aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--LICENSE14
-rw-r--r--err.go15
-rw-r--r--go.mod3
-rw-r--r--opts.go71
4 files changed, 103 insertions, 0 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..e663355
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,14 @@
+BSD Zero Clause License
+
+Copyright (c) 2023 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.
diff --git a/err.go b/err.go
new file mode 100644
index 0000000..b964c11
--- /dev/null
+++ b/err.go
@@ -0,0 +1,15 @@
+package opts
+
+import "fmt"
+
+type ErrBadOption rune
+
+func (e ErrBadOption) Error() string {
+ return fmt.Sprintf("unknown option ā€˜%cā€™", e)
+}
+
+type ErrNoArgument rune
+
+func (e ErrNoArgument) Error() string {
+ return fmt.Sprintf("expected argument for option ā€˜%cā€™", e)
+}
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..afe5f05
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,3 @@
+module git.sr.ht/~mango/opts
+
+go 1.21.4
diff --git a/opts.go b/opts.go
new file mode 100644
index 0000000..c7ab697
--- /dev/null
+++ b/opts.go
@@ -0,0 +1,71 @@
+package opts
+
+type ArgMode int
+
+const (
+ None ArgMode = iota
+ Required
+ Optional
+)
+
+type Flag struct {
+ Key rune
+ Value string
+}
+
+type LongOpt struct {
+ Short rune
+ Long string
+ Arg ArgMode
+}
+
+func Get(args []string, optstr string) (flags []Flag, optind int, err error) {
+ argmap := make(map[rune]bool)
+
+ rs := []rune(optstr)
+ for i, r := range rs {
+ if r != ':' {
+ argmap[r] = false
+ } else if i > 0 {
+ argmap[rs[i-1]] = true
+ }
+ }
+
+ for i := 1; i < len(args); i++ {
+ arg := args[i]
+ if len(arg) == 0 || arg == "-" || arg[0] != '-' {
+ optind = i
+ return
+ } else if arg == "--" {
+ optind = i + 1
+ return
+ }
+
+ rs := []rune(arg[1:])
+ outer:
+ for j, r := range rs {
+ argp, ok := argmap[r]
+ if !ok {
+ return nil, 0, ErrBadOption(r)
+ }
+
+ switch {
+ case argp && j < len(rs)-1:
+ s := string(rs[j+1:])
+ flags = append(flags, Flag{r, s})
+ break outer
+ case argp:
+ i++
+ if i >= len(args) {
+ return nil, 0, ErrNoArgument(r)
+ }
+ flags = append(flags, Flag{r, args[i]})
+ break outer
+ }
+ flags = append(flags, Flag{Key: r})
+ }
+ }
+
+ optind = len(args)
+ return
+}