Code:
$ cat mysrc/autotab.c
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
static FILE *tmp ; /* temp file */
static char *just = "l" ; /* output column justification */
static char *osep = " " ; /* output column sep */
static char j ; /* current justification */
static char sav[4096] ; /* output column store for justification */
static char savl[65536];/* output line store */
static int c ; /* character read */
static int cl = 0 ; /* current column length */
static int col = 0 ; /* current column # */
static int fs = 0 ; /* possibly embedded spaces found */
static int gen_hdr = 0 ; /* generate header state */
static int i ; /* utility int */
static int no ; /* narrow, overlap final column */
static int isep = '\t' ; /* input column sep */
static int jlen = 1 ; /* output column justification */
static int l[4096] ; /* array of column widths */
static int ll = 0 ; /* output line length */
static int maxcol = 0 ; /* max column # */
int main( int argc, char **argv ){
for ( i = 1 ; i < argc ; i++ ){
if ( !strcmp( argv[i], "-is" ) && ( i + 1 ) < argc ){
isep = argv[++i][0] ;
continue ;
}
if ( !strcmp( argv[i], "-os" ) && ( i + 1 ) < argc ){
osep = argv[++i] ;
continue ;
}
if ( !strcmp( argv[i], "-no" )){
no = 1 ;
continue ;
}
if ( !strcmp( argv[i], "-j" ) && ( i + 1 ) < argc ){
just = argv[++i] ;
jlen = strlen( just );
continue ;
}
if ( !strcmp( argv[i], "-gh" ) ){
gen_hdr = 1 ;
continue ;
}
fprintf( stderr,
"\n"
"Usage: autotab [ -is <i_sep> ] [ -os <o_sep> ] [ -gh ] [ -no ] [ -j <just> ]\n"
"\n"
"Scans input as columns defined by <i_sep> (default tab), measuring maximum\n"
"column width without blank padding and saving the input. Lines with no\n"
"<i_sep> are not measured. If -no is present (narrow, overlapping), the\n"
"characters between the last <i_sep> on a line and the line feed are not\n"
"measured. (The -no option is only useful with left justification.)\n"
"After reading EOF, the saved input is printed, padded to the measured\n"
"column width and separated by the <o_sep> string (default 2 spaces) with\n"
"empty right side columns, blanks and carriage returns suppressed.\n"
"If -j is present, the characters of <just> define the justification of each\n"
"column with the same relative offset:\n"
" r for right, c for centered, and anything else means left.\n"
"If -gh is present, the saved input is prefixed by a numbered column header,\n"
"which is padded and aligned like the data.\n"
"The size limits are: %d measured columns, output line %d characters\n"
"and right or center justified column data width %d characters.\n"
"\n",
sizeof( l )/sizeof(int),
sizeof( savl ),
sizeof( sav ));
exit( 1 );
}
if ( NULL == ( tmp = tmpfile() )){
perror( "tmpfile()" );
exit( 1 );
}
memset( (char*)l, 0, sizeof( l ) );
do {
switch( c = getchar() ){
case EOF:
if ( ferror( stdin ) ){
perror( "stdin" );
exit( 1 );
}
continue ; /* Out of loop */
case '\n':
if ( no ){
col = 0 ;
cl = 0 ;
fs = 0 ;
break ;
}
/* Intentional Fall Through */
case '\f':
if ( cl && col ){
if ( col == ( sizeof( l ) / sizeof( int ) )){
fprintf( stderr,
"Too many columns!\n" );
exit( 1 );
}
if ( cl > l[col] ){
l[col++] = cl ;
}
}
if ( col > maxcol ){
maxcol = col ;
}
col = 0 ;
cl = 0 ;
fs = 0 ;
break ;
case ' ':
if ( cl ){
fs++ ;
}
case '\r':
continue ;
default:
if ( c == isep ){
if ( cl ){
if ( col == ( sizeof( l )
/ sizeof( int ) )){
fprintf( stderr,
"Too many columns!\n"
);
exit( 1 );
}
if ( cl > l[col] ){
l[col] = cl ;
}
}
col++ ;
cl = 0 ;
fs = 0 ;
break ;
}
cl++ ;
cl += fs ;
while ( fs ){
fs-- ;
if ( EOF == putc( ' ', tmp )){
perror( "putc(tmp)" );
exit( 1 );
}
}
break ;
}
if ( EOF == putc( c, tmp )){
perror( "putc(tmp)" );
exit( 1 );
}
} while ( c != EOF );
rewind( tmp );
if ( gen_hdr ){
col = 0 ;
do {
if ( 0 > ( cl = printf( "Col. %d", col + 1 ))){
if ( ferror( stdout )){
perror( "stdout" );
exit( 1 );
}
exit( 0 );
}
if ( cl > l[col] ){
l[col] = cl ;
} else while ( cl++ < l[col] ){
if ( EOF == putchar( ' ' )){
if ( ferror( stdout )){
perror( "stdout" );
exit( 1 );
}
exit( 0 );
}
}
if ( ++col == maxcol ){
break ;
}
if ( EOF == fputs( osep, stdout )){
if ( ferror( stdout )){
perror( "stdout" );
exit( 1 );
}
exit( 0 );
}
} while ( 1 );
if ( EOF == putchar( '\n' )){
if ( ferror( stdout ) ){
perror( "stdout" );
exit( 1 );
}
exit( 0 );
}
cl = col = 0 ;
}
j = *just ;
do {
switch ( c = getc( tmp )){
case EOF:
if ( ferror( tmp )){
perror( "getc(tmp)" );
exit( 1 );
}
if ( !ll && !cl ){
exit( 0 );
}
c = '\n' ;
/* Intentional fall through for EOF as linefeed */
case '\f':
case '\n':
if ( cl ){
if ( col ){
fs = l[col] - cl ;
} else {
fs = 0 ;
}
switch ( j ){
case 'c':
fs >>= 1 ;
case 'r':
if ( ll > ( sizeof( savl ) - fs - cl )){
fputs(
"Output line too long!\n", stderr );
exit( -1 );
}
ll += sprintf( savl + ll,
"%*s%.*s",
fs,
"",
cl,
sav );
break ;
}
}
while ( savl[--ll] == ' '
|| savl[ll] == '\t' ){
/* nothing */
}
if ( 0 > printf( "%.*s%c", ++ll, savl, c )){
if ( ferror( stdout )){
perror( "stdout" );
}
exit( 1 );
}
ll = 0 ;
col = 0 ;
cl = 0 ;
fs = 0 ;
j = *just ;
break ;
default:
if ( c == isep ){
fs = l[col] - cl ;
if ( ll >
( sizeof( savl ) - fs - cl - strlen( osep ))){
fputs(
"Output line too long!\n", stderr );
exit( 1 );
}
switch ( j ){
case 'c':
ll += sprintf( savl + ll,
"%*s%.*s%*s",
fs >> 1,
"",
cl,
sav,
fs - ( fs >> 1 ),
"" );
break ;
case 'r':
ll += sprintf( savl + ll,
"%*s%.*s",
fs,
"",
cl,
sav );
break ;
default:
ll += sprintf( savl + ll, "%*s", fs, ""
);
break ;
}
ll += sprintf( savl + ll, "%s", osep );
if ( ++col < jlen ){
j = just[col] ;
} else {
j = 'l' ;
}
fs = 0 ;
cl = 0 ;
continue ;
}
if ( j == 'r' || j == 'c' ){
if ( cl >= sizeof( sav )){
fprintf( stderr,
"\nFatal: Column %d too wide.\n",
++col );
exit( 1 );
}
sav[cl++] = c ;
continue ;
}
if ( ll >= sizeof( savl )){
fprintf( stderr, "Output line too long!\n" );
exit( 1 );
}
cl++ ;
savl[ll++] = c ;
break ;
}
} while ( c != EOF );
exit( 0 );
}