diff options
Diffstat (limited to 'src/lib/flag/flag.go')
-rw-r--r-- | src/lib/flag/flag.go | 486 |
1 files changed, 486 insertions, 0 deletions
diff --git a/src/lib/flag/flag.go b/src/lib/flag/flag.go new file mode 100644 index 000000000..e66238f6d --- /dev/null +++ b/src/lib/flag/flag.go @@ -0,0 +1,486 @@ +// 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. + +/* + The flag package implements command-line flag parsing. + + 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.Fprintln(os.Stderr, "Usage of", sys.Args[0] + ":"); + } else { + fmt.Fprintln(os.Stderr, "Usage:"); + } + 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 +} + +// Args returns the non-flag command-line arguments. +func Args() []string { + return sys.Args[flags.first_arg:len(sys.Args)]; +} + +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 + } + } +} |