1implement Gunzip; 2 3include "sys.m"; 4 sys: Sys; 5 fprint, sprint: import sys; 6 7include "draw.m"; 8 9include "string.m"; 10 str: String; 11 12include "bufio.m"; 13 bufio: Bufio; 14 Iobuf: import bufio; 15 16include "filter.m"; 17 inflate: Filter; 18 19Gunzip: module 20{ 21 init: fn(ctxt: ref Draw->Context, argv: list of string); 22}; 23 24argv0: con "gunzip"; 25stderr: ref Sys->FD; 26 27INFLATEPATH: con "/dis/lib/inflate.dis"; 28 29init(nil: ref Draw->Context, argv: list of string) 30{ 31 sys = load Sys Sys->PATH; 32 stderr = sys->fildes(2); 33 bufio = load Bufio Bufio->PATH; 34 if (bufio == nil) 35 fatal(sys->sprint("cannot load %s: %r", Bufio->PATH)); 36 str = load String String->PATH; 37 if (str == nil) 38 fatal(sys->sprint("cannot load %s: %r", String->PATH)); 39 inflate = load Filter INFLATEPATH; 40 if (inflate == nil) 41 fatal(sys->sprint("cannot load %s: %r", INFLATEPATH)); 42 43 inflate->init(); 44 45 if(argv != nil) 46 argv = tl argv; 47 48 ok := 1; 49 if(len argv == 0){ 50 bin := bufio->fopen(sys->fildes(0), Bufio->OREAD); 51 bout := bufio->fopen(sys->fildes(1), Bufio->OWRITE); 52 ok = gunzip(bin, bout, "stdin", "stdout"); 53 bout.close(); 54 } else { 55 for(; argv != nil; argv = tl argv) 56 ok &= gunzipf(hd argv); 57 } 58 if(ok == 0) 59 raise "fail:errors"; 60} 61 62gunzipf(file: string): int 63{ 64 bin := bufio->open(file, Bufio->OREAD); 65 if(bin == nil){ 66 fprint(stderr, "%s: can't open %s: %r\n", argv0, file); 67 return 0; 68 } 69 70 (nil, ofile) := str->splitr(file, "/"); 71 n := len ofile; 72 if(n < 4 || ofile[n-3:] != ".gz"){ 73 fprint(stderr, "%s: .gz extension required: %s\n", argv0, file); 74 bin.close(); 75 return 0; 76 } else 77 ofile = ofile[:n-3]; 78 bout := bufio->create(ofile, Bufio->OWRITE, 8r666); 79 if(bout == nil){ 80 fprint(stderr, "%s: can't open %s: %r\n", argv0, ofile); 81 bin.close(); 82 return 0; 83 } 84 85 ok := gunzip(bin, bout, file, ofile); 86 bin.close(); 87 bout.close(); 88 if(ok) { 89 # did possibly rename file and update modification time here. 90 if (sys->remove(file) == -1) 91 sys->fprint(stderr, "%s: cannot remove %s: %r\n", argv0, file); 92 } 93 94 return ok; 95} 96 97gunzip(bin, bout: ref Iobuf, fin, fout: string): int 98{ 99 rq := inflate->start("h"); 100 for(;;) { 101 pick m := <-rq { 102 Fill => 103 n := bin.read(m.buf, len m.buf); 104 m.reply <-= n; 105 if (n == -1) { 106 sys->fprint(stderr, "%s: %s: read error: %r\n", argv0, fin); 107 return 0; 108 } 109 Result => 110 if (len m.buf > 0) { 111 n := bout.write(m.buf, len m.buf); 112 if (n != len m.buf) { 113 m.reply <-= -1; 114 sys->fprint(stderr, "%s: %s: write error: %r\n", argv0, fout); 115 return 0; 116 } 117 m.reply <-= 0; 118 } 119 #Info => 120 # if m.msg begins with "file", it's the original filename of the compressed file. 121 # if m.msg begins with "mtime", it's the original modification time. 122 Finished => 123 if (bout.flush() != 0) { 124 sys->fprint(stderr, "%s: %s: flush error: %r\n", argv0, fout); 125 return 0; 126 } 127 return 1; 128 Error => 129 sys->fprint(stderr, "%s: %s: inflate error: %s\n", argv0, fin, m.e); 130 return 0; 131 } 132 } 133} 134 135fatal(msg: string) 136{ 137 fprint(stderr, "%s: %s\n", argv0, msg); 138 raise "fail:error"; 139} 140