diff options
Diffstat (limited to 'appl/cmd/uudecode.b')
| -rw-r--r-- | appl/cmd/uudecode.b | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/appl/cmd/uudecode.b b/appl/cmd/uudecode.b new file mode 100644 index 00000000..12894aa3 --- /dev/null +++ b/appl/cmd/uudecode.b @@ -0,0 +1,132 @@ +implement Uudecode; + +include "sys.m"; + sys : Sys; +include "draw.m"; +include "string.m"; + str : String; +include "bufio.m"; + bufio : Bufio; + Iobuf : import bufio; + +Uudecode : module +{ + init : fn(nil : ref Draw->Context, argv : list of string); +}; + +fatal(s : string) +{ + sys->fprint(sys->fildes(2), "%s\n", s); + exit; +} + +usage() +{ + fatal("usage: uudecode [ -p ] [ encodedfile... ]"); +} + +init(nil : ref Draw->Context, argv : list of string) +{ + fd : ref Sys->FD; + + tostdout := 0; + sys = load Sys Sys->PATH; + str = load String String->PATH; + bufio = load Bufio Bufio->PATH; + argv = tl argv; + if (argv != nil && hd argv == "-p") { + tostdout = 1; + argv = tl argv; + } + if (argv != nil) { + for (; argv != nil; argv = tl argv) { + fd = sys->open(hd argv, Sys->OREAD); + if (fd == nil) + fatal(sys->sprint("cannot open %s", hd argv)); + decode(fd, tostdout); + } + } + else + decode(sys->fildes(0), tostdout); +} + +code(c : byte) : int +{ + return (int c - ' ')&16r3f; +} + +LEN : con 45; + +decode(ifd : ref Sys->FD, tostdout : int) +{ + mode : int; + ofile : string; + + bio := bufio->fopen(ifd, Bufio->OREAD); + if (bio == nil) + fatal("cannot open input for buffered io: %r"); + while ((s := bio.gets('\n')) != nil) { + if (len s >= 6 && s[0:6] == "begin ") { + (n, l) := sys->tokenize(s, " \n"); + if (n < 3) + fatal("bad begin line"); + (mode, nil) = str->toint(hd tl l, 8); + ofile = hd tl tl l; + break; + } + } + if (ofile == nil) + fatal("no begin line"); + if (tostdout) + ofd := sys->fildes(1); + else { + if (ofile[0] == '~') # ~user/file + ofile = "/usr/" + ofile[1:]; + ofd = sys->create(ofile, Sys->OWRITE, 8r666); + if (ofd == nil) + fatal(sys->sprint("cannot create %s: %r", ofile)); + } + ob := array[LEN] of byte; + while ((s = bio.gets('\n')) != nil) { + b := array of byte s; + n := code(b[0]); + if (n == 0 && (len b != 2 || b[1] != byte '\n')) + fatal("bad 0 count line"); + if (n <= 0) + break; + if (n > LEN) + fatal("too many bytes on line"); + e := 0; f := 0; + if (n%3 == 1) { + e = 2; f = 4; + } + else if (n%3 == 2) { + e = 3; f = 4; + } + if (len b < 4*(n/3)+e+2 || len b > 4*(n/3)+f+2) + fatal("bad uuencode count"); + b = b[1:]; + i := 0; + nl := n; + for (j := 0; nl > 0; j += 4) { + if (nl >= 1) + ob[i++] = byte (code(b[j+0])<<2 | code(b[j+1])>>4); + if (nl >= 2) + ob[i++] = byte (code(b[j+1])<<4 | code(b[j+2])>>2); + if (nl >= 3) + ob[i++] = byte (code(b[j+2])<<6 | code(b[j+3])>>0); + nl -= 3; + } + if (sys->write(ofd, ob, i) != i) + fatal("bad write to output: %r"); + } + s = bio.gets('\n'); + if (s == nil || len s < 4 || s[0:4] != "end\n") + fatal("missing end line"); + if (!tostdout) { + d := sys->nulldir; + d.mode = mode; + if (sys->fwstat(ofd, d) < 0) + fatal(sys->sprint("cannot wstat %s: %r", ofile)); + } +} |
