/* print.c


	simple print file utility for less by: Bob Leivian

	print -nh^ld#99|99t9wp:<string> file1 {-nh...}file2 file3 ...

	this is designed to be called from the less with the
	expanded list of files to print with a option list
*/

#include <stdio.h>
#include <ctype.h>
long Open();
#define MODE_OLDFILE 1005L
#define MODE_NEWFILE 1006L
long std_out;
extern char prog_name[];

/* this can be set with options */
int numbers = 0;
int headers = 0;
int control = 0;
int prefix = 0;
int lines_per_page = 0;
int chars_per_line = 0;
int tab_stops = 0;

long printer = 0;


start_print(my_argc, my_argv)
int my_argc;
char *my_argv[];
{
	int i;
	char *p;
	char name[30];
	char theprefix [30];
	char c;

	if (printer == 0) {
		printer = Open("PRT:", MODE_NEWFILE);
		if (!printer) exit(27);
	}

	while (my_argv[1]) {
		/* process options if any */
		while (*my_argv[1] == '-') {
			p = (char *) &*my_argv[1];

			p++;		/* point to the option chars */
			do {
				switch (*p) {
				case ' ':
				case '\0':		/* ignore nulls and spaces */
					break;

				case 'p': case 'P':		/* turn on proportional mode */
					Write(printer, "\x1b[2p", 3L);
					break;

				case 'c': case 'C':		/* turn on compressed mode */
					Write(printer, "\x1b[4w", 4L);
					break;

				case 'u': case 'U':		/* turn on uncompressed  mode */
					Write(printer, "\x1b[3w", 4L);
					break;

				case 'l': case 'L':		/* turn on letter quality mode */
					Write(printer, "\x1b[2\"z", 5L);
					break;

				case 'd': case 'D':		/* turn on draft mode */
					Write(printer, "\x1b[1\"z", 5L);
					break;

				case ':':		/* print control string first */
					strcpy(theprefix, ++p);
					prefix++;
					goto next; /* consume rest of option */

				case '^':		/* print control chars as ^X */
					control++;
					break;

				case 't': case 'T':		/* set tab stops */
					p++;
					if (isdigit(*p)) 
						tab_stops = *p - '0';
					else {
						tab_stops = 8;
						p--;
					}
					break;

				case '#':				/* set lines per page */
					p++;
					lines_per_page = 0;
					while(isdigit(*p)) {
						lines_per_page *= 10;
						lines_per_page += (*p++ - '0');
					}
					p--;
					break;

				case '|':				/* set chars per line */
					p++;
					chars_per_line = 0;
					while(isdigit(*p)) {
						chars_per_line *= 10;
						chars_per_line += (*p++ - '0');
					}
					p--;
					break;

				case 'n': case 'N':		/* print line numbers */
					numbers++;
					break;

				case 'h':		/* print a header */
					headers++;
					break;

				default:
					/* ignore invalid stuff for now */;
				}
				p++; 
			} while (*p);
	next:
			my_argc--;
			my_argv++;
		}

		/* put out the control prefix if any */
		if (prefix) {
			p = theprefix;
			while(*p) {
				if (*p == '^') { 
					p++;
					c = *p - '@';
					Write(printer, &c, 1L);
				} else
					Write(printer, *p, 1L);
				p++;
			}

			/* reset the prefix flag */
			prefix = 0;
		}

		/* now print the file */
		print_one_file(my_argv[1]);
		my_argv++;
	}
	Close(printer);
	printer = 0;
}

static char buf[1024];			/* Note! if called from WB we have */
static char outbuf[1024+100];	/*  very limited stack space       */

