xref: /freebsd/contrib/bzip2/bzip2.c (revision a35d88931c87cfe6bd38f01d7bad22140b3b38f3)
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 /*-----------------------------------------------------------*/
2104