minigzip.c revision 1.1.1.4 1 1.1 christos /* minigzip.c -- simulate gzip using the zlib compression library
2 1.1 christos * Copyright (C) 1995-2006, 2010, 2011, 2016 Jean-loup Gailly
3 1.1 christos * For conditions of distribution and use, see copyright notice in zlib.h
4 1.1 christos */
5 1.1 christos
6 1.1 christos /*
7 1.1 christos * minigzip is a minimal implementation of the gzip utility. This is
8 1.1 christos * only an example of using zlib and isn't meant to replace the
9 1.1 christos * full-featured gzip. No attempt is made to deal with file systems
10 1.1 christos * limiting names to 14 or 8+3 characters, etc... Error checking is
11 1.1 christos * very limited. So use minigzip only for testing; use gzip for the
12 1.1 christos * real thing. On MSDOS, use only on file names without extension
13 1.1 christos * or in pipe mode.
14 1.1 christos */
15 1.1 christos
16 1.1.1.3 christos /* @(#) Id */
17 1.1 christos
18 1.1 christos #include "zlib.h"
19 1.1 christos #include <stdio.h>
20 1.1 christos
21 1.1 christos #ifdef STDC
22 1.1 christos # include <string.h>
23 1.1 christos # include <stdlib.h>
24 1.1 christos #endif
25 1.1 christos
26 1.1 christos #ifdef USE_MMAP
27 1.1 christos # include <sys/types.h>
28 1.1 christos # include <sys/mman.h>
29 1.1 christos # include <sys/stat.h>
30 1.1 christos #endif
31 1.1 christos
32 1.1 christos #if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
33 1.1 christos # include <fcntl.h>
34 1.1 christos # include <io.h>
35 1.1 christos # ifdef UNDER_CE
36 1.1 christos # include <stdlib.h>
37 1.1 christos # endif
38 1.1 christos # define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
39 1.1 christos #else
40 1.1 christos # define SET_BINARY_MODE(file)
41 1.1 christos #endif
42 1.1 christos
43 1.1 christos #if defined(_MSC_VER) && _MSC_VER < 1900
44 1.1 christos # define snprintf _snprintf
45 1.1 christos #endif
46 1.1 christos
47 1.1 christos #ifdef VMS
48 1.1 christos # define unlink delete
49 1.1 christos # define GZ_SUFFIX "-gz"
50 1.1 christos #endif
51 1.1 christos #ifdef RISCOS
52 1.1 christos # define unlink remove
53 1.1 christos # define GZ_SUFFIX "-gz"
54 1.1 christos # define fileno(file) file->__file
55 1.1 christos #endif
56 1.1 christos #if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
57 1.1 christos # include <unix.h> /* for fileno */
58 1.1 christos #endif
59 1.1 christos
60 1.1 christos #if !defined(Z_HAVE_UNISTD_H) && !defined(_LARGEFILE64_SOURCE)
61 1.1 christos #ifndef WIN32 /* unlink already in stdio.h for WIN32 */
62 1.1.1.4 christos extern int unlink(const char *);
63 1.1 christos #endif
64 1.1 christos #endif
65 1.1 christos
66 1.1 christos #if defined(UNDER_CE)
67 1.1 christos # include <windows.h>
68 1.1 christos # define perror(s) pwinerror(s)
69 1.1 christos
70 1.1 christos /* Map the Windows error number in ERROR to a locale-dependent error
71 1.1 christos message string and return a pointer to it. Typically, the values
72 1.1 christos for ERROR come from GetLastError.
73 1.1 christos
74 1.1 christos The string pointed to shall not be modified by the application,
75 1.1 christos but may be overwritten by a subsequent call to strwinerror
76 1.1 christos
77 1.1 christos The strwinerror function does not change the current setting
78 1.1 christos of GetLastError. */
79 1.1 christos
80 1.1 christos static char *strwinerror (error)
81 1.1 christos DWORD error;
82 1.1 christos {
83 1.1 christos static char buf[1024];
84 1.1 christos
85 1.1 christos wchar_t *msgbuf;
86 1.1 christos DWORD lasterr = GetLastError();
87 1.1 christos DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
88 1.1 christos | FORMAT_MESSAGE_ALLOCATE_BUFFER,
89 1.1 christos NULL,
90 1.1 christos error,
91 1.1 christos 0, /* Default language */
92 1.1 christos (LPVOID)&msgbuf,
93 1.1 christos 0,
94 1.1 christos NULL);
95 1.1 christos if (chars != 0) {
96 1.1 christos /* If there is an \r\n appended, zap it. */
97 1.1 christos if (chars >= 2
98 1.1 christos && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') {
99 1.1 christos chars -= 2;
100 1.1 christos msgbuf[chars] = 0;
101 1.1 christos }
102 1.1 christos
103 1.1 christos if (chars > sizeof (buf) - 1) {
104 1.1 christos chars = sizeof (buf) - 1;
105 1.1 christos msgbuf[chars] = 0;
106 1.1 christos }
107 1.1 christos
108 1.1 christos wcstombs(buf, msgbuf, chars + 1);
109 1.1 christos LocalFree(msgbuf);
110 1.1 christos }
111 1.1 christos else {
112 1.1 christos sprintf(buf, "unknown win32 error (%ld)", error);
113 1.1 christos }
114 1.1 christos
115 1.1 christos SetLastError(lasterr);
116 1.1 christos return buf;
117 1.1 christos }
118 1.1 christos
119 1.1 christos static void pwinerror (s)
120 1.1 christos const char *s;
121 1.1 christos {
122 1.1 christos if (s && *s)
123 1.1 christos fprintf(stderr, "%s: %s\n", s, strwinerror(GetLastError ()));
124 1.1 christos else
125 1.1 christos fprintf(stderr, "%s\n", strwinerror(GetLastError ()));
126 1.1 christos }
127 1.1 christos
128 1.1 christos #endif /* UNDER_CE */
129 1.1 christos
130 1.1 christos #ifndef GZ_SUFFIX
131 1.1 christos # define GZ_SUFFIX ".gz"
132 1.1 christos #endif
133 1.1 christos #define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1)
134 1.1 christos
135 1.1 christos #define BUFLEN 16384
136 1.1 christos #define MAX_NAME_LEN 1024
137 1.1 christos
138 1.1 christos #ifdef MAXSEG_64K
139 1.1 christos # define local static
140 1.1 christos /* Needed for systems with limitation on stack size. */
141 1.1 christos #else
142 1.1 christos # define local
143 1.1 christos #endif
144 1.1 christos
145 1.1 christos #ifdef Z_SOLO
146 1.1 christos /* for Z_SOLO, create simplified gz* functions using deflate and inflate */
147 1.1 christos
148 1.1 christos #if defined(Z_HAVE_UNISTD_H) || defined(Z_LARGE)
149 1.1 christos # include <unistd.h> /* for unlink() */
150 1.1 christos #endif
151 1.1 christos
152 1.1.1.4 christos static void *myalloc(void *q, unsigned n, unsigned m) {
153 1.1 christos (void)q;
154 1.1 christos return calloc(n, m);
155 1.1 christos }
156 1.1 christos
157 1.1.1.4 christos static void myfree(void *q, void *p) {
158 1.1 christos (void)q;
159 1.1 christos free(p);
160 1.1 christos }
161 1.1 christos
162 1.1 christos typedef struct gzFile_s {
163 1.1 christos FILE *file;
164 1.1 christos int write;
165 1.1 christos int err;
166 1.1 christos char *msg;
167 1.1 christos z_stream strm;
168 1.1 christos } *gzFile;
169 1.1 christos
170 1.1.1.4 christos static gzFile gz_open(const char *path, int fd, const char *mode) {
171 1.1 christos gzFile gz;
172 1.1 christos int ret;
173 1.1 christos
174 1.1 christos gz = malloc(sizeof(struct gzFile_s));
175 1.1 christos if (gz == NULL)
176 1.1 christos return NULL;
177 1.1 christos gz->write = strchr(mode, 'w') != NULL;
178 1.1 christos gz->strm.zalloc = myalloc;
179 1.1 christos gz->strm.zfree = myfree;
180 1.1 christos gz->strm.opaque = Z_NULL;
181 1.1 christos if (gz->write)
182 1.1 christos ret = deflateInit2(&(gz->strm), -1, 8, 15 + 16, 8, 0);
183 1.1 christos else {
184 1.1 christos gz->strm.next_in = 0;
185 1.1 christos gz->strm.avail_in = Z_NULL;
186 1.1 christos ret = inflateInit2(&(gz->strm), 15 + 16);
187 1.1 christos }
188 1.1 christos if (ret != Z_OK) {
189 1.1 christos free(gz);
190 1.1 christos return NULL;
191 1.1 christos }
192 1.1 christos gz->file = path == NULL ? fdopen(fd, gz->write ? "wb" : "rb") :
193 1.1 christos fopen(path, gz->write ? "wb" : "rb");
194 1.1 christos if (gz->file == NULL) {
195 1.1 christos gz->write ? deflateEnd(&(gz->strm)) : inflateEnd(&(gz->strm));
196 1.1 christos free(gz);
197 1.1 christos return NULL;
198 1.1 christos }
199 1.1 christos gz->err = 0;
200 1.1 christos gz->msg = "";
201 1.1 christos return gz;
202 1.1 christos }
203 1.1 christos
204 1.1.1.4 christos static gzFile gzopen(const char *path, const char *mode) {
205 1.1.1.4 christos return gz_open(path, -1, mode);
206 1.1.1.4 christos }
207 1.1 christos
208 1.1.1.4 christos static gzFile gzdopen(int fd, const char *mode) {
209 1.1.1.4 christos return gz_open(NULL, fd, mode);
210 1.1.1.4 christos }
211 1.1.1.4 christos
212 1.1.1.4 christos static int gzwrite(gzFile gz, const void *buf, unsigned len) {
213 1.1 christos z_stream *strm;
214 1.1 christos unsigned char out[BUFLEN];
215 1.1 christos
216 1.1 christos if (gz == NULL || !gz->write)
217 1.1 christos return 0;
218 1.1 christos strm = &(gz->strm);
219 1.1 christos strm->next_in = (void *)buf;
220 1.1 christos strm->avail_in = len;
221 1.1 christos do {
222 1.1 christos strm->next_out = out;
223 1.1 christos strm->avail_out = BUFLEN;
224 1.1 christos (void)deflate(strm, Z_NO_FLUSH);
225 1.1 christos fwrite(out, 1, BUFLEN - strm->avail_out, gz->file);
226 1.1 christos } while (strm->avail_out == 0);
227 1.1 christos return len;
228 1.1 christos }
229 1.1 christos
230 1.1.1.4 christos static int gzread(gzFile gz, void *buf, unsigned len) {
231 1.1 christos int ret;
232 1.1 christos unsigned got;
233 1.1 christos unsigned char in[1];
234 1.1 christos z_stream *strm;
235 1.1 christos
236 1.1 christos if (gz == NULL || gz->write)
237 1.1 christos return 0;
238 1.1 christos if (gz->err)
239 1.1 christos return 0;
240 1.1 christos strm = &(gz->strm);
241 1.1 christos strm->next_out = (void *)buf;
242 1.1 christos strm->avail_out = len;
243 1.1 christos do {
244 1.1 christos got = fread(in, 1, 1, gz->file);
245 1.1 christos if (got == 0)
246 1.1 christos break;
247 1.1 christos strm->next_in = in;
248 1.1 christos strm->avail_in = 1;
249 1.1 christos ret = inflate(strm, Z_NO_FLUSH);
250 1.1 christos if (ret == Z_DATA_ERROR) {
251 1.1 christos gz->err = Z_DATA_ERROR;
252 1.1 christos gz->msg = strm->msg;
253 1.1 christos return 0;
254 1.1 christos }
255 1.1 christos if (ret == Z_STREAM_END)
256 1.1 christos inflateReset(strm);
257 1.1 christos } while (strm->avail_out);
258 1.1 christos return len - strm->avail_out;
259 1.1 christos }
260 1.1 christos
261 1.1.1.4 christos static int gzclose(gzFile gz) {
262 1.1 christos z_stream *strm;
263 1.1 christos unsigned char out[BUFLEN];
264 1.1 christos
265 1.1 christos if (gz == NULL)
266 1.1 christos return Z_STREAM_ERROR;
267 1.1 christos strm = &(gz->strm);
268 1.1 christos if (gz->write) {
269 1.1 christos strm->next_in = Z_NULL;
270 1.1 christos strm->avail_in = 0;
271 1.1 christos do {
272 1.1 christos strm->next_out = out;
273 1.1 christos strm->avail_out = BUFLEN;
274 1.1 christos (void)deflate(strm, Z_FINISH);
275 1.1 christos fwrite(out, 1, BUFLEN - strm->avail_out, gz->file);
276 1.1 christos } while (strm->avail_out == 0);
277 1.1 christos deflateEnd(strm);
278 1.1 christos }
279 1.1 christos else
280 1.1 christos inflateEnd(strm);
281 1.1 christos fclose(gz->file);
282 1.1 christos free(gz);
283 1.1 christos return Z_OK;
284 1.1 christos }
285 1.1 christos
286 1.1.1.4 christos static const char *gzerror(gzFile gz, int *err) {
287 1.1 christos *err = gz->err;
288 1.1 christos return gz->msg;
289 1.1 christos }
290 1.1 christos
291 1.1 christos #endif
292 1.1 christos
293 1.1 christos static char *prog;
294 1.1 christos
295 1.1 christos /* ===========================================================================
296 1.1 christos * Display error message and exit
297 1.1 christos */
298 1.1.1.4 christos static void error(const char *msg) {
299 1.1 christos fprintf(stderr, "%s: %s\n", prog, msg);
300 1.1 christos exit(1);
301 1.1 christos }
302 1.1 christos
303 1.1 christos #ifdef USE_MMAP /* MMAP version, Miguel Albrecht <malbrech (at) eso.org> */
304 1.1 christos
305 1.1 christos /* Try compressing the input file at once using mmap. Return Z_OK if
306 1.1.1.4 christos * success, Z_ERRNO otherwise.
307 1.1 christos */
308 1.1.1.4 christos static int gz_compress_mmap(FILE *in, gzFile out) {
309 1.1 christos int len;
310 1.1 christos int err;
311 1.1 christos int ifd = fileno(in);
312 1.1 christos caddr_t buf; /* mmap'ed buffer for the entire input file */
313 1.1 christos off_t buf_len; /* length of the input file */
314 1.1 christos struct stat sb;
315 1.1 christos
316 1.1 christos /* Determine the size of the file, needed for mmap: */
317 1.1 christos if (fstat(ifd, &sb) < 0) return Z_ERRNO;
318 1.1 christos buf_len = sb.st_size;
319 1.1 christos if (buf_len <= 0) return Z_ERRNO;
320 1.1 christos
321 1.1 christos /* Now do the actual mmap: */
322 1.1 christos buf = mmap((caddr_t) 0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0);
323 1.1 christos if (buf == (caddr_t)(-1)) return Z_ERRNO;
324 1.1 christos
325 1.1 christos /* Compress the whole file at once: */
326 1.1 christos len = gzwrite(out, (char *)buf, (unsigned)buf_len);
327 1.1 christos
328 1.1 christos if (len != (int)buf_len) error(gzerror(out, &err));
329 1.1 christos
330 1.1 christos munmap(buf, buf_len);
331 1.1 christos fclose(in);
332 1.1 christos if (gzclose(out) != Z_OK) error("failed gzclose");
333 1.1 christos return Z_OK;
334 1.1 christos }
335 1.1 christos #endif /* USE_MMAP */
336 1.1 christos
337 1.1 christos /* ===========================================================================
338 1.1.1.4 christos * Compress input to output then close both files.
339 1.1.1.4 christos */
340 1.1.1.4 christos
341 1.1.1.4 christos static void gz_compress(FILE *in, gzFile out) {
342 1.1.1.4 christos local char buf[BUFLEN];
343 1.1.1.4 christos int len;
344 1.1.1.4 christos int err;
345 1.1.1.4 christos
346 1.1.1.4 christos #ifdef USE_MMAP
347 1.1.1.4 christos /* Try first compressing with mmap. If mmap fails (minigzip used in a
348 1.1.1.4 christos * pipe), use the normal fread loop.
349 1.1.1.4 christos */
350 1.1.1.4 christos if (gz_compress_mmap(in, out) == Z_OK) return;
351 1.1.1.4 christos #endif
352 1.1.1.4 christos for (;;) {
353 1.1.1.4 christos len = (int)fread(buf, 1, sizeof(buf), in);
354 1.1.1.4 christos if (ferror(in)) {
355 1.1.1.4 christos perror("fread");
356 1.1.1.4 christos exit(1);
357 1.1.1.4 christos }
358 1.1.1.4 christos if (len == 0) break;
359 1.1.1.4 christos
360 1.1.1.4 christos if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err));
361 1.1.1.4 christos }
362 1.1.1.4 christos fclose(in);
363 1.1.1.4 christos if (gzclose(out) != Z_OK) error("failed gzclose");
364 1.1.1.4 christos }
365 1.1.1.4 christos
366 1.1.1.4 christos /* ===========================================================================
367 1.1 christos * Uncompress input to output then close both files.
368 1.1 christos */
369 1.1.1.4 christos static void gz_uncompress(gzFile in, FILE *out) {
370 1.1 christos local char buf[BUFLEN];
371 1.1 christos int len;
372 1.1 christos int err;
373 1.1 christos
374 1.1 christos for (;;) {
375 1.1 christos len = gzread(in, buf, sizeof(buf));
376 1.1 christos if (len < 0) error (gzerror(in, &err));
377 1.1 christos if (len == 0) break;
378 1.1 christos
379 1.1 christos if ((int)fwrite(buf, 1, (unsigned)len, out) != len) {
380 1.1 christos error("failed fwrite");
381 1.1 christos }
382 1.1 christos }
383 1.1 christos if (fclose(out)) error("failed fclose");
384 1.1 christos
385 1.1 christos if (gzclose(in) != Z_OK) error("failed gzclose");
386 1.1 christos }
387 1.1 christos
388 1.1 christos
389 1.1 christos /* ===========================================================================
390 1.1 christos * Compress the given file: create a corresponding .gz file and remove the
391 1.1 christos * original.
392 1.1 christos */
393 1.1.1.4 christos static void file_compress(char *file, char *mode) {
394 1.1 christos local char outfile[MAX_NAME_LEN];
395 1.1 christos FILE *in;
396 1.1 christos gzFile out;
397 1.1 christos
398 1.1 christos if (strlen(file) + strlen(GZ_SUFFIX) >= sizeof(outfile)) {
399 1.1 christos fprintf(stderr, "%s: filename too long\n", prog);
400 1.1 christos exit(1);
401 1.1 christos }
402 1.1 christos
403 1.1 christos #if !defined(NO_snprintf) && !defined(NO_vsnprintf)
404 1.1 christos snprintf(outfile, sizeof(outfile), "%s%s", file, GZ_SUFFIX);
405 1.1 christos #else
406 1.1 christos strcpy(outfile, file);
407 1.1 christos strcat(outfile, GZ_SUFFIX);
408 1.1 christos #endif
409 1.1 christos
410 1.1 christos in = fopen(file, "rb");
411 1.1 christos if (in == NULL) {
412 1.1 christos perror(file);
413 1.1 christos exit(1);
414 1.1 christos }
415 1.1 christos out = gzopen(outfile, mode);
416 1.1 christos if (out == NULL) {
417 1.1 christos fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile);
418 1.1 christos exit(1);
419 1.1 christos }
420 1.1 christos gz_compress(in, out);
421 1.1 christos
422 1.1 christos unlink(file);
423 1.1 christos }
424 1.1 christos
425 1.1 christos
426 1.1 christos /* ===========================================================================
427 1.1 christos * Uncompress the given file and remove the original.
428 1.1 christos */
429 1.1.1.4 christos static void file_uncompress(char *file) {
430 1.1 christos local char buf[MAX_NAME_LEN];
431 1.1 christos char *infile, *outfile;
432 1.1 christos FILE *out;
433 1.1 christos gzFile in;
434 1.1.1.2 christos z_size_t len = strlen(file);
435 1.1 christos
436 1.1 christos if (len + strlen(GZ_SUFFIX) >= sizeof(buf)) {
437 1.1 christos fprintf(stderr, "%s: filename too long\n", prog);
438 1.1 christos exit(1);
439 1.1 christos }
440 1.1 christos
441 1.1 christos #if !defined(NO_snprintf) && !defined(NO_vsnprintf)
442 1.1 christos snprintf(buf, sizeof(buf), "%s", file);
443 1.1 christos #else
444 1.1 christos strcpy(buf, file);
445 1.1 christos #endif
446 1.1 christos
447 1.1 christos if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) {
448 1.1 christos infile = file;
449 1.1 christos outfile = buf;
450 1.1 christos outfile[len-3] = '\0';
451 1.1 christos } else {
452 1.1 christos outfile = file;
453 1.1 christos infile = buf;
454 1.1 christos #if !defined(NO_snprintf) && !defined(NO_vsnprintf)
455 1.1 christos snprintf(buf + len, sizeof(buf) - len, "%s", GZ_SUFFIX);
456 1.1 christos #else
457 1.1 christos strcat(infile, GZ_SUFFIX);
458 1.1 christos #endif
459 1.1 christos }
460 1.1 christos in = gzopen(infile, "rb");
461 1.1 christos if (in == NULL) {
462 1.1 christos fprintf(stderr, "%s: can't gzopen %s\n", prog, infile);
463 1.1 christos exit(1);
464 1.1 christos }
465 1.1 christos out = fopen(outfile, "wb");
466 1.1 christos if (out == NULL) {
467 1.1 christos perror(file);
468 1.1 christos exit(1);
469 1.1 christos }
470 1.1 christos
471 1.1 christos gz_uncompress(in, out);
472 1.1 christos
473 1.1 christos unlink(infile);
474 1.1 christos }
475 1.1 christos
476 1.1 christos
477 1.1 christos /* ===========================================================================
478 1.1 christos * Usage: minigzip [-c] [-d] [-f] [-h] [-r] [-1 to -9] [files...]
479 1.1 christos * -c : write to standard output
480 1.1 christos * -d : decompress
481 1.1 christos * -f : compress with Z_FILTERED
482 1.1 christos * -h : compress with Z_HUFFMAN_ONLY
483 1.1 christos * -r : compress with Z_RLE
484 1.1 christos * -1 to -9 : compression level
485 1.1 christos */
486 1.1 christos
487 1.1.1.4 christos int main(int argc, char *argv[]) {
488 1.1 christos int copyout = 0;
489 1.1 christos int uncompr = 0;
490 1.1 christos gzFile file;
491 1.1 christos char *bname, outmode[20];
492 1.1 christos
493 1.1 christos #if !defined(NO_snprintf) && !defined(NO_vsnprintf)
494 1.1 christos snprintf(outmode, sizeof(outmode), "%s", "wb6 ");
495 1.1 christos #else
496 1.1 christos strcpy(outmode, "wb6 ");
497 1.1 christos #endif
498 1.1 christos
499 1.1 christos prog = argv[0];
500 1.1 christos bname = strrchr(argv[0], '/');
501 1.1 christos if (bname)
502 1.1 christos bname++;
503 1.1 christos else
504 1.1 christos bname = argv[0];
505 1.1 christos argc--, argv++;
506 1.1 christos
507 1.1 christos if (!strcmp(bname, "gunzip"))
508 1.1 christos uncompr = 1;
509 1.1 christos else if (!strcmp(bname, "zcat"))
510 1.1 christos copyout = uncompr = 1;
511 1.1 christos
512 1.1 christos while (argc > 0) {
513 1.1 christos if (strcmp(*argv, "-c") == 0)
514 1.1 christos copyout = 1;
515 1.1 christos else if (strcmp(*argv, "-d") == 0)
516 1.1 christos uncompr = 1;
517 1.1 christos else if (strcmp(*argv, "-f") == 0)
518 1.1 christos outmode[3] = 'f';
519 1.1 christos else if (strcmp(*argv, "-h") == 0)
520 1.1 christos outmode[3] = 'h';
521 1.1 christos else if (strcmp(*argv, "-r") == 0)
522 1.1 christos outmode[3] = 'R';
523 1.1 christos else if ((*argv)[0] == '-' && (*argv)[1] >= '1' && (*argv)[1] <= '9' &&
524 1.1 christos (*argv)[2] == 0)
525 1.1 christos outmode[2] = (*argv)[1];
526 1.1 christos else
527 1.1 christos break;
528 1.1 christos argc--, argv++;
529 1.1 christos }
530 1.1 christos if (outmode[3] == ' ')
531 1.1 christos outmode[3] = 0;
532 1.1 christos if (argc == 0) {
533 1.1 christos SET_BINARY_MODE(stdin);
534 1.1 christos SET_BINARY_MODE(stdout);
535 1.1 christos if (uncompr) {
536 1.1 christos file = gzdopen(fileno(stdin), "rb");
537 1.1 christos if (file == NULL) error("can't gzdopen stdin");
538 1.1 christos gz_uncompress(file, stdout);
539 1.1 christos } else {
540 1.1 christos file = gzdopen(fileno(stdout), outmode);
541 1.1 christos if (file == NULL) error("can't gzdopen stdout");
542 1.1 christos gz_compress(stdin, file);
543 1.1 christos }
544 1.1 christos } else {
545 1.1 christos if (copyout) {
546 1.1 christos SET_BINARY_MODE(stdout);
547 1.1 christos }
548 1.1 christos do {
549 1.1 christos if (uncompr) {
550 1.1 christos if (copyout) {
551 1.1 christos file = gzopen(*argv, "rb");
552 1.1 christos if (file == NULL)
553 1.1 christos fprintf(stderr, "%s: can't gzopen %s\n", prog, *argv);
554 1.1 christos else
555 1.1 christos gz_uncompress(file, stdout);
556 1.1 christos } else {
557 1.1 christos file_uncompress(*argv);
558 1.1 christos }
559 1.1 christos } else {
560 1.1 christos if (copyout) {
561 1.1 christos FILE * in = fopen(*argv, "rb");
562 1.1 christos
563 1.1 christos if (in == NULL) {
564 1.1 christos perror(*argv);
565 1.1 christos } else {
566 1.1 christos file = gzdopen(fileno(stdout), outmode);
567 1.1 christos if (file == NULL) error("can't gzdopen stdout");
568 1.1 christos
569 1.1 christos gz_compress(in, file);
570 1.1 christos }
571 1.1 christos
572 1.1 christos } else {
573 1.1 christos file_compress(*argv, outmode);
574 1.1 christos }
575 1.1 christos }
576 1.1 christos } while (argv++, --argc);
577 1.1 christos }
578 1.1 christos return 0;
579 1.1 christos }
580