xref: /plan9-contrib/sys/src/cmd/troff/n9.c (revision 14f51593fd82e19ba95969a8c07ff71131015979)
13e12c5d1SDavid du Colombier #include "tdef.h"
23e12c5d1SDavid du Colombier #include "ext.h"
33e12c5d1SDavid du Colombier #include "fns.h"
43e12c5d1SDavid du Colombier 
53e12c5d1SDavid du Colombier /*
63e12c5d1SDavid du Colombier  * troff9.c
73e12c5d1SDavid du Colombier  *
83e12c5d1SDavid du Colombier  * misc functions
93e12c5d1SDavid du Colombier  */
103e12c5d1SDavid du Colombier 
setz(void)113e12c5d1SDavid du Colombier Tchar setz(void)
123e12c5d1SDavid du Colombier {
133e12c5d1SDavid du Colombier 	Tchar i;
143e12c5d1SDavid du Colombier 
153e12c5d1SDavid du Colombier 	if (!ismot(i = getch()))
163e12c5d1SDavid du Colombier 		i |= ZBIT;
173e12c5d1SDavid du Colombier 	return(i);
183e12c5d1SDavid du Colombier }
193e12c5d1SDavid du Colombier 
setline(void)203e12c5d1SDavid du Colombier void setline(void)
213e12c5d1SDavid du Colombier {
223e12c5d1SDavid du Colombier 	Tchar *i;
233e12c5d1SDavid du Colombier 	Tchar c;
243e12c5d1SDavid du Colombier 	int length;
253e12c5d1SDavid du Colombier 	int j, w, cnt, delim, rem, temp;
263e12c5d1SDavid du Colombier 	Tchar linebuf[NC];
273e12c5d1SDavid du Colombier 
283e12c5d1SDavid du Colombier 	if (ismot(c = getch()))
293e12c5d1SDavid du Colombier 		return;
303e12c5d1SDavid du Colombier 	delim = cbits(c);
313e12c5d1SDavid du Colombier 	vflag = 0;
323e12c5d1SDavid du Colombier 	dfact = EM;
333e12c5d1SDavid du Colombier 	length = quant(atoi0(), HOR);
343e12c5d1SDavid du Colombier 	dfact = 1;
353e12c5d1SDavid du Colombier 	if (!length) {
363e12c5d1SDavid du Colombier 		eat(delim);
373e12c5d1SDavid du Colombier 		return;
383e12c5d1SDavid du Colombier 	}
393e12c5d1SDavid du Colombier s0:
403e12c5d1SDavid du Colombier 	if ((j = cbits(c = getch())) == delim || j == '\n') {
413e12c5d1SDavid du Colombier 		ch = c;
423e12c5d1SDavid du Colombier 		c = RULE | chbits;
433e12c5d1SDavid du Colombier 	} else if (cbits(c) == FILLER)
443e12c5d1SDavid du Colombier 		goto s0;
453e12c5d1SDavid du Colombier 	w = width(c);
463e12c5d1SDavid du Colombier 	if (w <= 0) {
473e12c5d1SDavid du Colombier 		ERROR "zero-width underline character ignored" WARN;
483e12c5d1SDavid du Colombier 		c = RULE | chbits;
493e12c5d1SDavid du Colombier 		w = width(c);
503e12c5d1SDavid du Colombier 	}
513e12c5d1SDavid du Colombier 	i = linebuf;
523e12c5d1SDavid du Colombier 	if (length < 0) {
533e12c5d1SDavid du Colombier 		*i++ = makem(length);
543e12c5d1SDavid du Colombier 		length = -length;
553e12c5d1SDavid du Colombier 	}
563e12c5d1SDavid du Colombier 	if (!(cnt = length / w)) {
573e12c5d1SDavid du Colombier 		*i++ = makem(-(temp = ((w - length) / 2)));
583e12c5d1SDavid du Colombier 		*i++ = c;
593e12c5d1SDavid du Colombier 		*i++ = makem(-(w - length - temp));
603e12c5d1SDavid du Colombier 		goto s1;
613e12c5d1SDavid du Colombier 	}
623e12c5d1SDavid du Colombier 	if (rem = length % w) {
633e12c5d1SDavid du Colombier 		if (cbits(c) == RULE || cbits(c) == UNDERLINE || cbits(c) == ROOTEN)
643e12c5d1SDavid du Colombier 			*i++ = c | ZBIT;
653e12c5d1SDavid du Colombier 		*i++ = makem(rem);
663e12c5d1SDavid du Colombier 	}
673e12c5d1SDavid du Colombier 	if (cnt) {
683e12c5d1SDavid du Colombier 		*i++ = RPT;
693e12c5d1SDavid du Colombier 		*i++ = cnt;
703e12c5d1SDavid du Colombier 		*i++ = c;
713e12c5d1SDavid du Colombier 	}
723e12c5d1SDavid du Colombier s1:
733e12c5d1SDavid du Colombier 	*i = 0;
743e12c5d1SDavid du Colombier 	eat(delim);
753e12c5d1SDavid du Colombier 	pushback(linebuf);
763e12c5d1SDavid du Colombier }
773e12c5d1SDavid du Colombier 
783e12c5d1SDavid du Colombier 
eat(int c)793e12c5d1SDavid du Colombier eat(int c)
803e12c5d1SDavid du Colombier {
813e12c5d1SDavid du Colombier 	int i;
823e12c5d1SDavid du Colombier 
833e12c5d1SDavid du Colombier 	while ((i = cbits(getch())) != c && i != '\n')
843e12c5d1SDavid du Colombier 		;
853e12c5d1SDavid du Colombier 	return(i);
863e12c5d1SDavid du Colombier }
873e12c5d1SDavid du Colombier 
883e12c5d1SDavid du Colombier 
setov(void)893e12c5d1SDavid du Colombier void setov(void)
903e12c5d1SDavid du Colombier {
913e12c5d1SDavid du Colombier 	int j, k;
923e12c5d1SDavid du Colombier 	Tchar i, o[NOV+1];
933e12c5d1SDavid du Colombier 	int delim, w[NOV+1];
943e12c5d1SDavid du Colombier 
953e12c5d1SDavid du Colombier 	if (ismot(i = getch()))
963e12c5d1SDavid du Colombier 		return;
973e12c5d1SDavid du Colombier 	delim = cbits(i);
983e12c5d1SDavid du Colombier 	for (k = 0; k < NOV && (j = cbits(i = getch())) != delim && j != '\n'; k++) {
993e12c5d1SDavid du Colombier 		o[k] = i;
1003e12c5d1SDavid du Colombier 		w[k] = width(i);
1013e12c5d1SDavid du Colombier 	}
1023e12c5d1SDavid du Colombier 	o[k] = w[k] = 0;
1033e12c5d1SDavid du Colombier 	if (o[0])
1043e12c5d1SDavid du Colombier 		for (j = 1; j; ) {
1053e12c5d1SDavid du Colombier 			j = 0;
1063e12c5d1SDavid du Colombier 			for (k = 1; o[k] ; k++) {
1073e12c5d1SDavid du Colombier 				if (w[k-1] < w[k]) {
1083e12c5d1SDavid du Colombier 					j++;
1093e12c5d1SDavid du Colombier 					i = w[k];
1103e12c5d1SDavid du Colombier 					w[k] = w[k-1];
1113e12c5d1SDavid du Colombier 					w[k-1] = i;
1123e12c5d1SDavid du Colombier 					i = o[k];
1133e12c5d1SDavid du Colombier 					o[k] = o[k-1];
1143e12c5d1SDavid du Colombier 					o[k-1] = i;
1153e12c5d1SDavid du Colombier 				}
1163e12c5d1SDavid du Colombier 			}
1173e12c5d1SDavid du Colombier 		}
1183e12c5d1SDavid du Colombier 	else
1193e12c5d1SDavid du Colombier 		return;
1203e12c5d1SDavid du Colombier 	*pbp++ = makem(w[0] / 2);
1213e12c5d1SDavid du Colombier 	for (k = 0; o[k]; k++)
1223e12c5d1SDavid du Colombier 		;
1233e12c5d1SDavid du Colombier 	while (k>0) {
1243e12c5d1SDavid du Colombier 		k--;
1253e12c5d1SDavid du Colombier 		*pbp++ = makem(-((w[k] + w[k+1]) / 2));
1263e12c5d1SDavid du Colombier 		*pbp++ = o[k];
1273e12c5d1SDavid du Colombier 	}
1283e12c5d1SDavid du Colombier }
1293e12c5d1SDavid du Colombier 
1303e12c5d1SDavid du Colombier 
setbra(void)1313e12c5d1SDavid du Colombier void setbra(void)
1323e12c5d1SDavid du Colombier {
1333e12c5d1SDavid du Colombier 	int k;
1343e12c5d1SDavid du Colombier 	Tchar i, *j, dwn;
1353e12c5d1SDavid du Colombier 	int cnt, delim;
1363e12c5d1SDavid du Colombier 	Tchar brabuf[NC];
1373e12c5d1SDavid du Colombier 
1383e12c5d1SDavid du Colombier 	if (ismot(i = getch()))
1393e12c5d1SDavid du Colombier 		return;
1403e12c5d1SDavid du Colombier 	delim = cbits(i);
1413e12c5d1SDavid du Colombier 	j = brabuf + 1;
1423e12c5d1SDavid du Colombier 	cnt = 0;
1433e12c5d1SDavid du Colombier 	if (NROFF)
1443e12c5d1SDavid du Colombier 		dwn = (2 * t.Halfline) | MOT | VMOT;
1453e12c5d1SDavid du Colombier 	else
1463e12c5d1SDavid du Colombier 		dwn = EM | MOT | VMOT;
1473e12c5d1SDavid du Colombier 	while ((k = cbits(i = getch())) != delim && k != '\n' && j <= brabuf + NC - 4) {
1483e12c5d1SDavid du Colombier 		*j++ = i | ZBIT;
1493e12c5d1SDavid du Colombier 		*j++ = dwn;
1503e12c5d1SDavid du Colombier 		cnt++;
1513e12c5d1SDavid du Colombier 	}
1523e12c5d1SDavid du Colombier 	if (--cnt < 0)
1533e12c5d1SDavid du Colombier 		return;
1543e12c5d1SDavid du Colombier 	else if (!cnt) {
1553e12c5d1SDavid du Colombier 		ch = *(j - 2);
1563e12c5d1SDavid du Colombier 		return;
1573e12c5d1SDavid du Colombier 	}
1583e12c5d1SDavid du Colombier 	*j = 0;
1593e12c5d1SDavid du Colombier 	if (NROFF)
1603e12c5d1SDavid du Colombier 		*--j = *brabuf = (cnt * t.Halfline) | MOT | NMOT | VMOT;
1613e12c5d1SDavid du Colombier 	else
1623e12c5d1SDavid du Colombier 		*--j = *brabuf = (cnt * EM) / 2 | MOT | NMOT | VMOT;
1633e12c5d1SDavid du Colombier 	*--j &= ~ZBIT;
1643e12c5d1SDavid du Colombier 	pushback(brabuf);
1653e12c5d1SDavid du Colombier }
1663e12c5d1SDavid du Colombier 
1673e12c5d1SDavid du Colombier 
setvline(void)1683e12c5d1SDavid du Colombier void setvline(void)
1693e12c5d1SDavid du Colombier {
1703e12c5d1SDavid du Colombier 	int i;
1713e12c5d1SDavid du Colombier 	Tchar c, rem, ver, neg;
1723e12c5d1SDavid du Colombier 	int cnt, delim, v;
1733e12c5d1SDavid du Colombier 	Tchar vlbuf[NC];
1743e12c5d1SDavid du Colombier 	Tchar *vlp;
1753e12c5d1SDavid du Colombier 
1763e12c5d1SDavid du Colombier 	if (ismot(c = getch()))
1773e12c5d1SDavid du Colombier 		return;
1783e12c5d1SDavid du Colombier 	delim = cbits(c);
1793e12c5d1SDavid du Colombier 	dfact = lss;
1803e12c5d1SDavid du Colombier 	vflag++;
1813e12c5d1SDavid du Colombier 	i = quant(atoi0(), VERT);
1823e12c5d1SDavid du Colombier 	dfact = 1;
1833e12c5d1SDavid du Colombier 	if (!i) {
1843e12c5d1SDavid du Colombier 		eat(delim);
1853e12c5d1SDavid du Colombier 		vflag = 0;
1863e12c5d1SDavid du Colombier 		return;
1873e12c5d1SDavid du Colombier 	}
1883e12c5d1SDavid du Colombier 	if ((cbits(c = getch())) == delim) {
1893e12c5d1SDavid du Colombier 		c = BOXRULE | chbits;	/*default box rule*/
1903e12c5d1SDavid du Colombier 	} else
1913e12c5d1SDavid du Colombier 		getch();
1923e12c5d1SDavid du Colombier 	c |= ZBIT;
1933e12c5d1SDavid du Colombier 	neg = 0;
1943e12c5d1SDavid du Colombier 	if (i < 0) {
1953e12c5d1SDavid du Colombier 		i = -i;
1963e12c5d1SDavid du Colombier 		neg = NMOT;
1973e12c5d1SDavid du Colombier 	}
1983e12c5d1SDavid du Colombier 	if (NROFF)
1993e12c5d1SDavid du Colombier 		v = 2 * t.Halfline;
2003e12c5d1SDavid du Colombier 	else {
2013e12c5d1SDavid du Colombier 		v = EM;
2023e12c5d1SDavid du Colombier 		if (v < VERT)		/* ATT EVK hack: Erik van Konijnenburg, */
2033e12c5d1SDavid du Colombier 			v = VERT;	/* hvlpb!evkonij, ATT NSI Hilversum, Holland */
2043e12c5d1SDavid du Colombier 	}
2053e12c5d1SDavid du Colombier 
2063e12c5d1SDavid du Colombier 	cnt = i / v;
2073e12c5d1SDavid du Colombier 	rem = makem(i % v) | neg;
2083e12c5d1SDavid du Colombier 	ver = makem(v) | neg;
2093e12c5d1SDavid du Colombier 	vlp = vlbuf;
2103e12c5d1SDavid du Colombier 	if (!neg)
2113e12c5d1SDavid du Colombier 		*vlp++ = ver;
2123e12c5d1SDavid du Colombier 	if (absmot(rem) != 0) {
2133e12c5d1SDavid du Colombier 		*vlp++ = c;
2143e12c5d1SDavid du Colombier 		*vlp++ = rem;
2153e12c5d1SDavid du Colombier 	}
2163e12c5d1SDavid du Colombier 	while (vlp < vlbuf + NC - 3 && cnt--) {
2173e12c5d1SDavid du Colombier 		*vlp++ = c;
2183e12c5d1SDavid du Colombier 		*vlp++ = ver;
2193e12c5d1SDavid du Colombier 	}
2203e12c5d1SDavid du Colombier 	*(vlp - 2) &= ~ZBIT;
2213e12c5d1SDavid du Colombier 	if (!neg)
2223e12c5d1SDavid du Colombier 		vlp--;
2233e12c5d1SDavid du Colombier 	*vlp = 0;
2243e12c5d1SDavid du Colombier 	pushback(vlbuf);
2253e12c5d1SDavid du Colombier 	vflag = 0;
2263e12c5d1SDavid du Colombier }
2273e12c5d1SDavid du Colombier 
2283e12c5d1SDavid du Colombier #define	NPAIR	(NC/2-6)	/* max pairs in spline, etc. */
2293e12c5d1SDavid du Colombier 
setdraw(void)2303e12c5d1SDavid du Colombier void setdraw(void)	/* generate internal cookies for a drawing function */
2313e12c5d1SDavid du Colombier {
2323e12c5d1SDavid du Colombier 	int i, j, k, dx[NPAIR], dy[NPAIR], delim, type;
2333e12c5d1SDavid du Colombier 	Tchar c, drawbuf[NC];
2343e12c5d1SDavid du Colombier 	int drawch = '.';	/* character to draw with */
2353e12c5d1SDavid du Colombier 
2363e12c5d1SDavid du Colombier 	/* input is \D'f dx dy dx dy ... c' (or at least it had better be) */
2373e12c5d1SDavid du Colombier 	/* this does drawing function f with character c and the */
2383e12c5d1SDavid du Colombier 	/* specified dx,dy pairs interpreted as appropriate */
2393e12c5d1SDavid du Colombier 	/* pairs are deltas from last point, except for radii */
2403e12c5d1SDavid du Colombier 
2413e12c5d1SDavid du Colombier 	/* l dx dy:	line from here by dx,dy */
2423e12c5d1SDavid du Colombier 	/* c x:		circle of diameter x, left side here */
2433e12c5d1SDavid du Colombier 	/* e x y:	ellipse of diameters x,y, left side here */
2443e12c5d1SDavid du Colombier 	/* a dx1 dy1 dx2 dy2:
2453e12c5d1SDavid du Colombier 			ccw arc: ctr at dx1,dy1, then end at dx2,dy2 from there */
2463e12c5d1SDavid du Colombier 	/* ~ dx1 dy1 dx2 dy2...:
2473e12c5d1SDavid du Colombier 			spline to dx1,dy1 to dx2,dy2 ... */
2483e12c5d1SDavid du Colombier 	/* b x c:
2493e12c5d1SDavid du Colombier 			built-up character of type c, ht x */
2503e12c5d1SDavid du Colombier 	/* f dx dy ...:	f is any other char:  like spline */
2513e12c5d1SDavid du Colombier 
2523e12c5d1SDavid du Colombier 	if (ismot(c = getch()))
2533e12c5d1SDavid du Colombier 		return;
2543e12c5d1SDavid du Colombier 	delim = cbits(c);
255219b2ee8SDavid du Colombier 	numerr.escarg = type = cbits(getch());
2563e12c5d1SDavid du Colombier 	if (type == '~')	/* head off the .tr ~ problem */
2573e12c5d1SDavid du Colombier 		type = 's';
2583e12c5d1SDavid du Colombier 	for (i = 0; i < NPAIR ; i++) {
2593e12c5d1SDavid du Colombier 		skip();
2603e12c5d1SDavid du Colombier 		vflag = 0;
2613e12c5d1SDavid du Colombier 		dfact = EM;
2623e12c5d1SDavid du Colombier 		dx[i] = quant(atoi0(), HOR);
2633e12c5d1SDavid du Colombier 		if (dx[i] > MAXMOT)
2643e12c5d1SDavid du Colombier 			dx[i] = MAXMOT;
2653e12c5d1SDavid du Colombier 		else if (dx[i] < -MAXMOT)
2663e12c5d1SDavid du Colombier 			dx[i] = -MAXMOT;
2673e12c5d1SDavid du Colombier 		skip();
268219b2ee8SDavid du Colombier 		if (type == 'c') {
269219b2ee8SDavid du Colombier 			dy[i] = 0;
270219b2ee8SDavid du Colombier 			goto eat;
271219b2ee8SDavid du Colombier 		}
2723e12c5d1SDavid du Colombier 		vflag = 1;
2733e12c5d1SDavid du Colombier 		dfact = lss;
2743e12c5d1SDavid du Colombier 		dy[i] = quant(atoi0(), VERT);
2753e12c5d1SDavid du Colombier 		if (dy[i] > MAXMOT)
2763e12c5d1SDavid du Colombier 			dy[i] = MAXMOT;
2773e12c5d1SDavid du Colombier 		else if (dy[i] < -MAXMOT)
2783e12c5d1SDavid du Colombier 			dy[i] = -MAXMOT;
279219b2ee8SDavid du Colombier eat:
2803e12c5d1SDavid du Colombier 		if (cbits(c = getch()) != ' ') {	/* must be the end */
2813e12c5d1SDavid du Colombier 			if (cbits(c) != delim) {
2823e12c5d1SDavid du Colombier 				drawch = cbits(c);
2833e12c5d1SDavid du Colombier 				getch();
2843e12c5d1SDavid du Colombier 			}
2853e12c5d1SDavid du Colombier 			i++;
2863e12c5d1SDavid du Colombier 			break;
2873e12c5d1SDavid du Colombier 		}
2883e12c5d1SDavid du Colombier 	}
2893e12c5d1SDavid du Colombier 	dfact = 1;
2903e12c5d1SDavid du Colombier 	vflag = 0;
2913e12c5d1SDavid du Colombier 	if (TROFF) {
2923e12c5d1SDavid du Colombier 		drawbuf[0] = DRAWFCN | chbits | ZBIT;
2933e12c5d1SDavid du Colombier 		drawbuf[1] = type | chbits | ZBIT;
2943e12c5d1SDavid du Colombier 		drawbuf[2] = drawch | chbits | ZBIT;
2953e12c5d1SDavid du Colombier 		for (k = 0, j = 3; k < i; k++) {
2963e12c5d1SDavid du Colombier 			drawbuf[j++] = MOT | ((dx[k] >= 0) ? dx[k] : (NMOT | -dx[k]));
2973e12c5d1SDavid du Colombier 			drawbuf[j++] = MOT | VMOT | ((dy[k] >= 0) ? dy[k] : (NMOT | -dy[k]));
2983e12c5d1SDavid du Colombier 		}
2993e12c5d1SDavid du Colombier 		if (type == DRAWELLIPSE) {
3003e12c5d1SDavid du Colombier 			drawbuf[5] = drawbuf[4] | NMOT;	/* so the net vertical is zero */
3013e12c5d1SDavid du Colombier 			j = 6;
3023e12c5d1SDavid du Colombier 		} else if (type == DRAWBUILD) {
3033e12c5d1SDavid du Colombier 			drawbuf[4] = drawbuf[3] | NMOT;	/* net horizontal motion is zero */
3043e12c5d1SDavid du Colombier 			drawbuf[2] &= ~ZBIT;		/* width taken from drawing char */
3053e12c5d1SDavid du Colombier 			j = 5;
3063e12c5d1SDavid du Colombier 		}
3073e12c5d1SDavid du Colombier 		drawbuf[j++] = DRAWFCN | chbits | ZBIT;	/* marks end for ptout */
3083e12c5d1SDavid du Colombier 		drawbuf[j] = 0;
3093e12c5d1SDavid du Colombier 		pushback(drawbuf);
3103e12c5d1SDavid du Colombier 	}
3113e12c5d1SDavid du Colombier }
3123e12c5d1SDavid du Colombier 
3133e12c5d1SDavid du Colombier 
casefc(void)3143e12c5d1SDavid du Colombier void casefc(void)
3153e12c5d1SDavid du Colombier {
3163e12c5d1SDavid du Colombier 	int i;
3173e12c5d1SDavid du Colombier 	Tchar j;
3183e12c5d1SDavid du Colombier 
3193e12c5d1SDavid du Colombier 	gchtab[fc] &= ~FCBIT;
3203e12c5d1SDavid du Colombier 	fc = IMP;
3213e12c5d1SDavid du Colombier 	padc = ' ';
3223e12c5d1SDavid du Colombier 	if (skip() || ismot(j = getch()) || (i = cbits(j)) == '\n')
3233e12c5d1SDavid du Colombier 		return;
3243e12c5d1SDavid du Colombier 	fc = i;
3253e12c5d1SDavid du Colombier 	gchtab[fc] |= FCBIT;
3263e12c5d1SDavid du Colombier 	if (skip() || ismot(ch) || (ch = cbits(ch)) == fc)
3273e12c5d1SDavid du Colombier 		return;
3283e12c5d1SDavid du Colombier 	padc = ch;
3293e12c5d1SDavid du Colombier }
3303e12c5d1SDavid du Colombier 
3313e12c5d1SDavid du Colombier 
setfield(int x)3323e12c5d1SDavid du Colombier Tchar setfield(int x)
3333e12c5d1SDavid du Colombier {
334*14f51593SDavid du Colombier 	Tchar rchar, ii, jj, *fp;
3353e12c5d1SDavid du Colombier 	Tchar **pp, *padptr[NPP];
3363e12c5d1SDavid du Colombier 	Tchar fbuf[FBUFSZ];
337*14f51593SDavid du Colombier 	int i, j, length, ws, npad, temp, type, savepos, savfc, savtc, savlc;
338219b2ee8SDavid du Colombier 	static Tchar wbuf[] = { WORDSP, 0};
3393e12c5d1SDavid du Colombier 
3403e12c5d1SDavid du Colombier 	if (x == tabch)
3413e12c5d1SDavid du Colombier 		rchar = tabc | chbits;
3423e12c5d1SDavid du Colombier 	else if (x == ldrch)
3433e12c5d1SDavid du Colombier 		rchar = dotc | chbits;
344*14f51593SDavid du Colombier 	else
345*14f51593SDavid du Colombier 		rchar = 0;
3463e12c5d1SDavid du Colombier 	temp = npad = ws = 0;
3473e12c5d1SDavid du Colombier 	savfc = fc;
3483e12c5d1SDavid du Colombier 	savtc = tabch;
3493e12c5d1SDavid du Colombier 	savlc = ldrch;
3503e12c5d1SDavid du Colombier 	tabch = ldrch = fc = IMP;
351219b2ee8SDavid du Colombier 	savepos = numtabp[HP].val;
3523e12c5d1SDavid du Colombier 	gchtab[tabch] &= ~TABBIT;
3533e12c5d1SDavid du Colombier 	gchtab[ldrch] &= ~LDRBIT;
3543e12c5d1SDavid du Colombier 	gchtab[fc] &= ~FCBIT;
3553e12c5d1SDavid du Colombier 	gchtab[IMP] |= TABBIT|LDRBIT|FCBIT;
3563e12c5d1SDavid du Colombier 	for (j = 0; ; j++) {
3573e12c5d1SDavid du Colombier 		if ((tabtab[j] & TABMASK) == 0) {
3583e12c5d1SDavid du Colombier 			if (x == savfc)
3593e12c5d1SDavid du Colombier 				ERROR "zero field width." WARN;
3603e12c5d1SDavid du Colombier 			jj = 0;
3613e12c5d1SDavid du Colombier 			goto rtn;
3623e12c5d1SDavid du Colombier 		}
363219b2ee8SDavid du Colombier 		if ((length = ((tabtab[j] & TABMASK) - numtabp[HP].val)) > 0 )
3643e12c5d1SDavid du Colombier 			break;
3653e12c5d1SDavid du Colombier 	}
3663e12c5d1SDavid du Colombier 	type = tabtab[j] & ~TABMASK;
3673e12c5d1SDavid du Colombier 	fp = fbuf;
3683e12c5d1SDavid du Colombier 	pp = padptr;
3693e12c5d1SDavid du Colombier 	if (x == savfc) {
3703e12c5d1SDavid du Colombier 		while (1) {
3713e12c5d1SDavid du Colombier 			j = cbits(ii = getch());
3723e12c5d1SDavid du Colombier 			jj = width(ii);
3733e12c5d1SDavid du Colombier 			widthp = jj;
374219b2ee8SDavid du Colombier 			numtabp[HP].val += jj;
3753e12c5d1SDavid du Colombier 			if (j == padc) {
3763e12c5d1SDavid du Colombier 				npad++;
3773e12c5d1SDavid du Colombier 				*pp++ = fp;
3783e12c5d1SDavid du Colombier 				if (pp > padptr + NPP - 1)
3793e12c5d1SDavid du Colombier 					break;
3803e12c5d1SDavid du Colombier 				goto s1;
3813e12c5d1SDavid du Colombier 			} else if (j == savfc)
3823e12c5d1SDavid du Colombier 				break;
3833e12c5d1SDavid du Colombier 			else if (j == '\n') {
3843e12c5d1SDavid du Colombier 				temp = j;
385219b2ee8SDavid du Colombier 				if (nlflg && ip == 0) {
386219b2ee8SDavid du Colombier 					numtabp[CD].val--;
3873e12c5d1SDavid du Colombier 					nlflg = 0;
388219b2ee8SDavid du Colombier 				}
3893e12c5d1SDavid du Colombier 				break;
3903e12c5d1SDavid du Colombier 			}
3913e12c5d1SDavid du Colombier 			ws += jj;
3923e12c5d1SDavid du Colombier s1:
3933e12c5d1SDavid du Colombier 			*fp++ = ii;
3943e12c5d1SDavid du Colombier 			if (fp > fbuf + FBUFSZ - 3)
3953e12c5d1SDavid du Colombier 				break;
3963e12c5d1SDavid du Colombier 		}
397219b2ee8SDavid du Colombier 		if (ws)
398219b2ee8SDavid du Colombier 			*fp++ = WORDSP;
3993e12c5d1SDavid du Colombier 		if (!npad) {
4003e12c5d1SDavid du Colombier 			npad++;
4013e12c5d1SDavid du Colombier 			*pp++ = fp;
4023e12c5d1SDavid du Colombier 			*fp++ = 0;
4033e12c5d1SDavid du Colombier 		}
4043e12c5d1SDavid du Colombier 		*fp++ = temp;
4053e12c5d1SDavid du Colombier 		*fp = 0;
4063e12c5d1SDavid du Colombier 		temp = i = (j = length - ws) / npad;
4073e12c5d1SDavid du Colombier 		i = (i / HOR) * HOR;
4083e12c5d1SDavid du Colombier 		if ((j -= i * npad) < 0)
4093e12c5d1SDavid du Colombier 			j = -j;
4103e12c5d1SDavid du Colombier 		ii = makem(i);
4113e12c5d1SDavid du Colombier 		if (temp < 0)
4123e12c5d1SDavid du Colombier 			ii |= NMOT;
4133e12c5d1SDavid du Colombier 		for (; npad > 0; npad--) {
4143e12c5d1SDavid du Colombier 			*(*--pp) = ii;
4153e12c5d1SDavid du Colombier 			if (j) {
4163e12c5d1SDavid du Colombier 				j -= HOR;
4173e12c5d1SDavid du Colombier 				(*(*pp)) += HOR;
4183e12c5d1SDavid du Colombier 			}
4193e12c5d1SDavid du Colombier 		}
4203e12c5d1SDavid du Colombier 		pushback(fbuf);
4213e12c5d1SDavid du Colombier 		jj = 0;
4223e12c5d1SDavid du Colombier 	} else if (type == 0) {
4233e12c5d1SDavid du Colombier 		/*plain tab or leader*/
4243e12c5d1SDavid du Colombier 		if ((j = width(rchar)) > 0) {
4253e12c5d1SDavid du Colombier 			int nchar = length / j;
4263e12c5d1SDavid du Colombier 			while (nchar-->0 && pbp < &pbbuf[NC-3]) {
427219b2ee8SDavid du Colombier 				numtabp[HP].val += j;
4283e12c5d1SDavid du Colombier 				widthp = j;
4293e12c5d1SDavid du Colombier 				*pbp++ = rchar;
4303e12c5d1SDavid du Colombier 			}
4313e12c5d1SDavid du Colombier 			length %= j;
4323e12c5d1SDavid du Colombier 		}
4333e12c5d1SDavid du Colombier 		if (length)
4343e12c5d1SDavid du Colombier 			jj = length | MOT;
4353e12c5d1SDavid du Colombier 		else
4363e12c5d1SDavid du Colombier 			jj = getch0();
437219b2ee8SDavid du Colombier 		if (savepos > 0)
438219b2ee8SDavid du Colombier 			pushback(wbuf);
4393e12c5d1SDavid du Colombier 	} else {
4403e12c5d1SDavid du Colombier 		/*center tab*/
4413e12c5d1SDavid du Colombier 		/*right tab*/
4423e12c5d1SDavid du Colombier 		while ((j = cbits(ii = getch())) != savtc && j != '\n' && j != savlc) {
4433e12c5d1SDavid du Colombier 			jj = width(ii);
4443e12c5d1SDavid du Colombier 			ws += jj;
445219b2ee8SDavid du Colombier 			numtabp[HP].val += jj;
4463e12c5d1SDavid du Colombier 			widthp = jj;
4473e12c5d1SDavid du Colombier 			*fp++ = ii;
4483e12c5d1SDavid du Colombier 			if (fp > fbuf + FBUFSZ - 3)
4493e12c5d1SDavid du Colombier 				break;
4503e12c5d1SDavid du Colombier 		}
4513e12c5d1SDavid du Colombier 		*fp++ = ii;
4523e12c5d1SDavid du Colombier 		*fp = 0;
4533e12c5d1SDavid du Colombier 		if (type == RTAB)
4543e12c5d1SDavid du Colombier 			length -= ws;
4553e12c5d1SDavid du Colombier 		else
4563e12c5d1SDavid du Colombier 			length -= ws / 2; /*CTAB*/
4573e12c5d1SDavid du Colombier 		pushback(fbuf);
4583e12c5d1SDavid du Colombier 		if ((j = width(rchar)) != 0 && length > 0) {
4593e12c5d1SDavid du Colombier 			int nchar = length / j;
4603e12c5d1SDavid du Colombier 			while (nchar-- > 0 && pbp < &pbbuf[NC-3])
4613e12c5d1SDavid du Colombier 				*pbp++ = rchar;
4623e12c5d1SDavid du Colombier 			length %= j;
4633e12c5d1SDavid du Colombier 		}
464219b2ee8SDavid du Colombier 		if (savepos > 0)
465219b2ee8SDavid du Colombier 			pushback(wbuf);
4663e12c5d1SDavid du Colombier 		length = (length / HOR) * HOR;
4673e12c5d1SDavid du Colombier 		jj = makem(length);
468219b2ee8SDavid du Colombier 		if (nlflg) {
469219b2ee8SDavid du Colombier 			if (ip == 0)
470219b2ee8SDavid du Colombier 				numtabp[CD].val--;
4713e12c5d1SDavid du Colombier 			nlflg = 0;
4723e12c5d1SDavid du Colombier 		}
473219b2ee8SDavid du Colombier 	}
4743e12c5d1SDavid du Colombier rtn:
4753e12c5d1SDavid du Colombier 	gchtab[fc] &= ~FCBIT;
4763e12c5d1SDavid du Colombier 	gchtab[tabch] &= ~TABBIT;
4773e12c5d1SDavid du Colombier 	gchtab[ldrch] &= ~LDRBIT;
4783e12c5d1SDavid du Colombier 	fc = savfc;
4793e12c5d1SDavid du Colombier 	tabch = savtc;
4803e12c5d1SDavid du Colombier 	ldrch = savlc;
4813e12c5d1SDavid du Colombier 	gchtab[fc] |= FCBIT;
4823e12c5d1SDavid du Colombier 	gchtab[tabch] = TABBIT;
4833e12c5d1SDavid du Colombier 	gchtab[ldrch] |= LDRBIT;
484219b2ee8SDavid du Colombier 	numtabp[HP].val = savepos;
4853e12c5d1SDavid du Colombier 	return(jj);
4863e12c5d1SDavid du Colombier }
487