(root)/
binutils-2.41/
zlib/
examples/
gun.c
       1  /* gun.c -- simple gunzip to give an example of the use of inflateBack()
       2   * Copyright (C) 2003, 2005, 2008, 2010, 2012 Mark Adler
       3   * For conditions of distribution and use, see copyright notice in zlib.h
       4     Version 1.7  12 August 2012  Mark Adler */
       5  
       6  /* Version history:
       7     1.0  16 Feb 2003  First version for testing of inflateBack()
       8     1.1  21 Feb 2005  Decompress concatenated gzip streams
       9                       Remove use of "this" variable (C++ keyword)
      10                       Fix return value for in()
      11                       Improve allocation failure checking
      12                       Add typecasting for void * structures
      13                       Add -h option for command version and usage
      14                       Add a bunch of comments
      15     1.2  20 Mar 2005  Add Unix compress (LZW) decompression
      16                       Copy file attributes from input file to output file
      17     1.3  12 Jun 2005  Add casts for error messages [Oberhumer]
      18     1.4   8 Dec 2006  LZW decompression speed improvements
      19     1.5   9 Feb 2008  Avoid warning in latest version of gcc
      20     1.6  17 Jan 2010  Avoid signed/unsigned comparison warnings
      21     1.7  12 Aug 2012  Update for z_const usage in zlib 1.2.8
      22   */
      23  
      24  /*
      25     gun [ -t ] [ name ... ]
      26  
      27     decompresses the data in the named gzip files.  If no arguments are given,
      28     gun will decompress from stdin to stdout.  The names must end in .gz, -gz,
      29     .z, -z, _z, or .Z.  The uncompressed data will be written to a file name
      30     with the suffix stripped.  On success, the original file is deleted.  On
      31     failure, the output file is deleted.  For most failures, the command will
      32     continue to process the remaining names on the command line.  A memory
      33     allocation failure will abort the command.  If -t is specified, then the
      34     listed files or stdin will be tested as gzip files for integrity (without
      35     checking for a proper suffix), no output will be written, and no files
      36     will be deleted.
      37  
      38     Like gzip, gun allows concatenated gzip streams and will decompress them,
      39     writing all of the uncompressed data to the output.  Unlike gzip, gun allows
      40     an empty file on input, and will produce no error writing an empty output
      41     file.
      42  
      43     gun will also decompress files made by Unix compress, which uses LZW
      44     compression.  These files are automatically detected by virtue of their
      45     magic header bytes.  Since the end of Unix compress stream is marked by the
      46     end-of-file, they cannot be concantenated.  If a Unix compress stream is
      47     encountered in an input file, it is the last stream in that file.
      48  
      49     Like gunzip and uncompress, the file attributes of the original compressed
      50     file are maintained in the final uncompressed file, to the extent that the
      51     user permissions allow it.
      52  
      53     On my Mac OS X PowerPC G4, gun is almost twice as fast as gunzip (version
      54     1.2.4) is on the same file, when gun is linked with zlib 1.2.2.  Also the
      55     LZW decompression provided by gun is about twice as fast as the standard
      56     Unix uncompress command.
      57   */
      58  
      59  /* external functions and related types and constants */
      60  #include <stdio.h>          /* fprintf() */
      61  #include <stdlib.h>         /* malloc(), free() */
      62  #include <string.h>         /* strerror(), strcmp(), strlen(), memcpy() */
      63  #include <errno.h>          /* errno */
      64  #include <fcntl.h>          /* open() */
      65  #include <unistd.h>         /* read(), write(), close(), chown(), unlink() */
      66  #include <sys/types.h>
      67  #include <sys/stat.h>       /* stat(), chmod() */
      68  #include <utime.h>          /* utime() */
      69  #include "zlib.h"           /* inflateBackInit(), inflateBack(), */
      70                              /* inflateBackEnd(), crc32() */
      71  
      72  /* function declaration */
      73  #define local static
      74  
      75  /* buffer constants */
      76  #define SIZE 32768U         /* input and output buffer sizes */
      77  #define PIECE 16384         /* limits i/o chunks for 16-bit int case */
      78  
      79  /* structure for infback() to pass to input function in() -- it maintains the
      80     input file and a buffer of size SIZE */
      81  struct ind {
      82      int infile;
      83      unsigned char *inbuf;
      84  };
      85  
      86  /* Load input buffer, assumed to be empty, and return bytes loaded and a
      87     pointer to them.  read() is called until the buffer is full, or until it
      88     returns end-of-file or error.  Return 0 on error. */
      89  local unsigned in(void *in_desc, z_const unsigned char **buf)
      90  {
      91      int ret;
      92      unsigned len;
      93      unsigned char *next;
      94      struct ind *me = (struct ind *)in_desc;
      95  
      96      next = me->inbuf;
      97      *buf = next;
      98      len = 0;
      99      do {
     100          ret = PIECE;
     101          if ((unsigned)ret > SIZE - len)
     102              ret = (int)(SIZE - len);
     103          ret = (int)read(me->infile, next, ret);
     104          if (ret == -1) {
     105              len = 0;
     106              break;
     107          }
     108          next += ret;
     109          len += ret;
     110      } while (ret != 0 && len < SIZE);
     111      return len;
     112  }
     113  
     114  /* structure for infback() to pass to output function out() -- it maintains the
     115     output file, a running CRC-32 check on the output and the total number of
     116     bytes output, both for checking against the gzip trailer.  (The length in
     117     the gzip trailer is stored modulo 2^32, so it's ok if a long is 32 bits and
     118     the output is greater than 4 GB.) */
     119  struct outd {
     120      int outfile;
     121      int check;                  /* true if checking crc and total */
     122      unsigned long crc;
     123      unsigned long total;
     124  };
     125  
     126  /* Write output buffer and update the CRC-32 and total bytes written.  write()
     127     is called until all of the output is written or an error is encountered.
     128     On success out() returns 0.  For a write failure, out() returns 1.  If the
     129     output file descriptor is -1, then nothing is written.
     130   */
     131  local int out(void *out_desc, unsigned char *buf, unsigned len)
     132  {
     133      int ret;
     134      struct outd *me = (struct outd *)out_desc;
     135  
     136      if (me->check) {
     137          me->crc = crc32(me->crc, buf, len);
     138          me->total += len;
     139      }
     140      if (me->outfile != -1)
     141          do {
     142              ret = PIECE;
     143              if ((unsigned)ret > len)
     144                  ret = (int)len;
     145              ret = (int)write(me->outfile, buf, ret);
     146              if (ret == -1)
     147                  return 1;
     148              buf += ret;
     149              len -= ret;
     150          } while (len != 0);
     151      return 0;
     152  }
     153  
     154  /* next input byte macro for use inside lunpipe() and gunpipe() */
     155  #define NEXT() (have ? 0 : (have = in(indp, &next)), \
     156                  last = have ? (have--, (int)(*next++)) : -1)
     157  
     158  /* memory for gunpipe() and lunpipe() --
     159     the first 256 entries of prefix[] and suffix[] are never used, could
     160     have offset the index, but it's faster to waste the memory */
     161  unsigned char inbuf[SIZE];              /* input buffer */
     162  unsigned char outbuf[SIZE];             /* output buffer */
     163  unsigned short prefix[65536];           /* index to LZW prefix string */
     164  unsigned char suffix[65536];            /* one-character LZW suffix */
     165  unsigned char match[65280 + 2];         /* buffer for reversed match or gzip
     166                                             32K sliding window */
     167  
     168  /* throw out what's left in the current bits byte buffer (this is a vestigial
     169     aspect of the compressed data format derived from an implementation that
     170     made use of a special VAX machine instruction!) */
     171  #define FLUSHCODE() \
     172      do { \
     173          left = 0; \
     174          rem = 0; \
     175          if (chunk > have) { \
     176              chunk -= have; \
     177              have = 0; \
     178              if (NEXT() == -1) \
     179                  break; \
     180              chunk--; \
     181              if (chunk > have) { \
     182                  chunk = have = 0; \
     183                  break; \
     184              } \
     185          } \
     186          have -= chunk; \
     187          next += chunk; \
     188          chunk = 0; \
     189      } while (0)
     190  
     191  /* Decompress a compress (LZW) file from indp to outfile.  The compress magic
     192     header (two bytes) has already been read and verified.  There are have bytes
     193     of buffered input at next.  strm is used for passing error information back
     194     to gunpipe().
     195  
     196     lunpipe() will return Z_OK on success, Z_BUF_ERROR for an unexpected end of
     197     file, read error, or write error (a write error indicated by strm->next_in
     198     not equal to Z_NULL), or Z_DATA_ERROR for invalid input.
     199   */
     200  local int lunpipe(unsigned have, z_const unsigned char *next, struct ind *indp,
     201                    int outfile, z_stream *strm)
     202  {
     203      int last;                   /* last byte read by NEXT(), or -1 if EOF */
     204      unsigned chunk;             /* bytes left in current chunk */
     205      int left;                   /* bits left in rem */
     206      unsigned rem;               /* unused bits from input */
     207      int bits;                   /* current bits per code */
     208      unsigned code;              /* code, table traversal index */
     209      unsigned mask;              /* mask for current bits codes */
     210      int max;                    /* maximum bits per code for this stream */
     211      unsigned flags;             /* compress flags, then block compress flag */
     212      unsigned end;               /* last valid entry in prefix/suffix tables */
     213      unsigned temp;              /* current code */
     214      unsigned prev;              /* previous code */
     215      unsigned final;             /* last character written for previous code */
     216      unsigned stack;             /* next position for reversed string */
     217      unsigned outcnt;            /* bytes in output buffer */
     218      struct outd outd;           /* output structure */
     219      unsigned char *p;
     220  
     221      /* set up output */
     222      outd.outfile = outfile;
     223      outd.check = 0;
     224  
     225      /* process remainder of compress header -- a flags byte */
     226      flags = NEXT();
     227      if (last == -1)
     228          return Z_BUF_ERROR;
     229      if (flags & 0x60) {
     230          strm->msg = (char *)"unknown lzw flags set";
     231          return Z_DATA_ERROR;
     232      }
     233      max = flags & 0x1f;
     234      if (max < 9 || max > 16) {
     235          strm->msg = (char *)"lzw bits out of range";
     236          return Z_DATA_ERROR;
     237      }
     238      if (max == 9)                           /* 9 doesn't really mean 9 */
     239          max = 10;
     240      flags &= 0x80;                          /* true if block compress */
     241  
     242      /* clear table */
     243      bits = 9;
     244      mask = 0x1ff;
     245      end = flags ? 256 : 255;
     246  
     247      /* set up: get first 9-bit code, which is the first decompressed byte, but
     248         don't create a table entry until the next code */
     249      if (NEXT() == -1)                       /* no compressed data is ok */
     250          return Z_OK;
     251      final = prev = (unsigned)last;          /* low 8 bits of code */
     252      if (NEXT() == -1)                       /* missing a bit */
     253          return Z_BUF_ERROR;
     254      if (last & 1) {                         /* code must be < 256 */
     255          strm->msg = (char *)"invalid lzw code";
     256          return Z_DATA_ERROR;
     257      }
     258      rem = (unsigned)last >> 1;              /* remaining 7 bits */
     259      left = 7;
     260      chunk = bits - 2;                       /* 7 bytes left in this chunk */
     261      outbuf[0] = (unsigned char)final;       /* write first decompressed byte */
     262      outcnt = 1;
     263  
     264      /* decode codes */
     265      stack = 0;
     266      for (;;) {
     267          /* if the table will be full after this, increment the code size */
     268          if (end >= mask && bits < max) {
     269              FLUSHCODE();
     270              bits++;
     271              mask <<= 1;
     272              mask++;
     273          }
     274  
     275          /* get a code of length bits */
     276          if (chunk == 0)                     /* decrement chunk modulo bits */
     277              chunk = bits;
     278          code = rem;                         /* low bits of code */
     279          if (NEXT() == -1) {                 /* EOF is end of compressed data */
     280              /* write remaining buffered output */
     281              if (outcnt && out(&outd, outbuf, outcnt)) {
     282                  strm->next_in = outbuf;     /* signal write error */
     283                  return Z_BUF_ERROR;
     284              }
     285              return Z_OK;
     286          }
     287          code += (unsigned)last << left;     /* middle (or high) bits of code */
     288          left += 8;
     289          chunk--;
     290          if (bits > left) {                  /* need more bits */
     291              if (NEXT() == -1)               /* can't end in middle of code */
     292                  return Z_BUF_ERROR;
     293              code += (unsigned)last << left; /* high bits of code */
     294              left += 8;
     295              chunk--;
     296          }
     297          code &= mask;                       /* mask to current code length */
     298          left -= bits;                       /* number of unused bits */
     299          rem = (unsigned)last >> (8 - left); /* unused bits from last byte */
     300  
     301          /* process clear code (256) */
     302          if (code == 256 && flags) {
     303              FLUSHCODE();
     304              bits = 9;                       /* initialize bits and mask */
     305              mask = 0x1ff;
     306              end = 255;                      /* empty table */
     307              continue;                       /* get next code */
     308          }
     309  
     310          /* special code to reuse last match */
     311          temp = code;                        /* save the current code */
     312          if (code > end) {
     313              /* Be picky on the allowed code here, and make sure that the code
     314                 we drop through (prev) will be a valid index so that random
     315                 input does not cause an exception.  The code != end + 1 check is
     316                 empirically derived, and not checked in the original uncompress
     317                 code.  If this ever causes a problem, that check could be safely
     318                 removed.  Leaving this check in greatly improves gun's ability
     319                 to detect random or corrupted input after a compress header.
     320                 In any case, the prev > end check must be retained. */
     321              if (code != end + 1 || prev > end) {
     322                  strm->msg = (char *)"invalid lzw code";
     323                  return Z_DATA_ERROR;
     324              }
     325              match[stack++] = (unsigned char)final;
     326              code = prev;
     327          }
     328  
     329          /* walk through linked list to generate output in reverse order */
     330          p = match + stack;
     331          while (code >= 256) {
     332              *p++ = suffix[code];
     333              code = prefix[code];
     334          }
     335          stack = p - match;
     336          match[stack++] = (unsigned char)code;
     337          final = code;
     338  
     339          /* link new table entry */
     340          if (end < mask) {
     341              end++;
     342              prefix[end] = (unsigned short)prev;
     343              suffix[end] = (unsigned char)final;
     344          }
     345  
     346          /* set previous code for next iteration */
     347          prev = temp;
     348  
     349          /* write output in forward order */
     350          while (stack > SIZE - outcnt) {
     351              while (outcnt < SIZE)
     352                  outbuf[outcnt++] = match[--stack];
     353              if (out(&outd, outbuf, outcnt)) {
     354                  strm->next_in = outbuf; /* signal write error */
     355                  return Z_BUF_ERROR;
     356              }
     357              outcnt = 0;
     358          }
     359          p = match + stack;
     360          do {
     361              outbuf[outcnt++] = *--p;
     362          } while (p > match);
     363          stack = 0;
     364  
     365          /* loop for next code with final and prev as the last match, rem and
     366             left provide the first 0..7 bits of the next code, end is the last
     367             valid table entry */
     368      }
     369  }
     370  
     371  /* Decompress a gzip file from infile to outfile.  strm is assumed to have been
     372     successfully initialized with inflateBackInit().  The input file may consist
     373     of a series of gzip streams, in which case all of them will be decompressed
     374     to the output file.  If outfile is -1, then the gzip stream(s) integrity is
     375     checked and nothing is written.
     376  
     377     The return value is a zlib error code: Z_MEM_ERROR if out of memory,
     378     Z_DATA_ERROR if the header or the compressed data is invalid, or if the
     379     trailer CRC-32 check or length doesn't match, Z_BUF_ERROR if the input ends
     380     prematurely or a write error occurs, or Z_ERRNO if junk (not a another gzip
     381     stream) follows a valid gzip stream.
     382   */
     383  local int gunpipe(z_stream *strm, int infile, int outfile)
     384  {
     385      int ret, first, last;
     386      unsigned have, flags, len;
     387      z_const unsigned char *next = NULL;
     388      struct ind ind, *indp;
     389      struct outd outd;
     390  
     391      /* setup input buffer */
     392      ind.infile = infile;
     393      ind.inbuf = inbuf;
     394      indp = &ind;
     395  
     396      /* decompress concatenated gzip streams */
     397      have = 0;                               /* no input data read in yet */
     398      first = 1;                              /* looking for first gzip header */
     399      strm->next_in = Z_NULL;                 /* so Z_BUF_ERROR means EOF */
     400      for (;;) {
     401          /* look for the two magic header bytes for a gzip stream */
     402          if (NEXT() == -1) {
     403              ret = Z_OK;
     404              break;                          /* empty gzip stream is ok */
     405          }
     406          if (last != 31 || (NEXT() != 139 && last != 157)) {
     407              strm->msg = (char *)"incorrect header check";
     408              ret = first ? Z_DATA_ERROR : Z_ERRNO;
     409              break;                          /* not a gzip or compress header */
     410          }
     411          first = 0;                          /* next non-header is junk */
     412  
     413          /* process a compress (LZW) file -- can't be concatenated after this */
     414          if (last == 157) {
     415              ret = lunpipe(have, next, indp, outfile, strm);
     416              break;
     417          }
     418  
     419          /* process remainder of gzip header */
     420          ret = Z_BUF_ERROR;
     421          if (NEXT() != 8) {                  /* only deflate method allowed */
     422              if (last == -1) break;
     423              strm->msg = (char *)"unknown compression method";
     424              ret = Z_DATA_ERROR;
     425              break;
     426          }
     427          flags = NEXT();                     /* header flags */
     428          NEXT();                             /* discard mod time, xflgs, os */
     429          NEXT();
     430          NEXT();
     431          NEXT();
     432          NEXT();
     433          NEXT();
     434          if (last == -1) break;
     435          if (flags & 0xe0) {
     436              strm->msg = (char *)"unknown header flags set";
     437              ret = Z_DATA_ERROR;
     438              break;
     439          }
     440          if (flags & 4) {                    /* extra field */
     441              len = NEXT();
     442              len += (unsigned)(NEXT()) << 8;
     443              if (last == -1) break;
     444              while (len > have) {
     445                  len -= have;
     446                  have = 0;
     447                  if (NEXT() == -1) break;
     448                  len--;
     449              }
     450              if (last == -1) break;
     451              have -= len;
     452              next += len;
     453          }
     454          if (flags & 8)                      /* file name */
     455              while (NEXT() != 0 && last != -1)
     456                  ;
     457          if (flags & 16)                     /* comment */
     458              while (NEXT() != 0 && last != -1)
     459                  ;
     460          if (flags & 2) {                    /* header crc */
     461              NEXT();
     462              NEXT();
     463          }
     464          if (last == -1) break;
     465  
     466          /* set up output */
     467          outd.outfile = outfile;
     468          outd.check = 1;
     469          outd.crc = crc32(0L, Z_NULL, 0);
     470          outd.total = 0;
     471  
     472          /* decompress data to output */
     473          strm->next_in = next;
     474          strm->avail_in = have;
     475          ret = inflateBack(strm, in, indp, out, &outd);
     476          if (ret != Z_STREAM_END) break;
     477          next = strm->next_in;
     478          have = strm->avail_in;
     479          strm->next_in = Z_NULL;             /* so Z_BUF_ERROR means EOF */
     480  
     481          /* check trailer */
     482          ret = Z_BUF_ERROR;
     483          if (NEXT() != (int)(outd.crc & 0xff) ||
     484              NEXT() != (int)((outd.crc >> 8) & 0xff) ||
     485              NEXT() != (int)((outd.crc >> 16) & 0xff) ||
     486              NEXT() != (int)((outd.crc >> 24) & 0xff)) {
     487              /* crc error */
     488              if (last != -1) {
     489                  strm->msg = (char *)"incorrect data check";
     490                  ret = Z_DATA_ERROR;
     491              }
     492              break;
     493          }
     494          if (NEXT() != (int)(outd.total & 0xff) ||
     495              NEXT() != (int)((outd.total >> 8) & 0xff) ||
     496              NEXT() != (int)((outd.total >> 16) & 0xff) ||
     497              NEXT() != (int)((outd.total >> 24) & 0xff)) {
     498              /* length error */
     499              if (last != -1) {
     500                  strm->msg = (char *)"incorrect length check";
     501                  ret = Z_DATA_ERROR;
     502              }
     503              break;
     504          }
     505  
     506          /* go back and look for another gzip stream */
     507      }
     508  
     509      /* clean up and return */
     510      return ret;
     511  }
     512  
     513  /* Copy file attributes, from -> to, as best we can.  This is best effort, so
     514     no errors are reported.  The mode bits, including suid, sgid, and the sticky
     515     bit are copied (if allowed), the owner's user id and group id are copied
     516     (again if allowed), and the access and modify times are copied. */
     517  local void copymeta(char *from, char *to)
     518  {
     519      struct stat was;
     520      struct utimbuf when;
     521  
     522      /* get all of from's Unix meta data, return if not a regular file */
     523      if (stat(from, &was) != 0 || (was.st_mode & S_IFMT) != S_IFREG)
     524          return;
     525  
     526      /* set to's mode bits, ignore errors */
     527      (void)chmod(to, was.st_mode & 07777);
     528  
     529      /* copy owner's user and group, ignore errors */
     530      (void)chown(to, was.st_uid, was.st_gid);
     531  
     532      /* copy access and modify times, ignore errors */
     533      when.actime = was.st_atime;
     534      when.modtime = was.st_mtime;
     535      (void)utime(to, &when);
     536  }
     537  
     538  /* Decompress the file inname to the file outnname, of if test is true, just
     539     decompress without writing and check the gzip trailer for integrity.  If
     540     inname is NULL or an empty string, read from stdin.  If outname is NULL or
     541     an empty string, write to stdout.  strm is a pre-initialized inflateBack
     542     structure.  When appropriate, copy the file attributes from inname to
     543     outname.
     544  
     545     gunzip() returns 1 if there is an out-of-memory error or an unexpected
     546     return code from gunpipe().  Otherwise it returns 0.
     547   */
     548  local int gunzip(z_stream *strm, char *inname, char *outname, int test)
     549  {
     550      int ret;
     551      int infile, outfile;
     552  
     553      /* open files */
     554      if (inname == NULL || *inname == 0) {
     555          inname = "-";
     556          infile = 0;     /* stdin */
     557      }
     558      else {
     559          infile = open(inname, O_RDONLY, 0);
     560          if (infile == -1) {
     561              fprintf(stderr, "gun cannot open %s\n", inname);
     562              return 0;
     563          }
     564      }
     565      if (test)
     566          outfile = -1;
     567      else if (outname == NULL || *outname == 0) {
     568          outname = "-";
     569          outfile = 1;    /* stdout */
     570      }
     571      else {
     572          outfile = open(outname, O_CREAT | O_TRUNC | O_WRONLY, 0666);
     573          if (outfile == -1) {
     574              close(infile);
     575              fprintf(stderr, "gun cannot create %s\n", outname);
     576              return 0;
     577          }
     578      }
     579      errno = 0;
     580  
     581      /* decompress */
     582      ret = gunpipe(strm, infile, outfile);
     583      if (outfile > 2) close(outfile);
     584      if (infile > 2) close(infile);
     585  
     586      /* interpret result */
     587      switch (ret) {
     588      case Z_OK:
     589      case Z_ERRNO:
     590          if (infile > 2 && outfile > 2) {
     591              copymeta(inname, outname);          /* copy attributes */
     592              unlink(inname);
     593          }
     594          if (ret == Z_ERRNO)
     595              fprintf(stderr, "gun warning: trailing garbage ignored in %s\n",
     596                      inname);
     597          break;
     598      case Z_DATA_ERROR:
     599          if (outfile > 2) unlink(outname);
     600          fprintf(stderr, "gun data error on %s: %s\n", inname, strm->msg);
     601          break;
     602      case Z_MEM_ERROR:
     603          if (outfile > 2) unlink(outname);
     604          fprintf(stderr, "gun out of memory error--aborting\n");
     605          return 1;
     606      case Z_BUF_ERROR:
     607          if (outfile > 2) unlink(outname);
     608          if (strm->next_in != Z_NULL) {
     609              fprintf(stderr, "gun write error on %s: %s\n",
     610                      outname, strerror(errno));
     611          }
     612          else if (errno) {
     613              fprintf(stderr, "gun read error on %s: %s\n",
     614                      inname, strerror(errno));
     615          }
     616          else {
     617              fprintf(stderr, "gun unexpected end of file on %s\n",
     618                      inname);
     619          }
     620          break;
     621      default:
     622          if (outfile > 2) unlink(outname);
     623          fprintf(stderr, "gun internal error--aborting\n");
     624          return 1;
     625      }
     626      return 0;
     627  }
     628  
     629  /* Process the gun command line arguments.  See the command syntax near the
     630     beginning of this source file. */
     631  int main(int argc, char **argv)
     632  {
     633      int ret, len, test;
     634      char *outname;
     635      unsigned char *window;
     636      z_stream strm;
     637  
     638      /* initialize inflateBack state for repeated use */
     639      window = match;                         /* reuse LZW match buffer */
     640      strm.zalloc = Z_NULL;
     641      strm.zfree = Z_NULL;
     642      strm.opaque = Z_NULL;
     643      ret = inflateBackInit(&strm, 15, window);
     644      if (ret != Z_OK) {
     645          fprintf(stderr, "gun out of memory error--aborting\n");
     646          return 1;
     647      }
     648  
     649      /* decompress each file to the same name with the suffix removed */
     650      argc--;
     651      argv++;
     652      test = 0;
     653      if (argc && strcmp(*argv, "-h") == 0) {
     654          fprintf(stderr, "gun 1.6 (17 Jan 2010)\n");
     655          fprintf(stderr, "Copyright (C) 2003-2010 Mark Adler\n");
     656          fprintf(stderr, "usage: gun [-t] [file1.gz [file2.Z ...]]\n");
     657          return 0;
     658      }
     659      if (argc && strcmp(*argv, "-t") == 0) {
     660          test = 1;
     661          argc--;
     662          argv++;
     663      }
     664      if (argc)
     665          do {
     666              if (test)
     667                  outname = NULL;
     668              else {
     669                  len = (int)strlen(*argv);
     670                  if (strcmp(*argv + len - 3, ".gz") == 0 ||
     671                      strcmp(*argv + len - 3, "-gz") == 0)
     672                      len -= 3;
     673                  else if (strcmp(*argv + len - 2, ".z") == 0 ||
     674                      strcmp(*argv + len - 2, "-z") == 0 ||
     675                      strcmp(*argv + len - 2, "_z") == 0 ||
     676                      strcmp(*argv + len - 2, ".Z") == 0)
     677                      len -= 2;
     678                  else {
     679                      fprintf(stderr, "gun error: no gz type on %s--skipping\n",
     680                              *argv);
     681                      continue;
     682                  }
     683                  outname = malloc(len + 1);
     684                  if (outname == NULL) {
     685                      fprintf(stderr, "gun out of memory error--aborting\n");
     686                      ret = 1;
     687                      break;
     688                  }
     689                  memcpy(outname, *argv, len);
     690                  outname[len] = 0;
     691              }
     692              ret = gunzip(&strm, *argv, outname, test);
     693              if (outname != NULL) free(outname);
     694              if (ret) break;
     695          } while (argv++, --argc);
     696      else
     697          ret = gunzip(&strm, NULL, NULL, test);
     698  
     699      /* clean up */
     700      inflateBackEnd(&strm);
     701      return ret;
     702  }