ref: babf901b4a508c3ec5d1f89655f10377bbdf9637
dir: /appl/cmd/gunzip.b/
implement Gunzip;
include "sys.m";
sys: Sys;
fprint, sprint: import sys;
include "draw.m";
include "string.m";
str: String;
include "bufio.m";
bufio: Bufio;
Iobuf: import bufio;
include "filter.m";
inflate: Filter;
Gunzip: module
{
init: fn(ctxt: ref Draw->Context, argv: list of string);
};
argv0: con "gunzip";
stderr: ref Sys->FD;
INFLATEPATH: con "/dis/lib/inflate.dis";
init(nil: ref Draw->Context, argv: list of string)
{
sys = load Sys Sys->PATH;
stderr = sys->fildes(2);
bufio = load Bufio Bufio->PATH;
if (bufio == nil)
fatal(sys->sprint("cannot load %s: %r", Bufio->PATH));
str = load String String->PATH;
if (bufio == nil)
fatal(sys->sprint("cannot load %s: %r", String->PATH));
inflate = load Filter INFLATEPATH;
if (inflate == nil)
fatal(sys->sprint("cannot load %s: %r", INFLATEPATH));
inflate->init();
if(argv != nil)
argv = tl argv;
ok := 1;
if(len argv == 0){
bin := bufio->fopen(sys->fildes(0), Bufio->OREAD);
bout := bufio->fopen(sys->fildes(1), Bufio->OWRITE);
ok = gunzip(bin, bout, "stdin", "stdout");
bout.close();
} else {
for(; argv != nil; argv = tl argv)
ok &= gunzipf(hd argv);
}
if(ok == 0)
raise "fail:errors";
}
gunzipf(file: string): int
{
bin := bufio->open(file, Bufio->OREAD);
if(bin == nil){
fprint(stderr, "%s: can't open %s: %r\n", argv0, file);
return 0;
}
(nil, ofile) := str->splitr(file, "/");
n := len ofile;
if(n < 4 || ofile[n-3:] != ".gz"){
fprint(stderr, "%s: .gz extension required: %s\n", argv0, file);
bin.close();
return 0;
} else
ofile = ofile[:n-3];
bout := bufio->create(ofile, Bufio->OWRITE, 8r666);
if(bout == nil){
fprint(stderr, "%s: can't open %s: %r\n", argv0, ofile);
bin.close();
return 0;
}
ok := gunzip(bin, bout, file, ofile);
bin.close();
bout.close();
if(ok) {
# did possibly rename file and update modification time here.
if (sys->remove(file) == -1)
sys->fprint(stderr, "%s: cannot remove %s: %r\n", argv0, file);
}
return ok;
}
gunzip(bin, bout: ref Iobuf, fin, fout: string): int
{
rq := inflate->start("h");
for(;;) {
pick m := <-rq {
Fill =>
n := bin.read(m.buf, len m.buf);
m.reply <-= n;
if (n == -1) {
sys->fprint(stderr, "%s: %s: read error: %r\n", argv0, fin);
return 0;
}
Result =>
if (len m.buf > 0) {
n := bout.write(m.buf, len m.buf);
if (n != len m.buf) {
m.reply <-= -1;
sys->fprint(stderr, "%s: %s: write error: %r\n", argv0, fout);
return 0;
}
m.reply <-= 0;
}
#Info =>
# if m.msg begins with "file", it's the original filename of the compressed file.
# if m.msg begins with "mtime", it's the original modification time.
Finished =>
if (bout.flush() != 0) {
sys->fprint(stderr, "%s: %s: flush error: %r\n", argv0, fout);
return 0;
}
return 1;
Error =>
sys->fprint(stderr, "%s: %s: inflate error: %s\n", argv0, fin, m.e);
return 0;
}
}
}
fatal(msg: string)
{
fprint(stderr, "%s: %s\n", argv0, msg);
raise "fail:error";
}