/* Daniel Roche script-fix.c
 * This program takes one or more text files that are created by the program
 * script and "fixes" them by removing all delete commands and "folding" lines
 * that are more than 80 characters wide into multiple lines.
 * The result is a single file suitable for printing with the qpr or lpr
 * command.
 * "Unfolded" lines will begin with a "@" character to show that they were
 * originally part of the previous line.
 * Input files may be specified as command-line arguments.  If no arguments are
 * given, stdin will be used.
 * By default, output will go to standard out.
 * Alternatively, output can be redirected to a file on the command line with
 * the syntax "-o filename" (this must appear before any input files).
 */

#include <stdio.h>
#include <stdlib.h>

#define MAX_WIDTH 80
#define MAX_HEIGHT 66
#define TAB_WIDTH 8

void displayUsage();

int main( int argc, char** argv ) {
	FILE* out = stdout, *tempOut, *curin = stdin;
	int row, col;
	int c, code1, code2;
	int i = 1; // i is the index in argv where we expect to find the first
		   // input filename.

	// Check if the first argument starts with a "-".  If so, see if we have
	// something of the form "-o outfile", and if so, set out accordingly.
	// Otherwise, set out to the default.
	if( argc >= 2 && argv[1][0] == '-' ) {
		if( argc < 3 || argv[1][1] != 'o' || argv[1][2] != '\0' )
			displayUsage(); // If the switch syntax is incorrect
		out = fopen( argv[2], "w" );
		i = 3;

		if( !out ) {
			fprintf( stderr, "Error opening output file %s\n",
				 argv[2] );
			exit(1);
		}
	}

	// Attempt to open the temporary output file.
	tempOut = tmpfile();
	if( !tempOut ) {
		fprintf( stderr, "Error opening temp file.\n" );
		exit(1);
	}
	
	// Here is a do loop to go through each named input file (or stdin) and
	// process backspaces and the like, writing to tempOut.
	do {
	    if( i < argc ) {
		if( argv[i][0] == '-' )
		    displayUsage(); // If the switch syntax is incorrect
		if( curin ) fclose( curin );
		curin = fopen( argv[i], "r" );
		if( !curin ) {
			fprintf( stderr,
				 "Error opening input file: %s\n", argv[i] );
			exit(1);
		}
	    }

	    while( (c = getc( curin )) != EOF ) {
		switch( c ) {
		    // Ignore nulls, feeds, and the like
		    case '\0':
		    case '\v':
		    case '\f':
		    case '\a': break;

		    // Carriage return means skip to end of line
		    case '\r':
			fseek( tempOut, 0, SEEK_END );
			break;

		    // Deal with escape sequences
		    case 27:
			code1 = getc(curin);
			code2 = getc(curin);
			if( code1 == 91 && code2 == 75 ) {
				putc( '\0', tempOut );
				fseek( tempOut, -1, SEEK_CUR );
			}
			break;

		    // Backspace
		    case '\b':
			fseek( tempOut, -1, SEEK_CUR );
			break;

		    // Normal characters
		    default:
			putc( c, tempOut );
			break;
		}
	    }

	} while( ++i < argc );

	if( curin ) fclose( curin );

	fseek( tempOut, 0, SEEK_SET );

	row = col = 0;
	while( (c = getc( tempOut )) != EOF ) {
	    switch( c ) {
		case '\0': break;

		case '\n':
			++row;
			col = 0;
			putc( c, out );
			break;

		case '\t':
			col = (col/TAB_WIDTH + 1) * TAB_WIDTH;
			if( col > MAX_WIDTH ) {
				++row;
				col = TAB_WIDTH;
				putc('\n',out);
				putc('@',out);
			}
			putc( c, out );
			break;

		default:
			if( col >= MAX_WIDTH ) {
				++row;
				col = 1;
				putc('\n',out);
				putc('@',out);
			}
			++col;
			putc( c, out );
			break;
	    }
	}

	fclose(out);
	fclose( tempOut ); // Temp file will automatically be deleted.

	fprintf(stderr, "Fix successful: %d lines, %d pages\n",
		row, row/MAX_HEIGHT + 1 );

	return 0;
}

// Displays information on how to use this program and exits.
void displayUsage() {
	fprintf( stderr,
		 "Usage: script-fix [-o outfile] [infile1 infile2 ...]\n" );
	exit(1);
}

