| // 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. | |
| */ | |
| import fmt "fmt" | |
| //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 (b *BoolValue) Str() string { | |
| if b.val { | |
| return "true" | |
| } | |
| else { | |
| return "false" | |
| } | |
| } | |
| 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 (i *IntValue) Str() string { | |
| return fmt.New().D(i.val).str() | |
| } | |
| 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 (s *StringValue) Str() string { | |
| return `"` + s.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; | |
| Str() string; | |
| ValidValue(str string) bool; | |
| } | |
| // -- Flag structure (internal) | |
| export type Flag struct { | |
| name string; | |
| usage string; | |
| value Value; | |
| next *Flag; // BUG: remove when we can iterate over maps | |
| } | |
| type Flags struct { | |
| actual *map[string] *Flag; | |
| formal *map[string] *Flag; | |
| first_arg int; | |
| flag_list *Flag; // BUG: remove when we can iterate over maps | |
| } | |
| func (flags *Flags) Usage() { | |
| // BUG: use map iteration when available | |
| print("Usage: \n"); | |
| for f := flags.flag_list; f != nil; f = f.next { | |
| print(" -", f.name, "=", f.value.Str(), ": ", f.usage, "\n"); | |
| } | |
| sys.exit(1); | |
| } | |
| // --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(); | |
| export func Arg(i int) string { | |
| i += flags.first_arg; | |
| if i < 0 || i >= sys.argc() { | |
| return ""; | |
| } | |
| return sys.argv(i) | |
| } | |
| export 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; | |
| f.next = flags.flag_list; // BUG: remove when we can iterate over maps | |
| flags.flag_list = f; // BUG: remove when we can iterate over maps | |
| return f; | |
| } | |
| export func Bool(name string, value bool, p *bool, usage string) *Flag { | |
| return Add(name, NewBoolValue(value, p), usage); | |
| } | |
| export func Int(name string, value int64, p *int64, usage string) *Flag { | |
| return Add(name, NewIntValue(value, p), usage); | |
| } | |
| export 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"); | |
| f.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"); | |
| f.Usage(); | |
| } | |
| m := flags.formal; | |
| flag, alreadythere = m[name]; // BUG | |
| if !alreadythere { | |
| print("flag provided but not defined: -", name, "\n"); | |
| f.Usage(); | |
| } | |
| 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"); | |
| f.Usage(); | |
| } | |
| 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"); | |
| f.Usage(); | |
| } | |
| k, ok := atoi(value); | |
| if !ok { | |
| print("invalid integer value ", value, " for flag: -", name, "\n"); | |
| f.Usage(); | |
| } | |
| flag.value.AsInt().Set(k) | |
| case flag.value.IsString(): | |
| if !has_value { | |
| print("flag needs an argument: -", name, "\n"); | |
| f.Usage(); | |
| } | |
| flag.value.AsString().Set(value) | |
| } | |
| flags.actual[name] = flag; | |
| return true, index + 1 | |
| } | |
| export 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 | |
| } | |
| } | |
| } |