mirror of
https://github.com/odin-lang/Odin.git
synced 2026-08-07 06:28:59 +00:00
Port core:flags to os2
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
package flags
|
||||
|
||||
import "core:os"
|
||||
import os "core:os/os2"
|
||||
|
||||
Parse_Error_Reason :: enum {
|
||||
None,
|
||||
@@ -29,8 +29,8 @@ Parse_Error :: struct {
|
||||
Open_File_Error :: struct {
|
||||
filename: string,
|
||||
errno: os.Error,
|
||||
mode: int,
|
||||
perms: int,
|
||||
flags: os.File_Flags,
|
||||
perms: os.Permissions,
|
||||
}
|
||||
|
||||
// Raised during parsing.
|
||||
|
||||
@@ -4,7 +4,7 @@ import "base:runtime"
|
||||
import "core:flags"
|
||||
import "core:fmt"
|
||||
import "core:net"
|
||||
import "core:os"
|
||||
import os "core:os/os2"
|
||||
import "core:time/datetime"
|
||||
|
||||
|
||||
@@ -76,8 +76,8 @@ 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."`,
|
||||
file: ^os.File `args:"pos=0,required,file=r" usage:"Input file."`,
|
||||
output: ^os.File `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."`,
|
||||
@@ -126,7 +126,7 @@ main :: proc() {
|
||||
|
||||
fmt.printfln("%#v", opt)
|
||||
|
||||
if opt.output != 0 {
|
||||
if opt.output != nil {
|
||||
os.write_string(opt.output, "Hellope!\n")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import "base:intrinsics"
|
||||
import "base:runtime"
|
||||
import "core:fmt"
|
||||
import "core:mem"
|
||||
import "core:os"
|
||||
@(require) import os "core:os/os2"
|
||||
import "core:reflect"
|
||||
import "core:strconv"
|
||||
import "core:strings"
|
||||
@@ -208,7 +208,7 @@ parse_and_set_pointer_by_base_type :: proc(ptr: rawptr, str: string, type_info:
|
||||
parse_and_set_pointer_by_named_type :: proc(ptr: rawptr, str: string, data_type: typeid, arg_tag: string, out_error: ^Error) {
|
||||
// Core types currently supported:
|
||||
//
|
||||
// - os.Handle
|
||||
// - ^os.File
|
||||
// - time.Time
|
||||
// - datetime.DateTime
|
||||
// - net.Host_Or_Endpoint
|
||||
@@ -216,47 +216,44 @@ parse_and_set_pointer_by_named_type :: proc(ptr: rawptr, str: string, data_type:
|
||||
GENERIC_RFC_3339_ERROR :: "Invalid RFC 3339 string. Try this format: `yyyy-mm-ddThh:mm:ssZ`, for example `2024-02-29T16:30:00Z`."
|
||||
|
||||
out_error^ = nil
|
||||
|
||||
if data_type == os.Handle {
|
||||
if data_type == ^os.File {
|
||||
// NOTE: `os` is hopefully available everywhere, even if it might panic on some calls.
|
||||
wants_read := false
|
||||
wants_write := false
|
||||
mode: int
|
||||
flags: os.File_Flags
|
||||
|
||||
if file, ok := get_struct_subtag(arg_tag, SUBTAG_FILE); ok {
|
||||
for i in 0..<len(file) {
|
||||
#no_bounds_check switch file[i] {
|
||||
case 'r': wants_read = true
|
||||
case 'w': wants_write = true
|
||||
case 'c': mode |= os.O_CREATE
|
||||
case 'a': mode |= os.O_APPEND
|
||||
case 't': mode |= os.O_TRUNC
|
||||
case 'r': flags |= {.Read}
|
||||
case 'w': flags |= {.Write}
|
||||
case 'c': flags |= {.Create}
|
||||
case 'a': flags |= {.Append}
|
||||
case 't': flags |= {.Trunc}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sane default.
|
||||
// owner/group/other: r--r--r--
|
||||
perms: int = 0o444
|
||||
octal_perms: int = 0o444
|
||||
|
||||
if wants_read && wants_write {
|
||||
mode |= os.O_RDWR
|
||||
perms |= 0o200
|
||||
} else if wants_write {
|
||||
mode |= os.O_WRONLY
|
||||
perms |= 0o200
|
||||
if flags >= {.Read, .Write} {
|
||||
octal_perms |= 0o200
|
||||
} else if .Write in flags {
|
||||
octal_perms |= 0o200
|
||||
} else {
|
||||
mode |= os.O_RDONLY
|
||||
flags |= {.Read}
|
||||
}
|
||||
|
||||
if permstr, ok := get_struct_subtag(arg_tag, SUBTAG_PERMS); ok {
|
||||
if value, parse_ok := strconv.parse_u64_of_base(permstr, 8); parse_ok {
|
||||
perms = int(value)
|
||||
octal_perms = int(value)
|
||||
}
|
||||
}
|
||||
|
||||
handle, errno := os.open(str, mode, perms)
|
||||
if errno != nil {
|
||||
perms := os.perm(octal_perms)
|
||||
|
||||
f, error := os.open(str, flags, perms)
|
||||
if error != nil {
|
||||
// NOTE(Feoramund): os.Error is system-dependent, and there's
|
||||
// currently no good way to translate them all into strings.
|
||||
//
|
||||
@@ -266,14 +263,14 @@ parse_and_set_pointer_by_named_type :: proc(ptr: rawptr, str: string, data_type:
|
||||
// it up.
|
||||
out_error^ = Open_File_Error {
|
||||
str,
|
||||
errno,
|
||||
mode,
|
||||
error,
|
||||
flags,
|
||||
perms,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
(^os.Handle)(ptr)^ = handle
|
||||
(^^os.File)(ptr)^ = f
|
||||
return
|
||||
}
|
||||
|
||||
@@ -463,6 +460,11 @@ parse_and_set_pointer_by_type :: proc(ptr: rawptr, str: string, type_info: ^runt
|
||||
}
|
||||
|
||||
case:
|
||||
if type_info.id == ^os.File {
|
||||
parse_and_set_pointer_by_named_type(ptr, str, type_info.id, arg_tag, &error)
|
||||
return
|
||||
}
|
||||
|
||||
if !parse_and_set_pointer_by_base_type(ptr, str, type_info) {
|
||||
return Parse_Error {
|
||||
// The caller will add more details.
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#+private
|
||||
package flags
|
||||
|
||||
@require import "base:runtime"
|
||||
@require import "core:container/bit_array"
|
||||
@require import "core:fmt"
|
||||
@require import "core:mem"
|
||||
@require import "core:os"
|
||||
@require import "core:reflect"
|
||||
@require import "core:strconv"
|
||||
@require import "core:strings"
|
||||
@require import "base:runtime"
|
||||
@require import "core:container/bit_array"
|
||||
@require import "core:fmt"
|
||||
@require import "core:mem"
|
||||
@require import os "core:os/os2"
|
||||
@require import "core:reflect"
|
||||
@require import "core:strconv"
|
||||
@require import "core:strings"
|
||||
|
||||
// This proc is used to assert that `T` meets the expectations of the library.
|
||||
@(optimization_mode="favor_size", disabled=ODIN_DISABLE_ASSERT)
|
||||
@@ -138,20 +138,20 @@ validate_structure :: proc(model_type: $T, style: Parsing_Style, loc := #caller_
|
||||
allowed_to_define_file_perms: bool = ---
|
||||
#partial switch specific_type_info in field.type.variant {
|
||||
case runtime.Type_Info_Map:
|
||||
allowed_to_define_file_perms = specific_type_info.value.id == os.Handle
|
||||
allowed_to_define_file_perms = specific_type_info.value.id == ^os.File
|
||||
case runtime.Type_Info_Dynamic_Array:
|
||||
allowed_to_define_file_perms = specific_type_info.elem.id == os.Handle
|
||||
allowed_to_define_file_perms = specific_type_info.elem.id == ^os.File
|
||||
case:
|
||||
allowed_to_define_file_perms = field.type.id == os.Handle
|
||||
allowed_to_define_file_perms = field.type.id == ^os.File
|
||||
}
|
||||
|
||||
if _, has_file := get_struct_subtag(args_tag, SUBTAG_FILE); has_file {
|
||||
fmt.assertf(allowed_to_define_file_perms, "%T.%s has `%s` defined, but it is not nor does it contain an `os.Handle` type.",
|
||||
fmt.assertf(allowed_to_define_file_perms, "%T.%s has `%s` defined, but it is not nor does it contain an `^os.File` type.",
|
||||
model_type, field.name, SUBTAG_FILE, loc = loc)
|
||||
}
|
||||
|
||||
if _, has_perms := get_struct_subtag(args_tag, SUBTAG_PERMS); has_perms {
|
||||
fmt.assertf(allowed_to_define_file_perms, "%T.%s has `%s` defined, but it is not nor does it contain an `os.Handle` type.",
|
||||
fmt.assertf(allowed_to_define_file_perms, "%T.%s has `%s` defined, but it is not nor does it contain an `^os.File` type.",
|
||||
model_type, field.name, SUBTAG_PERMS, loc = loc)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package flags
|
||||
|
||||
import "core:fmt"
|
||||
@require import "core:os"
|
||||
@require import os "core:os/os2"
|
||||
@require import "core:path/filepath"
|
||||
import "core:strings"
|
||||
|
||||
@@ -38,7 +38,7 @@ parse_or_exit :: proc(
|
||||
|
||||
error := parse(model, args, style, true, true, allocator, loc)
|
||||
if error != nil {
|
||||
stderr := os.stream_from_handle(os.stderr)
|
||||
stderr := os.to_stream(os.stderr)
|
||||
|
||||
if len(args) == 0 {
|
||||
// No arguments entered, and there was an error; show the usage,
|
||||
@@ -65,18 +65,18 @@ Inputs:
|
||||
*/
|
||||
@(optimization_mode="favor_size")
|
||||
print_errors :: proc(data_type: typeid, error: Error, program: string, style: Parsing_Style = .Odin) {
|
||||
stderr := os.stream_from_handle(os.stderr)
|
||||
stdout := os.stream_from_handle(os.stdout)
|
||||
stderr := os.to_stream(os.stderr)
|
||||
stdout := os.to_stream(os.stdout)
|
||||
|
||||
switch specific_error in error {
|
||||
case Parse_Error:
|
||||
fmt.wprintfln(stderr, "[%T.%v] %s", specific_error, specific_error.reason, specific_error.message)
|
||||
case Open_File_Error:
|
||||
fmt.wprintfln(stderr, "[%T#%i] Unable to open file with perms 0o%o in mode 0x%x: %s",
|
||||
fmt.wprintfln(stderr, "[%T#%i] Unable to open file with perms 0o%o and flags %v: %s",
|
||||
specific_error,
|
||||
specific_error.errno,
|
||||
specific_error.perms,
|
||||
specific_error.mode,
|
||||
specific_error.flags,
|
||||
specific_error.filename)
|
||||
case Validation_Error:
|
||||
fmt.wprintfln(stderr, "[%T] %s", specific_error, specific_error.message)
|
||||
|
||||
@@ -7,7 +7,7 @@ import "core:fmt"
|
||||
@require import "core:log"
|
||||
import "core:math"
|
||||
@require import "core:net"
|
||||
import "core:os"
|
||||
import os "core:os/os2"
|
||||
import "core:strings"
|
||||
import "core:testing"
|
||||
import "core:time/datetime"
|
||||
@@ -1249,7 +1249,7 @@ test_os_handle :: proc(t: ^testing.T) {
|
||||
test_data := "Hellope!"
|
||||
|
||||
W :: struct {
|
||||
outf: os.Handle `args:"file=cw"`,
|
||||
outf: ^os.File `args:"file=cw"`,
|
||||
}
|
||||
w: W
|
||||
|
||||
@@ -1263,7 +1263,7 @@ test_os_handle :: proc(t: ^testing.T) {
|
||||
os.write_string(w.outf, test_data)
|
||||
|
||||
R :: struct {
|
||||
inf: os.Handle `args:"file=r"`,
|
||||
inf: ^os.File `args:"file=r"`,
|
||||
}
|
||||
r: R
|
||||
|
||||
@@ -1274,8 +1274,8 @@ test_os_handle :: proc(t: ^testing.T) {
|
||||
return
|
||||
}
|
||||
defer os.close(r.inf)
|
||||
data, read_ok := os.read_entire_file_from_handle(r.inf, context.temp_allocator)
|
||||
testing.expect_value(t, read_ok, true)
|
||||
data, read_err := os.read_entire_file(r.inf, context.temp_allocator)
|
||||
testing.expect_value(t, read_err, nil)
|
||||
file_contents_equal := 0 == bytes.compare(transmute([]u8)test_data, data)
|
||||
testing.expectf(t, file_contents_equal, "expected file contents to be the same, got %v", data)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user