V8/usr/src/cmd/troff/Drivers/dsort.c

Compare this file to the similar file:
Show the results in this format:

/*
 *	dsort
 *
 *	sort troff output into troff output that only goes one
 *	direction down the page.
 *	caveat user:
 *		there are bugs herein
 *		it doesn't do anything with graphics like \D'...'
 */

/*
output language from troff:
all numbers are character strings

sn	size in points
fn	font as number from 1-n
cx	ascii character x
Cxyz	funny char xyz. terminated by white space
Hn	go to absolute horizontal position n
Vn	go to absolute vertical position n (down is positive)
hn	go n units horizontally (relative)
vn	ditto vertically
nnc	move right nn, then print c (exactly 2 digits!)
		(this wart is an optimization that shrinks output file size
		 about 35% and run-time about 15% while preserving ascii-ness)
Dt ...\n	draw operation 't':
	Dl x y		line from here by x,y
	Dc d		circle of diameter d with left side here
	De x y		ellipse of axes x,y with left side here
	Da x y r	arc counter-clockwise by x,y of radius r
	D~ x y x y ...	wiggly line by x,y then x,y ...
nb a	end of line (information only -- no action needed)
	b = space before line, a = after
p	new page begins -- set v to 0
#...\n	comment
x ...\n	device control functions:
	x i	init
	x T s	name of device is s
	x r n h v	resolution is n/inch
		h = min horizontal motion, v = min vert
	x p	pause (can restart)
	x s	stop -- done for ever
	x t	generate trailer
	x f n s	font position n contains font s
	x H n	set character height to n
	x S n	set slant to N

	Subcommands like "i" are often spelled out like "init".
*/

#include	<stdio.h>
#include	<ctype.h>

#define	FATAL	1
int	dbg	= 0;
int	res;		/* input assumed computed according to this resolution */
int	size	= 0;	/* current size */
int	font	= 0;	/* current font */
int	hpos;		/* horizontal position where we are supposed to be next (left = 0) */
int	vpos;		/* current vertical position (down positive) */
int	horig;		/* h origin of current block; hpos rel to this */
int	vorig;


main(argc, argv)
char *argv[];
{
	FILE *fp;
	int i;
	int done();
	extern int obufsize;

	while (argc > 1 && argv[1][0] == '-') {
		switch (argv[1][1]) {
		case 'd':
			dbg = atoi(&argv[1][2]);
			if (dbg == 0) dbg = 1;
			obufsize = 50;
			break;
		}
		argc--;
		argv++;
	}
	if (argc <= 1)
		conv(stdin);
	else
		while (--argc > 0) {
			if (strcmp(*++argv, "-") == 0)
				fp = stdin;
			else if ((fp = fopen(*argv, "r")) == NULL)
				error(FATAL, "can't open %s", *argv);
			conv(fp);
			fclose(fp);
		}
	done();
}

/* new data declarations go here */
struct vlist {
	int	v;
	int	h;
	int	s;
	int	f;
	char	*p;
};

#define	NVLIST	1500
struct	vlist	vlist[NVLIST + 1];
struct	vlist	*vlp	= vlist;
int	nvlist	= 0;
#define	OBUFSIZE	32000
int	obufsize	= OBUFSIZE;
#define	SLOP		500
char	obuf[OBUFSIZE + SLOP];
char	*op	= obuf;

