137da2899SCharles.Forsythimplement Ramfile; 237da2899SCharles.Forsythinclude "sys.m"; 337da2899SCharles.Forsyth sys: Sys; 437da2899SCharles.Forsythinclude "draw.m"; 537da2899SCharles.Forsyth 637da2899SCharles.Forsyth# synthesise a file that can be treated just like any other 737da2899SCharles.Forsyth# file. limitations of file2chan mean that it's not possible 837da2899SCharles.Forsyth# to know when an open should have truncated the file, so 937da2899SCharles.Forsyth# we do the only possible thing, and truncate it when we get 1037da2899SCharles.Forsyth# a write at offset 0. thus it can be edited with an editor, 1137da2899SCharles.Forsyth# but can't be used to store seekable, writable data records 1237da2899SCharles.Forsyth# (unless the first record is never written) 1337da2899SCharles.Forsyth 1437da2899SCharles.Forsyth# there should be some way to determine when the file should 1537da2899SCharles.Forsyth# go away - file2chan sends a nil channel whenever the file 1637da2899SCharles.Forsyth# is closed by anyone, which is not good enough. 1737da2899SCharles.Forsyth 1837da2899SCharles.Forsythstderr: ref Sys->FD; 1937da2899SCharles.Forsyth 2037da2899SCharles.ForsythRamfile: module { 2137da2899SCharles.Forsyth init: fn(nil: ref Draw->Context, argv: list of string); 2237da2899SCharles.Forsyth}; 2337da2899SCharles.Forsyth 2437da2899SCharles.Forsythinit(nil: ref Draw->Context, argv: list of string) 2537da2899SCharles.Forsyth{ 2637da2899SCharles.Forsyth sys = load Sys Sys->PATH; 2737da2899SCharles.Forsyth stderr = sys->fildes(2); 2837da2899SCharles.Forsyth if (len argv < 2 || len argv > 3) { 2937da2899SCharles.Forsyth sys->fprint(stderr, "usage: ramfile path [data]\n"); 3037da2899SCharles.Forsyth return; 3137da2899SCharles.Forsyth } 3237da2899SCharles.Forsyth path := hd tl argv; 3337da2899SCharles.Forsyth (dir, f) := pathsplit(path); 3437da2899SCharles.Forsyth 35*a3d4017dSCharles.Forsyth if (sys->bind("#s", dir, Sys->MBEFORE) == -1) { 3637da2899SCharles.Forsyth sys->fprint(stderr, "ramfile: %r\n"); 3737da2899SCharles.Forsyth return; 3837da2899SCharles.Forsyth } 3937da2899SCharles.Forsyth fio := sys->file2chan(dir, f); 4037da2899SCharles.Forsyth if (fio == nil) { 4137da2899SCharles.Forsyth sys->fprint(stderr, "ramfile: file2chan failed: %r\n"); 4237da2899SCharles.Forsyth return; 4337da2899SCharles.Forsyth } 4437da2899SCharles.Forsyth data := array[0] of byte; 4537da2899SCharles.Forsyth if (tl tl argv != nil) 4637da2899SCharles.Forsyth data = array of byte hd tl tl argv; 4737da2899SCharles.Forsyth 4837da2899SCharles.Forsyth spawn server(fio, data); 4937da2899SCharles.Forsyth data = nil; 5037da2899SCharles.Forsyth} 5137da2899SCharles.Forsyth 5237da2899SCharles.Forsythserver(fio: ref Sys->FileIO, data: array of byte) 5337da2899SCharles.Forsyth{ 5437da2899SCharles.Forsyth for (;;) alt { 553f1f06c5SCharles.Forsyth (offset, count, nil, rc) := <-fio.read => 5637da2899SCharles.Forsyth if (rc != nil) { 5737da2899SCharles.Forsyth if (offset > len data) 5837da2899SCharles.Forsyth rc <-= (nil, nil); 5937da2899SCharles.Forsyth else { 6037da2899SCharles.Forsyth end := offset + count; 6137da2899SCharles.Forsyth if (end > len data) 6237da2899SCharles.Forsyth end = len data; 6337da2899SCharles.Forsyth rc <-= (data[offset:end], nil); 6437da2899SCharles.Forsyth } 6537da2899SCharles.Forsyth } 663f1f06c5SCharles.Forsyth (offset, d, nil, wc) := <-fio.write => 6737da2899SCharles.Forsyth if (wc != nil) { 6837da2899SCharles.Forsyth if (offset == 0) 6937da2899SCharles.Forsyth data = array[0] of byte; 7037da2899SCharles.Forsyth end := offset + len d; 7137da2899SCharles.Forsyth if (end > len data) { 7237da2899SCharles.Forsyth ndata := array[end] of byte; 7337da2899SCharles.Forsyth ndata[0:] = data; 7437da2899SCharles.Forsyth data = ndata; 7537da2899SCharles.Forsyth ndata = nil; 7637da2899SCharles.Forsyth } 7737da2899SCharles.Forsyth data[offset:] = d; 7837da2899SCharles.Forsyth wc <-= (len d, nil); 7937da2899SCharles.Forsyth } 8037da2899SCharles.Forsyth } 8137da2899SCharles.Forsyth} 8237da2899SCharles.Forsyth 8337da2899SCharles.Forsythpathsplit(p: string): (string, string) 8437da2899SCharles.Forsyth{ 8537da2899SCharles.Forsyth for (i := len p - 1; i >= 0; i--) 8637da2899SCharles.Forsyth if (p[i] != '/') 8737da2899SCharles.Forsyth break; 8837da2899SCharles.Forsyth if (i < 0) 8937da2899SCharles.Forsyth return (p, nil); 9037da2899SCharles.Forsyth p = p[0:i+1]; 9137da2899SCharles.Forsyth for (i = len p - 1; i >=0; i--) 9237da2899SCharles.Forsyth if (p[i] == '/') 9337da2899SCharles.Forsyth break; 9437da2899SCharles.Forsyth if (i < 0) 9537da2899SCharles.Forsyth return (".", p); 9637da2899SCharles.Forsyth return (p[0:i+1], p[i+1:]); 9737da2899SCharles.Forsyth} 98