1// Copyright 2013 Google Inc. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5// Package getopt (v1) provides traditional getopt processing for implementing 6// commands that use traditional command lines. The standard Go flag package 7// cannot be used to write a program that parses flags the way ls or ssh does, 8// for example. 9// 10// A new version of this package (v2) (whose package name is also getopt) is 11// available as: 12// 13// "github.com/pborman/getopt/v2" 14// 15// Getopt supports functionality found in both the standard BSD getopt as well 16// as (one of the many versions of) the GNU getopt_long. Being a Go package, 17// this package makes common usage easy, but still enables more controlled usage 18// if needed. 19// 20// Typical usage: 21// 22// // Declare the flags to be used 23// helpFlag := getopt.Bool('?', "display help") 24// cmdFlag := getopt.StringLong("command", 'c', "", "the command) 25// 26// func main() { 27// // Parse the program arguments 28// getopt.Parse() 29// // Get the remaining positional parameters 30// args := getopt.Args() 31// 32// If you don't want the program to exit on error, use getopt.Getopt: 33// 34// err := getopt.Getopt(nil) 35// if err != nil { 36// // code to handle error 37// fmt.Fprintln(os.Stderr, err) 38// } 39// 40// Support is provided for both short (-f) and long (--flag) options. A single 41// option may have both a short and a long name. Each option may be a flag or a 42// value. A value takes an argument. 43// 44// Declaring no long names causes this package to process arguments like the 45// traditional BSD getopt. 46// 47// Short flags may be combined into a single parameter. For example, "-a -b -c" 48// may also be expressed "-abc". Long flags must stand on their own "--alpha 49// --beta" 50// 51// Values require an argument. For short options the argument may either be 52// immediately following the short name or as the next argument. Only one short 53// value may be combined with short flags in a single argument; the short value 54// must be after all short flags. For example, if f is a flag and v is a value, 55// then: 56// 57// -vvalue (sets v to "value") 58// -v value (sets v to "value") 59// -fvvalue (sets f, and sets v to "value") 60// -fv value (sets f, and sets v to "value") 61// -vf value (set v to "f" and value is the first parameter) 62// 63// For the long value option val: 64// 65// --val value (sets val to "value") 66// --val=value (sets val to "value") 67// --valvalue (invalid option "valvalue") 68// 69// Values with an optional value only set the value if the value is part of the 70// same argument. In any event, the option count is increased and the option is 71// marked as seen. 72// 73// -v -f (sets v and f as being seen) 74// -vvalue -f (sets v to "value" and sets f) 75// --val -f (sets v and f as being seen) 76// --val=value -f (sets v to "value" and sets f) 77// 78// There is no convience function defined for making the value optional. The 79// SetOptional method must be called on the actual Option. 80// 81// v := String("val", 'v', "", "the optional v") 82// Lookup("v").SetOptional() 83// 84// var s string 85// StringVar(&s, "val", 'v', "the optional v).SetOptional() 86// 87// Parsing continues until the first non-option or "--" is encountered. 88// 89// The short name "-" can be used, but it either is specified as "-" or as part 90// of a group of options, for example "-f-". If there are no long options 91// specified then "--f" could also be used. If "-" is not declared as an option 92// then the single "-" will also terminate the option processing but unlike 93// "--", the "-" will be part of the remaining arguments. 94// 95// Normally the parsing is performed by calling the Parse function. If it is 96// important to see the order of the options then the Getopt function should be 97// used. The standard Parse function does the equivalent of: 98// 99// func Parse() { 100// if err := getopt.Getopt(os.Args, nil); err != nil { 101// fmt.Fprintln(os.Stderr, err) 102// s.usage() 103// os.Exit(1) 104// } 105// 106// When calling Getopt it is the responsibility of the caller to print any 107// errors. 108// 109// Normally the default option set, CommandLine, is used. Other option sets may 110// be created with New. 111// 112// After parsing, the sets Args will contain the non-option arguments. If an 113// error is encountered then Args will begin with argument that caused the 114// error. 115// 116// It is valid to call a set's Parse a second time to amend the current set of 117// flags or values. As an example: 118// 119// var a = getopt.Bool('a', "", "The a flag") 120// var b = getopt.Bool('b', "", "The a flag") 121// var cmd = "" 122// 123// var opts = getopt.CommandLine 124// 125// opts.Parse(os.Args) 126// if opts.NArgs() > 0 { 127// cmd = opts.Arg(0) 128// opts.Parse(opts.Args()) 129// } 130// 131// If called with set to { "prog", "-a", "cmd", "-b", "arg" } then both and and 132// b would be set, cmd would be set to "cmd", and opts.Args() would return { 133// "arg" }. 134// 135// Unless an option type explicitly prohibits it, an option may appear more than 136// once in the arguments. The last value provided to the option is the value. 137// 138// SYNTAX 139// 140// For each option type there are an unfortunately large number of ways, 8, to 141// initialize the option. This number is derived from three attributes: 142// 143// 1) Short or Long name 144// 2) Normal vs Var 145// 3) Command Line vs Option Set 146// 147// The first two variations provide 4 signature: 148// 149// Option(name rune, [value type,] helpvalue... string) 150// OptionLong(name string, short rune, [value type,] helpvalue... string) 151// OptionVar(p *type, name rune, helpvalue... string) 152// OptionVarLong(p *type, name string, short rune, helpvalue... string) 153// 154// Foo can actually be expressed in terms of FooLong: 155// 156// func Foo(name rune, value type, helpvalue... string) *type { 157// return FooLong("", name, value, helpvalue...) 158// } 159// 160// Normally Foo is used, unless long options are needed. Setting short to 0 161// creates only a long option. 162// 163// The difference bentween Foo and FooVar is that you pass a pointer, p, to the 164// location of the value to FooVar. The default value is simply *p. The 165// initial value of *p is the defaut value of the option. 166// 167// Foo is actually a wrapper around FooVar: 168// 169// func Foo(name rune, value type, helpvalue... string) *type { 170// p := value 171// FooVar(&p, name, helpvalue... string) 172// return &p 173// } 174// 175// 176// The third variation provides a top-level function and a method on a Set: 177// 178// func Option(...) 179// func (s *Set) Option(...) 180// 181// The top-level function is simply: 182// 183// func Option(...) *type { 184// return CommandLine.Option(...) { 185// } 186// 187// To simplfy documentation, typically only the main top-level function is fully 188// documented. The others will have documentation when there is something 189// special about them. 190// 191// VALUEHELP 192// 193// All non-flag options are created with a "valuehelp" as the last parameter. 194// Valuehelp should be 0, 1, or 2 strings. The first string, if provided, is 195// the usage message for the option. If the second string, if provided, is the 196// name to use for the value when displaying the usage. If not provided the 197// term "value" is assumed. 198// 199// The usage message for the option created with 200// 201// StringLong("option", 'o', "defval", "a string of letters") 202// 203// is 204// 205// -o, -option=value 206// 207// StringLong("option", 'o', "defval", "a string of letters", "string") 208// 209// is 210// 211// -o, -option=string 212package getopt 213 214import ( 215 "fmt" 216 "io" 217 "os" 218 "path" 219 "sort" 220 "strings" 221) 222 223// stderr allows tests to capture output to standard error. 224var stderr io.Writer = os.Stderr 225 226// exit allows tests to capture an os.Exit call 227var exit = os.Exit 228 229// DisplayWidth is used to determine where to split usage long lines. 230var DisplayWidth = 80 231 232// HelpColumn is the maximum column position that help strings start to display 233// at. If the option usage is too long then the help string will be displayed 234// on the next line. For example: 235// 236// -a this is the a flag 237// -u, --under=location 238// the u flag's usage is quite long 239var HelpColumn = 20 240 241// PrintUsage prints the usage of the program to w. 242func (s *Set) PrintUsage(w io.Writer) { 243 sort.Sort(s.options) 244 flags := "" 245 246 // Build up the list of short flag names and also compute 247 // how to display the option in the longer help listing. 248 // We also keep track of the longest option usage string 249 // that is no more than HelpColumn-3 bytes (at which point 250 // we use two lines to display the help). The three 251 // is for the leading space and the two spaces before the 252 // help string. 253 for _, opt := range s.options { 254 if opt.name == "" { 255 opt.name = "value" 256 } 257 if opt.uname == "" { 258 opt.uname = opt.usageName() 259 } 260 if opt.flag && opt.short != 0 && opt.short != '-' { 261 flags += string(opt.short) 262 } 263 } 264 265 var opts []string 266 267 // The short option - is special 268 if s.shortOptions['-'] != nil { 269 opts = append(opts, "-") 270 } 271 272 // If we have a bundle of flags, add them to the list 273 if flags != "" { 274 opts = append(opts, "-"+flags) 275 } 276 277 // Now append all the long options and options that require 278 // values. 279 for _, opt := range s.options { 280 if opt.flag { 281 if opt.short != 0 { 282 continue 283 } 284 flags = "--" + opt.long 285 } else if opt.short != 0 { 286 flags = "-" + string(opt.short) + " " + opt.name 287 } else { 288 flags = "--" + string(opt.long) + " " + opt.name 289 } 290 opts = append(opts, flags) 291 } 292 flags = strings.Join(opts, "] [") 293 if flags != "" { 294 flags = " [" + flags + "]" 295 } 296 if s.parameters != "" { 297 flags += " " + s.parameters 298 } 299 fmt.Fprintf(w, "Usage: %s%s\n", s.program, flags) 300 s.PrintOptions(w) 301} 302 303// PrintOptions prints the list of options in s to w. 304func (s *Set) PrintOptions(w io.Writer) { 305 sort.Sort(s.options) 306 max := 4 307 for _, opt := range s.options { 308 if opt.name == "" { 309 opt.name = "value" 310 } 311 if opt.uname == "" { 312 opt.uname = opt.usageName() 313 } 314 if max < len(opt.uname) && len(opt.uname) <= HelpColumn-3 { 315 max = len(opt.uname) 316 } 317 } 318 // Now print one or more usage lines per option. 319 for _, opt := range s.options { 320 if opt.uname != "" { 321 opt.help = strings.TrimSpace(opt.help) 322 if len(opt.help) == 0 { 323 fmt.Fprintf(w, " %s\n", opt.uname) 324 continue 325 } 326 help := strings.Split(opt.help, "\n") 327 // If they did not put in newlines then we will insert 328 // them to keep the help messages from wrapping. 329 if len(help) == 1 { 330 help = breakup(help[0], DisplayWidth-HelpColumn) 331 } 332 if len(opt.uname) <= max { 333 fmt.Fprintf(w, " %-*s %s\n", max, opt.uname, help[0]) 334 help = help[1:] 335 } else { 336 fmt.Fprintf(w, " %s\n", opt.uname) 337 } 338 for _, s := range help { 339 fmt.Fprintf(w, " %-*s %s\n", max, " ", s) 340 } 341 } 342 } 343} 344 345// breakup breaks s up into strings no longer than max bytes. 346func breakup(s string, max int) []string { 347 var a []string 348 349 for { 350 // strip leading spaces 351 for len(s) > 0 && s[0] == ' ' { 352 s = s[1:] 353 } 354 // If the option is no longer than the max just return it 355 if len(s) <= max { 356 if len(s) != 0 { 357 a = append(a, s) 358 } 359 return a 360 } 361 x := max 362 for s[x] != ' ' { 363 // the first word is too long?! 364 if x == 0 { 365 x = max 366 for x < len(s) && s[x] != ' ' { 367 x++ 368 } 369 if x == len(s) { 370 x-- 371 } 372 break 373 } 374 x-- 375 } 376 for s[x] == ' ' { 377 x-- 378 } 379 a = append(a, s[:x+1]) 380 s = s[x+1:] 381 } 382} 383 384// Parse uses Getopt to parse args using the options set for s. The first 385// element of args is used to assign the program for s if it is not yet set. On 386// error, Parse displays the error message as well as a usage message on 387// standard error and then exits the program. 388func (s *Set) Parse(args []string) { 389 if err := s.Getopt(args, nil); err != nil { 390 fmt.Fprintln(stderr, err) 391 s.usage() 392 exit(1) 393 } 394} 395 396// Parse uses Getopt to parse args using the options set for s. The first 397// element of args is used to assign the program for s if it is not yet set. 398// Getop calls fn, if not nil, for each option parsed. 399// 400// Getopt returns nil when all options have been processed (a non-option 401// argument was encountered, "--" was encountered, or fn returned false). 402// 403// On error getopt returns a refernce to an InvalidOption (which implements 404// the error interface). 405func (s *Set) Getopt(args []string, fn func(Option) bool) (err error) { 406 s.State = InProgress 407 defer func() { 408 if s.State == InProgress { 409 switch { 410 case err != nil: 411 s.State = Failure 412 case len(s.args) == 0: 413 s.State = EndOfArguments 414 default: 415 s.State = Unknown 416 } 417 } 418 }() 419 if fn == nil { 420 fn = func(Option) bool { return true } 421 } 422 if len(args) == 0 { 423 return nil 424 } 425 426 if s.program == "" { 427 s.program = path.Base(args[0]) 428 } 429 args = args[1:] 430Parsing: 431 for len(args) > 0 { 432 arg := args[0] 433 s.args = args 434 args = args[1:] 435 436 // end of options? 437 if arg == "" || arg[0] != '-' { 438 s.State = EndOfOptions 439 return nil 440 } 441 442 if arg == "-" { 443 goto ShortParsing 444 } 445 446 // explicitly request end of options? 447 if arg == "--" { 448 s.args = args 449 s.State = DashDash 450 return nil 451 } 452 453 // Long option processing 454 if len(s.longOptions) > 0 && arg[1] == '-' { 455 e := strings.IndexRune(arg, '=') 456 var value string 457 if e > 0 { 458 value = arg[e+1:] 459 arg = arg[:e] 460 } 461 opt := s.longOptions[arg[2:]] 462 // If we are processing long options then --f is -f 463 // if f is not defined as a long option. 464 // This lets you say --f=false 465 if opt == nil && len(arg[2:]) == 1 { 466 opt = s.shortOptions[rune(arg[2])] 467 } 468 if opt == nil { 469 return unknownOption(arg[2:]) 470 } 471 opt.isLong = true 472 // If we require an option and did not have an = 473 // then use the next argument as an option. 474 if !opt.flag && e < 0 && !opt.optional { 475 if len(args) == 0 { 476 return missingArg(opt) 477 } 478 value = args[0] 479 args = args[1:] 480 } 481 opt.count++ 482 483 if err := opt.value.Set(value, opt); err != nil { 484 return setError(opt, value, err) 485 } 486 487 if !fn(opt) { 488 s.State = Terminated 489 return nil 490 } 491 continue Parsing 492 } 493 494 // Short option processing 495 arg = arg[1:] // strip - 496 ShortParsing: 497 for i, c := range arg { 498 opt := s.shortOptions[c] 499 if opt == nil { 500 // In traditional getopt, if - is not registered 501 // as an option, a lone - is treated as 502 // if there were a -- in front of it. 503 if arg == "-" { 504 s.State = Dash 505 return nil 506 } 507 return unknownOption(c) 508 } 509 opt.isLong = false 510 opt.count++ 511 var value string 512 if !opt.flag { 513 value = arg[1+i:] 514 if value == "" && !opt.optional { 515 if len(args) == 0 { 516 return missingArg(opt) 517 } 518 value = args[0] 519 args = args[1:] 520 } 521 } 522 if err := opt.value.Set(value, opt); err != nil { 523 return setError(opt, value, err) 524 } 525 if !fn(opt) { 526 s.State = Terminated 527 return nil 528 } 529 if !opt.flag { 530 continue Parsing 531 } 532 } 533 } 534 s.args = []string{} 535 return nil 536} 537