xref: /inferno-os/appl/cmd/gunzip.b (revision 1acfc925c1ab17e400f630f017155ac4316930a4)
1implement Gunzip;
2
3include "sys.m";
4	sys:	Sys;
5	fprint, sprint: import sys;
6
7include "draw.m";
8
9include "string.m";
10	str: String;
11
12include "bufio.m";
13	bufio:	Bufio;
14	Iobuf:	import bufio;
15
16include "filter.m";
17	inflate: Filter;
18
19Gunzip: module
20{
21	init:	fn(ctxt: ref Draw->Context, argv: list of string);
22};
23
24argv0:	con "gunzip";
25stderr:	ref Sys->FD;
26
27INFLATEPATH: con "/dis/lib/inflate.dis";
28
29init(nil: ref Draw->Context, argv: list of string)
30{
31	sys = load Sys Sys->PATH;
32	stderr = sys->fildes(2);
33	bufio = load Bufio Bufio->PATH;
34	if (bufio == nil)
35		fatal(sys->sprint("cannot load %s: %r", Bufio->PATH));
36	str = load String String->PATH;
37	if (str == nil)
38		fatal(sys->sprint("cannot load %s: %r", String->PATH));
39	inflate = load Filter INFLATEPATH;
40	if (inflate == nil)
41		fatal(sys->sprint("cannot load %s: %r", INFLATEPATH));
42
43	inflate->init();
44
45	if(argv != nil)
46		argv = tl argv;
47
48	ok := 1;
49	if(len argv == 0){
50		bin := bufio->fopen(sys->fildes(0), Bufio->OREAD);
51		bout := bufio->fopen(sys->fildes(1), Bufio->OWRITE);
52		ok = gunzip(bin, bout, "stdin", "stdout");
53		bout.close();
54	} else {
55		for(; argv != nil; argv = tl argv)
56			ok &= gunzipf(hd argv);
57	}
58	if(ok == 0)
59		raise "fail:errors";
60}
61
62gunzipf(file: string): int
63{
64	bin := bufio->open(file, Bufio->OREAD);
65	if(bin == nil){
66		fprint(stderr, "%s: can't open %s: %r\n", argv0, file);
67		return 0;
68	}
69
70	(nil, ofile) := str->splitr(file, "/");
71	n := len ofile;
72	if(n < 4 || ofile[n-3:] != ".gz"){
73		fprint(stderr, "%s: .gz extension required: %s\n", argv0, file);
74		bin.close();
75		return 0;
76	} else
77		ofile = ofile[:n-3];
78	bout := bufio->create(ofile, Bufio->OWRITE, 8r666);
79	if(bout == nil){
80		fprint(stderr, "%s: can't open %s: %r\n", argv0, ofile);
81		bin.close();
82		return 0;
83	}
84
85	ok := gunzip(bin, bout, file, ofile);
86	bin.close();
87	bout.close();
88	if(ok) {
89		# did possibly rename file and update modification time here.
90		if (sys->remove(file) == -1)
91			sys->fprint(stderr, "%s: cannot remove %s: %r\n", argv0, file);
92	}
93
94	return ok;
95}
96
97gunzip(bin, bout: ref Iobuf, fin, fout: string): int
98{
99	rq := inflate->start("h");
100	for(;;) {
101		pick m := <-rq {
102		Fill =>
103			n := bin.read(m.buf, len m.buf);
104			m.reply <-= n;
105			if (n == -1) {
106				sys->fprint(stderr, "%s: %s: read error: %r\n", argv0, fin);
107				return 0;
108			}
109		Result =>
110			if (len m.buf > 0) {
111				n := bout.write(m.buf, len m.buf);
112				if (n != len m.buf) {
113					m.reply <-= -1;
114					sys->fprint(stderr, "%s: %s: write error: %r\n", argv0, fout);
115					return 0;
116				}
117				m.reply <-= 0;
118			}
119		#Info =>
120		#	if m.msg begins with "file", it's the original filename of the compressed file.
121		#	if m.msg begins with "mtime", it's the original modification time.
122		Finished =>
123			if (bout.flush() != 0) {
124				sys->fprint(stderr, "%s: %s: flush error: %r\n", argv0, fout);
125				return 0;
126			}
127			return 1;
128		Error =>
129			sys->fprint(stderr, "%s: %s: inflate error: %s\n", argv0, fin, m.e);
130			return 0;
131		}
132	}
133}
134
135fatal(msg: string)
136{
137	fprint(stderr, "%s: %s\n", argv0, msg);
138	raise "fail:error";
139}
140