I know that nobody asked (and for all I know, everyone here may already be familiar with this), but I just thought I'd elaborate on ways to write programs that can be linked together.
The example here is just a simple C program that reads binary data from a file or standard input, converts it to a hexadecimal string, and then writes the result to standard output. A basic console-based hex-dump utility.
Code:
#include <stdlib.h>
#include <stdio.h>
void dump( FILE* in, FILE* out );
int main( int argc, char** argv )
{
/*
For now, just use stdout for output, and stderr for all messages
*/
FILE*
out = stdout;
fprintf( stderr, "HexDump Utility\n" );
if( argc == 1 )
dump( stdin, out );
else while( *( ++argv ) )
{
FILE*
in = fopen( *argv, "rb" );
if( in == 0 )
{
fprintf( stderr, "Error: cannot process file '%s'\n", *argv );
continue;
}
fprintf( stderr, "File: '%s'\n", *argv );
dump( in, out );
fclose( in );
}
return 0;
}
void dump( FILE* in, FILE* out )
{
unsigned char
ch;
char const
* pad = "",
table[ ] = "0123456789ABCDEF";
for( ;; )
{
if( !fread( &ch, 1, sizeof( ch ), in ) )
{
if( ferror( in ) )
fprintf( stderr, "\nError: read operation failed" );
break;
}
if( !fprintf( out, "%s%c%c", pad, table[ ch >> 4 ], table[ ch & 0xf ] ) )
{
fprintf( stderr, "\nError: write operation failed" );
break;
}
pad = " ";
}
fprintf( out, "\n" );
}
So the important points are:
1) Abstract the file source and destination streams.
2) By default, read from standard input and write to standard output. Additionally, it's often useful to provide facilities for reading/writing actual files (such as in the above example with respect to input).
3) Sometimes it's better to write all messages to stderr (even non-error messages), especially when the output is some sort of binary data.
Anyway, numerous utilities that I've written use some variation of that basic theme. It's pretty useful, actually.