/*
 *  DJ	-	Print files to Deskjet+ 2 pages side-by-side landscape mode.
 *
 *	DJ will output files to a HP Deskjet+ printer connected to the PAR:
 *	device.  It prints 2 pages side-by-side by putting the printer into
 *	tiny print landscape mode.  Each page has a header which include
 *	file modification time (or current time if redirected input),
 *	file name and page #.
 *
 *	DJ [file1] [file2 ... fileN] OR
 *	DJ <redirected file
 *
 * 		DJ.C an Amiga page formatter for HP Deskjet Plus printer.
 *
 *                  Copywrite (c) 1990 Jeff Kunzelman
 *						CIS:	76224,102
 *
 *   This software is freely redistributable, as long as all code,
 *	 comments, and documentation are included unaltered, and no other
 *   conditions are imposed on its redistribution.
 *
 *   This software is provided 'AS IS' if it doesn't work very well,
 *   sorry.
 *
 *	 Compiled and linked with Lattice/SAS Ver 5.10   'lc -L dj.c'
 *	 Ignore the character const warnings.
 *
 *	Modification History:
 *
 *	16-Oct-90	Jeff
 *	Ver 1.0 1st release.
 */
#include <stdio.h>
#include <dos.h>
#include <time.h>

typedef int		bool;
#define IS_NIL(x)     ((bool)((x) == NULL))
#define EOS				'\0'

#define	MAXPAGES  		2
#define	MAXROWS   		90
#define	MAXLINE	  		170

#define	LHS				0
#define	RHS				1

#define PAGE_END_COL	95
#define MIDDLE_COL		(PAGE_END_COL + 5)
#define	LAST_COL		(MIDDLE_COL*2)

#define UNDERWIDTH		80
#define	SEPCHAR			179
#define UNDERCHAR		196

#define TABWIDTH		4		/* Must be 4, 8, 16 ... */

static char *eosPtr	= "";

static void
initPrinter(FILE *outHandle)
{
	fprintf(outHandle, "\033&l1O");			/* landscape 			*/
	fprintf(outHandle, "\033&l4C");
	fprintf(outHandle, "\033(s20hs6V\r");
}

static void
resetPrinter(FILE *outHandle)
{
	fprintf(outHandle, "\033E");
}

static void
printLines(FILE *outHandle, char *lhsPtr, char *rhsPtr, bool doSep)
{
	int		tabCol;
	int		col;
	int		loc;
	char	c;

	/*
	 *  Reset current tab location and column pointer.
	 *  Output the line expanding tabs as we go.
	 */
	for (tabCol = -1, loc = col = 0; col < PAGE_END_COL;) {
		c = lhsPtr[loc];
		if (c == '\n' || c == EOS)
			break;
		else if (c == '\t') {
			if (tabCol == -1)
				tabCol = TABWIDTH - (col & (TABWIDTH - 1));
			else if (tabCol) {
			    fputc(' ', outHandle);
				col++;
				tabCol--;
			} else {
				tabCol = -1;
				loc++;
			}
		} else {
			fputc(c, outHandle);
			col++;
			loc++;
		}
	}

	/*
	 *  Check for RHS text, skip separator and line if none.
	 */
	if (*rhsPtr != EOS) {
		/*  
		 *  Skip to center column. 
		 */
		for (; col < MIDDLE_COL; col++) 
			fputc(' ', outHandle);

		/*  
		 *  Print separator if requested. 
		 */
		fputc(doSep ? SEPCHAR : ' ', outHandle);

		/*  
		 *  Print an nice comfy gap 
		 */
		fprintf(outHandle, "    ");

		/*
		 *  Output the line expanding tabs as we go.
		 */
		for (tabCol = -1, loc = col = 0; col < PAGE_END_COL;) {
			c = rhsPtr[loc];
			if (c == '\n' || c == EOS)
				break;
			else if (c == '\t') {
				if (tabCol == -1)
					tabCol = TABWIDTH - (col & (TABWIDTH - 1));
				else if (tabCol) {
				    fputc(' ', outHandle);
					col++;
					tabCol--;
				} else {
					tabCol = -1;
					loc++;
				}
			} else {
				fputc(c, outHandle);
				col++;
				loc++;
			}
		}
	}
	fprintf(outHandle, "\n\r");
}

