mirror of
https://github.com/odin-lang/Odin.git
synced 2025-12-31 10:22:08 +00:00
102 lines
2.6 KiB
Odin
102 lines
2.6 KiB
Odin
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 (manifold-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 (manifold-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
|
|
}
|