Code:
#include <stdio.h>
#include <stdlib.h>
/*
A case-insensitive strcmp
*/
int stricmp( char const* s1, char const* s2 )
{
int
c1,
c2,
diff;
for( ;; )
{
c1 = tolower( *s1++ );
c2 = tolower( *s2++ );
diff = c1 - c2;
if( diff )
return diff;
/*
Since c1 == c2 only one check is needed
*/
if( !c1 )
break;
}
return 0;
}
enum
{
first_code,
second_code,
third_code,
fourth_code,
undefined_code
};
char
first_symbol = ' ',
second_symbol = ':',
third_symbol = '@',
fourth_symbol = '\n',
lookup_code[ 256 ] =
{
undefined_code
},
translate_symbols[ 4 ][ 4 ][ 4 ][ 4 ],
translate_code[ 4 ];
void initialize( void )
{
int
level_0,
level_1,
level_2,
level_3;
lookup_code[ first_symbol ] = first_code;
lookup_code[ second_symbol ] = second_code;
lookup_code[ third_symbol ] = third_code;
lookup_code[ fourth_symbol ] = fourth_code;
for( level_0 = 0; level_0 < 4; ++level_0 )
for( level_1 = 0; level_1 < 4; ++level_1 )
for( level_2 = 0; level_2 < 4; ++level_2 )
for( level_3 = 0; level_3 < 4; ++level_3 )
translate_symbols[ level_0 ][ level_1 ][ level_2 ][ level_3 ] =
level_0 | ( level_1 << 2 ) | ( level_2 << 4 ) | ( level_3 << 6 );
translate_code[ first_code ] = first_symbol;
translate_code[ second_code ] = second_symbol;
translate_code[ third_code ] = third_symbol;
translate_code[ fourth_code ] = fourth_symbol;
}
int compress( FILE* in, FILE* out )
{
int
ch,
index,
levels[ 4 ];
for( ;; )
{
for( index = 0; index < 4; ++index )
{
ch = fgetc( in );
if( ch == EOF )
{
if( index != 0 )
return 0;
return 1;
}
ch = lookup_code[ ch ];
if( ch == undefined_code )
return 0;
levels[ index ] = ch;
}
fputc( translate_symbols[ levels[ 0 ] ][ levels[ 1 ] ][ levels[ 2 ] ][ levels[ 3 ] ], out );
}
/*
We never actually end up here
*/
return 1;
}
int decompress( FILE* in, FILE* out )
{
int
ch,
index;
while( ( ch = fgetc( in ) ) != EOF )
for( index = 0; index < 4; ++index, ch >>= 2 )
fputc( translate_code[ ch & 0x3 ], out );
/*
Never fails
*/
return 1;
}
int usage( char const* program, char const* message )
{
if( message )
fprintf( stderr, "\nError: '%s'\n", message );
fprintf( stderr, "Usage: %s <mode> <infile> <outfile>\n", program );
fprintf( stderr, "Mode: \n" );
fprintf( stderr, "\t'c': Compress\n" );
fprintf( stderr, "\t'd': Decompress\n" );
fprintf( stderr, "Infile: Input file ('stdin' to use standard input)\n" );
fprintf( stderr, "Outfile: Output file ('stdout' to use standard output)\n" );
fprintf( stderr, "Note: Allowed symbols to compress are <newline>, <space>, ':', and '@'\n" );
return EXIT_FAILURE;
}
int main( int argc, char** argv )
{
fprintf( stderr, "Simple Compressor\n" );
char const
* program = argv[ 0 ];
if( argc != 4 )
return usage( program, 0 );
FILE
* in,
* out;
int
result = EXIT_FAILURE,
( * process )( FILE*, FILE* );
char const
* mode = argv[ 1 ],
* infile = argv[ 2 ],
* outfile = argv[ 3 ];
initialize( );
if( stricmp( mode, "c" ) == 0 )
process = compress;
else if( stricmp( mode, "d" ) == 0 )
process = decompress;
else
return usage( program, "invalid arguments" );
if( stricmp( infile, "stdin" ) == 0 )
in = stdin;
else
in = fopen( infile, "rb" );
if( !in )
usage( program, "cannot open input file" );
else
{
if( stricmp( outfile, "stdout" ) == 0 )
out = stdout;
else
out = fopen( outfile, "wb" );
if( !out )
usage( program, "cannot open output file" );
else
{
if( !process( in, out ) )
usage( program, "invalid format" );
else
result = EXIT_SUCCESS;
fclose( out );
}
fclose( in );
}
return result;
}
Good luck.