diff options
Diffstat (limited to 'appl/cmd/ramfile.b')
| -rw-r--r-- | appl/cmd/ramfile.b | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/appl/cmd/ramfile.b b/appl/cmd/ramfile.b new file mode 100644 index 00000000..677bf18b --- /dev/null +++ b/appl/cmd/ramfile.b @@ -0,0 +1,97 @@ +implement Ramfile; +include "sys.m"; + sys: Sys; +include "draw.m"; + +# synthesise a file that can be treated just like any other +# file. limitations of file2chan mean that it's not possible +# to know when an open should have truncated the file, so +# we do the only possible thing, and truncate it when we get +# a write at offset 0. thus it can be edited with an editor, +# but can't be used to store seekable, writable data records +# (unless the first record is never written) + +# there should be some way to determine when the file should +# go away - file2chan sends a nil channel whenever the file +# is closed by anyone, which is not good enough. + +stderr: ref Sys->FD; + +Ramfile: module { + init: fn(nil: ref Draw->Context, argv: list of string); +}; + +init(nil: ref Draw->Context, argv: list of string) +{ + sys = load Sys Sys->PATH; + stderr = sys->fildes(2); + if (len argv < 2 || len argv > 3) { + sys->fprint(stderr, "usage: ramfile path [data]\n"); + return; + } + path := hd tl argv; + (dir, f) := pathsplit(path); + + if (sys->bind("#s", dir, Sys->MBEFORE|Sys->MCREATE) == -1) { + sys->fprint(stderr, "ramfile: %r\n"); + return; + } + fio := sys->file2chan(dir, f); + if (fio == nil) { + sys->fprint(stderr, "ramfile: file2chan failed: %r\n"); + return; + } + data := array[0] of byte; + if (tl tl argv != nil) + data = array of byte hd tl tl argv; + + spawn server(fio, data); + data = nil; +} + +server(fio: ref Sys->FileIO, data: array of byte) +{ + for (;;) alt { + (offset, count, fid, rc) := <-fio.read => + if (rc != nil) { + if (offset > len data) + rc <-= (nil, nil); + else { + end := offset + count; + if (end > len data) + end = len data; + rc <-= (data[offset:end], nil); + } + } + (offset, d, fid, wc) := <-fio.write => + if (wc != nil) { + if (offset == 0) + data = array[0] of byte; + end := offset + len d; + if (end > len data) { + ndata := array[end] of byte; + ndata[0:] = data; + data = ndata; + ndata = nil; + } + data[offset:] = d; + wc <-= (len d, nil); + } + } +} + +pathsplit(p: string): (string, string) +{ + for (i := len p - 1; i >= 0; i--) + if (p[i] != '/') + break; + if (i < 0) + return (p, nil); + p = p[0:i+1]; + for (i = len p - 1; i >=0; i--) + if (p[i] == '/') + break; + if (i < 0) + return (".", p); + return (p[0:i+1], p[i+1:]); +} |
