xref: /plan9/sys/src/cmd/eqn/text.c (revision 2651f6bb1dce6979361f5f2d230af377da2d5a92)
13e12c5d1SDavid du Colombier #include "e.h"
23e12c5d1SDavid du Colombier #include "y.tab.h"
33e12c5d1SDavid du Colombier #include <ctype.h>
4*2651f6bbSDavid du Colombier #include <utf.h>
53e12c5d1SDavid du Colombier 
63e12c5d1SDavid du Colombier #define	CSSIZE	1000
73e12c5d1SDavid du Colombier char	cs[CSSIZE+20];	/* text string converted into this */
83e12c5d1SDavid du Colombier char	*csp;		/* next spot in cs[] */
93e12c5d1SDavid du Colombier char	*psp;		/* next character in input token */
103e12c5d1SDavid du Colombier 
113e12c5d1SDavid du Colombier int	lf, rf;		/* temporary spots for left and right fonts */
123e12c5d1SDavid du Colombier int	lastft;		/* last \f added */
133e12c5d1SDavid du Colombier int	nextft;		/* next \f to be added */
143e12c5d1SDavid du Colombier 
153e12c5d1SDavid du Colombier int	pclass;		/* class of previous character */
163e12c5d1SDavid du Colombier int	nclass;		/* class of next character */
173e12c5d1SDavid du Colombier 
183e12c5d1SDavid du Colombier int class[LAST][LAST] ={	/* guesswork, tuned to times roman postscript */
193e12c5d1SDavid du Colombier 
203e12c5d1SDavid du Colombier 	/*OT OL IL DG LP RP SL PL IF IJ VB */
213e12c5d1SDavid du Colombier /*OT*/	{ 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 0 },		/* OTHER */
223e12c5d1SDavid du Colombier /*OL*/	{ 1, 0, 1, 1, 1, 1, 1, 2, 2, 2, 0 },		/* OLET */
233e12c5d1SDavid du Colombier /*IL*/	{ 1, 1, 0, 1, 1, 1, 1, 3, 2, 1, 0 },		/* ILET */
243e12c5d1SDavid du Colombier /*DG*/	{ 1, 1, 1, 0, 1, 1, 1, 2, 2, 2, 0 },		/* DIG */
253e12c5d1SDavid du Colombier /*LP*/	{ 1, 1, 1, 1, 1, 2, 1, 2, 3, 3, 0 },		/* LPAR */
263e12c5d1SDavid du Colombier /*RP*/	{ 2, 2, 2, 1, 1, 1, 1, 2, 3, 3, 0 },		/* RPAR */
273e12c5d1SDavid du Colombier /*SL*/	{ 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 0 },		/* SLASH */
283e12c5d1SDavid du Colombier /*PL*/	{ 2, 2, 2, 2, 2, 2, 3, 2, 3, 2, 0 },		/* PLUS */
293e12c5d1SDavid du Colombier /*IF*/	{ 3, 3, 1, 2, 2, 3, 2, 3, 0, 1, 1 },		/* ILETF */
303e12c5d1SDavid du Colombier /*IJ*/	{ 1, 1, 1, 1, 1, 1, 1, 2, 2, 0, 0 },		/* ILETJ */
313e12c5d1SDavid du Colombier /*VB*/	{ 4, 4, 4, 4, 4, 4, 4, 4, 5, 4, 1 },		/* VBAR */
323e12c5d1SDavid du Colombier 
333e12c5d1SDavid du Colombier };
343e12c5d1SDavid du Colombier 
353e12c5d1SDavid du Colombier extern void shim(int, int);
363e12c5d1SDavid du Colombier extern void roman(int);
373e12c5d1SDavid du Colombier extern void sadd(char *);
383e12c5d1SDavid du Colombier extern void cadd(int);
393e12c5d1SDavid du Colombier extern int trans(int, char *);
403e12c5d1SDavid du Colombier 
textc(void)417dd7cddfSDavid du Colombier int textc(void)	/* read next UTF rune from psp */
427dd7cddfSDavid du Colombier {
437dd7cddfSDavid du Colombier 	wchar_t r;
447dd7cddfSDavid du Colombier 	int w;
457dd7cddfSDavid du Colombier 
46*2651f6bbSDavid du Colombier 	w = mbtowc(&r, psp, UTFmax);
477dd7cddfSDavid du Colombier 	if(w == 0){
487dd7cddfSDavid du Colombier 		psp++;
497dd7cddfSDavid du Colombier 		return 0;
507dd7cddfSDavid du Colombier 	}
517dd7cddfSDavid du Colombier 	if(w < 0){
527dd7cddfSDavid du Colombier 		psp += 1;
53*2651f6bbSDavid du Colombier 		return Runeerror;	/* Plan 9-ism */
547dd7cddfSDavid du Colombier 	}
557dd7cddfSDavid du Colombier 	psp += w;
567dd7cddfSDavid du Colombier 	return r;
577dd7cddfSDavid du Colombier }
587dd7cddfSDavid du Colombier 
text(int t,char * p1)593e12c5d1SDavid du Colombier void text(int t, char *p1)	/* convert text string p1 of type t */
603e12c5d1SDavid du Colombier {
613e12c5d1SDavid du Colombier 	int c;
623e12c5d1SDavid du Colombier 	char *p;
633e12c5d1SDavid du Colombier 	tbl *tp;
643e12c5d1SDavid du Colombier 
653e12c5d1SDavid du Colombier 	yyval = salloc();
663e12c5d1SDavid du Colombier 	ebase[yyval] = 0;
673e12c5d1SDavid du Colombier 	eht[yyval] = EM(1.0, ps);	/* ht in ems of orig size */
683e12c5d1SDavid du Colombier 	lfont[yyval] = rfont[yyval] = ROM;
693e12c5d1SDavid du Colombier 	lclass[yyval] = rclass[yyval] = OTHER;
703e12c5d1SDavid du Colombier 	if (t == QTEXT) {
713e12c5d1SDavid du Colombier 		for (p = p1; *p; p++)	/* scan for embedded \f's */
723e12c5d1SDavid du Colombier 			if (*p == '\\' && *(p+1) == 'f')
733e12c5d1SDavid du Colombier 				break;
743e12c5d1SDavid du Colombier 		if (*p)		/* if found \f, leave it alone and hope */
753e12c5d1SDavid du Colombier 			p = p1;
763e12c5d1SDavid du Colombier 		else {
773e12c5d1SDavid du Colombier 			sprintf(cs, "\\f%s%s\\fP", ftp->name, p1);
783e12c5d1SDavid du Colombier 			p = cs;
793e12c5d1SDavid du Colombier 		}
803e12c5d1SDavid du Colombier 	} else if (t == SPACE)
813e12c5d1SDavid du Colombier 		p = "\\ ";
823e12c5d1SDavid du Colombier 	else if (t == THIN)
833e12c5d1SDavid du Colombier 		p = "\\|";
843e12c5d1SDavid du Colombier 	else if (t == TAB)
853e12c5d1SDavid du Colombier 		p = "\\t";
863e12c5d1SDavid du Colombier 	else if ((tp = lookup(restbl, p1)) != NULL) {
873e12c5d1SDavid du Colombier 		p = tp->cval;
883e12c5d1SDavid du Colombier 	} else {
893e12c5d1SDavid du Colombier 		lf = rf = 0;
903e12c5d1SDavid du Colombier 		lastft = 0;
913e12c5d1SDavid du Colombier 		nclass = NONE;	/* get started with no class == no pad */
923e12c5d1SDavid du Colombier 		csp = cs;
937dd7cddfSDavid du Colombier 		for (psp = p1; (c = textc()) != '\0'; ) {
943e12c5d1SDavid du Colombier 			nextft = ft;
953e12c5d1SDavid du Colombier 			pclass = nclass;
963e12c5d1SDavid du Colombier 			rf = trans(c, p1);
973e12c5d1SDavid du Colombier 			if (lf == 0) {
983e12c5d1SDavid du Colombier 				lf = rf;	/* left stuff is first found */
993e12c5d1SDavid du Colombier 				lclass[yyval] = nclass;
1003e12c5d1SDavid du Colombier 			}
1013e12c5d1SDavid du Colombier 			if (csp-cs > CSSIZE)
1023e12c5d1SDavid du Colombier 				ERROR "converted token %.25s... too long", p1 FATAL ;
1033e12c5d1SDavid du Colombier 		}
1043e12c5d1SDavid du Colombier 		sadd("\\fP");
1053e12c5d1SDavid du Colombier 		*csp = '\0';
1063e12c5d1SDavid du Colombier 		p = cs;
1073e12c5d1SDavid du Colombier 		lfont[yyval] = lf;
1083e12c5d1SDavid du Colombier 		rfont[yyval] = rf;
1093e12c5d1SDavid du Colombier 		rclass[yyval] = nclass;
1103e12c5d1SDavid du Colombier 	}
1113e12c5d1SDavid du Colombier 	dprintf(".\t%dtext: S%d <- %s; b=%g,h=%g,lf=%c,rf=%c,ps=%d\n",
1123e12c5d1SDavid du Colombier 		t, yyval, p, ebase[yyval], eht[yyval], lfont[yyval], rfont[yyval], ps);
1133e12c5d1SDavid du Colombier 	printf(".ds %d \"%s\n", yyval, p);
1143e12c5d1SDavid du Colombier }
1153e12c5d1SDavid du Colombier 
isdigitrune(int c)1167dd7cddfSDavid du Colombier int isdigitrune(int c)
1177dd7cddfSDavid du Colombier {
1187dd7cddfSDavid du Colombier 	return ('0'<=c && c<='9');
1197dd7cddfSDavid du Colombier }
1207dd7cddfSDavid du Colombier 
121*2651f6bbSDavid du Colombier int
trans(int c,char *)122*2651f6bbSDavid du Colombier trans(int c, char *)
1233e12c5d1SDavid du Colombier {
1243e12c5d1SDavid du Colombier 	int f;
1253e12c5d1SDavid du Colombier 
1267dd7cddfSDavid du Colombier 	if (isalpharune(c) && ft == ITAL && c != 'f' && c != 'j') {	/* italic letter */
1273e12c5d1SDavid du Colombier 		shim(pclass, nclass = ILET);
1283e12c5d1SDavid du Colombier 		cadd(c);
1293e12c5d1SDavid du Colombier 		return ITAL;
1303e12c5d1SDavid du Colombier 	}
1317dd7cddfSDavid du Colombier 	if (isalpharune(c) && ft != ITAL) {		/* other letter */
1323e12c5d1SDavid du Colombier 		shim(pclass, nclass = OLET);
1333e12c5d1SDavid du Colombier 		cadd(c);
1343e12c5d1SDavid du Colombier 		return ROM;
1353e12c5d1SDavid du Colombier 	}
1367dd7cddfSDavid du Colombier 	if (isdigitrune(c)) {
1373e12c5d1SDavid du Colombier 		shim(pclass, nclass = DIG);
1383e12c5d1SDavid du Colombier 		roman(c);
1393e12c5d1SDavid du Colombier 		return ROM;	/* this is the right side font of this object */
1403e12c5d1SDavid du Colombier 	}
1413e12c5d1SDavid du Colombier 	f = ROM;
1423e12c5d1SDavid du Colombier 	nclass = OTHER;
1433e12c5d1SDavid du Colombier 	switch (c) {
1443e12c5d1SDavid du Colombier 	case ':': case ';': case '!': case '%': case '?':
1453e12c5d1SDavid du Colombier 		shim(pclass, nclass);
1463e12c5d1SDavid du Colombier 		roman(c);
1473e12c5d1SDavid du Colombier 		return f;
1483e12c5d1SDavid du Colombier 	case '(': case '[':
1493e12c5d1SDavid du Colombier 		shim(pclass, nclass = LPAR);
1503e12c5d1SDavid du Colombier 		roman(c);
1513e12c5d1SDavid du Colombier 		return f;
1523e12c5d1SDavid du Colombier 	case ')': case ']':
1533e12c5d1SDavid du Colombier 		shim(pclass, nclass = RPAR);
1543e12c5d1SDavid du Colombier 		roman(c);
1553e12c5d1SDavid du Colombier 		return f;
1563e12c5d1SDavid du Colombier 	case ',':
1573e12c5d1SDavid du Colombier 		shim(pclass, nclass = OTHER);
1583e12c5d1SDavid du Colombier 		roman(c);
1593e12c5d1SDavid du Colombier 		return f;
1603e12c5d1SDavid du Colombier 	case '.':
1613e12c5d1SDavid du Colombier 		if (rf == ROM)
1623e12c5d1SDavid du Colombier 			roman(c);
1633e12c5d1SDavid du Colombier 		else
1643e12c5d1SDavid du Colombier 			cadd(c);
1653e12c5d1SDavid du Colombier 		return f;
1663e12c5d1SDavid du Colombier 	case '|':		/* postscript needs help with default width! */
1673e12c5d1SDavid du Colombier 		shim(pclass, nclass = VBAR);
1683e12c5d1SDavid du Colombier 		sadd("\\v'.17m'\\z|\\v'-.17m'\\|");	/* and height */
1693e12c5d1SDavid du Colombier 		return f;
1703e12c5d1SDavid du Colombier 	case '=':
1713e12c5d1SDavid du Colombier 		shim(pclass, nclass = PLUS);
1723e12c5d1SDavid du Colombier 		sadd("\\(eq");
1733e12c5d1SDavid du Colombier 		return f;
1743e12c5d1SDavid du Colombier 	case '+':
1753e12c5d1SDavid du Colombier 		shim(pclass, nclass = PLUS);
1763e12c5d1SDavid du Colombier 		sadd("\\(pl");
1773e12c5d1SDavid du Colombier 		return f;
1783e12c5d1SDavid du Colombier 	case '>':
1793e12c5d1SDavid du Colombier 	case '<':		/* >, >=, >>, <, <-, <=, << */
1803e12c5d1SDavid du Colombier 		shim(pclass, nclass = PLUS);
1813e12c5d1SDavid du Colombier 		if (*psp == '=') {
1823e12c5d1SDavid du Colombier 			sadd(c == '<' ? "\\(<=" : "\\(>=");
1833e12c5d1SDavid du Colombier 			psp++;
1843e12c5d1SDavid du Colombier 		} else if (c == '<' && *psp == '-') {	/* <- only */
1853e12c5d1SDavid du Colombier 			sadd("\\(<-");
1863e12c5d1SDavid du Colombier 			psp++;
1873e12c5d1SDavid du Colombier 		} else if (*psp == c) {		/* << or >> */
1883e12c5d1SDavid du Colombier 			cadd(c);
1893e12c5d1SDavid du Colombier 			cadd(c);
1903e12c5d1SDavid du Colombier 			psp++;
1913e12c5d1SDavid du Colombier 		} else {
1923e12c5d1SDavid du Colombier 			cadd(c);
1933e12c5d1SDavid du Colombier 		}
1943e12c5d1SDavid du Colombier 		return f;
1953e12c5d1SDavid du Colombier 	case '-':
1963e12c5d1SDavid du Colombier 		shim(pclass, nclass = PLUS);	/* probably too big for ->'s */
1973e12c5d1SDavid du Colombier 		if (*psp == '>') {
1983e12c5d1SDavid du Colombier 			sadd("\\(->");
1993e12c5d1SDavid du Colombier 			psp++;
2003e12c5d1SDavid du Colombier 		} else {
2013e12c5d1SDavid du Colombier 			sadd("\\(mi");
2023e12c5d1SDavid du Colombier 		}
2033e12c5d1SDavid du Colombier 		return f;
2043e12c5d1SDavid du Colombier 	case '/':
2053e12c5d1SDavid du Colombier 		shim(pclass, nclass = SLASH);
2063e12c5d1SDavid du Colombier 		cadd('/');
2073e12c5d1SDavid du Colombier 		return f;
2083e12c5d1SDavid du Colombier 	case '~':
2093e12c5d1SDavid du Colombier 	case ' ':
2103e12c5d1SDavid du Colombier 		sadd("\\|\\|");
2113e12c5d1SDavid du Colombier 		return f;
2123e12c5d1SDavid du Colombier 	case '^':
2133e12c5d1SDavid du Colombier 		sadd("\\|");
2143e12c5d1SDavid du Colombier 		return f;
2153e12c5d1SDavid du Colombier 	case '\\':	/* troff - pass only \(xx without comment */
2163e12c5d1SDavid du Colombier 		shim(pclass, nclass);
2173e12c5d1SDavid du Colombier 		cadd('\\');
2183e12c5d1SDavid du Colombier 		cadd(c = *psp++);
2193e12c5d1SDavid du Colombier 		if (c == '(' && *psp && *(psp+1)) {
2203e12c5d1SDavid du Colombier 			cadd(*psp++);
2213e12c5d1SDavid du Colombier 			cadd(*psp++);
2223e12c5d1SDavid du Colombier 		} else
2237dd7cddfSDavid du Colombier 			fprintf(stderr, "eqn warning: unquoted troff command \\%c, file %s:%d\n",
2247dd7cddfSDavid du Colombier 				c, curfile->fname, curfile->lineno);
2253e12c5d1SDavid du Colombier 		return f;
2263e12c5d1SDavid du Colombier 	case '\'':
2273e12c5d1SDavid du Colombier 		shim(pclass, nclass);
2283e12c5d1SDavid du Colombier 		sadd("\\(fm");
2293e12c5d1SDavid du Colombier 		return f;
2303e12c5d1SDavid du Colombier 
2313e12c5d1SDavid du Colombier 	case 'f':
2323e12c5d1SDavid du Colombier 		if (ft == ITAL) {
2333e12c5d1SDavid du Colombier 			shim(pclass, nclass = ILETF);
2343e12c5d1SDavid du Colombier 			cadd('f');
2353e12c5d1SDavid du Colombier 			f = ITAL;
2363e12c5d1SDavid du Colombier 		} else
2373e12c5d1SDavid du Colombier 			cadd('f');
2383e12c5d1SDavid du Colombier 		return f;
2393e12c5d1SDavid du Colombier 	case 'j':
2403e12c5d1SDavid du Colombier 		if (ft == ITAL) {
2413e12c5d1SDavid du Colombier 			shim(pclass, nclass = ILETJ);
2423e12c5d1SDavid du Colombier 			cadd('j');
2433e12c5d1SDavid du Colombier 			f = ITAL;
2443e12c5d1SDavid du Colombier 		} else
2453e12c5d1SDavid du Colombier 			cadd('j');
2463e12c5d1SDavid du Colombier 		return f;
2473e12c5d1SDavid du Colombier 	default:
2483e12c5d1SDavid du Colombier 		shim(pclass, nclass);
2493e12c5d1SDavid du Colombier 		cadd(c);
2503e12c5d1SDavid du Colombier 		return ft==ITAL ? ITAL : ROM;
2513e12c5d1SDavid du Colombier 	}
2523e12c5d1SDavid du Colombier }
2533e12c5d1SDavid du Colombier 
pad(int n)2543e12c5d1SDavid du Colombier char *pad(int n)	/* return the padding as a string */
2553e12c5d1SDavid du Colombier {
2563e12c5d1SDavid du Colombier 	static char buf[20];
2573e12c5d1SDavid du Colombier 
2583e12c5d1SDavid du Colombier 	buf[0] = 0;
2593e12c5d1SDavid du Colombier 	if (n < 0) {
2603e12c5d1SDavid du Colombier 		sprintf(buf, "\\h'-%du*\\w'\\^'u'", -n);
2613e12c5d1SDavid du Colombier 		return buf;
2623e12c5d1SDavid du Colombier 	}
2633e12c5d1SDavid du Colombier 	for ( ; n > 1; n -= 2)
2643e12c5d1SDavid du Colombier 		strcat(buf, "\\|");
2653e12c5d1SDavid du Colombier 	if (n > 0)
2663e12c5d1SDavid du Colombier 		strcat(buf, "\\^");
2673e12c5d1SDavid du Colombier 	return buf;
2683e12c5d1SDavid du Colombier }
2693e12c5d1SDavid du Colombier 
shim(int lc,int rc)2703e12c5d1SDavid du Colombier void shim(int lc, int rc)	/* add padding space suitable to left and right classes */
2713e12c5d1SDavid du Colombier {
2723e12c5d1SDavid du Colombier 	sadd(pad(class[lc][rc]));
2733e12c5d1SDavid du Colombier }
2743e12c5d1SDavid du Colombier 
roman(int c)2753e12c5d1SDavid du Colombier void roman(int c)	/* add char c in "roman" font */
2763e12c5d1SDavid du Colombier {
2773e12c5d1SDavid du Colombier 	nextft = ROM;
2783e12c5d1SDavid du Colombier 	cadd(c);
2793e12c5d1SDavid du Colombier }
2803e12c5d1SDavid du Colombier 
sadd(char * s)2813e12c5d1SDavid du Colombier void sadd(char *s)		/* add string s to cs */
2823e12c5d1SDavid du Colombier {
2833e12c5d1SDavid du Colombier 	while (*s)
2843e12c5d1SDavid du Colombier 		cadd(*s++);
2853e12c5d1SDavid du Colombier }
2863e12c5d1SDavid du Colombier 
cadd(int c)2877dd7cddfSDavid du Colombier void cadd(int c)		/* add character c to end of cs */
2883e12c5d1SDavid du Colombier {
2893e12c5d1SDavid du Colombier 	char *p;
2907dd7cddfSDavid du Colombier 	int w;
2913e12c5d1SDavid du Colombier 
2923e12c5d1SDavid du Colombier 	if (lastft != nextft) {
2933e12c5d1SDavid du Colombier 		if (lastft != 0) {
2943e12c5d1SDavid du Colombier 			*csp++ = '\\';
2953e12c5d1SDavid du Colombier 			*csp++ = 'f';
2963e12c5d1SDavid du Colombier 			*csp++ = 'P';
2973e12c5d1SDavid du Colombier 		}
2983e12c5d1SDavid du Colombier 		*csp++ = '\\';
2993e12c5d1SDavid du Colombier 		*csp++ = 'f';
3003e12c5d1SDavid du Colombier 		if (ftp == ftstack) {	/* bottom level */
3013e12c5d1SDavid du Colombier 			if (ftp->ft == ITAL)	/* usual case */
3023e12c5d1SDavid du Colombier 				*csp++ = nextft;
3033e12c5d1SDavid du Colombier 			else		/* gfont set, use it */
3043e12c5d1SDavid du Colombier 				for (p = ftp->name; *csp = *p++; )
3053e12c5d1SDavid du Colombier 					csp++;
3063e12c5d1SDavid du Colombier 		} else {	/* inside some kind of font ... */
3073e12c5d1SDavid du Colombier 			for (p = ftp->name; *csp = *p++; )
3083e12c5d1SDavid du Colombier 				csp++;
3093e12c5d1SDavid du Colombier 		}
3103e12c5d1SDavid du Colombier 		lastft = nextft;
3113e12c5d1SDavid du Colombier 	}
3127dd7cddfSDavid du Colombier 	w = wctomb(csp, c);
3137dd7cddfSDavid du Colombier 	if(w > 0)	/* ignore bad characters */
3147dd7cddfSDavid du Colombier 		csp += w;
3153e12c5d1SDavid du Colombier }
316