From 75f06dd967b0e241432d701ee8a0d1c3eeee6d5e Mon Sep 17 00:00:00 2001 From: Jon Webb Date: Tue, 8 Oct 2024 17:56:06 -0400 Subject: [PATCH] release v0.1.0 --- LICENSE | 9 +++++++ README.md | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- getopt.go | 15 +++++++++-- 3 files changed, 99 insertions(+), 3 deletions(-) diff --git a/LICENSE b/LICENSE index 10c58c8..2cf1a0c 100644 --- a/LICENSE +++ b/LICENSE @@ -19,3 +19,12 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +-------------------------------------------------------------------------------- + +Portions of this software were derived from third-party works licensed under +terms compatible with the above MIT license: + +The algorithm for permuting arguments is from musl-libc, and is used under the +MIT License: +Copyright © 2005-2020 Rich Felker, et al. diff --git a/README.md b/README.md index 8b6d29a..b56d6cb 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,79 @@ # getopt -A Go `getopt`. \ No newline at end of file +Package `getopt` provides a zero-dependency Go implementation of the Unix getopt function for parsing command-line options. + +The `getopt` package supports parsing options using the POSIX convention, supporting short options (e.g., `-a`) and option arguments. It also supports GNU extensions, including support for long options (e.g., `--option`), options with optional arguments, and permuting non-option parameters. + +## Install + +``` +go get github.com/jon-codes/getopt +``` + +## Usage + +This package emulates the C `getopt` function, but uses a state machine to encapsulate variables (instead of the global `optind`, `optopt`, `optarg` used in C). Rather than implement a high-level interface for defining CLI flags, it aims to implement an accurate emulation of C `getopt` that can be used by higher-level tools. + +Collect all options into a slice: + +```go +state := getopt.NewState(os.Args) +config := getopt.Config{Opts: getopt.OptStr(`ab:c::`)} +opts, err := state.Parse(config) +``` + +Iterate over each option for finer control: + +```go +state := getopt.NewState(os.Args) +config := getopt.Config{Opts: getopt.OptStr(`ab:c::`)} + +for opt, err := range state.All(config) { + if err != nil { + break + } + switch opt.Char { + case 'a': + fmt.Printf("Found opt a\n") + case 'b': + fmt.Printf("Found opt b with arg %s\n", opt.OptArg) + case 'c': + fmt.Printf("Found opt c") + if opt.OptArg != "" { + fmt.Printf(" with arg %s", opt.OptArg) + } + fmt.Printf("\n") + } +} +``` +# Behavior + +This package uses [GNU libc] as a reference for behavior, since many expect the +non-standard features it provides. + +It supports the same configuration options as the GNU options via [Mode](https://pkg.go.dev/github.com/jon-codes/getopt#Mode): + - [ModeGNU](https://pkg.go.dev/github.com/jon-codes/getopt#ModeGNU): enables default behavior. + - [ModePosix](https://pkg.go.dev/github.com/jon-codes/getopt#ModePosix): enables the '+' compatibility mode, disabling permuting arguments and terminating parsing on the first parameter. + - [ModeInOrder](https://pkg.go.dev/github.com/jon-codes/getopt#ModeInOrder): enables the '-' optstring prefix mode, treating all parameters as though they were arguments to an option with character code 1. + +The specific libc function that is emulated can be configured via [Func](https://pkg.go.dev/github.com/jon-codes/getopt#Func): + - [FuncGetOpt](https://pkg.go.dev/github.com/jon-codes/getopt#FuncGetOpt): parse only traditional POSIX short options (e.g., -a). + - [FuncGetOptLong](https://pkg.go.dev/github.com/jon-codes/getopt#FuncGetOptLong): parse short options, and GNU extension long options (e.g., + --option). + - [FuncGetOptLongOnly](https://pkg.go.dev/github.com/jon-codes/getopt#FuncGetOptLongOnly): parse short and long options, but allow long options to begin with a single dash (like [pkg/flag](https://pkg.go.dev/flag)). + +The parser differs from GNU libc's getopt in the following ways: + - It accepts multi-byte runes in short and long option definitions. + - This package does not implement the same argument permutation as GNU libc. + The value of OptInd and order of arguments mid-parsing may differ, and only + the final order is validated against the GNU implementation. + +## API Documentation + +The full API documentation can be found at [pkg.go.dev](https://pkg.go.dev/github.com/jon-codes/getopt). + +## Acknowledgements + +The algorithm for permuting arguments is from [musl-libc](https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT), and is used under the linked MIT License: + + | Copyright © 2005-2020 Rich Felker, et al. diff --git a/getopt.go b/getopt.go index 1e97fda..4dee025 100644 --- a/getopt.go +++ b/getopt.go @@ -12,7 +12,7 @@ with optional arguments, and permuting non-option parameters. This package emulates the C getopt function, but uses a state machine to encapsulate variables (instead of the global optind, optopt, optarg used in C). Rather than implement a high-level interface for defining CLI flags, it aims to -implement an accurate emulation of getopt that can be used by higher-level +implement an accurate emulation of C getopt that can be used by higher-level tools. Collect all options into a slice: @@ -65,9 +65,19 @@ The specific libc function that is emulated can be configured via [Func]: The parser differs from GNU libc's getopt in the following ways: - It accepts multi-byte runes in short and long option definitions. + - This package does not implement the same argument permutation as GNU libc. + The value of OptInd and order of arguments mid-parsing may differ, and only + the final order is validated against the GNU implementation. + +# Acknowledgements + +The algorithm for permuting arguments is from [musl-libc], and is used under the linked MIT License: + + Copyright © 2005-2020 Rich Felker, et al. [getopt]: https://www.man7.org/linux/man-pages/man3/getopt.3.html [GNU libc]: https://www.gnu.org/software/libc/ +[musl-libc]: https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT */ package getopt @@ -305,7 +315,8 @@ func (s *State) GetOpt(c Config) (res Result, err error) { return res, ErrDone } - // TODO: cite permutation algo source (musl libc) + // The algorithm for permuting arguments is from [musl-libc], and is used under the MIT License: + // Copyright © 2005-2020 Rich Felker, et al. pStart := s.optInd if s.args[s.optInd] == "" || s.args[s.optInd] == "-" || []rune(s.args[s.optInd])[0] != '-' { switch c.Mode {