130195Sdenise #ifndef lint
2*30592Sdenise static char sccsid[] = "@(#)nvsort.c	1.4 (CWI) 87/03/05";
330195Sdenise #endif
430195Sdenise /*
530195Sdenise  * from (Berkeley):
630195Sdenise  *    vsort.c	1.11	84/05/29
730194Sdenise  *
830194Sdenise  *	Sorts and shuffles ditroff output for versatec wide printer.  It
930194Sdenise  *	puts pages side-by-side on the output, and fits as many as it can
1030194Sdenise  *	on one horizontal span.  The versatec driver sees only pages of
1130194Sdenise  *	full width, not the individual pages.  Output is sorted vertically
1230194Sdenise  *	and bands are created NLINES pixels high.  Any object that has
1330194Sdenise  *	ANY part of it in a band is put on that band.
1430194Sdenise  *
1530194Sdenise  *	Jaap Akkerhuis
1630194Sdenise  *	de-Berkletized by #ifdef BERK
1730194Sdenise  */
1830194Sdenise 
1930194Sdenise 
2030194Sdenise #include	<stdio.h>
2130194Sdenise #include	<ctype.h>
2230194Sdenise #include	<math.h>
2330194Sdenise 
2430194Sdenise 
2530194Sdenise /* #define DEBUGABLE	/* compile-time flag for debugging */
2630194Sdenise #define	FATAL	1
2730194Sdenise #define	NVLIST	3000	/* size of list of vertical spans */
2830194Sdenise #define	OBUFSIZ	250000	/* size of character buffer before sorting */
2930194Sdenise #define	SLOP	1000	/* extra bit of buffer to allow for passing OBUFSIZ */
3030194Sdenise #define MAXVECT	200	/* maximum number of points (vectors) in a polygon */
3130194Sdenise 
3230194Sdenise #ifndef FONTDIR
3330194Sdenise #define FONTDIR "/usr/lib/font"
3430194Sdenise #endif FONTDIR
3530194Sdenise 
3630194Sdenise #define POINT	72			/* number of points per inch */
3730194Sdenise 
3830194Sdenise #ifndef VER80
3930194Sdenise #define WIDTH	7040			/* number of pixels across the page */
4030194Sdenise #else
4130194Sdenise #define WIDTH	2112			/* number of pixels across the page */
4230194Sdenise 	/*
4330194Sdenise 	 * Note that this does not work unless the input really is
4430194Sdenise 	 * designed for the versatec, i.e., res = 200.  But that's
4530194Sdenise 	 * OK, because it is only used for side-by-side pages, which
4630194Sdenise 	 * we don't do anyway.
4730194Sdenise 	 * DD
4830194Sdenise 	 */
4930194Sdenise #endif VER80
5030194Sdenise 
5130194Sdenise #define BAND	2.2			/* length of each band in inches */
5230194Sdenise #define NLINES	(int)(BAND * inch)	/* number of pixels in each band */
5330194Sdenise #define HALF	(inch/2)
5430194Sdenise 
5530194Sdenise #define hgoto(n)	if((hpos = leftmarg + n) > maxh) maxh = hpos
5630194Sdenise #define hmot(n)		if((hpos += n) > maxh) maxh = hpos
5730194Sdenise #define vmot(n)		vpos += (n)
5830194Sdenise #define vgoto(n)	vpos = (n)
5930194Sdenise 
6030194Sdenise 
6130194Sdenise int	dbg = 0;	/* debug flag != 0 means do debug output */
6230194Sdenise 
6330194Sdenise int	size	= 10;	/* current size (points) */
6430194Sdenise int	up	= 0;	/* number of pixels that the current size pushes up */
6530194Sdenise int	down	= 0;	/* # of pixels that the current size will hang down */
6630194Sdenise int	font	= 1;	/* current font */
6730194Sdenise char *	fontdir = FONTDIR;	/* place to find DESC.out file	*/
6830194Sdenise int	inch	= 200;	/* resolution of the device, in inches	*/
6930194Sdenise int	thick	= 3;	/* line thickness */
7030194Sdenise 
7130194Sdenise #ifdef BERK
7230194Sdenise int	stip	= 1;	/* current stipple */
7330194Sdenise int	style	= -1;	/* line style bit-mask */
7430194Sdenise #endif BERK
7530194Sdenise 
7630194Sdenise 
7730194Sdenise int	hpos	= 0;	/* horizontal position to be at next (left = 0) */
7830194Sdenise int	vpos	= 0;	/* current vertical position (down positive) */
7930194Sdenise 
8030194Sdenise int	maxh	= 0;	/* farthest right we've gone on the current span */
8130194Sdenise int	leftmarg= 0;	/* current page offset */
8230194Sdenise int	spanno	= 0;	/* current span number for driver in 'p#' commands */
8330194Sdenise int	pageno	= 0;	/* number of pages spread across a physical page */
8430194Sdenise 
8530194Sdenise 
8630194Sdenise struct vlist {
8730194Sdenise 	unsigned short	v;	/* vertical position of this spread */
8830194Sdenise 	unsigned short	h;	/* horizontal position */
8930194Sdenise 	unsigned short	t;	/* line thickness */
9030194Sdenise #ifdef BERK
9130194Sdenise 	short	st;		/* style mask */
9230194Sdenise 	unsigned char	l;	/* stipple number */
9330194Sdenise #endif BERK
9430194Sdenise 	unsigned short	u;	/* upper extent of height */
9530194Sdenise 	unsigned short	d;	/* depth of height */
9630194Sdenise 	unsigned short	s;	/* point size */
9730194Sdenise 	unsigned char	f;	/* font number */
9830216Sdenise 	unsigned short  x;	/* set if this span starts with `x' command */
9930194Sdenise 	char	*p;		/* text pointer to this spread */
10030194Sdenise };
10130194Sdenise 
10230194Sdenise struct	vlist	vlist[NVLIST + 1];
10330194Sdenise struct	vlist	*vlp;			/* current spread being added to */
10430194Sdenise int	nvlist	= 1;			/* number of spreads in list */
10530194Sdenise int	obufsiz	= OBUFSIZ;
10630194Sdenise char	obuf[OBUFSIZ + SLOP];
10730194Sdenise char	*op = obuf;			/* pointer to current spot in buffer */
10830194Sdenise 
10930194Sdenise 
11030194Sdenise 
main(argc,argv)11130194Sdenise main(argc, argv)
11230194Sdenise int argc;
11330194Sdenise char *argv[];
11430194Sdenise {
11530194Sdenise 	FILE *fp;
11630194Sdenise 	double atof();
11730194Sdenise 
11830194Sdenise 
11930194Sdenise 	vlp = &vlist[0];		/* initialize spread pointer */
12030194Sdenise 	vlp->p = op;
12130194Sdenise 	vlp->v = vlp->d = vlp->u = vlp->h = 0;
12230194Sdenise 	vlp->s = size;
12330194Sdenise 	vlp->f = font;
12430194Sdenise #ifdef BERK
12530194Sdenise 	vlp->l = stip;
12630194Sdenise 	vlp->st = style;
12730194Sdenise #endif BERK
12830194Sdenise 	vlp->t = thick;
12930216Sdenise 	/* we don't need added HxxVxxfxsxx for first span */
13030216Sdenise 	vlp->x++;
13130194Sdenise 
13230194Sdenise 	while (argc > 1 && **++argv == '-') {
13330194Sdenise 	    switch ((*argv)[1]) {
13430194Sdenise 		case 'f':
13530194Sdenise 			fontdir = &(*argv)[2];
13630194Sdenise 			break;
13730194Sdenise #ifdef DEBUGABLE
13830194Sdenise 		case 'd':
13930194Sdenise 			dbg = atoi(&(*argv)[2]);
14030194Sdenise 			if (!dbg) dbg = 1;
14130194Sdenise 			break;
14230194Sdenise 		case 's':
14330194Sdenise 			if((obufsiz = atoi(&(*argv)[2])) > OBUFSIZ)
14430194Sdenise 			    obufsiz = OBUFSIZ;
14530194Sdenise 			break;
14630194Sdenise #endif DEBUGABLE
14730194Sdenise 	    }
14830194Sdenise 	    argc--;
14930194Sdenise 	}
15030194Sdenise 
15130194Sdenise 	if (argc <= 1)
15230194Sdenise 	    conv(stdin);
15330194Sdenise 	else
15430194Sdenise 	    while (--argc > 0) {
15530194Sdenise 		if ((fp = fopen(*argv, "r")) == NULL)
15630194Sdenise 		    error(FATAL, "can't open %s", *argv);
15730194Sdenise 		conv(fp);
15830194Sdenise 		fclose(fp);
15930194Sdenise 	    }
16030194Sdenise 	done();
16130194Sdenise }
16230194Sdenise 
16330194Sdenise 			/* read number from input:  copy to output */
16430194Sdenise int
getnumber(fp)16530194Sdenise getnumber (fp)
16630194Sdenise register FILE *fp;
16730194Sdenise {
16830194Sdenise 	register int k;
16930194Sdenise 	register char c;
17030194Sdenise 
17130194Sdenise 	while (isspace(c = getc(fp)))
17230194Sdenise 	    ;
17330194Sdenise 	k = 0;
17430194Sdenise 	if (c == '-') {
17530194Sdenise #ifndef BERK
17630194Sdenise 	    *op++ = c;		/* should be output as well!!! */
17730194Sdenise #endif BERK
17830194Sdenise 	    c = getc(fp);
17930194Sdenise 	    do {
18030194Sdenise 		k = 10 * k - ((*op++ = c) - '0');
18130194Sdenise 	    } while (isdigit(c = getc(fp)));
18230194Sdenise 	} else {
18330194Sdenise 	    do {
18430194Sdenise 		k = 10 * k + (*op++ = c) - '0';
18530194Sdenise 	    } while (isdigit(c = getc(fp)));
18630194Sdenise 	}
18730194Sdenise 	ungetc(c, fp);
18830194Sdenise 	return (k);
18930194Sdenise }
19030194Sdenise 
19130194Sdenise 			/* read number from input:  do _N_O_T copy to output */
19230194Sdenise int
ngetnumber(fp)19330194Sdenise ngetnumber (fp)
19430194Sdenise register FILE *fp;
19530194Sdenise {
19630194Sdenise 	register int k;
19730194Sdenise 	register char c;
19830194Sdenise 
19930194Sdenise 	while (isspace(c = getc(fp)))
20030194Sdenise 	    ;
20130194Sdenise 	k = 0;
20230194Sdenise 	if (c == '-') {
20330194Sdenise 	    c = getc(fp);
20430194Sdenise 	    do {
20530194Sdenise 		k = 10 * k - (c - '0');
20630194Sdenise 	    } while (isdigit(c = getc(fp)));
20730194Sdenise 	} else {
20830194Sdenise 	    do {
20930194Sdenise 		k = 10 * k + c - '0';
21030194Sdenise 	    } while (isdigit(c = getc(fp)));
21130194Sdenise 	}
21230194Sdenise 	ungetc(c, fp);
21330194Sdenise 	return (k);
21430194Sdenise }
21530194Sdenise 
21630194Sdenise 
conv(fp)21730194Sdenise conv(fp)
21830194Sdenise register FILE *fp;
21930194Sdenise {
22030194Sdenise 	register int c;
22130194Sdenise 	int m, n, m1, n1;
22230194Sdenise 
22330194Sdenise 	while ((c = getc(fp)) != EOF) {
22430194Sdenise #ifdef DEBUGABLE
22530194Sdenise 	    if (dbg > 2) fprintf(stderr, "conv: got:<%c>, op-obuf=%d V=%d\n", c, op-obuf, vpos);
22630194Sdenise #endif DEBUGABLE
22730194Sdenise 	    if (op > obuf + obufsiz) {
22830194Sdenise 		error(!FATAL, "buffer overflow %d.", op - (obuf + obufsiz));
22930194Sdenise 		oflush();
23030194Sdenise 	    }
23130194Sdenise 	    switch (c) {
23230194Sdenise 		case '\0':	/* filter out noise */
23330194Sdenise 			break;
23430194Sdenise 		case '\n':	/* let text input through */
23530194Sdenise 		case '\t':
23630194Sdenise 		case ' ':
23730194Sdenise 			*op++ = c;
23830194Sdenise 			break;
23930194Sdenise 		case '{':	/* push down current environment */
24030194Sdenise 			*op++ = c;
24130194Sdenise 			t_push();
24230194Sdenise 			break;
24330194Sdenise 		case '}':	/* pop up last environment */
24430194Sdenise 			*op++ = c;
24530194Sdenise 			t_pop();
24630194Sdenise 			break;
24730194Sdenise 		case '0': case '1': case '2': case '3': case '4':
24830194Sdenise 		case '5': case '6': case '7': case '8': case '9':
24930194Sdenise 				/* two motion digits plus a character */
25030194Sdenise 			setlimit(vpos - up, vpos + down);
25130194Sdenise 			/*
25230194Sdenise 			*op++ = c;
25330194Sdenise 			hmot((c-'0') * 10 + (*op++ = getc(fp)) - '0');
25430194Sdenise 			*op++ = getc(fp);
25530194Sdenise 			 */
25630194Sdenise 			n = ((c - '0') * 10 + ( m = getc(fp)) - '0');
25730194Sdenise 			hmot(n);
25830194Sdenise 			sprintf(op, "%02d", n);
25930194Sdenise 			op += strlen(op);
26030194Sdenise 			*op++ = getc(fp);
26130194Sdenise 			break;
26230194Sdenise 		case 'c':	/* single ascii character */
26330194Sdenise 			setlimit(vpos - up, vpos + down);
26430194Sdenise 			*op++ = c;
26530194Sdenise 			*op++ = getc(fp);
26630194Sdenise 			break;
26730194Sdenise 		case 'C':	/* white-space terminated funny character */
26830194Sdenise 			setlimit(vpos - up, vpos + down);
26930194Sdenise 			*op++ = c;
27030194Sdenise 			do
27130194Sdenise 			    *op++ = c = getc(fp);
27230194Sdenise 			while (c != EOF && !isspace(c));
27330194Sdenise 			break;
27430194Sdenise 		case 't':	/* straight text */
27530194Sdenise 			setlimit(vpos - up, vpos + down);
27630194Sdenise 			*op++ = c;
27730194Sdenise 			fgets(op, SLOP, fp);
27830194Sdenise 			op += strlen(op);
27930194Sdenise 			break;
28030194Sdenise 		case 'D':	/* draw function */
28130194Sdenise 			switch (c = getc(fp)) {
28230194Sdenise 				int skip;
28330194Sdenise #ifdef BERK
28430194Sdenise 			case 's':	/* "style" */
28530194Sdenise 				sprintf(op, "Ds ");
28630194Sdenise 				op += 3;
28730194Sdenise 				style = getnumber(fp);
28830194Sdenise 				break;
28930194Sdenise 
29030194Sdenise 			case 't':	/* thickness */
29130194Sdenise 				sprintf(op, "Dt ");
29230194Sdenise 				op += 3;
29330194Sdenise 				thick = getnumber(fp);
29430194Sdenise 				break;
29530194Sdenise #endif BERK
29630194Sdenise 
29730194Sdenise 			case 'l':	/* draw a line */
29830194Sdenise 				n1 = ngetnumber(fp);
29930194Sdenise 				m1 = ngetnumber(fp);
30030194Sdenise 				n = n1;
30130194Sdenise 				m = m1;
30230194Sdenise 				if (m < 0) {
30330194Sdenise 				    setlimit(vpos+m-thick/2, vpos+thick/2);
30430194Sdenise 				} else {
30530194Sdenise 				    setlimit(vpos-(1+thick/2),vpos+1+m+thick/2);
30630194Sdenise 				}
30730194Sdenise 				sprintf(op, "Dl %d %d", n, m);
30830194Sdenise 				op += strlen(op);
30930194Sdenise 				hmot(n1);
31030194Sdenise 				vmot(m1);
31130194Sdenise #ifndef BERK
31230194Sdenise 				/*
31330194Sdenise 				 * note that this function is actually
31430194Sdenise 				 * Dl n m .
31530194Sdenise 				 * so we have to skip over the ".".
31630194Sdenise 				 *
31730194Sdenise 				 * Rhetoric question: Why doensn't Berkeley
31830194Sdenise 				 * maintain compatability?
31930194Sdenise 				 */
32030194Sdenise 				do{
32130194Sdenise 					skip = getc(fp);
32230194Sdenise 					if( skip == EOF)
32330194Sdenise 						error(FATAL,
32430194Sdenise 						 "Cannot find . in Dl\n");
32530194Sdenise 				}while( skip != '.');
32630194Sdenise #endif BERK
32730194Sdenise 				break;
32830194Sdenise 
32930194Sdenise 			case 'e':	/* ellipse */
33030194Sdenise 				n = ngetnumber(fp);
33130194Sdenise 				m = ngetnumber(fp);
33230194Sdenise 				setlimit(vpos-(m+thick)/2, vpos+(m+thick)/2);
33330194Sdenise 				sprintf(op, "De %d %d", n, m);
33430194Sdenise 				op += strlen(op);
33530194Sdenise 				hmot(n);
33630194Sdenise 				break;
33730194Sdenise 
33830194Sdenise 			case 'c':	/* circle */
33930194Sdenise 				n = ngetnumber(fp);
34030194Sdenise 				setlimit(vpos-(n+thick)/2, vpos+(n+thick)/2);
34130194Sdenise 				sprintf(op, "Dc %d", n);
34230194Sdenise 				op += strlen(op);
34330194Sdenise 				hmot(n);
34430194Sdenise 				break;
34530194Sdenise 
34630194Sdenise 			case 'a':	/* arc */
34730194Sdenise #ifdef BERK
34830194Sdenise 				n = getnumber(fp);
34930194Sdenise 				m = getnumber(fp);
35030194Sdenise 				n1 = getnumber(fp);
35130194Sdenise 				m1 = getnumber(fp);
35230194Sdenise #else
35330194Sdenise 				n = ngetnumber(fp);
35430194Sdenise 				m = ngetnumber(fp);
35530194Sdenise 				n1 = ngetnumber(fp);
35630194Sdenise 				m1 = ngetnumber(fp);
35730194Sdenise #endif BERK
35830194Sdenise 				arcbounds(n, m, n1, m1);
35930194Sdenise 				sprintf(op, "Da %d %d %d %d", n, m, n1, m1);
36030194Sdenise 				op += strlen(op);
36130194Sdenise 				hmot(n + n1);
36230194Sdenise 				vmot(m + m1);
36330194Sdenise 				break;
36430194Sdenise 
36530194Sdenise #ifdef BERK
36630194Sdenise 			case 'P':
36730194Sdenise 			case 'p':
36830194Sdenise 			    {
36930194Sdenise 				register int nvect;
37030194Sdenise 				int member;
37130194Sdenise 				int border;
37230194Sdenise 				int x[MAXVECT];
37330194Sdenise 				int y[MAXVECT];
37430194Sdenise 
37530194Sdenise 
37630194Sdenise 				border = (c == 'p');	/* type of polygon */
37730194Sdenise 				member = ngetnumber(fp);/* and member number */
37830194Sdenise 
37930194Sdenise 				nvect = 1;		/* starting point for */
38030194Sdenise 				x[1] = hpos;		/* points on polygon */
38130194Sdenise 				y[1] = vpos;
38230194Sdenise 				m = n = vpos;		/* = max/min vertical */
38330194Sdenise 							/* position for curve */
38430194Sdenise 				{
38530194Sdenise 				    register int h;
38630194Sdenise 				    register int v;
38730194Sdenise 
38830194Sdenise 
38930194Sdenise 				    h = hpos;	/* calculate max and minimum */
39030194Sdenise 				    v = vpos;		/* vertical position */
39130194Sdenise 							/*    and get points */
39230194Sdenise 				    do {
39330194Sdenise 					h += ngetnumber(fp);
39430194Sdenise 					v += ngetnumber(fp);
39530194Sdenise 
39630194Sdenise 					if (v < n) n = v;
39730194Sdenise 					else if (v > m) m = v;
39830194Sdenise 
39930194Sdenise 					if (nvect < (MAXVECT-1))/* keep the */
40030194Sdenise 					    nvect++;		/* points in */
40130194Sdenise 					x[nvect] = h;		/* bounds */
40230194Sdenise 					y[nvect] = v;		/* of arrays */
40330194Sdenise 					c = getc(fp);
40430194Sdenise 				    } while (c != '\n' && c != EOF);
40530194Sdenise 				}
40630194Sdenise 				if (border) {		/* output border as a */
40730194Sdenise 				    register int *x1;	/*  bunch of lines */
40830194Sdenise 				    register int *x2;	/*  instead of having */
40930194Sdenise 				    register int *y1;	/*  the filter do it */
41030194Sdenise 				    register int *y2;
41130194Sdenise 				    register int extra = thick/2;
41230194Sdenise 
41330194Sdenise 				    x1 = &(x[0]);	/* x1, y1, x2, y2 are */
41430194Sdenise 				    x2 = &(x[1]);	/* for indexing along */
41530194Sdenise 				    y1 = &(y[0]);	/* coordinate arrays */
41630194Sdenise 				    y2 = &(y[1]);
41730194Sdenise 				    for (border = 0; ++border < nvect; ) {
41830194Sdenise 					if (*++y1 > *++y2) {
41930194Sdenise 					   setlimit(*y2-extra, vpos+extra);
42030194Sdenise 					} else {
42130194Sdenise 					   setlimit(vpos-(1+extra),*y2+1+extra);
42230194Sdenise 						/* the extra 1's are to force */
42330194Sdenise 						/* setlimit to know this is a */
42430194Sdenise 						/* real entry (making sure it */
42530194Sdenise 						/* doesn't get vpos as limit */
42630194Sdenise 					}
42730194Sdenise 					sprintf(op, "Dl %d %d\n",
42830194Sdenise 						c = *++x2 - *++x1, *y2 - *y1);
42930194Sdenise 					op += strlen(op);
43030194Sdenise 					hmot(c);	/* update vpos for */
43130194Sdenise 					vgoto(*y2);	/* the setlimit call */
43230194Sdenise 				    }
43330194Sdenise 				} else {
43430194Sdenise 				    register int *x1;	/* x1, x2, are for */
43530194Sdenise 				    register int *x2;	/* indexing points */
43630194Sdenise 				    register int i;	/* random int */
43730194Sdenise 
43830194Sdenise 				    x1 = &(x[0]);
43930194Sdenise 				    x2 = &(x[1]);
44030194Sdenise 				    for (i = 0; ++i < nvect; ) {
44130194Sdenise 					hmot(*++x2 - *++x1);
44230194Sdenise 				    }
44330194Sdenise 				    vgoto(y[nvect]);
44430194Sdenise 				    sprintf(op, "H%dV%d", hpos, vpos);
44530194Sdenise 				    op += strlen(op);
44630194Sdenise 				}
44730194Sdenise 				if (member) {
44830194Sdenise 				    polygon(member, nvect, x, y, m, n);
44930194Sdenise 				}
45030194Sdenise 			    }
45130194Sdenise 			    break;
45230194Sdenise #endif BERK
45330194Sdenise 
45430194Sdenise 			case '~':	/* wiggly line */
45530194Sdenise #ifdef BERK
45630194Sdenise 			case 'g':	/* gremlin curve */
45730194Sdenise #endif BERK
45830194Sdenise 			    startspan(vpos);		/* always put curve */
45930194Sdenise 			    sprintf(op, "D%c ", c);	/* on its own span */
46030194Sdenise 			    op += 3;
46130194Sdenise 
46230194Sdenise 			    m = n = vpos;		/* = max/min vertical */
46330194Sdenise 			    do {			/* position for curve */
46430194Sdenise 				/*
46530194Sdenise 				hpos += getnumber(fp);
46630194Sdenise 				*op++ = ' ';
46730194Sdenise 				vpos += getnumber(fp);
46830194Sdenise 				*op++ = ' ';
46930194Sdenise 				 */
47030194Sdenise 				n1 = ngetnumber(fp);
47130194Sdenise 				m1 = ngetnumber(fp);
47230194Sdenise 
47330194Sdenise 				hmot(n1);
47430194Sdenise 				vmot(m1);
47530194Sdenise 				sprintf(op, "%d %d ", n1, m1);
47630194Sdenise 				op += strlen(op);
47730194Sdenise 
47830194Sdenise 				if (vpos < n) n = vpos;
47930194Sdenise 				else if (vpos > m) m = vpos;
48030194Sdenise 				c = getc(fp);
48130194Sdenise 			    } while (c != '\n' && c != EOF);
48230194Sdenise 
48330194Sdenise 			    vlp->u = n < 0 ? 0 : n;
48430194Sdenise 			    vlp->d = m;
48530194Sdenise 			    *op++ = '\n';
48630194Sdenise 			    startspan(vpos);
48730194Sdenise 			    break;
48830194Sdenise 
48930194Sdenise 			default:
49030194Sdenise 				error(FATAL,"unknown drawing command %c", c);
49130194Sdenise 				break;
49230194Sdenise 			}
49330194Sdenise 			break;
49430194Sdenise 		case 's':
49530194Sdenise 			*op++ = c;
49630194Sdenise 			size = getnumber(fp);
49730194Sdenise 			up = ((size + 1)*inch) / POINT;	/* ROUGH estimate */
49830194Sdenise 			down = up / 3;			/* of max up/down */
49930194Sdenise 			break;
50030194Sdenise 		case 'f':
50130194Sdenise 			*op++ = c;
50230194Sdenise 			font = getnumber(fp);
50330194Sdenise 			break;
50430194Sdenise #ifdef BERK
50530194Sdenise 		case 'i':
50630194Sdenise 			*op++ = c;
50730194Sdenise 			stip = getnumber(fp);
50830194Sdenise 			break;
50930194Sdenise #endif BERK
51030194Sdenise 		case 'H':	/* absolute horizontal motion */
51130194Sdenise 			hgoto(ngetnumber(fp));
51230194Sdenise 			sprintf(op, "H%d", hpos);
51330194Sdenise 			op += strlen(op);	/* reposition by page offset */
51430194Sdenise 			break;
51530194Sdenise 		case 'h':	/* relative horizontal motion */
51630194Sdenise 			/*
51730194Sdenise 			*op++ = c;
51830194Sdenise 			hmot(getnumber(fp));
51930194Sdenise 			 */
52030194Sdenise 			n = ngetnumber(fp);
52130194Sdenise 			hmot(n);
52230194Sdenise 			sprintf(op, "h%d", n);
52330194Sdenise 			op += strlen(op);
52430194Sdenise 			break;
52530194Sdenise 		case 'w':	/* useless */
52630194Sdenise 			*op++ = c;	/* But put it out anyway */
52730194Sdenise 			break;
52830194Sdenise 		case 'V':	/* absolute vertical motion */
52930194Sdenise 			/*
53030194Sdenise 			*op++ = c;
53130194Sdenise 			vgoto(getnumber(fp));
53230194Sdenise 			 */
53330194Sdenise 			vgoto(ngetnumber(fp));
53430194Sdenise 			sprintf(op, "V%d", vpos);
53530194Sdenise 			op += strlen(op);
53630194Sdenise 			break;
53730194Sdenise 		case 'v':
53830194Sdenise 			/*
53930194Sdenise 			*op++ = c;
54030194Sdenise 			vmot(getnumber(fp));
54130194Sdenise 			 */
54230194Sdenise 			n = ngetnumber(fp);
54330194Sdenise 			vmot(n);
54430194Sdenise 			sprintf(op, "v%d", n);
54530194Sdenise 			op += strlen(op);
54630194Sdenise 			break;
54730194Sdenise 		case 'p':	/* new page */
54830195Sdenise 			startspan(vpos);
54930194Sdenise 			t_page(ngetnumber(fp));
55030194Sdenise 			vpos = 0;
55130194Sdenise 			break;
55230194Sdenise 		case 'n':	/* end of line */
55330194Sdenise 			hpos = leftmarg;
55430194Sdenise 			/*
55530194Sdenise 			*op++ = c;
55630194Sdenise 			do
55730194Sdenise 			    *op++ = c = getc(fp);
55830194Sdenise 			while (c != '\n' && c != EOF);
55930194Sdenise 			 */
56030194Sdenise 			*op++ = c;
56130194Sdenise 			n = ngetnumber(fp);
56230194Sdenise 			m = ngetnumber(fp);
56330194Sdenise 			sprintf(op, "%d %d", n, m);
56430194Sdenise 			op += strlen(op);
56530194Sdenise 			break;
56630194Sdenise 		case '#':	/* comment */
56730194Sdenise 			do
56830194Sdenise 			    c = getc(fp);
56930194Sdenise 			while (c != '\n' && c != EOF);
57030194Sdenise 			break;
57130194Sdenise 		case 'x':	/* device control */
57230194Sdenise 			devcntrl(fp);
57330194Sdenise 			break;
57430194Sdenise 		default:
57530194Sdenise 			error(!FATAL, "unknown input character %o %c", c, c);
57630194Sdenise 			done();
57730194Sdenise 	    }
57830194Sdenise 	}
57930194Sdenise }
58030194Sdenise 
devcntrl(fp)58130194Sdenise devcntrl(fp)	/* interpret device control functions */
58230194Sdenise FILE *fp;		/* returns -1 apon recieving "stop" command */
58330194Sdenise {
58430194Sdenise         char str[20], str1[50], buf[50];
58530194Sdenise 	char *p;
58630194Sdenise 	int c, n, t1, t2;
58730194Sdenise 
58830194Sdenise 	fscanf(fp, "%s", str);
58930216Sdenise 	switch (str[0]) {
59030194Sdenise 	case 'r':	/* resolution assumed when prepared */
59130194Sdenise 		fscanf(fp, "%d %d %d", &inch, &t1, &t2);
59230194Sdenise 		sprintf(str1, "x res %d %d %d", inch, t1, t2);
59330194Sdenise 		break;
59430194Sdenise 	default:	/* reconstruct the string */
59530194Sdenise 		fgets(buf, sizeof buf, fp);
59630194Sdenise 		sprintf(str1, "x %s%s", str, buf);
59730194Sdenise 	}
59830194Sdenise 
59930194Sdenise 	startspan(vpos);
60030216Sdenise 	vlp->x++;		/* yes, this is an x command */
60130194Sdenise 	p = str1;
60230194Sdenise 	while (*p)
60330194Sdenise 		*op++ = *p++;
60430194Sdenise }
60530194Sdenise 
60630194Sdenise /*----------------------------------------------------------------------------*
60730194Sdenise  | Routine:	setlimit
60830194Sdenise  |
60930194Sdenise  | Results:	using "newup" and "newdown" decide when to start a new span.
61030194Sdenise  |		maximum rise and/or fall of a vertical extent are saved.
61130194Sdenise  |
61230194Sdenise  | Side Efct:	may start new span.
61330194Sdenise  *----------------------------------------------------------------------------*/
61430194Sdenise 
61530194Sdenise #define diffspan(x,y)	((x)/NLINES != (y)/NLINES)
61630194Sdenise 
setlimit(newup,newdown)61730194Sdenise setlimit(newup, newdown)
61830194Sdenise register int newup;
61930194Sdenise register int newdown;
62030194Sdenise {
62130194Sdenise 	register int currup = vlp->u;
62230194Sdenise 	register int currdown = vlp->d;
62330194Sdenise 
62430194Sdenise 	if (newup < 0) newup = 0;	/* don't go back beyond start of page */
62530194Sdenise 	if (newdown < 0) newdown = 0;
62630194Sdenise 
62730194Sdenise 	if (diffspan(currup, currdown)) {	/* now spans > one band */
62830194Sdenise 	    if (diffspan(newup, currup) || diffspan(newdown, currdown)) {
62930194Sdenise 		startspan (vpos);
63030194Sdenise 		vlp->u = newup;
63130194Sdenise 		vlp->d = newdown;
63230194Sdenise 	    } else {
63330194Sdenise 		if (newup < currup) vlp->u = newup;
63430194Sdenise 		if (newdown > currdown) vlp->d = newdown;
63530194Sdenise 	    }
63630194Sdenise 	} else {
63730194Sdenise 	    if (newup < currup) {	/* goes farther up than before */
63830194Sdenise 		if (currup == vlp->v) {		/* is new span, just set "up" */
63930194Sdenise 		    vlp->u = newup;
64030194Sdenise 		} else {
64130194Sdenise 		    if (diffspan(newup, currup)) {	/* goes up farther */
64230194Sdenise 			startspan(vpos);		/* than previously */
64330194Sdenise 			vlp->u = newup;			/* AND to a higher */
64430194Sdenise 			vlp->d = newdown;		/* band.  */
64530194Sdenise 			return;
64630194Sdenise 		    } else {
64730194Sdenise 			vlp->u = newup;
64830194Sdenise 		    }
64930194Sdenise 		}
65030194Sdenise 	    }
65130194Sdenise 	    if (newdown > currdown) {
65230194Sdenise 		if (currdown == vlp->v) {
65330194Sdenise 		    vlp->d = newdown;
65430194Sdenise 		    return;
65530194Sdenise 		} else {
65630194Sdenise 		    if (diffspan(newdown, currdown)) {
65730194Sdenise 			startspan(vpos);
65830194Sdenise 			vlp->u = newup;
65930194Sdenise 			vlp->d = newdown;
66030194Sdenise 			return;
66130194Sdenise 		    } else {
66230194Sdenise 			vlp->d = newdown;
66330194Sdenise 		    }
66430194Sdenise 		}
66530194Sdenise 	    }
66630194Sdenise 	}
66730194Sdenise }
66830194Sdenise 
66930194Sdenise 
67030194Sdenise /*----------------------------------------------------------------------------*
67130194Sdenise  | Routine:	arcbounds (h, v, h1, v1)
67230194Sdenise  |
67330194Sdenise  | Results:	using the horizontal positions of the starting and ending
67430194Sdenise  |		points relative to the center and vertically relative to
67530194Sdenise  |		each other, arcbounds calculates the upper and lower extent
67630194Sdenise  |		of the arc which is one of:  starting point, ending point
67730194Sdenise  |		or center + rad for bottom, and center - rad for top.
67830194Sdenise  |
67930194Sdenise  | Side Efct:	calls setlimit(up, down) to save the extent information.
68030194Sdenise  *----------------------------------------------------------------------------*/
68130194Sdenise 
arcbounds(h,v,h1,v1)68230194Sdenise arcbounds(h, v, h1, v1)
68330194Sdenise int h, v, h1, v1;
68430194Sdenise {
68530194Sdenise 	register unsigned rad = (int)(sqrt((double)(h*h + v*v)) + 0.5);
68630194Sdenise 	register int i = ((h >= 0) << 2) | ((h1 < 0) << 1) | ((v + v1) < 0);
68730194Sdenise 
68830194Sdenise 			/* i is a set of flags for the points being on the */
68930194Sdenise 			/* left of the center point, and which is higher */
69030194Sdenise 
69130194Sdenise 	v1 += vpos + v;		/* v1 is vertical position of ending point */
69230194Sdenise 				/* test relative positions for maximums */
69330194Sdenise 	setlimit(		/* and set the up/down of the arc */
69430194Sdenise 	    ((((i&3)==1) ? v1 : (((i&5)==4) ? vpos : vpos+v-rad)) - thick/2),
69530194Sdenise 	    ((((i&3)==2) ? v1 : (((i&5)==1) ? vpos : vpos+v+rad)) + thick/2));
69630194Sdenise }
69730194Sdenise 
69830194Sdenise 
oflush()69930194Sdenise oflush()	/* sort, then dump out contents of obuf */
70030194Sdenise {
70130194Sdenise 	register struct vlist *vp;
70230194Sdenise 	register int notdone;
70330194Sdenise 	register int topv;
70430194Sdenise 	register int botv;
70530194Sdenise 	register int i;
70630194Sdenise 	register char *p;
70730194Sdenise 
70830194Sdenise #ifdef DEBUGABLE
70930194Sdenise 	if (dbg) fprintf(stderr, "GAG me with an into oflush, V=%d\n", vpos);
71030194Sdenise #endif DEBUGABLE
71130194Sdenise 	if (op == obuf)
71230194Sdenise 		return;
71330194Sdenise 	*op = 0;
71430194Sdenise 
71530194Sdenise 	topv = 0;
71630194Sdenise 	botv = NLINES - 1;
71730194Sdenise 	do {
71830194Sdenise 	    notdone = 0;
71930194Sdenise 	    vp = vlist;
72030194Sdenise 	    for (i = 0; i < nvlist; i++, vp++) {
72130194Sdenise #ifdef DEBUGABLE
72230194Sdenise 		if(dbg>1)fprintf(stderr,"oflush: u=%d, d=%d,%.60s\n",vp->u,vp->d,vp->p);
72330194Sdenise #endif DEBUGABLE
72430194Sdenise 		if (vp->u <= botv && vp->d >= topv) {
725*30592Sdenise 			if(vp->x)	/* doesn't need font or size  */
726*30592Sdenise 			    printf("H%dV%d\n%s", vp->h,vp->v,vp->p);
72730216Sdenise 			else
72830216Sdenise 			    printf("H%dV%ds%df%d\n%s",
72930216Sdenise 					vp->h,vp->v,vp->s,vp->f,vp->p);
73030194Sdenise 		}
73130194Sdenise 		notdone |= vp->d > botv;	/* not done if there's still */
73230194Sdenise 	    }					/* something to put lower */
73330194Sdenise 	    if (notdone) putchar('P');		/* mark the end of the spread */
73430194Sdenise 	    topv += NLINES;			/* unless it's the last one */
73530194Sdenise 	    botv += NLINES;
73630194Sdenise 	} while (notdone);
73730194Sdenise 
73830194Sdenise 	fflush(stdout);
73930194Sdenise 	vlp = vlist;
74030194Sdenise 	vlp->p = op = obuf;
74130194Sdenise 	vlp->h = hpos;
74230194Sdenise 	vlp->v = vpos;
74330194Sdenise 	vlp->u = vpos;
74430194Sdenise 	vlp->d = vpos;
74530194Sdenise 	vlp->s = size;
74630194Sdenise 	vlp->f = font;
74730194Sdenise #ifdef BERK
74830194Sdenise 	vlp->l = stip;
74930194Sdenise 	vlp->st = style;
75030194Sdenise #endif BERK
75130194Sdenise 	vlp->t = thick;
75230216Sdenise 	vlp->x = 0;
75330194Sdenise 	*op = 0;
75430194Sdenise 	nvlist = 1;
75530194Sdenise }
75630194Sdenise 
75730194Sdenise 
done()75830194Sdenise done()
75930194Sdenise {
76030194Sdenise 	oflush();
76130194Sdenise 	exit(0);
76230194Sdenise }
76330194Sdenise 
error(f,s,a1,a2,a3,a4,a5,a6,a7)76430194Sdenise error(f, s, a1, a2, a3, a4, a5, a6, a7) {
76530194Sdenise 	fprintf(stderr, "vsort: ");
76630194Sdenise 	fprintf(stderr, s, a1, a2, a3, a4, a5, a6, a7);
76730194Sdenise 	fprintf(stderr, "\n");
76830194Sdenise 	if (f)
76930194Sdenise 		done();
77030194Sdenise }
77130194Sdenise 
77230194Sdenise #define	MAXSTATE	5
77330194Sdenise 
77430194Sdenise struct state {
77530194Sdenise 	int	ssize;
77630194Sdenise 	int	sfont;
77730194Sdenise 	int	shpos;
77830194Sdenise 	int	svpos;
77930194Sdenise };
78030194Sdenise struct	state	state[MAXSTATE];
78130194Sdenise struct	state	*statep = state;
78230194Sdenise 
t_push()78330194Sdenise t_push()	/* begin a new block */
78430194Sdenise {
78530194Sdenise 	statep->ssize = size;
78630194Sdenise 	statep->sfont = font;
78730194Sdenise 	statep->shpos = hpos;
78830194Sdenise 	statep->svpos = vpos;
78930194Sdenise 	hpos = vpos = 0;
79030194Sdenise 	if (statep++ >= state+MAXSTATE)
79130194Sdenise 		error(FATAL, "{ nested too deep");
79230194Sdenise 	hpos = vpos = 0;
79330194Sdenise }
79430194Sdenise 
t_pop()79530194Sdenise t_pop()	/* pop to previous state */
79630194Sdenise {
79730194Sdenise 	if (--statep < state)
79830194Sdenise 		error(FATAL, "extra }");
79930194Sdenise 	size = statep->ssize;
80030194Sdenise 	font = statep->sfont;
80130194Sdenise 	hpos = statep->shpos;
80230194Sdenise 	vpos = statep->svpos;
80330194Sdenise }
80430194Sdenise 
80530194Sdenise 
80630194Sdenise /*----------------------------------------------------------------------------*
80730194Sdenise  | Routine:	t_page
80830194Sdenise  |
80930194Sdenise  | Results:	new Margins are calculated for putting pages side-by-side.
81030194Sdenise  |		If no more pages can fit across the paper (WIDTH wide)
81130194Sdenise  |		a real page end is done and the currrent page is output.
81230194Sdenise  |
81330194Sdenise  | Side Efct:	oflush is called on a REAL page boundary.
81430194Sdenise  *----------------------------------------------------------------------------*/
81530194Sdenise 
t_page(n)81630194Sdenise t_page(n)
81730194Sdenise int n;
81830194Sdenise {
81930194Sdenise #ifndef VER80
82030194Sdenise     static int first = 1;		/* flag to catch the 1st time through */
82130194Sdenise 
82230195Sdenise     	/*
82330195Sdenise 	 * if we're near the edge,  or this is the first page
82430195Sdenise 	 * we'll go over on this page.
82530195Sdenise 	 */
82630195Sdenise     if (leftmarg + 2*(pageno ? leftmarg/pageno : 0) > WIDTH
82730195Sdenise 	  || maxh > WIDTH - inch || first) {
82830194Sdenise 	oflush();
82930194Sdenise 	printf("p%d\n", spanno++);		/* make it a REAL page-break */
83030194Sdenise 	first = pageno = leftmarg = maxh = 0;
83130195Sdenise 
83230195Sdenise     } else {
83330195Sdenise 	/* x = last page's width (in half-inches) */
83430194Sdenise 	register int x = (maxh - leftmarg + (HALF - 1)) / HALF;
83530194Sdenise 
83630194Sdenise 	if (x > 11 && x <= 17)
83730194Sdenise 	    leftmarg += (8 * inch) + HALF; 		/* if close to 8.5"  */
83830194Sdenise 	else						/* then make it so   */
83930194Sdenise 	    leftmarg = ((maxh + HALF) / HALF) * HALF;	/* else set it to the */
84030194Sdenise 	pageno++;					/* nearest half-inch */
84130194Sdenise     }
84230194Sdenise #else
84330194Sdenise     oflush();
84430194Sdenise     printf("p%d\n", n);
84530194Sdenise     pageno = leftmarg = maxh = 0;
84630194Sdenise #endif VER80
84730194Sdenise }
84830194Sdenise 
84930194Sdenise 
startspan(n)85030194Sdenise startspan(n)
85130194Sdenise register int n;
85230194Sdenise {
85330194Sdenise 	*op++ = 0;
85430194Sdenise 	if (nvlist >= NVLIST) {
85530194Sdenise #ifdef DEBUGABLE
85630194Sdenise 	    error(!FATAL, "(startspan) ran out of vlist");
85730194Sdenise #endif DEBUGABLE
85830194Sdenise 	    oflush();
85930194Sdenise 	}
86030194Sdenise 	vlp++;
86130194Sdenise 	vlp->p = op;
86230194Sdenise 	vlp->v = n;
86330194Sdenise 	vlp->d = n;
86430194Sdenise 	vlp->u = n;
86530194Sdenise 	vlp->h = hpos;
86630194Sdenise 	vlp->s = size;
86730194Sdenise 	vlp->f = font;
86830194Sdenise #ifdef BERK
86930194Sdenise 	vlp->l = stip;
87030194Sdenise 	vlp->st = style;
87130194Sdenise #endif BERK
87230194Sdenise 	vlp->t = thick;
87330216Sdenise 	vlp->x = 0;
87430194Sdenise 	nvlist++;
87530194Sdenise }
87630194Sdenise 
87730194Sdenise #ifdef BERK
87830194Sdenise 
87930194Sdenise #define MAXX	0x7fff
88030194Sdenise #define MINX	0x8000
88130194Sdenise 
88230194Sdenise typedef struct poly {
88330194Sdenise 	struct poly *next;	/* doublely-linked lists of vectors */
88430194Sdenise 	struct poly *prev;
88530194Sdenise 	int param;	/* bressenham line algorithm parameter */
88630194Sdenise 	short dx;	/* delta-x for calculating line */
88730194Sdenise 	short dy;	/* delta-y for calculating line */
88830194Sdenise 	short currx;	/* current x in this vector */
88930194Sdenise 	short endy;	/* where vector ends */
89030194Sdenise } polyvector;
89130194Sdenise 
89230194Sdenise 
89330194Sdenise /*----------------------------------------------------------------------------*
89430194Sdenise  | Routine:	polygon ( member, num_vectors, x_coor, y_coor, maxy, miny )
89530194Sdenise  |
89630194Sdenise  | Results:	outputs commands to draw a polygon starting at (x[1], y[1])
89730194Sdenise  |		going through each of (x_coordinates, y_coordinates), and
89830194Sdenise  |		filled with "member" stipple pattern.
89930194Sdenise  |
90030194Sdenise  |		A scan-line algorithm is simulated and pieces of the
90130194Sdenise  |		polygon are put out that fit on bands of the versatec
90230194Sdenise  |		output filter.
90330194Sdenise  |
90430194Sdenise  |		The format of the polygons put out are:
90530194Sdenise  |			'Dp member num miny maxy [p dx dy curx endy]'
90630194Sdenise  |		where "num" is the number of [..] entries in that
90730194Sdenise  |		section of the polygon.
90830194Sdenise  *----------------------------------------------------------------------------*/
90930194Sdenise 
polygon(member,nvect,x,y,maxy,miny)91030194Sdenise polygon(member, nvect, x, y, maxy, miny)
91130194Sdenise int member;
91230194Sdenise int nvect;
91330194Sdenise int x[];
91430194Sdenise int y[];
91530194Sdenise int maxy;
91630194Sdenise int miny;
91730194Sdenise {
91830194Sdenise     int nexty;			/* at what x value the next vector starts */
91930194Sdenise     register int active;	/* number of vectors in active list */
92030194Sdenise     int firsttime;		/* force out a polgon the first time through */
92130194Sdenise     polyvector *activehead;		/* doing fill, is active edge list */
92230194Sdenise     polyvector *waitinghead;		/* edges waiting to be active */
92330194Sdenise     register polyvector *vectptr;	/* random vector */
92430194Sdenise     register int i;			/* random register */
92530194Sdenise 
92630194Sdenise 
92730194Sdenise 				/* allocate space for raster-fill algorithm*/
92830194Sdenise     vectptr = (polyvector *) malloc(sizeof(polyvector) * (nvect + 4));
92930194Sdenise     if (vectptr == (polyvector *) NULL) {
93030194Sdenise 	error(!FATAL, "unable to allocate space for polygon");
93130194Sdenise 	return;
93230194Sdenise     }
93330194Sdenise 
93430194Sdenise     waitinghead = vectptr;
93530194Sdenise     vectptr->param = miny - 1;
93630194Sdenise     (vectptr++)->prev = NULL;		/* put dummy entry at start */
93730194Sdenise     waitinghead->next = vectptr;
93830194Sdenise     vectptr->prev = waitinghead;
93930194Sdenise     i = 1;					/* starting point of coords */
94030194Sdenise     if (y[1] != y[nvect] || x[1] != x[nvect]) {
94130194Sdenise 	y[0] = y[nvect];			/* close polygon if it's not */
94230194Sdenise 	x[0] = x[nvect];
94330194Sdenise 	i = 0;
94430194Sdenise     }
94530194Sdenise     active = 0;
94630194Sdenise     while (i < nvect) {		/* set up the vectors */
94730194Sdenise 	register int j;			/* indexes to work off of */
94830194Sdenise 	register int k;
94930194Sdenise 
95030194Sdenise 	j = i;			/* j "points" to the higher (lesser) point */
95130194Sdenise 	k = ++i;
95230194Sdenise 	if (y[j] == y[k])		/* ignore horizontal lines */
95330194Sdenise 	    continue;
95430194Sdenise 
95530194Sdenise 	if (y[j] > y[k]) {
95630194Sdenise 	    j++;
95730194Sdenise 	    k--;
95830194Sdenise 	}
95930194Sdenise 	active++;
96030194Sdenise 	vectptr->next = vectptr + 1;
96130194Sdenise 	vectptr->param = y[j];		/* starting point of vector */
96230194Sdenise 	vectptr->dx = x[k] - x[j];	/* line-calculating parameters */
96330194Sdenise 	vectptr->dy = y[k] - y[j];
96430194Sdenise 	vectptr->currx = x[j];		/* starting point */
96530194Sdenise 	(vectptr++)->endy = y[k];	/* ending point */
96630194Sdenise 	vectptr->prev = vectptr - 1;
96730194Sdenise     }
96830194Sdenise 					/* if no useable vectors, quit */
96930194Sdenise     if (active < 2)
97030194Sdenise 	goto leavepoly;
97130194Sdenise 
97230194Sdenise     vectptr->param = maxy + 1;		/* dummy entry at end, too */
97330194Sdenise     vectptr->next = NULL;
97430194Sdenise 
97530194Sdenise     activehead = ++vectptr;		/* two dummy entries for active list */
97630194Sdenise     vectptr->currx = MINX;		/* head */
97730194Sdenise     vectptr->endy = maxy + 1;
97830194Sdenise     vectptr->param = vectptr->dx = vectptr->dy = 0;
97930194Sdenise     activehead->next = ++vectptr;
98030194Sdenise     activehead->prev = vectptr;
98130194Sdenise     vectptr->prev = activehead;		/* tail */
98230194Sdenise     vectptr->next = activehead;
98330194Sdenise     vectptr->currx = MAXX;
98430194Sdenise     vectptr->endy = maxy + 1;
98530194Sdenise     vectptr->param = vectptr->dx = vectptr->dy = 0;
98630194Sdenise 
98730194Sdenise 					/* if there's no need to break the */
98830194Sdenise 					/* polygon into pieces, don't bother */
98930194Sdenise     if (diffspan(miny, maxy)) {
99030194Sdenise 	active = 0;			/* will keep track of # of vectors */
99130194Sdenise 	firsttime = 1;
99230194Sdenise     } else {				/*   in the active list */
99330194Sdenise 	startspan(miny);
99430194Sdenise 	sprintf(op, "Dq %d %d %d %d", member, active, miny, maxy);
99530194Sdenise 	op += strlen(op);
99630194Sdenise 	for (vectptr = waitinghead->next; active--; vectptr++) {
99730194Sdenise 	    sprintf(op, " %d %d %d %d %d",
99830194Sdenise 		vectptr->param, vectptr->dx, vectptr->dy,
99930194Sdenise 		vectptr->currx, vectptr->endy);
100030194Sdenise 	    op += strlen(op);
100130194Sdenise 	}
100230194Sdenise 	*(op++) = '\n';
100330194Sdenise 	goto leavepoly;
100430194Sdenise     }
100530194Sdenise 			/* main loop -- gets vectors off the waiting list, */
100630194Sdenise 			/* then displays spans while updating the vectors in */
100730194Sdenise     			/* the active list */
100830194Sdenise     while (miny <= maxy) {
100930194Sdenise 	i = maxy + 1;		/* this is the NEXT time to get a new vector */
101030194Sdenise 	for (vectptr = waitinghead->next; vectptr != NULL; ) {
101130194Sdenise 	    if (miny == vectptr->param) {
101230194Sdenise 				/* the entry in waiting list (vectptr) is */
101330194Sdenise 				/*   ready to go into active list.  Need to */
101430194Sdenise 				/*   convert some vector stuff and sort the */
101530194Sdenise 				/*   entry into the list. */
101630194Sdenise 		register polyvector *p;	/* random vector pointers */
101730194Sdenise 		register polyvector *v;
101830194Sdenise 
101930194Sdenise 							/* convert this */
102030194Sdenise 		if (vectptr->dx < 0)			/* entry to active */
102130194Sdenise 		    vectptr->param = -((vectptr->dx >> 1) + (vectptr->dy >> 1));
102230194Sdenise 		else
102330194Sdenise 		    vectptr->param = (vectptr->dx >> 1) - (vectptr->dy >> 1);
102430194Sdenise 
102530194Sdenise 		p = vectptr;			/* remove from the */
102630194Sdenise 		vectptr = vectptr->next;	/* waiting list */
102730194Sdenise 		vectptr->prev = p->prev;
102830194Sdenise 		p->prev->next = vectptr;
102930194Sdenise 						/* find where it goes */
103030194Sdenise 						/* in the active list */
103130194Sdenise 						/* (sorted smallest first) */
103230194Sdenise 		for (v = activehead->next; v->currx < p->currx; v = v->next)
103330194Sdenise 		    ;
103430194Sdenise 		p->next = v;		/* insert into active list */
103530194Sdenise 		p->prev = v->prev;	/* before the one it stopped on */
103630194Sdenise 		v->prev = p;
103730194Sdenise 		p->prev->next = p;
103830194Sdenise 		active++;
103930194Sdenise 	    } else {
104030194Sdenise 		if (i > vectptr->param) {
104130194Sdenise 		    i = vectptr->param;
104230194Sdenise 		}
104330194Sdenise 		vectptr = vectptr->next;
104430194Sdenise 	    }
104530194Sdenise 	}
104630194Sdenise 	nexty = i;
104730194Sdenise 
104830194Sdenise 					/* print the polygon while there */
104930194Sdenise 					/* are no more vectors to add */
105030194Sdenise 	while (miny < nexty) {
105130194Sdenise 					/* remove any finished vectors */
105230194Sdenise 	    vectptr = activehead->next;
105330194Sdenise 	    do {
105430194Sdenise 		if (vectptr->endy <= miny) {
105530194Sdenise 		    vectptr->prev->next = vectptr->next;
105630194Sdenise 		    vectptr->next->prev = vectptr->prev;
105730194Sdenise 		    active--;
105830194Sdenise 		}
105930194Sdenise 	    } while ((vectptr = vectptr->next) != activehead);
106030194Sdenise 
106130194Sdenise 					/* output a polygon for this band */
106230194Sdenise 	    if (firsttime || !(miny % NLINES)) {
106330194Sdenise 		register int numwait;	/* number in the waiting list */
106430194Sdenise 		register int newmaxy;	/* max for this band (bottom or maxy)*/
106530194Sdenise 
106630194Sdenise 
106730194Sdenise 		startspan(miny);
106830194Sdenise 		if ((newmaxy = (miny / NLINES) * NLINES + (NLINES - 1)) > maxy)
106930194Sdenise 		    newmaxy = maxy;
107030194Sdenise 
107130194Sdenise 					/* count up those vectors that WILL */
107230194Sdenise 					/* become active in this band */
107330194Sdenise 		for (numwait = 0, vectptr = waitinghead->next;
107430194Sdenise 				vectptr != NULL; vectptr = vectptr->next) {
107530194Sdenise 		    if (vectptr->param <= newmaxy)
107630194Sdenise 			numwait++;
107730194Sdenise 		}
107830194Sdenise 
107930194Sdenise 		sprintf(op,"Dq %d %d %d %d",member,active+numwait,miny,newmaxy);
108030194Sdenise 		op += strlen(op);
108130194Sdenise 		for (i = active, vectptr = activehead->next; i--;
108230194Sdenise 						vectptr = vectptr->next) {
108330194Sdenise 		    sprintf(op, " %d %d %d %d %d",
108430194Sdenise 			    vectptr->param, vectptr->dx, -vectptr->dy,
108530194Sdenise 			    vectptr->currx, vectptr->endy);
108630194Sdenise 		    op += strlen(op);
108730194Sdenise 		}
108830194Sdenise 		for (vectptr = waitinghead->next; vectptr != NULL;
108930194Sdenise 						vectptr = vectptr->next) {
109030194Sdenise 		    if (vectptr->param <= newmaxy) {
109130194Sdenise 			sprintf(op, " %d %d %d %d %d",
109230194Sdenise 				vectptr->param, vectptr->dx, vectptr->dy,
109330194Sdenise 				vectptr->currx, vectptr->endy);
109430194Sdenise 			op += strlen(op);
109530194Sdenise 		    }
109630194Sdenise 		}
109730194Sdenise 		*(op++) = '\n';
109830194Sdenise 		firsttime = 0;
109930194Sdenise 	    }
110030194Sdenise 
110130194Sdenise 					/* update the vectors */
110230194Sdenise 	    vectptr = activehead->next;
110330194Sdenise 	    do {
110430194Sdenise 		if (vectptr->dx > 0) {
110530194Sdenise 		    while (vectptr->param >= 0) {
110630194Sdenise 			vectptr->param -= vectptr->dy;
110730194Sdenise 			vectptr->currx++;
110830194Sdenise 		    }
110930194Sdenise 		    vectptr->param += vectptr->dx;
111030194Sdenise 		} else if (vectptr->dx < 0) {
111130194Sdenise 		    while (vectptr->param >= 0) {
111230194Sdenise 			vectptr->param -= vectptr->dy;
111330194Sdenise 			vectptr->currx--;
111430194Sdenise 		    }
111530194Sdenise 		    vectptr->param -= vectptr->dx;
111630194Sdenise 		}
111730194Sdenise 					/* must sort the vectors if updates */
111830194Sdenise 					/* caused them to cross */
111930194Sdenise 					/* also move to next vector here */
112030194Sdenise 		if (vectptr->currx < vectptr->prev->currx) {
112130194Sdenise 		    register polyvector *v;		/* vector to move */
112230194Sdenise 		    register polyvector *p;	/* vector to put it after */
112330194Sdenise 
112430194Sdenise 		    v = vectptr;
112530194Sdenise 		    p = v->prev;
112630194Sdenise 		    while (v->currx < p->currx)	/* find the */
112730194Sdenise 			p = p->prev;		/* right vector */
112830194Sdenise 
112930194Sdenise 		    vectptr = vectptr->next;	/* remove from spot */
113030194Sdenise 		    vectptr->prev = v->prev;
113130194Sdenise 		    v->prev->next = vectptr;
113230194Sdenise 
113330194Sdenise 		    v->prev = p;		/* put in new spot */
113430194Sdenise 		    v->next = p->next;
113530194Sdenise 		    p->next = v;
113630194Sdenise 		    v->next->prev = v;
113730194Sdenise 		} else {
113830194Sdenise 		    vectptr = vectptr->next;
113930194Sdenise 		}
114030194Sdenise 	    } while (vectptr != activehead);
114130194Sdenise 
114230194Sdenise 	    ++miny;
114330194Sdenise 	} /* while (miny < nexty) */
114430194Sdenise     } /* while (miny <= maxy) */
114530194Sdenise 
114630194Sdenise leavepoly:
114730194Sdenise     startspan(vpos);	/* make sure stuff after polygon is at correct vpos */
114830194Sdenise     free(waitinghead);
114930194Sdenise }  /* polygon function */
115030194Sdenise #endif BERK
1151