File:  [MW Coherent from dump] / coherent / b / bin / troff / output.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:36 2019 UTC (7 years, 2 months ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/*
 * output.c
 * troff
 * Back end to output device-dependent bits for troff.
 * Writes either PCL escape sequences for the Hewlett-Packard LaserJet
 * or (if pflag) PostScript.
 */

#include <ctype.h>
#include "roff.h"

extern	char	*fontname();
extern	char	*ndiv10();

/* HP LaserJet PCL. */
#define	HPLJEJECT	"\033&l0H"	/* page eject			*/

/* PostScript. */
#define	PSLINIT	"90 rotate\n0 -612 translate\n"
#define	PSEJECT	"\nshowpage\n"
#if	ZKLUDGE
#define	PSSAVE1	"/state1 save def\n"
#define	PSREST1	"state1 restore\n"
#endif

/*
 * Device parameters.
 */
int	ntroff	=	TROFF;		/* Programme is TROFF type	*/

long	semmul	=	1;		/* Multiplier for em space	*/
long	semdiv	=	1;		/* Divisor for em space		*/

long	senmul	=	1;		/* Multiplier for en space	*/
long	sendiv	=	2;		/* Divisor for en space		*/

long	shrmul	=	12;		/* Horizontal resolution (mul)	*/
long	shrdiv	=	5;		/* Horizontal resolution (div)	*/

long	sinmul	=	720;		/* Multiplier for inch		*/
long	sindiv	=	1;		/* Divisor for inch		*/

long	snrmul	=	1;		/* Narrow space (mul)		*/
long	snrdiv	=	6;		/* Narrow space (div)		*/

long	svrmul	=	12;		/* Vertical resolution (mul)	*/
long	svrdiv	=	5;		/* Vertical resolution (div)	*/

/*
 * Local variables for output writer.
 */
static	int	hposd;			/* device horizontal postition	*/
static	int	vposd;			/* device vertical position	*/
static	int	inword;			/* in word flag for PostScript	*/
static	int	lastfont = -1;		/* current output font		*/

#if	ZKLUDGE
static	int	npages;			/* Output page count		*/
#endif

/*
 * Initialize the device.
 */
dev_init()
{
#if	ZKLUDGE
	if (Zflag)
		printf(PSSAVE1);
#endif
}

#if	ZKLUDGE
/*
 * Close the device.
 */
dev_close()
{
	if (Zflag != 0)
		printf(PSREST1);
}
#endif

/*
 * Compute the scaled width of a character:
 *	width(c) == unit(swdmul*fonwidt[c]*psz, swddiv).
 */
int
width(c) register int c;
{
	register long l;

	/* Watch out for sign-extension of argument! */
	l = swdmul * fonwidt[c & 0xFF] * psz;
	return (swddiv == 1) ? (int)l : (int)(l/swddiv);
}

/*
 * Given a font number, change to the given font.
 */
dev_font(n) register int n;
{
	register FWTAB	*fp;

#if	0
	fprintf(stderr, "dev_font(%d)\n", n);
#endif
	if (n >= nfonts)
		panic("bad font %d at dev_font, nfonts=%d", n, nfonts);
	curfont = n;
	addidir(DFONT, n);
	fp = fwptab[n];
	csz = fcsz[n];
	swdmul = (long)fp->f_num;
	swddiv = (long)fp->f_den;
	fonwidt = fp->f_width;
	varsp = fp->f_spacing;
	dev_ps(fpsz[n]);
}

/*
 * Change to the given pointsize.
 * There are several different notions of pointsize:
 *	global psz (and oldpsz) in the environment,
 *	fpsz for each font in the environment,
 *	fp->f_psz for each font, and
 *	wpsz in flushl() (see comment below).
 * The font fp->f_psz is used to initialize fpsz in the environment
 * but is subsequently unused.
 * The environment fpsz[n] gives the current pointsize for each font.
 * The environment psz is the pointsize of the current input font,
 * wpsz is the pointsize of the current output font.
 * Changing pointsize with a .ps directive or \s escape
 * changes fpsz[] for each font.
 */
dev_ps(n) register int n;
{
	if (n <= 0) {
		printe("illegal pointsize %d, ignored", n/10);
		return;
	}
	oldpsz = psz;
	psz = n;
	addidir(DPSZE, n);

	/* Scale space width for pointsize change. */
	if (psz != oldpsz && sszdiv != 0)
		ssz = (int)((long)sszmul * psz / sszdiv);
}

/*
 * Set a fixed pointsize for a font.
 */
dev_fz(font, size) char *font, size;
{
	char name[2];
	register int n;

	argname(font, name);
	if ((n = font_number(name, ".fz: ")) < 0)
		return;
	fwptab[n]->f_flags |= F_FIXED;
	fpsz[n] = number(size, SMPOIN, SDPOIN, fpsz[n], 0, fpsz[n]);
	if (n == curfont)
		dev_ps(fpsz[n]);
}

/*
 * Specify a constant size font.
 */
dev_cs(n, size) register int n, size;
{
	fcsz[n] = size;
	if (n == curfont)
		csz = size;
}

/*
 * Change all non-fixed font pointsizes to the given pointsize,
 * then change the current pointsize.
 */
newpsze(n) register int n;
{
	register int i;

	if (n <= 0) {
		printe("illegal pointsize %d, ignored", n/10);
		return;
	}
	for (i = 0; i < nfonts; i++)
		if (((fwptab[i]->f_flags) & F_FIXED) == 0) {
			fwptab[i]->f_flags &= ~F_USED;
			fpsz[i] = n;
		}
	dev_ps(n);
}

/*
 * Given a pointer to a buffer containing stream directives
 * and a pointer to the end of the buffer,
 * print the buffer.
 * The output writer maintains its own notion of current font and pointsize
 * because [nt]roff buffers output and then flushes at the end of a line;
 * the environment "curfont" is the current font for input stream processing,
 * the output writer "font" is the current output stream font.
 * The font change is implicit until a character is written in the new font.
 */
flushl(buffer, bufend) CODE *buffer, *bufend;
{
	register CODE	*cp;
	register int	code;
	int		i;
	char		*tp;
	static	FWTAB	*fp;		/* current font table entry	*/
	static	int	newpage = 1;	/* new page flag		*/
	static	int	hpost;		/* troff horizontal pos (u's)	*/
	static	int	vpost;		/* troff vertical pos (u's)	*/
	static	int	font = -1;	/* current font			*/
	static	unsigned char *wtab;	/* current font width table	*/
	static	long	wnum;		/* current width numerator	*/
	static	long	wden;		/* current width denominator	*/
	static	int	wpsz;		/* current pointsize		*/

	for (cp = buffer; cp < bufend; cp++) {
		code = cp->l_arg.c_code;
		i = cp->l_arg.c_iarg;
		if (pflag && is_dir(code))
			endword();
#if	0
		fprintf(stderr, "output: code=%d arg=%d\n", code, i);
#endif
		switch (code) {
		case DNULL:			/* null code */
		case DHYPH:			/* place to hyphenate */
			continue;
		case DHMOV:			/* move horizontally */
		case DPADC:			/* paddable character */
			hpost += i;
			if (hpost < 0)
				hpost = 0;
			continue;
		case DVMOV:			/* move vertically */
			vpost += i;
			if (vpost < 0)
				vpost = 0;
			continue;
		case DFPOS:			/* fix position */
			move();
			continue;
		case DFONT:			/* change font */
			if (i == font)
				continue;	/* unchanged */
			if ((unsigned)i >= nfonts)
				panic("bad font %d, nfonts=%d", i, nfonts);
			font = i;
			fp = fwptab[font];
			wtab = fp->f_width;
			wpsz = fpsz[font];
			wnum = (long)fp->f_num * wpsz;
			wden = (long)fp->f_den;
			continue;
		case DTRAB:			/* transparent line */
			tp = cp->b_arg.c_bufp;
			while (*tp)
				putchar(*tp++);
			free(cp->b_arg.c_bufp);
			continue;
		case DPSZE:			/* change pointsize */
			if (wpsz != i) {
				wpsz = i;
				wnum = (long)fp->f_num * wpsz;
				if (pflag) {
					/* Mask off used bit to force rescaling */
					lastfont = -1;
					fp->f_flags &= ~F_USED;
				} else {
					printf("\033(s%sV", ndiv10(wpsz));
				}
			}
			continue;
		case DSPAR:			/* space down and return */
			hposd = hpost = 0;
			vpost += i;
			if (vpost < 0)
				vpost = 0;
			else if (vpost >= pgl) {
				/* New page. */
				endpage();
				vpost %= pgl;
				vposd = vpost;
				newpage = 1;
			}
			continue;
		case DHLIN:
		case DVLIN:
			if (code == DHLIN && i < 0) {
				hpost += i;
				i = -i;
			}
			hposd = hpost;
			vposd = vpost;
			move();
			if (code == DHLIN) {
				printf("\n%s 0 L", ndiv10(i));
				hpost += i;
			} else {
				printf("\n0 %s L", ndiv10(-i));
				vpost += i;
			}
			continue;
		default:			/* print something */
			/* Start a new page. */
			if (newpage) {
				if (lflag && pflag)
					printf(PSLINIT);
				hposd = hpost;
				vposd = vpost;
				move();
				newpage = 0;
			}
			/*
			 * Check whether we are on a new page.
			 * Note, the laser goes to funny places when it
			 * crosses a page boundary.
			 */
			if (vpost >= pgl) {
				/* New page. */
				endpage();
				vpost %= pgl;
				vposd = vpost;
				hposd = hpost;
				newpage = 1;
			}
			/* Output move to new position if appropriate. */
			if (hpost != hposd || vpost != vposd) {
				hposd = hpost;
				vposd = vpost;
				move();
			}
			/* Change to different font. */
			if (lastfont != font)
				selectfont(lastfont=font, wpsz);
			if (code == DHYPC)
				code = '-';
			if (code < 0 || code >= NWIDTH)
				panic("bad directive %d", code);
			hpost += cp->c_arg.c_move;
			hposd += unit(wnum*wtab[code], wden);
			i = code;
			if (pflag && !inword)
				startword();
			outchar(code);
			if (enb != 0) {	/* dag's enbolden...	*/
				hposd -= unit(wnum*wtab[i], wden);
				vposd -= enb;
				move();
				putchar(code);
				hposd -= enb;
				move();
				putchar(code);
				vposd += enb;
				putchar(code);
				hposd += (unit(wnum*wtab[i], wden) + enb);
				move();
			}
		}
	}
}

/*
 * Move horizontally and/or vertically.
 * This used to shift PCL output right to avoid printing at left border;
 * that responsibility is now left to the user.
 */
move()
{
	static int vold = -1;

	if (pflag) {
		/* PostScript. */
		if (inword)
			endword();
		printf("\n%s", ndiv10(hposd+pof));
		printf(" %s M", ndiv10(pgl - vposd));
	} else {
		/* PCL. */
		if (vposd == vold)
			printf("\033&a%dH", hposd+pof);
		else
			printf("\033&a%dh%dV", hposd+pof, vposd);
	}
	vold = vposd;
}

/*
 * Select a font.
 */
selectfont(font, ptsize) int font, ptsize;
{
	register FWTAB *fp;
	register char *s;

	fp = fwptab[font];
	if (!pflag) {
		/* Select font via PCL. */
		printf("\033(%d%c", fp->f_symset/32, fp->f_symset%32+64); /* symbol set */
		printf("\033(s%dp", fp->f_spacing);		/* spacing */
		/* fp->f_pitch is in quarterdots/char, convert to chars/inch. */
		if (fp->f_pitch != 0)
			printf("%sh", ndiv10(12000/fp->f_pitch)); /* pitch */
		printf("%sv", ndiv10(fpsz[font]));		/* point size */
		printf("%ds", fp->f_style);			/* style */
		printf("%db", fp->f_weight);			/* stroke weight */
		printf("%dT", fp->f_face);			/* typeface */
		return;
	}
	/* Select font via PostScript. */
	if ((s = fontname(font)) == NULL)
		panic("botch: fontname(%d)", font);
	endword();
	if ((fp->f_flags & F_USED) == 0) {
		fp->f_flags |= F_USED;
		printf("\n"
			"/font%s /%s findfont %d.%d scalefont def\n"
			"/f%s { font%s setfont } bind def\n",
			s, fp->f_PSname,
			ptsize / 10, ptsize % 10,
			s, s);
	}
	printf(" f%s", s);
}

/*
 * Convert e.g. 123 to "12.3" without using floating point output.
 * Return a pointer to statically allocated buffer.
 */
char *
ndiv10(n) register int n;
{
	static char buf[10];
	register char *cp;

	cp = buf;
	if (n < 0) {
		n = -n;
		*cp++ = '-';
	}
	if ((n % 10) == 0)
		sprintf(cp, "%d", n/10);
	else
		sprintf(cp, "%d.%d", n/10, n%10);
	return buf;
}

/*
 * Output a character.
 * If writing PostScript output, watch out for "()\\"
 * and expand high-bit characters to octal escapes.
 */
outchar(n) register int n;
{
	if (pflag) {
		if (n >= 128) {
			printf("\\%03o", n);
			return;
		} else if (n == '(' || n == ')' || n == '\\')
			putchar('\\');
	}
	putchar(n);
}

startword()
{
	putchar(' ');
	putchar('(');
	inword = 1;
}

endword()
{
	if (inword) {
		printf(") S");
		inword = 0;
	}
}

endpage()
{
	if (pflag)
		endword();
	printf((pflag) ? PSEJECT : HPLJEJECT);
#if	ZKLUDGE
	if (Zflag && ++npages % Zflag == 0) {
		register int i;

		printf(PSREST1);
		printf(PSSAVE1);
		for (i = 0; i < nfonts; i++)
			fwptab[i]->f_flags &= ~F_USED;
		lastfont = -1;
		dev_font(curfont);
	}
#endif
}

/* end of output.c */

unix.superglobalmegacorp.com

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