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