conv(fp)
register FILE *fp;
{
	register int c, k;
	int m, n, i, n1, m1;
	char str[100], buf[300];

	while ((c = getc(fp)) != EOF) {
		if(dbg)fprintf(stderr, "%c i=%d V=%d\n", c, op-obuf, vpos);
		pause();
		if (op >= obuf + obufsize)
			oflush();
		switch (c) {
		case '\n':	/* when input is text */
		case ' ':
			*op++ = c;
			break;
		case '{':	/* push down current environment */
			*op++ = c;
			t_push();
			break;
		case '}':
			*op++ = c;
			t_pop();
			break;
		case '0': case '1': case '2': case '3': case '4':
		case '5': case '6': case '7': case '8': case '9':
			/* two motion digits plus a character */
			*op++ = c;
			*op++ = getc(fp);
			hmot((op[-2]-'0') * 10 + op[-1] - '0');
			*op++ = getc(fp);
			break;
		case 'c':	/* single ascii character */
			*op++ = c;
			*op++ = getc(fp);
			break;
		case 'C':
			*op++ = c;
			while ((c = getc(fp)) != ' ' && c != '\n')
				*op++ = c;
			ungetc(c, fp);
			break;
		case 't':	/* straight text */
			*op++ = c;
			fgets(op, SLOP, fp);
			op += strlen(op);
			break;
		case 'D':	/* draw function */
			*op++ = c;
			fgets(op, SLOP, fp);
			switch (*op) {
			case 'l':	/* draw a line */
				sscanf(op+1, "%d %d", &n, &m);
				hmot(n);
				break;
			case 'c':	/* circle */
				sscanf(op+1, "%d", &n);
				hmot(n);
				break;
			case 'e':	/* ellipse */
				sscanf(op+1, "%d %d", &m, &n);
				hmot(m);
				break;
			case 'a':	/* arc */
				sscanf(op+1, "%d %d %d", &n, &m, &n1);
				hmot(n);
				break;
			case '~':	/* wiggly line */
				hmot(0);	/* bug */
				break;
			default:
				error(FATAL, "unknown drawing function %s\n", buf);
				break;
			}
			op += strlen(op);	/* skip over new stuff */
			break;
		case 's':
			*op++ = c;
			fscanf(fp, "%s", op);	/* ignore fractional sizes */
			size = atoi(op);
			op += strlen(op);
			break;
		case 'f':
			*op++ = c;
			fscanf(fp, "%s", op);
			font = atoi(op);
			op += strlen(op);
			break;
		case 'H':	/* absolute horizontal motion */
			/* fscanf(fp, "%d", &n); */
			*op++ = c;
			while ((c = getc(fp)) == ' ')
				;
			k = 0;
			do {
				*op++ = c;
				k = 10 * k + c - '0';
			} while (isdigit(c = getc(fp)));
			ungetc(c, fp);
			hgoto(k);
			break;
		case 'h':	/* relative horizontal motion */
			/* fscanf(fp, "%d", &n); */
			*op++ = c;
			while ((c = getc(fp)) == ' ')
				;
			k = 0;
			do {
				*op++ = c;
				k = 10 * k + c - '0';
			} while (isdigit(c = getc(fp)));
			ungetc(c, fp);
			hmot(k);
			break;
		case 'w':
			break;
		case 'V':
			*op++ = 0;
			if (vlp >= vlist + NVLIST) {
				oflush();
			}
			vlp->p = op;
			*op++ = c;
			fscanf(fp, "%s", op);
			n = atoi(op);
			vgoto(n);
			op += strlen(op);
			vlp->v = vpos;
			vlp->h = hpos;
			vlp->s = size;
			vlp->f = font;
			vlp++;
			nvlist++;
			break;
		case 'v':
			*op++ = c;
			fscanf(fp, "%d", &n);
			vmot(n);
/* punt for now, since never occurs */
			break;
		case 'p':	/* new page */
			vpos = 0;
			oflush();
			*op++ = c;
			fscanf(fp, "%s", op);
			op += strlen(op);
			break;
		case 'n':	/* end of line */
			*op++ = c;
			while ((*op++ = getc(fp)) != '\n')
				;
			hpos = 0;
			break;
		case '#':	/* comment */
			*op++ = c;
			while ((*op++ = getc(fp)) != '\n')
				;
			break;
		case 'x':	/* device control */
			oflush();
			putchar(c);
			fgets(buf, sizeof buf, fp);
			fputs(buf, stdout);
			fflush(stdout);
			break;
		default:
			error(!FATAL, "unknown input character %o %c\n", c, c);
			done();
		}
	}
}

pause(i, j, k)
{
}

oflush()	/* sort, then dump out contents of obuf */
{
	char *p;
	struct vlist *vp;
	int i;
	int compar();

	if(dbg)fprintf(stderr, "into oflush, V=%d\n", vpos);
	if (op == obuf)
		return;
 	qsort((char *) vlist, nvlist, sizeof (struct vlist), compar);
	*op++ = 0;
	vp = vlist;
	printf("V%d\n",  vp->v);
	for (i = 0; i < nvlist; i++, vp++) {
		printf("H%ds%df%d\n", vp->h, vp->s, vp->f);
		for (p = vp->p; *p != 0; p++)
			putchar(*p);
	}
	fflush(stdout);
	vlp = vlist;
	vlp->p = op = obuf;
	sprintf(op, "V%dH%d\n", vpos, hpos);
	op += strlen(op);
	vlp->h = hpos;
	vlp->v = vpos;
	vlp->s = size;
	vlp->f = font;
	*op = 0;
	vlp++;
	nvlist = 1;
}


compar(p1, p2)
struct vlist *p1, *p2;
{
	return(p1->v - p2->v);
}

done()
{
	oflush();
	exit(0);
}

error(f, s, a1, a2, a3, a4, a5, a6, a7) {
	fprintf(stderr, "dsort: ");
	fprintf(stderr, s, a1, a2, a3, a4, a5, a6, a7);
	fprintf(stderr, "\n");
	if (f)
		done();
}

#define	MAXSTATE	5

struct state {
	int	ssize;
	int	sfont;
	int	shpos;
	int	svpos;
	int	shorig;
	int	svorig;
};
struct	state	state[MAXSTATE];
struct	state	*statep = state;

t_push()	/* begin a new block */
{
	statep->ssize = size;
	statep->sfont = font;
	statep->shorig = horig;
	statep->svorig = vorig;
	statep->shpos = hpos;
	statep->svpos = vpos;
	horig = hpos;
	vorig = vpos;
	hpos = vpos = 0;
	if (statep++ >= state+MAXSTATE)
		error(FATAL, "{ nested too deep");
	hpos = vpos = 0;
}

t_pop()	/* pop to previous state */
{
	if (--statep < state)
		error(FATAL, "extra }");
	size = statep->ssize;
	font = statep->sfont;
	hpos = statep->shpos;
	vpos = statep->svpos;
	horig = statep->shorig;
	vorig = statep->svorig;
}

t_page(n)	/* do whatever new page functions */
{
	int i;

	vpos = 0;
}

hgoto(n)
{
	hpos = n;	/* this is where we want to be */
			/* before printing a character, */
			/* have to make sure it's true */
}

hmot(n)	/* generate n units of horizontal motion */
int n;
{
	hgoto(hpos + n);
}

vgoto(n)
{
	vpos = n;
}

vmot(n)	/* generate n units of vertical motion */
int n;
{
	vgoto(vpos + n);	/* ignores rounding */
}