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