155 lines
3.4 KiB
Go
155 lines
3.4 KiB
Go
// getopt is a POSIX-compatible implementation of getopt(3) for Go.
|
|
//
|
|
// Example usage:
|
|
//
|
|
// import (
|
|
// "os"
|
|
// "git.sr.ht/~sircmpwn/getopt"
|
|
// )
|
|
//
|
|
// func main() {
|
|
// opts, optind, err := getopt.Getopts(os.Args, "abc:d:")
|
|
// if err != nil {
|
|
// panic(err)
|
|
// }
|
|
// for _, opt := range opts {
|
|
// switch opt.Option {
|
|
// case 'a':
|
|
// println("Option -a specified")
|
|
// case 'b':
|
|
// println("Option -b specified")
|
|
// case 'c':
|
|
// println("Option -c specified: " + opt.Value)
|
|
// case 'd':
|
|
// println("Option -d specified: " + opt.Value)
|
|
// }
|
|
// }
|
|
// println("Remaining arguments:")
|
|
// for _, arg := range os.Args[optind:] {
|
|
// println(arg)
|
|
// }
|
|
// }
|
|
//
|
|
// A flag[0]-like interface is also supported.
|
|
//
|
|
// import (
|
|
// "git.sr.ht/~sircmpwn/getopt"
|
|
// )
|
|
//
|
|
// func main() {
|
|
// a := getopt.Bool("a", false, "turn on option a")
|
|
// b := getopt.Int("b", 1, "set b to a numerical value")
|
|
// var opt string
|
|
// getopt.StringVar(&opt, "c", "", "let c be specified string")
|
|
//
|
|
// err := getopt.Parse()
|
|
// if err != nil {
|
|
// panic(err)
|
|
// }
|
|
//
|
|
// print("Value of a: ")
|
|
// println(*a)
|
|
// print("Value of b: ")
|
|
// println(*b)
|
|
// println("Value of c: " + opt)
|
|
//
|
|
// println("Remaining arguments:")
|
|
// for _, arg := range getopt.Args() {
|
|
// println(arg)
|
|
// }
|
|
// }
|
|
//
|
|
// [0]: https://golang.org/pkg/flag/
|
|
package getopt
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
)
|
|
|
|
// In the case of "-o example", Option is 'o' and "example" is Value. For
|
|
// options which do not take an argument, Value is "".
|
|
type Option struct {
|
|
Option rune
|
|
Value string
|
|
}
|
|
|
|
// This is returned when an unknown option is found in argv, but not in the
|
|
// option spec.
|
|
type UnknownOptionError rune
|
|
|
|
func (e UnknownOptionError) Error() string {
|
|
return fmt.Sprintf("%s: unknown option -%c", os.Args[0], rune(e))
|
|
}
|
|
|
|
// This is returned when an option with a mandatory argument is missing that
|
|
// argument.
|
|
type MissingOptionError rune
|
|
|
|
func (e MissingOptionError) Error() string {
|
|
return fmt.Sprintf("%s: expected argument for -%c", os.Args[0], rune(e))
|
|
}
|
|
|
|
// Getopts implements a POSIX-compatible options interface.
|
|
//
|
|
// Returns a slice of options and the index of the first non-option argument.
|
|
//
|
|
// If an error is returned, you must print it to stderr to be POSIX complaint.
|
|
func Getopts(argv []string, spec string) ([]Option, int, error) {
|
|
optmap := make(map[rune]bool)
|
|
runes := []rune(spec)
|
|
for i, rn := range spec {
|
|
if rn == ':' {
|
|
if i == 0 {
|
|
continue
|
|
}
|
|
optmap[runes[i-1]] = true
|
|
} else {
|
|
optmap[rn] = false
|
|
}
|
|
}
|
|
|
|
var (
|
|
i int
|
|
opts []Option
|
|
)
|
|
for i = 1; i < len(argv); i++ {
|
|
arg := argv[i]
|
|
runes = []rune(arg)
|
|
if len(arg) == 0 || arg == "-" {
|
|
break
|
|
}
|
|
if arg[0] != '-' {
|
|
break
|
|
}
|
|
if arg == "--" {
|
|
i++
|
|
break
|
|
}
|
|
for j, opt := range runes[1:] {
|
|
if optopt, ok := optmap[opt]; !ok {
|
|
opts = append(opts, Option{'?', ""})
|
|
return opts, i, UnknownOptionError(opt)
|
|
} else if optopt {
|
|
if j+1 < len(runes)-1 {
|
|
opts = append(opts, Option{opt, string(runes[j+2:])})
|
|
break
|
|
} else {
|
|
if i+1 >= len(argv) {
|
|
if len(spec) >= 1 && spec[0] == ':' {
|
|
opts = append(opts, Option{':', string(opt)})
|
|
} else {
|
|
return opts, i, MissingOptionError(opt)
|
|
}
|
|
} else {
|
|
opts = append(opts, Option{opt, argv[i+1]})
|
|
i++
|
|
}
|
|
}
|
|
} else {
|
|
opts = append(opts, Option{opt, ""})
|
|
}
|
|
}
|
|
}
|
|
return opts, i, nil
|
|
}
|