📄 406-456.html
字号:
#endif putc( '\n', stderr ); vfprintf( stderr, fmt, args ); putc( '\n', stderr ); va_end( args ); if ( OutputCarFile != NULL ) fclose( OutputCarFile );#ifdef __STDC__ remove( TempFileName );#else unlink( TempFileName );#endif exit( 1 );}/** This routine simply builds the coefficient table used to calculate* 32-bit CRC values throughout this program. The 256-long word table* has to be set up once when the program starts. Alternatively, the* values could be hard-coded in, which would offer a miniscule* improvement in overall performance of the program.*/void BuildCRCTable(){ int i; int j; unsigned long value; for ( i = 0; i <= 255 ; i++ ) { value = i; for ( j = 8 ; j > 0; j-- ) { if ( value & 1 ) value = ( value >> 1 ) ^ CRC32_POLYNOMIAL; else value >>= 1; } Ccitt32Table[ i ] = value; }}/** This is the routine used to calculate the 32-bit CRC of a block of* data. This is done by processing the input buffer using the* coefficient table that was created when the program was initialized.* This routine takes an input value as a seed, so that a running* calculation of the CRC can be used as blocks are read and written.*/unsigned long CalculateBlockCRC32( count, crc, buffer )unsigned int count;unsigned long crc;void *buffer;{ unsigned char *p = (unsigned char *) buffer; unsigned long temp1; unsigned long temp2; while ( count-- != 0 ) { temp1 = ( crc >> 8 ) & 0x00FFFFFFL; temp2 = Ccitt32Table[ ( (int) crc ^ *p++ ) & 0xff ]; crc = temp1 ^ temp2; } return( crc );}/** If I/0 is being done on a byte-by-byte basis, as is the case with the* LZSS code, it is easier to calculate the CRC of a byte at a time* instead of a block at a time. This routine performs that function,* once again taking a CRC value as input, so that this can be used to* perform on the fly calculations. In situations where performance is* critical, this routine could easily be recorded as a macro.*/unsigned long UpdateCharacterCRC32( crc, c )unsigned long crc;int c;{ unsigned long temp1; unsigned long temp2; temp1 = ( crc >> 8 ) & 0x00FFFFFFL; temp2 = Ccitt32Table[ ( (int) crc ^ c ) & 0xff ]; crc = temp1 ^ temp2; return( crc );}/** When CARMAN first starts up, it calls this routine to parse the* command line. We look for several things here. If any of the* conditions needed to run CARMAN is not met, the routine opts for* the usage printout exit. The first thing to be sure of is that* the command line has at least three arguments, which should be* the "CARMAN", a single character command, and an CAR archive name.* After that, we check to be sure that the command name is a valid* letter, and incidentally print out a short message based on it.* Both the Addfiles and Delete commands require that some file names* be listed as well, so a check is made for additional arguments when* each of those arguments is encountered. Finally, the command itself* is returned to main(), for use later in processing the command.*/int ParseArguments( argc, argv )int argc;char *argv[];{ int command; if ( argc < 3 || strlen( argv[ 1 ] ) > 1 ) UsageExit(); switch( command = toupper( argv[ 1 ][ 0 ] ) ) { case 'X' : fprintf( stderr, "Extracting files\n"; break; case 'R' : fprintf( stderr, "Replacing files\n" ); break; case 'P' : fprintf( stderr, "Print files to stdout\n" ); break; case 'T' : fprintf( stderr, "Testing integrity of files\n" ); break; case 'L' : fprintf( stderr, "Listing archive contents\n" ); break; case 'A' : if ( argc <= 3 ) UsageExit(); fprintf( stderr, "Adding/replacing files to archive\n" ); break; case 'D' : if ( argc <= 3 ) UsageExit(); fprintf( stderr, "Deleting files from archive\n" )' break; default : UsageExit(); }; return( command );}/** UsageExit just provides a universal point of egress for those* times when there appears to be a problem on the command line.* This routine prints a short help message then exits back to the OS.*/void UsageExit(){ fputs( "CARMAN - Compressed ARchive MANager\n", stderr ); fputs( "Usage: carman command car-file [file ...]\n", stderr ); fputs( "Commands:\n", stderr ); fputs( " a: Add files to a CAR archive (replace if present)\n", stderr ); fputs( " x: Extract files from a CAR archive\n", stderr ); fputs( " r: Replace files in a CAR archive\n", stderr ); fputs( " d: Delete files from a CAR archive\n", stderr ); fputs( " p: Print files on standard output\n", stderr ); fputs( " l: List contents of a CAR archive\n", stderr ); fputs( " t: Test files in a CAR archive\n", stderr ); fputs( "\n", stderr ); exit( 1 );}/** After the command line has been parsed, main() has enough information* to intelligently open the input and output CAR archive files. The* name should have been specified on the command line, and passed to* this routine by main(). As a convenience to the user, if the CAR* suffix is left off the archive, this routine will add it on.* There is one legitimate excuse for not being able to open the input* file, which is if this is the 'Addfiles' command. There may not be* an input archive when that command is called, in which case a failure* is tolerated. Once the input file has been opened, an output file* may have to be opened as well. The 'Addfiles', 'Delete', and* 'Replace' commands all modify the CAR archive, which means the input* CAR file is going to be processed and copied to the output. Initially,* the output CAR file gets a temporary name. It will be renamed later* after the input has been processed.** Since we will probably be doing lots of bulk copies from the input* CAR file to the output CAR file, it makes sense to allocate big* buffers for the files. This is done with the two calls to setvbuf()* right before the routine exits.**/void OpenArchiveFiles( name, command )char *name;int command;{ char *s; int i; strncpy( CarFileName, name, FILENAME_MAX - 1 ); CarFileName[ FILENAME_MAX - 1 ] = '\0'; InputCarFile = fopen( CarFileName, "rb" ); if ( InputCarFile == NULL ) {#ifdef MSDOS s = strrchr( CarFileName, '\\' );#else /* UNIX */ s = strrchr( CarFileName, '/' );#endif if ( s == NULL ) s = CarFileName; if ( strrchr( s, '.' ) == NULL ) if ( strlen( CarFileName ) < ( FILENAME_MAX - 4 ) ) { strcat( CarFileName, ".car" ); InputCarFile = fopen( CarFileName, "rb" ); } } if ( InputCarFile == NULL && command != 'A' ) FatalError( "Can't open archive '%s'", CarFileName ); if ( command == 'A' || command == 'R' || command == 'D' ) { strcpy( TempFileName, CarFileName ); s = strrchr( TempFileName, '.'); if ( s == NULL ) s = TempFileName + strlen( TempFileName ); for ( i = 0 ; i < 10 ; i++ ) { sprintf( s, ".$$%d", i ); if ( ( OutputCarFile = fopen( TempFileName, "r" ) ) == NULL ) break; fclose( OutputCarFile ); OutputCarFile = NULL; } if ( i == 10 ) FatalError( "Can't open temporary file %s", TempFileName ); OutputCarFile = fopen( TempFileName, "wb" ); if ( OutputCarFile == NULL ) FatalError( "Can't open temporary file %s", TempFileName ); } if ( InputCarFile != NULL ) setvbuf( InputCarFile, NULL, _IOFBF, 8192 ); if ( OutputCarFile != NULL ) setvbuf( OutputCarFile, NULL, _IOFBF, 8192 );}/** Most of the commands given here take one or more file names as* arguments. The list of files given on the command line needs to be* processed here and put into a list that can easily be manipulated by* other parts of the program. That processing is done here. An array* called FileList is created, which will have a series of pointers to* file names. If no file names were listed on the command line, which* could be the case for commands like 'List' or 'Extract', a single* file name of '*' is put on the start of the list. Since '*' is the* ultimate wild card, matching everything, we don't have to have special* processing anywhere else for an empty file list. The file names here* are also massaged a bit further for MS-DOS file names. Under MS-DOS,* case is not significant in file names. This means that CARMAN* shouldn't get confused by thinking 'foo.c' and 'FOO.C' are two* different files. To avoid this, all MS-DOS file names are converted* here to lower case. Additionally, any file name without an extension* is forced to end with a period, for similar reasons. This ensures that* CARMAN knows 'FOO' and 'FOO.' are the same file. Note that I don't* want to do this for wild card specifications. Finally, there is the* problem of MS-DOS wild card file names. When using the 'Add' command,* wild cards on the command line need to be expanded into real file* names, then undergo the additional processing mentioned earlier. This* is done with a call to a function that is MS-DOS specific. None of* this special processing is done under UNIX, where case is significant,* and wild cards are expanded by the shell.*/void BuildFileList( argc, argv, command )int argc;char *argv[];int command;{ int i; int count; count = 0; if ( argc == 0 ) FileList[ count++ ] = "*"; else { for ( i = 0 ; i < argc ; i++ ) {#ifdef MSDOS if ( command == 'A' ) count = ExpandAndMassageMSDOSFileNames( count, argv[ i ] ); else MassageMSDOSFileName( count++, argv[ i ] );#endif#ifndef__MSDOS__ FileList [ count ] = malloc( strlen( argv[ i ] ) + 2 ); if ( FileList[ count ] == NULL ) FatalError( "Ran out of memory storing file names" ); strcpy( FileList[ count++ ], argv[ i ] );#endif if ( count > 99 ) FatalError( "Too many file names" ); } } FileList[ count ] = NULL;}/** Under MS-DOS, wildcards on the command line are not expanded to* a list of file names, so it is up to application programs to do the* expansion themselves. This routine takes care of that, by using* the findfirst and findnext routines. Unfortunately, each MS-DOS* compiler maker has implemented this function slightly differently, so* this may need to be modified for your particular compiler. However,* this routine can be replaced with a call to MassageMSDOSFileName(),* and the program will work just fine, without the ability to handle* wild card file names.*/#ifdef MSDOS#include <dos.h>#include <dir.h>int ExpandAndMassageMSDOSFileNames( count, wild_name )int count;char *wild_name;{ int done; DIR_STRUCT file_info_block; char *leading_path; char *file_name; char *p; leading_path = malloc( strlen( wild_name ) + 1 ); file_name = malloc( strlen( wild_name ) + 13 ); if ( leading_path == NULL || file_name == NULL ) FatalError( "Ran out of memory storing file names" ); strcpy( leading_path, wild_name ); p = strrchr( leading_path, '\\' ); if ( p != NULL ) p[ 1 ] = '\0'; else { p = strrchr( leading_path, ';' ); if ( p != NULL ) p[ 1 ] = '\0'; else leading_path[ 0 ] = '\0'; } done = FIND_FIRST( wild_name, & file_info_block, 0 ); while ( !done ) { strcpy( file_name, leading_path ); strcat( file_name, file_info_block.DIR_FILE_NAME ); MassageMSDOSFileName( count++, file_name ); done = FIND_NEXT( & file_info_block ); if ( count > 99 ) FatalError( "Too many file names" ); } free( leading_path ); free( file_name ); return( count );}/** As was discussed earlier, this routine is called to perform a small* amount of normalization on file names. Under MS_DOS, case is not* significant in file names. In order to avoid confusion later, we force* all file names to be all lower case, so we can't accidentally add two* files with the same name to a CAR archive. Likewise, we need to* prevent confusion between files that end in a period, and the same* file without the terminal period. We fix this by always forcing the* file name to end in a period.*/void MassageMSDOSFileName( count, file )int count;char *file;{ int i; char *p; FileList[ count ] = malloc( strlen( file ) + 2 ); if ( FileList[ count ] == NULL ) FatalError( "Ran out of memory storing file names" ); strcpy( FileList[ count ], file ); for ( i = 0 ; FileList[ count ] [ i ] != '\0' ; i++ ) FileList[ count ][ i ] = (char) tolower(FileList[ count ][ i ]); if ( strpbrk( FileList [ count ], "*?" ) == NULL ) { p = strrchr( FileList[ count ], '\\' ); if ( p == NULL ) p = FileList[ count ]; if ( strrchr( p, '.' ) == NULL ) strcat( FileList[ count ], "." ); }}#endif/** Once all of the argument processing is done, the main() procedure* checks to see if the command is 'Addfiles'. If it is, it calls* this procedure to add all of the listed files to the output buffer* before any other processing is done. That is taken care of right* here. This routine basically does three jobs before calling the* Insert() routine, where the compression actually takes place. First,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -