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 #ifndef UNICODE
221 int j;
222 #endif
223 char temp[50];
224 char *s;
226 #ifndef UNICODE
227 j = 0;
228 #endif
229 s = temp;
230 if (c == '(') { /* \(xx */
231 if ((*s++ = getach()) == 0 || (*s++ = getach()) == 0)
232 return(0);
233 } else { /* \C'...' */
234 c = getach();
235 while ((*s = getach()) != c && *s != 0 && s < temp + sizeof(temp) - 1)
236 s++;
238 *s = '\0';
239 #ifdef UNICODE
240 return chadd(temp, Troffchar, Install) | chbits; /* add name even if haven't seen it */
241 #else
242 if (NROFF) {
243 j = chadd(temp, Troffchar, Lookup);
244 if ( j == -1)
245 return 0;
246 else
247 return j | chbits;
248 } else
249 return chadd(temp, Troffchar, Install) | chbits; /* add name even if haven't seen it */
251 #endif /*UNICODE*/
254 Tchar t_setabs(void) /* set absolute char from \N'...' */
256 int n;
257 char temp[10];
259 getch(); /* delim */
260 n = 0;
261 n = inumb(&n);
262 getch(); /* delim */
263 if (nonumb)
264 return 0;
265 sprintf(temp, "%d", n); /* convert into "#n" */
266 n = chadd(temp, Number, Install);
267 return n | chbits;
271 /*
272 * fontlab[] is a cache that contains font information
273 * for each font.
274 * fontlab[] contains the 1- or 2-character name of the
275 * font current associated with that font.
276 * fonts 1..nfonts correspond to the mounted fonts;
277 * the last of these are the special fonts.
278 * If we don't use the (named) font in one of the
279 * standard positions, we install the name in the next
280 * free slot of fontlab[] and font[].
281 * Whenever we need info about the font, we
282 * read in the data into the next free slot with getfont.
283 * The ptfont() (t10.c) routine will tell
284 * the device filter to put the font always at position
285 * zero if xfont > nfonts, so no need to change these filters.
286 * Yes, this is a bit kludgy.
288 * This gives the new specs of findft:
289 * find the font name i, where i also can be a number.
290 * Installs the font(name) i when not present
291 * returns -1 on error
292 */
294 int
295 t_findft(int i)
297 int k;
298 Uchar *p;
300 p = unpair(i);
302 if (isdigit(p[0])) { /* first look for numbers */
303 k = p[0] - '0';
304 if (p[1] > 0 && isdigit(p[1]))
305 k = 10 * k + p[1] - '0';
306 if (k > 0 && k <= nfonts && k < smnt)
307 return(k); /* mounted font: .ft 3 */
308 if (fontlab[k] && k <= MAXFONTS) { /* translate */
309 return(k); /*number to a name */
310 } else {
311 fprintf(stderr, "troff: no font at position %d\n", k);
312 return(-1); /* wild number */
316 /*
317 * Now we look for font names
318 */
319 for (k = 1; fontlab[k] != i; k++) {
320 if (k > MAXFONTS)
321 return(-1); /* running out of fontlab space */
322 if (fontlab[k] == 0) { /* passed all existing names */
323 if (setfp(k, i, (char *) 0, 1) == -1)
324 return(-1);
325 else {
326 fontlab[k] = i; /* install the name */
327 return(k);
331 return(k); /* was one of the existing names */
335 void caseps(void)
337 int i;
339 if (TROFF) {
340 if(skip())
341 i = apts1;
342 else {
343 noscale++;
344 i = inumb(&apts); /* this is a disaster for fractional point sizes */
345 noscale = 0;
346 if(nonumb)
347 i = apts1;
349 casps1(i);
354 void casps1(int i)
357 /*
358 * in olden times, it used to ignore changes to 0 or negative.
359 * this is meant to allow the requested size to be anything,
360 * in particular so eqn can generate lots of \s-3's and still
361 * get back by matching \s+3's.
363 if (i <= 0)
364 return;
365 */
366 apts1 = apts;
367 apts = i;
368 pts1 = pts;
369 pts = findps(i);
370 mchbits();
373 int
374 findps(int i)
376 int j, k;
378 for (j=k=0 ; pstab[j] != 0 ; j++)
379 if (abs(pstab[j]-i) < abs(pstab[k]-i))
380 k = j;
382 return(pstab[k]);
386 void t_mchbits(void)
388 int i, j, k;
390 i = pts;
391 for (j = 0; i > (k = pstab[j]); j++)
392 if (!k) {
393 j--;
394 break;
396 chbits = 0;
397 setsbits(chbits, ++j);
398 setfbits(chbits, font);
399 sps = width(' ' | chbits);
400 zapwcache(1);
403 void t_setps(void)
405 int i, j;
407 j = 0;
408 i = cbits(getch());
409 if (isdigit(i)) { /* \sd or \sdd */
410 i -= '0';
411 if (i == 0) /* \s0 */
412 j = apts1;
413 else if (i <= 3 && (ch=getch()) && isdigit(j = cbits(ch))) { /* \sdd */
414 j = 10 * i + j - '0';
415 ch = 0;
416 } else /* \sd */
417 j = i;
418 } else if (i == '(') { /* \s(dd */
419 j = cbits(getch()) - '0';
420 j = 10 * j + cbits(getch()) - '0';
421 if (j == 0) /* \s(00 */
422 j = apts1;
423 } else if (i == '+' || i == '-') { /* \s+, \s- */
424 j = cbits(getch());
425 if (isdigit(j)) { /* \s+d, \s-d */
426 j -= '0';
427 } else if (j == '(') { /* \s+(dd, \s-(dd */
428 j = cbits(getch()) - '0';
429 j = 10 * j + cbits(getch()) - '0';
431 if (i == '-')
432 j = -j;
433 j += apts;
435 casps1(j);
439 Tchar t_setht(void) /* set character height from \H'...' */
441 int n;
442 Tchar c;
444 getch();
445 n = inumb(&apts);
446 getch();
447 if (n == 0 || nonumb)
448 n = apts; /* does this work? */
449 c = CHARHT;
450 c |= ZBIT;
451 setsbits(c, n);
452 setfbits(c, pts); /* sneaky, CHARHT font bits are size bits */
453 return(c);
456 Tchar t_setslant(void) /* set slant from \S'...' */
458 int n;
459 Tchar c;
461 getch();
462 n = 0;
463 n = inumb(&n);
464 getch();
465 if (nonumb)
466 n = 0;
467 c = SLANT;
468 c |= ZBIT;
469 setsfbits(c, n+180);
470 return(c);
474 void caseft(void)
476 if (!TROFF) {
477 n_caseft();
478 return;
480 skip();
481 setfont(1);
485 void t_setfont(int a)
487 int i, j;
489 if (a)
490 i = getrq();
491 else
492 i = getsn();
493 if (!i || i == 'P') {
494 j = font1;
495 goto s0;
497 if (/* i == 'S' || */ i == '0') /* an experiment -- why can't we change to it? */
498 return;
499 if ((j = findft(i)) == -1)
500 if ((j = setfp(0, i, (char*) 0, 1)) == -1) /* try to put it in position 0 */
501 return;
502 s0:
503 font1 = font;
504 font = j;
505 mchbits();
509 void t_setwd(void)
511 int base, wid;
512 Tchar i;
513 int delim, emsz, k;
514 int savhp, savapts, savapts1, savfont, savfont1, savpts, savpts1;
516 base = numtabp[ST].val = numtabp[SB].val = wid = numtabp[CT].val = 0;
517 if (ismot(i = getch()))
518 return;
519 delim = cbits(i);
520 savhp = numtabp[HP].val;
521 numtabp[HP].val = 0;
522 savapts = apts;
523 savapts1 = apts1;
524 savfont = font;
525 savfont1 = font1;
526 savpts = pts;
527 savpts1 = pts1;
528 setwdf++;
529 while (cbits(i = getch()) != delim && !nlflg) {
530 k = width(i);
531 wid += k;
532 numtabp[HP].val += k;
533 if (!ismot(i)) {
534 emsz = (INCH/72) * xpts;
535 } else if (isvmot(i)) {
536 k = absmot(i);
537 if (isnmot(i))
538 k = -k;
539 base -= k;
540 emsz = 0;
541 } else
542 continue;
543 if (base < numtabp[SB].val)
544 numtabp[SB].val = base;
545 if ((k = base + emsz) > numtabp[ST].val)
546 numtabp[ST].val = k;
548 setn1(wid, 0, (Tchar) 0);
549 numtabp[HP].val = savhp;
550 apts = savapts;
551 apts1 = savapts1;
552 font = savfont;
553 font1 = savfont1;
554 pts = savpts;
555 pts1 = savpts1;
556 mchbits();
557 setwdf = 0;
561 Tchar t_vmot(void)
563 dfact = lss;
564 vflag++;
565 return t_mot();
569 Tchar t_hmot(void)
571 dfact = EM;
572 return t_mot();
576 Tchar t_mot(void)
578 int j, n;
579 Tchar i;
581 j = HOR;
582 getch(); /*eat delim*/
583 if (n = atoi0()) {
584 if (vflag)
585 j = VERT;
586 i = makem(quant(n, j));
587 } else
588 i = 0;
589 getch();
590 vflag = 0;
591 dfact = 1;
592 return(i);
596 Tchar t_sethl(int k)
598 int j;
599 Tchar i;
601 j = EM / 2;
602 if (k == 'u')
603 j = -j;
604 else if (k == 'r')
605 j = -2 * j;
606 vflag++;
607 i = makem(j);
608 vflag = 0;
609 return(i);
613 Tchar t_makem(int i)
615 Tchar j;
617 if (i >= 0)
618 j = i;
619 else
620 j = -i;
621 if (Hor > 1 && !vflag)
622 j = (j + Hor/2)/Hor * Hor;
623 j |= MOT;
624 if (i < 0)
625 j |= NMOT;
626 if (vflag)
627 j |= VMOT;
628 return(j);
632 Tchar getlg(Tchar i)
634 Tchar j, k;
635 int lf;
637 if (!TROFF)
638 return i;
639 if ((lf = fonts[fbits(i)].ligfont) == 0) /* font lacks ligatures */
640 return(i);
641 j = getch0();
642 if (cbits(j) == 'i' && (lf & LFI))
643 j = LIG_FI;
644 else if (cbits(j) == 'l' && (lf & LFL))
645 j = LIG_FL;
646 else if (cbits(j) == 'f' && (lf & LFF)) {
647 if ((lf & (LFFI|LFFL)) && lg != 2) {
648 k = getch0();
649 if (cbits(k)=='i' && (lf&LFFI))
650 j = LIG_FFI;
651 else if (cbits(k)=='l' && (lf&LFFL))
652 j = LIG_FFL;
653 else {
654 *pbp++ = k;
655 j = LIG_FF;
657 } else
658 j = LIG_FF;
659 } else {
660 *pbp++ = j;
661 j = i;
663 return(i & SFMASK | j);
667 void caselg(void)
670 if(TROFF) {
671 skip();
672 lg = atoi0();
673 if (nonumb)
674 lg = 1;
678 void casefp(void)
680 int i, j;
682 if (!TROFF) {
683 n_casefp();
684 return;
686 skip();
687 i = cbits(getch());
688 if (isdigit(i)) {
689 i -= '0';
690 j = cbits(getch());
691 if (isdigit(j))
692 i = 10 * i + j - '0';
694 if (i <= 0 || i > nfonts)
695 ERROR "fp: bad font position %d", i WARN;
696 else if (skip() || !(j = getrq()))
697 ERROR "fp: no font name" WARN;
698 else if (skip() || !getname())
699 setfp(i, j, (char*) 0, 1);
700 else /* 3rd argument = filename */
701 setfp(i, j, nextf, 1);
704 char *strdupl(const char *s) /* make a copy of s */
706 char *t;
708 t = (char *) malloc(strlen(s) + 1);
709 if (t == NULL)
710 ERROR "out of space in strdupl(%s)", s FATAL;
711 strcpy(t, s);
712 return t;
715 int
716 setfp(int pos, int f, char *truename, int print) /* mount font f at position pos[0...nfonts] */
718 char pathname[NS], shortname[NS];
720 zapwcache(0);
721 if (truename)
722 strcpy(shortname, truename);
723 else
724 strcpy(shortname, (char *) unpair(f));
725 if (truename && strrchr(truename, '/')) { /* .fp 1 R dir/file: use verbatim */
726 snprintf(pathname, NS, "%s", truename);
727 if (fonts[pos].truename)
728 free(fonts[pos].truename);
729 fonts[pos].truename = strdupl(truename);
730 } else if (truename) { /* synonym: .fp 1 R Avant */
731 snprintf(pathname, NS, "%s/dev%s/%s", fontdir, devname, truename);
732 truename = 0; /* so doesn't get repeated by ptfpcmd */
733 } else /* vanilla: .fp 5 XX */
734 snprintf(pathname, NS, "%s/dev%s/%s", fontdir, devname, shortname);
735 if (truename == 0 && fonts[pos].truename != 0) {
736 free(fonts[pos].truename);
737 fonts[pos].truename = 0;
739 if (getfont(pathname, pos) < 0) {
740 ERROR "Can't open font file %s", pathname WARN;
741 return -1;
743 if (print && !ascii) {
744 ptfpcmd(pos, fonts[pos].longname, truename);
745 ptfont();
747 if (pos == smnt) {
748 smnt = 0;
749 sbold = 0;
751 fontlab[pos] = f;
752 if (smnt == 0 && fonts[pos].specfont)
753 smnt = pos;
754 bdtab[pos] = cstab[pos] = ccstab[pos] = 0;
755 return pos;
758 /*
759 * .cs request; don't check legality of optional arguments
760 */
761 void casecs(void)
763 int i, j;
765 if (TROFF) {
766 int savtr = trace;
768 trace = 0;
769 noscale++;
770 skip();
771 if (!(i = getrq()) || (i = findft(i)) < 0)
772 goto rtn;
773 skip();
774 cstab[i] = atoi0();
775 skip();
776 j = atoi0();
777 if(nonumb)
778 ccstab[i] = 0;
779 else
780 ccstab[i] = findps(j);
781 rtn:
782 zapwcache(0);
783 noscale = 0;
784 trace = savtr;
789 void casebd(void)
791 int i, j, k;
793 j=0;
794 if (!TROFF) {
795 n_casebd();
796 return;
798 zapwcache(0);
799 k = 0;
800 bd0:
801 if (skip() || !(i = getrq()) || (j = findft(i)) == -1) {
802 if (k)
803 goto bd1;
804 else
805 return;
807 if (j == smnt) {
808 k = smnt;
809 goto bd0;
811 if (k) {
812 sbold = j;
813 j = k;
815 bd1:
816 skip();
817 noscale++;
818 bdtab[j] = atoi0();
819 noscale = 0;
823 void casevs(void)
825 int i;
827 if (!TROFF) {
828 n_casevs();
829 return;
831 skip();
832 vflag++;
833 dfact = INCH; /* default scaling is points! */
834 dfactd = 72;
835 res = VERT;
836 i = inumb(&lss);
837 if (nonumb)
838 i = lss1;
839 if (i < VERT)
840 i = VERT;
841 lss1 = lss;
842 lss = i;
846 void casess(void)
848 int i;
850 if(TROFF) {
851 noscale++;
852 skip();
853 if(i = atoi0()) {
854 spacesz = i & 0177;
855 zapwcache(0);
856 sps = width(' ' | chbits);
858 noscale = 0;
863 Tchar t_xlss(void)
865 /* stores \x'...' into two successive Tchars.
866 /* the first contains HX, the second the value,
867 /* encoded as a vertical motion.
868 /* decoding is done in n2.c by pchar().
869 */
870 int i;
872 getch();
873 dfact = lss;
874 i = quant(atoi0(), VERT);
875 dfact = 1;
876 getch();
877 if (i >= 0)
878 *pbp++ = MOT | VMOT | i;
879 else
880 *pbp++ = MOT | VMOT | NMOT | -i;
881 return(HX);
884 Uchar *unpair(int i)
886 static Uchar name[3];
888 name[0] = i & SHORTMASK;
889 name[1] = (i >> SHORT) & SHORTMASK;
890 name[2] = 0;
891 return name;