diff options
Diffstat (limited to 'libgo/go/flag')
-rw-r--r-- | libgo/go/flag/export_test.go | 32 | ||||
-rw-r--r-- | libgo/go/flag/flag.go | 480 | ||||
-rw-r--r-- | libgo/go/flag/flag_test.go | 194 |
3 files changed, 706 insertions, 0 deletions
diff --git a/libgo/go/flag/export_test.go b/libgo/go/flag/export_test.go new file mode 100644 index 000000000..b5e3243b3 --- /dev/null +++ b/libgo/go/flag/export_test.go @@ -0,0 +1,32 @@ +// Copyright 2010 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. + +package flag + +import "os" + +// Additional routines compiled into the package only during testing. + +// ResetForTesting clears all flag state and sets the usage function as directed. +// After calling ResetForTesting, parse errors in flag handling will panic rather +// than exit the program. +func ResetForTesting(usage func()) { + flags = &allFlags{make(map[string]*Flag), make(map[string]*Flag), os.Args[1:]} + Usage = usage + panicOnError = true +} + +// ParseForTesting parses the flag state using the provided arguments. It +// should be called after 1) ResetForTesting and 2) setting up the new flags. +// The return value reports whether the parse was error-free. +func ParseForTesting(args []string) (result bool) { + defer func() { + if recover() != nil { + result = false + } + }() + os.Args = args + Parse() + return true +} diff --git a/libgo/go/flag/flag.go b/libgo/go/flag/flag.go new file mode 100644 index 000000000..143a10611 --- /dev/null +++ b/libgo/go/flag/flag.go @@ -0,0 +1,480 @@ +// 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: + + Define flags using flag.String(), Bool(), Int(), etc. Example: + import "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") + } + Or you can create custom flags that satisfy the Value interface (with + pointer receivers) and couple them to flag parsing by + flag.Var(&flagVal, "name", "help message for flagname") + For such flags, the default value is just the initial value of the variable. + + After all flags are defined, call + flag.Parse() + to parse the command line into the defined flags. + + 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. + fmt.Println("ip has value ", *ip); + fmt.Println("flagvar has value ", flagvar); + + After parsing, the arguments after the flag are available as the + slice flag.Args() or individually as flag.Arg(i). + The arguments are indexed from 0 up to flag.NArg(). + + Command line flag syntax: + -flag + -flag=x + -flag x // non-boolean flags only + One or two minus signs may be used; they are equivalent. + The last form is not permitted for boolean flags because the + meaning of the command + cmd -x * + will change if there is a file called 0, false, etc. You must + use the -flag=false form to turn off a boolean flag. + + 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. + + It is safe to call flag.Parse multiple times, possibly after changing + os.Args. This makes it possible to implement command lines with + subcommands that enable additional flags, as in: + + flag.Bool(...) // global options + flag.Parse() // parse leading command + subcmd := flag.Args(0) + switch subcmd { + // add per-subcommand options + } + os.Args = flag.Args() + flag.Parse() +*/ +package flag + +import ( + "fmt" + "os" + "strconv" +) + +// -- Bool Value +type boolValue bool + +func newBoolValue(val bool, p *bool) *boolValue { + *p = val + return (*boolValue)(p) +} + +func (b *boolValue) Set(s string) bool { + v, err := strconv.Atob(s) + *b = boolValue(v) + return err == nil +} + +func (b *boolValue) String() string { return fmt.Sprintf("%v", *b) } + +// -- Int Value +type intValue 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 = intValue(v) + return err == nil +} + +func (i *intValue) String() string { return fmt.Sprintf("%v", *i) } + +// -- Int64 Value +type int64Value 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 = int64Value(v) + return err == nil +} + +func (i *int64Value) String() string { return fmt.Sprintf("%v", *i) } + +// -- Uint Value +type uintValue 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 = uintValue(v) + return err == nil +} + +func (i *uintValue) String() string { return fmt.Sprintf("%v", *i) } + +// -- uint64 Value +type uint64Value 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 = uint64Value(v) + return err == nil +} + +func (i *uint64Value) String() string { return fmt.Sprintf("%v", *i) } + +// -- string Value +type stringValue string + +func newStringValue(val string, p *string) *stringValue { + *p = val + return (*stringValue)(p) +} + +func (s *stringValue) Set(val string) bool { + *s = stringValue(val) + return true +} + +func (s *stringValue) String() string { return fmt.Sprintf("%s", *s) } + +// -- Float64 Value +type float64Value float64 + +func newFloat64Value(val float64, p *float64) *float64Value { + *p = val + return (*float64Value)(p) +} + +func (f *float64Value) Set(s string) bool { + v, err := strconv.Atof64(s) + *f = float64Value(v) + return err == nil +} + +func (f *float64Value) String() string { return fmt.Sprintf("%v", *f) } + +// Value is the interface to the dynamic value stored in a flag. +// (The default value is represented as a string.) +type Value 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 Value // value as set + DefValue string // default value (as text); for usage message +} + +type allFlags struct { + actual map[string]*Flag + formal map[string]*Flag + args []string // arguments after flags +} + +var flags *allFlags + +// VisitAll visits the flags, calling fn for each. It visits all flags, even those not set. +func VisitAll(fn func(*Flag)) { + for _, 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 _, 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 { + return flags.formal[name] +} + +// Set sets the value of the 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 _, 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. +// The function is a variable that may be changed to point to a custom function. +var Usage = func() { + fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0]) + PrintDefaults() +} + +var panicOnError = false + +func fail() { + Usage() + if panicOnError { + panic("flag parse error") + } + os.Exit(2) +} + +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 { + if i < 0 || i >= len(flags.args) { + return "" + } + return flags.args[i] +} + +// NArg is the number of arguments remaining after flags have been processed. +func NArg() int { return len(flags.args) } + +// Args returns the non-flag command-line arguments. +func Args() []string { return flags.args } + +// 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) { + Var(newBoolValue(value, p), name, 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) { + Var(newIntValue(value, p), name, 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) { + Var(newInt64Value(value, p), name, 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) { + Var(newUintValue(value, p), name, 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) { + Var(newUint64Value(value, p), name, 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) { + Var(newStringValue(value, p), name, 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 +} + +// Float64Var defines a float64 flag with specified name, default value, and usage string. +// The argument p points to a float64 variable in which to store the value of the flag. +func Float64Var(p *float64, name string, value float64, usage string) { + Var(newFloat64Value(value, p), name, usage) +} + +// Float64 defines a float64 flag with specified name, default value, and usage string. +// The return value is the address of a float64 variable that stores the value of the flag. +func Float64(name string, value float64, usage string) *float64 { + p := new(float64) + Float64Var(p, name, value, usage) + return p +} + +// Var defines a user-typed flag with specified name, default value, and usage string. +// The argument p points to a Value variable in which to store the value of the flag. +func Var(value Value, name string, usage string) { + // Remember the default value as a string; it won't change. + f := &Flag{name, usage, value, value.String()} + _, alreadythere := flags.formal[name] + if alreadythere { + fmt.Fprintln(os.Stderr, "flag redefined:", name) + panic("flag redefinition") // Happens only if flags are declared with identical names + } + flags.formal[name] = f +} + + +func (f *allFlags) parseOne() (ok bool) { + if len(f.args) == 0 { + return false + } + s := f.args[0] + if len(s) == 0 || s[0] != '-' || len(s) == 1 { + return false + } + num_minuses := 1 + if s[1] == '-' { + num_minuses++ + if len(s) == 2 { // "--" terminates the flags + f.args = f.args[1:] + return false + } + } + name := s[num_minuses:] + if len(name) == 0 || name[0] == '-' || name[0] == '=' { + fmt.Fprintln(os.Stderr, "bad flag syntax:", s) + fail() + } + + // it's a flag. does it have an argument? + f.args = f.args[1:] + has_value := false + value := "" + for i := 1; i < len(name); i++ { // equals cannot be first + if name[i] == '=' { + value = name[i+1:] + has_value = true + name = name[0:i] + break + } + } + m := flags.formal + flag, alreadythere := m[name] // BUG + if !alreadythere { + fmt.Fprintf(os.Stderr, "flag provided but not defined: -%s\n", name) + fail() + } + if fv, ok := flag.Value.(*boolValue); ok { // special case: doesn't need an arg + if has_value { + if !fv.Set(value) { + fmt.Fprintf(os.Stderr, "invalid boolean value %q for flag: -%s\n", value, name) + fail() + } + } else { + fv.Set("true") + } + } else { + // It must have a value, which might be the next argument. + if !has_value && len(f.args) > 0 { + // value is the next arg + has_value = true + value, f.args = f.args[0], f.args[1:] + } + if !has_value { + fmt.Fprintf(os.Stderr, "flag needs an argument: -%s\n", name) + fail() + } + ok = flag.Value.Set(value) + if !ok { + fmt.Fprintf(os.Stderr, "invalid value %q for flag: -%s\n", value, name) + fail() + } + } + flags.actual[name] = flag + return true +} + +// Parse parses the command-line flags. Must be called after all flags are defined +// and before any are accessed by the program. +func Parse() { + flags.args = os.Args[1:] + for flags.parseOne() { + } +} + +func init() { + flags = &allFlags{make(map[string]*Flag), make(map[string]*Flag), os.Args[1:]} +} diff --git a/libgo/go/flag/flag_test.go b/libgo/go/flag/flag_test.go new file mode 100644 index 000000000..b91a8b567 --- /dev/null +++ b/libgo/go/flag/flag_test.go @@ -0,0 +1,194 @@ +// 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. + +package flag_test + +import ( + . "flag" + "fmt" + "os" + "testing" +) + +var ( + test_bool = Bool("test_bool", false, "bool value") + test_int = Int("test_int", 0, "int value") + test_int64 = Int64("test_int64", 0, "int64 value") + test_uint = Uint("test_uint", 0, "uint value") + test_uint64 = Uint64("test_uint64", 0, "uint64 value") + test_string = String("test_string", "0", "string value") + test_float64 = Float64("test_float64", 0, "float64 value") +) + +func boolString(s string) string { + if s == "0" { + return "false" + } + return "true" +} + +func TestEverything(t *testing.T) { + m := make(map[string]*Flag) + desired := "0" + visitor := func(f *Flag) { + if len(f.Name) > 5 && f.Name[0:5] == "test_" { + m[f.Name] = f + ok := false + switch { + case f.Value.String() == desired: + ok = true + case f.Name == "test_bool" && f.Value.String() == boolString(desired): + ok = true + } + if !ok { + t.Error("Visit: bad value", f.Value.String(), "for", f.Name) + } + } + } + VisitAll(visitor) + if len(m) != 7 { + t.Error("VisitAll misses some flags") + for k, v := range m { + t.Log(k, *v) + } + } + m = make(map[string]*Flag) + Visit(visitor) + if len(m) != 0 { + t.Errorf("Visit sees unset flags") + for k, v := range m { + t.Log(k, *v) + } + } + // Now set all flags + Set("test_bool", "true") + Set("test_int", "1") + Set("test_int64", "1") + Set("test_uint", "1") + Set("test_uint64", "1") + Set("test_string", "1") + Set("test_float64", "1") + desired = "1" + Visit(visitor) + if len(m) != 7 { + t.Error("Visit fails after set") + for k, v := range m { + t.Log(k, *v) + } + } +} + +func TestUsage(t *testing.T) { + called := false + ResetForTesting(func() { called = true }) + if ParseForTesting([]string{"a.out", "-x"}) { + t.Error("parse did not fail for unknown flag") + } + if !called { + t.Error("did not call Usage for unknown flag") + } +} + +func TestParse(t *testing.T) { + ResetForTesting(func() { t.Error("bad parse") }) + boolFlag := Bool("bool", false, "bool value") + bool2Flag := Bool("bool2", false, "bool2 value") + intFlag := Int("int", 0, "int value") + int64Flag := Int64("int64", 0, "int64 value") + uintFlag := Uint("uint", 0, "uint value") + uint64Flag := Uint64("uint64", 0, "uint64 value") + stringFlag := String("string", "0", "string value") + float64Flag := Float64("float64", 0, "float64 value") + extra := "one-extra-argument" + args := []string{ + "a.out", + "-bool", + "-bool2=true", + "--int", "22", + "--int64", "23", + "-uint", "24", + "--uint64", "25", + "-string", "hello", + "-float64", "2718e28", + extra, + } + if !ParseForTesting(args) { + t.Fatal("parse failed") + } + if *boolFlag != true { + t.Error("bool flag should be true, is ", *boolFlag) + } + if *bool2Flag != true { + t.Error("bool2 flag should be true, is ", *bool2Flag) + } + if *intFlag != 22 { + t.Error("int flag should be 22, is ", *intFlag) + } + if *int64Flag != 23 { + t.Error("int64 flag should be 23, is ", *int64Flag) + } + if *uintFlag != 24 { + t.Error("uint flag should be 24, is ", *uintFlag) + } + if *uint64Flag != 25 { + t.Error("uint64 flag should be 25, is ", *uint64Flag) + } + if *stringFlag != "hello" { + t.Error("string flag should be `hello`, is ", *stringFlag) + } + if *float64Flag != 2718e28 { + t.Error("float64 flag should be 2718e28, is ", *float64Flag) + } + if len(Args()) != 1 { + t.Error("expected one argument, got", len(Args())) + } else if Args()[0] != extra { + t.Errorf("expected argument %q got %q", extra, Args()[0]) + } +} + +// Declare a user-defined flag. +type flagVar []string + +func (f *flagVar) String() string { + return fmt.Sprint([]string(*f)) +} + +func (f *flagVar) Set(value string) bool { + *f = append(*f, value) + return true +} + +func TestUserDefined(t *testing.T) { + ResetForTesting(func() { t.Fatal("bad parse") }) + var v flagVar + Var(&v, "v", "usage") + if !ParseForTesting([]string{"a.out", "-v", "1", "-v", "2", "-v=3"}) { + t.Error("parse failed") + } + if len(v) != 3 { + t.Fatal("expected 3 args; got ", len(v)) + } + expect := "[1 2 3]" + if v.String() != expect { + t.Errorf("expected value %q got %q", expect, v.String()) + } +} + +func TestChangingArgs(t *testing.T) { + ResetForTesting(func() { t.Fatal("bad parse") }) + oldArgs := os.Args + defer func() { os.Args = oldArgs }() + os.Args = []string{"cmd", "-before", "subcmd", "-after", "args"} + before := Bool("before", false, "") + Parse() + cmd := Arg(0) + os.Args = Args() + after := Bool("after", false, "") + Parse() + args := Args() + + if !*before || cmd != "subcmd" || !*after || len(args) != 1 || args[0] != "args" { + t.Fatalf("expected true subcmd true [args] got %v %v %v %v", *before, cmd, *after, args) + } +} |