From ac0dd5ae525db0d057e94c03c3f506bc30afae31 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Wed, 23 Jul 2008 20:02:54 -0700 Subject: [PATCH] Add a flags package. R=gri OCL=13399 CL=13399 --- src/lib/flag.go | 439 ++++++++++++++++++++++++++++++++++++++++++++++ src/lib/fmt.go | 2 +- src/lib/make.bash | 6 +- 3 files changed, 444 insertions(+), 3 deletions(-) create mode 100644 src/lib/flag.go diff --git a/src/lib/flag.go b/src/lib/flag.go new file mode 100644 index 00000000000..dc4863d9878 --- /dev/null +++ b/src/lib/flag.go @@ -0,0 +1,439 @@ +// 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 + +/* + * Flags + * + * Usage: + * 1) Define flags using flag.String(), Bool(), or Int(). Int flag values have type int64. Example: + * import flag "flag" + * var i int64 + * var fi *flag.Flag = flag.Int("flagname", 1234, &i, "help message for flagname") + * The pointer may be nil; if non-nil, it points to a cell of the appropriate type to store the + * flag's value. + * + * 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 (getters are SVal, BVal, Ival) or through the associated + * cell, if set: + * print "fi has value ", fi.IVal(), "\n"; + * print "i has value ", i, "\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. + * A lone -- terminates the parsing of the command line. + * Integer flags accept 1234, 0664, 0x1234 and may be negative. + * Boolean flags may be 1, 0, t, f, true, false, TRUE, FALSE, True, False. + */ + +export Bool, Int, String +export Arg, NArg +export Parse +//export Flag.BVal BUG: variable exported but not defined: Flag.BVal +//export Flag.SVal BUG: variable exported but not defined: Flag.SVal +export Flag + +// BUG: ctoi, atoi, atob belong elsewhere +func ctoi(c int64) int64 { + if '0' <= c && c <= '9' { + return c - '0' + } + if 'a' <= c && c <= 'f' { + return c - 'a' + } + if 'A' <= c && c <= 'F' { + return c - 'A' + } + return 1000 // too large for any base +} + +func atoi(s string) (value int64, ok bool) { + if len(s) == 0 { + return 0, false + } + if s[0] == '-' { + n, t := atoi(s[1:len(s)]); + return -n, t + } + var base int64 = 10; + i := 0; + if s[0] == '0' { + base = 8 + if len(s) > 1 && (s[1] == 'x' || s[1] == 'X') { + base = 16; + i += 2; + } + } + var n int64 = 0 + for ; i < len(s); i++ { + k := ctoi(int64(s[i])); + if k >= base { + return 0, false + } + n = n * base + k + } + return n, true +} + +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 +} + +// -- Bool Value +type BoolValue struct { + val bool; + p *bool; +} + +func (b *BoolValue) AsBool() *BoolValue { + return b +} + +func (b *BoolValue) AsInt() *IntValue { + return nil +} + +func (b *BoolValue) AsString() *StringValue { + return nil +} + +func (b *BoolValue) IsBool() bool { + return true +} + +func (b *BoolValue) IsInt() bool { + return false +} + +func (b *BoolValue) IsString() bool { + return false +} + +func (b *BoolValue) ValidValue(str string) bool { + i, ok := atob(str); + return ok; +} + +func (b *BoolValue) Set(val bool) { + if b.p != nil { + *b.p = val + } + b.val = val +} + +func NewBoolValue(b bool, p *bool) *BoolValue { + v := new(BoolValue); + v.val = b; + v.p = p; + return v; +} + +// -- Int Value +type IntValue struct { + val int64; + p *int64; +} + +func (i *IntValue) AsBool() *BoolValue { + return nil +} + +func (i *IntValue) AsInt() *IntValue { + return i +} + +func (i *IntValue) AsString() *StringValue{ + return nil +} + +func (i *IntValue) IsBool() bool { + return false +} + +func (i *IntValue) IsInt() bool { + return true +} + +func (i *IntValue) IsString() bool { + return false +} + +func (i *IntValue) ValidValue(str string) bool { + k, ok := atoi(str); + return ok; +} + +func (i *IntValue) Set(val int64) { + if i.p != nil { + *i.p = val + } + i.val = val +} + +func +NewIntValue(i int64, p *int64) *IntValue { + v := new(IntValue); + v.val = i; + v.p = p; + return v; +} + +// -- String Value +type StringValue struct { + val string; + p *string; +} + +func (e *StringValue) AsBool() *BoolValue { + return nil +} + +func (e *StringValue) AsInt() *IntValue { + return nil +} + +func (s *StringValue) AsString() *StringValue{ + return s +} + +func (s *StringValue) IsBool() bool { + return false +} + +func (s *StringValue) IsInt() bool { + return false +} + +func (s *StringValue) IsString() bool { + return true +} + +func (s *StringValue) ValidValue(str string) bool { + return true +} + +func (s *StringValue) Set(val string) { + if s.p != nil { + *s.p = val + } + s.val = val +} + +func NewStringValue(s string, p *string) *StringValue { + v := new(StringValue); + v.val = s; + v.p = p; + return v; +} + +// -- Value interface +type Value interface { + AsBool() *BoolValue; + AsInt() *IntValue; + AsString() *StringValue; + IsBool() bool; + IsInt() bool; + IsString() bool; + ValidValue(str string) bool; +} + +// -- Flag structure (internal) +type Flag struct { + name string; + usage string; + value Value; +} + +type Flags struct { + actual *map[string] *Flag; + formal *map[string] *Flag; + first_arg int; +} + +// --Customer's value getters +func (f *Flag) BVal() bool { + if !f.value.IsBool() { + return false; + } + return f.value.AsBool().val; +} + +func (f *Flag) IVal() int64 { + if !f.value.IsInt() { + return 0 + } + return f.value.AsInt().val; +} + +func (f *Flag) SVal() string { + if !f.value.IsString() { + return "???"; + } + return f.value.AsString().val; +} + +func New() *Flags { + f := new(Flags); + f.first_arg = 1; // 0 is the program name, 1 is first arg + f.actual = new(map[string] *Flag); + f.formal = new(map[string] *Flag); + return f; +} + +var flags *Flags = New(); + +func Arg(i int) string { + i += flags.first_arg; + if i < 0 || i >= sys.argc() { + return ""; + } + return sys.argv(i) +} + +func NArg() int32 { + return sys.argc() - flags.first_arg +} + +func Add(name string, value Value, usage string) *Flag { + f := new(Flag); + f.name = name; + f.usage = usage; + f.value = value; + dummy, alreadythere := flags.formal[name]; + if alreadythere { + print "flag redefined: ", name, "\n"; + panic "flag redefinition" + } + flags.formal[name] = f; + return f; +} + +func Bool(name string, value bool, p *bool, usage string) *Flag { + return Add(name, NewBoolValue(value, p), usage); +} + +func Int(name string, value int64, p *int64, usage string) *Flag { + return Add(name, NewIntValue(value, p), usage); +} + +func String(name, value string, p *string, usage string) *Flag { + return Add(name, NewStringValue(value, p), usage); +} + +func (f *Flags) ParseOne(index int) (ok bool, next int) +{ + s := sys.argv(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, -1 + } + 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" + return false, -1 + } + + // 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" + return false, -1 + } + m := flags.formal; + flag, alreadythere = m[name]; // BUG + if !alreadythere { + print "flag provided but not defined: -", name, "\n" + return false, -1 + } + if !has_value && index < sys.argc()-1 && flag.value.ValidValue(sys.argv(index+1)) { + // value is the next arg + has_value = true; + index++; + value = sys.argv(index); + } + switch { + case flag.value.IsBool(): + if has_value { + k, ok := atob(value); + if !ok { + print "invalid boolean value ", value, " for flag: -", name, "\n" + return false, -1 + } + flag.value.AsBool().Set(k) + } else { + flag.value.AsBool().Set(true) + } + case flag.value.IsInt(): + if !has_value { + print "flag needs an argument: -", name, "\n" + return false, -1 + } + k, ok := atoi(value); + if !ok { + print "invalid integer value ", value, " for flag: -", name, "\n" + return false, -1 + } + flag.value.AsInt().Set(k) + case flag.value.IsString(): + if !has_value { + print "flag needs an argument: -", name, "\n" + return false, -1 + } + flag.value.AsString().Set(value) + } + flags.actual[name] = flag; + return true, index + 1 +} + +func Parse() { + for i := 1; i < sys.argc(); { + ok, next := flags.ParseOne(i); + if next > 0 { + flags.first_arg = next; + i = next; + } + if !ok { + break + } + } +} diff --git a/src/lib/fmt.go b/src/lib/fmt.go index 668d608d168..a123931e5f7 100644 --- a/src/lib/fmt.go +++ b/src/lib/fmt.go @@ -16,7 +16,7 @@ package fmt export Fmt, New; const NByte = 64; -const NPows10 = 160; // BUG: why not nelem(pows10); +const NPows10 = 160; var ldigits string = "0123456789abcdef"; // BUG: Should be const var udigits string = "0123456789ABCDEF"; // BUG: Should be const diff --git a/src/lib/make.bash b/src/lib/make.bash index 88c97c13881..d81d85193c8 100755 --- a/src/lib/make.bash +++ b/src/lib/make.bash @@ -5,6 +5,8 @@ #!/bin/bash rm -f *.6 -6g fmt.go -6g container/vector.go +for i in flag.go fmt.go container/vector.go +do + 6g $i +done mv *.6 $GOROOT/pkg