mirror of
https://github.com/Nexoniarz/Finch.git
synced 2026-11-03 16:54:25 +00:00
a standard library in Finch: path, time, proc, json
import json import path import time import proc -- found in std/ after the program's own files, so a program's own json.fch always wins. path: join, base, dir, ext, stem, parts, clean, is_abs. time: now, millis, sleep, date, local, format, days_in_month (clock_gettime, strftime through C import). proc: run, output (an error with the command's output when it fails), env, pid, cwd. json: parse (errors with line and column), stringify, pretty, new_*, get/at/set/push/has/names and str_or/int_or/float_or/bool_or; \u escapes with surrogate pairs. The C importer now leaves a plain (non-const) char * parameter a ptr[char], a buffer C writes into; only const char * is text going in. str(ptr) and str([]u8) are in the self-hosted compiler. boot.sh: 40 passed, 0 failed.
This commit is contained in:
parent
04eb0cce55
commit
ea6d2a57e5
13 changed files with 929 additions and 9 deletions
128
std/path.fch
Normal file
128
std/path.fch
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
// Paths, as text. Elements are separated by "/".
|
||||
//
|
||||
// import path
|
||||
// path.join("a", "b.txt") a/b.txt
|
||||
// path.base("/tmp/x/a.tar.gz") a.tar.gz path.stem(...) a.tar path.ext(...) .gz
|
||||
// path.dir("/tmp/x/a.txt") /tmp/x
|
||||
// path.clean("a//b/../c/./d") a/c/d
|
||||
|
||||
// a and b with one separator between; an absolute b replaces a
|
||||
fn join(str a, str b) -> str {
|
||||
if a.len == 0 {
|
||||
return b
|
||||
}
|
||||
if b.len == 0 {
|
||||
return a
|
||||
}
|
||||
if b[0] == '/' {
|
||||
return b
|
||||
}
|
||||
if a[a.len - 1] == '/' {
|
||||
return a + b
|
||||
}
|
||||
return a + "/" + b
|
||||
}
|
||||
|
||||
fn is_abs(str p) -> bool {
|
||||
return p.len > 0 && p[0] == '/'
|
||||
}
|
||||
|
||||
// the last element: "a/b.txt" -> "b.txt", "a/b/" -> "b", "" -> ".", "/" -> "/"
|
||||
fn base(str p) -> str {
|
||||
if p.len == 0 {
|
||||
return "."
|
||||
}
|
||||
end := p.len
|
||||
while end > 1 && p[end - 1] == '/' {
|
||||
end -= 1
|
||||
}
|
||||
if end == 1 && p[0] == '/' {
|
||||
return "/"
|
||||
}
|
||||
start := end
|
||||
while start > 0 && p[start - 1] != '/' {
|
||||
start -= 1
|
||||
}
|
||||
return p.sub(start, end)
|
||||
}
|
||||
|
||||
// everything before the last element: "a/b.txt" -> "a", "b.txt" -> ".", "/b" -> "/"
|
||||
fn dir(str p) -> str {
|
||||
end := p.len
|
||||
while end > 1 && p[end - 1] == '/' {
|
||||
end -= 1
|
||||
}
|
||||
i := end
|
||||
while i > 0 && p[i - 1] != '/' {
|
||||
i -= 1
|
||||
}
|
||||
if i == 0 {
|
||||
return "."
|
||||
}
|
||||
while i > 1 && p[i - 1] == '/' {
|
||||
i -= 1
|
||||
}
|
||||
return p.sub(0, i)
|
||||
}
|
||||
|
||||
// the part of the last element from its last dot: "a.tar.gz" -> ".gz"; "" when there is none
|
||||
fn ext(str p) -> str {
|
||||
b := base(p)
|
||||
i := b.len
|
||||
while i > 0 && b[i - 1] != '.' {
|
||||
i -= 1
|
||||
}
|
||||
if i <= 1 { // no dot, or a name that only starts with one (.bashrc)
|
||||
return ""
|
||||
}
|
||||
return b.sub(i - 1, b.len)
|
||||
}
|
||||
|
||||
// the last element without its extension
|
||||
fn stem(str p) -> str {
|
||||
b := base(p)
|
||||
e := ext(p)
|
||||
return b.sub(0, b.len - e.len)
|
||||
}
|
||||
|
||||
// the elements of a path: "/a/b/c" -> ["a", "b", "c"]
|
||||
fn parts(str p) -> []str {
|
||||
[]str out
|
||||
for piece in p.split("/") {
|
||||
if piece.len > 0 {
|
||||
out.push(piece)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// the shortest path with the same meaning: no "//", no ".", and ".." resolved where it can be
|
||||
fn clean(str p) -> str {
|
||||
if p.len == 0 {
|
||||
return "."
|
||||
}
|
||||
abs := is_abs(p)
|
||||
[]str out
|
||||
for piece in parts(p) {
|
||||
if piece == "." {
|
||||
continue
|
||||
}
|
||||
if piece == ".." {
|
||||
if out.len > 0 && out[out.len - 1] != ".." {
|
||||
out.pop()
|
||||
} else if !abs {
|
||||
out.push("..")
|
||||
}
|
||||
continue
|
||||
}
|
||||
out.push(piece)
|
||||
}
|
||||
joined := out.join("/")
|
||||
if abs {
|
||||
return "/" + joined
|
||||
}
|
||||
if joined.len == 0 {
|
||||
return "."
|
||||
}
|
||||
return joined
|
||||
}
|
||||
Loading…
Reference in a new issue