mirror of
https://github.com/odin-lang/Odin.git
synced 2026-04-22 06:15:20 +00:00
Merge pull request #1743 from Tetralux/filepath-stems
[path/filepath] Add file stem and long-extension procedures
This commit is contained in:
@@ -4,6 +4,8 @@ package filepath
|
||||
|
||||
import "core:strings"
|
||||
|
||||
SEPARATOR_CHARS :: `/\`
|
||||
|
||||
// is_separator checks whether the byte is a valid separator character
|
||||
is_separator :: proc(c: byte) -> bool {
|
||||
switch c {
|
||||
@@ -69,6 +71,16 @@ volume_name_len :: proc(path: string) -> int {
|
||||
return 0
|
||||
}
|
||||
|
||||
/*
|
||||
Gets the file name and extension from a path.
|
||||
|
||||
i.e:
|
||||
'path/to/name.tar.gz' -> 'name.tar.gz'
|
||||
'path/to/name.txt' -> 'name.txt'
|
||||
'path/to/name' -> 'name'
|
||||
|
||||
Returns "." if the path is an empty string.
|
||||
*/
|
||||
base :: proc(path: string) -> string {
|
||||
if path == "" {
|
||||
return "."
|
||||
@@ -94,6 +106,118 @@ base :: proc(path: string) -> string {
|
||||
return path
|
||||
}
|
||||
|
||||
/*
|
||||
Gets the name of a file from a path.
|
||||
|
||||
The stem of a file is such that stem(path) + ext(path) = base(path).
|
||||
|
||||
Only the last dot is considered when splitting the file extension.
|
||||
See `short_stem`.
|
||||
|
||||
i.e:
|
||||
'name.tar.gz' -> 'name.tar'
|
||||
'name.txt' -> 'name'
|
||||
|
||||
Returns an empty string if there is no stem. e.g: '.gitignore'.
|
||||
Returns an empty string if there's a trailing path separator.
|
||||
*/
|
||||
stem :: proc(path: string) -> string {
|
||||
if len(path) > 0 && is_separator(path[len(path) - 1]) {
|
||||
// NOTE(tetra): Trailing separator
|
||||
return ""
|
||||
}
|
||||
|
||||
// NOTE(tetra): Get the basename
|
||||
path := path
|
||||
if i := strings.last_index_any(path, SEPARATOR_CHARS); i != -1 {
|
||||
path = path[i+1:]
|
||||
}
|
||||
|
||||
if i := strings.last_index_byte(path, '.'); i != -1 {
|
||||
return path[:i]
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
/*
|
||||
Gets the name of a file from a path.
|
||||
|
||||
The short stem is such that short_stem(path) + long_ext(path) = base(path).
|
||||
|
||||
The first dot is used to split off the file extension, unlike `stem` which uses the last dot.
|
||||
|
||||
i.e:
|
||||
'name.tar.gz' -> 'name'
|
||||
'name.txt' -> 'name'
|
||||
|
||||
Returns an empty string if there is no stem. e.g: '.gitignore'.
|
||||
Returns an empty string if there's a trailing path separator.
|
||||
*/
|
||||
short_stem :: proc(path: string) -> string {
|
||||
s := stem(path)
|
||||
if i := strings.index_byte(s, '.'); i != -1 {
|
||||
return s[:i]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
/*
|
||||
Gets the file extension from a path, including the dot.
|
||||
|
||||
The file extension is such that stem(path) + ext(path) = base(path).
|
||||
|
||||
Only the last dot is considered when splitting the file extension.
|
||||
See `long_ext`.
|
||||
|
||||
i.e:
|
||||
'name.tar.gz' -> '.gz'
|
||||
'name.txt' -> '.txt'
|
||||
|
||||
Returns an empty string if there is no dot.
|
||||
Returns an empty string if there is a trailing path separator.
|
||||
*/
|
||||
ext :: proc(path: string) -> string {
|
||||
for i := len(path)-1; i >= 0 && !is_separator(path[i]); i -= 1 {
|
||||
if path[i] == '.' {
|
||||
return path[i:]
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
/*
|
||||
Gets the file extension from a path, including the dot.
|
||||
|
||||
The long file extension is such that short_stem(path) + long_ext(path) = base(path).
|
||||
|
||||
The first dot is used to split off the file extension, unlike `ext` which uses the last dot.
|
||||
|
||||
i.e:
|
||||
'name.tar.gz' -> '.tar.gz'
|
||||
'name.txt' -> '.txt'
|
||||
|
||||
Returns an empty string if there is no dot.
|
||||
Returns an empty string if there is a trailing path separator.
|
||||
*/
|
||||
long_ext :: proc(path: string) -> string {
|
||||
if len(path) > 0 && is_separator(path[len(path) - 1]) {
|
||||
// NOTE(tetra): Trailing separator
|
||||
return ""
|
||||
}
|
||||
|
||||
// NOTE(tetra): Get the basename
|
||||
path := path
|
||||
if i := strings.last_index_any(path, SEPARATOR_CHARS); i != -1 {
|
||||
path = path[i+1:]
|
||||
}
|
||||
|
||||
if i := strings.index_byte(path, '.'); i != -1 {
|
||||
return path[i:]
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
clean :: proc(path: string, allocator := context.allocator) -> string {
|
||||
context.allocator = allocator
|
||||
@@ -189,15 +313,6 @@ to_slash :: proc(path: string, allocator := context.allocator) -> (new_path: str
|
||||
return strings.replace_all(path, SEPARATOR_STRING, "/", allocator)
|
||||
}
|
||||
|
||||
ext :: proc(path: string) -> string {
|
||||
for i := len(path)-1; i >= 0 && !is_separator(path[i]); i -= 1 {
|
||||
if path[i] == '.' {
|
||||
return path[i:]
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
|
||||
Relative_Error :: enum {
|
||||
None,
|
||||
|
||||
Reference in New Issue
Block a user