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;}
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;
}