summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Pike <r@golang.org>2008-07-23 20:02:54 -0700
committerRob Pike <r@golang.org>2008-07-23 20:02:54 -0700
commitee9310c20e3d112c2da0344a6be1288ee45f9862 (patch)
treeefbbb8b1cf9ce8b249a9c303218c339c2afe2a97
parent97184bc4573f19f223da144b06fd5a8bf1803b4e (diff)
downloadgolang-ee9310c20e3d112c2da0344a6be1288ee45f9862.tar.gz
Add a flags package.
R=gri OCL=13399 CL=13399
-rw-r--r--src/lib/flag.go439
-rw-r--r--src/lib/fmt.go2
-rwxr-xr-xsrc/lib/make.bash6
3 files changed, 444 insertions, 3 deletions
diff --git a/src/lib/flag.go b/src/lib/flag.go
new file mode 100644
index 000000000..dc4863d98
--- /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 668d608d1..a123931e5 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 88c97c138..d81d85193 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