ref: babf901b4a508c3ec5d1f89655f10377bbdf9637
dir: /appl/cmd/uudecode.b/
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));
}
}