1implement Uudecode; 2 3include "sys.m"; 4 sys : Sys; 5include "draw.m"; 6include "string.m"; 7 str : String; 8include "bufio.m"; 9 bufio : Bufio; 10 Iobuf : import bufio; 11 12Uudecode : module 13{ 14 init : fn(nil : ref Draw->Context, argv : list of string); 15}; 16 17fatal(s : string) 18{ 19 sys->fprint(sys->fildes(2), "%s\n", s); 20 exit; 21} 22 23usage() 24{ 25 fatal("usage: uudecode [ -p ] [ encodedfile... ]"); 26} 27 28init(nil : ref Draw->Context, argv : list of string) 29{ 30 fd : ref Sys->FD; 31 32 tostdout := 0; 33 sys = load Sys Sys->PATH; 34 str = load String String->PATH; 35 bufio = load Bufio Bufio->PATH; 36 argv = tl argv; 37 if (argv != nil && hd argv == "-p") { 38 tostdout = 1; 39 argv = tl argv; 40 } 41 if (argv != nil) { 42 for (; argv != nil; argv = tl argv) { 43 fd = sys->open(hd argv, Sys->OREAD); 44 if (fd == nil) 45 fatal(sys->sprint("cannot open %s", hd argv)); 46 decode(fd, tostdout); 47 } 48 } 49 else 50 decode(sys->fildes(0), tostdout); 51} 52 53code(c : byte) : int 54{ 55 return (int c - ' ')&16r3f; 56} 57 58LEN : con 45; 59 60decode(ifd : ref Sys->FD, tostdout : int) 61{ 62 mode : int; 63 ofile : string; 64 65 bio := bufio->fopen(ifd, Bufio->OREAD); 66 if (bio == nil) 67 fatal("cannot open input for buffered io: %r"); 68 while ((s := bio.gets('\n')) != nil) { 69 if (len s >= 6 && s[0:6] == "begin ") { 70 (n, l) := sys->tokenize(s, " \n"); 71 if (n < 3) 72 fatal("bad begin line"); 73 (mode, nil) = str->toint(hd tl l, 8); 74 ofile = hd tl tl l; 75 break; 76 } 77 } 78 if (ofile == nil) 79 fatal("no begin line"); 80 if (tostdout) 81 ofd := sys->fildes(1); 82 else { 83 if (ofile[0] == '~') # ~user/file 84 ofile = "/usr/" + ofile[1:]; 85 ofd = sys->create(ofile, Sys->OWRITE, 8r666); 86 if (ofd == nil) 87 fatal(sys->sprint("cannot create %s: %r", ofile)); 88 } 89 ob := array[LEN] of byte; 90 while ((s = bio.gets('\n')) != nil) { 91 b := array of byte s; 92 n := code(b[0]); 93 if (n == 0 && (len b != 2 || b[1] != byte '\n')) 94 fatal("bad 0 count line"); 95 if (n <= 0) 96 break; 97 if (n > LEN) 98 fatal("too many bytes on line"); 99 e := 0; f := 0; 100 if (n%3 == 1) { 101 e = 2; f = 4; 102 } 103 else if (n%3 == 2) { 104 e = 3; f = 4; 105 } 106 if (len b < 4*(n/3)+e+2 || len b > 4*(n/3)+f+2) 107 fatal("bad uuencode count"); 108 b = b[1:]; 109 i := 0; 110 nl := n; 111 for (j := 0; nl > 0; j += 4) { 112 if (nl >= 1) 113 ob[i++] = byte (code(b[j+0])<<2 | code(b[j+1])>>4); 114 if (nl >= 2) 115 ob[i++] = byte (code(b[j+1])<<4 | code(b[j+2])>>2); 116 if (nl >= 3) 117 ob[i++] = byte (code(b[j+2])<<6 | code(b[j+3])>>0); 118 nl -= 3; 119 } 120 if (sys->write(ofd, ob, i) != i) 121 fatal("bad write to output: %r"); 122 } 123 s = bio.gets('\n'); 124 if (s == nil || len s < 4 || s[0:4] != "end\n") 125 fatal("missing end line"); 126 if (!tostdout) { 127 d := sys->nulldir; 128 d.mode = mode; 129 if (sys->fwstat(ofd, d) < 0) 130 fatal(sys->sprint("cannot wstat %s: %r", ofile)); 131 } 132} 133