aboutsummaryrefslogtreecommitdiff
path: root/core/flags
diff options
context:
space:
mode:
authorJeroen van Rijn <Kelimion@users.noreply.github.com>2025-06-27 01:20:37 +0200
committerGitHub <noreply@github.com>2025-06-27 01:20:37 +0200
commit2e83e221419b480160dbf11dd09edf8b5fa97f32 (patch)
treebc5e666006bf43931bc793ac921061b5630db4d4 /core/flags
parentc51df72f1a8a21dd0064086dfc1186a3dd79e2ef (diff)
parentf72b2b153057e1d629c85af2ea7c54f7928198d5 (diff)
Merge branch 'master' into args-leak
Diffstat (limited to 'core/flags')
-rw-r--r--core/flags/constants.odin4
-rw-r--r--core/flags/doc.odin20
-rw-r--r--core/flags/errors.odin2
-rw-r--r--core/flags/example/example.odin6
-rw-r--r--core/flags/internal_assignment.odin8
-rw-r--r--core/flags/internal_parsing.odin2
-rw-r--r--core/flags/internal_validation.odin21
-rw-r--r--core/flags/parsing.odin4
-rw-r--r--core/flags/usage.odin30
-rw-r--r--core/flags/util.odin4
10 files changed, 59 insertions, 42 deletions
diff --git a/core/flags/constants.odin b/core/flags/constants.odin
index 6f5281928..dc2663e2a 100644
--- a/core/flags/constants.odin
+++ b/core/flags/constants.odin
@@ -19,7 +19,7 @@ SUBTAG_NAME :: "name"
SUBTAG_POS :: "pos"
SUBTAG_REQUIRED :: "required"
SUBTAG_HIDDEN :: "hidden"
-SUBTAG_VARIADIC :: "variadic"
+SUBTAG_MANIFOLD :: "manifold"
SUBTAG_FILE :: "file"
SUBTAG_PERMS :: "perms"
SUBTAG_INDISTINCT :: "indistinct"
@@ -28,7 +28,7 @@ TAG_USAGE :: "usage"
UNDOCUMENTED_FLAG :: "<This flag has not been documented yet.>"
-INTERNAL_VARIADIC_FLAG :: "varg"
+INTERNAL_OVERFLOW_FLAG :: #config(ODIN_CORE_FLAGS_OVERFLOW_FLAG, "overflow")
RESERVED_HELP_FLAG :: "help"
RESERVED_HELP_FLAG_SHORT :: "h"
diff --git a/core/flags/doc.odin b/core/flags/doc.odin
index b97547806..440acd52c 100644
--- a/core/flags/doc.odin
+++ b/core/flags/doc.odin
@@ -20,6 +20,17 @@ The format is similar to the Odin binary's way of handling compiler flags.
-<map>:<key>=<value> set map[key] to value
+Unhandled Arguments:
+
+All unhandled positional arguments are placed into the `overflow` field on a
+struct, if it exists. In UNIX-style parsing, the existence of a `--` on the
+command line will also pass all arguments afterwards into this field.
+
+If desired, the name of the field may be changed from `overflow` to any string
+by setting the `ODIN_CORE_FLAGS_OVERFLOW_FLAG` compile-time config option with
+`-define:ODIN_CORE_FLAGS_OVERFLOW_FLAG=<name>`.
+
+
Struct Tags:
Users of the `core:encoding/json` package may be familiar with using tags to
@@ -32,7 +43,7 @@ Under the `args` tag, there are the following subtags:
- `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.
+- `manifold=N`: take several arguments at once, 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.
@@ -47,8 +58,9 @@ 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.
+`manifold` may be given a number (`manifold=N`) above 1 to limit how many extra
+arguments it consumes at once. If this number is not specified, it will take as
+many arguments as can be converted to the underlying element type.
`file` determines the file open mode for an `os.Handle`.
@@ -160,7 +172,7 @@ at parse time.
--flag
--flag=argument
--flag argument
- --flag argument repeating-argument
+ --flag argument (manifold-argument)
`-flag` may also be substituted for `--flag`.
diff --git a/core/flags/errors.odin b/core/flags/errors.odin
index 6e48f6ccf..3d34a95d3 100644
--- a/core/flags/errors.odin
+++ b/core/flags/errors.odin
@@ -4,7 +4,7 @@ import "core:os"
Parse_Error_Reason :: enum {
None,
- // An extra positional argument was given, and there is no `varg` field.
+ // An extra positional argument was given, and there is no `overflow` field.
Extra_Positional,
// The underlying type does not support the string value it is being set to.
Bad_Value,
diff --git a/core/flags/example/example.odin b/core/flags/example/example.odin
index b1d7b58d6..a3af44790 100644
--- a/core/flags/example/example.odin
+++ b/core/flags/example/example.odin
@@ -107,14 +107,14 @@ main :: proc() {
// assignments: map[string]u8 `args:"name=assign" usage:"Number of jobs per worker."`,
- // (Variadic) Only available in UNIX style:
+ // (Manifold) Only available in UNIX style:
- // bots: [dynamic]string `args:"variadic=2,required"`,
+ // bots: [dynamic]string `args:"manifold=2,required"`,
verbose: bool `usage:"Show verbose output."`,
debug: bool `args:"hidden" usage:"print debug info"`,
- varg: [dynamic]string `usage:"Any extra arguments go here."`,
+ overflow: [dynamic]string `usage:"Any extra arguments go here."`,
}
opt: Options
diff --git a/core/flags/internal_assignment.odin b/core/flags/internal_assignment.odin
index 12ddb876f..5999dbf2d 100644
--- a/core/flags/internal_assignment.odin
+++ b/core/flags/internal_assignment.odin
@@ -33,9 +33,9 @@ push_positional :: #force_no_inline proc (model: ^$T, parser: ^Parser, arg: stri
field, index, has_pos_assigned := get_field_by_pos(model, pos)
if !has_pos_assigned {
- when intrinsics.type_has_field(T, INTERNAL_VARIADIC_FLAG) {
+ when intrinsics.type_has_field(T, INTERNAL_OVERFLOW_FLAG) {
// Add it to the fallback array.
- field = reflect.struct_field_by_name(T, INTERNAL_VARIADIC_FLAG)
+ field = reflect.struct_field_by_name(T, INTERNAL_OVERFLOW_FLAG)
} else {
return Parse_Error {
.Extra_Positional,
@@ -117,8 +117,8 @@ set_unix_flag :: proc(model: ^$T, parser: ^Parser, name: string) -> (future_args
case runtime.Type_Info_Dynamic_Array:
future_args = 1
if tag, ok := reflect.struct_tag_lookup(field.tag, TAG_ARGS); ok {
- if length, is_variadic := get_struct_subtag(tag, SUBTAG_VARIADIC); is_variadic {
- // Variadic arrays may specify how many arguments they consume at once.
+ if length, is_manifold := get_struct_subtag(tag, SUBTAG_MANIFOLD); is_manifold {
+ // Manifold arrays may specify how many arguments they consume at once.
// Otherwise, they take everything that's left.
if value, value_ok := strconv.parse_u64_of_base(length, 10); value_ok {
future_args = cast(int)value
diff --git a/core/flags/internal_parsing.odin b/core/flags/internal_parsing.odin
index 4e49f45b0..6d544e5af 100644
--- a/core/flags/internal_parsing.odin
+++ b/core/flags/internal_parsing.odin
@@ -95,7 +95,7 @@ parse_one_unix_arg :: proc(model: ^$T, parser: ^Parser, arg: string) -> (
// `--`, and only `--`.
// Everything from now on will be treated as an argument.
future_args = max(int)
- current_flag = INTERNAL_VARIADIC_FLAG
+ current_flag = INTERNAL_OVERFLOW_FLAG
return
}
}
diff --git a/core/flags/internal_validation.odin b/core/flags/internal_validation.odin
index afd05331c..cd903c3e5 100644
--- a/core/flags/internal_validation.odin
+++ b/core/flags/internal_validation.odin
@@ -59,7 +59,8 @@ validate_structure :: proc(model_type: $T, style: Parsing_Style, loc := #caller_
}
}
- if pos_str, has_pos := get_struct_subtag(args_tag, SUBTAG_POS); has_pos {
+ pos_str, has_pos := get_struct_subtag(args_tag, SUBTAG_POS)
+ if has_pos {
#partial switch specific_type_info in field.type.variant {
case runtime.Type_Info_Map:
fmt.panicf("%T.%s has `%s` defined, and this does not make sense on a map type.",
@@ -79,7 +80,7 @@ validate_structure :: proc(model_type: $T, style: Parsing_Style, loc := #caller_
fmt.assertf(!reflect.is_boolean(field.type), "%T.%s is a required boolean. This is disallowed.",
model_type, field.name, loc = loc)
- fmt.assertf(field.name != INTERNAL_VARIADIC_FLAG, "%T.%s is defined as required. This is disallowed.",
+ fmt.assertf(field.name != INTERNAL_OVERFLOW_FLAG, "%T.%s is defined as required. This is disallowed.",
model_type, field.name, loc = loc)
if len(requirement) > 0 {
@@ -109,24 +110,28 @@ validate_structure :: proc(model_type: $T, style: Parsing_Style, loc := #caller_
}
}
- if length, is_variadic := get_struct_subtag(args_tag, SUBTAG_VARIADIC); is_variadic {
+ if length, is_manifold := get_struct_subtag(args_tag, SUBTAG_MANIFOLD); is_manifold {
+ fmt.assertf(!has_pos,
+ "%T.%s has both `%s` and `%s` defined. This is disallowed.\n\tSuggestion: Use a dynamic array field named `%s` to accept unspecified positional arguments.",
+ model_type, field.name, SUBTAG_POS, SUBTAG_MANIFOLD, INTERNAL_OVERFLOW_FLAG, loc = loc)
+
if value, parse_ok := strconv.parse_u64_of_base(length, 10); parse_ok {
fmt.assertf(value > 0,
"%T.%s has `%s` set to %i. It must be greater than zero.",
- model_type, field.name, value, SUBTAG_VARIADIC, loc = loc)
+ model_type, field.name, value, SUBTAG_MANIFOLD, loc = loc)
fmt.assertf(value != 1,
- "%T.%s has `%s` set to 1. This has no effect.",
- model_type, field.name, SUBTAG_VARIADIC, loc = loc)
+ "%T.%s has `%s` set to 1. This is equivalent to not defining `%s`.",
+ model_type, field.name, SUBTAG_MANIFOLD, SUBTAG_MANIFOLD, loc = loc)
}
#partial switch specific_type_info in field.type.variant {
case runtime.Type_Info_Dynamic_Array:
fmt.assertf(style != .Odin,
"%T.%s has `%s` defined, but this only makes sense in UNIX-style parsing mode.",
- model_type, field.name, SUBTAG_VARIADIC, loc = loc)
+ model_type, field.name, SUBTAG_MANIFOLD, loc = loc)
case:
fmt.panicf("%T.%s has `%s` defined, but this only makes sense on dynamic arrays.",
- model_type, field.name, SUBTAG_VARIADIC, loc = loc)
+ model_type, field.name, SUBTAG_MANIFOLD, loc = loc)
}
}
diff --git a/core/flags/parsing.odin b/core/flags/parsing.odin
index 2d8ce34eb..989a9a1a6 100644
--- a/core/flags/parsing.odin
+++ b/core/flags/parsing.odin
@@ -6,7 +6,7 @@ package flags
Parsing_Style :: enum {
// Odin-style: `-flag`, `-flag:option`, `-map:key=value`
Odin,
- // UNIX-style: `-flag` or `--flag`, `--flag=argument`, `--flag argument repeating-argument`
+ // UNIX-style: `-flag` or `--flag`, `--flag=argument`, `--flag argument (manifold-argument)`
Unix,
}
@@ -61,7 +61,7 @@ parse :: proc(
}
case .Unix:
- // Support for `-flag argument (repeating-argument ...)`
+ // Support for `-flag argument (manifold-argument ...)`
future_args: int
current_flag: string
diff --git a/core/flags/usage.odin b/core/flags/usage.odin
index c42df7576..a44baec81 100644
--- a/core/flags/usage.odin
+++ b/core/flags/usage.odin
@@ -30,18 +30,18 @@ write_usage :: proc(out: io.Writer, data_type: typeid, program: string = "", sty
is_positional: bool,
is_required: bool,
is_boolean: bool,
- is_variadic: bool,
- variadic_length: int,
+ is_manifold: bool,
+ manifold_length: int,
}
//
// POSITIONAL+REQUIRED, POSITIONAL, REQUIRED, NON_REQUIRED+NON_POSITIONAL, ...
//
sort_flags :: proc(i, j: Flag) -> slice.Ordering {
- // `varg` goes to the end.
- if i.name == INTERNAL_VARIADIC_FLAG {
+ // `overflow` goes to the end.
+ if i.name == INTERNAL_OVERFLOW_FLAG {
return .Greater
- } else if j.name == INTERNAL_VARIADIC_FLAG {
+ } else if j.name == INTERNAL_OVERFLOW_FLAG {
return .Less
}
@@ -120,10 +120,10 @@ write_usage :: proc(out: io.Writer, data_type: typeid, program: string = "", sty
flag.is_required = true
flag.required_min, flag.required_max, _ = parse_requirements(requirement)
}
- if length_str, is_variadic := get_struct_subtag(args_tag, SUBTAG_VARIADIC); is_variadic {
- flag.is_variadic = true
+ if length_str, is_manifold := get_struct_subtag(args_tag, SUBTAG_MANIFOLD); is_manifold {
+ flag.is_manifold = true
if length, parse_ok := strconv.parse_u64_of_base(length_str, 10); parse_ok {
- flag.variadic_length = cast(int)length
+ flag.manifold_length = cast(int)length
}
}
}
@@ -147,15 +147,15 @@ write_usage :: proc(out: io.Writer, data_type: typeid, program: string = "", sty
case runtime.Type_Info_Dynamic_Array:
requirement_spec := describe_array_requirements(flag)
- if flag.is_variadic || flag.name == INTERNAL_VARIADIC_FLAG {
- if flag.variadic_length == 0 {
+ if flag.is_manifold || flag.name == INTERNAL_OVERFLOW_FLAG {
+ if flag.manifold_length == 0 {
flag.type_description = fmt.tprintf("<%v, ...>%s",
specific_type_info.elem.id,
requirement_spec)
} else {
flag.type_description = fmt.tprintf("<%v, %i at once>%s",
specific_type_info.elem.id,
- flag.variadic_length,
+ flag.manifold_length,
requirement_spec)
}
} else {
@@ -177,7 +177,7 @@ write_usage :: proc(out: io.Writer, data_type: typeid, program: string = "", sty
}
}
- if flag.name == INTERNAL_VARIADIC_FLAG {
+ if flag.name == INTERNAL_OVERFLOW_FLAG {
flag.full_length = len(flag.type_description)
} else if flag.is_boolean {
flag.full_length = len(flag_prefix) + len(flag.name) + len(flag.type_description)
@@ -201,13 +201,13 @@ write_usage :: proc(out: io.Writer, data_type: typeid, program: string = "", sty
strings.write_string(&builder, program)
for flag in visible_flags {
- if keep_it_short && !(flag.is_required || flag.is_positional || flag.name == INTERNAL_VARIADIC_FLAG) {
+ if keep_it_short && !(flag.is_required || flag.is_positional || flag.name == INTERNAL_OVERFLOW_FLAG) {
continue
}
strings.write_byte(&builder, ' ')
- if flag.name == INTERNAL_VARIADIC_FLAG {
+ if flag.name == INTERNAL_OVERFLOW_FLAG {
strings.write_string(&builder, "...")
continue
}
@@ -252,7 +252,7 @@ write_usage :: proc(out: io.Writer, data_type: typeid, program: string = "", sty
strings.write_byte(&builder, '\t')
- if flag.name == INTERNAL_VARIADIC_FLAG {
+ if flag.name == INTERNAL_OVERFLOW_FLAG {
strings.write_string(&builder, flag.type_description)
} else {
strings.write_string(&builder, flag_prefix)
diff --git a/core/flags/util.odin b/core/flags/util.odin
index f1bd60e75..ce7e2e36c 100644
--- a/core/flags/util.odin
+++ b/core/flags/util.odin
@@ -36,7 +36,7 @@ parse_or_exit :: proc(
args = program_args[1:]
}
- error := parse(model, args, style)
+ error := parse(model, args, style, true, true, allocator, loc)
if error != nil {
stderr := os.stream_from_handle(os.stderr)
@@ -95,7 +95,7 @@ Example:
import "core:flags"
import "core:fmt"
- subtag_example :: proc() {
+ get_subtag_example :: proc() {
args_tag := "precision=3,signed"
precision, has_precision := flags.get_subtag(args_tag, "precision")