File:  [Power 6/32 Unix Tahoe 4.2BSD] / cci / usr / src / usr.bin / bsc / cmd / batch / bscpr.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Sun Jul 28 12:26:12 2019 UTC (7 years ago) by root
Branches: bsd, MAIN
CVS tags: v121, HEAD
Power 6/32 Unix version 1.21

/*	D.L.Buck and Associates, Inc. - 10/16/84
 *
 *	COPYRIGHT NOTICE:
 *		Copyright c 10/16/84 - An unpublished work by 
 *		D.L.Buck and Associates, Inc.
 *
 *	PROPRIETARY RIGHTS NOTICE:
 *		All rights reserved. This document and program contains
 *		proprietary information of D.L.Buck and Associates,Inc.
 *		of San Jose, California, U.S.A., embodying confidential
 *		information,  ideas, and expressions,  no part of which
 *		may be reproduced, or transmitted in any form or by any
 *		means,  electronic,  mechanical,  or otherwise, without
 *		the written permission of D.L.Buck and Associates, Inc.
 *
 * NAME
 *	bscpr -- BISYNC batch file print utility
 *
 * SYNOPSIS
 *	bscpr [-ascii] [-page=pp] [chan=lineno ...] [file]
 *
 * DESCRIPTION
 *	bscpr paginates a file which contains IBM 2780 or 3780 terminal
 *	control characters and escape sequences which control paper motion
 *	on a line printer.
 *
 * ALGORITHM
 *	I. initialize, get options from command line
 *		A. special instructions coded in ASCII or EBCDIC
 *		B. page length
 *		C. channel assignments
 *		D. get and open file, if specified
 *
 *     II. while not at end of file:
 *		A. read a line
 *		B. set character pointer (s1) to beginning of line
 *		C. if s1 points to an ESC character, this is the
 *		   beginning of a special instruction (Escape) sequence.
 *		D. if the next character is an HT (horizontal tab) character:
 *			1. set up tabs in the tab rack according to
 *			   instructions on this line
 *		E. output the line a character at a time, expanding the tabs
 *		   along the way
 *		F. do line feeds
 *
 *    III. close the file
 */

#include <stdio.h>
#include "local.h"

#ifndef lint
static char sccsid[] = "@(#)bscpr.c	1.8 REL";
#endif

#define RCDLN  512	/* max allowed record length */
#define DEFLINES 66	/* default max lines allowed per page */

#define	ESC	0x1b 	/* ASCII escape 				*/
#define	HT	0x09 	/* ASCII Horizontal Tab format effector		*/
#define	VT	0x0b	/* ASCII Vertical Tab format effector		*/
#define	FF	0x0c	/* ASCII Form Feed format effector		*/
#define DC1	0x11	/* select printer code				*/

#define YES 1
#define NO 0
char tabrack[RCDLN];	/* contains horizontal tab positions */
char line[RCDLN];	/* simple data record */
char *index(); 
int channel[13];        /* contains "vertical tabbing" instructions -- line
			numbers on the page corresponding to printer channels */

/* the arrays asctab and ebctab are used to decode vertical tab instructions and
line skip instructions embedded in input lines in ASCII or EBCDIC, respectively.
negative numbers correspond to vertical tab instructions (ESC<alpha> sequences);
e.g. ESC B corresponds to asctab or ebctab -2, meaning "skip to channel 2".
the positive numbers correspond to line skip instructions; 1=skip 1 line, 2=skip
2 lines, 3=skip 3 lines (all after printing the current one).

	       A  B  C	D  E  F  G  H  I   J   K   L M N O P Q R S T U V W X Y*/
int asctab[]={-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,0,1,1,1,1,2,3,1,1,1,1,1,1,
	1}; /* <-Z */

/*	       A  B  C	D  E  F  G  H  I   J   K   L M N O P Q R S T U V W X Y*/
int ebctab[]={-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,0,1,1,1,1,1,2,3,1,1,1,1,1,
	1}; /* <-Z */

