ref: babf901b4a508c3ec5d1f89655f10377bbdf9637
dir: /appl/cmd/gzip.b/
implement Gzip;
include "sys.m";
sys: Sys;
print, fprint: import sys;
include "draw.m";
include "string.m";
str: String;
include "daytime.m";
daytime: Daytime;
include "bufio.m";
bufio: Bufio;
Iobuf: import bufio;
include "filter.m";
deflate: Filter;
DEFLATEPATH: con "/dis/lib/deflate.dis";
Gzip: module
{
init: fn(ctxt: ref Draw->Context, argv: list of string);
};
Arg: adt
{
argv: list of string;
c: int;
opts: string;
init: fn(argv: list of string): ref Arg;
opt: fn(arg: self ref Arg): int;
arg: fn(arg: self ref Arg): string;
};
argv0: con "gzip";
stderr: ref Sys->FD;
debug := 0;
verbose := 0;
level := 0;
usage()
{
fprint(stderr, "usage: %s [-vD1-9] [file ...]\n", argv0);
raise "fail:usage";
}
nomod(path: string)
{
sys->fprint(stderr, "%s: cannot load %s: %r\n", argv0, path);
raise "fail:bad module";
}
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)
nomod(Bufio->PATH);
str = load String String->PATH;
if (str == nil)
nomod(String->PATH);
daytime = load Daytime Daytime->PATH;
if (daytime == nil)
nomod(Daytime->PATH);
deflate = load Filter DEFLATEPATH;
if(deflate == nil)
nomod(DEFLATEPATH);
arg := Arg.init(argv);
level = 6;
while(c := arg.opt()){
case c{
'D' =>
debug++;
'v' =>
verbose++;
'1' to '9' =>
level = c - '0';
* =>
usage();
}
}
deflate->init();
argv = arg.argv;
ok := 1;
if(len argv == 0){
bin := bufio->fopen(sys->fildes(0), Bufio->OREAD);
bout := bufio->fopen(sys->fildes(1), Bufio->OWRITE);
ok = gzip(nil, daytime->now(), bin, bout, "stdin", "stdout");
bout.close();
bin.close();
}else{
for(; argv != nil; argv = tl argv)
ok &= gzipf(hd argv);
}
exit;
}
gzipf(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;
}
(ok, dir) := sys->fstat(bin.fd);
if(ok >= 0)
mtime := dir.mtime;
else
mtime = daytime->now();
(nil, ofile) := str->splitr(file, "/");
ofile += ".gz";
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 = gzip(file, mtime, bin, bout, file, ofile);
bout.close();
bin.close();
if (ok)
sys->remove(file);
else
sys->remove(ofile);
return ok;
}
gzip(nil: string, nil: int, bin, bout: ref Iobuf, fin, fout: string): int
{
param := "h" + string level;
incount := outcount := 0;
if (debug)
param += "dv";
rq := deflate->start(param);
for (;;) {
pick m := <-rq {
Fill =>
n := bin.read(m.buf, len m.buf);
m.reply <-= n;
if (n == -1) {
sys->fprint(stderr, "%s: error reading %s: %r\n", argv0, fin);
return 0;
}
incount += n;
Result =>
n := len m.buf;
if (bout.write(m.buf, n) != n) {
sys->fprint(stderr, "%s: error writing %s: %r\n", argv0, fout);
m.reply <-= -1;
return 0;
}
m.reply <-= 0;
outcount += n;
Info =>
sys->fprint(stderr, "%s\n", m.msg);
Finished =>
comp := 0.0;
if (incount > 0)
comp = 1.0 - real outcount / real incount;
if (verbose)
sys->fprint(stderr, "%s: %5.2f%%\n", fin, comp * 100.0);
return 1;
Error =>
sys->fprint(stderr, "%s: error compressing %s: %s\n", argv0, fin, m.e);
return 0;
}
}
}
fatal(msg: string)
{
fprint(stderr, "%s: %s\n", argv0, msg);
exit;
}
Arg.init(argv: list of string): ref Arg
{
if(argv != nil)
argv = tl argv;
return ref Arg(argv, 0, nil);
}
Arg.opt(arg: self ref Arg): int
{
if(arg.opts != ""){
arg.c = arg.opts[0];
arg.opts = arg.opts[1:];
return arg.c;
}
if(arg.argv == nil)
return arg.c = 0;
arg.opts = hd arg.argv;
if(len arg.opts < 2 || arg.opts[0] != '-')
return arg.c = 0;
arg.argv = tl arg.argv;
if(arg.opts == "--")
return arg.c = 0;
arg.c = arg.opts[1];
arg.opts = arg.opts[2:];
return arg.c;
}
Arg.arg(arg: self ref Arg): string
{
s := arg.opts;
arg.opts = "";
if(s != "")
return s;
if(arg.argv == nil)
return "";
s = hd arg.argv;
arg.argv = tl arg.argv;
return s;
}