summaryrefslogtreecommitdiff
path: root/appl/cmd/gzip.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/cmd/gzip.b')
-rw-r--r--appl/cmd/gzip.b228
1 files changed, 228 insertions, 0 deletions
diff --git a/appl/cmd/gzip.b b/appl/cmd/gzip.b
new file mode 100644
index 00000000..b87186d0
--- /dev/null
+++ b/appl/cmd/gzip.b
@@ -0,0 +1,228 @@
+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);
+ crc := 0;
+ 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;
+}