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