Home | History | Annotate | Line # | Download | only in test
      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