Merge from vendor branch CVS:
[dragonfly.git] / contrib / bzip2 / bzip2.c
1
2 /*-----------------------------------------------------------*/
3 /*--- A block-sorting, lossless compressor        bzip2.c ---*/
4 /*-----------------------------------------------------------*/
5
6 /*--
7   This file is a part of bzip2 and/or libbzip2, a program and
8   library for lossless, block-sorting data compression.
9
10   Copyright (C) 1996-2002 Julian R Seward.  All rights reserved.
11
12   Redistribution and use in source and binary forms, with or without
13   modification, are permitted provided that the following conditions
14   are met:
15
16   1. Redistributions of source code must retain the above copyright
17      notice, this list of conditions and the following disclaimer.
18
19   2. The origin of this software must not be misrepresented; you must 
20      not claim that you wrote the original software.  If you use this 
21      software in a product, an acknowledgment in the product 
22      documentation would be appreciated but is not required.
23
24   3. Altered source versions must be plainly marked as such, and must
25      not be misrepresented as being the original software.
26
27   4. The name of the author may not be used to endorse or promote 
28      products derived from this software without specific prior written 
29      permission.
30
31   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
32   OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
33   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
35   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
37   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
39   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
40   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
41   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42
43   Julian Seward, Cambridge, UK.
44   jseward@acm.org
45   bzip2/libbzip2 version 1.0 of 21 March 2000
46
47   This program is based on (at least) the work of:
48      Mike Burrows
49      David Wheeler
50      Peter Fenwick
51      Alistair Moffat
52      Radford Neal
53      Ian H. Witten
54      Robert Sedgewick
55      Jon L. Bentley
56
57   For more information on these sources, see the manual.
58 --*/
59
60
61 /*----------------------------------------------------*/
62 /*--- IMPORTANT                                    ---*/
63 /*----------------------------------------------------*/
64
65 /*--
66    WARNING:
67       This program and library (attempts to) compress data by 
68       performing several non-trivial transformations on it.  
69       Unless you are 100% familiar with *all* the algorithms 
70       contained herein, and with the consequences of modifying them, 
71       you should NOT meddle with the compression or decompression 
72       machinery.  Incorrect changes can and very likely *will* 
73       lead to disasterous loss of data.
74
75    DISCLAIMER:
76       I TAKE NO RESPONSIBILITY FOR ANY LOSS OF DATA ARISING FROM THE
77       USE OF THIS PROGRAM, HOWSOEVER CAUSED.
78
79       Every compression of a file implies an assumption that the
80       compressed file can be decompressed to reproduce the original.
81       Great efforts in design, coding and testing have been made to
82       ensure that this program works correctly.  However, the
83       complexity of the algorithms, and, in particular, the presence
84       of various special cases in the code which occur with very low
85       but non-zero probability make it impossible to rule out the
86       possibility of bugs remaining in the program.  DO NOT COMPRESS
87       ANY DATA WITH THIS PROGRAM AND/OR LIBRARY UNLESS YOU ARE PREPARED 
88       TO ACCEPT THE POSSIBILITY, HOWEVER SMALL, THAT THE DATA WILL 
89       NOT BE RECOVERABLE.
90
91       That is not to say this program is inherently unreliable.
92       Indeed, I very much hope the opposite is true.  bzip2/libbzip2
93       has been carefully constructed and extensively tested.
94
95    PATENTS:
96       To the best of my knowledge, bzip2/libbzip2 does not use any 
97       patented algorithms.  However, I do not have the resources 
98       available to carry out a full patent search.  Therefore I cannot 
99       give any guarantee of the above statement.
100 --*/
101
102
103
104 /*----------------------------------------------------*/
105 /*--- and now for something much more pleasant :-) ---*/
106 /*----------------------------------------------------*/
107
108 /*---------------------------------------------*/
109 /*--
110   Place a 1 beside your platform, and 0 elsewhere.
111 --*/
112
113 /*--
114   Generic 32-bit Unix.
115   Also works on 64-bit Unix boxes.
116   This is the default.
117 --*/
118 #define BZ_UNIX      1
119
120 /*--
121   Win32, as seen by Jacob Navia's excellent
122   port of (Chris Fraser & David Hanson)'s excellent
123   lcc compiler.  Or with MS Visual C.
124   This is selected automatically if compiled by a compiler which
125   defines _WIN32, not including the Cygwin GCC.
126 --*/
127 #define BZ_LCCWIN32  0
128
129 #if defined(_WIN32) && !defined(__CYGWIN__)
130 #undef  BZ_LCCWIN32
131 #define BZ_LCCWIN32 1
132 #undef  BZ_UNIX
133 #define BZ_UNIX 0
134 #endif
135
136
137 /*---------------------------------------------*/
138 /*--
139   Some stuff for all platforms.
140 --*/
141
142 #include <stdio.h>
143 #include <stdlib.h>
144 #include <string.h>
145 #include <signal.h>
146 #include <math.h>
147 #include <errno.h>
148 #include <ctype.h>
149 #include "bzlib.h"
150
151 #define ERROR_IF_EOF(i)       { if ((i) == EOF)  ioError(); }
152 #define ERROR_IF_NOT_ZERO(i)  { if ((i) != 0)    ioError(); }
153 #define ERROR_IF_MINUS_ONE(i) { if ((i) == (-1)) ioError(); }
154
155
156 /*---------------------------------------------*/
157 /*--
158    Platform-specific stuff.
159 --*/
160
161 #if BZ_UNIX
162 #   include <fcntl.h>
163 #   include <sys/types.h>
164 #   include <utime.h>
165 #   include <unistd.h>
166 #   include <sys/stat.h>
167 #   include <sys/times.h>
168
169 #   define PATH_SEP    '/'
170 #   define MY_LSTAT    lstat
171 #   define MY_STAT     stat
172 #   define MY_S_ISREG  S_ISREG
173 #   define MY_S_ISDIR  S_ISDIR
174
175 #   define APPEND_FILESPEC(root, name) \
176       root=snocString((root), (name))
177
178 #   define APPEND_FLAG(root, name) \
179       root=snocString((root), (name))
180
181 #   define SET_BINARY_MODE(fd) /**/
182
183 #   ifdef __GNUC__
184 #      define NORETURN __attribute__ ((noreturn))
185 #   else
186 #      define NORETURN /**/
187 #   endif
188
189 #   ifdef __DJGPP__
190 #     include <io.h>
191 #     include <fcntl.h>
192 #     undef MY_LSTAT
193 #     undef MY_STAT
194 #     define MY_LSTAT stat
195 #     define MY_STAT stat
196 #     undef SET_BINARY_MODE
197 #     define SET_BINARY_MODE(fd)                        \
198         do {                                            \
199            int retVal = setmode ( fileno ( fd ),        \
200                                   O_BINARY );           \
201            ERROR_IF_MINUS_ONE ( retVal );               \
202         } while ( 0 )
203 #   endif
204
205 #   ifdef __CYGWIN__
206 #     include <io.h>
207 #     include <fcntl.h>
208 #     undef SET_BINARY_MODE
209 #     define SET_BINARY_MODE(fd)                        \
210         do {                                            \
211            int retVal = setmode ( fileno ( fd ),        \
212                                   O_BINARY );           \
213            ERROR_IF_MINUS_ONE ( retVal );               \
214         } while ( 0 )
215 #   endif
216 #endif /* BZ_UNIX */
217
218
219
220 #if BZ_LCCWIN32
221 #   include <io.h>
222 #   include <fcntl.h>
223 #   include <sys\stat.h>
224
225 #   define NORETURN       /**/
226 #   define PATH_SEP       '\\'
227 #   define MY_LSTAT       _stat
228 #   define MY_STAT        _stat
229 #   define MY_S_ISREG(x)  ((x) & _S_IFREG)
230 #   define MY_S_ISDIR(x)  ((x) & _S_IFDIR)
231
232 #   define APPEND_FLAG(root, name) \
233       root=snocString((root), (name))
234
235 #   define APPEND_FILESPEC(root, name)                \
236       root = snocString ((root), (name))
237
238 #   define SET_BINARY_MODE(fd)                        \
239       do {                                            \
240          int retVal = setmode ( fileno ( fd ),        \
241                                 O_BINARY );           \
242          ERROR_IF_MINUS_ONE ( retVal );               \
243       } while ( 0 )
244
245 #endif /* BZ_LCCWIN32 */
246
247
248 /*---------------------------------------------*/
249 /*--
250   Some more stuff for all platforms :-)
251 --*/
252
253 typedef char            Char;
254 typedef unsigned char   Bool;
255 typedef unsigned char   UChar;
256 typedef int             Int32;
257 typedef unsigned int    UInt32;
258 typedef short           Int16;
259 typedef unsigned short  UInt16;
260                                        
261 #define True  ((Bool)1)
262 #define False ((Bool)0)
263
264 /*--
265   IntNative is your platform's `native' int size.
266   Only here to avoid probs with 64-bit platforms.
267 --*/
268 typedef int IntNative;
269
270
271 /*---------------------------------------------------*/
272 /*--- Misc (file handling) data decls             ---*/
273 /*---------------------------------------------------*/
274
275 Int32   verbosity;
276 Bool    keepInputFiles, smallMode, deleteOutputOnInterrupt;
277 Bool    forceOverwrite, testFailsExist, unzFailsExist, noisy;
278 Int32   numFileNames, numFilesProcessed, blockSize100k;
279 Int32   exitValue;
280
281 /*-- source modes; F==file, I==stdin, O==stdout --*/
282 #define SM_I2O           1
283 #define SM_F2O           2
284 #define SM_F2F           3
285
286 /*-- operation modes --*/
287 #define OM_Z             1
288 #define OM_UNZ           2
289 #define OM_TEST          3
290
291 Int32   opMode;
292 Int32   srcMode;
293
294 #define FILE_NAME_LEN 1034
295
296 Int32   longestFileName;
297 Char    inName [FILE_NAME_LEN];
298 Char    outName[FILE_NAME_LEN];
299 Char    tmpName[FILE_NAME_LEN];
300 Char    *progName;
301 Char    progNameReally[FILE_NAME_LEN];
302 FILE    *outputHandleJustInCase;
303 Int32   workFactor;
304
305 static void    panic                 ( Char* )   NORETURN;
306 static void    ioError               ( void )    NORETURN;
307 static void    outOfMemory           ( void )    NORETURN;
308 static void    configError           ( void )    NORETURN;
309 static void    crcError              ( void )    NORETURN;
310 static void    cleanUpAndFail        ( Int32 )   NORETURN;
311 static void    compressedStreamEOF   ( void )    NORETURN;
312
313 static void    copyFileName ( Char*, Char* );
314 static void*   myMalloc     ( Int32 );
315
316
317
318 /*---------------------------------------------------*/
319 /*--- An implementation of 64-bit ints.  Sigh.    ---*/
320 /*--- Roll on widespread deployment of ANSI C9X ! ---*/
321 /*---------------------------------------------------*/
322
323 typedef
324    struct { UChar b[8]; } 
325    UInt64;
326
327
328 static
329 void uInt64_from_UInt32s ( UInt64* n, UInt32 lo32, UInt32 hi32 )
330 {
331    n->b[7] = (UChar)((hi32 >> 24) & 0xFF);
332    n->b[6] = (UChar)((hi32 >> 16) & 0xFF);
333    n->b[5] = (UChar)((hi32 >> 8)  & 0xFF);
334    n->b[4] = (UChar) (hi32        & 0xFF);
335    n->b[3] = (UChar)((lo32 >> 24) & 0xFF);
336    n->b[2] = (UChar)((lo32 >> 16) & 0xFF);
337    n->b[1] = (UChar)((lo32 >> 8)  & 0xFF);
338    n->b[0] = (UChar) (lo32        & 0xFF);
339 }
340
341
342 static
343 double uInt64_to_double ( UInt64* n )
344 {
345    Int32  i;
346    double base = 1.0;
347    double sum  = 0.0;
348    for (i = 0; i < 8; i++) {
349       sum  += base * (double)(n->b[i]);
350       base *= 256.0;
351    }
352    return sum;
353 }
354
355
356 static
357 Bool uInt64_isZero ( UInt64* n )
358 {
359    Int32 i;
360    for (i = 0; i < 8; i++)
361       if (n->b[i] != 0) return 0;
362    return 1;
363 }
364
365
366 /* Divide *n by 10, and return the remainder.  */
367 static 
368 Int32 uInt64_qrm10 ( UInt64* n )
369 {
370    UInt32 rem, tmp;
371    Int32  i;
372    rem = 0;
373    for (i = 7; i >= 0; i--) {
374       tmp = rem * 256 + n->b[i];
375       n->b[i] = tmp / 10;
376       rem = tmp % 10;
377    }
378    return rem;
379 }
380
381
382 /* ... and the Whole Entire Point of all this UInt64 stuff is
383    so that we can supply the following function.
384 */
385 static
386 void uInt64_toAscii ( char* outbuf, UInt64* n )
387 {
388    Int32  i, q;
389    UChar  buf[32];
390    Int32  nBuf   = 0;
391    UInt64 n_copy = *n;
392    do {
393       q = uInt64_qrm10 ( &n_copy );
394       buf[nBuf] = q + '0';
395       nBuf++;
396    } while (!uInt64_isZero(&n_copy));
397    outbuf[nBuf] = 0;
398    for (i = 0; i < nBuf; i++) 
399       outbuf[i] = buf[nBuf-i-1];
400 }
401
402
403 /*---------------------------------------------------*/
404 /*--- Processing of complete files and streams    ---*/
405 /*---------------------------------------------------*/
406
407 /*---------------------------------------------*/
408 static 
409 Bool myfeof ( FILE* f )
410 {
411    Int32 c = fgetc ( f );
412    if (c == EOF) return True;
413    ungetc ( c, f );
414    return False;
415 }
416
417
418 /*---------------------------------------------*/
419 static 
420 void compressStream ( FILE *stream, FILE *zStream )
421 {
422    BZFILE* bzf = NULL;
423    UChar   ibuf[5000];
424    Int32   nIbuf;
425    UInt32  nbytes_in_lo32, nbytes_in_hi32;
426    UInt32  nbytes_out_lo32, nbytes_out_hi32;
427    Int32   bzerr, bzerr_dummy, ret;
428
429    SET_BINARY_MODE(stream);
430    SET_BINARY_MODE(zStream);
431
432    if (ferror(stream)) goto errhandler_io;
433    if (ferror(zStream)) goto errhandler_io;
434
435    bzf = BZ2_bzWriteOpen ( &bzerr, zStream, 
436                            blockSize100k, verbosity, workFactor );   
437    if (bzerr != BZ_OK) goto errhandler;
438
439    if (verbosity >= 2) fprintf ( stderr, "\n" );
440
441    while (True) {
442
443       if (myfeof(stream)) break;
444       nIbuf = fread ( ibuf, sizeof(UChar), 5000, stream );
445       if (ferror(stream)) goto errhandler_io;
446       if (nIbuf > 0) BZ2_bzWrite ( &bzerr, bzf, (void*)ibuf, nIbuf );
447       if (bzerr != BZ_OK) goto errhandler;
448
449    }
450
451    BZ2_bzWriteClose64 ( &bzerr, bzf, 0, 
452                         &nbytes_in_lo32, &nbytes_in_hi32,
453                         &nbytes_out_lo32, &nbytes_out_hi32 );
454    if (bzerr != BZ_OK) goto errhandler;
455
456    if (ferror(zStream)) goto errhandler_io;
457    ret = fflush ( zStream );
458    if (ret == EOF) goto errhandler_io;
459    if (zStream != stdout) {
460       ret = fclose ( zStream );
461       outputHandleJustInCase = NULL;
462       if (ret == EOF) goto errhandler_io;
463    }
464    outputHandleJustInCase = NULL;
465    if (ferror(stream)) goto errhandler_io;
466    ret = fclose ( stream );
467    if (ret == EOF) goto errhandler_io;
468
469    if (verbosity >= 1) {
470       if (nbytes_in_lo32 == 0 && nbytes_in_hi32 == 0) {
471          fprintf ( stderr, " no data compressed.\n");
472       } else {
473          Char   buf_nin[32], buf_nout[32];
474          UInt64 nbytes_in,   nbytes_out;
475          double nbytes_in_d, nbytes_out_d;
476          uInt64_from_UInt32s ( &nbytes_in, 
477                                nbytes_in_lo32, nbytes_in_hi32 );
478          uInt64_from_UInt32s ( &nbytes_out, 
479                                nbytes_out_lo32, nbytes_out_hi32 );
480          nbytes_in_d  = uInt64_to_double ( &nbytes_in );
481          nbytes_out_d = uInt64_to_double ( &nbytes_out );
482          uInt64_toAscii ( buf_nin, &nbytes_in );
483          uInt64_toAscii ( buf_nout, &nbytes_out );
484          fprintf ( stderr, "%6.3f:1, %6.3f bits/byte, "
485                    "%5.2f%% saved, %s in, %s out.\n",
486                    nbytes_in_d / nbytes_out_d,
487                    (8.0 * nbytes_out_d) / nbytes_in_d,
488                    100.0 * (1.0 - nbytes_out_d / nbytes_in_d),
489                    buf_nin,
490                    buf_nout
491                  );
492       }
493    }
494
495    return;
496
497    errhandler:
498    BZ2_bzWriteClose64 ( &bzerr_dummy, bzf, 1, 
499                         &nbytes_in_lo32, &nbytes_in_hi32,
500                         &nbytes_out_lo32, &nbytes_out_hi32 );
501    switch (bzerr) {
502       case BZ_CONFIG_ERROR:
503          configError(); break;
504       case BZ_MEM_ERROR:
505          outOfMemory (); break;
506       case BZ_IO_ERROR:
507          errhandler_io:
508          ioError(); break;
509       default:
510          panic ( "compress:unexpected error" );
511    }
512
513    panic ( "compress:end" );
514    /*notreached*/
515 }
516
517
518
519 /*---------------------------------------------*/
520 static 
521 Bool uncompressStream ( FILE *zStream, FILE *stream )
522 {
523    BZFILE* bzf = NULL;
524    Int32   bzerr, bzerr_dummy, ret, nread, streamNo, i;
525    UChar   obuf[5000];
526    UChar   unused[BZ_MAX_UNUSED];
527    Int32   nUnused;
528    UChar*  unusedTmp;
529
530    nUnused = 0;
531    streamNo = 0;
532
533    SET_BINARY_MODE(stream);
534    SET_BINARY_MODE(zStream);
535
536    if (ferror(stream)) goto errhandler_io;
537    if (ferror(zStream)) goto errhandler_io;
538
539    while (True) {
540
541       bzf = BZ2_bzReadOpen ( 
542                &bzerr, zStream, verbosity, 
543                (int)smallMode, unused, nUnused
544             );
545       if (bzf == NULL || bzerr != BZ_OK) goto errhandler;
546       streamNo++;
547
548       while (bzerr == BZ_OK) {
549          nread = BZ2_bzRead ( &bzerr, bzf, obuf, 5000 );
550          if (bzerr == BZ_DATA_ERROR_MAGIC) goto trycat;
551          if ((bzerr == BZ_OK || bzerr == BZ_STREAM_END) && nread > 0)
552             fwrite ( obuf, sizeof(UChar), nread, stream );
553          if (ferror(stream)) goto errhandler_io;
554       }
555       if (bzerr != BZ_STREAM_END) goto errhandler;
556
557       BZ2_bzReadGetUnused ( &bzerr, bzf, (void**)(&unusedTmp), &nUnused );
558       if (bzerr != BZ_OK) panic ( "decompress:bzReadGetUnused" );
559
560       for (i = 0; i < nUnused; i++) unused[i] = unusedTmp[i];
561
562       BZ2_bzReadClose ( &bzerr, bzf );
563       if (bzerr != BZ_OK) panic ( "decompress:bzReadGetUnused" );
564
565       if (nUnused == 0 && myfeof(zStream)) break;
566    }
567
568    closeok:
569    if (ferror(zStream)) goto errhandler_io;
570    ret = fclose ( zStream );
571    if (ret == EOF) goto errhandler_io;
572
573    if (ferror(stream)) goto errhandler_io;
574    ret = fflush ( stream );
575    if (ret != 0) goto errhandler_io;
576    if (stream != stdout) {
577       ret = fclose ( stream );
578       outputHandleJustInCase = NULL;
579       if (ret == EOF) goto errhandler_io;
580    }
581    outputHandleJustInCase = NULL;
582    if (verbosity >= 2) fprintf ( stderr, "\n    " );
583    return True;
584
585    trycat: 
586    if (forceOverwrite) {
587       rewind(zStream);
588       while (True) {
589          if (myfeof(zStream)) break;
590          nread = fread ( obuf, sizeof(UChar), 5000, zStream );
591          if (ferror(zStream)) goto errhandler_io;
592          if (nread > 0) fwrite ( obuf, sizeof(UChar), nread, stream );
593          if (ferror(stream)) goto errhandler_io;
594       }
595       goto closeok;
596    }
597   
598    errhandler:
599    BZ2_bzReadClose ( &bzerr_dummy, bzf );
600    switch (bzerr) {
601       case BZ_CONFIG_ERROR:
602          configError(); break;
603       case BZ_IO_ERROR:
604          errhandler_io:
605          ioError(); break;
606       case BZ_DATA_ERROR:
607          crcError();
608       case BZ_MEM_ERROR:
609          outOfMemory();
610       case BZ_UNEXPECTED_EOF:
611          compressedStreamEOF();
612       case BZ_DATA_ERROR_MAGIC:
613          if (zStream != stdin) fclose(zStream);
614          if (stream != stdout) fclose(stream);
615          if (streamNo == 1) {
616             return False;
617          } else {
618             if (noisy)
619             fprintf ( stderr, 
620                       "\n%s: %s: trailing garbage after EOF ignored\n",
621                       progName, inName );
622             return True;       
623          }
624       default:
625          panic ( "decompress:unexpected error" );
626    }
627
628    panic ( "decompress:end" );
629    return True; /*notreached*/
630 }
631
632
633 /*---------------------------------------------*/
634 static 
635 Bool testStream ( FILE *zStream )
636 {
637    BZFILE* bzf = NULL;
638    Int32   bzerr, bzerr_dummy, ret, nread, streamNo, i;
639    UChar   obuf[5000];
640    UChar   unused[BZ_MAX_UNUSED];
641    Int32   nUnused;
642    UChar*  unusedTmp;
643
644    nUnused = 0;
645    streamNo = 0;
646
647    SET_BINARY_MODE(zStream);
648    if (ferror(zStream)) goto errhandler_io;
649
650    while (True) {
651
652       bzf = BZ2_bzReadOpen ( 
653                &bzerr, zStream, verbosity, 
654                (int)smallMode, unused, nUnused
655             );
656       if (bzf == NULL || bzerr != BZ_OK) goto errhandler;
657       streamNo++;
658
659       while (bzerr == BZ_OK) {
660          nread = BZ2_bzRead ( &bzerr, bzf, obuf, 5000 );
661          if (bzerr == BZ_DATA_ERROR_MAGIC) goto errhandler;
662       }
663       if (bzerr != BZ_STREAM_END) goto errhandler;
664
665       BZ2_bzReadGetUnused ( &bzerr, bzf, (void**)(&unusedTmp), &nUnused );
666       if (bzerr != BZ_OK) panic ( "test:bzReadGetUnused" );
667
668       for (i = 0; i < nUnused; i++) unused[i] = unusedTmp[i];
669
670       BZ2_bzReadClose ( &bzerr, bzf );
671       if (bzerr != BZ_OK) panic ( "test:bzReadGetUnused" );
672       if (nUnused == 0 && myfeof(zStream)) break;
673
674    }
675
676    if (ferror(zStream)) goto errhandler_io;
677    ret = fclose ( zStream );
678    if (ret == EOF) goto errhandler_io;
679
680    if (verbosity >= 2) fprintf ( stderr, "\n    " );
681    return True;
682
683    errhandler:
684    BZ2_bzReadClose ( &bzerr_dummy, bzf );
685    if (verbosity == 0) 
686       fprintf ( stderr, "%s: %s: ", progName, inName );
687    switch (bzerr) {
688       case BZ_CONFIG_ERROR:
689          configError(); break;
690       case BZ_IO_ERROR:
691          errhandler_io:
692          ioError(); break;
693       case BZ_DATA_ERROR:
694          fprintf ( stderr,
695                    "data integrity (CRC) error in data\n" );
696          return False;
697       case BZ_MEM_ERROR:
698          outOfMemory();
699       case BZ_UNEXPECTED_EOF:
700          fprintf ( stderr,
701                    "file ends unexpectedly\n" );
702          return False;
703       case BZ_DATA_ERROR_MAGIC:
704          if (zStream != stdin) fclose(zStream);
705          if (streamNo == 1) {
706           fprintf ( stderr, 
707                     "bad magic number (file not created by bzip2)\n" );
708             return False;
709          } else {
710             if (noisy)
711             fprintf ( stderr, 
712                       "trailing garbage after EOF ignored\n" );
713             return True;       
714          }
715       default:
716          panic ( "test:unexpected error" );
717    }
718
719    panic ( "test:end" );
720    return True; /*notreached*/
721 }
722
723
724 /*---------------------------------------------------*/
725 /*--- Error [non-] handling grunge                ---*/
726 /*---------------------------------------------------*/
727
728 /*---------------------------------------------*/
729 static
730 void setExit ( Int32 v )
731 {
732    if (v > exitValue) exitValue = v;
733 }
734
735
736 /*---------------------------------------------*/
737 static 
738 void cadvise ( void )
739 {
740    if (noisy)
741    fprintf (
742       stderr,
743       "\nIt is possible that the compressed file(s) have become corrupted.\n"
744         "You can use the -tvv option to test integrity of such files.\n\n"
745         "You can use the `bzip2recover' program to attempt to recover\n"
746         "data from undamaged sections of corrupted files.\n\n"
747     );
748 }
749
750
751 /*---------------------------------------------*/
752 static 
753 void showFileNames ( void )
754 {
755    if (noisy)
756    fprintf (
757       stderr,
758       "\tInput file = %s, output file = %s\n",
759       inName, outName 
760    );
761 }
762
763
764 /*---------------------------------------------*/
765 static 
766 void cleanUpAndFail ( Int32 ec )
767 {
768    IntNative      retVal;
769    struct MY_STAT statBuf;
770
771    if ( srcMode == SM_F2F 
772         && opMode != OM_TEST
773         && deleteOutputOnInterrupt ) {
774
775       /* Check whether input file still exists.  Delete output file
776          only if input exists to avoid loss of data.  Joerg Prante, 5
777          January 2002.  (JRS 06-Jan-2002: other changes in 1.0.2 mean
778          this is less likely to happen.  But to be ultra-paranoid, we
779          do the check anyway.)  */
780       retVal = MY_STAT ( inName, &statBuf );
781       if (retVal == 0) {
782          if (noisy)
783             fprintf ( stderr, 
784                       "%s: Deleting output file %s, if it exists.\n",
785                       progName, outName );
786          if (outputHandleJustInCase != NULL)
787             fclose ( outputHandleJustInCase );
788          retVal = remove ( outName );
789          if (retVal != 0)
790             fprintf ( stderr,
791                       "%s: WARNING: deletion of output file "
792                       "(apparently) failed.\n",
793                       progName );
794       } else {
795          fprintf ( stderr,
796                    "%s: WARNING: deletion of output file suppressed\n",
797                     progName );
798          fprintf ( stderr,
799                    "%s:    since input file no longer exists.  Output file\n",
800                    progName );
801          fprintf ( stderr,
802                    "%s:    `%s' may be incomplete.\n",
803                    progName, outName );
804          fprintf ( stderr, 
805                    "%s:    I suggest doing an integrity test (bzip2 -tv)"
806                    " of it.\n",
807                    progName );
808       }
809    }
810
811    if (noisy && numFileNames > 0 && numFilesProcessed < numFileNames) {
812       fprintf ( stderr, 
813                 "%s: WARNING: some files have not been processed:\n"
814                 "%s:    %d specified on command line, %d not processed yet.\n\n",
815                 progName, progName,
816                 numFileNames, numFileNames - numFilesProcessed );
817    }
818    setExit(ec);
819    exit(exitValue);
820 }
821
822
823 /*---------------------------------------------*/
824 static 
825 void panic ( Char* s )
826 {
827    fprintf ( stderr,
828              "\n%s: PANIC -- internal consistency error:\n"
829              "\t%s\n"
830              "\tThis is a BUG.  Please report it to me at:\n"
831              "\tjseward@acm.org\n",
832              progName, s );
833    showFileNames();
834    cleanUpAndFail( 3 );
835 }
836
837
838 /*---------------------------------------------*/
839 static 
840 void crcError ( void )
841 {
842    fprintf ( stderr,
843              "\n%s: Data integrity error when decompressing.\n",
844              progName );
845    showFileNames();
846    cadvise();
847    cleanUpAndFail( 2 );
848 }
849
850
851 /*---------------------------------------------*/
852 static 
853 void compressedStreamEOF ( void )
854 {
855   if (noisy) {
856     fprintf ( stderr,
857               "\n%s: Compressed file ends unexpectedly;\n\t"
858               "perhaps it is corrupted?  *Possible* reason follows.\n",
859               progName );
860     perror ( progName );
861     showFileNames();
862     cadvise();
863   }
864   cleanUpAndFail( 2 );
865 }
866
867
868 /*---------------------------------------------*/
869 static 
870 void ioError ( void )
871 {
872    fprintf ( stderr,
873              "\n%s: I/O or other error, bailing out.  "
874              "Possible reason follows.\n",
875              progName );
876    perror ( progName );
877    showFileNames();
878    cleanUpAndFail( 1 );
879 }
880
881
882 /*---------------------------------------------*/
883 static 
884 void mySignalCatcher ( IntNative n )
885 {
886    fprintf ( stderr,
887              "\n%s: Control-C or similar caught, quitting.\n",
888              progName );
889    cleanUpAndFail(1);
890 }
891
892
893 /*---------------------------------------------*/
894 static 
895 void mySIGSEGVorSIGBUScatcher ( IntNative n )
896 {
897    if (opMode == OM_Z)
898       fprintf ( 
899       stderr,
900       "\n%s: Caught a SIGSEGV or SIGBUS whilst compressing.\n"
901       "\n"
902       "   Possible causes are (most likely first):\n"
903       "   (1) This computer has unreliable memory or cache hardware\n"
904       "       (a surprisingly common problem; try a different machine.)\n"
905       "   (2) A bug in the compiler used to create this executable\n"
906       "       (unlikely, if you didn't compile bzip2 yourself.)\n"
907       "   (3) A real bug in bzip2 -- I hope this should never be the case.\n"
908       "   The user's manual, Section 4.3, has more info on (1) and (2).\n"
909       "   \n"
910       "   If you suspect this is a bug in bzip2, or are unsure about (1)\n"
911       "   or (2), feel free to report it to me at: jseward@acm.org.\n"
912       "   Section 4.3 of the user's manual describes the info a useful\n"
913       "   bug report should have.  If the manual is available on your\n"
914       "   system, please try and read it before mailing me.  If you don't\n"
915       "   have the manual or can't be bothered to read it, mail me anyway.\n"
916       "\n",
917       progName );
918       else
919       fprintf ( 
920       stderr,
921       "\n%s: Caught a SIGSEGV or SIGBUS whilst decompressing.\n"
922       "\n"
923       "   Possible causes are (most likely first):\n"
924       "   (1) The compressed data is corrupted, and bzip2's usual checks\n"
925       "       failed to detect this.  Try bzip2 -tvv my_file.bz2.\n"
926       "   (2) This computer has unreliable memory or cache hardware\n"
927       "       (a surprisingly common problem; try a different machine.)\n"
928       "   (3) A bug in the compiler used to create this executable\n"
929       "       (unlikely, if you didn't compile bzip2 yourself.)\n"
930       "   (4) A real bug in bzip2 -- I hope this should never be the case.\n"
931       "   The user's manual, Section 4.3, has more info on (2) and (3).\n"
932       "   \n"
933       "   If you suspect this is a bug in bzip2, or are unsure about (2)\n"
934       "   or (3), feel free to report it to me at: jseward@acm.org.\n"
935       "   Section 4.3 of the user's manual describes the info a useful\n"
936       "   bug report should have.  If the manual is available on your\n"
937       "   system, please try and read it before mailing me.  If you don't\n"
938       "   have the manual or can't be bothered to read it, mail me anyway.\n"
939       "\n",
940       progName );
941
942    showFileNames();
943    if (opMode == OM_Z)
944       cleanUpAndFail( 3 ); else
945       { cadvise(); cleanUpAndFail( 2 ); }
946 }
947
948
949 /*---------------------------------------------*/
950 static 
951 void outOfMemory ( void )
952 {
953    fprintf ( stderr,
954              "\n%s: couldn't allocate enough memory\n",
955              progName );
956    showFileNames();
957    cleanUpAndFail(1);
958 }
959
960
961 /*---------------------------------------------*/
962 static 
963 void configError ( void )
964 {
965    fprintf ( stderr,
966              "bzip2: I'm not configured correctly for this platform!\n"
967              "\tI require Int32, Int16 and Char to have sizes\n"
968              "\tof 4, 2 and 1 bytes to run properly, and they don't.\n"
969              "\tProbably you can fix this by defining them correctly,\n"
970              "\tand recompiling.  Bye!\n" );
971    setExit(3);
972    exit(exitValue);
973 }
974
975
976 /*---------------------------------------------------*/
977 /*--- The main driver machinery                   ---*/
978 /*---------------------------------------------------*/
979
980 /* All rather crufty.  The main problem is that input files
981    are stat()d multiple times before use.  This should be
982    cleaned up. 
983 */
984
985 /*---------------------------------------------*/
986 static 
987 void pad ( Char *s )
988 {
989    Int32 i;
990    if ( (Int32)strlen(s) >= longestFileName ) return;
991    for (i = 1; i <= longestFileName - (Int32)strlen(s); i++)
992       fprintf ( stderr, " " );
993 }
994
995
996 /*---------------------------------------------*/
997 static 
998 void copyFileName ( Char* to, Char* from ) 
999 {
1000    if ( strlen(from) > FILE_NAME_LEN-10 )  {
1001       fprintf (
1002          stderr,
1003          "bzip2: file name\n`%s'\n"
1004          "is suspiciously (more than %d chars) long.\n"
1005          "Try using a reasonable file name instead.  Sorry! :-)\n",
1006          from, FILE_NAME_LEN-10
1007       );
1008       setExit(1);
1009       exit(exitValue);
1010    }
1011
1012   strncpy(to,from,FILE_NAME_LEN-10);
1013   to[FILE_NAME_LEN-10]='\0';
1014 }
1015
1016
1017 /*---------------------------------------------*/
1018 static 
1019 Bool fileExists ( Char* name )
1020 {
1021    FILE *tmp   = fopen ( name, "rb" );
1022    Bool exists = (tmp != NULL);
1023    if (tmp != NULL) fclose ( tmp );
1024    return exists;
1025 }
1026
1027
1028 /*---------------------------------------------*/
1029 /* Open an output file safely with O_EXCL and good permissions.
1030    This avoids a race condition in versions < 1.0.2, in which
1031    the file was first opened and then had its interim permissions
1032    set safely.  We instead use open() to create the file with
1033    the interim permissions required. (--- --- rw-).
1034
1035    For non-Unix platforms, if we are not worrying about
1036    security issues, simple this simply behaves like fopen.
1037 */
1038 FILE* fopen_output_safely ( Char* name, const char* mode )
1039 {
1040 #  if BZ_UNIX
1041    FILE*     fp;
1042    IntNative fh;
1043    fh = open(name, O_WRONLY|O_CREAT|O_EXCL, S_IWUSR|S_IRUSR);
1044    if (fh == -1) return NULL;
1045    fp = fdopen(fh, mode);
1046    if (fp == NULL) close(fh);
1047    return fp;
1048 #  else
1049    return fopen(name, mode);
1050 #  endif
1051 }
1052
1053
1054 /*---------------------------------------------*/
1055 /*--
1056   if in doubt, return True
1057 --*/
1058 static 
1059 Bool notAStandardFile ( Char* name )
1060 {
1061    IntNative      i;
1062    struct MY_STAT statBuf;
1063
1064    i = MY_LSTAT ( name, &statBuf );
1065    if (i != 0) return True;
1066    if (MY_S_ISREG(statBuf.st_mode)) return False;
1067    return True;
1068 }
1069
1070
1071 /*---------------------------------------------*/
1072 /*--
1073   rac 11/21/98 see if file has hard links to it
1074 --*/
1075 static 
1076 Int32 countHardLinks ( Char* name )
1077 {  
1078    IntNative      i;
1079    struct MY_STAT statBuf;
1080
1081    i = MY_LSTAT ( name, &statBuf );
1082    if (i != 0) return 0;
1083    return (statBuf.st_nlink - 1);
1084 }
1085
1086
1087 /*---------------------------------------------*/
1088 /* Copy modification date, access date, permissions and owner from the
1089    source to destination file.  We have to copy this meta-info off
1090    into fileMetaInfo before starting to compress / decompress it,
1091    because doing it afterwards means we get the wrong access time.
1092
1093    To complicate matters, in compress() and decompress() below, the
1094    sequence of tests preceding the call to saveInputFileMetaInfo()
1095    involves calling fileExists(), which in turn establishes its result
1096    by attempting to fopen() the file, and if successful, immediately
1097    fclose()ing it again.  So we have to assume that the fopen() call
1098    does not cause the access time field to be updated.
1099
1100    Reading of the man page for stat() (man 2 stat) on RedHat 7.2 seems
1101    to imply that merely doing open() will not affect the access time.
1102    Therefore we merely need to hope that the C library only does
1103    open() as a result of fopen(), and not any kind of read()-ahead
1104    cleverness.
1105
1106    It sounds pretty fragile to me.  Whether this carries across
1107    robustly to arbitrary Unix-like platforms (or even works robustly
1108    on this one, RedHat 7.2) is unknown to me.  Nevertheless ...  
1109 */
1110 #if BZ_UNIX
1111 static 
1112 struct MY_STAT fileMetaInfo;
1113 #endif
1114
1115 static 
1116 void saveInputFileMetaInfo ( Char *srcName )
1117 {
1118 #  if BZ_UNIX
1119    IntNative retVal;
1120    /* Note use of stat here, not lstat. */
1121    retVal = MY_STAT( srcName, &fileMetaInfo );
1122    ERROR_IF_NOT_ZERO ( retVal );
1123 #  endif
1124 }
1125
1126
1127 static 
1128 void applySavedMetaInfoToOutputFile ( Char *dstName )
1129 {
1130 #  if BZ_UNIX
1131    IntNative      retVal;
1132    struct utimbuf uTimBuf;
1133
1134    uTimBuf.actime = fileMetaInfo.st_atime;
1135    uTimBuf.modtime = fileMetaInfo.st_mtime;
1136
1137    retVal = chmod ( dstName, fileMetaInfo.st_mode );
1138    ERROR_IF_NOT_ZERO ( retVal );
1139
1140    retVal = utime ( dstName, &uTimBuf );
1141    ERROR_IF_NOT_ZERO ( retVal );
1142
1143    retVal = chown ( dstName, fileMetaInfo.st_uid, fileMetaInfo.st_gid );
1144    /* chown() will in many cases return with EPERM, which can
1145       be safely ignored.
1146    */
1147 #  endif
1148 }
1149
1150
1151 /*---------------------------------------------*/
1152 static 
1153 Bool containsDubiousChars ( Char* name )
1154 {
1155 #  if BZ_UNIX
1156    /* On unix, files can contain any characters and the file expansion
1157     * is performed by the shell.
1158     */
1159    return False;
1160 #  else /* ! BZ_UNIX */
1161    /* On non-unix (Win* platforms), wildcard characters are not allowed in 
1162     * filenames.
1163     */
1164    for (; *name != '\0'; name++)
1165       if (*name == '?' || *name == '*') return True;
1166    return False;
1167 #  endif /* BZ_UNIX */
1168 }
1169
1170
1171 /*---------------------------------------------*/
1172 #define BZ_N_SUFFIX_PAIRS 4
1173
1174 Char* zSuffix[BZ_N_SUFFIX_PAIRS] 
1175    = { ".bz2", ".bz", ".tbz2", ".tbz" };
1176 Char* unzSuffix[BZ_N_SUFFIX_PAIRS] 
1177    = { "", "", ".tar", ".tar" };
1178
1179 static 
1180 Bool hasSuffix ( Char* s, Char* suffix )
1181 {
1182    Int32 ns = strlen(s);
1183    Int32 nx = strlen(suffix);
1184    if (ns < nx) return False;
1185    if (strcmp(s + ns - nx, suffix) == 0) return True;
1186    return False;
1187 }
1188
1189 static 
1190 Bool mapSuffix ( Char* name, 
1191                  Char* oldSuffix, Char* newSuffix )
1192 {
1193    if (!hasSuffix(name,oldSuffix)) return False;
1194    name[strlen(name)-strlen(oldSuffix)] = 0;
1195    strcat ( name, newSuffix );
1196    return True;
1197 }
1198
1199
1200 /*---------------------------------------------*/
1201 static 
1202 void compress ( Char *name )
1203 {
1204    FILE  *inStr;
1205    FILE  *outStr;
1206    Int32 n, i;
1207    struct MY_STAT statBuf;
1208
1209    deleteOutputOnInterrupt = False;
1210
1211    if (name == NULL && srcMode != SM_I2O)
1212       panic ( "compress: bad modes\n" );
1213
1214    switch (srcMode) {
1215       case SM_I2O: 
1216          copyFileName ( inName, "(stdin)" );
1217          copyFileName ( outName, "(stdout)" ); 
1218          break;
1219       case SM_F2F: 
1220          copyFileName ( inName, name );
1221          copyFileName ( outName, name );
1222          strcat ( outName, ".bz2" ); 
1223          break;
1224       case SM_F2O: 
1225          copyFileName ( inName, name );
1226          copyFileName ( outName, "(stdout)" ); 
1227          break;
1228    }
1229
1230    if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
1231       if (noisy)
1232       fprintf ( stderr, "%s: There are no files matching `%s'.\n",
1233                 progName, inName );
1234       setExit(1);
1235       return;
1236    }
1237    if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
1238       fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
1239                 progName, inName, strerror(errno) );
1240       setExit(1);
1241       return;
1242    }
1243    for (i = 0; i < BZ_N_SUFFIX_PAIRS; i++) {
1244       if (hasSuffix(inName, zSuffix[i])) {
1245          if (noisy)
1246          fprintf ( stderr, 
1247                    "%s: Input file %s already has %s suffix.\n",
1248                    progName, inName, zSuffix[i] );
1249          setExit(1);
1250          return;
1251       }
1252    }
1253    if ( srcMode == SM_F2F || srcMode == SM_F2O ) {
1254       MY_STAT(inName, &statBuf);
1255       if ( MY_S_ISDIR(statBuf.st_mode) ) {
1256          fprintf( stderr,
1257                   "%s: Input file %s is a directory.\n",
1258                   progName,inName);
1259          setExit(1);
1260          return;
1261       }
1262    }
1263    if ( srcMode == SM_F2F && !forceOverwrite && notAStandardFile ( inName )) {
1264       if (noisy)
1265       fprintf ( stderr, "%s: Input file %s is not a normal file.\n",
1266                 progName, inName );
1267       setExit(1);
1268       return;
1269    }
1270    if ( srcMode == SM_F2F && fileExists ( outName ) ) {
1271       if (forceOverwrite) {
1272          remove(outName);
1273       } else {
1274          fprintf ( stderr, "%s: Output file %s already exists.\n",
1275                    progName, outName );
1276          setExit(1);
1277          return;
1278       }
1279    }
1280    if ( srcMode == SM_F2F && !forceOverwrite &&
1281         (n=countHardLinks ( inName )) > 0) {
1282       fprintf ( stderr, "%s: Input file %s has %d other link%s.\n",
1283                 progName, inName, n, n > 1 ? "s" : "" );
1284       setExit(1);
1285       return;
1286    }
1287
1288    if ( srcMode == SM_F2F ) {
1289       /* Save the file's meta-info before we open it.  Doing it later
1290          means we mess up the access times. */
1291       saveInputFileMetaInfo ( inName );
1292    }
1293
1294    switch ( srcMode ) {
1295
1296       case SM_I2O:
1297          inStr = stdin;
1298          outStr = stdout;
1299          if ( isatty ( fileno ( stdout ) ) ) {
1300             fprintf ( stderr,
1301                       "%s: I won't write compressed data to a terminal.\n",
1302                       progName );
1303             fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
1304                               progName, progName );
1305             setExit(1);
1306             return;
1307          };
1308          break;
1309
1310       case SM_F2O:
1311          inStr = fopen ( inName, "rb" );
1312          outStr = stdout;
1313          if ( isatty ( fileno ( stdout ) ) ) {
1314             fprintf ( stderr,
1315                       "%s: I won't write compressed data to a terminal.\n",
1316                       progName );
1317             fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
1318                               progName, progName );
1319             if ( inStr != NULL ) fclose ( inStr );
1320             setExit(1);
1321             return;
1322          };
1323          if ( inStr == NULL ) {
1324             fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
1325                       progName, inName, strerror(errno) );
1326             setExit(1);
1327             return;
1328          };
1329          break;
1330
1331       case SM_F2F:
1332          inStr = fopen ( inName, "rb" );
1333          outStr = fopen_output_safely ( outName, "wb" );
1334          if ( outStr == NULL) {
1335             fprintf ( stderr, "%s: Can't create output file %s: %s.\n",
1336                       progName, outName, strerror(errno) );
1337             if ( inStr != NULL ) fclose ( inStr );
1338             setExit(1);
1339             return;
1340          }
1341          if ( inStr == NULL ) {
1342             fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
1343                       progName, inName, strerror(errno) );
1344             if ( outStr != NULL ) fclose ( outStr );
1345             setExit(1);
1346             return;
1347          };
1348          break;
1349
1350       default:
1351          panic ( "compress: bad srcMode" );
1352          break;
1353    }
1354
1355    if (verbosity >= 1) {
1356       fprintf ( stderr,  "  %s: ", inName );
1357       pad ( inName );
1358       fflush ( stderr );
1359    }
1360
1361    /*--- Now the input and output handles are sane.  Do the Biz. ---*/
1362    outputHandleJustInCase = outStr;
1363    deleteOutputOnInterrupt = True;
1364    compressStream ( inStr, outStr );
1365    outputHandleJustInCase = NULL;
1366
1367    /*--- If there was an I/O error, we won't get here. ---*/
1368    if ( srcMode == SM_F2F ) {
1369       applySavedMetaInfoToOutputFile ( outName );
1370       deleteOutputOnInterrupt = False;
1371       if ( !keepInputFiles ) {
1372          IntNative retVal = remove ( inName );
1373          ERROR_IF_NOT_ZERO ( retVal );
1374       }
1375    }
1376
1377    deleteOutputOnInterrupt = False;
1378 }
1379
1380
1381 /*---------------------------------------------*/
1382 static 
1383 void uncompress ( Char *name )
1384 {
1385    FILE  *inStr;
1386    FILE  *outStr;
1387    Int32 n, i;
1388    Bool  magicNumberOK;
1389    Bool  cantGuess;
1390    struct MY_STAT statBuf;
1391
1392    deleteOutputOnInterrupt = False;
1393
1394    if (name == NULL && srcMode != SM_I2O)
1395       panic ( "uncompress: bad modes\n" );
1396
1397    cantGuess = False;
1398    switch (srcMode) {
1399       case SM_I2O: 
1400          copyFileName ( inName, "(stdin)" );
1401          copyFileName ( outName, "(stdout)" ); 
1402          break;
1403       case SM_F2F: 
1404          copyFileName ( inName, name );
1405          copyFileName ( outName, name );
1406          for (i = 0; i < BZ_N_SUFFIX_PAIRS; i++)
1407             if (mapSuffix(outName,zSuffix[i],unzSuffix[i]))
1408                goto zzz; 
1409          cantGuess = True;
1410          strcat ( outName, ".out" );
1411          break;
1412       case SM_F2O: 
1413          copyFileName ( inName, name );
1414          copyFileName ( outName, "(stdout)" ); 
1415          break;
1416    }
1417
1418    zzz:
1419    if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
1420       if (noisy)
1421       fprintf ( stderr, "%s: There are no files matching `%s'.\n",
1422                 progName, inName );
1423       setExit(1);
1424       return;
1425    }
1426    if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
1427       fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
1428                 progName, inName, strerror(errno) );
1429       setExit(1);
1430       return;
1431    }
1432    if ( srcMode == SM_F2F || srcMode == SM_F2O ) {
1433       MY_STAT(inName, &statBuf);
1434       if ( MY_S_ISDIR(statBuf.st_mode) ) {
1435          fprintf( stderr,
1436                   "%s: Input file %s is a directory.\n",
1437                   progName,inName);
1438          setExit(1);
1439          return;
1440       }
1441    }
1442    if ( srcMode == SM_F2F && !forceOverwrite && notAStandardFile ( inName )) {
1443       if (noisy)
1444       fprintf ( stderr, "%s: Input file %s is not a normal file.\n",
1445                 progName, inName );
1446       setExit(1);
1447       return;
1448    }
1449    if ( /* srcMode == SM_F2F implied && */ cantGuess ) {
1450       if (noisy)
1451       fprintf ( stderr, 
1452                 "%s: Can't guess original name for %s -- using %s\n",
1453                 progName, inName, outName );
1454       /* just a warning, no return */
1455    }   
1456    if ( srcMode == SM_F2F && fileExists ( outName ) ) {
1457       if (forceOverwrite) {
1458         remove(outName);
1459       } else {
1460         fprintf ( stderr, "%s: Output file %s already exists.\n",
1461                   progName, outName );
1462         setExit(1);
1463         return;
1464       }
1465    }
1466    if ( srcMode == SM_F2F && !forceOverwrite &&
1467         (n=countHardLinks ( inName ) ) > 0) {
1468       fprintf ( stderr, "%s: Input file %s has %d other link%s.\n",
1469                 progName, inName, n, n > 1 ? "s" : "" );
1470       setExit(1);
1471       return;
1472    }
1473
1474    if ( srcMode == SM_F2F ) {
1475       /* Save the file's meta-info before we open it.  Doing it later
1476          means we mess up the access times. */
1477       saveInputFileMetaInfo ( inName );
1478    }
1479
1480    switch ( srcMode ) {
1481
1482       case SM_I2O:
1483          inStr = stdin;
1484          outStr = stdout;
1485          if ( isatty ( fileno ( stdin ) ) ) {
1486             fprintf ( stderr,
1487                       "%s: I won't read compressed data from a terminal.\n",
1488                       progName );
1489             fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
1490                               progName, progName );
1491             setExit(1);
1492             return;
1493          };
1494          break;
1495
1496       case SM_F2O:
1497          inStr = fopen ( inName, "rb" );
1498          outStr = stdout;
1499          if ( inStr == NULL ) {
1500             fprintf ( stderr, "%s: Can't open input file %s:%s.\n",
1501                       progName, inName, strerror(errno) );
1502             if ( inStr != NULL ) fclose ( inStr );
1503             setExit(1);
1504             return;
1505          };
1506          break;
1507
1508       case SM_F2F:
1509          inStr = fopen ( inName, "rb" );
1510          outStr = fopen_output_safely ( outName, "wb" );
1511          if ( outStr == NULL) {
1512             fprintf ( stderr, "%s: Can't create output file %s: %s.\n",
1513                       progName, outName, strerror(errno) );
1514             if ( inStr != NULL ) fclose ( inStr );
1515             setExit(1);
1516             return;
1517          }
1518          if ( inStr == NULL ) {
1519             fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
1520                       progName, inName, strerror(errno) );
1521             if ( outStr != NULL ) fclose ( outStr );
1522             setExit(1);
1523             return;
1524          };
1525          break;
1526
1527       default:
1528          panic ( "uncompress: bad srcMode" );
1529          break;
1530    }
1531
1532    if (verbosity >= 1) {
1533       fprintf ( stderr, "  %s: ", inName );
1534       pad ( inName );
1535       fflush ( stderr );
1536    }
1537
1538    /*--- Now the input and output handles are sane.  Do the Biz. ---*/
1539    outputHandleJustInCase = outStr;
1540    deleteOutputOnInterrupt = True;
1541    magicNumberOK = uncompressStream ( inStr, outStr );
1542    outputHandleJustInCase = NULL;
1543
1544    /*--- If there was an I/O error, we won't get here. ---*/
1545    if ( magicNumberOK ) {
1546       if ( srcMode == SM_F2F ) {
1547          applySavedMetaInfoToOutputFile ( outName );
1548          deleteOutputOnInterrupt = False;
1549          if ( !keepInputFiles ) {
1550             IntNative retVal = remove ( inName );
1551             ERROR_IF_NOT_ZERO ( retVal );
1552          }
1553       }
1554    } else {
1555       unzFailsExist = True;
1556       deleteOutputOnInterrupt = False;
1557       if ( srcMode == SM_F2F ) {
1558          IntNative retVal = remove ( outName );
1559          ERROR_IF_NOT_ZERO ( retVal );
1560       }
1561    }
1562    deleteOutputOnInterrupt = False;
1563
1564    if ( magicNumberOK ) {
1565       if (verbosity >= 1)
1566          fprintf ( stderr, "done\n" );
1567    } else {
1568       setExit(2);
1569       if (verbosity >= 1)
1570          fprintf ( stderr, "not a bzip2 file.\n" ); else
1571          fprintf ( stderr,
1572                    "%s: %s is not a bzip2 file.\n",
1573                    progName, inName );
1574    }
1575
1576 }
1577
1578
1579 /*---------------------------------------------*/
1580 static 
1581 void testf ( Char *name )
1582 {
1583    FILE *inStr;
1584    Bool allOK;
1585    struct MY_STAT statBuf;
1586
1587    deleteOutputOnInterrupt = False;
1588
1589    if (name == NULL && srcMode != SM_I2O)
1590       panic ( "testf: bad modes\n" );
1591
1592    copyFileName ( outName, "(none)" );
1593    switch (srcMode) {
1594       case SM_I2O: copyFileName ( inName, "(stdin)" ); break;
1595       case SM_F2F: copyFileName ( inName, name ); break;
1596       case SM_F2O: copyFileName ( inName, name ); break;
1597    }
1598
1599    if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
1600       if (noisy)
1601       fprintf ( stderr, "%s: There are no files matching `%s'.\n",
1602                 progName, inName );
1603       setExit(1);
1604       return;
1605    }
1606    if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
1607       fprintf ( stderr, "%s: Can't open input %s: %s.\n",
1608                 progName, inName, strerror(errno) );
1609       setExit(1);
1610       return;
1611    }
1612    if ( srcMode != SM_I2O ) {
1613       MY_STAT(inName, &statBuf);
1614       if ( MY_S_ISDIR(statBuf.st_mode) ) {
1615          fprintf( stderr,
1616                   "%s: Input file %s is a directory.\n",
1617                   progName,inName);
1618          setExit(1);
1619          return;
1620       }
1621    }
1622
1623    switch ( srcMode ) {
1624
1625       case SM_I2O:
1626          if ( isatty ( fileno ( stdin ) ) ) {
1627             fprintf ( stderr,
1628                       "%s: I won't read compressed data from a terminal.\n",
1629                       progName );
1630             fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
1631                               progName, progName );
1632             setExit(1);
1633             return;
1634          };
1635          inStr = stdin;
1636          break;
1637
1638       case SM_F2O: case SM_F2F:
1639          inStr = fopen ( inName, "rb" );
1640          if ( inStr == NULL ) {
1641             fprintf ( stderr, "%s: Can't open input file %s:%s.\n",
1642                       progName, inName, strerror(errno) );
1643             setExit(1);
1644             return;
1645          };
1646          break;
1647
1648       default:
1649          panic ( "testf: bad srcMode" );
1650          break;
1651    }
1652
1653    if (verbosity >= 1) {
1654       fprintf ( stderr, "  %s: ", inName );
1655       pad ( inName );
1656       fflush ( stderr );
1657    }
1658
1659    /*--- Now the input handle is sane.  Do the Biz. ---*/
1660    outputHandleJustInCase = NULL;
1661    allOK = testStream ( inStr );
1662
1663    if (allOK && verbosity >= 1) fprintf ( stderr, "ok\n" );
1664    if (!allOK) testFailsExist = True;
1665 }
1666
1667
1668 /*---------------------------------------------*/
1669 static 
1670 void license ( void )
1671 {
1672    fprintf ( stderr,
1673
1674     "bzip2, a block-sorting file compressor.  "
1675     "Version %s.\n"
1676     "   \n"
1677     "   Copyright (C) 1996-2002 by Julian Seward.\n"
1678     "   \n"
1679     "   This program is free software; you can redistribute it and/or modify\n"
1680     "   it under the terms set out in the LICENSE file, which is included\n"
1681     "   in the bzip2-1.0 source distribution.\n"
1682     "   \n"
1683     "   This program is distributed in the hope that it will be useful,\n"
1684     "   but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1685     "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
1686     "   LICENSE file for more details.\n"
1687     "   \n",
1688     BZ2_bzlibVersion()
1689    );
1690 }
1691
1692
1693 /*---------------------------------------------*/
1694 static 
1695 void usage ( Char *fullProgName )
1696 {
1697    fprintf (
1698       stderr,
1699       "bzip2, a block-sorting file compressor.  "
1700       "Version %s.\n"
1701       "\n   usage: %s [flags and input files in any order]\n"
1702       "\n"
1703       "   -h --help           print this message\n"
1704       "   -d --decompress     force decompression\n"
1705       "   -z --compress       force compression\n"
1706       "   -k --keep           keep (don't delete) input files\n"
1707       "   -f --force          overwrite existing output files\n"
1708       "   -t --test           test compressed file integrity\n"
1709       "   -c --stdout         output to standard out\n"
1710       "   -q --quiet          suppress noncritical error messages\n"
1711       "   -v --verbose        be verbose (a 2nd -v gives more)\n"
1712       "   -L --license        display software version & license\n"
1713       "   -V --version        display software version & license\n"
1714       "   -s --small          use less memory (at most 2500k)\n"
1715       "   -1 .. -9            set block size to 100k .. 900k\n"
1716       "   --fast              alias for -1\n"
1717       "   --best              alias for -9\n"
1718       "\n"
1719       "   If invoked as `bzip2', default action is to compress.\n"
1720       "              as `bunzip2',  default action is to decompress.\n"
1721       "              as `bzcat', default action is to decompress to stdout.\n"
1722       "\n"
1723       "   If no file names are given, bzip2 compresses or decompresses\n"
1724       "   from standard input to standard output.  You can combine\n"
1725       "   short flags, so `-v -4' means the same as -v4 or -4v, &c.\n"
1726 #     if BZ_UNIX
1727       "\n"
1728 #     endif
1729       ,
1730
1731       BZ2_bzlibVersion(),
1732       fullProgName
1733    );
1734 }
1735
1736
1737 /*---------------------------------------------*/
1738 static 
1739 void redundant ( Char* flag )
1740 {
1741    fprintf ( 
1742       stderr, 
1743       "%s: %s is redundant in versions 0.9.5 and above\n",
1744       progName, flag );
1745 }
1746
1747
1748 /*---------------------------------------------*/
1749 /*--
1750   All the garbage from here to main() is purely to
1751   implement a linked list of command-line arguments,
1752   into which main() copies argv[1 .. argc-1].
1753
1754   The purpose of this exercise is to facilitate 
1755   the expansion of wildcard characters * and ? in 
1756   filenames for OSs which don't know how to do it
1757   themselves, like MSDOS, Windows 95 and NT.
1758
1759   The actual Dirty Work is done by the platform-
1760   specific macro APPEND_FILESPEC.
1761 --*/
1762
1763 typedef
1764    struct zzzz {
1765       Char        *name;
1766       struct zzzz *link;
1767    }
1768    Cell;
1769
1770
1771 /*---------------------------------------------*/
1772 static 
1773 void *myMalloc ( Int32 n )
1774 {
1775    void* p;
1776
1777    p = malloc ( (size_t)n );
1778    if (p == NULL) outOfMemory ();
1779    return p;
1780 }
1781
1782
1783 /*---------------------------------------------*/
1784 static 
1785 Cell *mkCell ( void )
1786 {
1787    Cell *c;
1788
1789    c = (Cell*) myMalloc ( sizeof ( Cell ) );
1790    c->name = NULL;
1791    c->link = NULL;
1792    return c;
1793 }
1794
1795
1796 /*---------------------------------------------*/
1797 static 
1798 Cell *snocString ( Cell *root, Char *name )
1799 {
1800    if (root == NULL) {
1801       Cell *tmp = mkCell();
1802       tmp->name = (Char*) myMalloc ( 5 + strlen(name) );
1803       strcpy ( tmp->name, name );
1804       return tmp;
1805    } else {
1806       Cell *tmp = root;
1807       while (tmp->link != NULL) tmp = tmp->link;
1808       tmp->link = snocString ( tmp->link, name );
1809       return root;
1810    }
1811 }
1812
1813
1814 /*---------------------------------------------*/
1815 static 
1816 void addFlagsFromEnvVar ( Cell** argList, Char* varName ) 
1817 {
1818    Int32 i, j, k;
1819    Char *envbase, *p;
1820
1821    envbase = getenv(varName);
1822    if (envbase != NULL) {
1823       p = envbase;
1824       i = 0;
1825       while (True) {
1826          if (p[i] == 0) break;
1827          p += i;
1828          i = 0;
1829          while (isspace((Int32)(p[0]))) p++;
1830          while (p[i] != 0 && !isspace((Int32)(p[i]))) i++;
1831          if (i > 0) {
1832             k = i; if (k > FILE_NAME_LEN-10) k = FILE_NAME_LEN-10;
1833             for (j = 0; j < k; j++) tmpName[j] = p[j];
1834             tmpName[k] = 0;
1835             APPEND_FLAG(*argList, tmpName);
1836          }
1837       }
1838    }
1839 }
1840
1841
1842 /*---------------------------------------------*/
1843 #define ISFLAG(s) (strcmp(aa->name, (s))==0)
1844
1845 IntNative main ( IntNative argc, Char *argv[] )
1846 {
1847    Int32  i, j;
1848    Char   *tmp;
1849    Cell   *argList;
1850    Cell   *aa;
1851    Bool   decode;
1852
1853    /*-- Be really really really paranoid :-) --*/
1854    if (sizeof(Int32) != 4 || sizeof(UInt32) != 4  ||
1855        sizeof(Int16) != 2 || sizeof(UInt16) != 2  ||
1856        sizeof(Char)  != 1 || sizeof(UChar)  != 1)
1857       configError();
1858
1859    /*-- Initialise --*/
1860    outputHandleJustInCase  = NULL;
1861    smallMode               = False;
1862    keepInputFiles          = False;
1863    forceOverwrite          = False;
1864    noisy                   = True;
1865    verbosity               = 0;
1866    blockSize100k           = 9;
1867    testFailsExist          = False;
1868    unzFailsExist           = False;
1869    numFileNames            = 0;
1870    numFilesProcessed       = 0;
1871    workFactor              = 30;
1872    deleteOutputOnInterrupt = False;
1873    exitValue               = 0;
1874    i = j = 0; /* avoid bogus warning from egcs-1.1.X */
1875
1876    /*-- Set up signal handlers for mem access errors --*/
1877    signal (SIGSEGV, mySIGSEGVorSIGBUScatcher);
1878 #  if BZ_UNIX
1879 #  ifndef __DJGPP__
1880    signal (SIGBUS,  mySIGSEGVorSIGBUScatcher);
1881 #  endif
1882 #  endif
1883
1884    copyFileName ( inName,  "(none)" );
1885    copyFileName ( outName, "(none)" );
1886
1887    copyFileName ( progNameReally, argv[0] );
1888    progName = &progNameReally[0];
1889    for (tmp = &progNameReally[0]; *tmp != '\0'; tmp++)
1890       if (*tmp == PATH_SEP) progName = tmp + 1;
1891
1892
1893    /*-- Copy flags from env var BZIP2, and 
1894         expand filename wildcards in arg list.
1895    --*/
1896    argList = NULL;
1897    addFlagsFromEnvVar ( &argList,  "BZIP2" );
1898    addFlagsFromEnvVar ( &argList,  "BZIP" );
1899    for (i = 1; i <= argc-1; i++)
1900       APPEND_FILESPEC(argList, argv[i]);
1901
1902
1903    /*-- Find the length of the longest filename --*/
1904    longestFileName = 7;
1905    numFileNames    = 0;
1906    decode          = True;
1907    for (aa = argList; aa != NULL; aa = aa->link) {
1908       if (ISFLAG("--")) { decode = False; continue; }
1909       if (aa->name[0] == '-' && decode) continue;
1910       numFileNames++;
1911       if (longestFileName < (Int32)strlen(aa->name) )
1912          longestFileName = (Int32)strlen(aa->name);
1913    }
1914
1915
1916    /*-- Determine source modes; flag handling may change this too. --*/
1917    if (numFileNames == 0)
1918       srcMode = SM_I2O; else srcMode = SM_F2F;
1919
1920
1921    /*-- Determine what to do (compress/uncompress/test/cat). --*/
1922    /*-- Note that subsequent flag handling may change this. --*/
1923    opMode = OM_Z;
1924
1925    if ( (strstr ( progName, "unzip" ) != 0) ||
1926         (strstr ( progName, "UNZIP" ) != 0) )
1927       opMode = OM_UNZ;
1928
1929    if ( (strstr ( progName, "z2cat" ) != 0) ||
1930         (strstr ( progName, "Z2CAT" ) != 0) ||
1931         (strstr ( progName, "zcat" ) != 0)  ||
1932         (strstr ( progName, "ZCAT" ) != 0) )  {
1933       opMode = OM_UNZ;
1934       srcMode = (numFileNames == 0) ? SM_I2O : SM_F2O;
1935    }
1936
1937
1938    /*-- Look at the flags. --*/
1939    for (aa = argList; aa != NULL; aa = aa->link) {
1940       if (ISFLAG("--")) break;
1941       if (aa->name[0] == '-' && aa->name[1] != '-') {
1942          for (j = 1; aa->name[j] != '\0'; j++) {
1943             switch (aa->name[j]) {
1944                case 'c': srcMode          = SM_F2O; break;
1945                case 'd': opMode           = OM_UNZ; break;
1946                case 'z': opMode           = OM_Z; break;
1947                case 'f': forceOverwrite   = True; break;
1948                case 't': opMode           = OM_TEST; break;
1949                case 'k': keepInputFiles   = True; break;
1950                case 's': smallMode        = True; break;
1951                case 'q': noisy            = False; break;
1952                case '1': blockSize100k    = 1; break;
1953                case '2': blockSize100k    = 2; break;
1954                case '3': blockSize100k    = 3; break;
1955                case '4': blockSize100k    = 4; break;
1956                case '5': blockSize100k    = 5; break;
1957                case '6': blockSize100k    = 6; break;
1958                case '7': blockSize100k    = 7; break;
1959                case '8': blockSize100k    = 8; break;
1960                case '9': blockSize100k    = 9; break;
1961                case 'V':
1962                case 'L': license();            break;
1963                case 'v': verbosity++; break;
1964                case 'h': usage ( progName );
1965                          exit ( 0 );
1966                          break;
1967                default:  fprintf ( stderr, "%s: Bad flag `%s'\n",
1968                                    progName, aa->name );
1969                          usage ( progName );
1970                          exit ( 1 );
1971                          break;
1972             }
1973          }
1974       }
1975    }
1976    
1977    /*-- And again ... --*/
1978    for (aa = argList; aa != NULL; aa = aa->link) {
1979       if (ISFLAG("--")) break;
1980       if (ISFLAG("--stdout"))            srcMode          = SM_F2O;  else
1981       if (ISFLAG("--decompress"))        opMode           = OM_UNZ;  else
1982       if (ISFLAG("--compress"))          opMode           = OM_Z;    else
1983       if (ISFLAG("--force"))             forceOverwrite   = True;    else
1984       if (ISFLAG("--test"))              opMode           = OM_TEST; else
1985       if (ISFLAG("--keep"))              keepInputFiles   = True;    else
1986       if (ISFLAG("--small"))             smallMode        = True;    else
1987       if (ISFLAG("--quiet"))             noisy            = False;   else
1988       if (ISFLAG("--version"))           license();                  else
1989       if (ISFLAG("--license"))           license();                  else
1990       if (ISFLAG("--exponential"))       workFactor = 1;             else 
1991       if (ISFLAG("--repetitive-best"))   redundant(aa->name);        else
1992       if (ISFLAG("--repetitive-fast"))   redundant(aa->name);        else
1993       if (ISFLAG("--fast"))              blockSize100k = 1;          else
1994       if (ISFLAG("--best"))              blockSize100k = 9;          else
1995       if (ISFLAG("--verbose"))           verbosity++;                else
1996       if (ISFLAG("--help"))              { usage ( progName ); exit ( 0 ); }
1997          else
1998          if (strncmp ( aa->name, "--", 2) == 0) {
1999             fprintf ( stderr, "%s: Bad flag `%s'\n", progName, aa->name );
2000             usage ( progName );
2001             exit ( 1 );
2002          }
2003    }
2004
2005    if (verbosity > 4) verbosity = 4;
2006    if (opMode == OM_Z && smallMode && blockSize100k > 2) 
2007       blockSize100k = 2;
2008
2009    if (opMode == OM_TEST && srcMode == SM_F2O) {
2010       fprintf ( stderr, "%s: -c and -t cannot be used together.\n",
2011                 progName );
2012       exit ( 1 );
2013    }
2014
2015    if (srcMode == SM_F2O && numFileNames == 0)
2016       srcMode = SM_I2O;
2017
2018    if (opMode != OM_Z) blockSize100k = 0;
2019
2020    if (srcMode == SM_F2F) {
2021       signal (SIGINT,  mySignalCatcher);
2022       signal (SIGTERM, mySignalCatcher);
2023 #     if BZ_UNIX
2024       signal (SIGHUP,  mySignalCatcher);
2025 #     endif
2026    }
2027
2028    if (opMode == OM_Z) {
2029      if (srcMode == SM_I2O) {
2030         compress ( NULL );
2031      } else {
2032         decode = True;
2033         for (aa = argList; aa != NULL; aa = aa->link) {
2034            if (ISFLAG("--")) { decode = False; continue; }
2035            if (aa->name[0] == '-' && decode) continue;
2036            numFilesProcessed++;
2037            compress ( aa->name );
2038         }
2039      }
2040    } 
2041    else
2042
2043    if (opMode == OM_UNZ) {
2044       unzFailsExist = False;
2045       if (srcMode == SM_I2O) {
2046          uncompress ( NULL );
2047       } else {
2048          decode = True;
2049          for (aa = argList; aa != NULL; aa = aa->link) {
2050             if (ISFLAG("--")) { decode = False; continue; }
2051             if (aa->name[0] == '-' && decode) continue;
2052             numFilesProcessed++;
2053             uncompress ( aa->name );
2054          }      
2055       }
2056       if (unzFailsExist) { 
2057          setExit(2); 
2058          exit(exitValue);
2059       }
2060    } 
2061
2062    else {
2063       testFailsExist = False;
2064       if (srcMode == SM_I2O) {
2065          testf ( NULL );
2066       } else {
2067          decode = True;
2068          for (aa = argList; aa != NULL; aa = aa->link) {
2069             if (ISFLAG("--")) { decode = False; continue; }
2070             if (aa->name[0] == '-' && decode) continue;
2071             numFilesProcessed++;
2072             testf ( aa->name );
2073          }
2074       }
2075       if (testFailsExist && noisy) {
2076          fprintf ( stderr,
2077            "\n"
2078            "You can use the `bzip2recover' program to attempt to recover\n"
2079            "data from undamaged sections of corrupted files.\n\n"
2080          );
2081          setExit(2);
2082          exit(exitValue);
2083       }
2084    }
2085
2086    /* Free the argument list memory to mollify leak detectors 
2087       (eg) Purify, Checker.  Serves no other useful purpose.
2088    */
2089    aa = argList;
2090    while (aa != NULL) {
2091       Cell* aa2 = aa->link;
2092       if (aa->name != NULL) free(aa->name);
2093       free(aa);
2094       aa = aa2;
2095    }
2096
2097    return exitValue;
2098 }
2099
2100
2101 /*-----------------------------------------------------------*/
2102 /*--- end                                         bzip2.c ---*/
2103 /*-----------------------------------------------------------*/