diff --git a/main.odin b/main.odin index 6b5fbdc..1acab58 100644 --- a/main.odin +++ b/main.odin @@ -1,6 +1,7 @@ package flag import "core:fmt" +import vmem "core:mem/virtual" import "myflag" main :: proc(){ @@ -12,22 +13,24 @@ main :: proc(){ defer vmem.arena_destroy(&arena) //clean myflag.init_custom_allocator(arena_alloc) - defer myflag.destroy() */ defer myflag.destroy() isRunning: bool isNumber: int isString: string + isFloat: f32 myflag.BoolVar(&isRunning, "isRunning", true, "A select piece of code is running!") myflag.IntVar(&isNumber, "isNumber", 3434, "A number!") myflag.StringVar(&isString, "isString", "Hellope!", "A string!") - + myflag.Float32Var(&isFloat, "isFloat", 3.1415, "A float!") myflag.parse_flags() + fmt.println("-------MAIN--------") fmt.println(isRunning) fmt.println(isNumber) fmt.println(isString) + fmt.println(isFloat) fmt.println("-------MAIN--------") } \ No newline at end of file diff --git a/myflag/flag.odin b/myflag/flag.odin index 9305e91..e11f684 100644 --- a/myflag/flag.odin +++ b/myflag/flag.odin @@ -1,103 +1,105 @@ +#+vet explicit-allocators package myflag +import "base:runtime" +import "core:fmt" +import "core:os" import "core:strconv" import "core:strings" -import "core:os" -import "core:fmt" -import "base:runtime" -Flag_Value_Ptr :: union{ +FORCE_HELP_ON_EMPTY_ARGS := false + +Flag_Value_Ptr :: union { ^bool, - ^int, - ^string, -} + ^int, + ^string, + ^f32, + ^f64, +} Flag :: struct { - name: string, - value: Flag_Value_Ptr, - usage: string, + name: string, + value: Flag_Value_Ptr, + usage: string, parsed: bool, // sck: flag to check if it has been parsed } all_flags: [dynamic]Flag - +flag_allocator: runtime.Allocator // sck: Used to create a customer allocator -init_custom_allocator :: proc(allocator: runtime.Allocator){ - // sck: make sure to destory the old allocations - destroy() - all_flags = make([dynamic]Flag, allocator = allocator) +init_custom_allocator :: proc(allocator: runtime.Allocator) { + destroy() // sck: make sure to destory the old allocations + + flag_allocator = allocator + all_flags = make([dynamic]Flag, flag_allocator) } -destroy :: proc(){ +destroy :: proc() { delete(all_flags) all_flags = {} // sck: needed? } -print_flags :: proc(){ - for f in all_flags{ +print_flags :: proc() { + for f in all_flags { fmt.printfln("%s: %v: %s", f.name, f.value, f.usage) } } -print_usage :: proc(){ +print_usage :: proc() { fmt.println("\tUsage: ") for f in all_flags { - switch v in f.value { - case ^bool: - fmt.printfln("\t-%s:\n\t\t%s (default: %v)\n", - f.name, f.usage, v^) - - case ^int: - fmt.printfln("\t-%s:\n\t\t%s (default: %d)\n", - f.name, f.usage, v^) - - case ^string: - fmt.printfln("\t-%s:\n\t\t%s (default: %s)\n", - f.name, f.usage, v^) - } + switch v in f.value { + case ^bool: + fmt.printfln("\t-%s:\n\t\t%s (default: %v)\n", f.name, f.usage, v^) + case ^int: + fmt.printfln("\t-%s:\n\t\t%s (default: %d)\n", f.name, f.usage, v^) + case ^string: + fmt.printfln("\t-%s:\n\t\t%s (default: %s)\n", f.name, f.usage, v^) + case ^f32: + fmt.printfln("\t-%s:\n\t\t%s (default: %f)\n", f.name, f.usage, v^) + case ^f64: + fmt.printfln("\t-%s:\n\t\t%s (default: %f)\n", f.name, f.usage, v^) + } } os.exit(0) } BoolVar :: proc(ptr: ^bool, name: string, default: bool, usage: string) { - ptr^ = default - - append(&all_flags, Flag{ - name = name, - value = ptr, - usage = usage, - }) + ptr^ = default + append(&all_flags, Flag{name = name, value = ptr, usage = usage}) } IntVar :: proc(ptr: ^int, name: string, default: int, usage: string) { - ptr^ = default - - append(&all_flags, Flag{ - name = name, - value = ptr, - usage = usage, - }) + ptr^ = default + append(&all_flags, Flag{name = name, value = ptr, usage = usage}) } StringVar :: proc(ptr: ^string, name: string, default: string, usage: string) { - ptr^ = default - - append(&all_flags, Flag{ - name = name, - value = ptr, - usage = usage, - }) + ptr^ = default + append(&all_flags, Flag{name = name, value = ptr, usage = usage}) } -parse_flags :: proc (){ - if len(os.args) < 2 { print_usage() } + +Float32Var :: proc(ptr: ^f32, name: string, default: f32, usage: string) { + ptr^ = default + append(&all_flags, Flag{name = name, value = ptr, usage = usage}) +} + +Float64Var :: proc(ptr: ^f64, name: string, default: f64, usage: string) { + ptr^ = default + append(&all_flags, Flag{name = name, value = ptr, usage = usage}) +} + +parse_flags :: proc() { + if len(os.args) < 2 && FORCE_HELP_ON_EMPTY_ARGS {print_usage()} for &a in os.args { - if a == "-help" || a == "--help"{ print_usage() } - if a == os.args[0] { continue } + if a == "-help" || a == "--help" {print_usage()} + if a == os.args[0] {continue} for &f in all_flags { - a = strings.trim_prefix(a, "-") + if f.parsed {continue} + a = strings.trim_prefix(a, "-") name := a value: string @@ -105,41 +107,56 @@ parse_flags :: proc (){ split := strings.index_any(a, "=") if split >= 0 { name = a[:split] - value = a[split+1:] + value = a[split + 1:] + } else { + name = a } - if name == f.name && !f.parsed{ + if name == f.name && !f.parsed { f.parsed = true switch &v in f.value { - case ^bool: - parsed, ok := strconv.parse_bool(value) + case ^bool: + if value == "" {break} + parsed, ok := strconv.parse_bool(value) if !ok { - //error + fmt.fprintfln(os.stderr, "[ERROR] Failed to parse flag %s: got %T, wanted bool", f.name, value) + os.exit(1) } v^ = parsed - case ^int: + case ^int: + if value == "" {break} parsed, ok := strconv.parse_int(value) if !ok { - fmt.fprintfln(os.stderr, "[ERROR] Failed to parsed flag %s:%s", f.name, ok) + fmt.fprintfln(os.stderr, "[ERROR] Failed to parse flag %s: got %T, wanted int", f.name, value) + os.exit(1) } v^ = parsed - case ^string: - // TODO: validate string + case ^string: + if value == "" {break} + // TODO: validate string? v^ = value + + case ^f32: + if value == "" {break} + parsed, ok := strconv.parse_f32(value) + if !ok { + fmt.fprintfln(os.stderr, "[ERROR] Failed to parse flag %s: got %T, wanted f32", f.name, value) + os.exit(1) + } + v^ = parsed + + case ^f64: + if value == "" {break} + parsed, ok := strconv.parse_f64(value) + if !ok { + fmt.fprintfln(os.stderr, "[ERROR] Failed to parse flag %s: got %T, wanted f64", f.name, value) + os.exit(1) + } + v^ = parsed } } } } - - /* - fmt.println("[INFO] parsed flags: ") - for f in all_flags{ - if f.parsed == true{ - fmt.println(f.name) - fmt.println(f.value) - } - } - */ }