1 #pragma prototyped
2 
3 /*-----------------------------------------------------------*/
4 /*--- A block-sorting, lossless compressor        bzip2.c ---*/
5 /*-----------------------------------------------------------*/
6 
7 /*--
8   This file is a part of bzip2 and/or libbzip2, a program and
9   library for lossless, block-sorting data compression.
10 
11   Copyright (C) 1996-1998 Julian R Seward.  All rights reserved.
12 
13   Redistribution and use in source and binary forms, with or without
14   modification, are permitted provided that the following conditions
15   are met:
16 
17   1. Redistributions of source code must retain the above copyright
18      notice, this list of conditions and the following disclaimer.
19 
20   2. The origin of this software must not be misrepresented; you must
21      not claim that you wrote the original software.  If you use this
22      software in a product, an acknowledgment in the product
23      documentation would be appreciated but is not required.
24 
25   3. Altered source versions must be plainly marked as such, and must
26      not be misrepresented as being the original software.
27 
28   4. The name of the author may not be used to endorse or promote
29      products derived from this software without specific prior written
30      permission.
31 
32   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
33   OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
34   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
36   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
38   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
39   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
40   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
41   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
42   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43 
44   Julian Seward, Guildford, Surrey, UK.
45   jseward@acm.org
46   bzip2/libbzip2 version 0.9.0c of 18 October 1998
47 
48   This program is based on (at least) the work of:
49      Mike Burrows
50      David Wheeler
51      Peter Fenwick
52      Alistair Moffat
53      Radford Neal
54      Ian H. Witten
55      Robert Sedgewick
56      Jon L. Bentley
57 
58   For more information on these sources, see the manual.
59 --*/
60 
61 
62 /*----------------------------------------------------*/
63 /*--- IMPORTANT                                    ---*/
64 /*----------------------------------------------------*/
65 
66 /*--
67    WARNING:
68       This program and library (attempts to) compress data by
69       performing several non-trivial transformations on it.
70       Unless you are 100% familiar with *all* the algorithms
71       contained herein, and with the consequences of modifying them,
72       you should NOT meddle with the compression or decompression
73       machinery.  Incorrect changes can and very likely *will*
74       lead to disasterous loss of data.
75 
76    DISCLAIMER:
77       I TAKE NO RESPONSIBILITY FOR ANY LOSS OF DATA ARISING FROM THE
78       USE OF THIS PROGRAM, HOWSOEVER CAUSED.
79 
80       Every compression of a file implies an assumption that the
81       compressed file can be decompressed to reproduce the original.
82       Great efforts in design, coding and testing have been made to
83       ensure that this program works correctly.  However, the
84       complexity of the algorithms, and, in particular, the presence
85       of various special cases in the code which occur with very low
86       but non-zero probability make it impossible to rule out the
87       possibility of bugs remaining in the program.  DO NOT COMPRESS
88       ANY DATA WITH THIS PROGRAM AND/OR LIBRARY UNLESS YOU ARE PREPARED
89       TO ACCEPT THE POSSIBILITY, HOWEVER SMALL, THAT THE DATA WILL
90       NOT BE RECOVERABLE.
91 
92       That is not to say this program is inherently unreliable.
93       Indeed, I very much hope the opposite is true.  bzip2/libbzip2
94       has been carefully constructed and extensively tested.
95 
96    PATENTS:
97       To the best of my knowledge, bzip2/libbzip2 does not use any
98       patented algorithms.  However, I do not have the resources
99       available to carry out a full patent search.  Therefore I cannot
100       give any guarantee of the above statement.
101 --*/
102 
103 
104 
105 /*----------------------------------------------------*/
106 /*--- and now for something much more pleasant :-) ---*/
107 /*----------------------------------------------------*/
108 
109 /*---------------------------------------------*/
110 /*--
111   Some stuff for all platforms.
112 --*/
113 
114 #include <bzlib.h>
115 #include <stdio.h>
116 #include <stdlib.h>
117 #include <string.h>
118 #include <signal.h>
119 #include <math.h>
120 
121 #define ERROR_IF_EOF(i)       { if ((i) == EOF)  ioError(); }
122 #define ERROR_IF_NOT_ZERO(i)  { if ((i) != 0)    ioError(); }
123 #define ERROR_IF_MINUS_ONE(i) { if ((i) == (-1)) ioError(); }
124 
125 #define panic	bzpanic
126 
127 /*---------------------------------------------*/
128 /*--
129    Platform-specific stuff.
130 --*/
131 
132 #if BZ_UNIX
133 #   if _PACKAGE_ast
134 #	include <ast.h>
135 #	include <ls.h>
136 #	include <tm.h>
137 #   else
138 #	include <sys/types.h>
139 #	include <unistd.h>
140 #	include <sys/stat.h>
141 #	include <sys/times.h>
142 #   endif
143 
144 #   define PATH_SEP    '/'
145 #   define MY_LSTAT    lstat
146 #   define MY_S_IFREG  S_ISREG
147 #   define MY_STAT     stat
148 
149 #   define APPEND_FILESPEC(root, name) \
150       root=snocString((root), (name))
151 
152 #   define SET_BINARY_MODE(fd) /**/
153 #endif
154 
155 
156 
157 #if BZ_LCCWIN32
158 #   include <io.h>
159 #   include <fcntl.h>
160 #   include <sys\stat.h>
161 
162 #   define PATH_SEP       '\\'
163 #   define MY_LSTAT       _stat
164 #   define MY_STAT        _stat
165 #   define MY_S_IFREG(x)  ((x) & _S_IFREG)
166 
167 #   if 0
168    /*-- lcc-win32 seems to expand wildcards itself --*/
169 #   define APPEND_FILESPEC(root, spec)                \
170       do {                                            \
171          if ((spec)[0] == '-') {                      \
172             root = snocString((root), (spec));        \
173          } else {                                     \
174             struct _finddata_t c_file;                \
175             long hFile;                               \
176             hFile = _findfirst((spec), &c_file);      \
177             if ( hFile == -1L ) {                     \
178                root = snocString ((root), (spec));    \
179             } else {                                  \
180                int anInt = 0;                         \
181                while ( anInt == 0 ) {                 \
182                   root = snocString((root),           \
183                             &c_file.name[0]);         \
184                   anInt = _findnext(hFile, &c_file);  \
185                }                                      \
186             }                                         \
187          }                                            \
188       } while ( 0 )
189 #   else
190 #   define APPEND_FILESPEC(root, name)                \
191       root = snocString ((root), (name))
192 #   endif
193 
194 #   define SET_BINARY_MODE(fd)                        \
195       do {                                            \
196          int retVal = setmode ( fileno ( fd ),        \
197                                O_BINARY );            \
198          ERROR_IF_MINUS_ONE ( retVal );               \
199       } while ( 0 )
200 
201 #endif
202 
203 
204 /*---------------------------------------------*/
205 /*--
206   Some more stuff for all platforms :-)
207 --*/
208 
209 typedef char            Char;
210 typedef unsigned char   Bool;
211 typedef unsigned char   UChar;
212 typedef int             Int32;
213 typedef unsigned int    UInt32;
214 typedef short           Int16;
215 typedef unsigned short  UInt16;
216 
217 #define True  ((Bool)1)
218 #define False ((Bool)0)
219 
220 /*--
221   IntNative is your platform's `native' int size.
222   Only here to avoid probs with 64-bit platforms.
223 --*/
224 typedef int IntNative;
225 
226 
227 /*---------------------------------------------------*/
228 /*--- Misc (file handling) data decls             ---*/
229 /*---------------------------------------------------*/
230 
231 Int32   verbosity;
232 Bool    keepInputFiles, smallMode;
233 Bool    forceOverwrite, testFailsExist;
234 Int32   numFileNames, numFilesProcessed, blockSize100k;
235 
236 
237 /*-- source modes; F==file, I==stdin, O==stdout --*/
238 #define SM_I2O           1
239 #define SM_F2O           2
240 #define SM_F2F           3
241 
242 /*-- operation modes --*/
243 #define OM_Z             1
244 #define OM_UNZ           2
245 #define OM_TEST          3
246 
247 Int32   opMode;
248 Int32   srcMode;
249 
250 #define FILE_NAME_LEN 1034
251 
252 Int32   longestFileName;
253 Char    inName[FILE_NAME_LEN];
254 Char    outName[FILE_NAME_LEN];
255 Char    *progName;
256 Char    progNameReally[FILE_NAME_LEN];
257 FILE    *outputHandleJustInCase;
258 Int32   workFactor;
259 
260 void    panic                 ( Char* );
261 void    ioError               ( void );
262 void    outOfMemory           ( void );
263 void    blockOverrun          ( void );
264 void    badBlockHeader        ( void );
265 void    badBGLengths          ( void );
266 void    crcError              ( void );
267 void    bitStreamEOF          ( void );
268 void    cleanUpAndFail        ( Int32 );
269 void    compressedStreamEOF   ( void );
270 
271 void    copyFileName ( Char*, Char* );
272 void*   myMalloc ( Int32 );
273 
274 
275 
276 /*---------------------------------------------------*/
277 /*--- Processing of complete files and streams    ---*/
278 /*---------------------------------------------------*/
279 
280 /*---------------------------------------------*/
myfeof(FILE * f)281 Bool myfeof ( FILE* f )
282 {
283    Int32 c = fgetc ( f );
284    if (c == EOF) return True;
285    ungetc ( c, f );
286    return False;
287 }
288 
289 
290 /*---------------------------------------------*/
compressStream(FILE * stream,FILE * zStream)291 void compressStream ( FILE *stream, FILE *zStream )
292 {
293    BZFILE* bzf = NULL;
294    UChar   ibuf[5000];
295    Int32   nIbuf;
296    UInt32  nbytes_in, nbytes_out;
297    Int32   bzerr, bzerr_dummy, ret;
298 
299    SET_BINARY_MODE(stream);
300    SET_BINARY_MODE(zStream);
301 
302    if (ferror(stream)) goto errhandler_io;
303    if (ferror(zStream)) goto errhandler_io;
304 
305    bzf = bzWriteOpen ( &bzerr, zStream,
306                        blockSize100k, verbosity, workFactor );
307    if (bzerr != BZ_OK) goto errhandler;
308 
309    if (verbosity >= 2) fprintf ( stderr, "\n" );
310 
311    while (True) {
312 
313       if (myfeof(stream)) break;
314       nIbuf = fread ( ibuf, sizeof(UChar), 5000, stream );
315       if (ferror(stream)) goto errhandler_io;
316       if (nIbuf > 0) bzWrite ( &bzerr, bzf, (void*)ibuf, nIbuf );
317       if (bzerr != BZ_OK) goto errhandler;
318 
319    }
320 
321    bzWriteClose ( &bzerr, bzf, 0, &nbytes_in, &nbytes_out );
322    if (bzerr != BZ_OK) goto errhandler;
323 
324    if (ferror(zStream)) goto errhandler_io;
325    ret = fflush ( zStream );
326    if (ret == EOF) goto errhandler_io;
327    if (zStream != stdout) {
328       ret = fclose ( zStream );
329       if (ret == EOF) goto errhandler_io;
330    }
331    if (ferror(stream)) goto errhandler_io;
332    ret = fclose ( stream );
333    if (ret == EOF) goto errhandler_io;
334 
335    if (nbytes_in == 0) nbytes_in = 1;
336 
337    if (verbosity >= 1)
338       fprintf ( stderr, "%6.3f:1, %6.3f bits/byte, "
339                         "%5.2f%% saved, %d in, %d out.\n",
340                 (float)nbytes_in / (float)nbytes_out,
341                 (8.0 * (float)nbytes_out) / (float)nbytes_in,
342                 100.0 * (1.0 - (float)nbytes_out / (float)nbytes_in),
343                 nbytes_in,
344                 nbytes_out
345               );
346 
347    return;
348 
349    errhandler:
350    bzWriteClose ( &bzerr_dummy, bzf, 1, &nbytes_in, &nbytes_out );
351    switch (bzerr) {
352       case BZ_MEM_ERROR:
353          outOfMemory ();
354       case BZ_IO_ERROR:
355          errhandler_io:
356          ioError(); break;
357       default:
358          panic ( "compress:unexpected error" );
359    }
360 
361    panic ( "compress:end" );
362    /*notreached*/
363 }
364 
365 
366 
367 /*---------------------------------------------*/
uncompressStream(FILE * zStream,FILE * stream)368 Bool uncompressStream ( FILE *zStream, FILE *stream )
369 {
370    BZFILE* bzf = NULL;
371    Int32   bzerr, bzerr_dummy, ret, nread, streamNo, i;
372    UChar   obuf[5000];
373    UChar   unused[BZ_MAX_UNUSED];
374    Int32   nUnused;
375    UChar*  unusedTmp;
376 
377    nUnused = 0;
378    streamNo = 0;
379 
380    SET_BINARY_MODE(stream);
381    SET_BINARY_MODE(zStream);
382 
383    if (ferror(stream)) goto errhandler_io;
384    if (ferror(zStream)) goto errhandler_io;
385 
386    while (True) {
387 
388       bzf = bzReadOpen (
389                &bzerr, zStream, verbosity,
390                (int)smallMode, unused, nUnused
391             );
392       if (bzf == NULL || bzerr != BZ_OK) goto errhandler;
393       streamNo++;
394 
395       while (bzerr == BZ_OK) {
396          nread = bzRead ( &bzerr, bzf, obuf, 5000 );
397          if (bzerr == BZ_DATA_ERROR_MAGIC) goto errhandler;
398          if ((bzerr == BZ_OK || bzerr == BZ_STREAM_END) && nread > 0)
399             fwrite ( obuf, sizeof(UChar), nread, stream );
400          if (ferror(stream)) goto errhandler_io;
401       }
402       if (bzerr != BZ_STREAM_END) goto errhandler;
403 
404       bzReadGetUnused ( &bzerr, bzf, &unusedTmp, &nUnused );
405       if (bzerr != BZ_OK) panic ( "decompress:bzReadGetUnused" );
406 
407       for (i = 0; i < nUnused; i++) unused[i] = unusedTmp[i];
408 
409       bzReadClose ( &bzerr, bzf );
410       if (bzerr != BZ_OK) panic ( "decompress:bzReadGetUnused" );
411 
412       if (nUnused == 0 && myfeof(zStream)) break;
413 
414    }
415 
416    if (ferror(zStream)) goto errhandler_io;
417    ret = fclose ( zStream );
418    if (ret == EOF) goto errhandler_io;
419 
420    if (ferror(stream)) goto errhandler_io;
421    ret = fflush ( stream );
422    if (ret != 0) goto errhandler_io;
423    if (stream != stdout) {
424       ret = fclose ( stream );
425       if (ret == EOF) goto errhandler_io;
426    }
427    if (verbosity >= 2) fprintf ( stderr, "\n    " );
428    return True;
429 
430    errhandler:
431    bzReadClose ( &bzerr_dummy, bzf );
432    switch (bzerr) {
433       case BZ_IO_ERROR:
434          errhandler_io:
435          ioError(); break;
436       case BZ_DATA_ERROR:
437          crcError();
438       case BZ_MEM_ERROR:
439          outOfMemory();
440       case BZ_UNEXPECTED_EOF:
441          compressedStreamEOF();
442       case BZ_DATA_ERROR_MAGIC:
443          if (streamNo == 1) {
444             return False;
445          } else {
446             fprintf ( stderr,
447                       "\n%s: %s: trailing garbage after EOF ignored\n",
448                       progName, inName );
449             return True;
450          }
451       default:
452          panic ( "decompress:unexpected error" );
453    }
454 
455    panic ( "decompress:end" );
456    return True; /*notreached*/
457 }
458 
459 
460 /*---------------------------------------------*/
testStream(FILE * zStream)461 Bool testStream ( FILE *zStream )
462 {
463    BZFILE* bzf = NULL;
464    Int32   bzerr, bzerr_dummy, ret, streamNo, i;
465    UChar   obuf[5000];
466    UChar   unused[BZ_MAX_UNUSED];
467    Int32   nUnused;
468    UChar*  unusedTmp;
469 
470    nUnused = 0;
471    streamNo = 0;
472 
473    SET_BINARY_MODE(zStream);
474    if (ferror(zStream)) goto errhandler_io;
475 
476    while (True) {
477 
478       bzf = bzReadOpen (
479                &bzerr, zStream, verbosity,
480                (int)smallMode, unused, nUnused
481             );
482       if (bzf == NULL || bzerr != BZ_OK) goto errhandler;
483       streamNo++;
484 
485       while (bzerr == BZ_OK) {
486          bzRead ( &bzerr, bzf, obuf, 5000 );
487          if (bzerr == BZ_DATA_ERROR_MAGIC) goto errhandler;
488       }
489       if (bzerr != BZ_STREAM_END) goto errhandler;
490 
491       bzReadGetUnused ( &bzerr, bzf, &unusedTmp, &nUnused );
492       if (bzerr != BZ_OK) panic ( "test:bzReadGetUnused" );
493 
494       for (i = 0; i < nUnused; i++) unused[i] = unusedTmp[i];
495 
496       bzReadClose ( &bzerr, bzf );
497       if (bzerr != BZ_OK) panic ( "test:bzReadGetUnused" );
498       if (nUnused == 0 && myfeof(zStream)) break;
499 
500    }
501 
502    if (ferror(zStream)) goto errhandler_io;
503    ret = fclose ( zStream );
504    if (ret == EOF) goto errhandler_io;
505 
506    if (verbosity >= 2) fprintf ( stderr, "\n    " );
507    return True;
508 
509    errhandler:
510    bzReadClose ( &bzerr_dummy, bzf );
511    switch (bzerr) {
512       case BZ_IO_ERROR:
513          errhandler_io:
514          ioError(); break;
515       case BZ_DATA_ERROR:
516          fprintf ( stderr,
517                    "\n%s: data integrity (CRC) error in data\n",
518                    inName );
519          return False;
520       case BZ_MEM_ERROR:
521          outOfMemory();
522       case BZ_UNEXPECTED_EOF:
523          fprintf ( stderr,
524                    "\n%s: file ends unexpectedly\n",
525                    inName );
526          return False;
527       case BZ_DATA_ERROR_MAGIC:
528          if (streamNo == 1) {
529           fprintf ( stderr,
530                     "\n%s: bad magic number (ie, not created by bzip2)\n",
531                     inName );
532             return False;
533          } else {
534             fprintf ( stderr,
535                       "\n%s: %s: trailing garbage after EOF ignored\n",
536                       progName, inName );
537             return True;
538          }
539       default:
540          panic ( "test:unexpected error" );
541    }
542 
543    panic ( "test:end" );
544    return True; /*notreached*/
545 }
546 
547 
548 /*---------------------------------------------------*/
549 /*--- Error [non-] handling grunge                ---*/
550 /*---------------------------------------------------*/
551 
552 /*---------------------------------------------*/
cadvise(void)553 void cadvise ( void )
554 {
555    fprintf (
556       stderr,
557       "\nIt is possible that the compressed file(s) have become corrupted.\n"
558         "You can use the -tvv option to test integrity of such files.\n\n"
559         "You can use the `bzip2recover' program to *attempt* to recover\n"
560         "data from undamaged sections of corrupted files.\n\n"
561     );
562 }
563 
564 
565 /*---------------------------------------------*/
showFileNames(void)566 void showFileNames ( void )
567 {
568    fprintf (
569       stderr,
570       "\tInput file = %s, output file = %s\n",
571       inName, outName
572    );
573 }
574 
575 
576 /*---------------------------------------------*/
cleanUpAndFail(Int32 ec)577 void cleanUpAndFail ( Int32 ec )
578 {
579    IntNative retVal;
580 
581    if ( srcMode == SM_F2F && opMode != OM_TEST ) {
582       fprintf ( stderr, "%s: Deleting output file %s, if it exists.\n",
583                 progName, outName );
584       if (outputHandleJustInCase != NULL)
585          fclose ( outputHandleJustInCase );
586       retVal = remove ( outName );
587       if (retVal != 0)
588          fprintf ( stderr,
589                    "%s: WARNING: deletion of output file (apparently) failed.\n",
590                    progName );
591    }
592    if (numFileNames > 0 && numFilesProcessed < numFileNames) {
593       fprintf ( stderr,
594                 "%s: WARNING: some files have not been processed:\n"
595                 "\t%d specified on command line, %d not processed yet.\n\n",
596                 progName, numFileNames,
597                           numFileNames - numFilesProcessed );
598    }
599    exit ( ec );
600 }
601 
602 
603 /*---------------------------------------------*/
panic(Char * s)604 void panic ( Char* s )
605 {
606    fprintf ( stderr,
607              "\n%s: PANIC -- internal consistency error:\n"
608              "\t%s\n"
609              "\tThis is a BUG.  Please report it to me at:\n"
610              "\tjseward@acm.org\n",
611              progName, s );
612    showFileNames();
613    cleanUpAndFail( 3 );
614 }
615 
616 
617 /*---------------------------------------------*/
crcError()618 void crcError ()
619 {
620    fprintf ( stderr,
621              "\n%s: Data integrity error when decompressing.\n",
622              progName );
623    showFileNames();
624    cadvise();
625    cleanUpAndFail( 2 );
626 }
627 
628 
629 /*---------------------------------------------*/
compressedStreamEOF(void)630 void compressedStreamEOF ( void )
631 {
632    fprintf ( stderr,
633              "\n%s: Compressed file ends unexpectedly;\n\t"
634              "perhaps it is corrupted?  *Possible* reason follows.\n",
635              progName );
636    perror ( progName );
637    showFileNames();
638    cadvise();
639    cleanUpAndFail( 2 );
640 }
641 
642 
643 /*---------------------------------------------*/
ioError()644 void ioError ( )
645 {
646    fprintf ( stderr,
647              "\n%s: I/O or other error, bailing out.  Possible reason follows.\n",
648              progName );
649    perror ( progName );
650    showFileNames();
651    cleanUpAndFail( 1 );
652 }
653 
654 
655 /*---------------------------------------------*/
mySignalCatcher(IntNative n)656 void mySignalCatcher ( IntNative n )
657 {
658    fprintf ( stderr,
659              "\n%s: Control-C (or similar) caught, quitting.\n",
660              progName );
661    cleanUpAndFail(1);
662 }
663 
664 
665 /*---------------------------------------------*/
mySIGSEGVorSIGBUScatcher(IntNative n)666 void mySIGSEGVorSIGBUScatcher ( IntNative n )
667 {
668    if (opMode == OM_Z)
669       fprintf ( stderr,
670                 "\n%s: Caught a SIGSEGV or SIGBUS whilst compressing,\n"
671                 "\twhich probably indicates a bug in bzip2.  Please\n"
672                 "\treport it to me at: jseward@acm.org\n",
673                 progName );
674       else
675       fprintf ( stderr,
676                 "\n%s: Caught a SIGSEGV or SIGBUS whilst decompressing,\n"
677                 "\twhich probably indicates that the compressed data\n"
678                 "\tis corrupted.\n",
679                 progName );
680 
681    showFileNames();
682    if (opMode == OM_Z)
683       cleanUpAndFail( 3 ); else
684       { cadvise(); cleanUpAndFail( 2 ); }
685 }
686 
687 
688 /*---------------------------------------------*/
outOfMemory(void)689 void outOfMemory ( void )
690 {
691    fprintf ( stderr,
692              "\n%s: couldn't allocate enough memory\n",
693              progName );
694    showFileNames();
695    cleanUpAndFail(1);
696 }
697 
698 
699 /*---------------------------------------------------*/
700 /*--- The main driver machinery                   ---*/
701 /*---------------------------------------------------*/
702 
703 /*---------------------------------------------*/
pad(Char * s)704 void pad ( Char *s )
705 {
706    Int32 i;
707    if ( (Int32)strlen(s) >= longestFileName ) return;
708    for (i = 1; i <= longestFileName - (Int32)strlen(s); i++)
709       fprintf ( stderr, " " );
710 }
711 
712 
713 /*---------------------------------------------*/
copyFileName(Char * to,Char * from)714 void copyFileName ( Char* to, Char* from )
715 {
716    if ( strlen(from) > FILE_NAME_LEN-10 )  {
717       fprintf (
718          stderr,
719          "bzip2: file name\n`%s'\nis suspiciously (> 1024 chars) long.\n"
720          "Try using a reasonable file name instead.  Sorry! :)\n",
721          from
722       );
723       exit(1);
724    }
725 
726   strncpy(to,from,FILE_NAME_LEN-10);
727   to[FILE_NAME_LEN-10]='\0';
728 }
729 
730 
731 /*---------------------------------------------*/
fileExists(Char * name)732 Bool fileExists ( Char* name )
733 {
734    FILE *tmp   = fopen ( name, "rb" );
735    Bool exists = (tmp != NULL);
736    if (tmp != NULL) fclose ( tmp );
737    return exists;
738 }
739 
740 
741 /*---------------------------------------------*/
742 /*--
743   if in doubt, return True
744 --*/
notAStandardFile(Char * name)745 Bool notAStandardFile ( Char* name )
746 {
747    IntNative      i;
748    struct MY_STAT statBuf;
749 
750    i = MY_LSTAT ( name, &statBuf );
751    if (i != 0) return True;
752    if (MY_S_IFREG(statBuf.st_mode)) return False;
753    return True;
754 }
755 
756 
757 /*---------------------------------------------*/
copyDatePermissionsAndOwner(Char * srcName,Char * dstName)758 void copyDatePermissionsAndOwner ( Char *srcName, Char *dstName )
759 {
760 #if BZ_UNIX
761    IntNative      retVal;
762    struct MY_STAT statBuf;
763 #if !_PACKAGE_ast
764    struct utimbuf uTimBuf;
765 #endif
766 
767    retVal = MY_LSTAT ( srcName, &statBuf );
768    ERROR_IF_NOT_ZERO ( retVal );
769 #if !_PACKAGE_ast
770    uTimBuf.actime = statBuf.st_atime;
771    uTimBuf.modtime = statBuf.st_mtime;
772 #endif
773 
774    retVal = chmod ( dstName, statBuf.st_mode );
775    ERROR_IF_NOT_ZERO ( retVal );
776    /* Not sure if this is really portable or not.  Causes
777       problems on my x86-Linux Redhat 5.0 box.  Decided
778       to omit it from 0.9.0.  JRS, 27 June 98.  If you
779       understand Unix file semantics and portability issues
780       well enough to fix this properly, drop me a line
781       at jseward@acm.org.
782    retVal = chown ( dstName, statBuf.st_uid, statBuf.st_gid );
783    ERROR_IF_NOT_ZERO ( retVal );
784    */
785 #if _PACKAGE_ast
786    retVal = touch ( dstName, statBuf.st_atime, statBuf.st_mtime, 0 );
787 #else
788    retVal = utime ( dstName, &uTimBuf );
789 #endif
790    ERROR_IF_NOT_ZERO ( retVal );
791 #endif
792 }
793 
794 
795 /*---------------------------------------------*/
setInterimPermissions(Char * dstName)796 void setInterimPermissions ( Char *dstName )
797 {
798 #if BZ_UNIX
799    IntNative      retVal;
800    retVal = chmod ( dstName, S_IRUSR | S_IWUSR );
801    ERROR_IF_NOT_ZERO ( retVal );
802 #endif
803 }
804 
805 
806 
807 /*---------------------------------------------*/
endsInBz2(Char * name)808 Bool endsInBz2 ( Char* name )
809 {
810    Int32 n = strlen ( name );
811    if (n <= 4) return False;
812    return
813       (name[n-4] == '.' &&
814        name[n-3] == 'b' &&
815        name[n-2] == 'z' &&
816        name[n-1] == '2');
817 }
818 
819 
820 /*---------------------------------------------*/
containsDubiousChars(Char * name)821 Bool containsDubiousChars ( Char* name )
822 {
823    Bool cdc = False;
824    for (; *name != '\0'; name++)
825       if (*name == '?' || *name == '*') cdc = True;
826    return cdc;
827 }
828 
829 
830 /*---------------------------------------------*/
compress(Char * name)831 void compress ( Char *name )
832 {
833    FILE *inStr;
834    FILE *outStr;
835 
836    if (name == NULL && srcMode != SM_I2O)
837       panic ( "compress: bad modes\n" );
838 
839    switch (srcMode) {
840       case SM_I2O: copyFileName ( inName, "(stdin)" );
841                    copyFileName ( outName, "(stdout)" ); break;
842       case SM_F2F: copyFileName ( inName, name );
843                    copyFileName ( outName, name );
844                    strcat ( outName, ".bz2" ); break;
845       case SM_F2O: copyFileName ( inName, name );
846                    copyFileName ( outName, "(stdout)" ); break;
847    }
848 
849    if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
850       fprintf ( stderr, "%s: There are no files matching `%s'.\n",
851       progName, inName );
852       return;
853    }
854    if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
855       fprintf ( stderr, "%s: Input file %s doesn't exist, skipping.\n",
856                 progName, inName );
857       return;
858    }
859    if ( srcMode != SM_I2O && endsInBz2 ( inName )) {
860       fprintf ( stderr, "%s: Input file name %s ends in `.bz2', skipping.\n",
861                 progName, inName );
862       return;
863    }
864    if ( srcMode != SM_I2O && notAStandardFile ( inName )) {
865       fprintf ( stderr, "%s: Input file %s is not a normal file, skipping.\n",
866                 progName, inName );
867       return;
868    }
869    if ( srcMode == SM_F2F && !forceOverwrite && fileExists ( outName ) ) {
870       fprintf ( stderr, "%s: Output file %s already exists, skipping.\n",
871                 progName, outName );
872       return;
873    }
874 
875    switch ( srcMode ) {
876 
877       case SM_I2O:
878          inStr = stdin;
879          outStr = stdout;
880          if ( isatty ( fileno ( stdout ) ) ) {
881             fprintf ( stderr,
882                       "%s: I won't write compressed data to a terminal.\n",
883                       progName );
884             fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
885                               progName, progName );
886             return;
887          };
888          break;
889 
890       case SM_F2O:
891          inStr = fopen ( inName, "rb" );
892          outStr = stdout;
893          if ( isatty ( fileno ( stdout ) ) ) {
894             fprintf ( stderr,
895                       "%s: I won't write compressed data to a terminal.\n",
896                       progName );
897             fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
898                               progName, progName );
899             return;
900          };
901          if ( inStr == NULL ) {
902             fprintf ( stderr, "%s: Can't open input file %s, skipping.\n",
903                       progName, inName );
904             return;
905          };
906          break;
907 
908       case SM_F2F:
909          inStr = fopen ( inName, "rb" );
910          outStr = fopen ( outName, "wb" );
911          if ( outStr == NULL) {
912             fprintf ( stderr, "%s: Can't create output file %s, skipping.\n",
913                       progName, outName );
914             return;
915          }
916          if ( inStr == NULL ) {
917             fprintf ( stderr, "%s: Can't open input file %s, skipping.\n",
918                       progName, inName );
919             return;
920          };
921          setInterimPermissions ( outName );
922          break;
923 
924       default:
925          panic ( "compress: bad srcMode" );
926          break;
927    }
928 
929    if (verbosity >= 1) {
930       fprintf ( stderr,  "  %s: ", inName );
931       pad ( inName );
932       fflush ( stderr );
933    }
934 
935    /*--- Now the input and output handles are sane.  Do the Biz. ---*/
936    outputHandleJustInCase = outStr;
937    compressStream ( inStr, outStr );
938    outputHandleJustInCase = NULL;
939 
940    /*--- If there was an I/O error, we won't get here. ---*/
941    if ( srcMode == SM_F2F ) {
942       copyDatePermissionsAndOwner ( inName, outName );
943       if ( !keepInputFiles ) {
944          IntNative retVal = remove ( inName );
945          ERROR_IF_NOT_ZERO ( retVal );
946       }
947    }
948 }
949 
950 
951 /*---------------------------------------------*/
uncompress(Char * name)952 void uncompress ( Char *name )
953 {
954    FILE *inStr;
955    FILE *outStr;
956    Bool magicNumberOK;
957 
958    if (name == NULL && srcMode != SM_I2O)
959       panic ( "uncompress: bad modes\n" );
960 
961    switch (srcMode) {
962       case SM_I2O: copyFileName ( inName, "(stdin)" );
963                    copyFileName ( outName, "(stdout)" ); break;
964       case SM_F2F: copyFileName ( inName, name );
965                    copyFileName ( outName, name );
966                    if (endsInBz2 ( outName ))
967                       outName [ strlen ( outName ) - 4 ] = '\0';
968                    break;
969       case SM_F2O: copyFileName ( inName, name );
970                    copyFileName ( outName, "(stdout)" ); break;
971    }
972 
973    if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
974       fprintf ( stderr, "%s: There are no files matching `%s'.\n",
975                 progName, inName );
976       return;
977    }
978    if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
979       fprintf ( stderr, "%s: Input file %s doesn't exist, skipping.\n",
980                 progName, inName );
981       return;
982    }
983    if ( srcMode != SM_I2O && !endsInBz2 ( inName )) {
984       fprintf ( stderr,
985                 "%s: Input file name %s doesn't end in `.bz2', skipping.\n",
986                 progName, inName );
987       return;
988    }
989    if ( srcMode != SM_I2O && notAStandardFile ( inName )) {
990       fprintf ( stderr, "%s: Input file %s is not a normal file, skipping.\n",
991                 progName, inName );
992       return;
993    }
994    if ( srcMode == SM_F2F && !forceOverwrite && fileExists ( outName ) ) {
995       fprintf ( stderr, "%s: Output file %s already exists, skipping.\n",
996                 progName, outName );
997       return;
998    }
999 
1000    switch ( srcMode ) {
1001 
1002       case SM_I2O:
1003          inStr = stdin;
1004          outStr = stdout;
1005          if ( isatty ( fileno ( stdin ) ) ) {
1006             fprintf ( stderr,
1007                       "%s: I won't read compressed data from a terminal.\n",
1008                       progName );
1009             fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
1010                               progName, progName );
1011             return;
1012          };
1013          break;
1014 
1015       case SM_F2O:
1016          inStr = fopen ( inName, "rb" );
1017          outStr = stdout;
1018          if ( inStr == NULL ) {
1019             fprintf ( stderr, "%s: Can't open input file %s, skipping.\n",
1020                       progName, inName );
1021             return;
1022          };
1023          break;
1024 
1025       case SM_F2F:
1026          inStr = fopen ( inName, "rb" );
1027          outStr = fopen ( outName, "wb" );
1028          if ( outStr == NULL) {
1029             fprintf ( stderr, "%s: Can't create output file %s, skipping.\n",
1030                       progName, outName );
1031             return;
1032          }
1033          if ( inStr == NULL ) {
1034             fprintf ( stderr, "%s: Can't open input file %s, skipping.\n",
1035                       progName, inName );
1036             return;
1037          };
1038          setInterimPermissions ( outName );
1039          break;
1040 
1041       default:
1042          panic ( "uncompress: bad srcMode" );
1043          break;
1044    }
1045 
1046    if (verbosity >= 1) {
1047       fprintf ( stderr, "  %s: ", inName );
1048       pad ( inName );
1049       fflush ( stderr );
1050    }
1051 
1052    /*--- Now the input and output handles are sane.  Do the Biz. ---*/
1053    outputHandleJustInCase = outStr;
1054    magicNumberOK = uncompressStream ( inStr, outStr );
1055    outputHandleJustInCase = NULL;
1056 
1057    /*--- If there was an I/O error, we won't get here. ---*/
1058    if ( magicNumberOK ) {
1059       if ( srcMode == SM_F2F ) {
1060          copyDatePermissionsAndOwner ( inName, outName );
1061          if ( !keepInputFiles ) {
1062             IntNative retVal = remove ( inName );
1063             ERROR_IF_NOT_ZERO ( retVal );
1064          }
1065       }
1066    } else {
1067       if ( srcMode == SM_F2F ) {
1068          IntNative retVal = remove ( outName );
1069          ERROR_IF_NOT_ZERO ( retVal );
1070       }
1071    }
1072 
1073    if ( magicNumberOK ) {
1074       if (verbosity >= 1)
1075          fprintf ( stderr, "done\n" );
1076    } else {
1077       if (verbosity >= 1)
1078          fprintf ( stderr, "not a bzip2 file, skipping.\n" ); else
1079          fprintf ( stderr,
1080                    "%s: %s is not a bzip2 file, skipping.\n",
1081                    progName, inName );
1082    }
1083 
1084 }
1085 
1086 
1087 /*---------------------------------------------*/
testf(Char * name)1088 void testf ( Char *name )
1089 {
1090    FILE *inStr;
1091    Bool allOK;
1092 
1093    if (name == NULL && srcMode != SM_I2O)
1094       panic ( "testf: bad modes\n" );
1095 
1096    copyFileName ( outName, "(none)" );
1097    switch (srcMode) {
1098       case SM_I2O: copyFileName ( inName, "(stdin)" ); break;
1099       case SM_F2F: copyFileName ( inName, name ); break;
1100       case SM_F2O: copyFileName ( inName, name ); break;
1101    }
1102 
1103    if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
1104       fprintf ( stderr, "%s: There are no files matching `%s'.\n",
1105                 progName, inName );
1106       return;
1107    }
1108    if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
1109       fprintf ( stderr, "%s: Input file %s doesn't exist, skipping.\n",
1110                 progName, inName );
1111       return;
1112    }
1113    if ( srcMode != SM_I2O && !endsInBz2 ( inName )) {
1114       fprintf ( stderr,
1115                 "%s: Input file name %s doesn't end in `.bz2', skipping.\n",
1116                 progName, inName );
1117       return;
1118    }
1119    if ( srcMode != SM_I2O && notAStandardFile ( inName )) {
1120       fprintf ( stderr, "%s: Input file %s is not a normal file, skipping.\n",
1121                 progName, inName );
1122       return;
1123    }
1124 
1125    switch ( srcMode ) {
1126 
1127       case SM_I2O:
1128          if ( isatty ( fileno ( stdin ) ) ) {
1129             fprintf ( stderr,
1130                       "%s: I won't read compressed data from a terminal.\n",
1131                       progName );
1132             fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
1133                               progName, progName );
1134             return;
1135          };
1136          inStr = stdin;
1137          break;
1138 
1139       case SM_F2O: case SM_F2F:
1140          inStr = fopen ( inName, "rb" );
1141          if ( inStr == NULL ) {
1142             fprintf ( stderr, "%s: Can't open input file %s, skipping.\n",
1143                       progName, inName );
1144             return;
1145          };
1146          break;
1147 
1148       default:
1149          panic ( "testf: bad srcMode" );
1150          break;
1151    }
1152 
1153    if (verbosity >= 1) {
1154       fprintf ( stderr, "  %s: ", inName );
1155       pad ( inName );
1156       fflush ( stderr );
1157    }
1158 
1159    /*--- Now the input handle is sane.  Do the Biz. ---*/
1160    allOK = testStream ( inStr );
1161 
1162    if (allOK && verbosity >= 1) fprintf ( stderr, "ok\n" );
1163    if (!allOK) testFailsExist = True;
1164 }
1165 
1166 
1167 /*---------------------------------------------*/
license(void)1168 void license ( void )
1169 {
1170    fprintf ( stderr,
1171 
1172     "bzip2, a block-sorting file compressor.  "
1173     "Version 0.9.0c, 18-Oct-98.\n"
1174     "   \n"
1175     "   Copyright (C) 1996, 1997, 1998 by Julian Seward.\n"
1176     "   \n"
1177     "   This program is free software; you can redistribute it and/or modify\n"
1178     "   it under the terms set out in the LICENSE file, which is included\n"
1179     "   in the bzip2-0.9.0c source distribution.\n"
1180     "   \n"
1181     "   This program is distributed in the hope that it will be useful,\n"
1182     "   but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1183     "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
1184     "   LICENSE file for more details.\n"
1185     "   \n"
1186    );
1187 }
1188 
1189 
1190 /*---------------------------------------------*/
usage(Char * fullProgName)1191 void usage ( Char *fullProgName )
1192 {
1193    fprintf (
1194       stderr,
1195       "bzip2, a block-sorting file compressor.  "
1196       "Version 0.9.0c, 18-Oct-98.\n"
1197       "\n   usage: %s [flags and input files in any order]\n"
1198       "\n"
1199       "   -h --help           print this message\n"
1200       "   -d --decompress     force decompression\n"
1201       "   -z --compress       force compression\n"
1202       "   -k --keep           keep (don't delete) input files\n"
1203       "   -f --force          overwrite existing output filess\n"
1204       "   -t --test           test compressed file integrity\n"
1205       "   -c --stdout         output to standard out\n"
1206       "   -v --verbose        be verbose (a 2nd -v gives more)\n"
1207       "   -L --license        display software version & license\n"
1208       "   -V --version        display software version & license\n"
1209       "   -s --small          use less memory (at most 2500k)\n"
1210       "   -1 .. -9            set block size to 100k .. 900k\n"
1211       "   --repetitive-fast   compress repetitive blocks faster\n"
1212       "   --repetitive-best   compress repetitive blocks better\n"
1213       "\n"
1214       "   If invoked as `bzip2', default action is to compress.\n"
1215       "              as `bunzip2',  default action is to decompress.\n"
1216       "              as `bz2cat', default action is to decompress to stdout.\n"
1217       "\n"
1218       "   If no file names are given, bzip2 compresses or decompresses\n"
1219       "   from standard input to standard output.  You can combine\n"
1220       "   short flags, so `-v -4' means the same as -v4 or -4v, &c.\n"
1221 #if BZ_UNIX
1222       "\n"
1223 #endif
1224       ,
1225 
1226       fullProgName
1227    );
1228 }
1229 
1230 
1231 /*---------------------------------------------*/
1232 /*--
1233   All the garbage from here to main() is purely to
1234   implement a linked list of command-line arguments,
1235   into which main() copies argv[1 .. argc-1].
1236 
1237   The purpose of this ridiculous exercise is to
1238   facilitate the expansion of wildcard characters
1239   * and ? in filenames for halfwitted OSs like
1240   MSDOS, Windows 95 and NT.
1241 
1242   The actual Dirty Work is done by the platform-specific
1243   macro APPEND_FILESPEC.
1244 --*/
1245 
1246 typedef
1247    struct zzzz {
1248       Char        *name;
1249       struct zzzz *link;
1250    }
1251    Cell;
1252 
1253 
1254 /*---------------------------------------------*/
myMalloc(Int32 n)1255 void *myMalloc ( Int32 n )
1256 {
1257    void* p;
1258 
1259    p = malloc ( (size_t)n );
1260    if (p == NULL) outOfMemory ();
1261    return p;
1262 }
1263 
1264 
1265 /*---------------------------------------------*/
mkCell(void)1266 Cell *mkCell ( void )
1267 {
1268    Cell *c;
1269 
1270    c = (Cell*) myMalloc ( sizeof ( Cell ) );
1271    c->name = NULL;
1272    c->link = NULL;
1273    return c;
1274 }
1275 
1276 
1277 /*---------------------------------------------*/
snocString(Cell * root,Char * name)1278 Cell *snocString ( Cell *root, Char *name )
1279 {
1280    if (root == NULL) {
1281       Cell *tmp = mkCell();
1282       tmp->name = (Char*) myMalloc ( 5 + strlen(name) );
1283       strcpy ( tmp->name, name );
1284       return tmp;
1285    } else {
1286       Cell *tmp = root;
1287       while (tmp->link != NULL) tmp = tmp->link;
1288       tmp->link = snocString ( tmp->link, name );
1289       return root;
1290    }
1291 }
1292 
1293 
1294 /*---------------------------------------------*/
1295 #define ISFLAG(s) (strcmp(aa->name, (s))==0)
1296 
1297 
main(IntNative argc,Char * argv[])1298 IntNative main ( IntNative argc, Char *argv[] )
1299 {
1300    Int32  i, j;
1301    Char   *tmp;
1302    Cell   *argList;
1303    Cell   *aa;
1304 
1305    /*-- Be really really really paranoid :-) --*/
1306    if (sizeof(Int32) != 4 || sizeof(UInt32) != 4  ||
1307        sizeof(Int16) != 2 || sizeof(UInt16) != 2  ||
1308        sizeof(Char)  != 1 || sizeof(UChar)  != 1) {
1309       fprintf ( stderr,
1310                 "bzip2: I'm not configured correctly for this platform!\n"
1311                 "\tI require Int32, Int16 and Char to have sizes\n"
1312                 "\tof 4, 2 and 1 bytes to run properly, and they don't.\n"
1313                 "\tProbably you can fix this by defining them correctly,\n"
1314                 "\tand recompiling.  Bye!\n" );
1315       exit(3);
1316    }
1317 
1318 
1319    /*-- Set up signal handlers --*/
1320    signal (SIGINT,  mySignalCatcher);
1321    signal (SIGTERM, mySignalCatcher);
1322    signal (SIGSEGV, mySIGSEGVorSIGBUScatcher);
1323 #if BZ_UNIX
1324    signal (SIGHUP,  mySignalCatcher);
1325    signal (SIGBUS,  mySIGSEGVorSIGBUScatcher);
1326 #endif
1327 
1328 
1329    /*-- Initialise --*/
1330    outputHandleJustInCase  = NULL;
1331    smallMode               = False;
1332    keepInputFiles          = False;
1333    forceOverwrite          = False;
1334    verbosity               = 0;
1335    blockSize100k           = 9;
1336    testFailsExist          = False;
1337    numFileNames            = 0;
1338    numFilesProcessed       = 0;
1339    workFactor              = 30;
1340 
1341    copyFileName ( inName,  "(none)" );
1342    copyFileName ( outName, "(none)" );
1343 
1344    copyFileName ( progNameReally, argv[0] );
1345    progName = &progNameReally[0];
1346    for (tmp = &progNameReally[0]; *tmp != '\0'; tmp++)
1347       if (*tmp == PATH_SEP) progName = tmp + 1;
1348 
1349 
1350    /*-- Expand filename wildcards in arg list --*/
1351    argList = NULL;
1352    for (i = 1; i <= argc-1; i++)
1353       APPEND_FILESPEC(argList, argv[i]);
1354 
1355 
1356    /*-- Find the length of the longest filename --*/
1357    longestFileName = 7;
1358    numFileNames    = 0;
1359    for (aa = argList; aa != NULL; aa = aa->link)
1360       if (aa->name[0] != '-') {
1361          numFileNames++;
1362          if (longestFileName < (Int32)strlen(aa->name) )
1363             longestFileName = (Int32)strlen(aa->name);
1364       }
1365 
1366 
1367    /*-- Determine source modes; flag handling may change this too. --*/
1368    if (numFileNames == 0)
1369       srcMode = SM_I2O; else srcMode = SM_F2F;
1370 
1371 
1372    /*-- Determine what to do (compress/uncompress/test/cat). --*/
1373    /*-- Note that subsequent flag handling may change this. --*/
1374    opMode = OM_Z;
1375    tmp = progName;
1376    for (;;)
1377    {
1378 	switch (*tmp++)
1379 	{
1380 	case 0:
1381 	    break;
1382 	case 'u':
1383 	case 'U':
1384 	    if (!strncasecmp(tmp, "nzip", 4))
1385 	    {
1386       		opMode = OM_UNZ;
1387 		break;
1388 	    }
1389 	    continue;
1390 	case 'z':
1391 	case 'Z':
1392 	    if (!strncasecmp(tmp, "zcat", 4) || !strncasecmp(tmp, "z2cat", 5))
1393 	    {
1394       		opMode = OM_UNZ;
1395 		srcMode = (numFileNames == 0) ? SM_I2O : SM_F2O;
1396 		break;
1397 	    }
1398 	    continue;
1399 	default:
1400 	    continue;
1401 	}
1402 	break;
1403    }
1404 
1405    /*-- Look at the flags. --*/
1406    for (aa = argList; aa != NULL; aa = aa->link)
1407       if (aa->name[0] == '-' && aa->name[1] != '-')
1408          for (j = 1; aa->name[j] != '\0'; j++)
1409             switch (aa->name[j]) {
1410                case 'c': srcMode          = SM_F2O; break;
1411                case 'd': opMode           = OM_UNZ; break;
1412                case 'z': opMode           = OM_Z; break;
1413                case 'f': forceOverwrite   = True; break;
1414                case 't': opMode           = OM_TEST; break;
1415                case 'k': keepInputFiles   = True; break;
1416                case 's': smallMode        = True; break;
1417                case '1': blockSize100k    = 1; break;
1418                case '2': blockSize100k    = 2; break;
1419                case '3': blockSize100k    = 3; break;
1420                case '4': blockSize100k    = 4; break;
1421                case '5': blockSize100k    = 5; break;
1422                case '6': blockSize100k    = 6; break;
1423                case '7': blockSize100k    = 7; break;
1424                case '8': blockSize100k    = 8; break;
1425                case '9': blockSize100k    = 9; break;
1426                case 'V':
1427                case 'L': license();            break;
1428                case 'v': verbosity++; break;
1429                case 'h': usage ( progName );
1430                          exit ( 1 );
1431                          break;
1432                default:  fprintf ( stderr, "%s: Bad flag `%s'\n",
1433                                    progName, aa->name );
1434                          usage ( progName );
1435                          exit ( 1 );
1436                          break;
1437          }
1438 
1439    /*-- And again ... --*/
1440    for (aa = argList; aa != NULL; aa = aa->link) {
1441       if (ISFLAG("--stdout"))            srcMode          = SM_F2O;  else
1442       if (ISFLAG("--decompress"))        opMode           = OM_UNZ;  else
1443       if (ISFLAG("--compress"))          opMode           = OM_Z;    else
1444       if (ISFLAG("--force"))             forceOverwrite   = True;    else
1445       if (ISFLAG("--test"))              opMode           = OM_TEST; else
1446       if (ISFLAG("--keep"))              keepInputFiles   = True;    else
1447       if (ISFLAG("--small"))             smallMode        = True;    else
1448       if (ISFLAG("--version"))           license();                  else
1449       if (ISFLAG("--license"))           license();                  else
1450       if (ISFLAG("--repetitive-fast"))   workFactor = 5;             else
1451       if (ISFLAG("--repetitive-best"))   workFactor = 150;           else
1452       if (ISFLAG("--verbose"))           verbosity++;                else
1453       if (ISFLAG("--help"))              { usage ( progName ); exit ( 1 ); }
1454          else
1455          if (strncmp ( aa->name, "--", 2) == 0) {
1456             fprintf ( stderr, "%s: Bad flag `%s'\n", progName, aa->name );
1457             usage ( progName );
1458             exit ( 1 );
1459          }
1460    }
1461 
1462    if (verbosity > 4) verbosity = 4;
1463    if (opMode == OM_Z && smallMode) blockSize100k = 2;
1464 
1465    if (srcMode == SM_F2O && numFileNames == 0) {
1466       fprintf ( stderr, "%s: -c expects at least one filename.\n",
1467                 progName );
1468       exit ( 1 );
1469    }
1470 
1471    if (opMode == OM_TEST && srcMode == SM_F2O) {
1472       fprintf ( stderr, "%s: -c and -t cannot be used together.\n",
1473                 progName );
1474       exit ( 1 );
1475    }
1476 
1477    if (opMode != OM_Z) blockSize100k = 0;
1478 
1479    if (opMode == OM_Z) {
1480       if (srcMode == SM_I2O)
1481          compress ( NULL );
1482          else
1483          for (aa = argList; aa != NULL; aa = aa->link)
1484             if (aa->name[0] != '-') {
1485                numFilesProcessed++;
1486                compress ( aa->name );
1487             }
1488    } else
1489    if (opMode == OM_UNZ) {
1490       if (srcMode == SM_I2O)
1491          uncompress ( NULL );
1492          else
1493          for (aa = argList; aa != NULL; aa = aa->link)
1494             if (aa->name[0] != '-') {
1495                numFilesProcessed++;
1496                uncompress ( aa->name );
1497             }
1498    } else {
1499       testFailsExist = False;
1500       if (srcMode == SM_I2O)
1501          testf ( NULL );
1502          else
1503          for (aa = argList; aa != NULL; aa = aa->link)
1504             if (aa->name[0] != '-') {
1505                numFilesProcessed++;
1506                testf ( aa->name );
1507             }
1508       if (testFailsExist) {
1509          fprintf ( stderr,
1510            "\n"
1511            "You can use the `bzip2recover' program to *attempt* to recover\n"
1512            "data from undamaged sections of corrupted files.\n\n"
1513          );
1514          exit(2);
1515       }
1516    }
1517    return 0;
1518 }
1519 
1520 
1521 /*-----------------------------------------------------------*/
1522 /*--- end                                         bzip2.c ---*/
1523 /*-----------------------------------------------------------*/
1524