package flag
import (
"fmt"
"os"
"strconv"
)
type boolValue bool
func newBoolValue(val bool, p *bool) *boolValue {
*p = val
return (*boolValue)(p)
}
func (b *boolValue) Set(s string) bool {
v, err := strconv.Atob(s)
*b = boolValue(v)
return err == nil
}
func (b *boolValue) String() string { return fmt.Sprintf("%v", *b) }
type intValue int
func newIntValue(val int, p *int) *intValue {
*p = val
return (*intValue)(p)
}
func (i *intValue) Set(s string) bool {
v, err := strconv.Atoi(s)
*i = intValue(v)
return err == nil
}
func (i *intValue) String() string { return fmt.Sprintf("%v", *i) }
type int64Value int64
func newInt64Value(val int64, p *int64) *int64Value {
*p = val
return (*int64Value)(p)
}
func (i *int64Value) Set(s string) bool {
v, err := strconv.Atoi64(s)
*i = int64Value(v)
return err == nil
}
func (i *int64Value) String() string { return fmt.Sprintf("%v", *i) }
type uintValue uint
func newUintValue(val uint, p *uint) *uintValue {
*p = val
return (*uintValue)(p)
}
func (i *uintValue) Set(s string) bool {
v, err := strconv.Atoui(s)
*i = uintValue(v)
return err == nil
}
func (i *uintValue) String() string { return fmt.Sprintf("%v", *i) }
type uint64Value uint64
func newUint64Value(val uint64, p *uint64) *uint64Value {
*p = val
return (*uint64Value)(p)
}
func (i *uint64Value) Set(s string) bool {
v, err := strconv.Atoui64(s)
*i = uint64Value(v)
return err == nil
}
func (i *uint64Value) String() string { return fmt.Sprintf("%v", *i) }
type stringValue string
func newStringValue(val string, p *string) *stringValue {
*p = val
return (*stringValue)(p)
}
func (s *stringValue) Set(val string) bool {
*s = stringValue(val)
return true
}
func (s *stringValue) String() string { return fmt.Sprintf("%s", *s) }
type floatValue float
func newFloatValue(val float, p *float) *floatValue {
*p = val
return (*floatValue)(p)
}
func (f *floatValue) Set(s string) bool {
v, err := strconv.Atof(s)
*f = floatValue(v)
return err == nil
}
func (f *floatValue) String() string { return fmt.Sprintf("%v", *f) }
type float64Value float64
func newFloat64Value(val float64, p *float64) *float64Value {
*p = val
return (*float64Value)(p)
}
func (f *float64Value) Set(s string) bool {
v, err := strconv.Atof64(s)
*f = float64Value(v)
return err == nil
}
func (f *float64Value) String() string { return fmt.Sprintf("%v", *f) }
type Value interface {
String() string
Set(string) bool
}
type Flag struct {
Name string
Usage string
Value Value
DefValue string
}
type allFlags struct {
actual map[string]*Flag
formal map[string]*Flag
first_arg int
}
var flags *allFlags
func VisitAll(fn func(*Flag)) {
for _, f := range flags.formal {
fn(f)
}
}
func Visit(fn func(*Flag)) {
for _, f := range flags.actual {
fn(f)
}
}
func Lookup(name string) *Flag {
return flags.formal[name]
}
func Set(name, value string) bool {
f, ok := flags.formal[name]
if !ok {
return false
}
ok = f.Value.Set(value)
if !ok {
return false
}
flags.actual[name] = f
return true
}
func PrintDefaults() {
VisitAll(func(f *Flag) {
format := " -%s=%s: %s\n"
if _, ok := f.Value.(*stringValue); ok {
format = " -%s=%q: %s\n"
}
fmt.Fprintf(os.Stderr, format, f.Name, f.DefValue, f.Usage)
})
}
var Usage = func() {
fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
PrintDefaults()
}
var panicOnError = false
func fail() {
Usage()
if panicOnError {
panic("flag parse error")
}
os.Exit(2)
}
func NFlag() int { return len(flags.actual) }
func Arg(i int) string {
i += flags.first_arg
if i < 0 || i >= len(os.Args) {
return ""
}
return os.Args[i]
}
func NArg() int { return len(os.Args) - flags.first_arg }
func Args() []string { return os.Args[flags.first_arg:] }
func BoolVar(p *bool, name string, value bool, usage string) {
Var(newBoolValue(value, p), name, usage)
}
func Bool(name string, value bool, usage string) *bool {
p := new(bool)
BoolVar(p, name, value, usage)
return p
}
func IntVar(p *int, name string, value int, usage string) {
Var(newIntValue(value, p), name, usage)
}
func Int(name string, value int, usage string) *int {
p := new(int)
IntVar(p, name, value, usage)
return p
}
func Int64Var(p *int64, name string, value int64, usage string) {
Var(newInt64Value(value, p), name, usage)
}
func Int64(name string, value int64, usage string) *int64 {
p := new(int64)
Int64Var(p, name, value, usage)
return p
}
func UintVar(p *uint, name string, value uint, usage string) {
Var(newUintValue(value, p), name, usage)
}
func Uint(name string, value uint, usage string) *uint {
p := new(uint)
UintVar(p, name, value, usage)
return p
}
func Uint64Var(p *uint64, name string, value uint64, usage string) {
Var(newUint64Value(value, p), name, usage)
}
func Uint64(name string, value uint64, usage string) *uint64 {
p := new(uint64)
Uint64Var(p, name, value, usage)
return p
}
func StringVar(p *string, name, value string, usage string) {
Var(newStringValue(value, p), name, usage)
}
func String(name, value string, usage string) *string {
p := new(string)
StringVar(p, name, value, usage)
return p
}
func FloatVar(p *float, name string, value float, usage string) {
Var(newFloatValue(value, p), name, usage)
}
func Float(name string, value float, usage string) *float {
p := new(float)
FloatVar(p, name, value, usage)
return p
}
func Float64Var(p *float64, name string, value float64, usage string) {
Var(newFloat64Value(value, p), name, usage)
}
func Float64(name string, value float64, usage string) *float64 {
p := new(float64)
Float64Var(p, name, value, usage)
return p
}
func Var(value Value, name string, usage string) {
f := &Flag{name, usage, value, value.String()}
_, alreadythere := flags.formal[name]
if alreadythere {
fmt.Fprintln(os.Stderr, "flag redefined:", name)
panic("flag redefinition")
}
flags.formal[name] = f
}
func (f *allFlags) parseOne(index int) (ok bool, next int) {
s := os.Args[index]
f.first_arg = index
if len(s) == 0 {
return false, -1
}
if s[0] != '-' {
return false, -1
}
num_minuses := 1
if len(s) == 1 {
return false, index
}
if s[1] == '-' {
num_minuses++
if len(s) == 2 {
return false, index + 1
}
}
name := s[num_minuses:]
if len(name) == 0 || name[0] == '-' || name[0] == '=' {
fmt.Fprintln(os.Stderr, "bad flag syntax:", s)
fail()
}
has_value := false
value := ""
for i := 1; i < len(name); i++ {
if name[i] == '=' {
value = name[i+1:]
has_value = true
name = name[0:i]
break
}
}
m := flags.formal
flag, alreadythere := m[name]
if !alreadythere {
fmt.Fprintf(os.Stderr, "flag provided but not defined: -%s\n", name)
fail()
}
if f, ok := flag.Value.(*boolValue); ok {
if has_value {
if !f.Set(value) {
fmt.Fprintf(os.Stderr, "invalid boolean value %t for flag: -%s\n", value, name)
fail()
}
} else {
f.Set("true")
}
} else {
if !has_value && index < len(os.Args)-1 {
has_value = true
index++
value = os.Args[index]
}
if !has_value {
fmt.Fprintf(os.Stderr, "flag needs an argument: -%s\n", name)
fail()
}
ok = flag.Value.Set(value)
if !ok {
fmt.Fprintf(os.Stderr, "invalid value %s for flag: -%s\n", value, name)
fail()
}
}
flags.actual[name] = flag
return true, index + 1
}
func Parse() {
for i := 1; i < len(os.Args); {
ok, next := flags.parseOne(i)
if next > 0 {
flags.first_arg = next
i = next
}
if !ok {
break
}
}
}
func ResetForTesting(usage func()) {
flags = &allFlags{make(map[string]*Flag), make(map[string]*Flag), 1}
Usage = usage
panicOnError = true
}
func ParseForTesting(args []string) (result bool) {
defer func() {
if recover() != nil {
result = false
}
}()
os.Args = args
Parse()
return true
}
func init() {
flags = &allFlags{make(map[string]*Flag), make(map[string]*Flag), 1}
}