aboutsummaryrefslogtreecommitdiff
path: root/core/flags/example/example.odin
blob: a3af44790953261d6a5b96dc82f70085d74a4d92 (plain)
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
125
126
127
128
129
130
131
132
package core_flags_example

import "base:runtime"
import "core:flags"
import "core:fmt"
import "core:net"
import "core:os"
import "core:time/datetime"


Fixed_Point1_1 :: struct {
	integer: u8,
	fractional: u8,
}

Optimization_Level :: enum {
	Slow,
	Fast,
	Warp_Speed,
	Ludicrous_Speed,
}

// It's simple but powerful.
my_custom_type_setter :: proc(
	data: rawptr,
	data_type: typeid,
	unparsed_value: string,
	args_tag: string,
) -> (
	error: string,
	handled: bool,
	alloc_error: runtime.Allocator_Error,
) {
	if data_type == Fixed_Point1_1 {
		handled = true
		ptr := cast(^Fixed_Point1_1)data

		// precision := flags.get_subtag(args_tag, "precision")

		if len(unparsed_value) == 3 {
			ptr.integer = unparsed_value[0] - '0'
			ptr.fractional = unparsed_value[2] - '0'
		} else {
			error = "Incorrect format. Must be in the form of `i.f`."
		}

		// Perform sanity checking here in the type parsing phase.
		//
		// The validation phase is flag-specific.
		if !(0 <= ptr.integer && ptr.integer < 10) || !(0 <= ptr.fractional && ptr.fractional < 10) {
			error = "Incorrect format. Must be between `0.0` and `9.9`."
		}
	}

	return
}

my_custom_flag_checker :: proc(
	model: rawptr,
	name: string,
	value: any,
	args_tag: string,
) -> (error: string) {
	if name == "iterations" {
		v := value.(int)
		if !(1 <= v && v < 5) {
			error = "Iterations only supports 1 ..< 5."
		}
	}

	return
}

Distinct_Int :: distinct int

main :: proc() {
	Options :: struct {

		file: os.Handle `args:"pos=0,required,file=r" usage:"Input file."`,
		output: os.Handle `args:"pos=1,file=cw" usage:"Output file."`,

		hub: net.Host_Or_Endpoint `usage:"Internet address to contact for updates."`,
		schedule: datetime.DateTime `usage:"Launch tasks at this time."`,

		opt: Optimization_Level `usage:"Optimization level."`,
		todo: [dynamic]string `usage:"Todo items."`,

		accuracy: Fixed_Point1_1 `args:"required" usage:"Lenience in FLOP calculations."`,
		iterations: int `usage:"Run this many times."`,

		// Note how the parser will transform this flag's name into `special-int`.
		special_int: Distinct_Int `args:"indistinct" usage:"Able to set distinct types."`,

		quat: quaternion256,

		bits: bit_set[0..<8],

		// Many different requirement styles:

		// gadgets: [dynamic]string `args:"required=1" usage:"gadgets"`,
		// widgets: [dynamic]string `args:"required=<3" usage:"widgets"`,
		// foos: [dynamic]string `args:"required=2<4"`,
		// bars: [dynamic]string `args:"required=3<4"`,
		// bots: [dynamic]string `args:"required"`,

		// (Maps) Only available in Odin style:

		// assignments: map[string]u8 `args:"name=assign" usage:"Number of jobs per worker."`,

		// (Manifold) Only available in UNIX style:

		// bots: [dynamic]string `args:"manifold=2,required"`,

		verbose: bool `usage:"Show verbose output."`,
		debug: bool `args:"hidden" usage:"print debug info"`,

		overflow: [dynamic]string `usage:"Any extra arguments go here."`,
	}

	opt: Options
	style : flags.Parsing_Style = .Odin

	flags.register_type_setter(my_custom_type_setter)
	flags.register_flag_checker(my_custom_flag_checker)
	flags.parse_or_exit(&opt, os.args, style)

	fmt.printfln("%#v", opt)

	if opt.output != 0 {
		os.write_string(opt.output, "Hellope!\n")
	}
}