/* pcprint.c -- Print files on a printer which is locally attached to a DEC 
 * VT102, VT200, VT300, or compatible, or to a PC that emulates them (e.g. IBM 
 * PC with Kermit 2.31 or later).
 *
 * Usage:
 *   command | pcprint
 *   pcprint < file
 *   pcprint file(s)
 * and in MM, "set print-filter pcprint", then use MM's "print" command.
 *
 * "pcprint" allows printing of text files and binary files with no parity.
 * To do this, the terminal has to be put in "raw mode", in which none of its
 * other functions work.  Therefore, the terminal is periodically restored to
 * normal so that it can be interrupted with Ctrl-C, do Xon/Xoff, etc.
 *
 * Authors: Christine Gianone and Frank da Cruz, CUCCA, March 14, 1989
 */

/* Preprocessor includes and defines */

#include <stdio.h>			/* Standard i/o */
#include <sgtty.h>			/* Set/Get terminal modes */
#include <signal.h>			/* For keyboard interrupts */
#include <sys/types.h>			/* For stat.h... */
#include <sys/stat.h>			/* For file status queries */
#define BUFL 1000			/* Input buffer length */

/* Global Declarations */

static struct sgttyb old, new;		/* Terminal modes structure */
static struct stat statbuf;		/* File status structure */
int fd;					/* Input file descriptor */
int doexit();				/* Forward declaration of doexit() */

/* Main function */

main(argc,argv) int argc; char *argv[]; {
    int nf;				/* File number from command line. */
    int x;				/* Temporary variable. */

/* Find out the current terminal settings from Unix */

    gtty(1,&old);			/* For restoring tty to how it was. */
    gtty(1,&new);			/* Plus a new copy, */
    new.sg_flags |= RAW;		/* for putting tty in "raw mode" */
					/* to allow 8-bit data output */
					/* with no parity. */

/* Send the ANSI "begin transparent print" sequence, "ESC [ 5 i".  This */
/* makes the terminal send its input to the printer instead of the screen. */

    printf("%c[5i",'\033');		/* Print the escape sequence. */
    fflush(stdout);			/* Make sure it goes out */
					/* before we change tty modes. */

/* Since programs can be halted by users typing Ctrl-C or other keyboard */
/* interrupt characters, we must catch these interrupts in order to restore */
/* the terminal to normal (non-printing, non-raw) mode before exiting. */

    signal(SIGINT,doexit);		/* Control-C */
    signal(SIGQUIT,doexit);		/* Control-\ */

/* Input can either be from standard input (redirected stdin, pipe, or MM */
/* PRINT command), or else from a list of files given on the command line. */

/* Case 1: Print from Standard Input, e.g. "pcprint < test.txt". */

    if (argc == 1) {			/* If printing from standard input */
	fd = 0;				/* File descriptor 0 = stdin */
	dofile();			/* Print until no more data */
	doexit();			/* Done */
    }

/* Case 2: Filename(s) specified on command line, e.g. "pcprint x.a x.b". */
/* Each file must be opened, printed, & closed.  Skip over directory files. */

    nf = 0;				/* Current file number. */
    while (++nf < argc) {		/* Start with file 1, if any .*/
	if (stat(argv[nf],&statbuf) < 0) /* First see if the file exists. */
	  continue;			/* Doesn't exist, try next one. */
	x = statbuf.st_mode & S_IFMT;	/* Check file format. */
	if ((x != 0) && (x != S_IFREG))	/* If not a regular file, */
	  continue;			/* try the next file. */
	if ((fd = open(argv[nf]),0) < 0) /* Try to open the file read-only. */
	  continue;			/* On failure, try next file. */
	dofile();			/* Opened OK, call printing function */
	close(fd);			/* and after printing close the file */
    }
    doexit();				/* No more files, clean up and exit. */
}

/* Function to print one file */

dofile() {
    char buf[BUFL];			/* Input buffer */
    int i;				/* Input buffer counter */
    int n;				/* Input character EOF indicator */
    char c;				/* Input character itself */
    int done;				/* Flag for done */

    done = 0;				/* Initial condition for loop. */
    while (!done) {			/* While not done... */
	stty(1,&old);			/* Put terminal in normal mode */
					/* to catch terminal interrupts. */
	for (i = 0; i < BUFL-1; i++) {  /* Loop to fill the input buffer. */
	    n = read(fd,&c,1);		/* Read one character. */
	    if (n == 0) {		/* If no more, */
		done = 1;		/* we're done! */
		break;			/* Break out of this for-loop. */
	    }
	    if (c == '\n') 		/* If character is a newline, */
	      buf[i++] = '\r';		/* supply a carriage return. */
	    buf[i] = c;			/* Deposit character in buffer. */
	}
	stty(1,&new);			/* Put tty in raw (no-parity) mode. */
	write(1,buf,i);			/* Request UNIX write the buffer. */
	fflush(stdout);			/* Now make UNIX really do it. */
    }
}

/* Exit function.  Leave user's terminal the way it was upon entry. */
/* Turn off transparent print by sending the escape sequence "ESC [ 4 i". */

doexit() {				/* Program exit. */
    if (fd != 0) close(fd);		/* Close any open input file. */
    signal(SIGINT,SIG_DFL);		/* Return keyboard interrupts */
    signal(SIGQUIT,SIG_DFL);		/* to normal. */
    printf("%c[4i",'\033');		/* Turn off transparent print. */
    fflush(stdout);			/* Make sure it goes out. */
    stty(1,&old);			/* Restore terminal to normal. */
    exit(0);				/* And exit. */
}