/* do the actual print for a file */
print_one_file(name)
char *name;
{
	long in;
	long bytes, Read();

	register long outbytes;
	register char *p;

	int line;
	int page;
	int num_lines;
	int new_line;
	int chars;

	char line_buf[10];
	char ctl[4];
	int i;

	in = Open(name, MODE_OLDFILE);

	if (!in) {
		sprintf(buf, "unable to open: '%s'\f", name);
		Write(printer, buf, (long) strlen(buf));
		return;
	}

	line = 1;
	page = 1;

	/* print a file header if desired */
	if (headers) {
		sprintf(buf, "File: %s    Page %d\n\n", name, page);
		Write(printer, buf, (long) strlen(buf));
		num_lines = 3;
	} else
		num_lines = 1;

	if (numbers || control || lines_per_page || chars_per_line) {

		outbytes = 0;
		if (numbers) {
			sprintf(outbuf, "%4d ", line);
			outbytes = strlen(outbuf);
			chars = outbytes;
		}

		/* now read the file a block at a time */
		while(bytes = Read(in, buf, 1024L)) {
			p = buf;
			if (bytes < 0) {
				sprintf(buf, "Error reading file: %s\n", name);
				Write(printer, buf, (long) sizeof(buf));
				return;
			}

			/* now write out this block */
			while(bytes) {
				/* check for control chars, if requested */
				if (control) {
					if ((*p < ' ')&&(*p != '\n')&&(*p != '\t')){
						/* print all other control chars in ^A format */
						outbuf[outbytes++] = '^';
						*p += '@';
						chars++;
					}
				}

				/* check for a new line */
				if ((*p == '\n')||(*p == '\f')) {
					/* newline, need a page break? */
					if (((*p == '\f') && (!control)) ||
						(lines_per_page && (num_lines >= lines_per_page))) {

						/* is this a user formfeed */
						if (*p == '\f') {
							sprintf(buf, "<form feed>\f");
							strcpy(&outbuf[outbytes], buf);
							outbytes += strlen(buf);
							line--;
						} else
							outbuf[outbytes++] = '\f';

						/* print a file header if desired */
						page++;
						if (headers) {
							sprintf(buf, "File: %s    Page %d\n\n",
								    name, page);
							strcpy(&outbuf[outbytes], buf);
							outbytes += strlen(buf);
							num_lines = 2;
						} else
							num_lines = 0;
					}
					line++;
					num_lines++;
					new_line = 1;
				} else
					new_line = 0;

				/* now put the character and account for it */
				chars++;
				bytes--;
				switch (*p) {
				case '\t':
					if (tab_stops) {
						if ((chars % tab_stops) == 0) {
							for(i=0; i < tab_stops; i++) {
								outbuf[outbytes++] = ' ';
								chars++;
							}
						} else 
							while(chars % tab_stops) {
								outbuf[outbytes++] = ' ';
								chars++;
							}
						p++;
					} else {
						while(chars % 8) chars++;
						outbuf[outbytes++] = *p++;
					}
					break;

				case '\f':	/* formfeeds are accounted for eariler */
					p++;
					break;

				case 8:
					chars--;
					outbuf[outbytes++] = *p++;
					break;

				default:
					outbuf[outbytes++] = *p++;
				}

				/* check for line overflow, if requested */
				if (chars_per_line && (chars >= chars_per_line)) {
					outbuf[outbytes++] = '\n';
					num_lines++;
					if (numbers) {
					    strcpy(&outbuf[outbytes], "     ");
						outbytes += 5;
						chars = 5;
					} else
						chars = 0;
				}

				/* now put out the line number if needed */
				if (new_line && numbers) {
					sprintf(&outbuf[outbytes], "%4d ", line);
					outbytes += 5;
					chars = 5;
				}

				/* dump the buffer if near full */
				if (outbytes >= 1000L) {
					Write(printer, outbuf, outbytes);
					outbytes = 0;
				}
			} /* while chars in this block */
		} /* while not EOF */

		/* flush last line */
		if (outbytes) 
			Write(printer, outbuf, outbytes);
	} else {
		/* we can just pump out the data untouched */
		while(bytes = Read(in, buf, 1024L))
			if (bytes > 0)
				Write(printer, buf, bytes);
			else {
				sprintf(buf, "Error reading file");
				Write(printer, buf, (long) sizeof(buf));
			}

	}
	Write(printer, "\f", 1L);
	Close(in);
	in = 0;
}