int linect = 1;		/* current position on page			*/
int maxlines;		/* maximum # of lines per page */
void exit();

main (argc,argv)
int argc;
char *argv[];
{
	int i;
	int chan;	/* pulled-out channel goes here */
	int lineno;	/* pulled-out line# channel corresponds to goes here */
	int maxused;	/* max line # referred to in chan=line */
	int usedin;	/* chan having max line# above */
	char *pos;
	register char *s1,*s2;
	int ascii;	/* flags ASCII or EBCDIC esc sequence (YES or NO) */
	FILE *bscfile;		/* input file to be paginated		*/
	FILE *fopen();		/* file open function			*/

	bscfile = stdin;	/* default input file is the terminal	*/
	ascii = NO;		/* default transmission code is EBCDIC	*/
	channel[1] = 1; 	/* channel 1 is always top-of-form	*/
	maxlines = channel[12] =DEFLINES;  /* default page length	*/
	maxused = 1;
	usedin = 1;

	for (i=1;i<argc;++i) {	/* get options from command line	*/
                if (strcmp(argv[i],"-ascii") == 0) {
			ascii = YES;
			continue;
		}

		/* pull out maxlines here if in command line */
                if (strncmp(argv[i],"-page=",6) == 0) {
			if (argv[i][6] >= '0' && argv[i][6] <= '9')
				maxlines = atoi(&argv[i][6]);
			else {
				fprintf(stderr,
                                "bscpr: not a numeric <%s>\n",argv[i]);
				exit(1);
			}

			channel[12] = maxlines;
			if (maxused > maxlines) {
                                fprintf(stderr,"%s %d %s\n",
                                "bscpr: line assignment for channel",usedin,
                                "is greater than page length");
				exit(1);
			}
			continue;
		}

		/* get channel assignments */
		if ((pos=index(argv[i],'=')) != NULL) {
			if (argv[i][0] >= '0' && argv[i][0] <= '9' &&
			    pos[1] >= '0' && pos[1] <= '9') {
				chan = atoi(argv[i]);
				lineno = atoi(&pos[1]);
			} else {
				fprintf(stderr,
                                "bscpr: not a numeric <%s>\n",argv[i]);
				exit(1);
			}

			if (chan < 2 || chan > 12) {
				fprintf(stderr,
				"bscpr: channel number not 2 to 12 <%s>\n",
					argv[i]);
				exit(1);
			}
			/* check that assignment's less than page length */
			if (lineno > maxlines) {
                                fprintf(stderr,"%s %d %s\n",
                                "bscpr: line assignment for channel",chan,
                                "is greater than page length");
				exit(1);
			}

			channel[chan] = lineno;
			if (lineno > maxused) {	/* set max line# used */
				maxused = lineno;
				usedin = chan;
			}
			continue;
		}

		/* ...get filename (if any specified)...
		   first check that, if this arg isn't a flag or a
		   channel assignment, that it's the last arg. If it
		   isn't, it's an illegal option specification */


		if (argv[i][0] == '-' || i < argc-1) {
			fprintf(stderr,
				"bscpr: unrecognized option (%s)\n",argv[i]);
			exit(1);
		}

		/* open it if it's okay */
                if ((bscfile=fopen(argv[i],"r")) == NULL) {
			fprintf(stderr,"bscpr: %s not found\n",argv[i]);
			exit(1);
		}
	}

/* now print the file */

	while (fgets(line,(RCDLN),bscfile) != NULL) {
		s1 = line;
		/* Check for Tab Rack: ESC HT .....			*/
		if (s1[0] == ESC && s1[1] == HT) {
			s1 = &line[2];	/* point beyond ESC HT sequence */
			s2 = tabrack;	/* point to beginning of tabrack */

/* set up output tabrack (used to do horizontal tabbing):
   while the input tabrack position != newline, if the input position s1 pts to
   is HT, then the corresponding output position s2 pts to is HT; otherwise,
   output position is ' ' (blank). */

		  while (*s1 != '\n')
			*s2++ = (*s1++ == HT)?HT:' ';

/* NULL-out rest of output tabrack (s2) */
		  while (s2 < &tabrack[RCDLN])
			*s2++ = '\0';

			continue;
		}

		output();

/* do line feeds (dolfs): if line length<2, or there are no special instructions
   for this line (s1 != ESC), or the ESC sequence isn't valid 
   (<alpha> less than A or greater than Z), do single spacing. Otherwise, if 
   this file is ASCII coded, get the number of line feeds to do from 
   asctab(*s1-'A'). If it's EBCDIC coded, get the number of line feeds to do 
   from ebctab(*s1-'A'). */

		if (strlen(line) < 2 || *s1 != ESC ||
		    (*s1 == ESC && (*(s1+1) < 'A' || *(s1+1) > 'Z')))
			dolfs(1);	 /* do single spacing */
		else
			dolfs((ascii?asctab:ebctab)[s1[1]-'A']);
	}
}

