Blob


1 /*
2 * t6.c
3 *
4 * width functions, sizes and fonts
5 */
7 #include "tdef.h"
8 #include "fns.h"
9 #include "ext.h"
11 int fontlab[MAXFONTS+1];
12 int cstab[MAXFONTS+1];
13 int ccstab[MAXFONTS+1];
14 int bdtab[MAXFONTS+1];
15 int sbold = 0;
17 int
18 t_width(Tchar j)
19 {
20 int i, k;
22 if (iszbit(j))
23 return 0;
24 if (ismot(j)) {
25 if (isvmot(j))
26 return(0);
27 k = absmot(j);
28 if (isnmot(j))
29 k = -k;
30 return(k);
31 }
32 i = cbits(j);
33 if (i < ' ') {
34 if (i == '\b')
35 return(-widthp);
36 if (i == PRESC)
37 i = eschar;
38 else if (i == HX)
39 return(0);
40 }
41 if (i == ohc)
42 return(0);
43 i = trtab[i];
44 if (i < ' ')
45 return(0);
46 if (sfbits(j) == oldbits) {
47 xfont = pfont;
48 xpts = ppts;
49 } else
50 xbits(j, 0);
51 if (i < nchnames + ALPHABET && widcache[i].fontpts == (xfont<<8) + xpts && !setwdf)
52 k = widcache[i].width;
53 else {
54 k = getcw(i);
55 if (bd)
56 k += (bd - 1) * HOR;
57 if (cs)
58 k = cs;
59 }
60 widthp = k;
61 return(k);
62 }
64 /*
65 * clear width cache-- s means just space
66 */
67 void zapwcache(int s)
68 {
69 int i;
71 if (s) {
72 widcache[' '].fontpts = 0;
73 return;
74 }
75 for (i=0; i<NWIDCACHE; i++)
76 widcache[i].fontpts = 0;
77 }
79 int
80 onfont(int n, int f) /* is char n on font f? */
81 {
82 int i;
83 Font *fp = &fonts[f];
84 Chwid *cp, *ep;
85 char *np;
87 if (n < ALPHABET) {
88 if (fp->wp[n].num == n) /* ascii at front */
89 return n;
90 else
91 return -1;
92 }
93 cp = &fp->wp[ALPHABET];
94 ep = &fp->wp[fp->nchars];
95 for ( ; cp < ep; cp++) /* search others */
96 if (cp->num == n)
97 return cp - &fp->wp[0];
98 /* maybe it was a \N... */
99 np = chname(n);
100 if (*np == Number) {
101 i = atoi(np+1); /* sscanf(np+1, "%d", &i); */
102 cp = &fp->wp[0];
103 ep = &fp->wp[fp->nchars];
104 for ( ; cp < ep; cp++) { /* search others */
105 if (cp->code == i)
106 return cp - &fp->wp[0];
108 return -2; /* a \N that doesn't have an entry */
110 return -1; /* vanilla not found */
113 int
114 getcw(int i)
116 int k, n, x;
117 Font *fp;
118 int nocache = 0;
119 if (i < ' ')
120 return 0;
121 bd = 0;
122 fp = &fonts[xfont];
123 if (i == ' ') { /* a blank */
124 k = (fp->spacewidth * spacesz + 6) / 12;
125 /* this nonsense because .ss cmd uses 1/36 em as its units */
126 /* and default is 12 */
127 } else if ((n = onfont(i, xfont)) >= 0) { /* on this font at n */
128 k = fp->wp[n].wid;
129 if (setwdf)
130 numtabp[CT].val |= fp->wp[n].kern;
131 } else if (n == -2) { /* \N with default width */
133 k = fp->defaultwidth;
134 } else { /* not on current font */
135 nocache = 1;
136 k = fp->defaultwidth; /* default-size space */
137 if (smnt) {
138 int ii, jj;
139 for (ii=smnt, jj=0; jj < nfonts; jj++, ii=ii % nfonts + 1) {
140 if ((n = onfont(i, ii)) >= 0) {
141 k = fonts[ii].wp[n].wid;
142 if (xfont == sbold)
143 bd = bdtab[ii];
144 if (setwdf)
145 numtabp[CT].val |= fonts[ii].wp[n].kern;
146 break;
151 if (!bd)
152 bd = bdtab[xfont];
153 if (cs = cstab[xfont]) {
154 nocache = 1;
155 if (ccs = ccstab[xfont])
156 x = ccs;
157 else
158 x = xpts;
159 cs = (cs * EMPTS(x)) / 36;
161 /* was (k & BYTEMASK); since .wid is unsigned, should never happen */
162 if (k < 0)
163 ERROR "can't happen: negative width %d in getcw %d\n", k, i WARN;
164 k = (k * xpts + (Unitwidth / 2)) / Unitwidth;
165 if (nocache|bd)
166 widcache[i].fontpts = 0;
167 else {
168 widcache[i].fontpts = (xfont<<8) + xpts;
169 widcache[i].width = k;
171 return(k);
172 /* Unitwidth is Units/Point, where
173 /* Units is the fundamental digitization
174 /* of the character set widths, and
175 /* Point is the number of goobies in a point
176 /* e.g., for cat, Units=36, Point=6, so Unitwidth=36/6=6
177 /* In effect, it's the size at which the widths
178 /* translate directly into units.
179 */
182 void xbits(Tchar i, int bitf)
184 int k;
186 if(TROFF) {
187 xfont = fbits(i);
188 k = sbits(i);
189 if(k) {
190 xpts = pstab[k-1];
191 oldbits = sfbits(i);
192 pfont = xfont;
193 ppts = xpts;
194 return;
196 switch(bitf) {
197 case 0:
198 xfont = font;
199 xpts = pts;
200 break;
201 case 1:
202 xfont = pfont;
203 xpts = ppts;
204 break;
205 case 2:
206 xfont = mfont;
207 xpts = mpts;
213 /* these next two functions ought to be the same in troff and nroff, */
214 /* but the data structures they search are different. */
215 /* silly historical problem. */
218 Tchar t_setch(int c)
220 int j;
221 char temp[50];
222 char *s;
224 j = 0;
225 s = temp;
226 if (c == '(') { /* \(xx */
227 if ((*s++ = getach()) == 0 || (*s++ = getach()) == 0)
228 return(0);
229 } else { /* \C'...' */
230 c = getach();
231 while ((*s = getach()) != c && *s != 0 && s < temp + sizeof(temp) - 1)
232 s++;
234 *s = '\0';
235 #ifdef UNICODE
236 return chadd(temp, Troffchar, Install) | chbits; /* add name even if haven't seen it */
237 #else
238 if (NROFF) {
239 j = chadd(temp, Troffchar, Lookup);
240 if ( j == -1)
241 return 0;
242 else
243 return j | chbits;
244 } else
245 return chadd(temp, Troffchar, Install) | chbits; /* add name even if haven't seen it */
247 #endif /*UNICODE*/
250 Tchar t_setabs(void) /* set absolute char from \N'...' */
252 int n;
253 char temp[10];
255 getch(); /* delim */
256 n = 0;
257 n = inumb(&n);
258 getch(); /* delim */
259 if (nonumb)
260 return 0;
261 sprintf(temp, "%d", n); /* convert into "#n" */
262 n = chadd(temp, Number, Install);
263 return n | chbits;
267 /*
268 * fontlab[] is a cache that contains font information
269 * for each font.
270 * fontlab[] contains the 1- or 2-character name of the
271 * font current associated with that font.
272 * fonts 1..nfonts correspond to the mounted fonts;
273 * the last of these are the special fonts.
274 * If we don't use the (named) font in one of the
275 * standard positions, we install the name in the next
276 * free slot of fontlab[] and font[].
277 * Whenever we need info about the font, we
278 * read in the data into the next free slot with getfont.
279 * The ptfont() (t10.c) routine will tell
280 * the device filter to put the font always at position
281 * zero if xfont > nfonts, so no need to change these filters.
282 * Yes, this is a bit kludgy.
284 * This gives the new specs of findft:
285 * find the font name i, where i also can be a number.
286 * Installs the font(name) i when not present
287 * returns -1 on error
288 */
290 int
291 t_findft(int i)
293 int k;
294 Uchar *p;
296 p = unpair(i);
298 if (isdigit(p[0])) { /* first look for numbers */
299 k = p[0] - '0';
300 if (p[1] > 0 && isdigit(p[1]))
301 k = 10 * k + p[1] - '0';
302 if (k > 0 && k <= nfonts && k < smnt)
303 return(k); /* mounted font: .ft 3 */
304 if (fontlab[k] && k <= MAXFONTS) { /* translate */
305 return(k); /*number to a name */
306 } else {
307 fprintf(stderr, "troff: no font at position %d\n", k);
308 return(-1); /* wild number */
312 /*
313 * Now we look for font names
314 */
315 for (k = 1; fontlab[k] != i; k++) {
316 if (k > MAXFONTS)
317 return(-1); /* running out of fontlab space */
318 if (fontlab[k] == 0) { /* passed all existing names */
319 if (setfp(k, i, (char *) 0, 1) == -1)
320 return(-1);
321 else {
322 fontlab[k] = i; /* install the name */
323 return(k);
327 return(k); /* was one of the existing names */
331 void caseps(void)
333 int i;
335 if (TROFF) {
336 if(skip())
337 i = apts1;
338 else {
339 noscale++;
340 i = inumb(&apts); /* this is a disaster for fractional point sizes */
341 noscale = 0;
342 if(nonumb)
343 i = apts1;
345 casps1(i);
350 void casps1(int i)
353 /*
354 * in olden times, it used to ignore changes to 0 or negative.
355 * this is meant to allow the requested size to be anything,
356 * in particular so eqn can generate lots of \s-3's and still
357 * get back by matching \s+3's.
359 if (i <= 0)
360 return;
361 */
362 apts1 = apts;
363 apts = i;
364 pts1 = pts;
365 pts = findps(i);
366 mchbits();
369 int
370 findps(int i)
372 int j, k;
374 for (j=k=0 ; pstab[j] != 0 ; j++)
375 if (abs(pstab[j]-i) < abs(pstab[k]-i))
376 k = j;
378 return(pstab[k]);
382 void t_mchbits(void)
384 int i, j, k;
386 i = pts;
387 for (j = 0; i > (k = pstab[j]); j++)
388 if (!k) {
389 j--;
390 break;
392 chbits = 0;
393 setsbits(chbits, ++j);
394 setfbits(chbits, font);
395 sps = width(' ' | chbits);
396 zapwcache(1);
399 void t_setps(void)
401 int i, j;
403 j = 0;
404 i = cbits(getch());
405 if (isdigit(i)) { /* \sd or \sdd */
406 i -= '0';
407 if (i == 0) /* \s0 */
408 j = apts1;
409 else if (i <= 3 && (ch=getch()) && isdigit(j = cbits(ch))) { /* \sdd */
410 j = 10 * i + j - '0';
411 ch = 0;
412 } else /* \sd */
413 j = i;
414 } else if (i == '(') { /* \s(dd */
415 j = cbits(getch()) - '0';
416 j = 10 * j + cbits(getch()) - '0';
417 if (j == 0) /* \s(00 */
418 j = apts1;
419 } else if (i == '+' || i == '-') { /* \s+, \s- */
420 j = cbits(getch());
421 if (isdigit(j)) { /* \s+d, \s-d */
422 j -= '0';
423 } else if (j == '(') { /* \s+(dd, \s-(dd */
424 j = cbits(getch()) - '0';
425 j = 10 * j + cbits(getch()) - '0';
427 if (i == '-')
428 j = -j;
429 j += apts;
431 casps1(j);
435 Tchar t_setht(void) /* set character height from \H'...' */
437 int n;
438 Tchar c;
440 getch();
441 n = inumb(&apts);
442 getch();
443 if (n == 0 || nonumb)
444 n = apts; /* does this work? */
445 c = CHARHT;
446 c |= ZBIT;
447 setsbits(c, n);
448 setfbits(c, pts); /* sneaky, CHARHT font bits are size bits */
449 return(c);
452 Tchar t_setslant(void) /* set slant from \S'...' */
454 int n;
455 Tchar c;
457 getch();
458 n = 0;
459 n = inumb(&n);
460 getch();
461 if (nonumb)
462 n = 0;
463 c = SLANT;
464 c |= ZBIT;
465 setsfbits(c, n+180);
466 return(c);
470 void caseft(void)
472 if (!TROFF) {
473 n_caseft();
474 return;
476 skip();
477 setfont(1);
481 void t_setfont(int a)
483 int i, j;
485 if (a)
486 i = getrq();
487 else
488 i = getsn();
489 if (!i || i == 'P') {
490 j = font1;
491 goto s0;
493 if (/* i == 'S' || */ i == '0') /* an experiment -- why can't we change to it? */
494 return;
495 if ((j = findft(i)) == -1)
496 if ((j = setfp(0, i, (char*) 0, 1)) == -1) /* try to put it in position 0 */
497 return;
498 s0:
499 font1 = font;
500 font = j;
501 mchbits();
505 void t_setwd(void)
507 int base, wid;
508 Tchar i;
509 int delim, emsz, k;
510 int savhp, savapts, savapts1, savfont, savfont1, savpts, savpts1;
512 base = numtabp[ST].val = numtabp[SB].val = wid = numtabp[CT].val = 0;
513 if (ismot(i = getch()))
514 return;
515 delim = cbits(i);
516 savhp = numtabp[HP].val;
517 numtabp[HP].val = 0;
518 savapts = apts;
519 savapts1 = apts1;
520 savfont = font;
521 savfont1 = font1;
522 savpts = pts;
523 savpts1 = pts1;
524 setwdf++;
525 while (cbits(i = getch()) != delim && !nlflg) {
526 k = width(i);
527 wid += k;
528 numtabp[HP].val += k;
529 if (!ismot(i)) {
530 emsz = (INCH/72) * xpts;
531 } else if (isvmot(i)) {
532 k = absmot(i);
533 if (isnmot(i))
534 k = -k;
535 base -= k;
536 emsz = 0;
537 } else
538 continue;
539 if (base < numtabp[SB].val)
540 numtabp[SB].val = base;
541 if ((k = base + emsz) > numtabp[ST].val)
542 numtabp[ST].val = k;
544 setn1(wid, 0, (Tchar) 0);
545 numtabp[HP].val = savhp;
546 apts = savapts;
547 apts1 = savapts1;
548 font = savfont;
549 font1 = savfont1;
550 pts = savpts;
551 pts1 = savpts1;
552 mchbits();
553 setwdf = 0;
557 Tchar t_vmot(void)
559 dfact = lss;
560 vflag++;
561 return t_mot();
565 Tchar t_hmot(void)
567 dfact = EM;
568 return t_mot();
572 Tchar t_mot(void)
574 int j, n;
575 Tchar i;
577 j = HOR;
578 getch(); /*eat delim*/
579 if (n = atoi0()) {
580 if (vflag)
581 j = VERT;
582 i = makem(quant(n, j));
583 } else
584 i = 0;
585 getch();
586 vflag = 0;
587 dfact = 1;
588 return(i);
592 Tchar t_sethl(int k)
594 int j;
595 Tchar i;
597 j = EM / 2;
598 if (k == 'u')
599 j = -j;
600 else if (k == 'r')
601 j = -2 * j;
602 vflag++;
603 i = makem(j);
604 vflag = 0;
605 return(i);
609 Tchar t_makem(int i)
611 Tchar j;
613 if (i >= 0)
614 j = i;
615 else
616 j = -i;
617 if (Hor > 1 && !vflag)
618 j = (j + Hor/2)/Hor * Hor;
619 j |= MOT;
620 if (i < 0)
621 j |= NMOT;
622 if (vflag)
623 j |= VMOT;
624 return(j);
628 Tchar getlg(Tchar i)
630 Tchar j, k;
631 int lf;
633 if (!TROFF)
634 return i;
635 if ((lf = fonts[fbits(i)].ligfont) == 0) /* font lacks ligatures */
636 return(i);
637 j = getch0();
638 if (cbits(j) == 'i' && (lf & LFI))
639 j = LIG_FI;
640 else if (cbits(j) == 'l' && (lf & LFL))
641 j = LIG_FL;
642 else if (cbits(j) == 'f' && (lf & LFF)) {
643 if ((lf & (LFFI|LFFL)) && lg != 2) {
644 k = getch0();
645 if (cbits(k)=='i' && (lf&LFFI))
646 j = LIG_FFI;
647 else if (cbits(k)=='l' && (lf&LFFL))
648 j = LIG_FFL;
649 else {
650 *pbp++ = k;
651 j = LIG_FF;
653 } else
654 j = LIG_FF;
655 } else {
656 *pbp++ = j;
657 j = i;
659 return(i & SFMASK | j);
663 void caselg(void)
666 if(TROFF) {
667 skip();
668 lg = atoi0();
669 if (nonumb)
670 lg = 1;
674 void casefp(void)
676 int i, j;
678 if (!TROFF) {
679 n_casefp();
680 return;
682 skip();
683 i = cbits(getch());
684 if (isdigit(i)) {
685 i -= '0';
686 j = cbits(getch());
687 if (isdigit(j))
688 i = 10 * i + j - '0';
690 if (i <= 0 || i > nfonts)
691 ERROR "fp: bad font position %d", i WARN;
692 else if (skip() || !(j = getrq()))
693 ERROR "fp: no font name" WARN;
694 else if (skip() || !getname())
695 setfp(i, j, (char*) 0, 1);
696 else /* 3rd argument = filename */
697 setfp(i, j, nextf, 1);
700 char *strdupl(const char *s) /* make a copy of s */
702 char *t;
704 t = (char *) malloc(strlen(s) + 1);
705 if (t == NULL)
706 ERROR "out of space in strdupl(%s)", s FATAL;
707 strcpy(t, s);
708 return t;
711 int
712 setfp(int pos, int f, char *truename, int print) /* mount font f at position pos[0...nfonts] */
714 char pathname[NS], shortname[NS], *sl;
716 sl = (char*)0;
717 zapwcache(0);
718 if (truename)
719 strcpy(shortname, truename);
720 else
721 strcpy(shortname, (char *) unpair(f));
722 if (truename && strrchr(truename, '/')) { /* .fp 1 R dir/file: use verbatim */
723 sprintf(pathname, "%s", truename);
724 if (fonts[pos].truename)
725 free(fonts[pos].truename);
726 fonts[pos].truename = strdupl(truename);
727 } else if (truename) { /* synonym: .fp 1 R Avant */
728 sprintf(pathname, "%s/dev%s/%s", fontdir, devname, truename);
729 truename = 0; /* so doesn't get repeated by ptfpcmd */
730 } else /* vanilla: .fp 5 XX */
731 sprintf(pathname, "%s/dev%s/%s", fontdir, devname, shortname);
732 if (truename == 0 && fonts[pos].truename != 0) {
733 free(fonts[pos].truename);
734 fonts[pos].truename = 0;
736 if (getfont(pathname, pos) < 0) {
737 ERROR "Can't open font file %s", pathname WARN;
738 return -1;
740 if (print && !ascii) {
741 ptfpcmd(pos, fonts[pos].longname, truename);
742 ptfont();
744 if (pos == smnt) {
745 smnt = 0;
746 sbold = 0;
748 fontlab[pos] = f;
749 if (smnt == 0 && fonts[pos].specfont)
750 smnt = pos;
751 bdtab[pos] = cstab[pos] = ccstab[pos] = 0;
752 return pos;
755 /*
756 * .cs request; don't check legality of optional arguments
757 */
758 void casecs(void)
760 int i, j;
762 if (TROFF) {
763 int savtr = trace;
765 trace = 0;
766 noscale++;
767 skip();
768 if (!(i = getrq()) || (i = findft(i)) < 0)
769 goto rtn;
770 skip();
771 cstab[i] = atoi0();
772 skip();
773 j = atoi0();
774 if(nonumb)
775 ccstab[i] = 0;
776 else
777 ccstab[i] = findps(j);
778 rtn:
779 zapwcache(0);
780 noscale = 0;
781 trace = savtr;
786 void casebd(void)
788 int i, j, k;
790 j=0;
791 if (!TROFF) {
792 n_casebd();
793 return;
795 zapwcache(0);
796 k = 0;
797 bd0:
798 if (skip() || !(i = getrq()) || (j = findft(i)) == -1) {
799 if (k)
800 goto bd1;
801 else
802 return;
804 if (j == smnt) {
805 k = smnt;
806 goto bd0;
808 if (k) {
809 sbold = j;
810 j = k;
812 bd1:
813 skip();
814 noscale++;
815 bdtab[j] = atoi0();
816 noscale = 0;
820 void casevs(void)
822 int i;
824 if (!TROFF) {
825 n_casevs();
826 return;
828 skip();
829 vflag++;
830 dfact = INCH; /* default scaling is points! */
831 dfactd = 72;
832 res = VERT;
833 i = inumb(&lss);
834 if (nonumb)
835 i = lss1;
836 if (i < VERT)
837 i = VERT;
838 lss1 = lss;
839 lss = i;
843 void casess(void)
845 int i;
847 if(TROFF) {
848 noscale++;
849 skip();
850 if(i = atoi0()) {
851 spacesz = i & 0177;
852 zapwcache(0);
853 sps = width(' ' | chbits);
855 noscale = 0;
860 Tchar t_xlss(void)
862 /* stores \x'...' into two successive Tchars.
863 /* the first contains HX, the second the value,
864 /* encoded as a vertical motion.
865 /* decoding is done in n2.c by pchar().
866 */
867 int i;
869 getch();
870 dfact = lss;
871 i = quant(atoi0(), VERT);
872 dfact = 1;
873 getch();
874 if (i >= 0)
875 *pbp++ = MOT | VMOT | i;
876 else
877 *pbp++ = MOT | VMOT | NMOT | -i;
878 return(HX);
881 Uchar *unpair(int i)
883 static Uchar name[3];
885 name[0] = i & SHORTMASK;
886 name[1] = (i >> SHORT) & SHORTMASK;
887 name[2] = 0;
888 return name;