Previous Table of Contents Next


There are a few expectations about how MAIN-C.C will run. MAIN-C.C is called to compress an input file supplied on the command line and send the compressed output to another file, also supplied on the command line. Thus, the basic command-line invocation of MAIN-C.C is MAIN-C input-file output-file. If the user invokes MAIN-C.C without any arguments, a simple usage statement prints out. The usage statement includes the usage string supplied by the compression module.

If two likely looking file names are on the command line, MAIN-C.C tries to open them both. The input file is opened as a standard file specified in STDIO.H, using fopen(). The output file is opened as a BIT_FILE, as defined in BITIO.H. If either file doesn’t open, an error message is printed out and the program exits. If both files open, the next step is to call the compression routine.

MAIN-C.C expects the compression routine to be named CompressFile(). This routine is called with four arguments. The first two are pointers to the file structure for the input file and a pointer to the BIT_FILE structure for the output file. Finally, the updated values for argc and argv are passed to the compression routine. The values for argc and argv will have been adjusted to go past argv[0], which should be the program name, as well as argv[1] and argv[2], the names of the input and output files. The compression program can then scan the remaining arguments for any arguments specific to that particular compression routine. After the compression routine has finished, it returns to MAIN-C.C, which closes down the files and exits.

MAIN-E.C is the converse program to MAIN-C.C. It takes two arguments as well, but this time the input file is the compressed file and the output file is destined to be the uncompressed clear text file. Just like MAIN-C.C, it checks to be sure there are at least two arguments, then tries to open the two files. If there aren’t two arguments, a usage message is printed. If either of the files fails to open, an error message is printed. MAIN-E.C is listed below.

/***********************Start of MAIN-E.C***********************/
* This driver program tests compression algorithms.  To cut back on
* repetitive code, this version of main is used with all the expansion
* routines.  The main() routine supplied here checks for valid input and
* output files, opens them, then calls the compression routine.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "bitio.h"
#include "errhand.h"
#include "main.h"

void usage_exit( char *prog_name );
void usage_exit();

int main( argc, argv )
int argc;
char *argv[];
     FILE *output;
     BIT_FILE *input;

     setbuf( stdout, NULL );
     if  ( argc < 3 )
        usage_exit( argv[ 0 ] );
     input = OpenInputBitFile( argv[ 1 ] );
     if ( input == NULL )
          fatal_error( "Error opening %s for input\n", argv[ 1 ]
     output = fopen( argv[ 2 ], "wb" );
     if ( output == NULL )
          fatal_error( "Error opening %s for output\n", argv[ 2 ]
     printf( "\nExpanding %s to %s for output\n", argv[ 2 ] );
     printf( "Using %\n", CompressionName );
     argc -= 3;
     argv += 3;
     ExpandFile( input, output, argc, argv );
     CloseInputBitFile( input );
     fclose( output );
     putc( '\n', stdout );
     return( 0 );

* This routine wants to print out the usage message called for when the
* program is run with no parameters.  The first part of the Usage state
* ment is supposed to be just the programname. argv[ 0 ] generally holds
* the fully qualified path name of the program being run.
void usage_exit( prog_name )
char *prog_name;
     char *short_name;
     char *extension;

     short_name = strrchr( prog_name, '\\' );
     if ( short_name = = NULL )
          short_name = = strrchr( prog_name, '/' );
     if ( short_name = = NULL )
          short_name = strrchr( prog_name, ':' );
     if ( short_name != NULL )
        short_name = prog_name;
     extension = strrchr( short_name, '.' );
     if ( extension != NULL )
          *extension = '\0';
     printf( "\nUsage: %s %s\n", short_name, Usage );
     exit( 0 );
/********************** End of MAIN-E.C**************************/


One additional routine helps simplify the code. A production version of a program generally needs a somewhat sophisticated error-handling mechanism. In particular, it is important to let the end user know what is happening, clean up any files that may have been only partially processed, and restore any system settings that may have been changed.

In this book, our interest in compression concentrates on testing for accuracy, speed, and compression ratios. Because of this, we have created a simple universal fatal-error handler. The error handler is defined in ERRHAND.H:

/********************** Start of ERRHAND.H **********************/

     #ifndef _ERRHAND_H
     #define _ERRHAND_H

     #ifdef ___STDC___

     void fatal_error( char *fmt, ... );

     #else /* ___STDC___ */

     void fatal_error();

     #endif /* ___STDC___ */

     #endif /* _ERRHAND_H */

/********************** End of ERRHAND.H *************************/

The fatal-error handler is called when an unrecoverable error occurs in the program. It has the same syntax as printf, which means it can be passed a format string and arguments to format and print out.

/************************ Start of ERRHAND.C ***********************/

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "errhand.h"

#ifdef __STDC__
void fatal_error( char *fmt, ... )
#ifdef __UNIX__
void fatal_error( fmt )
char *fmt;
void fatal_error( fmt )

     va_list argptr;

     va_start( argptr, fmt );
     printf( "Fatal error: " );
     vprintf( fmt, argptr  );
     va_end( argptr );
     exit( -1 );

/************************ End of ERRHAND.C ***********************/

Previous Table of Contents Next