-
-
Notifications
You must be signed in to change notification settings - Fork 672
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
3,599 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
BSD 3-Clause License | ||
|
||
Copyright (c) 2024, Feoramund | ||
|
||
Redistribution and use in source and binary forms, with or without | ||
modification, are permitted provided that the following conditions are met: | ||
|
||
1. Redistributions of source code must retain the above copyright notice, this | ||
list of conditions and the following disclaimer. | ||
|
||
2. Redistributions in binary form must reproduce the above copyright notice, | ||
this list of conditions and the following disclaimer in the documentation | ||
and/or other materials provided with the distribution. | ||
|
||
3. Neither the name of the copyright holder nor the names of its | ||
contributors may be used to endorse or promote products derived from | ||
this software without specific prior written permission. | ||
|
||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | ||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package flags | ||
|
||
import "core:time" | ||
|
||
// Set to true to compile with support for core named types disabled, as a | ||
// fallback in the event your platform does not support one of the types, or | ||
// you have no need for them and want a smaller binary. | ||
NO_CORE_NAMED_TYPES :: #config(ODIN_CORE_FLAGS_NO_CORE_NAMED_TYPES, false) | ||
|
||
// Override support for parsing `time` types. | ||
IMPORTING_TIME :: #config(ODIN_CORE_FLAGS_USE_TIME, time.IS_SUPPORTED) | ||
|
||
// Override support for parsing `net` types. | ||
// TODO: Update this when the BSDs are supported. | ||
IMPORTING_NET :: #config(ODIN_CORE_FLAGS_USE_NET, ODIN_OS == .Windows || ODIN_OS == .Linux || ODIN_OS == .Darwin) | ||
|
||
TAG_ARGS :: "args" | ||
SUBTAG_NAME :: "name" | ||
SUBTAG_POS :: "pos" | ||
SUBTAG_REQUIRED :: "required" | ||
SUBTAG_HIDDEN :: "hidden" | ||
SUBTAG_VARIADIC :: "variadic" | ||
SUBTAG_FILE :: "file" | ||
SUBTAG_PERMS :: "perms" | ||
SUBTAG_INDISTINCT :: "indistinct" | ||
|
||
TAG_USAGE :: "usage" | ||
|
||
UNDOCUMENTED_FLAG :: "<This flag has not been documented yet.>" | ||
|
||
INTERNAL_VARIADIC_FLAG :: "varg" | ||
|
||
RESERVED_HELP_FLAG :: "help" | ||
RESERVED_HELP_FLAG_SHORT :: "h" | ||
|
||
// If there are more than this number of flags in total, only the required and | ||
// positional flags will be shown in the one-line usage summary. | ||
ONE_LINE_FLAG_CUTOFF_COUNT :: 16 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
/* | ||
package flags implements a command-line argument parser. | ||
It works by using Odin's run-time type information to determine where and how | ||
to store data on a struct provided by the program. Type conversion is handled | ||
automatically and errors are reported with useful messages. | ||
Command-Line Syntax: | ||
Arguments are treated differently depending on how they're formatted. | ||
The format is similar to the Odin binary's way of handling compiler flags. | ||
``` | ||
type handling | ||
------------ ------------------------ | ||
<positional> depends on struct layout | ||
-<flag> set a bool true | ||
-<flag:option> set flag to option | ||
-<flag=option> set flag to option, alternative syntax | ||
-<map>:<key>=<value> set map[key] to value | ||
``` | ||
Struct Tags: | ||
Users of the `core:encoding/json` package may be familiar with using tags to | ||
annotate struct metadata. The same technique is used here to annotate where | ||
arguments should go and which are required. | ||
Under the `args` tag, there are the following subtags: | ||
- `name=S`: set `S` as the flag's name. | ||
- `pos=N`: place positional argument `N` into this flag. | ||
- `hidden`: hide this flag from the usage documentation. | ||
- `required`: cause verification to fail if this argument is not set. | ||
- `variadic`: take all remaining arguments when set, UNIX-style only. | ||
- `file`: for `os.Handle` types, file open mode. | ||
- `perms`: for `os.Handle` types, file open permissions. | ||
- `indistinct`: allow the setting of distinct types by their base type. | ||
`required` may be given a range specifier in the following formats: | ||
``` | ||
min | ||
<max | ||
min<max | ||
``` | ||
`max` is not inclusive in this range, as noted by the less-than `<` sign, so if | ||
you want to require 3 and only 3 arguments in a dynamic array, you would | ||
specify `required=3<4`. | ||
`variadic` may be given a number (`variadic=N`) above 1 to limit how many extra | ||
arguments it consumes. | ||
`file` determines the file open mode for an `os.Handle`. | ||
It accepts a string of flags that can be mixed together: | ||
- r: read | ||
- w: write | ||
- c: create, create the file if it doesn't exist | ||
- a: append, add any new writes to the end of the file | ||
- t: truncate, erase the file on open | ||
`perms` determines the file open permissions for an `os.Handle`. | ||
The permissions are represented by three numbers in octal format. The first | ||
number is the owner, the second is the group, and the third is other. Read is | ||
represented by 4, write by 2, and execute by 1. | ||
These numbers are added together to get combined permissions. For example, 644 | ||
represents read/write for the owner, read for the group, and read for other. | ||
Note that this may only have effect on UNIX-like platforms. By default, `perms` | ||
is set to 444 when only reading and 644 when writing. | ||
`indistinct` tells the parser that it's okay to treat distinct types as their | ||
underlying base type. Normally, the parser will hand those types off to the | ||
custom type setter (more about that later) if one is available, if it doesn't | ||
know how to handle the type. | ||
Usage Tag: | ||
There is also the `usage` tag, which is a plain string to be printed alongside | ||
the flag in the usage output. If `usage` contains a newline, it will be | ||
properly aligned when printed. | ||
All surrounding whitespace is trimmed when formatting with multiple lines. | ||
Supported Flag Data Types: | ||
- all booleans | ||
- all integers | ||
- all floats | ||
- all enums | ||
- all complex numbers | ||
- all quaternions | ||
- all bit_sets | ||
- `string` and `cstring` | ||
- `rune` | ||
- `os.Handle` | ||
- `time.Time` | ||
- `datetime.DateTime` | ||
- `net.Host_Or_Endpoint`, | ||
- additional custom types, see Custom Types below | ||
- `dynamic` arrays with element types of the above | ||
- `map[string]`s or `map[cstring]`s with value types of the above | ||
Validation: | ||
The parser will ensure `required` arguments are set, if no errors occurred | ||
during parsing. This is on by default. | ||
Additionally, you may call `register_flag_checker` to set your own argument | ||
validation procedure that will be called after the default checker. | ||
Strict: | ||
The parser will return on the first error and stop parsing. This is on by | ||
default. Otherwise, all arguments that can be parsed, will be, and only the | ||
last error is returned. | ||
Error Messages: | ||
All error message strings are allocated using the context's `temp_allocator`, | ||
so if you need them to persist, make sure to clone the underlying `message`. | ||
Help: | ||
By default, `-h` and `-help` are reserved flags which raise their own error | ||
type when set, allowing the program to handle the request differently from | ||
other errors. | ||
Custom Types: | ||
You may specify your own type setter for program-specific structs and other | ||
named types. Call `register_type_setter` with an appropriate proc before | ||
calling any of the parsing procs. | ||
A compliant `Custom_Type_Setter` must return three values: | ||
- an error message if one occurred, | ||
- a boolean indicating if the proc handles the type, and | ||
- an `Allocator_Error` if any occurred. | ||
If the setter does not handle the type, simply return without setting any of | ||
the values. | ||
UNIX-style: | ||
This package also supports parsing arguments in a limited flavor of UNIX. | ||
Odin and UNIX style are mutually exclusive, and which one to be used is chosen | ||
at parse time. | ||
``` | ||
--flag | ||
--flag=argument | ||
--flag argument | ||
--flag argument repeating-argument | ||
``` | ||
`-flag` may also be substituted for `--flag`. | ||
Do note that map flags are not currently supported in this parsing style. | ||
Example: | ||
A complete example is given in the `example` subdirectory. | ||
*/ | ||
package flags |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package flags | ||
|
||
import "base:runtime" | ||
import "core:net" | ||
import "core:os" | ||
|
||
Parse_Error_Reason :: enum { | ||
None, | ||
// An extra positional argument was given, and there is no `varg` field. | ||
Extra_Positional, | ||
// The underlying type does not support the string value it is being set to. | ||
Bad_Value, | ||
// No flag was given by the user. | ||
No_Flag, | ||
// No value was given by the user. | ||
No_Value, | ||
// The flag on the struct is missing. | ||
Missing_Flag, | ||
// The type itself isn't supported. | ||
Unsupported_Type, | ||
} | ||
|
||
Unified_Parse_Error_Reason :: union #shared_nil { | ||
Parse_Error_Reason, | ||
runtime.Allocator_Error, | ||
net.Parse_Endpoint_Error, | ||
} | ||
|
||
// Raised during parsing, naturally. | ||
Parse_Error :: struct { | ||
reason: Unified_Parse_Error_Reason, | ||
message: string, | ||
} | ||
|
||
// Raised during parsing. | ||
// Provides more granular information than what just a string could hold. | ||
Open_File_Error :: struct { | ||
filename: string, | ||
errno: os.Errno, | ||
mode: int, | ||
perms: int, | ||
} | ||
|
||
// Raised during parsing. | ||
Help_Request :: distinct bool | ||
|
||
|
||
// Raised after parsing, during validation. | ||
Validation_Error :: struct { | ||
message: string, | ||
} | ||
|
||
Error :: union { | ||
Parse_Error, | ||
Open_File_Error, | ||
Help_Request, | ||
Validation_Error, | ||
} |
Oops, something went wrong.