diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
| commit | 37da2899f40661e3e9631e497da8dc59b971cbd0 (patch) | |
| tree | cbc6d4680e347d906f5fa7fca73214418741df72 /appl/cmd/gzip.b | |
| parent | 54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff) | |
20060303a
Diffstat (limited to 'appl/cmd/gzip.b')
| -rw-r--r-- | appl/cmd/gzip.b | 228 |
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; +} |
