1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 1989 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30
31 /* from OpenSolaris "n9.c 1.11 05/06/08 SMI" */
32
33 /*
34 * Portions Copyright (c) 2005 Gunnar Ritter, Freiburg i. Br., Germany
35 *
36 * Sccsid @(#)n9.c 1.78 (gritter) 10/23/09
37 */
38
39 /*
40 * University Copyright- Copyright (c) 1982, 1986, 1988
41 * The Regents of the University of California
42 * All Rights Reserved
43 *
44 * University Acknowledgment- Portions of this document are derived from
45 * software developed by the University of California, Berkeley, and its
46 * contributors.
47 */
48
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <sys/types.h>
53 #include <sys/stat.h>
54 #include <fcntl.h>
55 #include <unistd.h>
56
57 #ifdef EUC
58 #include <locale.h>
59 #include <wctype.h>
60 #include <langinfo.h>
61 #endif /* EUC */
62 #include "tdef.h"
63 #ifdef NROFF
64 #include "tw.h"
65 #endif
66 #include "pt.h"
67 #include "ext.h"
68
69 #ifdef EUC
70 #define ISO646 "646"
71
72 int multi_locale;
73 int (*wdbdg)(wchar_t, wchar_t, int);
74 wchar_t *(*wddlm)(wchar_t, wchar_t, int);
75
76 int csi_width[4] = {
77 1,
78 1,
79 2,
80 3,
81 };
82 #endif /* EUC */
83
84 /*
85 * troff9.c
86 *
87 * misc functions
88 */
89
90 tchar
setz(void)91 setz(void)
92 {
93 tchar i;
94
95 if (!ismot(i = getch()) && cbits(i) != ohc)
96 i |= ZBIT;
97 return(i);
98 }
99
100 static int
connectchar(tchar i)101 connectchar(tchar i)
102 {
103 int *cp, c;
104
105 c = cbits(i);
106 if (*connectch) {
107 for (cp = connectch; *cp; cp++)
108 if (c == *cp)
109 return 1;
110 return 0;
111 }
112 return c == RULE || c == UNDERLINE || c == ROOTEN;
113 }
114
115 void
setline(void)116 setline(void)
117 {
118 register tchar *i;
119 tchar c, delim;
120 int length;
121 int w, cnt, rem, temp;
122 tchar linebuf[NC];
123
124 if (ismot(c = getch()))
125 return;
126 delim = c;
127 vflag = 0;
128 dfact = EM;
129 length = quant(hatoi(), HOR);
130 dfact = 1;
131 if (!length) {
132 eat(delim);
133 return;
134 }
135 s0:
136 if (c = getch(), issame(c, delim)) {
137 ch = c;
138 c = RULE | chbits;
139 } else if (cbits(c) == FILLER)
140 goto s0;
141 w = width(c);
142 i = linebuf;
143 if (length < 0) {
144 *i++ = makem(length);
145 length = -length;
146 }
147 if (!(cnt = length / w)) {
148 *i++ = makem(-(temp = ((w - length) / 2)));
149 *i++ = c;
150 *i++ = makem(-(w - length - temp));
151 goto s1;
152 }
153 if ((rem = length % w)) {
154 if (connectchar(c))
155 *i++ = c | ZBIT;
156 *i++ = makem(rem);
157 }
158 if (cnt) {
159 *i++ = RPT;
160 *i++ = cnt;
161 *i++ = c;
162 }
163 s1:
164 *i++ = 0;
165 eat(delim);
166 pushback(linebuf);
167 }
168
169
170 tchar
eat(tchar c)171 eat(tchar c)
172 {
173 register tchar i;
174
175 while (i = getch(), !issame(i, c) && (cbits(i) != '\n'))
176 ;
177 if (cbits(c) != ' ' && !issame(i, c))
178 nodelim(c);
179 return(i);
180 }
181
182
183 void
setov(void)184 setov(void)
185 {
186 register int j = 0, k;
187 tchar i, delim, o[NOV];
188 int w[NOV];
189
190 if (ismot(i = getch()))
191 return;
192 delim = i;
193 for (k = 0; (k < NOV) && (j = cbits(i = getch()), !issame(i, delim)) && (j != '\n'); k++) {
194 o[k] = i;
195 w[k] = width(i);
196 }
197 if (!issame(j, delim))
198 nodelim(delim);
199 o[k] = w[k] = 0;
200 if (o[0])
201 for (j = 1; j; ) {
202 j = 0;
203 for (k = 1; o[k] ; k++) {
204 if (w[k-1] < w[k]) {
205 j++;
206 i = w[k];
207 w[k] = w[k-1];
208 w[k-1] = i;
209 i = o[k];
210 o[k] = o[k-1];
211 o[k-1] = i;
212 }
213 }
214 }
215 else
216 return;
217 pbbuf[pbp++] = makem(w[0] / 2);
218 for (k = 0; o[k]; k++)
219 ;
220 while (k>0) {
221 k--;
222 if (pbp >= pbsize-4)
223 if (growpbbuf() == NULL) {
224 errprint("no space for .ov");
225 done(2);
226 }
227 pbbuf[pbp++] = makem(-((w[k] + w[k+1]) / 2));
228 pbbuf[pbp++] = o[k];
229 }
230 }
231
232
233 void
setbra(void)234 setbra(void)
235 {
236 register int k;
237 tchar i, *j, dwn, delim;
238 int cnt;
239 tchar brabuf[NC];
240
241 if (ismot(i = getch()))
242 return;
243 delim = i;
244 j = brabuf + 1;
245 cnt = 0;
246 #ifdef NROFF
247 dwn = sabsmot(2 * t.Halfline) | MOT | VMOT;
248 #endif
249 #ifndef NROFF
250 dwn = sabsmot((int)EM) | MOT | VMOT;
251 #endif
252 while ((k = cbits(i = getch()), !issame(delim, i)) && (k != '\n') && (j <= (brabuf + NC - 4))) {
253 *j++ = i | ZBIT;
254 *j++ = dwn;
255 cnt++;
256 }
257 if (!issame(i, delim))
258 nodelim(delim);
259 if (--cnt < 0)
260 return;
261 else if (!cnt) {
262 ch = *(j - 2);
263 return;
264 }
265 *j = 0;
266 #ifdef NROFF
267 *--j = *brabuf = sabsmot(cnt * t.Halfline) | MOT | NMOT | VMOT;
268 #endif
269 #ifndef NROFF
270 *--j = *brabuf = sabsmot((cnt * (int)EM) / 2) | MOT | NMOT | VMOT;
271 #endif
272 *--j &= ~ZBIT;
273 pushback(brabuf);
274 }
275
276
277 void
setvline(void)278 setvline(void)
279 {
280 register int i;
281 tchar c, d, delim, rem, ver, neg;
282 int cnt, v;
283 tchar vlbuf[NC];
284 register tchar *vlp;
285
286 if (ismot(c = getch()))
287 return;
288 delim = c;
289 dfact = lss;
290 vflag++;
291 i = quant(hatoi(), VERT);
292 dfact = 1;
293 if (!i) {
294 eat(delim);
295 vflag = 0;
296 return;
297 }
298 if (c = getch(), issame(c, delim)) {
299 c = BOXRULE | chbits; /*default box rule*/
300 } else {
301 d = getch();
302 if (!issame(d, delim))
303 nodelim(delim);
304 }
305 c |= ZBIT;
306 neg = 0;
307 if (i < 0) {
308 i = -i;
309 neg = NMOT;
310 }
311 #ifdef NROFF
312 v = 2 * t.Halfline;
313 #endif
314 #ifndef NROFF
315 v = EM;
316 #endif
317 cnt = i / v;
318 rem = makem(i % v) | neg;
319 ver = makem(v) | neg;
320 vlp = vlbuf;
321 if (!neg)
322 *vlp++ = ver;
323 if (absmot(rem) != 0) {
324 *vlp++ = c;
325 *vlp++ = rem;
326 }
327 while ((vlp < (vlbuf + NC - 3)) && cnt--) {
328 *vlp++ = c;
329 *vlp++ = ver;
330 }
331 *(vlp - 2) &= ~ZBIT;
332 if (!neg)
333 vlp--;
334 *vlp++ = 0;
335 pushback(vlbuf);
336 vflag = 0;
337 }
338
339 #define NPAIR (NC/2-6) /* max pairs in spline, etc. */
340
341 void
setdraw(void)342 setdraw (void) /* generate internal cookies for a drawing function */
343 {
344 int i, dx[NPAIR], dy[NPAIR], type;
345 tchar c, delim;
346 #ifndef NROFF
347 int hpos, vpos;
348 int j, k;
349 tchar drawbuf[NC];
350 #else
351 extern int tlp, utf8;
352 char drawbuf[NC];
353 #endif /* NROFF */
354
355 /* input is \D'f dx dy dx dy ... c' (or at least it had better be) */
356 /* this does drawing function f with character c and the */
357 /* specified dx,dy pairs interpreted as appropriate */
358 /* pairs are deltas from last point, except for radii */
359
360 /* l dx dy: line from here by dx,dy */
361 /* c x: circle of diameter x, left side here */
362 /* e x y: ellipse of diameters x,y, left side here */
363 /* a dx1 dy1 dx2 dy2:
364 ccw arc: ctr at dx1,dy1, then end at dx2,dy2 from there */
365 /* ~ dx1 dy1 dx2 dy2...:
366 spline to dx1,dy1 to dx2,dy2 ... */
367 /* f dx dy ...: f is any other char: like spline */
368
369 if (ismot(c = getch()))
370 return;
371 delim = c;
372 type = cbits(getch());
373 for (i = 0; i < NPAIR ; i++) {
374 c = getch();
375 if (issame(c, delim))
376 break;
377 /* ought to pick up optional drawing character */
378 if (cbits(c) != ' ')
379 ch = c;
380 vflag = 0;
381 dfact = type == DRAWTHICKNESS ? 1 : EM;
382 dx[i] = quant(hatoi(), HOR);
383 if (dx[i] > MAXMOT)
384 dx[i] = MAXMOT;
385 else if (dx[i] < -MAXMOT)
386 dx[i] = -MAXMOT;
387 if (c = getch(), issame(c, delim)) { /* spacer */
388 dy[i++] = 0;
389 break;
390 }
391 vflag = 1;
392 dfact = lss;
393 dy[i] = quant(hatoi(), VERT);
394 if (type == DRAWTHICKNESS)
395 dy[i] = 0;
396 else if (dy[i] > MAXMOT)
397 dy[i] = MAXMOT;
398 else if (dy[i] < -MAXMOT)
399 dy[i] = -MAXMOT;
400 }
401 dfact = 1;
402 vflag = 0;
403 #ifndef NROFF
404 drawbuf[0] = DRAWFCN | chbits | ZBIT;
405 drawbuf[1] = type | chbits | ZBIT;
406 drawbuf[2] = '.' | chbits | ZBIT; /* use default drawing character */
407 hpos = vpos = 0;
408 for (k = 0, j = 3; k < i; k++) {
409 drawbuf[j++] = MOT | ((dx[k] >= 0) ?
410 sabsmot(dx[k]) : (NMOT | sabsmot(-dx[k])));
411 drawbuf[j++] = MOT | VMOT | ((dy[k] >= 0) ?
412 sabsmot(dy[k]) : (NMOT | sabsmot(-dy[k])));
413 hpos += dx[k];
414 vpos += dy[k];
415 }
416 if (type == DRAWELLIPSE || type == DRAWELLIPSEFI) {
417 drawbuf[5] = drawbuf[4] | NMOT; /* so the net vertical is zero */
418 j = 6;
419 }
420 if (gflag && (type == DRAWPOLYGON || type == DRAWPOLYGONFI) &&
421 (hpos || vpos)) {
422 drawbuf[j++] = MOT | ((hpos < 0) ?
423 sabsmot(-hpos) : (NMOT | sabsmot(hpos)));
424 drawbuf[j++] = MOT | VMOT | ((vpos < 0) ?
425 sabsmot(-vpos) : (NMOT | sabsmot(vpos)));
426 }
427 drawbuf[j++] = DRAWFCN | chbits | ZBIT; /* marks end for ptout */
428 drawbuf[j] = 0;
429 pushback(drawbuf);
430 #else
431 switch (type) {
432 case 'l':
433 if (dx[0] && !dy[0]) {
434 if (dx[0] < 0) {
435 snprintf(drawbuf, sizeof(drawbuf), "\\h'%du'",
436 dx[0]);
437 cpushback(drawbuf);
438 }
439 snprintf(drawbuf, sizeof(drawbuf), "\\l'%du%s'",
440 dx[0], tlp ? "\\&-" : utf8 ? "\\U'2500'" : "");
441 cpushback(drawbuf);
442 } else if (dy[0] && !dx[0]) {
443 snprintf(drawbuf, sizeof(drawbuf), "\\L'%du%s'",
444 dy[0], tlp ? "|" : utf8 ? "\\U'2502'" : "");
445 cpushback(drawbuf);
446 }
447 }
448 #endif
449 }
450
451
452 void
casefc(void)453 casefc(void)
454 {
455 register int i;
456 tchar j;
457
458 gchtab[fc] &= ~FCBIT;
459 fc = IMP;
460 padc = ' ';
461 if (skip(0) || ismot(j = getch()) || (i = cbits(j)) == '\n')
462 return;
463 fc = i;
464 gchtab[fc] |= FCBIT;
465 if (skip(0) || ismot(ch) || (ch = cbits(ch)) == fc)
466 return;
467 padc = ch;
468 }
469
470
471 tchar
setfield(int x)472 setfield(int x)
473 {
474 register tchar ii, jj, *fp;
475 register int i, j, k;
476 int length, ws, npad, temp, type;
477 tchar **pp, *padptr[NPP];
478 tchar fbuf[FBUFSZ];
479 int savfc, savtc, savlc;
480 tchar rchar = 0, nexti = 0;
481 int savepos;
482 int oev;
483
484 prdblesc = 1;
485 if (x == tabch)
486 rchar = tabc | chbits;
487 else if (x == ldrch)
488 rchar = dotc | chbits;
489 if (chartab[trtab[cbits(rchar)]] != 0)
490 rchar = setchar(rchar);
491 temp = npad = ws = 0;
492 savfc = fc;
493 savtc = tabch;
494 savlc = ldrch;
495 tabch = ldrch = fc = IMP;
496 savepos = numtab[HP].val;
497 gchtab[tabch] &= ~TABBIT;
498 gchtab[ldrch] &= ~LDRBIT;
499 gchtab[fc] &= ~FCBIT;
500 gchtab[IMP] |= TABBIT|LDRBIT|FCBIT;
501 for (j = 0; ; j++) {
502 if ((tabtab[j] & TABMASK) == 0) {
503 if (x == savfc)
504 errprint("zero field width.");
505 jj = 0;
506 goto rtn;
507 }
508 if ((length = ((tabtab[j] & TABMASK) - numtab[HP].val)) > 0 )
509 break;
510 }
511 type = tabtab[j] & (~TABMASK);
512 fp = fbuf;
513 pp = padptr;
514 if (x == savfc) {
515 *fp++ = mkxfunc(FLDMARK, 0);
516 nexti = getch();
517 while (1) {
518 j = cbits(ii = nexti);
519 jj = width(ii);
520 oev = ev;
521 if (j != savfc && j != '\n' &&
522 pp < (padptr + NPP - 1) &&
523 fp < (fbuf + FBUFSZ - 3))
524 nexti = getch();
525 else
526 nexti = 0;
527 if (ev == oev)
528 jj += kernadjust(ii, nexti);
529 widthp = jj;
530 numtab[HP].val += jj;
531 if (j == padc) {
532 npad++;
533 *pp++ = fp;
534 if (pp > (padptr + NPP - 1))
535 break;
536 goto s1;
537 } else if (j == savfc)
538 break;
539 else if (j == '\n') {
540 temp = j;
541 nlflg = 0;
542 break;
543 }
544 ws += jj;
545 s1:
546 *fp++ = ii;
547 if (fp > (fbuf + FBUFSZ - 3))
548 break;
549 }
550 if (!npad) {
551 npad++;
552 *pp++ = fp;
553 *fp++ = 0;
554 }
555 *fp++ = temp;
556 *fp++ = 0;
557 temp = i = (j = length - ws) / npad;
558 i = (i / HOR) * HOR;
559 if ((j -= i * npad) < 0)
560 j = -j;
561 ii = makem(i);
562 if (temp < 0)
563 ii |= NMOT;
564 for (; npad > 0; npad--) {
565 *(*--pp) = ii;
566 if (j) {
567 j -= HOR;
568 (*(*pp)) += HOR;
569 }
570 }
571 pushback(fbuf);
572 jj = 0;
573 } else if (type == 0) {
574 /*plain tab or leader*/
575 if (pbp >= pbsize-4)
576 growpbbuf();
577 pbbuf[pbp++] = mkxfunc(FLDMARK, 0);
578 if ((j = width(rchar)) > 0) {
579 int nchar;
580 k = kernadjust(rchar, rchar);
581 if (length < j)
582 nchar = 0;
583 else {
584 nchar = 1;
585 length -= j;
586 nchar += length / (k+j);
587 length %= k+j;
588 }
589 pbbuf[pbp++] = FILLER;
590 while (nchar-->0) {
591 if (pbp >= pbsize-5)
592 if (growpbbuf() == NULL)
593 break;
594 numtab[HP].val += j;
595 widthp = j;
596 if (nchar > 0) {
597 numtab[HP].val += k;
598 widthp += k;
599 }
600 pbbuf[pbp++] = rchar;
601 }
602 pbbuf[pbp++] = FILLER;
603 }
604 if (length)
605 jj = sabsmot(length) | MOT;
606 else
607 jj = 0;
608 } else {
609 /*center tab*/
610 /*right tab*/
611 *fp++ = mkxfunc(FLDMARK, 0);
612 nexti = getch();
613 while (((j = cbits(ii = nexti)) != savtc) && (j != '\n') && (j != savlc)) {
614 jj = width(ii);
615 oev = ev;
616 if (fp < (fbuf + FBUFSZ - 3)) {
617 nexti = getch();
618 if (ev == oev)
619 jj += kernadjust(ii, nexti);
620 }
621 ws += jj;
622 numtab[HP].val += jj;
623 widthp = jj;
624 *fp++ = ii;
625 if (fp > (fbuf + FBUFSZ - 3))
626 break;
627 }
628 *fp++ = ii;
629 *fp++ = 0;
630 if (type == RTAB)
631 length -= ws;
632 else
633 length -= ws / 2; /*CTAB*/
634 pushback(fbuf);
635 if ((j = width(rchar)) != 0 && length > 0) {
636 int nchar;
637 k = kernadjust(rchar, rchar);
638 if (length < j)
639 nchar = 0;
640 else {
641 nchar = 1;
642 length -= j;
643 nchar += length / (k+j);
644 length %= k+j;
645 }
646 if (pbp >= pbsize-3)
647 growpbbuf();
648 pbbuf[pbp++] = FILLER;
649 while (nchar-- > 0) {
650 if (pbp >= pbsize-3)
651 if (growpbbuf() == NULL)
652 break;
653 pbbuf[pbp++] = rchar;
654 }
655 }
656 length = (length / HOR) * HOR;
657 jj = makem(length);
658 nlflg = 0;
659 }
660 rtn:
661 gchtab[fc] &= ~FCBIT;
662 gchtab[tabch] &= ~TABBIT;
663 gchtab[ldrch] &= ~LDRBIT;
664 fc = savfc;
665 tabch = savtc;
666 ldrch = savlc;
667 gchtab[fc] |= FCBIT;
668 gchtab[tabch] = TABBIT;
669 gchtab[ldrch] |= LDRBIT;
670 numtab[HP].val = savepos;
671 if (pbp < pbsize-3 || growpbbuf())
672 pbbuf[pbp++] = mkxfunc(FLDMARK, x);
673 prdblesc = 0;
674 return(jj | ADJBIT);
675 }
676
677
678 static int
readpenalty(int * valp)679 readpenalty(int *valp)
680 {
681 int n, t;
682
683 t = dpenal ? dpenal - INFPENALTY0 - 1 : 0;
684 noscale++;
685 n = inumb(&t);
686 noscale--;
687 if (nonumb)
688 return 0;
689 if (n > INFPENALTY0)
690 n = INFPENALTY0;
691 else if (n < -INFPENALTY0)
692 n = -INFPENALTY0;
693 n += INFPENALTY0 + 1;
694 *valp = n;
695 return 1;
696 }
697
698 static int
getpenalty(int * valp)699 getpenalty(int *valp)
700 {
701 tchar c, delim;
702
703 if (ismot(delim = getch()))
704 return 0;
705 if (readpenalty(valp) == 0)
706 return 0;
707 c = getch();
708 if (!issame(c, delim)) {
709 nodelim(delim);
710 return 0;
711 }
712 return 1;
713 }
714
715 tchar
setpenalty(void)716 setpenalty(void)
717 {
718 int n;
719
720 if (getpenalty(&n))
721 return mkxfunc(PENALTY, n);
722 return 0;
723 }
724
725 tchar
setdpenal(void)726 setdpenal(void)
727 {
728 if (getpenalty(&dpenal))
729 return mkxfunc(DPENAL, dpenal);
730 return 0;
731 }
732
733
734 tchar
mkxfunc(int f,int s)735 mkxfunc(int f, int s)
736 {
737 tchar t = XFUNC;
738 setfbits(t, f);
739 setsbits(t, s);
740 return t;
741 }
742
743 void
pushinlev(void)744 pushinlev(void)
745 {
746 if (ninlev >= ainlev) {
747 ainlev += 4;
748 inlevp = realloc(inlevp, ainlev * sizeof *inlevp);
749 }
750 inlevp[ninlev]._apts = apts;
751 inlevp[ninlev]._apts1 = apts1;
752 inlevp[ninlev]._pts = pts;
753 inlevp[ninlev]._pts1 = pts1;
754 inlevp[ninlev]._font = font;
755 inlevp[ninlev]._font1 = font1;
756 inlevp[ninlev]._cc = cc;
757 inlevp[ninlev]._c2 = c2;
758 inlevp[ninlev]._ohc = ohc;
759 inlevp[ninlev]._hyf = hyf;
760 inlevp[ninlev]._tabc = tabc;
761 inlevp[ninlev]._dotc = dotc;
762 inlevp[ninlev]._dpenal = dpenal;
763 ninlev++;
764 }
765
766 tchar
popinlev(void)767 popinlev(void)
768 {
769 tchar c = 0;
770
771 if (--ninlev < 0) {
772 ninlev = 0;
773 return c;
774 }
775 if (dpenal != inlevp[ninlev]._dpenal)
776 c = mkxfunc(DPENAL, inlevp[ninlev]._dpenal);
777 apts = inlevp[ninlev]._apts;
778 apts1 = inlevp[ninlev]._apts1;
779 pts = inlevp[ninlev]._pts;
780 pts1 = inlevp[ninlev]._pts1;
781 font = inlevp[ninlev]._font;
782 font1 = inlevp[ninlev]._font1;
783 cc = inlevp[ninlev]._cc;
784 c2 = inlevp[ninlev]._c2;
785 ohc = inlevp[ninlev]._ohc;
786 hyf = inlevp[ninlev]._hyf;
787 tabc = inlevp[ninlev]._tabc;
788 dotc = inlevp[ninlev]._dotc;
789 dpenal = inlevp[ninlev]._dpenal;
790 mchbits();
791 if (ninlev == 0) {
792 free(inlevp);
793 inlevp = NULL;
794 ainlev = 0;
795 }
796 return c;
797 }
798
799 #ifdef EUC
800 /* locale specific initialization */
801 void
localize(void)802 localize(void)
803 {
804 extern int wdbindf(wchar_t, wchar_t, int);
805 extern wchar_t *wddelim(wchar_t, wchar_t, int);
806 char *codeset;
807
808 codeset = nl_langinfo(CODESET);
809
810 if (mb_cur_max > 1)
811 multi_locale = 1;
812 else {
813 if (*codeset == '\0' ||
814 (strcmp(codeset, ISO646) == 0)) {
815 /*
816 * if codeset is an empty string
817 * assumes this is C locale (7-bit) locale.
818 * This happens in 2.5, 2.5.1, and 2.6 system
819 * Or, if codeset is "646"
820 * this is 7-bit locale.
821 */
822 multi_locale = 0;
823 } else {
824 /* 8-bit locale */
825 multi_locale = 1;
826 }
827
828 }
829 wdbdg = wdbindf;
830 wddlm = wddelim;
831 }
832
833 #ifndef __sun
834 int
wdbindf(wchar_t wc1,wchar_t wc2,int type)835 wdbindf(wchar_t wc1, wchar_t wc2, int type)
836 {
837 return 6;
838 }
839
840 wchar_t *
wddelim(wchar_t wc1,wchar_t wc2,int type)841 wddelim(wchar_t wc1, wchar_t wc2, int type)
842 {
843 return L" ";
844 }
845 #endif /* !__sun */
846 #endif /* EUC */
847
848 void
caselc_ctype(void)849 caselc_ctype(void)
850 {
851 #ifdef EUC
852 char c, *buf = NULL;
853 int i = 0, sz = 0;
854
855 skip(1);
856 do {
857 c = getach()&0377;
858 if (i >= sz)
859 buf = realloc(buf, (sz += 8) * sizeof *buf);
860 buf[i++] = c;
861 } while (c && c != ' ' && c != '\n');
862 buf[i-1] = 0;
863 setlocale(LC_CTYPE, buf);
864 mb_cur_max = MB_CUR_MAX;
865 localize();
866 #ifndef NROFF
867 ptlocale(buf);
868 #endif
869 free(buf);
870 #endif
871 }
872
873 #ifndef NROFF
874 struct fg {
875 char buf[512];
876 char *bp;
877 char *ep;
878 int fd;
879 int eof;
880 };
881
882 static int
psskip(struct fg * fp,size_t n)883 psskip(struct fg *fp, size_t n)
884 {
885 size_t i;
886
887 if (fp->eof)
888 return -1;
889 if (fp->bp < fp->ep) {
890 i = fp->ep - fp->bp;
891 if (i > n) {
892 fp->bp += n;
893 return 0;
894 }
895 fp->bp = fp->buf;
896 n -= i;
897 }
898 if (lseek(fp->fd, n, SEEK_CUR) == (off_t)-1)
899 return -1;
900 return 0;
901 }
902
903 static int
psgetline(struct fg * fp,char ** linebp,size_t * linesize)904 psgetline(struct fg *fp, char **linebp, size_t *linesize)
905 {
906 int i, n = 0;
907 int nl = 0;
908
909 if (fp->bp == NULL)
910 fp->bp = fp->buf;
911 for (;;) {
912 if (fp->eof == 0 && fp->bp == fp->buf) {
913 if ((i = read(fp->fd, fp->buf, sizeof fp->buf)) <= 0)
914 fp->eof = 1;
915 fp->ep = &fp->buf[i];
916 }
917 for (;;) {
918 if (*linesize < n + 2)
919 *linebp = realloc(*linebp, *linesize += 128);
920 if (fp->bp >= fp->ep)
921 break;
922 if (*fp->bp == '\n' || nl) {
923 nl = 2;
924 break;
925 }
926 if (*fp->bp == '\r')
927 nl = 1;
928 (*linebp)[n++] = *fp->bp++;
929 }
930 if (fp->bp < fp->ep && *fp->bp == '\n') {
931 (*linebp)[n++] = *fp->bp++;
932 break;
933 }
934 if (nl == 2 || fp->eof)
935 break;
936 fp->bp = fp->buf;
937 }
938 (*linebp)[n] = 0;
939 return n;
940 }
941
942 static char *
getcom(const char * cp,const char * tp)943 getcom(const char *cp, const char *tp)
944 {
945 int n;
946
947 n = strlen(tp);
948 if (strncmp(cp, tp, n))
949 return NULL;
950 if (cp[n] == ' ' || cp[n] == '\t' || cp[n] == '\r' ||
951 cp[n] == '\n' || cp[n] == 0)
952 return (char *)&cp[n];
953 return NULL;
954 }
955
956 static void
getpsbb(const char * name,double bb[4])957 getpsbb(const char *name, double bb[4])
958 {
959 struct fg *fp;
960 char *buf = NULL;
961 char *cp;
962 size_t size = 0;
963 int fd, n, k;
964 int lineno = 0;
965 int found = 0;
966 int atend = 0;
967 int state = 0;
968 int indoc = 0;
969
970 if ((fd = open(name, O_RDONLY)) < 0) {
971 errprint("can't open %s", name);
972 return;
973 }
974 fp = calloc(1, sizeof *fp);
975 fp->fd = fd;
976 for (;;) {
977 n = psgetline(fp, &buf, &size);
978 if (++lineno == 1 && (n == 0 || strncmp(buf, "%!PS-", 5))) {
979 errprint("%s is not a DSC-conforming "
980 "PostScript document", name);
981 break;
982 }
983 if (n > 0 && state != 1 &&
984 (cp = getcom(buf, "%%BoundingBox:")) != NULL) {
985 while (*cp == ' ' || *cp == '\t')
986 cp++;
987 if (strncmp(cp, "(atend)", 7) == 0) {
988 atend++;
989 continue;
990 }
991 bb[0] = strtod(cp, &cp);
992 if (*cp)
993 bb[1] = strtod(cp, &cp);
994 if (*cp)
995 bb[2] = strtod(cp, &cp);
996 if (*cp) {
997 bb[3] = strtod(cp, &cp);
998 found = 1;
999 } else
1000 errprint("missing arguments to "
1001 "%%%%BoundingBox: in %s, line %d\n",
1002 name, lineno);
1003 continue;
1004 }
1005 if (n > 0 && state != 1 &&
1006 (cp = getcom(buf, "%%HiResBoundingBox:"))
1007 != NULL) {
1008 while (*cp == ' ' || *cp == '\t')
1009 cp++;
1010 if (strncmp(cp, "(atend)", 7) == 0) {
1011 atend++;
1012 continue;
1013 }
1014 bb[0] = strtod(cp, &cp);
1015 if (*cp)
1016 bb[1] = strtod(cp, &cp);
1017 if (*cp)
1018 bb[2] = strtod(cp, &cp);
1019 if (*cp) {
1020 bb[3] = strtod(cp, &cp);
1021 break;
1022 } else {
1023 errprint("missing arguments to "
1024 "%%%%HiResBoundingBox: in %s, "
1025 "line %d\n",
1026 name, lineno);
1027 continue;
1028 }
1029 }
1030 if (n == 0 || (state == 0 &&
1031 (getcom(buf, "%%EndComments") != NULL ||
1032 buf[0] != '%' || buf[1] == ' ' ||
1033 buf[1] == '\t' || buf[1] == '\r' ||
1034 buf[1] == '\n'))) {
1035 eof: if (found == 0 && (atend == 0 || n == 0))
1036 errprint("%s lacks a %%%%BoundingBox: DSC "
1037 "comment", name);
1038 if (atend == 0 || n == 0)
1039 break;
1040 state = 1;
1041 continue;
1042 }
1043 if (indoc == 0 && getcom(buf, "%%EOF") != NULL) {
1044 n = 0;
1045 goto eof;
1046 }
1047 if (state == 1 && indoc == 0 &&
1048 getcom(buf, "%%Trailer") != NULL) {
1049 state = 2;
1050 continue;
1051 }
1052 if (state == 1 && getcom(buf, "%%BeginDocument:") != NULL) {
1053 indoc++;
1054 continue;
1055 }
1056 if (state == 1 && indoc > 0 &&
1057 getcom(buf, "%%EndDocument") != NULL) {
1058 indoc--;
1059 continue;
1060 }
1061 if (state == 1 &&
1062 (cp = getcom(buf, "%%BeginBinary:")) != NULL) {
1063 if ((k = strtol(cp, &cp, 10)) > 0)
1064 psskip(fp, k);
1065 continue;
1066 }
1067 if (state == 1 && (cp = getcom(buf, "%%BeginData:")) != NULL) {
1068 if ((k = strtol(cp, &cp, 10)) > 0) {
1069 while (*cp == ' ' || *cp == '\t')
1070 cp++;
1071 while (*cp && *cp != ' ' && *cp != '\t')
1072 cp++;
1073 while (*cp == ' ' || *cp == '\t')
1074 cp++;
1075 if (strncmp(cp, "Bytes", 5) == 0)
1076 psskip(fp, k);
1077 else if (strncmp(cp, "Lines", 5) == 0) {
1078 while (k--) {
1079 n = psgetline(fp, &buf, &size);
1080 if (n == 0)
1081 goto eof;
1082 }
1083 }
1084 }
1085 continue;
1086 }
1087 }
1088 free(fp);
1089 free(buf);
1090 close(fd);
1091 }
1092 #endif /* !NROFF */
1093
1094 void
casepsbb(void)1095 casepsbb(void)
1096 {
1097 #ifndef NROFF
1098 char *buf = NULL;
1099 int c;
1100 int n = 0, sz = 0;
1101 double bb[4] = { 0, 0, 0, 0 };
1102
1103 lgf++;
1104 skip(1);
1105 do {
1106 c = getach();
1107 if (n >= sz)
1108 buf = realloc(buf, (sz += 14) * sizeof *buf);
1109 buf[n++] = c;
1110 } while (c);
1111 getpsbb(buf, bb);
1112 free(buf);
1113 setnrf("llx", bb[0], 0);
1114 setnrf("lly", bb[1], 0);
1115 setnrf("urx", bb[2], 0);
1116 setnrf("ury", bb[3], 0);
1117 #endif /* !NROFF */
1118 }
1119
1120 static const struct {
1121 enum warn n;
1122 const char *s;
1123 } warnnames[] = {
1124 { WARN_NONE, "none" },
1125 { WARN_CHAR, "char" },
1126 { WARN_NUMBER, "number" },
1127 { WARN_BREAK, "break" },
1128 { WARN_DELIM, "delim" },
1129 { WARN_EL, "el" },
1130 { WARN_SCALE, "scale" },
1131 { WARN_RANGE, "range" },
1132 { WARN_SYNTAX, "syntax" },
1133 { WARN_DI, "di" },
1134 { WARN_MAC, "mac" },
1135 { WARN_REG, "reg" },
1136 { WARN_RIGHT_BRACE, "right-brace" },
1137 { WARN_MISSING, "missing" },
1138 { WARN_INPUT, "input" },
1139 { WARN_ESCAPE, "escape" },
1140 { WARN_SPACE, "space" },
1141 { WARN_FONT, "font" },
1142 { WARN_ALL, "all" },
1143 { WARN_W, "w" },
1144 { 0, NULL }
1145 };
1146
1147 static int
warn1(void)1148 warn1(void)
1149 {
1150 char name[NC];
1151 int i, n, sign;
1152 tchar c;
1153
1154 switch (cbits(c = getch())) {
1155 case '-':
1156 c = getch();
1157 sign = -1;
1158 break;
1159 case '+':
1160 c = getch();
1161 sign = 1;
1162 break;
1163 default:
1164 sign = 0;
1165 break;
1166 case 0:
1167 return 1;
1168 }
1169 ch = c;
1170 n = atoi0();
1171 if ((i = cbits(ch)) != 0 && i != ' ' && i != '\n') {
1172 if (c != ch) {
1173 while (getach());
1174 errprint("illegal number, char %c", i);
1175 return 1;
1176 }
1177 for (i = 0; i < sizeof name - 2; i++) {
1178 if ((c = getach()) == 0)
1179 break;
1180 name[i] = c;
1181 }
1182 name[i] = 0;
1183 for (i = 0; warnnames[i].s; i++)
1184 if (strcmp(name, warnnames[i].s) == 0) {
1185 n = warnnames[i].n;
1186 break;
1187 }
1188 if (warnnames[i].s == NULL) {
1189 errprint("unknown warning category %s", name);
1190 return 1;
1191 }
1192 }
1193 switch (sign) {
1194 case 1:
1195 warn |= n;
1196 break;
1197 case -1:
1198 warn &= ~n;
1199 break;
1200 default:
1201 warn = n;
1202 }
1203 return 0;
1204 }
1205
1206 void
casewarn(void)1207 casewarn(void)
1208 {
1209 if (skip(0))
1210 warn = WARN_W;
1211 else
1212 while (!warn1() && !skip(0));
1213 }
1214
1215 void
nosuch(int rq)1216 nosuch(int rq)
1217 {
1218 if (rq && rq != RIGHT && rq != PAIR(RIGHT, RIGHT) && warn & WARN_MAC)
1219 errprint("%s: no such request", macname(rq));
1220 }
1221
1222 void
missing(void)1223 missing(void)
1224 {
1225 if (warn & WARN_MISSING) {
1226 if (lastrq)
1227 errprint("%s: missing argument", macname(lastrq));
1228 else
1229 errprint("missing argument");
1230 }
1231 }
1232
1233 void
nodelim(int delim)1234 nodelim(int delim)
1235 {
1236 if (warn & WARN_DELIM)
1237 errprint("%c delimiter missing", (int)delim);
1238 }
1239
1240 void
illseq(int wc,const char * mb,int n)1241 illseq(int wc, const char *mb, int n)
1242 {
1243 if ((warn & WARN_INPUT) == 0)
1244 return;
1245 if (n == -3)
1246 errprint("non-ASCII input byte 0x%x terminates name", wc);
1247 else if (n == 0) {
1248 if (wc & ~0177)
1249 errprint("ignoring '%U' in input", wc);
1250 else
1251 errprint("ignoring '\\%o' in input", wc);
1252 } else
1253 errprint("illegal byte sequence at '\\%o' in input", *mb&0377);
1254 }
1255
1256 void
storerq(int i)1257 storerq(int i)
1258 {
1259 tchar tp[2];
1260
1261 tp[0] = mkxfunc(RQ, i);
1262 tp[1] = 0;
1263 pushback(tp);
1264 }
1265
1266 int
fetchrq(tchar * tp)1267 fetchrq(tchar *tp)
1268 {
1269 if (ismot(tp[0]) || !isxfunc(tp[0], RQ))
1270 return 0;
1271 return sbits(tp[0]);
1272 }
1273
1274 void
morechars(int n)1275 morechars(int n)
1276 {
1277 int i, nnc;
1278
1279 if (n <= NCHARS)
1280 return;
1281 for (nnc = 1024; nnc <= n; nnc <<= 1);
1282 widcache = realloc(widcache, nnc * sizeof *widcache);
1283 memset(&widcache[NCHARS], 0, (nnc-NCHARS) * sizeof *widcache);
1284 trtab = realloc(trtab, nnc * sizeof *trtab);
1285 trnttab = realloc(trnttab, nnc * sizeof *trnttab);
1286 for (i = NCHARS; i < nnc; i++)
1287 trnttab[i] = trtab[i] = i;
1288 trintab = realloc(trintab, nnc * sizeof *trintab);
1289 memset(&trintab[NCHARS], 0, (nnc-NCHARS) * sizeof *trintab);
1290 gchtab = realloc(gchtab, nnc * sizeof *gchtab);
1291 memset(&gchtab[NCHARS], 0, (nnc-NCHARS) * sizeof *gchtab);
1292 chartab = realloc(chartab, nnc * sizeof *chartab);
1293 memset(&chartab[NCHARS], 0, (nnc-NCHARS) * sizeof *chartab);
1294 #ifndef NROFF
1295 fchartab = realloc(fchartab, nnc * sizeof *fchartab);
1296 memset(&fchartab[NCHARS], 0, (nnc-NCHARS) * sizeof *fchartab);
1297 for (i = 0; i <= nfonts; i++) {
1298 extern short **fitab;
1299 if (fitab != NULL && fitab[i] != NULL) {
1300 fitab[i] = realloc(fitab[i], nnc * sizeof **fitab);
1301 memset(&fitab[i][NCHARS], 0,
1302 (nnc-NCHARS) * sizeof **fitab);
1303 }
1304 if (lhangtab != NULL && lhangtab[i] != NULL) {
1305 lhangtab[i] = realloc(lhangtab[i],
1306 nnc * sizeof **lhangtab);
1307 memset(&lhangtab[i][NCHARS], 0,
1308 (nnc-NCHARS) * sizeof **lhangtab);
1309 }
1310 if (lhangtab != NULL && rhangtab[i] != NULL) {
1311 rhangtab[i] = realloc(rhangtab[i],
1312 nnc * sizeof **rhangtab);
1313 memset(&rhangtab[i][NCHARS], 0,
1314 (nnc-NCHARS) * sizeof **rhangtab);
1315 }
1316 if (kernafter != NULL && kernafter[i] != NULL) {
1317 kernafter[i] = realloc(kernafter[i],
1318 nnc * sizeof **kernafter);
1319 memset(&kernafter[i][NCHARS], 0,
1320 (nnc-NCHARS) * sizeof **kernafter);
1321 }
1322 if (kernbefore != NULL && kernbefore[i] != NULL) {
1323 kernbefore[i] = realloc(kernbefore[i],
1324 nnc * sizeof **kernbefore);
1325 memset(&kernbefore[i][NCHARS], 0,
1326 (nnc-NCHARS) * sizeof **kernbefore);
1327 }
1328 if (ftrtab != NULL && ftrtab[i] != NULL) {
1329 int j;
1330 ftrtab[i] = realloc(ftrtab[i], nnc * sizeof **ftrtab);
1331 for (j = NCHARS; j < nnc; j++)
1332 ftrtab[i][j] = j;
1333 }
1334 if (lgtab != NULL && lgtab[i] != NULL) {
1335 lgtab[i] = realloc(lgtab[i], nnc * sizeof **lgtab);
1336 memset(&lgtab[i][NCHARS], 0,
1337 (nnc-NCHARS) * sizeof **lgtab);
1338 }
1339 if (lgrevtab != NULL && lgrevtab[i] != NULL) {
1340 lgrevtab[i] = realloc(lgrevtab[i],
1341 nnc * sizeof **lgrevtab);
1342 memset(&lgrevtab[i][NCHARS], 0,
1343 (nnc-NCHARS) * sizeof **lgrevtab);
1344 }
1345 }
1346 #endif /* !NROFF */
1347 NCHARS = nnc;
1348 }
1349