1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
# `core:flags`
`core:flags` is a complete command-line argument parser for the Odin programming
language.
It works by using Odin's run-time type information to determine where and how
to store data on a struct provided by the user. Type conversion is handled
automatically and errors are reported with useful messages.
## Struct Tags
Users of the `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 `flags` tag:
- `name=S`, alias a struct field to `S`
- `pos=N`, place positional argument `N` into this field
- `hidden`, hide this field from the usage documentation
- `required`, cause verification to fail if this argument is not set
There is also the `usage` tag, which is a plain string to be printed alongside
the flag in the usage output.
## Syntax
Arguments are treated differently 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 to true
-<flag:option> set flag to option
-<flag=option> set flag to option, alternative syntax
-<map>:<key>=<value> set map[key] to value
```
## Complete Example
```odin
package main
import "core:fmt"
import "core:mem"
import "core:os"
import "core:path/filepath"
import "core:flags"
main :: proc() {
Options :: struct {
file: string `flags:"pos=0,required" usage:"input file"`,
out: string `flags:"pos=1" usage:"output file"`,
retry_count: uint `flags:"name=retries" usage:"times to retry process"`,
debug: bool `flags:"hidden" usage:"print debug info"`,
collection: map[string]string `usage:"path aliases"`,
}
opt: Options
program: string
args: []string
switch len(os.args) {
case 0:
flags.print_usage(&opt)
os.exit(0)
case:
program = filepath.base(os.args[0])
args = os.args[1:]
}
err := flags.parse(&opt, args)
switch subtype in err {
case mem.Allocator_Error:
fmt.println("allocation error:", subtype)
os.exit(1)
case flags.Parse_Error:
fmt.println(subtype.message)
os.exit(1)
case flags.Validation_Error:
fmt.println(subtype.message)
os.exit(1)
case flags.Help_Request:
flags.print_usage(&opt, program)
os.exit(0)
}
fmt.printf("%#v\n", opt)
}
```
```
$ ./odin-flags
required argument `file` was not set
$ ./odin-flags -help
Usage:
odin-flags file [out] [-collection] [-retries]
Flags:
-file:<string> input file
-out:<string> output file
-collection:<string>=<string> path aliases
-retries:<uint> times to retry process
$ ./odin-flags -retries:-3
unable to set `retries` of type uint to `-3`
$ ./odin-flags data -retries:3 -collection:core=./core -collection:runtime=./runtime
Options{
file = "data",
out = "",
retry_count = 3,
debug = false,
collection = map[
core = "./core",
runtime = "./runtime",
],
}
```
|