123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101 |
- package flags
- @require import "core:container/bit_array"
- @require import "core:fmt"
- Parsing_Style :: enum {
- // Odin-style: `-flag`, `-flag:option`, `-map:key=value`
- Odin,
- // UNIX-style: `-flag` or `--flag`, `--flag=argument`, `--flag argument repeating-argument`
- Unix,
- }
- /*
- Parse a slice of command-line arguments into an annotated struct.
- *Allocates Using Provided Allocator*
- By default, this proc will only allocate memory outside of its lifetime if it
- has to append to a dynamic array, set a map value, or set a cstring.
- The program is expected to free any allocations on `model` as a result of parsing.
- Inputs:
- - model: A pointer to an annotated struct with flag definitions.
- - args: A slice of strings, usually `os.args[1:]`.
- - style: The argument parsing style.
- - validate_args: If `true`, will ensure that all required arguments are set if no errors occurred.
- - strict: If `true`, will return on first error. Otherwise, parsing continues.
- - allocator: (default: context.allocator)
- - loc: The caller location for debugging purposes (default: #caller_location)
- Returns:
- - error: A union of errors; parsing, file open, a help request, or validation.
- */
- @(optimization_mode="favor_size")
- parse :: proc(
- model: ^$T,
- args: []string,
- style: Parsing_Style = .Odin,
- validate_args: bool = true,
- strict: bool = true,
- allocator := context.allocator,
- loc := #caller_location,
- ) -> (error: Error) {
- context.allocator = allocator
- validate_structure(model^, style, loc)
- parser: Parser
- defer {
- bit_array.destroy(&parser.filled_pos)
- bit_array.destroy(&parser.fields_set)
- }
- switch style {
- case .Odin:
- for arg in args {
- error = parse_one_odin_arg(model, &parser, arg)
- if strict && error != nil {
- return
- }
- }
- case .Unix:
- // Support for `-flag argument (repeating-argument ...)`
- future_args: int
- current_flag: string
- for i := 0; i < len(args); i += 1 {
- #no_bounds_check arg := args[i]
- future_args, current_flag, error = parse_one_unix_arg(model, &parser, arg)
- if strict && error != nil {
- return
- }
- for starting_future_args := future_args; future_args > 0; future_args -= 1 {
- i += 1
- if i == len(args) {
- if future_args == starting_future_args {
- return Parse_Error {
- .No_Value,
- fmt.tprintf("Expected a value for `%s` but none was given.", current_flag),
- }
- }
- break
- }
- #no_bounds_check arg = args[i]
- error = set_option(model, &parser, current_flag, arg)
- if strict && error != nil {
- return
- }
- }
- }
- }
- if error == nil && validate_args {
- return validate_arguments(model, &parser)
- }
- return
- }
|