mirror of
https://github.com/odin-lang/Odin.git
synced 2026-02-12 06:18:39 +00:00
Link some more of filepath to os2
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -227,4 +227,4 @@ walker_walk :: proc(w: ^Walker) -> (fi: File_Info, ok: bool) {
|
||||
}
|
||||
|
||||
return info, iter_ok
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
split_list :: os.split_path_list
|
||||
@@ -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
|
||||
}
|
||||
LIST_SEPARATOR :: ':'
|
||||
@@ -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
|
||||
}
|
||||
LIST_SEPARATOR :: ':'
|
||||
@@ -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
|
||||
}
|
||||
LIST_SEPARATOR :: ':'
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
Walker :: os.Walker
|
||||
|
||||
// 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)
|
||||
/*
|
||||
Initializes a walker, either using a path or a file pointer to a directory the walker will start at.
|
||||
|
||||
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
|
||||
}
|
||||
You are allowed to repeatedly call this to reuse it for later walks.
|
||||
|
||||
For an example on how to use the walker, see `walker_walk`.
|
||||
*/
|
||||
walker_init :: os.walker_init
|
||||
|
||||
@(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)
|
||||
}
|
||||
/*
|
||||
Creates 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)
|
||||
For an example on how to use the walker, see `walker_walk`.
|
||||
*/
|
||||
walker_create :: os.walker_create
|
||||
|
||||
err1, skip_dir = walk_proc(info, err, user_data)
|
||||
if err != nil || err1 != nil || skip_dir {
|
||||
err = err1
|
||||
return
|
||||
}
|
||||
/*
|
||||
Returns the last error that occurred during the walker's operations.
|
||||
|
||||
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
|
||||
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"
|
||||
|
||||
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
|
||||
|
||||
return
|
||||
}
|
||||
/*
|
||||
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
|
||||
|
||||
@(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 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
|
||||
|
||||
/*
|
||||
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
|
||||
Reference in New Issue
Block a user