]> Cypherpunks repositories - gostls13.git/commitdiff
Add a flags package.
authorRob Pike <r@golang.org>
Thu, 24 Jul 2008 03:02:54 +0000 (20:02 -0700)
committerRob Pike <r@golang.org>
Thu, 24 Jul 2008 03:02:54 +0000 (20:02 -0700)
R=gri
OCL=13399
CL=13399

src/lib/flag.go [new file with mode: 0644]
src/lib/fmt.go
src/lib/make.bash

diff --git a/src/lib/flag.go b/src/lib/flag.go
new file mode 100644 (file)
index 0000000..dc4863d
--- /dev/null
@@ -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
+               }
+       }
+}
index 668d608d1681578b8f43d21d48cbd022c5f0e8a4..a123931e5f74d090ac44bca32fd49d4d008cc3d8 100644 (file)
@@ -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
index 88c97c1388131d252f76499617ee9c08338615a5..d81d85193c8d92439b847832a285161425f761b5 100755 (executable)
@@ -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