// 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 } } }