aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--err.go12
-rw-r--r--opts.go56
-rw-r--r--opts_test.go6
3 files changed, 60 insertions, 14 deletions
diff --git a/err.go b/err.go
index b964c11..cbe96b4 100644
--- a/err.go
+++ b/err.go
@@ -2,14 +2,18 @@ package opts
import "fmt"
-type ErrBadOption rune
+// A BadOptionError describes an option that the user attempted to pass
+// which the developer did not register.
+type BadOptionError rune
-func (e ErrBadOption) Error() string {
+func (e BadOptionError) Error() string {
return fmt.Sprintf("unknown option ‘%c’", e)
}
-type ErrNoArgument rune
+// A NoArgumentError describes an option that the user attempted to pass
+// without an argument, which required an argument.
+type NoArgumentError rune
-func (e ErrNoArgument) Error() string {
+func (e NoArgumentError) Error() string {
return fmt.Sprintf("expected argument for option ‘%c’", e)
}
diff --git a/opts.go b/opts.go
index 8085c0a..3d07b0e 100644
--- a/opts.go
+++ b/opts.go
@@ -1,24 +1,66 @@
+// Package opts implements unicode-aware getopt(3)- and getopt_long(3)
+// flag parsing.
+//
+// The opts package aims to provide as simple an API as possible. If
+// your usecase requires more advanced argument-parsing or a more robust
+// API, this may not be the ideal package for you.
+//
+// While the opts package aims to closely follow the POSIX getopt(3) and
+// GNU getopt_long(3) C functions, there are some notable differences.
+// This package properly supports unicode flags, but also does not
+// support a leading ‘:’ in the [Get] function’s option string; all
+// user-facing I/O is delegrated to the caller.
package opts
+// ArgMode represents the whether or not a long-option takes an argument.
type ArgMode int
+// These tokens can be used to specify whether or not a long-option takes
+// an argument.
const (
- None ArgMode = iota
- Required
- Optional
+ None ArgMode = iota // long opt takes no argument
+ Required // long opt takes an argument
+ Optional // long opt optionally takes an argument
)
+// Flag represents a parsed command-line flag. Key corresponds to the
+// rune that was passed on the command-line, and Value corresponds to the
+// flags argument if one was provided. In the case of long-options Key
+// will map to the corresponding short-code, even if a long-option was
+// used.
type Flag struct {
- Key rune
- Value string
+ Key rune // the flag that was passed
+ Value string // the flags argument
}
+// LongOpt represents a long-option to attempt to parse. All long
+// options have a short-hand form represented by Short and a long-form
+// represented by Long. Arg is used to represent whether or not a takes
+// an argument.
+//
+// In the case that you want to parse a long-option which doesn’t have a
+// short-hand form, you can set Short to a negative integer.
type LongOpt struct {
Short rune
Long string
Arg ArgMode
}
+// Get parses the command-line arguments in args according to optstr.
+// Unlike POSIX-getopt(3), a leading ‘:’ in optstr is not supported and
+// will be ignored and no I/O is ever performed.
+//
+// Get will look for the flags listed in optstr (i.e., it will look for
+// ‘-a’, ‘-ß’, and ‘λ’ given optstr == "aßλ"). The optstr need not be
+// sorted in any particular order. If an option takes a required
+// argument, it can be suffixed by a colon. If an option takes an
+// optional argument, it can be suffixed by two colons. As an example,
+// optstr == "a::ßλ:" will search for ‘-a’ with an optional argument,
+// ‘-ß’ with no argument, and ‘-λ’ with a required argument.
+//
+// A successful parse returns the flags in the flags slice and the index
+// of the first non-option argument in optind. In the case of failure,
+// err will be one of [BadOptionError] or [NoArgumentError].
func Get(args []string, optstr string) (flags []Flag, optind int, err error) {
argmap := make(map[rune]bool)
@@ -48,13 +90,13 @@ func Get(args []string, optstr string) (flags []Flag, optind int, err error) {
switch {
case !ok:
- return nil, 0, ErrBadOption(r)
+ return nil, 0, BadOptionError(r)
case argp && j < len(rs)-1:
s = string(rs[j+1:])
case argp:
i++
if i >= len(args) {
- return nil, 0, ErrNoArgument(r)
+ return nil, 0, NoArgumentError(r)
}
s = args[i]
default:
diff --git a/opts_test.go b/opts_test.go
index a972867..2ea9334 100644
--- a/opts_test.go
+++ b/opts_test.go
@@ -35,7 +35,7 @@ func TestNoFlag(t *testing.T) {
func TestCNoArg(t *testing.T) {
args := []string{"foo", "-c"}
- assertGet(t, args, 0, 0, ErrNoArgument('c'))
+ assertGet(t, args, 0, 0, NoArgumentError('c'))
}
func TestCWithArg(t *testing.T) {
@@ -200,12 +200,12 @@ func TestΛAsArgToC(t *testing.T) {
func TestInvalidFlag(t *testing.T) {
args := []string{"foo", "-X"}
- assertGet(t, args, 0, 0, ErrBadOption('X'))
+ assertGet(t, args, 0, 0, BadOptionError('X'))
}
func TestInvalidFlagWithArg(t *testing.T) {
args := []string{"foo", "-X", "bar"}
- assertGet(t, args, 0, 0, ErrBadOption('X'))
+ assertGet(t, args, 0, 0, BadOptionError('X'))
}
func TestAAfterArg(t *testing.T) {