aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeroen van Rijn <Kelimion@users.noreply.github.com>2025-11-01 17:19:46 +0100
committerJeroen van Rijn <Kelimion@users.noreply.github.com>2026-02-08 12:56:05 +0100
commit2e970db51dc6e9edaefd6e3346807d6974bd155d (patch)
tree21a83cb071f33968fddab6d52c3585d83aef71eb
parent0c341123cb7cd07db56def2be23865550bdef75a (diff)
Link some more of filepath to os2
-rw-r--r--core/odin/parser/parse_files.odin8
-rw-r--r--core/os/os2/dir_walker.odin2
-rw-r--r--core/os/os2/path.odin29
-rw-r--r--core/path/filepath/path.odin143
-rw-r--r--core/path/filepath/path_js.odin17
-rw-r--r--core/path/filepath/path_unix.odin25
-rw-r--r--core/path/filepath/path_wasi.odin17
-rw-r--r--core/path/filepath/path_windows.odin17
-rw-r--r--core/path/filepath/walk.odin160
9 files changed, 143 insertions, 275 deletions
diff --git a/core/odin/parser/parse_files.odin b/core/odin/parser/parse_files.odin
index 5e7bee923..93c282d35 100644
--- a/core/odin/parser/parse_files.odin
+++ b/core/odin/parser/parse_files.odin
@@ -11,8 +11,8 @@ import "core:strings"
collect_package :: proc(path: string) -> (pkg: ^ast.Package, success: bool) {
NO_POS :: tokenizer.Pos{}
- pkg_path, pkg_path_ok := filepath.abs(path)
- if !pkg_path_ok {
+ pkg_path, pkg_path_err := os.get_absolute_path(path, context.allocator)
+ if pkg_path_err != nil {
return
}
@@ -28,8 +28,8 @@ collect_package :: proc(path: string) -> (pkg: ^ast.Package, success: bool) {
pkg.fullpath = pkg_path
for match in matches {
- fullpath, ok := filepath.abs(match)
- if !ok {
+ fullpath, fullpath_err := os.get_absolute_path(match, context.allocator)
+ if fullpath_err != nil {
return
}
diff --git a/core/os/os2/dir_walker.odin b/core/os/os2/dir_walker.odin
index 0af751f31..ba5342cf8 100644
--- a/core/os/os2/dir_walker.odin
+++ b/core/os/os2/dir_walker.odin
@@ -227,4 +227,4 @@ walker_walk :: proc(w: ^Walker) -> (fi: File_Info, ok: bool) {
}
return info, iter_ok
-}
+} \ No newline at end of file
diff --git a/core/os/os2/path.odin b/core/os/os2/path.odin
index 2c6412a8f..ac18b7562 100644
--- a/core/os/os2/path.odin
+++ b/core/os/os2/path.odin
@@ -22,9 +22,32 @@ is_path_separator :: proc(c: byte) -> bool {
return _is_path_separator(c)
}
-@(private)
-is_slash :: proc(c: byte) -> bool {
- return c == '\\' || c == '/'
+/*
+Returns the result of replacing each path separator character in the path
+with the `new_sep` rune.
+
+*Allocates Using Provided Allocator*
+*/
+replace_path_separators :: proc(path: string, new_sep: rune, allocator: runtime.Allocator) -> (new_path: string, err: Error) {
+ buf := make([]u8, len(path), allocator) or_return
+
+ i: int
+ for r in path {
+ replacement := r
+ if r == '/' || r == '\\' {
+ replacement = new_sep
+ }
+
+ if replacement <= rune(0x7F) {
+ buf[i] = u8(replacement)
+ i += 1
+ } else {
+ b, w := utf8.encode_rune(r)
+ copy(buf[i:], b[:w])
+ i += w
+ }
+ }
+ return string(buf), nil
}
mkdir :: make_directory
diff --git a/core/path/filepath/path.odin b/core/path/filepath/path.odin
index db8269cc2..2f2f7996c 100644
--- a/core/path/filepath/path.odin
+++ b/core/path/filepath/path.odin
@@ -2,7 +2,6 @@
// To process paths such as URLs that depend on forward slashes regardless of the OS, use the slashpath package.
package filepath
-import "base:runtime"
import os "core:os/os2"
import "core:strings"
@@ -11,11 +10,6 @@ SEPARATOR_CHARS :: `/\`
// is_separator checks whether the byte is a valid separator character
is_separator :: os.is_path_separator
-@(private)
-is_slash :: proc(c: byte) -> bool {
- return c == '\\' || c == '/'
-}
-
/*
In Windows, returns `true` if `path` is one of the following:
"CON", "PRN", "AUX", "NUL",
@@ -144,22 +138,25 @@ long_ext :: os.long_ext
*/
clean :: os.clean_path
-// Returns the result of replacing each forward slash `/` character in the path with the separate OS specific character.
-from_slash :: proc(path: string, allocator := context.allocator) -> (new_path: string, new_allocation: bool) {
- if SEPARATOR == '/' {
- return path, false
- }
- return strings.replace_all(path, "/", SEPARATOR_STRING, allocator)
-}
+/*
+Returns the result of replacing each path separator character in the path
+with the specific character `new_sep`.
-// Returns the result of replacing each OS specific separator with a forward slash `/` character.
-to_slash :: proc(path: string, allocator := context.allocator) -> (new_path: string, new_allocation: bool) {
- if SEPARATOR == '/' {
- return path, false
- }
- return strings.replace_all(path, SEPARATOR_STRING, "/", allocator)
-}
+*Allocates Using Provided Allocator*
+*/
+replace_path_separators := os.replace_path_separators
+/*
+Return true if `path` is an absolute path as opposed to a relative one.
+*/
+is_abs :: os.is_absolute_path
+
+/*
+Get the absolute path to `path` with respect to the process's current directory.
+
+*Allocates Using Provided Allocator*
+*/
+abs :: os.get_absolute_path
Relative_Error :: enum {
None,
@@ -275,108 +272,4 @@ dir :: proc(path: string, allocator := context.allocator) -> string {
// An empty string returns nil. A non-empty string with no separators returns a 1-element array.
// Any empty components will be included, e.g. `a::b` will return a 3-element array, as will `::`.
// Separators within pairs of double-quotes will be ignored and stripped, e.g. `"a:b"c:d` will return []{`a:bc`, `d`}.
-split_list :: proc(path: string, allocator := context.allocator) -> (list: []string, err: runtime.Allocator_Error) #optional_allocator_error {
- if path == "" {
- return nil, nil
- }
-
- start: int
- quote: bool
-
- start, quote = 0, false
- count := 0
-
- for i := 0; i < len(path); i += 1 {
- c := path[i]
- switch {
- case c == '"':
- quote = !quote
- case c == LIST_SEPARATOR && !quote:
- count += 1
- }
- }
-
- start, quote = 0, false
- list = make([]string, count + 1, allocator) or_return
- index := 0
- for i := 0; i < len(path); i += 1 {
- c := path[i]
- switch {
- case c == '"':
- quote = !quote
- case c == LIST_SEPARATOR && !quote:
- list[index] = path[start:i]
- index += 1
- start = i + 1
- }
- }
- assert(index == count)
- list[index] = path[start:]
-
- for s0, i in list {
- s, new := strings.replace_all(s0, `"`, ``, allocator)
- if !new {
- s = strings.clone(s, allocator) or_return
- }
- list[i] = s
- }
-
- return list, nil
-}
-
-
-
-
-/*
- Lazy_Buffer is a lazily made path buffer
- When it does allocate, it uses the context.allocator
- */
-@(private)
-Lazy_Buffer :: struct {
- s: string,
- b: []byte,
- w: int, // write index
- vol_and_path: string,
- vol_len: int,
-}
-
-@(private)
-lazy_buffer_index :: proc(lb: ^Lazy_Buffer, i: int) -> byte {
- if lb.b != nil {
- return lb.b[i]
- }
- return lb.s[i]
-}
-@(private)
-lazy_buffer_append :: proc(lb: ^Lazy_Buffer, c: byte) -> (err: runtime.Allocator_Error) {
- if lb.b == nil {
- if lb.w < len(lb.s) && lb.s[lb.w] == c {
- lb.w += 1
- return
- }
- lb.b = make([]byte, len(lb.s)) or_return
- copy(lb.b, lb.s[:lb.w])
- }
- lb.b[lb.w] = c
- lb.w += 1
- return
-}
-@(private)
-lazy_buffer_string :: proc(lb: ^Lazy_Buffer) -> (s: string, err: runtime.Allocator_Error) {
- if lb.b == nil {
- return strings.clone(lb.vol_and_path[:lb.vol_len+lb.w])
- }
-
- x := lb.vol_and_path[:lb.vol_len]
- y := string(lb.b[:lb.w])
- z := make([]byte, len(x)+len(y)) or_return
- copy(z, x)
- copy(z[len(x):], y)
- return string(z), nil
-}
-@(private)
-lazy_buffer_destroy :: proc(lb: ^Lazy_Buffer) -> runtime.Allocator_Error {
- err := delete(lb.b)
- lb^ = {}
- return err
-} \ No newline at end of file
+split_list :: os.split_path_list \ No newline at end of file
diff --git a/core/path/filepath/path_js.odin b/core/path/filepath/path_js.odin
index c0c85b487..e2657cb3e 100644
--- a/core/path/filepath/path_js.odin
+++ b/core/path/filepath/path_js.odin
@@ -1,20 +1,5 @@
package filepath
-import "base:runtime"
-import "core:strings"
-
SEPARATOR :: '/'
SEPARATOR_STRING :: `/`
-LIST_SEPARATOR :: ':'
-
-is_abs :: proc(path: string) -> bool {
- return strings.has_prefix(path, "/")
-}
-
-abs :: proc(path: string, allocator := context.allocator) -> (string, bool) {
- if is_abs(path) {
- return strings.clone(string(path), allocator), true
- }
-
- return path, false
-} \ No newline at end of file
+LIST_SEPARATOR :: ':' \ No newline at end of file
diff --git a/core/path/filepath/path_unix.odin b/core/path/filepath/path_unix.odin
index e43264961..2e1b1419e 100644
--- a/core/path/filepath/path_unix.odin
+++ b/core/path/filepath/path_unix.odin
@@ -1,29 +1,6 @@
#+build linux, darwin, freebsd, openbsd, netbsd, haiku
package filepath
-import "core:strings"
-import "core:sys/posix"
-
SEPARATOR :: '/'
SEPARATOR_STRING :: `/`
-LIST_SEPARATOR :: ':'
-
-is_abs :: proc(path: string) -> bool {
- return strings.has_prefix(path, "/")
-}
-
-abs :: proc(path: string, allocator := context.allocator) -> (string, bool) {
- rel := path
- if rel == "" {
- rel = "."
- }
- rel_cstr := strings.clone_to_cstring(rel, context.temp_allocator)
- path_ptr := posix.realpath(rel_cstr, nil)
- if path_ptr == nil {
- return "", posix.errno() == nil
- }
- defer posix.free(path_ptr)
-
- path_str := strings.clone(string(path_ptr), allocator)
- return path_str, true
-} \ No newline at end of file
+LIST_SEPARATOR :: ':' \ No newline at end of file
diff --git a/core/path/filepath/path_wasi.odin b/core/path/filepath/path_wasi.odin
index c0c85b487..e2657cb3e 100644
--- a/core/path/filepath/path_wasi.odin
+++ b/core/path/filepath/path_wasi.odin
@@ -1,20 +1,5 @@
package filepath
-import "base:runtime"
-import "core:strings"
-
SEPARATOR :: '/'
SEPARATOR_STRING :: `/`
-LIST_SEPARATOR :: ':'
-
-is_abs :: proc(path: string) -> bool {
- return strings.has_prefix(path, "/")
-}
-
-abs :: proc(path: string, allocator := context.allocator) -> (string, bool) {
- if is_abs(path) {
- return strings.clone(string(path), allocator), true
- }
-
- return path, false
-} \ No newline at end of file
+LIST_SEPARATOR :: ':' \ No newline at end of file
diff --git a/core/path/filepath/path_windows.odin b/core/path/filepath/path_windows.odin
index 00aae8d7f..9b8e92bbd 100644
--- a/core/path/filepath/path_windows.odin
+++ b/core/path/filepath/path_windows.odin
@@ -1,26 +1,9 @@
package filepath
-import "base:runtime"
-import os "core:os/os2"
-
SEPARATOR :: '\\'
SEPARATOR_STRING :: `\`
LIST_SEPARATOR :: ';'
is_UNC :: proc(path: string) -> bool {
return len(volume_name(path)) > 2
-}
-
-is_abs :: proc(path: string) -> bool {
- return os.is_absolute_path(path)
-}
-
-abs :: proc(path: string, allocator := context.allocator) -> (string, bool) {
- runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = allocator == context.temp_allocator)
- full_path, err := os.get_absolute_path(path, context.temp_allocator)
- if err != nil {
- return "", false
- }
- p, _ := clean(full_path, allocator)
- return p, true
} \ No newline at end of file
diff --git a/core/path/filepath/walk.odin b/core/path/filepath/walk.odin
index 845ba06a0..00b063bc7 100644
--- a/core/path/filepath/walk.odin
+++ b/core/path/filepath/walk.odin
@@ -3,81 +3,103 @@
package filepath
import os "core:os/os2"
-import "core:slice"
-
-// Walk_Proc is the type of the procedure called for each file or directory visited by 'walk'
-// The 'path' parameter contains the parameter to walk as a prefix (this is the same as info.fullpath except on 'root')
-// The 'info' parameter is the os.File_Info for the named path
-//
-// If there was a problem walking to the file or directory named by path, the incoming error will describe the problem
-// and the procedure can decide how to handle that error (and walk will not descend into that directory)
-// In the case of an error, the info argument will be 0
-// If an error is returned, processing stops
-// The sole exception is if 'skip_dir' is returned as true:
-// when 'skip_dir' is invoked on a directory. 'walk' skips directory contents
-// when 'skip_dir' is invoked on a non-directory. 'walk' skips the remaining files in the containing directory
-Walk_Proc :: #type proc(info: os.File_Info, in_err: os.Error, user_data: rawptr) -> (err: os.Error, skip_dir: bool)
-
-// walk walks the file tree rooted at 'root', calling 'walk_proc' for each file or directory in the tree, including 'root'
-// All errors that happen visiting files and directories are filtered by walk_proc
-// The files are walked in lexical order to make the output deterministic
-// NOTE: Walking large directories can be inefficient due to the lexical sort
-// NOTE: walk does not follow symbolic links
-// NOTE: os.File_Info uses the 'context.temp_allocator' to allocate, and will delete when it is done
-walk :: proc(root: string, walk_proc: Walk_Proc, user_data: rawptr) -> os.Error {
- info, err := os.lstat(root, context.temp_allocator)
- defer os.file_info_delete(info, context.temp_allocator)
-
- skip_dir: bool
- if err != nil {
- err, skip_dir = walk_proc(info, err, user_data)
- } else {
- err, skip_dir = _walk(info, walk_proc, user_data)
- }
- return nil if skip_dir else err
-}
+Walker :: os.Walker
-@(private)
-_walk :: proc(info: os.File_Info, walk_proc: Walk_Proc, user_data: rawptr) -> (err: os.Error, skip_dir: bool) {
- if info.type != .Directory {
- if info.fullpath == "" && info.name == "" {
- // ignore empty things
- return
- }
- return walk_proc(info, nil, user_data)
- }
+/*
+Initializes a walker, either using a path or a file pointer to a directory the walker will start at.
- fis: []os.File_Info
- err1: os.Error
- fis, err = read_dir(info.fullpath, context.temp_allocator)
- defer os.file_info_slice_delete(fis, context.temp_allocator)
+You are allowed to repeatedly call this to reuse it for later walks.
- err1, skip_dir = walk_proc(info, err, user_data)
- if err != nil || err1 != nil || skip_dir {
- err = err1
- return
- }
+For an example on how to use the walker, see `walker_walk`.
+*/
+walker_init :: os.walker_init
+
+/*
+Creates a walker, either using a path or a file pointer to a directory the walker will start at.
+
+For an example on how to use the walker, see `walker_walk`.
+*/
+walker_create :: os.walker_create
+
+/*
+Returns the last error that occurred during the walker's operations.
+
+Can be called while iterating, or only at the end to check if anything failed.
+*/
+walker_error :: os.walker_error
+
+walker_destroy :: os.walker_destroy
+
+// Marks the current directory to be skipped (not entered into).
+walker_skip_dir :: os.walker_skip_dir
+
+/*
+Returns the next file info in the iterator, files are iterated in breadth-first order.
+
+If an error occurred opening a directory, you may get zero'd info struct and
+`walker_error` will return the error.
+
+Example:
+ package main
+
+ import "core:fmt"
+ import "core:strings"
+ import os "core:os/os2"
- for fi in fis {
- err, skip_dir = _walk(fi, walk_proc, user_data)
- if err != nil || skip_dir {
- if fi.type != .Directory || !skip_dir {
- return
+ main :: proc() {
+ w := os.walker_create("core")
+ defer os.walker_destroy(&w)
+
+ for info in os.walker_walk(&w) {
+ // Optionally break on the first error:
+ // _ = walker_error(&w) or_break
+
+ // Or, handle error as we go:
+ if path, err := os.walker_error(&w); err != nil {
+ fmt.eprintfln("failed walking %s: %s", path, err)
+ continue
+ }
+
+ // Or, do not handle errors during iteration, and just check the error at the end.
+
+
+
+ // Skip a directory:
+ if strings.has_suffix(info.fullpath, ".git") {
+ os.walker_skip_dir(&w)
+ continue
}
+
+ fmt.printfln("%#v", info)
+ }
+
+ // Handle error if one happened during iteration at the end:
+ if path, err := os.walker_error(&w); err != nil {
+ fmt.eprintfln("failed walking %s: %v", path, err)
}
}
+*/
+walker_walk :: os.walker_walk
+
+/*
+ Reads the file `f` (assuming it is a directory) and returns the unsorted directory entries.
+ This returns up to `n` entries OR all of them if `n <= 0`.
+*/
+read_directory :: os.read_directory
+
+/*
+ Reads the file `f` (assuming it is a directory) and returns all of the unsorted directory entries.
+*/
+read_all_directory :: os.read_all_directory
+
+/*
+ Reads the named directory by path (assuming it is a directory) and returns the unsorted directory entries.
+ This returns up to `n` entries OR all of them if `n <= 0`.
+*/
+read_directory_by_path :: os.read_directory_by_path
- return
-}
-
-@(private)
-read_dir :: proc(dir_name: string, allocator := context.temp_allocator) -> (fis: []os.File_Info, err: os.Error) {
- f := os.open(dir_name, os.O_RDONLY) or_return
- defer os.close(f)
- fis = os.read_dir(f, -1, allocator) or_return
- slice.sort_by(fis, proc(a, b: os.File_Info) -> bool {
- return a.name < b.name
- })
- return
-}
+/*
+ Reads the named directory by path (assuming it is a directory) and returns all of the unsorted directory entries.
+*/
+read_all_directory_by_path :: os.read_all_directory_by_path \ No newline at end of file