1
2
3
4
5
6 package cmdflag
7
8 import (
9 "errors"
10 "flag"
11 "fmt"
12 "strings"
13 )
14
15
16
17
18
19
20
21
22 var ErrFlagTerminator = errors.New("flag terminator")
23
24
25
26 type FlagNotDefinedError struct {
27 RawArg string
28 Name string
29 HasValue bool
30 Value string
31 }
32
33 func (e FlagNotDefinedError) Error() string {
34 return fmt.Sprintf("flag provided but not defined: -%s", e.Name)
35 }
36
37
38 type NonFlagError struct {
39 RawArg string
40 }
41
42 func (e NonFlagError) Error() string {
43 return fmt.Sprintf("not a flag: %q", e.RawArg)
44 }
45
46
47
48
49
50
51
52
53 func ParseOne(fs *flag.FlagSet, args []string) (f *flag.Flag, remainingArgs []string, err error) {
54
55
56 raw, args := args[0], args[1:]
57 arg := raw
58 if strings.HasPrefix(arg, "--") {
59 if arg == "--" {
60 return nil, args, ErrFlagTerminator
61 }
62 arg = arg[1:]
63 }
64
65 switch arg {
66 case "-?", "-h", "-help":
67 return nil, args, flag.ErrHelp
68 }
69 if len(arg) < 2 || arg[0] != '-' || arg[1] == '-' || arg[1] == '=' {
70 return nil, args, NonFlagError{RawArg: raw}
71 }
72
73 name := arg[1:]
74 hasValue := false
75 value := ""
76 if i := strings.Index(name, "="); i >= 0 {
77 value = name[i+1:]
78 hasValue = true
79 name = name[0:i]
80 }
81
82 f = fs.Lookup(name)
83 if f == nil {
84 return nil, args, FlagNotDefinedError{
85 RawArg: raw,
86 Name: name,
87 HasValue: hasValue,
88 Value: value,
89 }
90 }
91
92
93
94
95 failf := func(format string, a ...any) (*flag.Flag, []string, error) {
96 return f, args, fmt.Errorf(format, a...)
97 }
98
99 if fv, ok := f.Value.(boolFlag); ok && fv.IsBoolFlag() {
100 if hasValue {
101 if err := fs.Set(name, value); err != nil {
102 return failf("invalid boolean value %q for -%s: %v", value, name, err)
103 }
104 } else {
105 if err := fs.Set(name, "true"); err != nil {
106 return failf("invalid boolean flag %s: %v", name, err)
107 }
108 }
109 } else {
110
111 if !hasValue && len(args) > 0 {
112
113 hasValue = true
114 value, args = args[0], args[1:]
115 }
116 if !hasValue {
117 return failf("flag needs an argument: -%s", name)
118 }
119 if err := fs.Set(name, value); err != nil {
120 return failf("invalid value %q for flag -%s: %v", value, name, err)
121 }
122 }
123
124 return f, args, nil
125 }
126
127 type boolFlag interface {
128 IsBoolFlag() bool
129 }
130
View as plain text