1 #include "e.h"
2 #include "y.tab.h"
3 #include <ctype.h>
4 
5 #define	CSSIZE	1000
6 char	cs[CSSIZE+20];	/* text string converted into this */
7 char	*csp;		/* next spot in cs[] */
8 char	*psp;		/* next character in input token */
9 
10 int	lf, rf;		/* temporary spots for left and right fonts */
11 int	lastft;		/* last \f added */
12 int	nextft;		/* next \f to be added */
13 
14 int	pclass;		/* class of previous character */
15 int	nclass;		/* class of next character */
16 
17 int class[LAST][LAST] ={	/* guesswork, tuned to times roman postscript */
18 
19 	/*OT OL IL DG LP RP SL PL IF IJ VB */
20 /*OT*/	{ 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 0 },		/* OTHER */
21 /*OL*/	{ 1, 0, 1, 1, 1, 1, 1, 2, 2, 2, 0 },		/* OLET */
22 /*IL*/	{ 1, 1, 0, 1, 1, 1, 1, 3, 2, 1, 0 },		/* ILET */
23 /*DG*/	{ 1, 1, 1, 0, 1, 1, 1, 2, 2, 2, 0 },		/* DIG */
24 /*LP*/	{ 1, 1, 1, 1, 1, 2, 1, 2, 3, 3, 0 },		/* LPAR */
25 /*RP*/	{ 2, 2, 2, 1, 1, 1, 1, 2, 3, 3, 0 },		/* RPAR */
26 /*SL*/	{ 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 0 },		/* SLASH */
27 /*PL*/	{ 2, 2, 2, 2, 2, 2, 3, 2, 3, 2, 0 },		/* PLUS */
28 /*IF*/	{ 3, 3, 1, 2, 2, 3, 2, 3, 0, 1, 1 },		/* ILETF */
29 /*IJ*/	{ 1, 1, 1, 1, 1, 1, 1, 2, 2, 0, 0 },		/* ILETJ */
30 /*VB*/	{ 4, 4, 4, 4, 4, 4, 4, 4, 5, 4, 1 },		/* VBAR */
31 
32 };
33 
34 extern void shim(int, int);
35 extern void roman(int);
36 extern void sadd(char *);
37 extern void cadd(int);
38 extern int trans(int, char *);
39 
textc(void)40 int textc(void)	/* read next UTF rune from psp */
41 {
42 	wchar_t r;
43 	int w;
44 
45 	w = mbtowc(&r, psp, 3);
46 	if(w == 0){
47 		psp++;
48 		return 0;
49 	}
50 	if(w < 0){
51 		psp += 1;
52 		return 0x80;	/* Plan 9-ism */
53 	}
54 	psp += w;
55 	return r;
56 }
57 
text(int t,char * p1)58 void text(int t, char *p1)	/* convert text string p1 of type t */
59 {
60 	int c;
61 	char *p;
62 	tbl *tp;
63 
64 	yyval = salloc();
65 	ebase[yyval] = 0;
66 	eht[yyval] = EM(1.0, ps);	/* ht in ems of orig size */
67 	lfont[yyval] = rfont[yyval] = ROM;
68 	lclass[yyval] = rclass[yyval] = OTHER;
69 	if (t == QTEXT) {
70 		for (p = p1; *p; p++)	/* scan for embedded \f's */
71 			if (*p == '\\' && *(p+1) == 'f')
72 				break;
73 		if (*p)		/* if found \f, leave it alone and hope */
74 			p = p1;
75 		else {
76 			sprintf(cs, "\\f%s%s\\fP", ftp->name, p1);
77 			p = cs;
78 		}
79 	} else if (t == SPACE)
80 		p = "\\ ";
81 	else if (t == THIN)
82 		p = "\\|";
83 	else if (t == TAB)
84 		p = "\\t";
85 	else if ((tp = lookup(restbl, p1)) != NULL) {
86 		p = tp->cval;
87 	} else {
88 		lf = rf = 0;
89 		lastft = 0;
90 		nclass = NONE;	/* get started with no class == no pad */
91 		csp = cs;
92 		for (psp = p1; (c = textc()) != '\0'; ) {
93 			nextft = ft;
94 			pclass = nclass;
95 			rf = trans(c, p1);
96 			if (lf == 0) {
97 				lf = rf;	/* left stuff is first found */
98 				lclass[yyval] = nclass;
99 			}
100 			if (csp-cs > CSSIZE)
101 				ERROR "converted token %.25s... too long", p1 FATAL ;
102 		}
103 		sadd("\\fP");
104 		*csp = '\0';
105 		p = cs;
106 		lfont[yyval] = lf;
107 		rfont[yyval] = rf;
108 		rclass[yyval] = nclass;
109 	}
110 	dprintf(".\t%dtext: S%d <- %s; b=%g,h=%g,lf=%c,rf=%c,ps=%d\n",
111 		t, (int)yyval, p, ebase[yyval], eht[yyval], lfont[yyval], rfont[yyval], ps);
112 	printf(".ds %d \"%s\n", (int)yyval, p);
113 }
114 
isalpharune(int c)115 int isalpharune(int c)
116 {
117 	return ('a'<=c && c<='z') || ('A'<=c && c<='Z');
118 }
119 
isdigitrune(int c)120 int isdigitrune(int c)
121 {
122 	return ('0'<=c && c<='9');
123 }
124 
125 int
trans(int c,char * p1)126 trans(int c, char *p1)
127 {
128 	int f;
129 
130 	if (isalpharune(c) && ft == ITAL && c != 'f' && c != 'j') {	/* italic letter */
131 		shim(pclass, nclass = ILET);
132 		cadd(c);
133 		return ITAL;
134 	}
135 	if (isalpharune(c) && ft != ITAL) {		/* other letter */
136 		shim(pclass, nclass = OLET);
137 		cadd(c);
138 		return ROM;
139 	}
140 	if (isdigitrune(c)) {
141 		shim(pclass, nclass = DIG);
142 		roman(c);
143 		return ROM;	/* this is the right side font of this object */
144 	}
145 	f = ROM;
146 	nclass = OTHER;
147 	switch (c) {
148 	case ':': case ';': case '!': case '%': case '?':
149 		shim(pclass, nclass);
150 		roman(c);
151 		return f;
152 	case '(': case '[':
153 		shim(pclass, nclass = LPAR);
154 		roman(c);
155 		return f;
156 	case ')': case ']':
157 		shim(pclass, nclass = RPAR);
158 		roman(c);
159 		return f;
160 	case ',':
161 		shim(pclass, nclass = OTHER);
162 		roman(c);
163 		return f;
164 	case '.':
165 		if (rf == ROM)
166 			roman(c);
167 		else
168 			cadd(c);
169 		return f;
170 	case '|':		/* postscript needs help with default width! */
171 		shim(pclass, nclass = VBAR);
172 		sadd("\\v'.17m'\\z|\\v'-.17m'\\|");	/* and height */
173 		return f;
174 	case '=':
175 		shim(pclass, nclass = PLUS);
176 		sadd("\\(eq");
177 		return f;
178 	case '+':
179 		shim(pclass, nclass = PLUS);
180 		sadd("\\(pl");
181 		return f;
182 	case '>':
183 	case '<':		/* >, >=, >>, <, <-, <=, << */
184 		shim(pclass, nclass = PLUS);
185 		if (*psp == '=') {
186 			sadd(c == '<' ? "\\(<=" : "\\(>=");
187 			psp++;
188 		} else if (c == '<' && *psp == '-') {	/* <- only */
189 			sadd("\\(<-");
190 			psp++;
191 		} else if (*psp == c) {		/* << or >> */
192 			cadd(c);
193 			cadd(c);
194 			psp++;
195 		} else {
196 			cadd(c);
197 		}
198 		return f;
199 	case '-':
200 		shim(pclass, nclass = PLUS);	/* probably too big for ->'s */
201 		if (*psp == '>') {
202 			sadd("\\(->");
203 			psp++;
204 		} else {
205 			sadd("\\(mi");
206 		}
207 		return f;
208 	case '/':
209 		shim(pclass, nclass = SLASH);
210 		cadd('/');
211 		return f;
212 	case '~':
213 	case ' ':
214 		sadd("\\|\\|");
215 		return f;
216 	case '^':
217 		sadd("\\|");
218 		return f;
219 	case '\\':	/* troff - pass only \(xx without comment */
220 		shim(pclass, nclass);
221 		cadd('\\');
222 		cadd(c = *psp++);
223 		if (c == '(' && *psp && *(psp+1)) {
224 			cadd(*psp++);
225 			cadd(*psp++);
226 		} else
227 			fprintf(stderr, "eqn warning: unquoted troff command \\%c, file %s:%d\n",
228 				c, curfile->fname, curfile->lineno);
229 		return f;
230 	case '\'':
231 		shim(pclass, nclass);
232 		sadd("\\(fm");
233 		return f;
234 
235 	case 'f':
236 		if (ft == ITAL) {
237 			shim(pclass, nclass = ILETF);
238 			cadd('f');
239 			f = ITAL;
240 		} else
241 			cadd('f');
242 		return f;
243 	case 'j':
244 		if (ft == ITAL) {
245 			shim(pclass, nclass = ILETJ);
246 			cadd('j');
247 			f = ITAL;
248 		} else
249 			cadd('j');
250 		return f;
251 	default:
252 		shim(pclass, nclass);
253 		cadd(c);
254 		return ft==ITAL ? ITAL : ROM;
255 	}
256 }
257 
pad(int n)258 char *pad(int n)	/* return the padding as a string */
259 {
260 	static char buf[30];
261 
262 	buf[0] = 0;
263 	if (n < 0) {
264 		sprintf(buf, "\\h'-%du*\\w'\\^'u'", -n);
265 		return buf;
266 	}
267 	for ( ; n > 1; n -= 2)
268 		strcat(buf, "\\|");
269 	if (n > 0)
270 		strcat(buf, "\\^");
271 	return buf;
272 }
273 
shim(int lc,int rc)274 void shim(int lc, int rc)	/* add padding space suitable to left and right classes */
275 {
276 	sadd(pad(class[lc][rc]));
277 }
278 
roman(int c)279 void roman(int c)	/* add char c in "roman" font */
280 {
281 	nextft = ROM;
282 	cadd(c);
283 }
284 
sadd(char * s)285 void sadd(char *s)		/* add string s to cs */
286 {
287 	while (*s)
288 		cadd(*s++);
289 }
290 
cadd(int c)291 void cadd(int c)		/* add character c to end of cs */
292 {
293 	char *p;
294 	int w;
295 
296 	if (lastft != nextft) {
297 		if (lastft != 0) {
298 			*csp++ = '\\';
299 			*csp++ = 'f';
300 			*csp++ = 'P';
301 		}
302 		*csp++ = '\\';
303 		*csp++ = 'f';
304 		if (ftp == ftstack) {	/* bottom level */
305 			if (ftp->ft == ITAL)	/* usual case */
306 				*csp++ = nextft;
307 			else		/* gfont set, use it */
308 				for (p = ftp->name; (*csp = *p++); )
309 					csp++;
310 		} else {	/* inside some kind of font ... */
311 			for (p = ftp->name; (*csp = *p++); )
312 				csp++;
313 		}
314 		lastft = nextft;
315 	}
316 	w = wctomb(csp, c);
317 	if(w > 0)	/* ignore bad characters */
318 		csp += w;
319 }
320