parser_private.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. package flags
  2. import (
  3. "bytes"
  4. "fmt"
  5. "os"
  6. "strings"
  7. "unicode/utf8"
  8. )
  9. type parseState struct {
  10. arg string
  11. args []string
  12. retargs []string
  13. err error
  14. command *Command
  15. lookup lookup
  16. }
  17. func (p *parseState) eof() bool {
  18. return len(p.args) == 0
  19. }
  20. func (p *parseState) pop() string {
  21. if p.eof() {
  22. return ""
  23. }
  24. p.arg = p.args[0]
  25. p.args = p.args[1:]
  26. return p.arg
  27. }
  28. func (p *parseState) peek() string {
  29. if p.eof() {
  30. return ""
  31. }
  32. return p.args[0]
  33. }
  34. func (p *parseState) checkRequired() error {
  35. required := p.lookup.required
  36. if len(required) == 0 {
  37. return nil
  38. }
  39. names := make([]string, 0, len(required))
  40. for k := range required {
  41. names = append(names, "`"+k.String()+"'")
  42. }
  43. var msg string
  44. if len(names) == 1 {
  45. msg = fmt.Sprintf("the required flag %s was not specified", names[0])
  46. } else {
  47. msg = fmt.Sprintf("the required flags %s and %s were not specified",
  48. strings.Join(names[:len(names)-1], ", "), names[len(names)-1])
  49. }
  50. p.err = newError(ErrRequired, msg)
  51. return p.err
  52. }
  53. func (p *parseState) estimateCommand() error {
  54. commands := p.command.sortedCommands()
  55. cmdnames := make([]string, len(commands))
  56. for i, v := range commands {
  57. cmdnames[i] = v.Name
  58. }
  59. var msg string
  60. if len(p.retargs) != 0 {
  61. c, l := closestChoice(p.retargs[0], cmdnames)
  62. msg = fmt.Sprintf("Unknown command `%s'", p.retargs[0])
  63. if float32(l)/float32(len(c)) < 0.5 {
  64. msg = fmt.Sprintf("%s, did you mean `%s'?", msg, c)
  65. } else if len(cmdnames) == 1 {
  66. msg = fmt.Sprintf("%s. You should use the %s command",
  67. msg,
  68. cmdnames[0])
  69. } else {
  70. msg = fmt.Sprintf("%s. Please specify one command of: %s or %s",
  71. msg,
  72. strings.Join(cmdnames[:len(cmdnames)-1], ", "),
  73. cmdnames[len(cmdnames)-1])
  74. }
  75. } else {
  76. if len(cmdnames) == 1 {
  77. msg = fmt.Sprintf("Please specify the %s command", cmdnames[0])
  78. } else {
  79. msg = fmt.Sprintf("Please specify one command of: %s or %s",
  80. strings.Join(cmdnames[:len(cmdnames)-1], ", "),
  81. cmdnames[len(cmdnames)-1])
  82. }
  83. }
  84. return newError(ErrRequired, msg)
  85. }
  86. func (p *Parser) parseOption(s *parseState, name string, option *Option, canarg bool, argument *string) (retoption *Option, err error) {
  87. if !option.canArgument() {
  88. if argument != nil {
  89. msg := fmt.Sprintf("bool flag `%s' cannot have an argument", option)
  90. return option, newError(ErrNoArgumentForBool, msg)
  91. }
  92. err = option.set(nil)
  93. } else if argument != nil {
  94. err = option.set(argument)
  95. } else if canarg && !s.eof() {
  96. arg := s.pop()
  97. err = option.set(&arg)
  98. } else if option.OptionalArgument {
  99. option.clear()
  100. for _, v := range option.OptionalValue {
  101. err = option.set(&v)
  102. if err != nil {
  103. break
  104. }
  105. }
  106. } else {
  107. msg := fmt.Sprintf("expected argument for flag `%s'", option)
  108. err = newError(ErrExpectedArgument, msg)
  109. }
  110. if err != nil {
  111. if _, ok := err.(*Error); !ok {
  112. msg := fmt.Sprintf("invalid argument for flag `%s' (expected %s): %s",
  113. option,
  114. option.value.Type(),
  115. err.Error())
  116. err = newError(ErrMarshal, msg)
  117. }
  118. }
  119. return option, err
  120. }
  121. func (p *Parser) parseLong(s *parseState, name string, argument *string) (option *Option, err error) {
  122. if option := s.lookup.longNames[name]; option != nil {
  123. // Only long options that are required can consume an argument
  124. // from the argument list
  125. canarg := !option.OptionalArgument
  126. return p.parseOption(s, name, option, canarg, argument)
  127. }
  128. return nil, newError(ErrUnknownFlag, fmt.Sprintf("unknown flag `%s'", name))
  129. }
  130. func (p *Parser) splitShortConcatArg(s *parseState, optname string) (string, *string) {
  131. c, n := utf8.DecodeRuneInString(optname)
  132. if n == len(optname) {
  133. return optname, nil
  134. }
  135. first := string(c)
  136. if option := s.lookup.shortNames[first]; option != nil && option.canArgument() {
  137. arg := optname[n:]
  138. return first, &arg
  139. }
  140. return optname, nil
  141. }
  142. func (p *Parser) parseShort(s *parseState, optname string, argument *string) (option *Option, err error) {
  143. if argument == nil {
  144. optname, argument = p.splitShortConcatArg(s, optname)
  145. }
  146. for i, c := range optname {
  147. shortname := string(c)
  148. if option = s.lookup.shortNames[shortname]; option != nil {
  149. // Only the last short argument can consume an argument from
  150. // the arguments list, and only if it's non optional
  151. canarg := (i+utf8.RuneLen(c) == len(optname)) && !option.OptionalArgument
  152. if _, err := p.parseOption(s, shortname, option, canarg, argument); err != nil {
  153. return option, err
  154. }
  155. } else {
  156. return nil, newError(ErrUnknownFlag, fmt.Sprintf("unknown flag `%s'", shortname))
  157. }
  158. // Only the first option can have a concatted argument, so just
  159. // clear argument here
  160. argument = nil
  161. }
  162. return option, nil
  163. }
  164. func (p *Parser) parseNonOption(s *parseState) error {
  165. if cmd := s.lookup.commands[s.arg]; cmd != nil {
  166. if err := s.checkRequired(); err != nil {
  167. return err
  168. }
  169. s.command.Active = cmd
  170. s.command = cmd
  171. s.lookup = cmd.makeLookup()
  172. } else if (p.Options & PassAfterNonOption) != None {
  173. // If PassAfterNonOption is set then all remaining arguments
  174. // are considered positional
  175. s.retargs = append(append(s.retargs, s.arg), s.args...)
  176. s.args = []string{}
  177. } else {
  178. s.retargs = append(s.retargs, s.arg)
  179. }
  180. return nil
  181. }
  182. func (p *Parser) showBuiltinHelp() error {
  183. var b bytes.Buffer
  184. p.WriteHelp(&b)
  185. return newError(ErrHelp, b.String())
  186. }
  187. func (p *Parser) printError(err error) error {
  188. if err != nil && (p.Options&PrintErrors) != None {
  189. fmt.Fprintln(os.Stderr, err)
  190. }
  191. return err
  192. }