diff options
author | Thomas Voss <mail@thomasvoss.com> | 2021-10-08 23:46:05 +0200 |
---|---|---|
committer | Thomas Voss <mail@thomasvoss.com> | 2021-10-08 23:46:05 +0200 |
commit | d4a272edf46ad64b5bb9f1d1305f471d1f15ecfa (patch) | |
tree | 8fe297cbb9091eecac286833a375bfcd88850b5d /getgopt.go |
[Meta] Initial commit
Diffstat (limited to 'getgopt.go')
-rw-r--r-- | getgopt.go | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/getgopt.go b/getgopt.go new file mode 100644 index 0000000..166430a --- /dev/null +++ b/getgopt.go @@ -0,0 +1,156 @@ +/* + * BSD Zero Clause License + * + * Copyright (c) 2021 Thomas Voss + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +package getgopt + +import ( + "fmt" + "os" +) + +const ( + errNoArg = "option requires an argument -- %c\n" + errBadArg = "unknown option -- %c\n" +) + +var ( + opt = 1 + optlen int + parsed bool + opts [255]option +) + +var ( + /* The argument to the matched flag */ + Optarg string + /* If true, print error messages */ + Opterr = true + /* During parsing this is the current index into os.Args being parsed. After parsing this is + * the index to the first non-option element of os.Args. + */ + Optind = 1 + /* The flag that caused the last parsing error */ + Optopt byte +) + +type option struct { + arg bool + used bool +} + +func parseArgs(optstring string) { + length := len(optstring) + + if (length > 0) && (optstring[0] == ':') { + Opterr = false + } + + for i, c := range optstring { + if c != ':' { + opts[c].used = true + opts[c].arg = ((i < length-1) && (optstring[i+1] == ':')) + } + } +} + +/* A function to parse command line flags. This function takes as it's arguments from first to last, + * the count of command line arguments, the array of command line arguments (os.Args), an option + * string, and a pointer to a byte where the current flag can be stored. When called the current + * flag will be stored in `optptr` and the global variables `Optarg`, `Opterr`, `Optind`, and + * `Optopt` may be set. + * + * If there are still more arguments to be parsed, the function will return true. Otherwise false is + * returned. This makes it very easy to incorperate into a for/while loop. + */ +func Getopt(argc int, argv []string, optstring string, optptr *byte) bool { + /* If we havem't parsed the optstring yet, parse it */ + if !parsed { + parseArgs(optstring) + parsed = true + } + + /* Instantly return false if the follow cases are met */ + if Optind >= argc || argv[Optind] == "" || argv[Optind][0] != '-' || + argv[Optind] == "-" || optstring == "" { + return false + } else if argv[Optind] == "--" { + Optind++ + return false + } + + /* For each element of argv we calculate its length */ + if opt == 1 { + optlen = len(argv[Optind]) + } + + /* The current flag */ + currFlag := argv[Optind][opt] + + if opts[currFlag].used { + if opts[currFlag].arg { + if opt == optlen-1 { + Optind += 2 + if Optind > argc { + Optopt = currFlag + if Opterr { + *optptr = '?' + fmt.Fprintf(os.Stderr, errNoArg, Optopt) + } else { + *optptr = ':' + } + } else { + Optarg = argv[Optind-1] + *optptr = currFlag + } + opt = 1 + return true + } + + /* If the opt takes an argument but it's not the last character in the + * string + */ + *optptr = currFlag + Optarg = string(argv[Optind][opt+1:]) + Optind++ + opt = 1 + } else { /* If the opt doesn't take an argument */ + if opt == optlen-1 { + opt = 1 + Optind++ + } else { + opt++ + } + + *optptr = currFlag + } + } else { /* If the arg isn't in optstring */ + if Opterr { + fmt.Fprintf(os.Stderr, errBadArg, argv[Optind][opt]) + } + Optopt = currFlag + *optptr = '?' + + if opt == optlen-1 { + Optind++ + opt = 1 + } else { + opt++ + } + } + + return true +} |