ref: c212e703cdde390fc26e18bbe0f7e96bc6546647
parent: 968a619a87998e26aca1498e42a296d1e9d5a5e7
author: Ori Bernstein <[email protected]>
date: Thu Aug 14 06:40:32 EDT 2014
Add path joining and normalization functions.
--- a/libstd/Makefile
+++ b/libstd/Makefile
@@ -26,6 +26,7 @@
now.myr \
option.myr \
optparse.myr \
+ pathjoin.myr \
rand.myr \
resolve.myr \
result.myr \
--- /dev/null
+++ b/libstd/pathjoin.myr
@@ -1,0 +1,85 @@
+use "alloc.use"
+use "strjoin.use"
+use "strsplit.use"
+use "sleq.use"
+use "sldup.use"
+use "slcp.use"
+use "die.use"
+use "fmt.use"
+
+pkg std =
+ const pathcat : (a : byte[:], b : byte[:] -> byte[:])
+ const pathjoin : (p : byte[:][:] -> byte[:])
+ const pathnorm : (p : byte[:] -> byte[:])
+;;
+
+const pathcat = {a, b
+ -> pathjoin([a, b][:])
+}
+
+const pathjoin = {l
+ var p, q
+
+ p = strjoin(l, "/")
+ q = pathnorm(p)
+ slfree(p)
+ -> q
+}
+
+const pathnorm = {p
+ var comps
+ var i, del, dst
+ var s, ret
+
+ comps = strsplit(p, "/")
+ /* "." is a no-op component, so we drop it */
+ for i = 0; i < comps.len; i++
+ if sleq(comps[i], ".")
+ comps[i] = ""
+ ;;
+ ;;
+
+ /* then, resolve '..' by cancelling out previous components */
+ for i = 0; i < comps.len; i++
+ if !sleq(comps[i], "..")
+ continue
+ ;;
+ for del = 1; del <= i; del++
+ if comps[i - del].len > 0 && !sleq(comps[i-del], "..")
+ comps[i - del] = ""
+ comps[i] = ""
+ break
+ ;;
+ ;;
+ ;;
+
+ /* clear out the path nodes we decided to drop */
+ dst = 0
+ for i = 0; i < comps.len; i++
+ if comps[i].len > 0
+ comps[dst++] = comps[i]
+ ;;
+ ;;
+ comps = comps[:dst]
+
+ /* and reassemble */
+ if p.len > 0 && sleq(p[:1], "/")
+ /* /.. is just / */
+ for i = 0; i < comps.len; i++
+ if !sleq(comps[i], "..")
+ break
+ ;;
+ ;;
+ s = strjoin(comps[i:], "/")
+ ret = fmt("/%s", s)
+ slfree(s)
+ elif comps.len == 0
+ /* empty paths become '.' */
+ ret = sldup(".")
+ else
+ ret = strjoin(comps, "/")
+ ;;
+ slfree(comps)
+ -> ret
+}
+
--- a/myrbuild/myrbuild.c
+++ b/myrbuild/myrbuild.c
@@ -419,8 +419,6 @@
die("Unknown file type %s", files[i]);
lappend(&args, &nargs, strdup(buf));
}
- snprintf(buf, sizeof buf, "-L%s%s", Instroot, "/lib/myr");
- lappend(&args, &nargs, strdup(buf));
/* ld -T ldscript -o outfile foo.o bar.o baz.o -L/path1 -L/path2 */
for (i = 0; i < nincpaths; i++) {
@@ -427,6 +425,8 @@
snprintf(buf, sizeof buf, "-L%s", incpaths[i]);
lappend(&args, &nargs, strdup(buf));
}
+ snprintf(buf, sizeof buf, "-L%s%s", Instroot, "/lib/myr");
+ lappend(&args, &nargs, strdup(buf));
/* ld -T ldscript -o outfile foo.o bar.o baz.o -L/path1 -L/path2 -llib1 -llib2*/
addlibs(&args, &nargs, libgraph);
--- /dev/null
+++ b/test/stdpathnorm.myr
@@ -1,0 +1,38 @@
+use std
+
+const main = {
+ /* untouched */
+ std.put("%s\n", std.pathnorm("foo"))
+ std.put("%s\n", std.pathnorm("foo/bar"))
+ std.put("%s\n", std.pathnorm("/foo/bar"))
+ std.put("%s\n", std.pathnorm("."))
+
+ /* empty path becomes "." */
+ std.put("%s\n", std.pathnorm("."))
+
+ /* delete //, trailing / */
+ std.put("%s\n", std.pathnorm("foo/"))
+ std.put("%s\n", std.pathnorm("foo//bar/baz"))
+ std.put("%s\n", std.pathnorm("//foo//bar/"))
+
+ /* delete '.' */
+ std.put("%s\n", std.pathnorm("foo/./bar"))
+ std.put("%s\n", std.pathnorm("/foo/bar/."))
+ std.put("%s\n", std.pathnorm("./foo/bar/."))
+
+ /* elide '..' */
+ std.put("%s\n", std.pathnorm("/../foo/bar"))
+ std.put("%s\n", std.pathnorm("../../foo/bar"))
+ std.put("%s\n", std.pathnorm("foo/bar/.."))
+ std.put("%s\n", std.pathnorm("foo/bar/../.."))
+ std.put("%s\n", std.pathnorm("foo/../bar/../.."))
+ std.put("%s\n", std.pathnorm("/foo/../bar/../.."))
+
+ /* mix all of the above */
+ std.put("%s\n", std.pathnorm("/../foo//bar"))
+ std.put("%s\n", std.pathnorm("..//../foo/bar"))
+ std.put("%s\n", std.pathnorm("foo//./bar/.."))
+ std.put("%s\n", std.pathnorm("foo/bar/.././.."))
+ std.put("%s\n", std.pathnorm("//foo/../bar/../.."))
+ std.put("%s\n", std.pathnorm("foo/../bar/../.."))
+}
--- a/test/tests
+++ b/test/tests
@@ -129,6 +129,7 @@
B strjoin C
B stdslcp C
B stdfmtpad C
+B stdpathnorm C
B bigint C
B exporttrait
# B local-labels E 10 ## BUGGERED