/* Here is dolfs -- do linefeeds (lines get hungry too) */
dolfs(action)
register int action;
{
	register int loop;
	register int lfeeds;	/* contains # of line feeds to do */

	if (action == 0) {	/* do carriage return only */
		putchar('\r');
		return;
	}

	if (action > 0) { 	/* output 'action' newlines if positive */
		for (loop=0;loop < action;++loop) {
			putchar('\n');
			++linect;
			if (linect >= maxlines)
				putchar('\f');
		}
		return;
	}

	/* If `action' negative, skip to line given in channel table	*/
	/* If already past that line, skip to top of next page		*/
	if ((lfeeds = channel[-action])) {
		if (linect >= lfeeds) {
			putchar('\r');
			putchar('\f');
			linect = 1;
		}
		while (linect < lfeeds) {
			putchar('\n');
			++linect;
		}
		return;
	}

	putchar('\n');
	++linect;
}
/* Here is output -- the magic tab expander and character-outputter.
 *
 * 1. set lnptr to point to beginning of input line, tabptr to beginning of
 * output tabrack.
 *
 * 2. if the first char lnptr points to is ESC, there are special instructions
 * embedded in the line. Set lnptr to point beyond them (lnptr = &line[2]).
 * Upon return to caller, the ESC will be handled.
 *
 * 3. Until reaching end of line:
 *
 *	a. If char is HT (or '\t'):
 *		 increment tabptr by counter (tabptr += counter) to set it to
 *		 the current output column.
 *
 *		 use tabptr to output blanks until a corresponding HT is
 *		 found in the tabrack.
 *
 *		 set counter back to zero.
 *
 *	b. If char is VT:
 *	   terminate the line, skip to channel 2, then move remainder of
 *	   line to beginning of line and restart.
 *	c. If char is FF:
 *	   terminate the line, skip to channel 1, then move remainder of
 *	   line to beginning of line and restart.
 *	d. If char is NL:
 *	   skip the character ... caller will do newlines as necessary.
 *	e. Otherwise:
 *	   output lnptr's char, increment lnptr, increment counter.
 */

output()
{
	register char *lnptr;	/* points to beginning of line */
	register char *tabptr;	/* points to beginning of tabrack */

	lnptr = line;
	tabptr = tabrack;

	if (*lnptr == DC1)		/* Skip "select printer" 	*/
		++lnptr;
	if (*lnptr == ESC)		/* Skip ESC, command		*/
		lnptr += 2;
	while (*lnptr)	{
		switch(*lnptr) {
		case HT:
			if (*tabptr == HT)
				tabptr++;

			while (*tabptr != HT && *tabptr != '\0') {
				putchar(' ');
				tabptr++;
			}
			tabptr--;
			break;

		case '\n':
			break;

		default:
			putchar(*lnptr);
			break;

		case VT:
			dolfs(-2);
			goto redo;
		case FF:
			dolfs(-1);
redo:
			strcpy(line,++lnptr);
			lnptr = &line[-1];
			tabptr = &tabrack[-1];
			break;
		}
		++lnptr;
		if (*tabptr)
			++tabptr;
	}
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.