diff options
author | Ori Bernstein <ori@markovcorp.com> | 2018-01-26 18:14:27 -0800 |
---|---|---|
committer | Ori Bernstein <ori@markovcorp.com> | 2018-01-26 18:14:27 -0800 |
commit | 24a566ff1751b246c8b6efd8adea3447975b9efa (patch) | |
tree | b535f619dfc91f50622643f121fb0283fac8eac5 | |
parent | 83bca2aaa7635be1ef17fdd5e3b02348b79f7dcc (diff) | |
download | mc-24a566ff1751b246c8b6efd8adea3447975b9efa.tar.gz |
Improve our env code, add tests.
It was fragile.
-rw-r--r-- | lib/std/env+posixy.myr | 85 | ||||
-rw-r--r-- | lib/std/test/env.myr | 38 |
2 files changed, 81 insertions, 42 deletions
diff --git a/lib/std/env+posixy.myr b/lib/std/env+posixy.myr index f5e77d1..795089a 100644 --- a/lib/std/env+posixy.myr +++ b/lib/std/env+posixy.myr @@ -11,6 +11,7 @@ use "sldup" use "slcp" use "sleq" use "slpush" +use "threadhooks" pkg std = const getenv : (name : byte[:] -> option(byte[:])) @@ -47,67 +48,67 @@ const getenvv = {name, default } const setenv = {name, val - var n, e, env, idx + var n, e, env, idx, found + + envinit() - envdup() idx = 0 + found = false e = fmt("{}={}\0", name, val) + + lock(envlck) for envp : environ - if envp == Zenvp - slpush(&environ, (0 : byte#)) - environ[idx] = (e : byte#) - break - ;; - env = cstrconvp(envp) - n = min(name.len, env.len) - if sleq(name, env[:n]) && sleq(env[n:n+1], "=") - e = cstrconvp(environ[idx]) - std.slfree(e) - environ[idx] = (e : byte#) - break + if envp != Zenvp + env = cstrconvp(envp) + n = min(name.len, env.len - 1) + if sleq(name, env[:n]) && env[n] == ('=' : byte) + found = true + break + ;; + idx++ ;; - idx++ ;; + if !found + idx = env.len - 1 + std.slpush(&environ, Zenvp) + ;; + e = cstrconvp(environ[idx]) sys.__cenvp = (environ : byte##) + unlock(envlck) } const envinit = { - var len + var len, e, p + lock(envlck) if environ.len != 0 + unlock(envlck) -> void ;; - environ = sys.__cenvp[:1] + + /* + Here, we duplicate the environment so we can + modify it. We take progressively bigger slices + as we go, until we find the terminating null. + + It's a bit ugly, but what do? + */ len = 0 + environ = [][:] while true - len++ - environ = sys.__cenvp[:len + 1] + p = sys.__cenvp[:len+1][len] + if p != Zenvp + e = sldup(cstrconvp(p)) + slpush(&e, 0) + p = (e : byte#) + ;; + std.slpush(&environ, p) if environ[len] == Zenvp - environ = sys.__cenvp[:len + 1] break ;; + len++ ;; -} - -const envdup = { - var e, s, dup - - if envduped - -> void - ;; - envduped = true - envinit() - dup = std.slalloc(environ.len + 1) - for var i = 0; i < environ.len; i++ - if environ[i] != Zenvp - s = cstrconvp(environ[i]) - e = std.slalloc(s.len + 1) - slcp(e[:e.len - 1], s) - e[e.len - 1] = 0 - dup[i] = (e : byte#) - ;; - ;; - dup[dup.len - 1] = Zenvp - environ = dup sys.__cenvp = (environ : byte##) + unlock(envlck) } + diff --git a/lib/std/test/env.myr b/lib/std/test/env.myr new file mode 100644 index 0000000..31b3b2d --- /dev/null +++ b/lib/std/test/env.myr @@ -0,0 +1,38 @@ +use std +use testr + +const main = { + var e, v + + /* set */ + for var i = 0; i < 100; i++ + e = std.fmt("ENV{}", i) + v = std.fmt("VAL{}", i) + std.setenv(e, v) + std.slfree(e) + std.slfree(v) + ;; + + for var i = 0; i < 100; i++ + e = std.fmt("ENV{}", i) + v = std.fmt("VAL{}", i) + std.assert(std.eq(std.getenvv(e, v), v), "get of {} failed", e) + std.slfree(e) + std.slfree(v) + ;; + + for var i = 0; i < 100; i++ + e = std.fmt("ENV{}", i) + v = std.fmt("VAL{}", 100-i) + std.setenv(e, v) + std.slfree(e) + std.slfree(v) + ;; + for var i = 0; i < 100; i++ + e = std.fmt("ENV{}", i) + v = std.fmt("VAL{}", 100-i) + std.assert(std.eq(std.getenvv(e, v), v), "get of {} failed", e) + std.slfree(e) + std.slfree(v) + ;; +} |