1package flags 2 3import ( 4 "bytes" 5 "fmt" 6 "os" 7 "sort" 8 "strings" 9 "unicode/utf8" 10) 11 12type parseState struct { 13 arg string 14 args []string 15 retargs []string 16 positional []*Arg 17 err error 18 19 command *Command 20 lookup lookup 21} 22 23func (p *parseState) eof() bool { 24 return len(p.args) == 0 25} 26 27func (p *parseState) pop() string { 28 if p.eof() { 29 return "" 30 } 31 32 p.arg = p.args[0] 33 p.args = p.args[1:] 34 35 return p.arg 36} 37 38func (p *parseState) peek() string { 39 if p.eof() { 40 return "" 41 } 42 43 return p.args[0] 44} 45 46func (p *parseState) checkRequired(parser *Parser) error { 47 c := parser.Command 48 49 var required []*Option 50 51 for c != nil { 52 c.eachGroup(func(g *Group) { 53 for _, option := range g.options { 54 if !option.isSet && option.Required { 55 required = append(required, option) 56 } 57 } 58 }) 59 60 c = c.Active 61 } 62 63 if len(required) == 0 { 64 if len(p.positional) > 0 && p.command.ArgsRequired { 65 var reqnames []string 66 67 for _, arg := range p.positional { 68 if arg.isRemaining() { 69 break 70 } 71 72 reqnames = append(reqnames, "`"+arg.Name+"`") 73 } 74 75 if len(reqnames) == 0 { 76 return nil 77 } 78 79 var msg string 80 81 if len(reqnames) == 1 { 82 msg = fmt.Sprintf("the required argument %s was not provided", reqnames[0]) 83 } else { 84 msg = fmt.Sprintf("the required arguments %s and %s were not provided", 85 strings.Join(reqnames[:len(reqnames)-1], ", "), reqnames[len(reqnames)-1]) 86 } 87 88 p.err = newError(ErrRequired, msg) 89 return p.err 90 } 91 92 return nil 93 } 94 95 names := make([]string, 0, len(required)) 96 97 for _, k := range required { 98 names = append(names, "`"+k.String()+"'") 99 } 100 101 sort.Strings(names) 102 103 var msg string 104 105 if len(names) == 1 { 106 msg = fmt.Sprintf("the required flag %s was not specified", names[0]) 107 } else { 108 msg = fmt.Sprintf("the required flags %s and %s were not specified", 109 strings.Join(names[:len(names)-1], ", "), names[len(names)-1]) 110 } 111 112 p.err = newError(ErrRequired, msg) 113 return p.err 114} 115 116func (p *parseState) estimateCommand() error { 117 commands := p.command.sortedCommands() 118 cmdnames := make([]string, len(commands)) 119 120 for i, v := range commands { 121 cmdnames[i] = v.Name 122 } 123 124 var msg string 125 var errtype ErrorType 126 127 if len(p.retargs) != 0 { 128 c, l := closestChoice(p.retargs[0], cmdnames) 129 msg = fmt.Sprintf("Unknown command `%s'", p.retargs[0]) 130 errtype = ErrUnknownCommand 131 132 if float32(l)/float32(len(c)) < 0.5 { 133 msg = fmt.Sprintf("%s, did you mean `%s'?", msg, c) 134 } else if len(cmdnames) == 1 { 135 msg = fmt.Sprintf("%s. You should use the %s command", 136 msg, 137 cmdnames[0]) 138 } else { 139 msg = fmt.Sprintf("%s. Please specify one command of: %s or %s", 140 msg, 141 strings.Join(cmdnames[:len(cmdnames)-1], ", "), 142 cmdnames[len(cmdnames)-1]) 143 } 144 } else { 145 errtype = ErrCommandRequired 146 147 if len(cmdnames) == 1 { 148 msg = fmt.Sprintf("Please specify the %s command", cmdnames[0]) 149 } else { 150 msg = fmt.Sprintf("Please specify one command of: %s or %s", 151 strings.Join(cmdnames[:len(cmdnames)-1], ", "), 152 cmdnames[len(cmdnames)-1]) 153 } 154 } 155 156 return newError(errtype, msg) 157} 158 159func (p *Parser) parseOption(s *parseState, name string, option *Option, canarg bool, argument *string) (err error) { 160 if !option.canArgument() { 161 if argument != nil { 162 return newErrorf(ErrNoArgumentForBool, "bool flag `%s' cannot have an argument", option) 163 } 164 165 err = option.set(nil) 166 } else if argument != nil || (canarg && !s.eof()) { 167 var arg string 168 169 if argument != nil { 170 arg = *argument 171 } else { 172 arg = s.pop() 173 if argumentIsOption(arg) { 174 return newErrorf(ErrExpectedArgument, "expected argument for flag `%s', but got option `%s'", option, arg) 175 } 176 } 177 178 if option.tag.Get("unquote") != "false" { 179 arg, err = unquoteIfPossible(arg) 180 } 181 182 if err == nil { 183 err = option.set(&arg) 184 } 185 } else if option.OptionalArgument { 186 option.empty() 187 188 for _, v := range option.OptionalValue { 189 err = option.set(&v) 190 191 if err != nil { 192 break 193 } 194 } 195 } else { 196 err = newErrorf(ErrExpectedArgument, "expected argument for flag `%s'", option) 197 } 198 199 if err != nil { 200 if _, ok := err.(*Error); !ok { 201 err = newErrorf(ErrMarshal, "invalid argument for flag `%s' (expected %s): %s", 202 option, 203 option.value.Type(), 204 err.Error()) 205 } 206 } 207 208 return err 209} 210 211func (p *Parser) parseLong(s *parseState, name string, argument *string) error { 212 if option := s.lookup.longNames[name]; option != nil { 213 // Only long options that are required can consume an argument 214 // from the argument list 215 canarg := !option.OptionalArgument 216 217 return p.parseOption(s, name, option, canarg, argument) 218 } 219 220 return newErrorf(ErrUnknownFlag, "unknown flag `%s'", name) 221} 222 223func (p *Parser) splitShortConcatArg(s *parseState, optname string) (string, *string) { 224 c, n := utf8.DecodeRuneInString(optname) 225 226 if n == len(optname) { 227 return optname, nil 228 } 229 230 first := string(c) 231 232 if option := s.lookup.shortNames[first]; option != nil && option.canArgument() { 233 arg := optname[n:] 234 return first, &arg 235 } 236 237 return optname, nil 238} 239 240func (p *Parser) parseShort(s *parseState, optname string, argument *string) error { 241 if argument == nil { 242 optname, argument = p.splitShortConcatArg(s, optname) 243 } 244 245 for i, c := range optname { 246 shortname := string(c) 247 248 if option := s.lookup.shortNames[shortname]; option != nil { 249 // Only the last short argument can consume an argument from 250 // the arguments list, and only if it's non optional 251 canarg := (i+utf8.RuneLen(c) == len(optname)) && !option.OptionalArgument 252 253 if err := p.parseOption(s, shortname, option, canarg, argument); err != nil { 254 return err 255 } 256 } else { 257 return newErrorf(ErrUnknownFlag, "unknown flag `%s'", shortname) 258 } 259 260 // Only the first option can have a concatted argument, so just 261 // clear argument here 262 argument = nil 263 } 264 265 return nil 266} 267 268func (p *parseState) addArgs(args ...string) error { 269 for len(p.positional) > 0 && len(args) > 0 { 270 arg := p.positional[0] 271 272 if err := convert(args[0], arg.value, arg.tag); err != nil { 273 return err 274 } 275 276 if !arg.isRemaining() { 277 p.positional = p.positional[1:] 278 } 279 280 args = args[1:] 281 } 282 283 p.retargs = append(p.retargs, args...) 284 return nil 285} 286 287func (p *Parser) parseNonOption(s *parseState) error { 288 if len(s.positional) > 0 { 289 return s.addArgs(s.arg) 290 } 291 292 if cmd := s.lookup.commands[s.arg]; cmd != nil { 293 s.command.Active = cmd 294 cmd.fillParseState(s) 295 } else if (p.Options & PassAfterNonOption) != None { 296 // If PassAfterNonOption is set then all remaining arguments 297 // are considered positional 298 if err := s.addArgs(s.arg); err != nil { 299 return err 300 } 301 302 if err := s.addArgs(s.args...); err != nil { 303 return err 304 } 305 306 s.args = []string{} 307 } else { 308 return s.addArgs(s.arg) 309 } 310 311 return nil 312} 313 314func (p *Parser) showBuiltinHelp() error { 315 var b bytes.Buffer 316 317 p.WriteHelp(&b) 318 return newError(ErrHelp, b.String()) 319} 320 321func (p *Parser) printError(err error) error { 322 if err != nil && (p.Options&PrintErrors) != None { 323 fmt.Fprintln(os.Stderr, err) 324 } 325 326 return err 327} 328 329func (p *Parser) clearIsSet() { 330 p.eachCommand(func(c *Command) { 331 c.eachGroup(func(g *Group) { 332 for _, option := range g.options { 333 option.isSet = false 334 } 335 }) 336 }, true) 337} 338