Main Page   Class Hierarchy   Compound List   File List   Compound Members   File Members  

bzip2.c

Go to the documentation of this file.
00001 
00002 /*-----------------------------------------------------------*/
00003 /*--- A block-sorting, lossless compressor        bzip2.c ---*/
00004 /*-----------------------------------------------------------*/
00005 
00006 /*--
00007   This file is a part of bzip2 and/or libbzip2, a program and
00008   library for lossless, block-sorting data compression.
00009 
00010   Copyright (C) 1996-1999 Julian R Seward.  All rights reserved.
00011 
00012   Redistribution and use in source and binary forms, with or without
00013   modification, are permitted provided that the following conditions
00014   are met:
00015 
00016   1. Redistributions of source code must retain the above copyright
00017      notice, this list of conditions and the following disclaimer.
00018 
00019   2. The origin of this software must not be misrepresented; you must 
00020      not claim that you wrote the original software.  If you use this 
00021      software in a product, an acknowledgment in the product 
00022      documentation would be appreciated but is not required.
00023 
00024   3. Altered source versions must be plainly marked as such, and must
00025      not be misrepresented as being the original software.
00026 
00027   4. The name of the author may not be used to endorse or promote 
00028      products derived from this software without specific prior written 
00029      permission.
00030 
00031   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
00032   OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00033   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00034   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
00035   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00036   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00037   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00038   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
00039   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00040   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00041   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00042 
00043   Julian Seward, Cambridge, UK.
00044   jseward@acm.org
00045   bzip2/libbzip2 version 0.9.5 of 24 May 1999
00046 
00047   This program is based on (at least) the work of:
00048      Mike Burrows
00049      David Wheeler
00050      Peter Fenwick
00051      Alistair Moffat
00052      Radford Neal
00053      Ian H. Witten
00054      Robert Sedgewick
00055      Jon L. Bentley
00056 
00057   For more information on these sources, see the manual.
00058 --*/
00059 
00060 
00061 /*----------------------------------------------------*/
00062 /*--- IMPORTANT                                    ---*/
00063 /*----------------------------------------------------*/
00064 
00065 /*--
00066    WARNING:
00067       This program and library (attempts to) compress data by 
00068       performing several non-trivial transformations on it.  
00069       Unless you are 100% familiar with *all* the algorithms 
00070       contained herein, and with the consequences of modifying them, 
00071       you should NOT meddle with the compression or decompression 
00072       machinery.  Incorrect changes can and very likely *will* 
00073       lead to disasterous loss of data.
00074 
00075    DISCLAIMER:
00076       I TAKE NO RESPONSIBILITY FOR ANY LOSS OF DATA ARISING FROM THE
00077       USE OF THIS PROGRAM, HOWSOEVER CAUSED.
00078 
00079       Every compression of a file implies an assumption that the
00080       compressed file can be decompressed to reproduce the original.
00081       Great efforts in design, coding and testing have been made to
00082       ensure that this program works correctly.  However, the
00083       complexity of the algorithms, and, in particular, the presence
00084       of various special cases in the code which occur with very low
00085       but non-zero probability make it impossible to rule out the
00086       possibility of bugs remaining in the program.  DO NOT COMPRESS
00087       ANY DATA WITH THIS PROGRAM AND/OR LIBRARY UNLESS YOU ARE PREPARED 
00088       TO ACCEPT THE POSSIBILITY, HOWEVER SMALL, THAT THE DATA WILL 
00089       NOT BE RECOVERABLE.
00090 
00091       That is not to say this program is inherently unreliable.
00092       Indeed, I very much hope the opposite is true.  bzip2/libbzip2
00093       has been carefully constructed and extensively tested.
00094 
00095    PATENTS:
00096       To the best of my knowledge, bzip2/libbzip2 does not use any 
00097       patented algorithms.  However, I do not have the resources 
00098       available to carry out a full patent search.  Therefore I cannot 
00099       give any guarantee of the above statement.
00100 --*/
00101 
00102 
00103 
00104 /*----------------------------------------------------*/
00105 /*--- and now for something much more pleasant :-) ---*/
00106 /*----------------------------------------------------*/
00107 
00108 /*---------------------------------------------*/
00109 /*--
00110   Place a 1 beside your platform, and 0 elsewhere.
00111 --*/
00112 
00113 /*--
00114   Generic 32-bit Unix.
00115   Also works on 64-bit Unix boxes.
00116 --*/
00117 #define BZ_UNIX      1
00118 
00119 /*--
00120   Win32, as seen by Jacob Navia's excellent
00121   port of (Chris Fraser & David Hanson)'s excellent
00122   lcc compiler.
00123 --*/
00124 #define BZ_LCCWIN32  0
00125 
00126 #if defined(_WIN32) && !defined(__CYGWIN32__)
00127 #undef BZ_LCCWIN32
00128 #define BZ_LCCWIN32 1
00129 #undef BZ_UNIX
00130 #define BZ_UNIX 0
00131 #endif
00132 
00133 
00134 /*---------------------------------------------*/
00135 /*--
00136   Some stuff for all platforms.
00137 --*/
00138 
00139 #include <stdio.h>
00140 #include <stdlib.h>
00141 #include <string.h>
00142 #include <time.h>
00143 #include <signal.h>
00144 #include <math.h>
00145 #include <errno.h>
00146 #include <ctype.h>
00147 #include "bzlib.h"
00148 
00149 #define ERROR_IF_EOF(i)       { if ((i) == EOF)  ioError(); }
00150 #define ERROR_IF_NOT_ZERO(i)  { if ((i) != 0)    ioError(); }
00151 #define ERROR_IF_MINUS_ONE(i) { if ((i) == (-1)) ioError(); }
00152 
00153 
00154 /*---------------------------------------------*/
00155 /*--
00156    Platform-specific stuff.
00157 --*/
00158 
00159 #if BZ_UNIX
00160 #   include <sys/types.h>
00161 #   include <utime.h>
00162 #   include <unistd.h>
00163 #   include <sys/stat.h>
00164 #   include <sys/times.h>
00165 
00166 #   define PATH_SEP    '/'
00167 #   define MY_LSTAT    lstat
00168 #   define MY_S_IFREG  S_ISREG
00169 #   define MY_STAT     stat
00170 
00171 #   define APPEND_FILESPEC(root, name) \
00172       root=snocString((root), (name))
00173 
00174 #   define APPEND_FLAG(root, name) \
00175       root=snocString((root), (name))
00176 
00177 #   define SET_BINARY_MODE(fd) /**/
00178 
00179 #   ifdef __GNUC__
00180 #      define NORETURN __attribute__ ((noreturn))
00181 #   else
00182 #      define NORETURN /**/
00183 #   endif
00184 #   ifdef __DJGPP__
00185 #     include <io.h>
00186 #     include <fcntl.h>
00187 #     undef MY_LSTAT
00188 #     define MY_LSTAT stat
00189 #     undef SET_BINARY_MODE
00190 #     define SET_BINARY_MODE(fd)                        \
00191         do {                                            \
00192            int retVal = setmode ( fileno ( fd ),        \
00193                                  O_BINARY );            \
00194            ERROR_IF_MINUS_ONE ( retVal );               \
00195         } while ( 0 )
00196 #   endif
00197 #endif
00198 
00199 
00200 
00201 #if BZ_LCCWIN32
00202 #   include <io.h>
00203 #   include <fcntl.h>
00204 #   include <sys\stat.h>
00205 
00206 #   define NORETURN       /**/
00207 #   define PATH_SEP       '\\'
00208 #   define MY_LSTAT       _stat
00209 #   define MY_STAT        _stat
00210 #   define MY_S_IFREG(x)  ((x) & _S_IFREG)
00211 
00212 #   define APPEND_FLAG(root, name) \
00213       root=snocString((root), (name))
00214 
00215 #   if 0
00216    /*-- lcc-win32 seems to expand wildcards itself --*/
00217 #   define APPEND_FILESPEC(root, spec)                \
00218       do {                                            \
00219          if ((spec)[0] == '-') {                      \
00220             root = snocString((root), (spec));        \
00221          } else {                                     \
00222             struct _finddata_t c_file;                \
00223             long hFile;                               \
00224             hFile = _findfirst((spec), &c_file);      \
00225             if ( hFile == -1L ) {                     \
00226                root = snocString ((root), (spec));    \
00227             } else {                                  \
00228                int anInt = 0;                         \
00229                while ( anInt == 0 ) {                 \
00230                   root = snocString((root),           \
00231                             &c_file.name[0]);         \
00232                   anInt = _findnext(hFile, &c_file);  \
00233                }                                      \
00234             }                                         \
00235          }                                            \
00236       } while ( 0 )
00237 #   else
00238 #   define APPEND_FILESPEC(root, name)                \
00239       root = snocString ((root), (name))
00240 #   endif
00241 
00242 #   define SET_BINARY_MODE(fd)                        \
00243       do {                                            \
00244          int retVal = setmode ( fileno ( fd ),        \
00245                                O_BINARY );            \
00246          ERROR_IF_MINUS_ONE ( retVal );               \
00247       } while ( 0 )
00248 
00249 #endif
00250 
00251 
00252 /*---------------------------------------------*/
00253 /*--
00254   Some more stuff for all platforms :-)
00255 --*/
00256 
00257 typedef char            Char;
00258 typedef unsigned char   Bool;
00259 typedef unsigned char   UChar;
00260 typedef int             Int32;
00261 typedef unsigned int    UInt32;
00262 typedef short           Int16;
00263 typedef unsigned short  UInt16;
00264                                        
00265 #define True  ((Bool)1)
00266 #define False ((Bool)0)
00267 
00268 /*--
00269   IntNative is your platform's `native' int size.
00270   Only here to avoid probs with 64-bit platforms.
00271 --*/
00272 typedef int IntNative;
00273 
00274 
00275 /*---------------------------------------------------*/
00276 /*--- Misc (file handling) data decls             ---*/
00277 /*---------------------------------------------------*/
00278 
00279 Int32   verbosity;
00280 Bool    keepInputFiles, smallMode;
00281 Bool    forceOverwrite, testFailsExist, noisy;
00282 Int32   numFileNames, numFilesProcessed, blockSize100k;
00283 
00284 
00285 /*-- source modes; F==file, I==stdin, O==stdout --*/
00286 #define SM_I2O           1
00287 #define SM_F2O           2
00288 #define SM_F2F           3
00289 
00290 /*-- operation modes --*/
00291 #define OM_Z             1
00292 #define OM_UNZ           2
00293 #define OM_TEST          3
00294 
00295 Int32   opMode;
00296 Int32   srcMode;
00297 
00298 #define FILE_NAME_LEN 1034
00299 
00300 Int32   longestFileName;
00301 Char    inName [FILE_NAME_LEN];
00302 Char    outName[FILE_NAME_LEN];
00303 Char    tmpName[FILE_NAME_LEN];
00304 Char    *progName;
00305 Char    progNameReally[FILE_NAME_LEN];
00306 FILE    *outputHandleJustInCase;
00307 Int32   workFactor;
00308 
00309 void    panic                 ( Char* )   NORETURN;
00310 void    ioError               ( void )    NORETURN;
00311 void    outOfMemory           ( void )    NORETURN;
00312 void    blockOverrun          ( void )    NORETURN;
00313 void    badBlockHeader        ( void )    NORETURN;
00314 void    badBGLengths          ( void )    NORETURN;
00315 void    crcError              ( void )    NORETURN;
00316 void    bitStreamEOF          ( void )    NORETURN;
00317 void    cleanUpAndFail        ( Int32 )   NORETURN;
00318 void    compressedStreamEOF   ( void )    NORETURN;
00319 
00320 void    copyFileName ( Char*, Char* );
00321 void*   myMalloc ( Int32 );
00322 
00323 
00324 
00325 /*---------------------------------------------------*/
00326 /*--- Processing of complete files and streams    ---*/
00327 /*---------------------------------------------------*/
00328 
00329 /*---------------------------------------------*/
00330 Bool myfeof ( FILE* f )
00331 {
00332    Int32 c = fgetc ( f );
00333    if (c == EOF) return True;
00334    ungetc ( c, f );
00335    return False;
00336 }
00337 
00338 
00339 /*---------------------------------------------*/
00340 void compressStream ( FILE *stream, FILE *zStream )
00341 {
00342    BZFILE* bzf = NULL;
00343    UChar   ibuf[5000];
00344    Int32   nIbuf;
00345    UInt32  nbytes_in, nbytes_out;
00346    Int32   bzerr, bzerr_dummy, ret;
00347 
00348    SET_BINARY_MODE(stream);
00349    SET_BINARY_MODE(zStream);
00350 
00351    if (ferror(stream)) goto errhandler_io;
00352    if (ferror(zStream)) goto errhandler_io;
00353 
00354    bzf = bzWriteOpen ( &bzerr, zStream, 
00355                        blockSize100k, verbosity, workFactor );   
00356    if (bzerr != BZ_OK) goto errhandler;
00357 
00358    if (verbosity >= 2) fprintf ( stderr, "\n" );
00359 
00360    while (True) {
00361 
00362       if (myfeof(stream)) break;
00363       nIbuf = fread ( ibuf, sizeof(UChar), 5000, stream );
00364       if (ferror(stream)) goto errhandler_io;
00365       if (nIbuf > 0) bzWrite ( &bzerr, bzf, (void*)ibuf, nIbuf );
00366       if (bzerr != BZ_OK) goto errhandler;
00367 
00368    }
00369 
00370    bzWriteClose ( &bzerr, bzf, 0, &nbytes_in, &nbytes_out );
00371    if (bzerr != BZ_OK) goto errhandler;
00372 
00373    if (ferror(zStream)) goto errhandler_io;
00374    ret = fflush ( zStream );
00375    if (ret == EOF) goto errhandler_io;
00376    if (zStream != stdout) {
00377       ret = fclose ( zStream );
00378       if (ret == EOF) goto errhandler_io;
00379    }
00380    if (ferror(stream)) goto errhandler_io;
00381    ret = fclose ( stream );
00382    if (ret == EOF) goto errhandler_io;
00383 
00384    if (nbytes_in == 0) nbytes_in = 1;
00385 
00386    if (verbosity >= 1)
00387       fprintf ( stderr, "%6.3f:1, %6.3f bits/byte, "
00388                         "%5.2f%% saved, %d in, %d out.\n",
00389                 (float)nbytes_in / (float)nbytes_out,
00390                 (8.0 * (float)nbytes_out) / (float)nbytes_in,
00391                 100.0 * (1.0 - (float)nbytes_out / (float)nbytes_in),
00392                 nbytes_in,
00393                 nbytes_out
00394               );
00395 
00396    return;
00397 
00398    errhandler:
00399    bzWriteClose ( &bzerr_dummy, bzf, 1, &nbytes_in, &nbytes_out );
00400    switch (bzerr) {
00401       case BZ_MEM_ERROR:
00402          outOfMemory ();
00403       case BZ_IO_ERROR:
00404          errhandler_io:
00405          ioError(); break;
00406       default:
00407          panic ( "compress:unexpected error" );
00408    }
00409 
00410    panic ( "compress:end" );
00411    /*notreached*/
00412 }
00413 
00414 
00415 
00416 /*---------------------------------------------*/
00417 Bool uncompressStream ( FILE *zStream, FILE *stream )
00418 {
00419    BZFILE* bzf = NULL;
00420    Int32   bzerr, bzerr_dummy, ret, nread, streamNo, i;
00421    UChar   obuf[5000];
00422    UChar   unused[BZ_MAX_UNUSED];
00423    Int32   nUnused;
00424    UChar*  unusedTmp;
00425 
00426    nUnused = 0;
00427    streamNo = 0;
00428 
00429    SET_BINARY_MODE(stream);
00430    SET_BINARY_MODE(zStream);
00431 
00432    if (ferror(stream)) goto errhandler_io;
00433    if (ferror(zStream)) goto errhandler_io;
00434 
00435    while (True) {
00436 
00437       bzf = bzReadOpen ( 
00438                &bzerr, zStream, verbosity, 
00439                (int)smallMode, unused, nUnused
00440             );
00441       if (bzf == NULL || bzerr != BZ_OK) goto errhandler;
00442       streamNo++;
00443 
00444       while (bzerr == BZ_OK) {
00445          nread = bzRead ( &bzerr, bzf, obuf, 5000 );
00446          if (bzerr == BZ_DATA_ERROR_MAGIC) goto errhandler;
00447          if ((bzerr == BZ_OK || bzerr == BZ_STREAM_END) && nread > 0)
00448             fwrite ( obuf, sizeof(UChar), nread, stream );
00449          if (ferror(stream)) goto errhandler_io;
00450       }
00451       if (bzerr != BZ_STREAM_END) goto errhandler;
00452 
00453       bzReadGetUnused ( &bzerr, bzf, (void**)(&unusedTmp), &nUnused );
00454       if (bzerr != BZ_OK) panic ( "decompress:bzReadGetUnused" );
00455 
00456       for (i = 0; i < nUnused; i++) unused[i] = unusedTmp[i];
00457 
00458       bzReadClose ( &bzerr, bzf );
00459       if (bzerr != BZ_OK) panic ( "decompress:bzReadGetUnused" );
00460 
00461       if (nUnused == 0 && myfeof(zStream)) break;
00462 
00463    }
00464 
00465    if (ferror(zStream)) goto errhandler_io;
00466    ret = fclose ( zStream );
00467    if (ret == EOF) goto errhandler_io;
00468 
00469    if (ferror(stream)) goto errhandler_io;
00470    ret = fflush ( stream );
00471    if (ret != 0) goto errhandler_io;
00472    if (stream != stdout) {
00473       ret = fclose ( stream );
00474       if (ret == EOF) goto errhandler_io;
00475    }
00476    if (verbosity >= 2) fprintf ( stderr, "\n    " );
00477    return True;
00478 
00479    errhandler:
00480    bzReadClose ( &bzerr_dummy, bzf );
00481    switch (bzerr) {
00482       case BZ_IO_ERROR:
00483          errhandler_io:
00484          ioError(); break;
00485       case BZ_DATA_ERROR:
00486          crcError();
00487       case BZ_MEM_ERROR:
00488          outOfMemory();
00489       case BZ_UNEXPECTED_EOF:
00490          compressedStreamEOF();
00491       case BZ_DATA_ERROR_MAGIC:
00492          if (streamNo == 1) {
00493             return False;
00494          } else {
00495             if (noisy)
00496             fprintf ( stderr, 
00497                       "\n%s: %s: trailing garbage after EOF ignored\n",
00498                       progName, inName );
00499             return True;       
00500          }
00501       default:
00502          panic ( "decompress:unexpected error" );
00503    }
00504 
00505    panic ( "decompress:end" );
00506    return True; /*notreached*/
00507 }
00508 
00509 
00510 /*---------------------------------------------*/
00511 Bool testStream ( FILE *zStream )
00512 {
00513    BZFILE* bzf = NULL;
00514    Int32   bzerr, bzerr_dummy, ret, nread, streamNo, i;
00515    UChar   obuf[5000];
00516    UChar   unused[BZ_MAX_UNUSED];
00517    Int32   nUnused;
00518    UChar*  unusedTmp;
00519 
00520    nUnused = 0;
00521    streamNo = 0;
00522 
00523    SET_BINARY_MODE(zStream);
00524    if (ferror(zStream)) goto errhandler_io;
00525 
00526    while (True) {
00527 
00528       bzf = bzReadOpen ( 
00529                &bzerr, zStream, verbosity, 
00530                (int)smallMode, unused, nUnused
00531             );
00532       if (bzf == NULL || bzerr != BZ_OK) goto errhandler;
00533       streamNo++;
00534 
00535       while (bzerr == BZ_OK) {
00536          nread = bzRead ( &bzerr, bzf, obuf, 5000 );
00537          if (bzerr == BZ_DATA_ERROR_MAGIC) goto errhandler;
00538       }
00539       if (bzerr != BZ_STREAM_END) goto errhandler;
00540 
00541       bzReadGetUnused ( &bzerr, bzf, (void**)(&unusedTmp), &nUnused );
00542       if (bzerr != BZ_OK) panic ( "test:bzReadGetUnused" );
00543 
00544       for (i = 0; i < nUnused; i++) unused[i] = unusedTmp[i];
00545 
00546       bzReadClose ( &bzerr, bzf );
00547       if (bzerr != BZ_OK) panic ( "test:bzReadGetUnused" );
00548       if (nUnused == 0 && myfeof(zStream)) break;
00549 
00550    }
00551 
00552    if (ferror(zStream)) goto errhandler_io;
00553    ret = fclose ( zStream );
00554    if (ret == EOF) goto errhandler_io;
00555 
00556    if (verbosity >= 2) fprintf ( stderr, "\n    " );
00557    return True;
00558 
00559    errhandler:
00560    bzReadClose ( &bzerr_dummy, bzf );
00561    if (verbosity == 0) 
00562       fprintf ( stderr, "%s: %s: ", progName, inName );
00563    switch (bzerr) {
00564       case BZ_IO_ERROR:
00565          errhandler_io:
00566          ioError(); break;
00567       case BZ_DATA_ERROR:
00568          fprintf ( stderr,
00569                    "data integrity (CRC) error in data\n" );
00570          return False;
00571       case BZ_MEM_ERROR:
00572          outOfMemory();
00573       case BZ_UNEXPECTED_EOF:
00574          fprintf ( stderr,
00575                    "file ends unexpectedly\n" );
00576          return False;
00577       case BZ_DATA_ERROR_MAGIC:
00578          if (streamNo == 1) {
00579           fprintf ( stderr, 
00580                     "bad magic number (file not created by bzip2)\n" );
00581             return False;
00582          } else {
00583             if (noisy)
00584             fprintf ( stderr, 
00585                       "trailing garbage after EOF ignored\n" );
00586             return True;       
00587          }
00588       default:
00589          panic ( "test:unexpected error" );
00590    }
00591 
00592    panic ( "test:end" );
00593    return True; /*notreached*/
00594 }
00595 
00596 
00597 /*---------------------------------------------------*/
00598 /*--- Error [non-] handling grunge                ---*/
00599 /*---------------------------------------------------*/
00600 
00601 /*---------------------------------------------*/
00602 void cadvise ( void )
00603 {
00604    if (noisy)
00605    fprintf (
00606       stderr,
00607       "\nIt is possible that the compressed file(s) have become corrupted.\n"
00608         "You can use the -tvv option to test integrity of such files.\n\n"
00609         "You can use the `bzip2recover' program to *attempt* to recover\n"
00610         "data from undamaged sections of corrupted files.\n\n"
00611     );
00612 }
00613 
00614 
00615 /*---------------------------------------------*/
00616 void showFileNames ( void )
00617 {
00618    if (noisy)
00619    fprintf (
00620       stderr,
00621       "\tInput file = %s, output file = %s\n",
00622       inName, outName 
00623    );
00624 }
00625 
00626 
00627 /*---------------------------------------------*/
00628 void cleanUpAndFail ( Int32 ec )
00629 {
00630    IntNative retVal;
00631 
00632    if ( srcMode == SM_F2F && opMode != OM_TEST ) {
00633       if (noisy)
00634       fprintf ( stderr, "%s: Deleting output file %s, if it exists.\n",
00635                 progName, outName );
00636       if (outputHandleJustInCase != NULL)
00637          fclose ( outputHandleJustInCase );
00638       retVal = remove ( outName );
00639       if (retVal != 0)
00640          fprintf ( stderr,
00641                    "%s: WARNING: deletion of output file (apparently) failed.\n",
00642                    progName );
00643    }
00644    if (noisy && numFileNames > 0 && numFilesProcessed < numFileNames) {
00645       fprintf ( stderr, 
00646                 "%s: WARNING: some files have not been processed:\n"
00647                 "\t%d specified on command line, %d not processed yet.\n\n",
00648                 progName, numFileNames, 
00649                           numFileNames - numFilesProcessed );
00650    }
00651    exit ( ec );
00652 }
00653 
00654 
00655 /*---------------------------------------------*/
00656 void panic ( Char* s )
00657 {
00658    fprintf ( stderr,
00659              "\n%s: PANIC -- internal consistency error:\n"
00660              "\t%s\n"
00661              "\tThis is a BUG.  Please report it to me at:\n"
00662              "\tjseward@acm.org\n",
00663              progName, s );
00664    showFileNames();
00665    cleanUpAndFail( 3 );
00666 }
00667 
00668 
00669 /*---------------------------------------------*/
00670 void crcError ( void )
00671 {
00672    fprintf ( stderr,
00673              "\n%s: Data integrity error when decompressing.\n",
00674              progName );
00675    showFileNames();
00676    cadvise();
00677    cleanUpAndFail( 2 );
00678 }
00679 
00680 
00681 /*---------------------------------------------*/
00682 void compressedStreamEOF ( void )
00683 {
00684    fprintf ( stderr,
00685              "\n%s: Compressed file ends unexpectedly;\n\t"
00686              "perhaps it is corrupted?  *Possible* reason follows.\n",
00687              progName );
00688    perror ( progName );
00689    showFileNames();
00690    cadvise();
00691    cleanUpAndFail( 2 );
00692 }
00693 
00694 
00695 /*---------------------------------------------*/
00696 void ioError ( void )
00697 {
00698    fprintf ( stderr,
00699              "\n%s: I/O or other error, bailing out.  Possible reason follows.\n",
00700              progName );
00701    perror ( progName );
00702    showFileNames();
00703    cleanUpAndFail( 1 );
00704 }
00705 
00706 
00707 /*---------------------------------------------*/
00708 #ifdef WIN32
00709 void __cdecl mySignalCatcher ( IntNative n )
00710 #else
00711 void mySignalCatcher ( IntNative n )
00712 #endif
00713 {
00714    fprintf ( stderr,
00715              "\n%s: Control-C or similar caught, quitting.\n",
00716              progName );
00717    cleanUpAndFail(1);
00718 }
00719 
00720 
00721 /*---------------------------------------------*/
00722 #ifdef WIN32
00723 void __cdecl mySIGSEGVorSIGBUScatcher ( IntNative n )
00724 #else
00725 void mySIGSEGVorSIGBUScatcher ( IntNative n )
00726 #endif
00727 {
00728    if (opMode == OM_Z)
00729       fprintf ( stderr,
00730                 "\n%s: Caught a SIGSEGV or SIGBUS whilst compressing,\n"
00731                 "\twhich probably indicates a bug in bzip2.  Please\n"
00732                 "\treport it to me at: jseward@acm.org\n",
00733                 progName );
00734       else
00735       fprintf ( stderr,
00736                 "\n%s: Caught a SIGSEGV or SIGBUS whilst decompressing,\n"
00737                 "\twhich probably indicates that the compressed data\n"
00738                 "\tis corrupted.\n",
00739                 progName );
00740 
00741    showFileNames();
00742    if (opMode == OM_Z)
00743       cleanUpAndFail( 3 ); else
00744       { cadvise(); cleanUpAndFail( 2 ); }
00745 }
00746 
00747 
00748 /*---------------------------------------------*/
00749 void outOfMemory ( void )
00750 {
00751    fprintf ( stderr,
00752              "\n%s: couldn't allocate enough memory\n",
00753              progName );
00754    showFileNames();
00755    cleanUpAndFail(1);
00756 }
00757 
00758 
00759 /*---------------------------------------------------*/
00760 /*--- The main driver machinery                   ---*/
00761 /*---------------------------------------------------*/
00762 
00763 /*---------------------------------------------*/
00764 void pad ( Char *s )
00765 {
00766    Int32 i;
00767    if ( (Int32)strlen(s) >= longestFileName ) return;
00768    for (i = 1; i <= longestFileName - (Int32)strlen(s); i++)
00769       fprintf ( stderr, " " );
00770 }
00771 
00772 
00773 /*---------------------------------------------*/
00774 void copyFileName ( Char* to, Char* from ) 
00775 {
00776    if ( strlen(from) > FILE_NAME_LEN-10 )  {
00777       fprintf (
00778          stderr,
00779          "bzip2: file name\n`%s'\n"
00780          "is suspiciously (more than %d chars) long.\n"
00781          "Try using a reasonable file name instead.  Sorry! :-)\n",
00782          from, FILE_NAME_LEN-10
00783       );
00784       exit(1);
00785    }
00786 
00787   strncpy(to,from,FILE_NAME_LEN-10);
00788   to[FILE_NAME_LEN-10]='\0';
00789 }
00790 
00791 
00792 /*---------------------------------------------*/
00793 Bool fileExists ( Char* name )
00794 {
00795    FILE *tmp   = fopen ( name, "rb" );
00796    Bool exists = (tmp != NULL);
00797    if (tmp != NULL) fclose ( tmp );
00798    return exists;
00799 }
00800 
00801 
00802 /*---------------------------------------------*/
00803 /*--
00804   if in doubt, return True
00805 --*/
00806 Bool notAStandardFile ( Char* name )
00807 {
00808    IntNative      i;
00809    struct MY_STAT statBuf;
00810 
00811    i = MY_LSTAT ( name, &statBuf );
00812    if (i != 0) return True;
00813    if (MY_S_IFREG(statBuf.st_mode)) return False;
00814    return True;
00815 }
00816 
00817 
00818 /*---------------------------------------------*/
00819 /*--
00820   rac 11/21/98 see if file has hard links to it
00821 --*/
00822 Int32 countHardLinks ( Char* name )
00823 {  
00824    IntNative      i;
00825    struct MY_STAT statBuf;
00826 
00827    i = MY_LSTAT ( name, &statBuf );
00828    if (i != 0) return 0;
00829    return (statBuf.st_nlink - 1);
00830 }
00831 
00832 
00833 /*---------------------------------------------*/
00834 void copyDatePermissionsAndOwner ( Char *srcName, Char *dstName )
00835 {
00836 #if BZ_UNIX
00837    IntNative      retVal;
00838    struct MY_STAT statBuf;
00839    struct utimbuf uTimBuf;
00840 
00841    retVal = MY_LSTAT ( srcName, &statBuf );
00842    ERROR_IF_NOT_ZERO ( retVal );
00843    uTimBuf.actime = statBuf.st_atime;
00844    uTimBuf.modtime = statBuf.st_mtime;
00845 
00846    retVal = chmod ( dstName, statBuf.st_mode );
00847    ERROR_IF_NOT_ZERO ( retVal );
00848 
00849    retVal = utime ( dstName, &uTimBuf );
00850    ERROR_IF_NOT_ZERO ( retVal );
00851 
00852    retVal = chown ( dstName, statBuf.st_uid, statBuf.st_gid );
00853    /* chown() will in many cases return with EPERM, which can
00854       be safely ignored.
00855    */
00856 #endif
00857 }
00858 
00859 
00860 /*---------------------------------------------*/
00861 void setInterimPermissions ( Char *dstName )
00862 {
00863 #if BZ_UNIX
00864    IntNative      retVal;
00865    retVal = chmod ( dstName, S_IRUSR | S_IWUSR );
00866    ERROR_IF_NOT_ZERO ( retVal );
00867 #endif
00868 }
00869 
00870 
00871 /*---------------------------------------------*/
00872 Bool containsDubiousChars ( Char* name )
00873 {
00874    Bool cdc = False;
00875    for (; *name != '\0'; name++)
00876       if (*name == '?' || *name == '*') cdc = True;
00877    return cdc;
00878 }
00879 
00880 
00881 /*---------------------------------------------*/
00882 #define BZ_N_SUFFIX_PAIRS 4
00883 
00884 Char* zSuffix[BZ_N_SUFFIX_PAIRS] 
00885    = { ".bz2", ".bz", ".tbz2", ".tbz" };
00886 Char* unzSuffix[BZ_N_SUFFIX_PAIRS] 
00887    = { "", "", ".tar", ".tar" };
00888 
00889 Bool hasSuffix ( Char* s, Char* suffix )
00890 {
00891    Int32 ns = strlen(s);
00892    Int32 nx = strlen(suffix);
00893    if (ns < nx) return False;
00894    if (strcmp(s + ns - nx, suffix) == 0) return True;
00895    return False;
00896 }
00897 
00898 Bool mapSuffix ( Char* name, 
00899                  Char* oldSuffix, Char* newSuffix )
00900 {
00901    if (!hasSuffix(name,oldSuffix)) return False;
00902    name[strlen(name)-strlen(oldSuffix)] = 0;
00903    strcat ( name, newSuffix );
00904    return True;
00905 }
00906 
00907 
00908 /*---------------------------------------------*/
00909 void compress ( Char *name )
00910 {
00911    FILE  *inStr;
00912    FILE  *outStr;
00913    Int32 n, i;
00914    if (name == NULL && srcMode != SM_I2O)
00915       panic ( "compress: bad modes\n" );
00916 
00917    switch (srcMode) {
00918       case SM_I2O: 
00919          copyFileName ( inName, "(stdin)" );
00920          copyFileName ( outName, "(stdout)" ); 
00921          break;
00922       case SM_F2F: 
00923          copyFileName ( inName, name );
00924          copyFileName ( outName, name );
00925          strcat ( outName, ".bz2" ); 
00926          break;
00927       case SM_F2O: 
00928          copyFileName ( inName, name );
00929          copyFileName ( outName, "(stdout)" ); 
00930          break;
00931    }
00932 
00933    if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
00934       if (noisy)
00935       fprintf ( stderr, "%s: There are no files matching `%s'.\n",
00936       progName, inName );
00937       return;
00938    }
00939    if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
00940       fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
00941                 progName, inName, strerror(errno) );
00942       return;
00943    }
00944    for (i = 0; i < BZ_N_SUFFIX_PAIRS; i++) {
00945       if (hasSuffix(inName, zSuffix[i])) {
00946          if (noisy)
00947          fprintf ( stderr, 
00948                    "%s: Input file %s already has %s suffix.\n",
00949                    progName, inName, zSuffix[i] );
00950          return;
00951       }
00952    }
00953    if ( srcMode == SM_F2F && !forceOverwrite && notAStandardFile ( inName )) {
00954       if (noisy)
00955       fprintf ( stderr, "%s: Input file %s is not a normal file.\n",
00956                 progName, inName );
00957       return;
00958    }
00959    if ( srcMode == SM_F2F && !forceOverwrite && fileExists ( outName ) ) {
00960       fprintf ( stderr, "%s: Output file %s already exists.\n",
00961                 progName, outName );
00962       return;
00963    }
00964    if ( srcMode == SM_F2F && !forceOverwrite &&
00965         (n=countHardLinks ( inName )) > 0) {
00966       fprintf ( stderr, "%s: Input file %s has %d other link%s.\n",
00967                 progName, inName, n, n > 1 ? "s" : "" );
00968       return;
00969    }
00970 
00971    switch ( srcMode ) {
00972 
00973       case SM_I2O:
00974          inStr = stdin;
00975          outStr = stdout;
00976 /*
00977          if ( isatty ( fileno ( stdout ) ) ) {
00978             fprintf ( stderr,
00979                       "%s: I won't write compressed data to a terminal.\n",
00980                       progName );
00981             fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
00982                               progName, progName );
00983             return;
00984          };
00985 */
00986          break;
00987 
00988       case SM_F2O:
00989          inStr = fopen ( inName, "rb" );
00990          outStr = stdout;
00991 /*
00992          if ( isatty ( fileno ( stdout ) ) ) {
00993             fprintf ( stderr,
00994                       "%s: I won't write compressed data to a terminal.\n",
00995                       progName );
00996             fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
00997                               progName, progName );
00998             if ( inStr != NULL ) fclose ( inStr );
00999             return;
01000          };
01001 */
01002          if ( inStr == NULL ) {
01003             fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
01004                       progName, inName, strerror(errno) );
01005             return;
01006          };
01007          break;
01008 
01009       case SM_F2F:
01010          inStr = fopen ( inName, "rb" );
01011          outStr = fopen ( outName, "wb" );
01012          if ( outStr == NULL) {
01013             fprintf ( stderr, "%s: Can't create output file %s: %s.\n",
01014                       progName, outName, strerror(errno) );
01015             if ( inStr != NULL ) fclose ( inStr );
01016             return;
01017          }
01018          if ( inStr == NULL ) {
01019             fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
01020                       progName, inName, strerror(errno) );
01021             if ( outStr != NULL ) fclose ( outStr );
01022             return;
01023          };
01024          setInterimPermissions ( outName );
01025          break;
01026 
01027       default:
01028          panic ( "compress: bad srcMode" );
01029          break;
01030    }
01031 
01032    if (verbosity >= 1) {
01033       fprintf ( stderr,  "  %s: ", inName );
01034       pad ( inName );
01035       fflush ( stderr );
01036    }
01037 
01038    /*--- Now the input and output handles are sane.  Do the Biz. ---*/
01039    outputHandleJustInCase = outStr;
01040    compressStream ( inStr, outStr );
01041    outputHandleJustInCase = NULL;
01042 
01043    /*--- If there was an I/O error, we won't get here. ---*/
01044    if ( srcMode == SM_F2F ) {
01045       copyDatePermissionsAndOwner ( inName, outName );
01046       if ( !keepInputFiles ) {
01047          IntNative retVal = remove ( inName );
01048          ERROR_IF_NOT_ZERO ( retVal );
01049       }
01050    }
01051 }
01052 
01053 
01054 /*---------------------------------------------*/
01055 void uncompress ( Char *name )
01056 {
01057    FILE  *inStr;
01058    FILE  *outStr;
01059    Int32 n, i;
01060    Bool  magicNumberOK;
01061    Bool  cantGuess;
01062 
01063    if (name == NULL && srcMode != SM_I2O)
01064       panic ( "uncompress: bad modes\n" );
01065 
01066    cantGuess = False;
01067    switch (srcMode) {
01068       case SM_I2O: 
01069          copyFileName ( inName, "(stdin)" );
01070          copyFileName ( outName, "(stdout)" ); 
01071          break;
01072       case SM_F2F: 
01073          copyFileName ( inName, name );
01074          copyFileName ( outName, name );
01075          for (i = 0; i < BZ_N_SUFFIX_PAIRS; i++)
01076             if (mapSuffix(outName,zSuffix[i],unzSuffix[i]))
01077                goto zzz; 
01078          cantGuess = True;
01079          strcat ( outName, ".out" );
01080          break;
01081       case SM_F2O: 
01082          copyFileName ( inName, name );
01083          copyFileName ( outName, "(stdout)" ); 
01084          break;
01085    }
01086 
01087    zzz:
01088    if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
01089       if (noisy)
01090       fprintf ( stderr, "%s: There are no files matching `%s'.\n",
01091                 progName, inName );
01092       return;
01093    }
01094    if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
01095       fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
01096                 progName, inName, strerror(errno) );
01097       return;
01098    }
01099    if ( srcMode == SM_F2F && !forceOverwrite && notAStandardFile ( inName )) {
01100       if (noisy)
01101       fprintf ( stderr, "%s: Input file %s is not a normal file.\n",
01102                 progName, inName );
01103       return;
01104    }
01105    if ( /* srcMode == SM_F2F implied && */ cantGuess ) {
01106       if (noisy)
01107       fprintf ( stderr, 
01108                 "%s: Can't guess original name for %s -- using %s\n",
01109                 progName, inName, outName );
01110       /* just a warning, no return */
01111    }   
01112    if ( srcMode == SM_F2F && !forceOverwrite && fileExists ( outName ) ) {
01113       fprintf ( stderr, "%s: Output file %s already exists.\n",
01114                 progName, outName );
01115       return;
01116    }
01117    if ( srcMode == SM_F2F && !forceOverwrite &&
01118         (n=countHardLinks ( inName ) ) > 0) {
01119       fprintf ( stderr, "%s: Input file %s has %d other link%s.\n",
01120                 progName, inName, n, n > 1 ? "s" : "" );
01121       return;
01122    }
01123 
01124    switch ( srcMode ) {
01125 
01126       case SM_I2O:
01127          inStr = stdin;
01128          outStr = stdout;
01129          if ( isatty ( fileno ( stdin ) ) ) {
01130             fprintf ( stderr,
01131                       "%s: I won't read compressed data from a terminal.\n",
01132                       progName );
01133             fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
01134                               progName, progName );
01135             return;
01136          };
01137          break;
01138 
01139       case SM_F2O:
01140          inStr = fopen ( inName, "rb" );
01141          outStr = stdout;
01142          if ( inStr == NULL ) {
01143             fprintf ( stderr, "%s: Can't open input file %s:%s.\n",
01144                       progName, inName, strerror(errno) );
01145             if ( inStr != NULL ) fclose ( inStr );
01146             return;
01147          };
01148          break;
01149 
01150       case SM_F2F:
01151          inStr = fopen ( inName, "rb" );
01152          outStr = fopen ( outName, "wb" );
01153          if ( outStr == NULL) {
01154             fprintf ( stderr, "%s: Can't create output file %s: %s.\n",
01155                       progName, outName, strerror(errno) );
01156             if ( inStr != NULL ) fclose ( inStr );
01157             return;
01158          }
01159          if ( inStr == NULL ) {
01160             fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
01161                       progName, inName, strerror(errno) );
01162             if ( outStr != NULL ) fclose ( outStr );
01163             return;
01164          };
01165          setInterimPermissions ( outName );
01166          break;
01167 
01168       default:
01169          panic ( "uncompress: bad srcMode" );
01170          break;
01171    }
01172 
01173    if (verbosity >= 1) {
01174       fprintf ( stderr, "  %s: ", inName );
01175       pad ( inName );
01176       fflush ( stderr );
01177    }
01178 
01179    /*--- Now the input and output handles are sane.  Do the Biz. ---*/
01180    outputHandleJustInCase = outStr;
01181    magicNumberOK = uncompressStream ( inStr, outStr );
01182    outputHandleJustInCase = NULL;
01183 
01184    /*--- If there was an I/O error, we won't get here. ---*/
01185    if ( magicNumberOK ) {
01186       if ( srcMode == SM_F2F ) {
01187          copyDatePermissionsAndOwner ( inName, outName );
01188          if ( !keepInputFiles ) {
01189             IntNative retVal = remove ( inName );
01190             ERROR_IF_NOT_ZERO ( retVal );
01191          }
01192       }
01193    } else {
01194       if ( srcMode == SM_F2F ) {
01195          IntNative retVal = remove ( outName );
01196          ERROR_IF_NOT_ZERO ( retVal );
01197       }
01198    }
01199 
01200    if ( magicNumberOK ) {
01201       if (verbosity >= 1)
01202          fprintf ( stderr, "done\n" );
01203    } else {
01204       if (verbosity >= 1)
01205          fprintf ( stderr, "not a bzip2 file.\n" ); else
01206          fprintf ( stderr,
01207                    "%s: %s is not a bzip2 file.\n",
01208                    progName, inName );
01209    }
01210 
01211 }
01212 
01213 
01214 /*---------------------------------------------*/
01215 void testf ( Char *name )
01216 {
01217    FILE *inStr;
01218    Bool allOK;
01219 
01220    if (name == NULL && srcMode != SM_I2O)
01221       panic ( "testf: bad modes\n" );
01222 
01223    copyFileName ( outName, "(none)" );
01224    switch (srcMode) {
01225       case SM_I2O: copyFileName ( inName, "(stdin)" ); break;
01226       case SM_F2F: copyFileName ( inName, name ); break;
01227       case SM_F2O: copyFileName ( inName, name ); break;
01228    }
01229 
01230    if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
01231       if (noisy)
01232       fprintf ( stderr, "%s: There are no files matching `%s'.\n",
01233                 progName, inName );
01234       return;
01235    }
01236    if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
01237       fprintf ( stderr, "%s: Can't open input %s: %s.\n",
01238                 progName, inName, strerror(errno) );
01239       return;
01240    }
01241 
01242    switch ( srcMode ) {
01243 
01244       case SM_I2O:
01245          if ( isatty ( fileno ( stdin ) ) ) {
01246             fprintf ( stderr,
01247                       "%s: I won't read compressed data from a terminal.\n",
01248                       progName );
01249             fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
01250                               progName, progName );
01251             return;
01252          };
01253          inStr = stdin;
01254          break;
01255 
01256       case SM_F2O: case SM_F2F:
01257          inStr = fopen ( inName, "rb" );
01258          if ( inStr == NULL ) {
01259             fprintf ( stderr, "%s: Can't open input file %s:%s.\n",
01260                       progName, inName, strerror(errno) );
01261             return;
01262          };
01263          break;
01264 
01265       default:
01266          panic ( "testf: bad srcMode" );
01267          break;
01268    }
01269 
01270    if (verbosity >= 1) {
01271       fprintf ( stderr, "  %s: ", inName );
01272       pad ( inName );
01273       fflush ( stderr );
01274    }
01275 
01276    /*--- Now the input handle is sane.  Do the Biz. ---*/
01277    allOK = testStream ( inStr );
01278 
01279    if (allOK && verbosity >= 1) fprintf ( stderr, "ok\n" );
01280    if (!allOK) testFailsExist = True;
01281 }
01282 
01283 
01284 /*---------------------------------------------*/
01285 void license ( void )
01286 {
01287    fprintf ( stderr,
01288 
01289     "bzip2, a block-sorting file compressor.  "
01290     "Version 0.9.5c, 9-Aug-99.\n"
01291     "   \n"
01292     "   Copyright (C) 1996, 1997, 1998, 1999 by Julian Seward.\n"
01293     "   \n"
01294     "   This program is free software; you can redistribute it and/or modify\n"
01295     "   it under the terms set out in the LICENSE file, which is included\n"
01296     "   in the bzip2-0.9.5 source distribution.\n"
01297     "   \n"
01298     "   This program is distributed in the hope that it will be useful,\n"
01299     "   but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
01300     "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
01301     "   LICENSE file for more details.\n"
01302     "   \n"
01303    );
01304 }
01305 
01306 
01307 /*---------------------------------------------*/
01308 void usage ( Char *fullProgName )
01309 {
01310    fprintf (
01311       stderr,
01312       "bzip2, a block-sorting file compressor.  "
01313       "Version 0.9.5c, 9-Aug-99.\n"
01314       "\n   usage: %s [flags and input files in any order]\n"
01315       "\n"
01316       "   -h --help           print this message\n"
01317       "   -d --decompress     force decompression\n"
01318       "   -z --compress       force compression\n"
01319       "   -k --keep           keep (don't delete) input files\n"
01320       "   -f --force          overwrite existing output filess\n"
01321       "   -t --test           test compressed file integrity\n"
01322       "   -c --stdout         output to standard out\n"
01323       "   -q --quiet          suppress noncritical error messages\n"
01324       "   -v --verbose        be verbose (a 2nd -v gives more)\n"
01325       "   -L --license        display software version & license\n"
01326       "   -V --version        display software version & license\n"
01327       "   -s --small          use less memory (at most 2500k)\n"
01328       "   -1 .. -9            set block size to 100k .. 900k\n"
01329       "\n"
01330       "   If invoked as `bzip2', default action is to compress.\n"
01331       "              as `bunzip2',  default action is to decompress.\n"
01332       "              as `bzcat', default action is to decompress to stdout.\n"
01333       "\n"
01334       "   If no file names are given, bzip2 compresses or decompresses\n"
01335       "   from standard input to standard output.  You can combine\n"
01336       "   short flags, so `-v -4' means the same as -v4 or -4v, &c.\n"
01337 #if BZ_UNIX
01338       "\n"
01339 #endif
01340       ,
01341 
01342       fullProgName
01343    );
01344 }
01345 
01346 
01347 /*---------------------------------------------*/
01348 void redundant ( Char* flag )
01349 {
01350    fprintf ( 
01351       stderr, 
01352       "%s: %s is redundant in versions 0.9.5 and above\n",
01353       progName, flag );
01354 }
01355 
01356 
01357 /*---------------------------------------------*/
01358 /*--
01359   All the garbage from here to main() is purely to
01360   implement a linked list of command-line arguments,
01361   into which main() copies argv[1 .. argc-1].
01362 
01363   The purpose of this exercise is to facilitate 
01364   the expansion of wildcard characters * and ? in 
01365   filenames for OSs which don't know how to do it
01366   themselves, like MSDOS, Windows 95 and NT.
01367 
01368   The actual Dirty Work is done by the platform-
01369   specific macro APPEND_FILESPEC.
01370 --*/
01371 
01372 typedef
01373    struct zzzz {
01374       Char        *name;
01375       struct zzzz *link;
01376    }
01377    Cell;
01378 
01379 
01380 /*---------------------------------------------*/
01381 void *myMalloc ( Int32 n )
01382 {
01383    void* p;
01384 
01385    p = malloc ( (size_t)n );
01386    if (p == NULL) outOfMemory ();
01387    return p;
01388 }
01389 
01390 
01391 /*---------------------------------------------*/
01392 Cell *mkCell ( void )
01393 {
01394    Cell *c;
01395 
01396    c = (Cell*) myMalloc ( sizeof ( Cell ) );
01397    c->name = NULL;
01398    c->link = NULL;
01399    return c;
01400 }
01401 
01402 
01403 /*---------------------------------------------*/
01404 Cell *snocString ( Cell *root, Char *name )
01405 {
01406    if (root == NULL) {
01407       Cell *tmp = mkCell();
01408       tmp->name = (Char*) myMalloc ( 5 + strlen(name) );
01409       strcpy ( tmp->name, name );
01410       return tmp;
01411    } else {
01412       Cell *tmp = root;
01413       while (tmp->link != NULL) tmp = tmp->link;
01414       tmp->link = snocString ( tmp->link, name );
01415       return root;
01416    }
01417 }
01418 
01419 
01420 /*---------------------------------------------*/
01421 void addFlagsFromEnvVar ( Cell** argList, Char* varName ) 
01422 {
01423    Int32 i, j, k;
01424    Char *envbase, *p;
01425 
01426    envbase = getenv(varName);
01427    if (envbase != NULL) {
01428       p = envbase;
01429       i = 0;
01430       while (True) {
01431          if (p[i] == 0) break;
01432          p += i;
01433          i = 0;
01434          while (isspace((Int32)(p[0]))) p++;
01435          while (p[i] != 0 && !isspace((Int32)(p[i]))) i++;
01436          if (i > 0) {
01437             k = i; if (k > FILE_NAME_LEN-10) k = FILE_NAME_LEN-10;
01438             for (j = 0; j < k; j++) tmpName[j] = p[j];
01439             tmpName[k] = 0;
01440             APPEND_FLAG(*argList, tmpName);
01441          }
01442       }
01443    }
01444 }
01445 
01446 
01447 /*---------------------------------------------*/
01448 #define ISFLAG(s) (strcmp(aa->name, (s))==0)
01449 
01450 #ifdef WIN32
01451 IntNative __cdecl main ( IntNative argc, Char *argv[] )
01452 #else
01453 IntNative main ( IntNative argc, Char *argv[] )
01454 #endif
01455 {
01456    Int32  i, j;
01457    Char   *tmp;
01458    Cell   *argList;
01459    Cell   *aa;
01460    Bool   decode;
01461         clock_t c1,c2;
01462 
01463    /*-- Be really really really paranoid :-) --*/
01464    if (sizeof(Int32) != 4 || sizeof(UInt32) != 4  ||
01465        sizeof(Int16) != 2 || sizeof(UInt16) != 2  ||
01466        sizeof(Char)  != 1 || sizeof(UChar)  != 1) {
01467       fprintf ( stderr,
01468                 "bzip2: I'm not configured correctly for this platform!\n"
01469                 "\tI require Int32, Int16 and Char to have sizes\n"
01470                 "\tof 4, 2 and 1 bytes to run properly, and they don't.\n"
01471                 "\tProbably you can fix this by defining them correctly,\n"
01472                 "\tand recompiling.  Bye!\n" );
01473       exit(3);
01474    }
01475 
01476 
01477    /*-- Initialise --*/
01478    outputHandleJustInCase  = NULL;
01479    smallMode               = False;
01480    keepInputFiles          = False;
01481    forceOverwrite          = False;
01482    noisy                   = True;
01483    verbosity               = 0;
01484    blockSize100k           = 9;
01485    testFailsExist          = False;
01486    numFileNames            = 0;
01487    numFilesProcessed       = 0;
01488    workFactor              = 30;
01489    i = j = 0; /* avoid bogus warning from egcs-1.1.X */
01490 
01491    /*-- Set up signal handlers for mem access errors --*/
01492    signal (SIGSEGV, mySIGSEGVorSIGBUScatcher);
01493 #if BZ_UNIX
01494 #ifndef __DJGPP__
01495    signal (SIGBUS,  mySIGSEGVorSIGBUScatcher);
01496 #endif
01497 #endif
01498 
01499    copyFileName ( inName,  "(none)" );
01500    copyFileName ( outName, "(none)" );
01501 
01502    copyFileName ( progNameReally, argv[0] );
01503    progName = &progNameReally[0];
01504    for (tmp = &progNameReally[0]; *tmp != '\0'; tmp++)
01505       if (*tmp == PATH_SEP) progName = tmp + 1;
01506 
01507 
01508    /*-- Copy flags from env var BZIP2, and 
01509         expand filename wildcards in arg list.
01510    --*/
01511    argList = NULL;
01512    addFlagsFromEnvVar ( &argList,  "BZIP2" );
01513    addFlagsFromEnvVar ( &argList,  "BZIP" );
01514    for (i = 1; i <= argc-1; i++)
01515       APPEND_FILESPEC(argList, argv[i]);
01516 
01517 
01518    /*-- Find the length of the longest filename --*/
01519    longestFileName = 7;
01520    numFileNames    = 0;
01521    decode          = True;
01522    for (aa = argList; aa != NULL; aa = aa->link) {
01523       if (ISFLAG("--")) { decode = False; continue; }
01524       if (aa->name[0] == '-' && decode) continue;
01525       numFileNames++;
01526       if (longestFileName < (Int32)strlen(aa->name) )
01527          longestFileName = (Int32)strlen(aa->name);
01528    }
01529 
01530 
01531    /*-- Determine source modes; flag handling may change this too. --*/
01532    if (numFileNames == 0)
01533       srcMode = SM_I2O; else srcMode = SM_F2F;
01534 
01535 
01536    /*-- Determine what to do (compress/uncompress/test/cat). --*/
01537    /*-- Note that subsequent flag handling may change this. --*/
01538    opMode = OM_Z;
01539 
01540    if ( (strstr ( progName, "unzip" ) != 0) ||
01541         (strstr ( progName, "UNZIP" ) != 0) )
01542       opMode = OM_UNZ;
01543 
01544    if ( (strstr ( progName, "z2cat" ) != 0) ||
01545         (strstr ( progName, "Z2CAT" ) != 0) ||
01546         (strstr ( progName, "zcat" ) != 0)  ||
01547         (strstr ( progName, "ZCAT" ) != 0) )  {
01548       opMode = OM_UNZ;
01549       srcMode = (numFileNames == 0) ? SM_I2O : SM_F2O;
01550    }
01551 
01552 
01553    /*-- Look at the flags. --*/
01554    for (aa = argList; aa != NULL; aa = aa->link) {
01555       if (ISFLAG("--")) break;
01556       if (aa->name[0] == '-' && aa->name[1] != '-') {
01557          for (j = 1; aa->name[j] != '\0'; j++) {
01558             switch (aa->name[j]) {
01559                case 'c': srcMode          = SM_F2O; break;
01560                case 'd': opMode           = OM_UNZ; break;
01561                case 'z': opMode           = OM_Z; break;
01562                case 'f': forceOverwrite   = True; break;
01563                case 't': opMode           = OM_TEST; break;
01564                case 'k': keepInputFiles   = True; break;
01565                case 's': smallMode        = True; break;
01566                case 'q': noisy            = False; break;
01567                case '1': blockSize100k    = 1; break;
01568                case '2': blockSize100k    = 2; break;
01569                case '3': blockSize100k    = 3; break;
01570                case '4': blockSize100k    = 4; break;
01571                case '5': blockSize100k    = 5; break;
01572                case '6': blockSize100k    = 6; break;
01573                case '7': blockSize100k    = 7; break;
01574                case '8': blockSize100k    = 8; break;
01575                case '9': blockSize100k    = 9; break;
01576                case 'V':
01577                case 'L': license();            break;
01578                case 'v': verbosity++; break;
01579                case 'h': usage ( progName );
01580                          exit ( 0 );
01581                          break;
01582                default:  fprintf ( stderr, "%s: Bad flag `%s'\n",
01583                                    progName, aa->name );
01584                          usage ( progName );
01585                          exit ( 1 );
01586                          break;
01587             }
01588          }
01589       }
01590    }
01591    
01592    /*-- And again ... --*/
01593    for (aa = argList; aa != NULL; aa = aa->link) {
01594       if (ISFLAG("--")) break;
01595       if (ISFLAG("--stdout"))            srcMode          = SM_F2O;  else
01596       if (ISFLAG("--decompress"))        opMode           = OM_UNZ;  else
01597       if (ISFLAG("--compress"))          opMode           = OM_Z;    else
01598       if (ISFLAG("--force"))             forceOverwrite   = True;    else
01599       if (ISFLAG("--test"))              opMode           = OM_TEST; else
01600       if (ISFLAG("--keep"))              keepInputFiles   = True;    else
01601       if (ISFLAG("--small"))             smallMode        = True;    else
01602       if (ISFLAG("--quiet"))             noisy            = False;   else
01603       if (ISFLAG("--version"))           license();                  else
01604       if (ISFLAG("--license"))           license();                  else
01605       if (ISFLAG("--exponential"))       workFactor = 1;             else 
01606       if (ISFLAG("--repetitive-best"))   redundant(aa->name);        else
01607       if (ISFLAG("--repetitive-fast"))   redundant(aa->name);        else
01608       if (ISFLAG("--verbose"))           verbosity++;                else
01609       if (ISFLAG("--help"))              { usage ( progName ); exit ( 0 ); }
01610          else
01611          if (strncmp ( aa->name, "--", 2) == 0) {
01612             fprintf ( stderr, "%s: Bad flag `%s'\n", progName, aa->name );
01613             usage ( progName );
01614             exit ( 1 );
01615          }
01616    }
01617 
01618    if (verbosity > 4) verbosity = 4;
01619    if (opMode == OM_Z && smallMode && blockSize100k > 2) 
01620       blockSize100k = 2;
01621 
01622    if (opMode == OM_TEST && srcMode == SM_F2O) {
01623       fprintf ( stderr, "%s: -c and -t cannot be used together.\n",
01624                 progName );
01625       exit ( 1 );
01626    }
01627 
01628    if (srcMode == SM_F2O && numFileNames == 0)
01629       srcMode = SM_I2O;
01630 
01631    if (opMode != OM_Z) blockSize100k = 0;
01632 
01633    if (srcMode == SM_F2F) {
01634       signal (SIGINT,  mySignalCatcher);
01635       signal (SIGTERM, mySignalCatcher);
01636 #     if BZ_UNIX
01637       signal (SIGHUP,  mySignalCatcher);
01638 #     endif
01639    }
01640 
01641         c1=clock();
01642 
01643    if (opMode == OM_Z) {
01644      if (srcMode == SM_I2O) {
01645         compress ( NULL );
01646      } else {
01647         decode = True;
01648         for (aa = argList; aa != NULL; aa = aa->link) {
01649            if (ISFLAG("--")) { decode = False; continue; }
01650            if (aa->name[0] == '-' && decode) continue;
01651            numFilesProcessed++;
01652            compress ( aa->name );
01653         }
01654      }
01655    } 
01656    else
01657 
01658    if (opMode == OM_UNZ) {
01659       if (srcMode == SM_I2O) {
01660          uncompress ( NULL );
01661       } else {
01662          decode = True;
01663          for (aa = argList; aa != NULL; aa = aa->link) {
01664             if (ISFLAG("--")) { decode = False; continue; }
01665             if (aa->name[0] == '-' && decode) continue;
01666             numFilesProcessed++;
01667             uncompress ( aa->name );
01668          }      
01669       }
01670    } 
01671 
01672    else {
01673       testFailsExist = False;
01674       if (srcMode == SM_I2O) {
01675          testf ( NULL );
01676       } else {
01677          decode = True;
01678          for (aa = argList; aa != NULL; aa = aa->link) {
01679             if (ISFLAG("--")) { decode = False; continue; }
01680             if (aa->name[0] == '-' && decode) continue;
01681             numFilesProcessed++;
01682             testf ( aa->name );
01683          }
01684       }
01685       if (testFailsExist && noisy) {
01686          fprintf ( stderr,
01687            "\n"
01688            "You can use the `bzip2recover' program to attempt to recover\n"
01689            "data from undamaged sections of corrupted files.\n\n"
01690          );
01691          exit(2);
01692       }
01693    }
01694 
01695    /* Free the argument list memory to mollify leak detectors 
01696       (eg) Purify, Checker.  Serves no other useful purpose.
01697    */
01698    aa = argList;
01699    while (aa != NULL) {
01700       Cell* aa2 = aa->link;
01701       if (aa->name) free(aa->name);
01702       free(aa);
01703       aa = aa2;
01704    }
01705 
01706         c2=clock();
01707         printf("Time: %f\n",((float)c2-(float)c1)/(float)CLOCKS_PER_SEC);
01708 
01709    return 0;
01710 }
01711 
01712 
01713 /*-----------------------------------------------------------*/
01714 /*--- end                                         bzip2.c ---*/
01715 /*-----------------------------------------------------------*/

Generated on Sat Oct 13 16:08:33 2001 for XMILL by doxygen1.2.11.1 written by Dimitri van Heesch, © 1997-2001