summaryrefslogtreecommitdiff
path: root/src/pkg/flag
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2011-01-17 12:40:45 +0100
committerOndřej Surý <ondrej@sury.org>2011-01-17 12:40:45 +0100
commit3e45412327a2654a77944249962b3652e6142299 (patch)
treebc3bf69452afa055423cbe0c5cfa8ca357df6ccf /src/pkg/flag
parentc533680039762cacbc37db8dc7eed074c3e497be (diff)
downloadgolang-3e45412327a2654a77944249962b3652e6142299.tar.gz
Imported Upstream version 2011.01.12upstream/2011.01.12
Diffstat (limited to 'src/pkg/flag')
-rw-r--r--src/pkg/flag/Makefile2
-rw-r--r--src/pkg/flag/export_test.go32
-rw-r--r--src/pkg/flag/flag.go114
-rw-r--r--src/pkg/flag/flag_test.go24
4 files changed, 99 insertions, 73 deletions
diff --git a/src/pkg/flag/Makefile b/src/pkg/flag/Makefile
index 3ffbea83c..3408ca474 100644
--- a/src/pkg/flag/Makefile
+++ b/src/pkg/flag/Makefile
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=flag
GOFILES=\
diff --git a/src/pkg/flag/export_test.go b/src/pkg/flag/export_test.go
new file mode 100644
index 000000000..b5e3243b3
--- /dev/null
+++ b/src/pkg/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/src/pkg/flag/flag.go b/src/pkg/flag/flag.go
index 59c33403d..04fe2fa05 100644
--- a/src/pkg/flag/flag.go
+++ b/src/pkg/flag/flag.go
@@ -7,7 +7,7 @@
Usage:
- 1) Define flags using flag.String(), Bool(), Int(), etc. Example:
+ 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.
@@ -20,17 +20,18 @@
flag.Var(&flagVal, "name", "help message for flagname")
For such flags, the default value is just the initial value of the variable.
- 2) After all flags are defined, call
+ 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,
+ 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);
- 4) After parsing, flag.Arg(i) is the i'th argument after the flags.
- Args are indexed from 0 up to flag.NArg().
+ 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
@@ -48,6 +49,19 @@
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
@@ -200,9 +214,9 @@ type Flag struct {
}
type allFlags struct {
- actual map[string]*Flag
- formal map[string]*Flag
- first_arg int // 0 is the program name, 1 is first arg
+ actual map[string]*Flag
+ formal map[string]*Flag
+ args []string // arguments after flags
}
var flags *allFlags
@@ -275,18 +289,17 @@ 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(os.Args) {
+ if i < 0 || i >= len(flags.args) {
return ""
}
- return os.Args[i]
+ return flags.args[i]
}
// NArg is the number of arguments remaining after flags have been processed.
-func NArg() int { return len(os.Args) - flags.first_arg }
+func NArg() int { return len(flags.args) }
// Args returns the non-flag command-line arguments.
-func Args() []string { return os.Args[flags.first_arg:] }
+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.
@@ -414,23 +427,20 @@ func Var(value Value, name string, usage string) {
}
-func (f *allFlags) parseOne(index int) (ok bool, next int) {
- s := os.Args[index]
- f.first_arg = index // until proven otherwise
- if len(s) == 0 {
- return false, -1
+func (f *allFlags) parseOne() (ok bool) {
+ if len(f.args) == 0 {
+ return false
}
- if s[0] != '-' {
- return false, -1
+ s := f.args[0]
+ if len(s) == 0 || s[0] != '-' || len(s) == 1 {
+ return false
}
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
+ f.args = f.args[1:]
+ return false
}
}
name := s[num_minuses:]
@@ -440,6 +450,7 @@ func (f *allFlags) parseOne(index int) (ok bool, next int) {
}
// 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
@@ -456,22 +467,21 @@ func (f *allFlags) parseOne(index int) (ok bool, next int) {
fmt.Fprintf(os.Stderr, "flag provided but not defined: -%s\n", name)
fail()
}
- if f, ok := flag.Value.(*boolValue); ok { // special case: doesn't need an arg
+ if fv, ok := flag.Value.(*boolValue); ok { // special case: doesn't need an arg
if has_value {
- if !f.Set(value) {
- fmt.Fprintf(os.Stderr, "invalid boolean value %t for flag: -%s\n", value, name)
+ if !fv.Set(value) {
+ fmt.Fprintf(os.Stderr, "invalid boolean value %q for flag: -%s\n", value, name)
fail()
}
} else {
- f.Set("true")
+ fv.Set("true")
}
} else {
// It must have a value, which might be the next argument.
- if !has_value && index < len(os.Args)-1 {
+ if !has_value && len(f.args) > 0 {
// value is the next arg
has_value = true
- index++
- value = os.Args[index]
+ value, f.args = f.args[0], f.args[1:]
}
if !has_value {
fmt.Fprintf(os.Stderr, "flag needs an argument: -%s\n", name)
@@ -479,54 +489,22 @@ func (f *allFlags) parseOne(index int) (ok bool, next int) {
}
ok = flag.Value.Set(value)
if !ok {
- fmt.Fprintf(os.Stderr, "invalid value %s for flag: -%s\n", value, name)
+ fmt.Fprintf(os.Stderr, "invalid value %q for flag: -%s\n", value, name)
fail()
}
}
flags.actual[name] = flag
- return true, index + 1
+ 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() {
- for i := 1; i < len(os.Args); {
- ok, next := flags.parseOne(i)
- if next > 0 {
- flags.first_arg = next
- i = next
- }
- if !ok {
- break
- }
+ flags.args = os.Args[1:]
+ for flags.parseOne() {
}
}
-// 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.
-// For testing only!
-func ResetForTesting(usage func()) {
- flags = &allFlags{make(map[string]*Flag), make(map[string]*Flag), 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.
-// For testing only!
-func ParseForTesting(args []string) (result bool) {
- defer func() {
- if recover() != nil {
- result = false
- }
- }()
- os.Args = args
- Parse()
- return true
-}
-
func init() {
- flags = &allFlags{make(map[string]*Flag), make(map[string]*Flag), 1}
+ flags = &allFlags{make(map[string]*Flag), make(map[string]*Flag), os.Args[1:]}
}
diff --git a/src/pkg/flag/flag_test.go b/src/pkg/flag/flag_test.go
index 83bf7eebf..4ebb73805 100644
--- a/src/pkg/flag/flag_test.go
+++ b/src/pkg/flag/flag_test.go
@@ -7,6 +7,7 @@ package flag_test
import (
. "flag"
"fmt"
+ "os"
"testing"
)
@@ -161,10 +162,7 @@ func (f *flagVar) String() string {
}
func (f *flagVar) Set(value string) bool {
- n := make(flagVar, len(*f)+1)
- copy(n, *f)
- *f = n
- (*f)[len(*f)-1] = value
+ *f = append(*f, value)
return true
}
@@ -183,3 +181,21 @@ func TestUserDefined(t *testing.T) {
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)
+ }
+}