xref: /plan9/sys/src/cmd/troff/t10.c (revision 14f51593fd82e19ba95969a8c07ff71131015979)
1 #include "tdef.h"
2 #include "fns.h"
3 #include "ext.h"
4 
5 /*
6  * troff10.c
7  *
8  * typesetter interface
9  */
10 
11 int	vpos	 = 0;	/* absolute vertical position on page */
12 int	hpos	 = 0;	/* ditto horizontal */
13 
14 extern Font fonts[MAXFONTS+1];
15 
16 int	Inch;
17 int	Hor;
18 int	Vert;
19 int	Unitwidth;
20 int	nfonts;
21 
22 
23 
t_ptinit(void)24 void t_ptinit(void)
25 {
26 	int i;
27 	char buf[100], *p;
28 
29 	hmot = t_hmot;
30 	makem = t_makem;
31 	setabs = t_setabs;
32 	setch = t_setch;
33 	sethl = t_sethl;
34 	setht = t_setht;
35 	setslant = t_setslant;
36 	vmot = t_vmot;
37 	xlss = t_xlss;
38 	findft = t_findft;
39 	width = t_width;
40 	mchbits = t_mchbits;
41 	ptlead = t_ptlead;
42 	ptout = t_ptout;
43 	ptpause = t_ptpause;
44 	setfont = t_setfont;
45 	setps = t_setps;
46 	setwd = t_setwd;
47 
48 	/* open table for device, */
49 	/* read in resolution, size info, font info, etc., set params */
50 	if ((p = getenv("TYPESETTER")) != 0){
51 		strncpy(devname, p, sizeof devname);
52 		devname[sizeof devname-1] = 0;
53 	}
54 	if (termtab[0] == 0)
55 		strcpy(termtab, DWBfontdir);
56 	if (fontdir[0] == 0)
57 		strcpy(fontdir, DWBfontdir);
58 	if (devname[0] == 0)
59 		strcpy(devname, TDEVNAME);
60 	hyf = 1;
61 	lg = 1;
62 
63 	snprintf(buf, sizeof buf, "/dev%s/DESC", devname);
64 	strcat(termtab, buf);
65 	if (getdesc(termtab) < 0) {
66 		ERROR "can't open DESC file %s", termtab WARN;
67 		done3(1);
68 	}
69 	if (!ascii) {
70 		OUT "x T %s\n", devname PUT;
71 		OUT "x res %d %d %d\n", Inch, Hor, Vert PUT;
72 		OUT "x init\n" PUT;
73 	}
74 	for (i = 1; i <= nfonts; i++)
75 		setfp(i, fontlab[i], (char *) 0, 0);
76 	sps = EM/3;	/* space size */
77 	ics = EM;	/* insertion character space */
78 	for (i = 0; i < (NTAB - 1) && DTAB * (i + 1) < TABMASK; i++)
79 		tabtab[i] = DTAB * (i + 1);
80 	tabtab[NTAB-1] = 0;
81 	pl = 11 * INCH;			/* paper length */
82 	po = PO;		/* page offset */
83 	spacesz = SS;
84 	lss = lss1 = VS;
85 	ll = ll1 = lt = lt1 = LL;
86 	t_specnames();	/* install names like "hyphen", etc. */
87 }
88 
t_specnames(void)89 void t_specnames(void)
90 {
91 	int	i;
92 
93 	for (i = 0; spnames[i].n; i++)
94 		*spnames[i].n = chadd(spnames[i].v, Troffchar, Install);
95 }
96 
t_ptout(Tchar i)97 void t_ptout(Tchar i)
98 {
99 	int dv;
100 	Tchar *k;
101 	int temp, a, b;
102 	int diff;
103 
104 	if (cbits(i) != '\n') {
105 		if (olinep >= oline + olnsize) {
106 			diff = olinep - oline;
107 			olnsize += OLNSIZE;
108 			if ((oline = (Tchar *)realloc((char *)oline, olnsize * sizeof(Tchar))) != NULL) {
109 				if (diff && olinep)
110 					olinep = oline + diff;
111 			} else {
112 				ERROR "Output line overflow." WARN;
113 				done(2);
114 			}
115 		}
116 		*olinep++ = i;
117 		return;
118 	}
119 	if (olinep == oline) {
120 		lead += lss;
121 		return;
122 	}
123 
124 	hpos = po;	/* ??? */
125 	esc = 0;	/* ??? */
126 	ptesc();	/* the problem is to get back to the left end of the line */
127 	dv = 0;
128 	for (k = oline; k < olinep; k++) {
129 		if (ismot(*k) && isvmot(*k)) {
130 			temp = absmot(*k);
131 			if (isnmot(*k))
132 				temp = -temp;
133 			dv += temp;
134 		}
135 	}
136 	if (dv) {
137 		vflag++;
138 		*olinep++ = makem(-dv);
139 		vflag = 0;
140 	}
141 
142 	b = dip->blss + lss;
143 	lead += dip->blss + lss;
144 	dip->blss = 0;
145 	for (k = oline; k < olinep; )
146 		k += ptout0(k);	/* now passing a pointer! */
147 	olinep = oline;
148 	lead += dip->alss;
149 	a = dip->alss;
150 	dip->alss = 0;
151 	/*
152 	OUT "x xxx end of line: hpos=%d, vpos=%d\n", hpos, vpos PUT;
153 */
154 	OUT "n%d %d\n", b, a PUT;	/* be nice to chuck */
155 }
156 
ptout0(Tchar * pi)157 int ptout0(Tchar *pi)
158 {
159 	int j, k, w, z, dx, dy, dx2, dy2, n;
160 	int outsize;	/* size of object being printed */
161 	Tchar i;
162 
163 	w = 0;
164 	outsize = 1;	/* default */
165 	i = *pi;
166 	k = cbits(i);
167 	if (ismot(i)) {
168 		j = absmot(i);
169 		if (isnmot(i))
170 			j = -j;
171 		if (isvmot(i))
172 			lead += j;
173 		else
174 			esc += j;
175 		return(outsize);
176 	}
177 	if (k == CHARHT) {
178 		xpts = fbits(i);	/* sneaky, font bits as size bits */
179 		if (xpts != mpts)
180 			ptps();
181 		OUT "x H %d\n", sbits(i) PUT;
182 		return(outsize);
183 	}
184 	if (k == SLANT) {
185 		OUT "x S %d\n", sfbits(i)-180 PUT;
186 		return(outsize);
187 	}
188 	if (k == WORDSP) {
189 		oput('w');
190 		return(outsize);
191 	}
192 	if (sfbits(i) == oldbits) {
193 		xfont = pfont;
194 		xpts = ppts;
195 	} else
196 		xbits(i, 2);
197 	if (k == XON) {
198 		extern int xon;
199 		ptflush();	/* guarantee that everything is out */
200 		if (esc)
201 			ptesc();
202 		if (xfont != mfont)
203 			ptfont();
204 		if (xpts != mpts)
205 			ptps();
206 		if (lead)
207 			ptlead();
208 		OUT "x X " PUT;
209 		xon++;
210 		for (j = 1; cbits(pi[j]) != XOFF; j++)
211 			outascii(pi[j]);
212 		oput('\n');
213 		xon--;
214 		return j+1;
215 	}
216 	if (k < 040 && k != DRAWFCN)
217 		return(outsize);
218 	j = z = 0;
219 	if (k != DRAWFCN) {
220 		if (widcache[k].fontpts == (xfont<<8) + xpts  && !setwdf) {
221 			w = widcache[k].width;
222 			bd = 0;
223 			cs = 0;
224 		} else
225 			w = getcw(k);
226 		if (cs) {
227 			if (bd)
228 				w += (bd - 1) * HOR;
229 			j = (cs - w) / 2;
230 			w = cs - j;
231 			if (bd)
232 				w -= (bd - 1) * HOR;
233 		}
234 		if (iszbit(i)) {
235 			if (cs)
236 				w = -j;
237 			else
238 				w = 0;
239 			z = 1;
240 		}
241 	}
242 	esc += j;
243 	if (xfont != mfont)
244 		ptfont();
245 	if (xpts != mpts)
246 		ptps();
247 	if (lead)
248 		ptlead();
249 	/* put out the real character here */
250 	if (k == DRAWFCN) {
251 		if (esc)
252 			ptesc();
253 		w = 0;
254 		dx = absmot(pi[3]);
255 		if (isnmot(pi[3]))
256 			dx = -dx;
257 		dy = absmot(pi[4]);
258 		if (isnmot(pi[4]))
259 			dy = -dy;
260 		switch (cbits(pi[1])) {
261 		case DRAWCIRCLE:	/* circle */
262 			OUT "D%c %d\n", DRAWCIRCLE, dx PUT;	/* dx is diameter */
263 			hpos += dx;
264 			break;
265 		case DRAWELLIPSE:
266 			OUT "D%c %d %d\n", DRAWELLIPSE, dx, dy PUT;
267 			hpos += dx;
268 			break;
269 		case DRAWBUILD:
270 			k = cbits(pi[2]);
271 			OUT "D%c %d ", DRAWBUILD, dx PUT;
272 			if (k < ALPHABET)
273 				OUT "%c\n", k PUT;
274 			else
275 				ptchname(k);
276 			hpos += dx;
277 			break;
278 		case DRAWLINE:	/* line */
279 			k = cbits(pi[2]);
280 			OUT "D%c %d %d ", DRAWLINE, dx, dy PUT;
281 			if (k < ALPHABET)
282 				OUT "%c\n", k PUT;
283 			else
284 				ptchname(k);
285 			hpos += dx;
286 			vpos += dy;
287 			break;
288 		case DRAWARC:	/* arc */
289 			dx2 = absmot(pi[5]);
290 			if (isnmot(pi[5]))
291 				dx2 = -dx2;
292 			dy2 = absmot(pi[6]);
293 			if (isnmot(pi[6]))
294 				dy2 = -dy2;
295 			OUT "D%c %d %d %d %d\n", DRAWARC,
296 				dx, dy, dx2, dy2 PUT;
297 			hpos += dx + dx2;
298 			vpos += dy + dy2;
299 			break;
300 
301 		case 's':	/* using 's' internally to avoid .tr ~ */
302 			pi[1] = '~';
303 		case DRAWSPLINE:	/* spline */
304 		default:	/* something else; copy it like spline */
305 			OUT "D%c %d %d", cbits(pi[1]), dx, dy PUT;
306 			hpos += dx;
307 			vpos += dy;
308 			if (cbits(pi[3]) == DRAWFCN || cbits(pi[4]) == DRAWFCN) {
309 				/* it was somehow defective */
310 				OUT "\n" PUT;
311 				break;
312 			}
313 			for (n = 5; cbits(pi[n]) != DRAWFCN; n += 2) {
314 				dx = absmot(pi[n]);
315 				if (isnmot(pi[n]))
316 					dx = -dx;
317 				dy = absmot(pi[n+1]);
318 				if (isnmot(pi[n+1]))
319 					dy = -dy;
320 				OUT " %d %d", dx, dy PUT;
321 				hpos += dx;
322 				vpos += dy;
323 			}
324 			OUT "\n" PUT;
325 			break;
326 		}
327 		for (n = 3; cbits(pi[n]) != DRAWFCN; n++)
328 			;
329 		outsize = n + 1;
330 	} else if (k < ALPHABET) {
331 		/* try to go faster and compress output */
332 		/* by printing nnc for small positive motion followed by c */
333 		/* kludgery; have to make sure set all the vars too */
334 		if (esc > 0 && esc < 100) {
335 			oput(esc / 10 + '0');
336 			oput(esc % 10 + '0');
337 			oput(k);
338 			hpos += esc;
339 			esc = 0;
340 		} else {
341 			if (esc)
342 				ptesc();
343 			oput('c');
344 			oput(k);
345 			oput('\n');
346 		}
347 	} else {
348 		if (esc)
349 			ptesc();
350 		ptchname(k);
351 	}
352 	if (bd) {
353 		bd -= HOR;
354 		if (esc += bd)
355 			ptesc();
356 		if (k < ALPHABET)
357 			OUT "c%c\n", k PUT;
358 		else
359 			ptchname(k);
360 		if (z)
361 			esc -= bd;
362 	}
363 	esc += w;
364 	return(outsize);
365 }
366 
ptchname(int k)367 void ptchname(int k)
368 {
369 	char *chn = chname(k);
370 
371 	switch (chn[0]) {
372 	case MBchar:
373 		OUT "c%s\n", chn+1 PUT;	/* \n not needed? */
374 		break;
375 	case Number:
376 		OUT "N%s\n", chn+1 PUT;
377 		break;
378 	case Troffchar:
379 		OUT "C%s\n", chn+1 PUT;
380 		break;
381 	default:
382 		ERROR "illegal char type %s", chn WARN;
383 		break;
384 	}
385 }
386 
ptflush(void)387 void ptflush(void)	/* get us to a clean output state */
388 {
389 	if (TROFF) {
390 		/* ptesc(); but always H, no h */
391 		hpos += esc;
392 		OUT "\nH%d\n", hpos PUT;
393 		esc = 0;
394 		ptps();
395 		ptfont();
396 		ptlead();
397 	}
398 }
399 
ptps(void)400 void ptps(void)
401 {
402 	int i, j, k;
403 
404 	i = xpts;
405 	for (j = 0; i > (k = pstab[j]); j++)
406 		if (!k) {
407 			k = pstab[--j];
408 			break;
409 		}
410 	if (!ascii)
411 		OUT "s%d\n", k PUT;	/* really should put out string rep of size */
412 	mpts = i;
413 }
414 
ptfont(void)415 void ptfont(void)
416 {
417 	mfont = xfont;
418 	if (ascii)
419 		return;
420 	if (xfont > nfonts) {
421 		ptfpcmd(0, fonts[xfont].longname, 0);	/* Put the desired font in the
422 					 * fontcache of the filter */
423 		OUT "f0\n" PUT;	/* make sure that it gets noticed */
424 	} else
425 		OUT "f%d\n", xfont PUT;
426 }
427 
ptfpcmd(int f,char * s,char * longname)428 void ptfpcmd(int f, char *s, char *longname)
429 {
430 	if (f > nfonts)		/* a bit risky? */
431 		f = 0;
432 	if (longname) {
433 		OUT "x font %d %s %s\n", f, s, longname PUT;
434 	} else {
435 		OUT "x font %d %s\n", f, s PUT;
436 	}
437 /*	OUT "f%d\n", xfont PUT;	/* need this for buggy version of adobe transcript */
438 				/* which apparently believes that x font means */
439 				/* to set the font, not just the position. */
440 }
441 
t_ptlead(void)442 void t_ptlead(void)
443 {
444 	vpos += lead;
445 	if (!ascii)
446 		OUT "V%d\n", vpos PUT;
447 	lead = 0;
448 }
449 
ptesc(void)450 void ptesc(void)
451 {
452 	hpos += esc;
453 	if (!ascii)
454 		if (esc > 0) {
455 			oput('h');
456 			if (esc>=10 && esc<100) {
457 				oput(esc/10 + '0');
458 				oput(esc%10 + '0');
459 			} else
460 				OUT "%d", esc PUT;
461 		} else
462 			OUT "H%d\n", hpos PUT;
463 	esc = 0;
464 }
465 
ptpage(int n)466 void ptpage(int n)	/* called at end of each output page, we hope */
467 {
468 	int i;
469 
470 	if (NROFF)
471 		return;
472 	ptlead();
473 	vpos = 0;
474 	if (ascii)
475 		return;
476 	OUT "p%d\n", n PUT;	/* new page */
477 	for (i = 0; i <= nfonts; i++)
478 		if (fontlab[i]) {
479 			if (fonts[i].truename)
480 				OUT "x font %d %s %s\n", i, fonts[i].longname, fonts[i].truename PUT;
481 			else
482 				OUT "x font %d %s\n", i, fonts[i].longname PUT;
483 		}
484 	ptps();
485 	ptfont();
486 }
487 
pttrailer(void)488 void pttrailer(void)
489 {
490 	if (TROFF)
491 		OUT "x trailer\n" PUT;
492 }
493 
ptstop(void)494 void ptstop(void)
495 {
496 	if (TROFF)
497 		OUT "x stop\n" PUT;
498 }
499 
t_ptpause(void)500 void t_ptpause(void)
501 {
502 	if (ascii)
503 		return;
504 	ptlead();
505 	vpos = 0;
506 	pttrailer();
507 	ptlead();
508 	OUT "x pause\n" PUT;
509 	flusho();
510 	mpts = mfont = 0;
511 	ptesc();
512 	esc = po;
513 	hpos = vpos = 0;	/* probably in wrong place */
514 }
515