static void
printFile(register FILE *inHandle, register FILE *outHandle, 
		  char *name, char *fTime)
{
	static char pageBuffer[MAXPAGES][MAXROWS][MAXLINE+1];
	static char titleBuffer[MAXPAGES][MAXLINE+1];

	register 	int		bufPage;
	register 	int		line;
	register 	bool	eof;
	int					page = 1;
	int					col;
	bool				haveRHS;

	do {
		/*
		 *  Read lines upto a full page buffer worth.
		 */
		for (eof = FALSE, bufPage = 0; bufPage < MAXPAGES && !eof; bufPage++)
		{
			/*
			 *  Load a page worth of text.
			 */
			for (line = 0; line < MAXROWS && !eof; line++) 
				eof =  IS_NIL(fgets(pageBuffer[bufPage][line],  
						      MAXLINE, inHandle));
			/*
			 *  Terminate empty part of this page buffer.
			 */
			for (; line < MAXROWS; line++)
				pageBuffer[bufPage][line][0] = EOS;
		}
		haveRHS = bufPage > 1;

		/*
		 *  Terminate empty part of next page if we hit EOF.
		 */
		for (; bufPage < MAXPAGES; bufPage++)
			for (line = 0; line < MAXROWS; line++)
				pageBuffer[bufPage][line][0] = EOS;

		/*
		 *  Output page title text header line.
		 */
		sprintf(titleBuffer[LHS], "%s   File: %-39sPage %3d", 
				fTime, name, page);
		sprintf(titleBuffer[RHS], "%s   File: %-39sPage %3d", 
				fTime, name, page + 1);
		printLines(outHandle, titleBuffer[LHS],
				   haveRHS ? titleBuffer[RHS] : eosPtr, FALSE);

		/*
		 *  Add in header division underline.
		 */
		for (col = 0; col < UNDERWIDTH; col++)
			titleBuffer[LHS][col] = UNDERCHAR;
		titleBuffer[LHS][col] = EOS;
		printLines(outHandle, titleBuffer[LHS], 
				   haveRHS ? titleBuffer[LHS] : eosPtr,  FALSE);
		fprintf(outHandle, "\n\n\r");

		/*
		 *  Output page text contents.
		 */
		for (line = 0;  line < MAXROWS && pageBuffer[LHS][line] != EOS; 
		     line++) {
			printLines(outHandle, pageBuffer[LHS][line],
					   pageBuffer[RHS][line], TRUE);
		}

		/*
		 *  Eject page and advance page count.
		 */
		fputc('\f', outHandle);
		page += 2;
	} while (!eof);
}

static char *
fileTime(long time)
{
	return asctime(gmtime(&time));
}

static char *
sysTime(long time)
{
	return ctime(&time);
}

void
main(int argc, char **argv)
{
	FILE		*fh;
	FILE		*oh;
	char	   	*timeString;

	printf("\x9b1mDJ Ver 1.0\x9b0m (c) 1990 Jeff Kunzelman.\n");

	if (IS_NIL(oh = fopen("par:", "w"))) {
		fprintf(stderr, "Cannot open PAR: device for output.\n");
		exit(1);
	}

	initPrinter(oh);

	if (argc == 1) {
		timeString = sysTime(time(NULL));
		timeString[strlen(timeString) - 1] = EOS; /* strip \n from string */
		printFile(stdin, oh, "Standard Input", timeString);
	} else for (argc--, argv++; argc; argc--, argv++) {
		fh = fopen(*argv, "r");
		if (!IS_NIL(fh)) {
			timeString = fileTime(getft(*argv));
			timeString[strlen(timeString) - 1] = EOS; 
			printf("Printing: %s...\n", *argv);
			printFile(fh, oh, *argv, timeString); 
			fclose(fh);
		} else
			fprintf(stderr, "Cannot open %s.\n", *argv);
	}

	resetPrinter(oh);
	exit(0);
}
