summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libstd/Makefile1
-rw-r--r--libstd/pathjoin.myr85
-rw-r--r--myrbuild/myrbuild.c4
-rw-r--r--test/stdpathnorm.myr38
-rw-r--r--test/tests1
5 files changed, 127 insertions, 2 deletions
diff --git a/libstd/Makefile b/libstd/Makefile
index 6df82c5..5a0d6eb 100644
--- a/libstd/Makefile
+++ b/libstd/Makefile
@@ -26,6 +26,7 @@ MYRSRC= \
now.myr \
option.myr \
optparse.myr \
+ pathjoin.myr \
rand.myr \
resolve.myr \
result.myr \
diff --git a/libstd/pathjoin.myr b/libstd/pathjoin.myr
new file mode 100644
index 0000000..026f4e0
--- /dev/null
+++ b/libstd/pathjoin.myr
@@ -0,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
+}
+
diff --git a/myrbuild/myrbuild.c b/myrbuild/myrbuild.c
index 4d2c434..2e098da 100644
--- a/myrbuild/myrbuild.c
+++ b/myrbuild/myrbuild.c
@@ -419,14 +419,14 @@ void linkobj(char **files, size_t nfiles)
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++) {
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);
diff --git a/test/stdpathnorm.myr b/test/stdpathnorm.myr
new file mode 100644
index 0000000..1e8c3d6
--- /dev/null
+++ b/test/stdpathnorm.myr
@@ -0,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/../.."))
+}
diff --git a/test/tests b/test/tests
index e20d30b..963f5a0 100644
--- a/test/tests
+++ b/test/tests
@@ -129,6 +129,7 @@ B strfind C
B strjoin C
B stdslcp C
B stdfmtpad C
+B stdpathnorm C
B bigint C
B exporttrait
# B local-labels E 10 ## BUGGERED