set_up_print(name)
char *name;
{
	long save;
	extern long tty;
	extern char **av;
	extern int called_from_WB;
	extern long current_dir;
	char option_string[80];
	char numbuf[16];
	char c;
	int i;
	char buf[100];
	long result, Execute();
	int fake_argc;
	char *fake_argv[4];

   /* 
    * print the current file
    */

	save = tty;

	/* first make sure we can get the printer */
	printer = Open("PRT:", MODE_NEWFILE);
	if (!printer) {
		error("can't access the printer at this time");
	} else {

		/* printer is avail so... */
		tty = Open("RAW:100/50/470/100/Less's print server", MODE_NEWFILE);
		if (!tty) {
		 	tty = save;
			Close(printer);
			printer = 0;
			error("Can't open window!");
			return;
		}

		ttputs("Print File: ");
		ttputs(name);
		ttputs("\nEnter the first letter of each option, if any\n");
		ttputs("For example 'nh#60|80t8^l', the options are...\n");
		so_enter();
		ttputs("numberedlines headers ^ctrl proportional         \n");
		ttputs("letterquality draft wide uncompressed            \n");
		ttputs("#<num> of rows, |<num> of columns, t<num> tabstop\n");
		so_exit();
		ttputs("\nOptions or 'q' to quit? ");

		/* get a responce */
		i = 0;
		while (c = ttgetc()) {
			if (c == 8) { /* backspace ? */
				if (i > 0) {
					i--;
					ttputc(c);
				}
			} else {
				if ((c < ' ') || (i > 32)) break;
				option_string[i++] = c;
				ttputc(c);
			}
		}
		option_string[i] = 0;

        if(toupper(option_string[0]) != 'Q') {

			if (called_from_WB) {
/* I haven't figured out how to queue from WB */
#ifndef WB_QUEUED
				if (option_string[0]) {
					sprintf(buf, "-%s", option_string);
					fake_argc = 3;
					fake_argv[1] = buf;
					fake_argv[2] = name;
				} else {
					fake_argc = 2;
					fake_argv[1] = name;
				}
				fake_argv[fake_argc] = NULL;

				ttputs("\nPrinting...\n");
				start_print(fake_argc, fake_argv);
				ttputs("Complete!\n");
#else
				/* this should work but I can't figure out why not */
				sprintf(buf, "RUN %s -p %ld ", prog_name, current_dir); 

				if (option_string[0]) {
					strcat(buf, "-");
					strcat(buf, option_string);
					strcat(buf, " ");
				}
				strcat(buf, name);

				/* give up the printer */
				Close(printer);
				printer = 0;

				/* and execute the job */
				std_out = Open("NIL:", MODE_OLDFILE);
				result = Execute(buf, 0L, std_out);
				if (result) {
					ttputs("\nJob queued\n");
				} else {
					sprintf(buf, "\nError on Execute: %ld", result);
					ttputs(buf);
				}
#endif
			} else {
				/* from CLI, queue it  to a copy of myself */
				sprintf(buf, "RUN %s -p ", prog_name); 

				if (option_string[0]) {
					strcat(buf, "-");
					strcat(buf, option_string);
					strcat(buf, " ");
				}
				strcat(buf, name);

				/* give up the printer */
				Close(printer);
				printer = 0;

				/* and execute the job */
				result = Execute(buf, 0L, 0L);
				if (result) {
					ttputs("\nJob queued\n");
				} else {
					sprintf(buf, "\nError on Execute: %ld", result);
					ttputs(buf);
				}
			}
		} else {
			Close(printer);
			printer = 0;
			ttputs("\nPrint request canceled by user!\n");
		}

		Delay(100L);
		ttclose();
		tty = save;
	}
}

