// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. /* * Flags * * Usage: * 1) Define flags using flag.String(), Bool(), Int(), etc. Example: * import flag "flag" * var ip *int = flag.Int("flagname", 1234, "help message for flagname") * If you like, you can bind the flag to a variable using the Var() functions. * var flagvar int * func init() { * flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname") * } * * 2) After all flags are defined, call * flag.Parse() * to parse the command line into the defined flags. * * 3) Flags may then be used directly. If you're using the flags themselves, * they are all pointers; if you bind to variables, they're values. * print("ip has value ", *ip, "\n"); * print("flagvar has value ", flagvar, "\n"); * * 4) After parsing, flag.Arg(i) is the i'th argument after the flags. * Args are indexed from 0 up to flag.NArg(). * * Command line flag syntax: * -flag * -flag=x * -flag x * One or two minus signs may be used; they are equivalent. * * Flag parsing stops just before the first non-flag argument * ("-" is a non-flag argument) or after the terminator "--". * * Integer flags accept 1234, 0664, 0x1234 and may be negative. * Boolean flags may be 1, 0, t, f, true, false, TRUE, FALSE, True, False. */ package flag import ( "fmt"; "os"; "strconv" ) // BUG: atob belongs elsewhere func atob(str string) (value bool, ok bool) { switch str { case "1", "t", "T", "true", "TRUE", "True": return true, true; case "0", "f", "F", "false", "FALSE", "False": return false, true } return false, false } type ( boolValue struct; intValue struct; int64Value struct; uintValue struct; uint64Value struct; stringValue struct; ) // -- Bool Value type boolValue struct { p *bool; } func newBoolValue(val bool, p *bool) *boolValue { *p = val; return &boolValue{p} } func (b *boolValue) set(s string) bool { v, ok := atob(s); *b.p = v; return ok } func (b *boolValue) String() string { return fmt.Sprintf("%v", *b.p) } // -- Int Value type intValue struct { p *int; } func newIntValue(val int, p *int) *intValue { *p = val; return &intValue{p} } func (i *intValue) set(s string) bool { v, err := strconv.Atoi(s); *i.p = int(v); return err == nil } func (i *intValue) String() string { return fmt.Sprintf("%v", *i.p) } // -- Int64 Value type int64Value struct { p *int64; } func newInt64Value(val int64, p *int64) *int64Value { *p = val; return &int64Value{p} } func (i *int64Value) set(s string) bool { v, err := strconv.Atoi64(s); *i.p = v; return err == nil; } func (i *int64Value) String() string { return fmt.Sprintf("%v", *i.p) } // -- Uint Value type uintValue struct { p *uint; } func newUintValue(val uint, p *uint) *uintValue { *p = val; return &uintValue{p} } func (i *uintValue) set(s string) bool { v, err := strconv.Atoui(s); *i.p = uint(v); return err == nil; } func (i *uintValue) String() string { return fmt.Sprintf("%v", *i.p) } // -- uint64 Value type uint64Value struct { p *uint64; } func newUint64Value(val uint64, p *uint64) *uint64Value { *p = val; return &uint64Value{p} } func (i *uint64Value) set(s string) bool { v, err := strconv.Atoui64(s); *i.p = uint64(v); return err == nil; } func (i *uint64Value) String() string { return fmt.Sprintf("%v", *i.p) } // -- string Value type stringValue struct { p *string; } func newStringValue(val string, p *string) *stringValue { *p = val; return &stringValue{p} } func (s *stringValue) set(val string) bool { *s.p = val; return true; } func (s *stringValue) String() string { return fmt.Sprintf("%s", *s.p) } // FlagValue is the interface to the dynamic value stored in a flag. // (The default value is represented as a string.) type FlagValue interface { String() string; set(string) bool; } // A Flag represents the state of a flag. type Flag struct { Name string; // name as it appears on command line Usage string; // help message Value FlagValue; // value as set DefValue string; // default value (as text); for usage message } type allFlags struct { actual map[string] *Flag; formal map[string] *Flag; first_arg int; // 0 is the program name, 1 is first arg } var flags *allFlags = &allFlags{make(map[string] *Flag), make(map[string] *Flag), 1} // VisitAll visits the flags, calling fn for each. It visits all flags, even those not set. func VisitAll(fn func(*Flag)) { for k, f := range flags.formal { fn(f) } } // Visit visits the flags, calling fn for each. It visits only those flags that have been set. func Visit(fn func(*Flag)) { for k, f := range flags.actual { fn(f) } } // Lookup returns the Flag structure of the named flag, returning nil if none exists. func Lookup(name string) *Flag { f, ok := flags.formal[name]; if !ok { return nil } return f } // Set sets the value of tne named flag. It returns true if the set succeeded; false if // there is no such flag defined. func Set(name, value string) bool { f, ok := flags.formal[name]; if !ok { return false } ok = f.Value.set(value); if !ok { return false } flags.actual[name] = f; return true; } // PrintDefaults prints to standard error the default values of all defined flags. func PrintDefaults() { VisitAll(func(f *Flag) { format := " -%s=%s: %s\n"; if s, ok := f.Value.(*stringValue); ok { // put quotes on the value format = " -%s=%q: %s\n"; } fmt.Fprintf(os.Stderr, format, f.Name, f.DefValue, f.Usage); }) } // Usage prints to standard error a default usage message documenting all defined flags and // then calls sys.Exit(1). func Usage() { if len(sys.Args) > 0 { fmt.Fprintf(os.Stderr, "Usage of ", sys.Args[0], ": \n"); } else { fmt.Fprintf(os.Stderr, "Usage: \n"); } PrintDefaults(); sys.Exit(1); } func NFlag() int { return len(flags.actual) } // Arg returns the i'th command-line argument. Arg(0) is the first remaining argument // after flags have been processed. func Arg(i int) string { i += flags.first_arg; if i < 0 || i >= len(sys.Args) { return ""; } return sys.Args[i] } // NArg is the number of arguments remaining after flags have been processed. func NArg() int { return len(sys.Args) - flags.first_arg } func add(name string, value FlagValue, usage string) { // Remember the default value as a string; it won't change. f := &Flag{name, usage, value, value.String()}; dummy, alreadythere := flags.formal[name]; if alreadythere { print("flag redefined: ", name, "\n"); panic("flag redefinition"); // Happens only if flags are declared with identical names } flags.formal[name] = f; } // BoolVar defines a bool flag with specified name, default value, and usage string. // The argument p points to a bool variable in which to store the value of the flag. func BoolVar(p *bool, name string, value bool, usage string) { add(name, newBoolValue(value, p), usage); } // Bool defines a bool flag with specified name, default value, and usage string. // The return value is the address of a bool variable that stores the value of the flag. func Bool(name string, value bool, usage string) *bool { p := new(bool); BoolVar(p, name, value, usage); return p; } // IntVar defines an int flag with specified name, default value, and usage string. // The argument p points to an int variable in which to store the value of the flag. func IntVar(p *int, name string, value int, usage string) { add(name, newIntValue(value, p), usage); } // Int defines an int flag with specified name, default value, and usage string. // The return value is the address of an int variable that stores the value of the flag. func Int(name string, value int, usage string) *int { p := new(int); IntVar(p, name, value, usage); return p; } // Int64Var defines an int64 flag with specified name, default value, and usage string. // The argument p points to an int64 variable in which to store the value of the flag. func Int64Var(p *int64, name string, value int64, usage string) { add(name, newInt64Value(value, p), usage); } // Int64 defines an int64 flag with specified name, default value, and usage string. // The return value is the address of an int64 variable that stores the value of the flag. func Int64(name string, value int64, usage string) *int64 { p := new(int64); Int64Var(p, name, value, usage); return p; } // UintVar defines a uint flag with specified name, default value, and usage string. // The argument p points to a uint variable in which to store the value of the flag. func UintVar(p *uint, name string, value uint, usage string) { add(name, newUintValue(value, p), usage); } // Uint defines a uint flag with specified name, default value, and usage string. // The return value is the address of a uint variable that stores the value of the flag. func Uint(name string, value uint, usage string) *uint { p := new(uint); UintVar(p, name, value, usage); return p; } // Uint64Var defines a uint64 flag with specified name, default value, and usage string. // The argument p points to a uint64 variable in which to store the value of the flag. func Uint64Var(p *uint64, name string, value uint64, usage string) { add(name, newUint64Value(value, p), usage); } // Uint64 defines a uint64 flag with specified name, default value, and usage string. // The return value is the address of a uint64 variable that stores the value of the flag. func Uint64(name string, value uint64, usage string) *uint64 { p := new(uint64); Uint64Var(p, name, value, usage); return p; } // StringVar defines a string flag with specified name, default value, and usage string. // The argument p points to a string variable in which to store the value of the flag. func StringVar(p *string, name, value string, usage string) { add(name, newStringValue(value, p), usage); } // String defines a string flag with specified name, default value, and usage string. // The return value is the address of a string variable that stores the value of the flag. func String(name, value string, usage string) *string { p := new(string); StringVar(p, name, value, usage); return p; } func (f *allFlags) parseOne(index int) (ok bool, next int) { s := sys.Args[index]; f.first_arg = index; // until proven otherwise if len(s) == 0 { return false, -1 } if s[0] != '-' { return false, -1 } num_minuses := 1; if len(s) == 1 { return false, index } if s[1] == '-' { num_minuses++; if len(s) == 2 { // "--" terminates the flags return false, index + 1 } } name := s[num_minuses : len(s)]; if len(name) == 0 || name[0] == '-' || name[0] == '=' { print("bad flag syntax: ", s, "\n"); Usage(); } // it's a flag. does it have an argument? has_value := false; value := ""; for i := 1; i < len(name); i++ { // equals cannot be first if name[i] == '=' { value = name[i+1 : len(name)]; has_value = true; name = name[0 : i]; break; } } flag, alreadythere := flags.actual[name]; if alreadythere { print("flag specified twice: -", name, "\n"); Usage(); } m := flags.formal; flag, alreadythere = m[name]; // BUG if !alreadythere { print("flag provided but not defined: -", name, "\n"); Usage(); } if f, ok := flag.Value.(*boolValue); ok { // special case: doesn't need an arg if has_value { if !f.set(value) { print("invalid boolean value ", value, " for flag: -", name, "\n"); Usage(); } } else { f.set("true") } } else { // It must have a value, which might be the next argument. if !has_value && index < len(sys.Args)-1 { // value is the next arg has_value = true; index++; value = sys.Args[index]; } if !has_value { print("flag needs an argument: -", name, "\n"); Usage(); } ok = flag.Value.set(value); if !ok { print("invalid value ", value, " for flag: -", name, "\n"); Usage(); } } flags.actual[name] = flag; return true, index + 1 } // Parse parses the command-line flags. Must be called after all flags are defined // and before any are accessed by the program. func Parse() { for i := 1; i < len(sys.Args); { ok, next := flags.parseOne(i); if next > 0 { flags.first_arg = next; i = next; } if !ok { break } } }