mkdev: remove devutf/C*
[troff.git] / troff / t6.c
blob6f08c99af802a928ebea22bc1e71e44c991be642
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 t_width(Tchar j)
19 int i, k;
21 if (iszbit(j))
22 return 0;
23 if (ismot(j)) {
24 if (isvmot(j))
25 return 0;
26 k = absmot(j);
27 if (isnmot(j))
28 k = -k;
29 return k;
31 i = cbits(j);
32 if (i < ' ') {
33 if (i == '\b')
34 return -widthp;
35 if (i == PRESC)
36 i = eschar;
37 else if (i == HX)
38 return 0;
40 if (i == ohc)
41 return 0;
42 i = trtab[i];
43 if (i < ' ')
44 return 0;
45 if (sfbits(j) == oldbits) {
46 xfont = pfont;
47 xpts = ppts;
48 } else
49 xbits(j, 0);
50 if (i < nchnames + ALPHABET && widcache[i].fontpts == (xfont<<8) + xpts && !setwdf)
51 k = widcache[i].width;
52 else {
53 k = getcw(i);
54 if (bd)
55 k += (bd - 1) * HOR;
56 if (cs)
57 k = cs;
59 widthp = k;
60 return k;
64 * clear width cache-- s means just space
66 void zapwcache(int s)
68 int i;
70 if (s) {
71 widcache[' '].fontpts = 0;
72 return;
74 for (i=0; i<NWIDCACHE; i++)
75 widcache[i].fontpts = 0;
78 int onfont(int n, int f) /* is char n on font f? */
80 int i;
81 Font *fp = &fonts[f];
82 Chwid *cp, *ep;
83 char *np;
85 if (n < ALPHABET) {
86 if (fp->wp[n].num == n) /* ascii at front */
87 return n;
88 else
89 return -1;
91 cp = &fp->wp[ALPHABET];
92 ep = &fp->wp[fp->nchars];
93 for ( ; cp < ep; cp++) /* search others */
94 if (cp->num == n)
95 return cp - &fp->wp[0];
96 /* maybe it was a \N... */
97 np = chname(n);
98 if (*np == Number) {
99 i = atoi(np+1); /* sscanf(np+1, "%d", &i); */
100 cp = &fp->wp[0];
101 ep = &fp->wp[fp->nchars];
102 for ( ; cp < ep; cp++) { /* search others */
103 if (cp->code == i)
104 return cp - &fp->wp[0];
106 return -2; /* a \N that doesn't have an entry */
108 return -1; /* vanilla not found */
111 int getcw(int i)
113 int k, n, x;
114 Font *fp;
115 int nocache = 0;
116 if (i < ' ')
117 return 0;
118 bd = 0;
119 fp = &fonts[xfont];
120 if (i == ' ') { /* a blank */
121 k = (fp->spacewidth * spacesz + 6) / 12;
122 /* this nonsense because .ss cmd uses 1/36 em as its units */
123 /* and default is 12 */
124 } else if ((n = onfont(i, xfont)) >= 0) { /* on this font at n */
125 k = fp->wp[n].wid;
126 if (setwdf)
127 numtabp[CT].val |= fp->wp[n].kern;
128 } else if (n == -2) { /* \N with default width */
130 k = fp->defaultwidth;
131 } else { /* not on current font */
132 nocache = 1;
133 k = fp->defaultwidth; /* default-size space */
134 if (smnt) {
135 int ii, jj;
136 for (ii=smnt, jj=0; jj < nfonts; jj++, ii=ii % nfonts + 1) {
137 if ((n = onfont(i, ii)) >= 0) {
138 k = fonts[ii].wp[n].wid;
139 if (xfont == sbold)
140 bd = bdtab[ii];
141 if (setwdf)
142 numtabp[CT].val |= fonts[ii].wp[n].kern;
143 break;
148 if (!bd)
149 bd = bdtab[xfont];
150 if (cs = cstab[xfont]) {
151 nocache = 1;
152 if (ccs = ccstab[xfont])
153 x = ccs;
154 else
155 x = xpts;
156 cs = (cs * EMPTS(x)) / 36;
158 /* was (k & BYTEMASK); since .wid is unsigned, should never happen */
159 if (k < 0)
160 ERROR "can't happen: negative width %d in getcw %d\n", k, i WARN;
161 k = (k * xpts + (Unitwidth / 2)) / Unitwidth;
162 if (nocache|bd)
163 widcache[i].fontpts = 0;
164 else {
165 widcache[i].fontpts = (xfont<<8) + xpts;
166 widcache[i].width = k;
168 return(k);
169 /* Unitwidth is Units/Point, where
170 * Units is the fundamental digitization
171 * of the character set widths, and
172 * Point is the number of goobies in a point
173 * e.g., for cat, Units=36, Point=6, so Unitwidth=36/6=6
174 * In effect, it's the size at which the widths
175 * translate directly into units.
179 void xbits(Tchar i, int bitf)
181 int k;
183 if(TROFF) {
184 xfont = fbits(i);
185 k = sbits(i);
186 if(k) {
187 xpts = pstab[k-1];
188 oldbits = sfbits(i);
189 pfont = xfont;
190 ppts = xpts;
191 return;
193 switch(bitf) {
194 case 0:
195 xfont = font;
196 xpts = pts;
197 break;
198 case 1:
199 xfont = pfont;
200 xpts = ppts;
201 break;
202 case 2:
203 xfont = mfont;
204 xpts = mpts;
210 /* these next two functions ought to be the same in troff and nroff, */
211 /* but the data structures they search are different. */
212 /* silly historical problem. */
215 Tchar t_setch(int c)
217 char temp[50];
218 char *s;
220 s = temp;
221 if (c == '(') { /* \(xx */
222 if ((*s++ = getach()) == 0 || (*s++ = getach()) == 0)
223 return(0);
224 } else { /* \C'...' */
225 c = getach();
226 while ((*s = getach()) != c && *s != 0 && s < temp + sizeof(temp) - 1)
227 s++;
229 *s = '\0';
230 #ifdef UNICODE
231 return chadd(temp, Troffchar, Install) | chbits; /* add name even if haven't seen it */
232 #else
233 if (NROFF) {
234 j = chadd(temp, Troffchar, Lookup);
235 if (j == -1)
236 return 0;
237 else
238 return j | chbits;
239 } else
240 return chadd(temp, Troffchar, Install) | chbits; /* add name even if haven't seen it */
242 #endif /*UNICODE*/
245 Tchar t_setabs(void) /* set absolute char from \N'...' */
247 int n;
248 char temp[10];
250 getch(); /* delim */
251 n = 0;
252 n = inumb(&n);
253 getch(); /* delim */
254 if (nonumb)
255 return 0;
256 sprintf(temp, "%d", n); /* convert into "#n" */
257 n = chadd(temp, Number, Install);
258 return n | chbits;
263 * fontlab[] is a cache that contains font information
264 * for each font.
265 * fontlab[] contains the 1- or 2-character name of the
266 * font current associated with that font.
267 * fonts 1..nfonts correspond to the mounted fonts;
268 * the last of these are the special fonts.
269 * If we don't use the (named) font in one of the
270 * standard positions, we install the name in the next
271 * free slot of fontlab[] and font[].
272 * Whenever we need info about the font, we
273 * read in the data into the next free slot with getfont.
274 * The ptfont() (t10.c) routine will tell
275 * the device filter to put the font always at position
276 * zero if xfont > nfonts, so no need to change these filters.
277 * Yes, this is a bit kludgy.
279 * This gives the new specs of findft:
280 * find the font name i, where i also can be a number.
281 * Installs the font(name) i when not present
282 * returns -1 on error
286 int t_findft(int i)
288 int k;
289 Uchar *p;
291 p = unpair(i);
293 if (isdigit(p[0])) { /* first look for numbers */
294 k = p[0] - '0';
295 if (p[1] > 0 && isdigit(p[1]))
296 k = 10 * k + p[1] - '0';
297 if (k > 0 && k <= nfonts && k < smnt)
298 return k; /* mounted font: .ft 3 */
299 if (fontlab[k] && k <= MAXFONTS) { /* translate */
300 return k; /*number to a name */
301 } else {
302 fprintf(stderr, "troff: no font at position %d\n", k);
303 return -1; /* wild number */
308 * Now we look for font names
310 for (k = 1; fontlab[k] != i; k++) {
311 if (k > MAXFONTS)
312 return -1; /* running out of fontlab space */
313 if (fontlab[k] == 0) { /* passed all existing names */
314 if (setfp(k, i, (char *) 0, 1) == -1)
315 return -1;
316 else {
317 fontlab[k] = i; /* install the name */
318 return k;
322 return k; /* was one of the existing names */
326 void caseps(void)
328 int i;
330 if (TROFF) {
331 if(skip())
332 i = apts1;
333 else {
334 noscale++;
335 i = inumb(&apts); /* this is a disaster for fractional point sizes */
336 noscale = 0;
337 if(nonumb)
338 i = apts1;
340 casps1(i);
345 void casps1(int i)
349 * in olden times, it used to ignore changes to 0 or negative.
350 * this is meant to allow the requested size to be anything,
351 * in particular so eqn can generate lots of \s-3's and still
352 * get back by matching \s+3's.
354 if (i <= 0)
355 return;
357 apts1 = apts;
358 apts = i;
359 pts1 = pts;
360 pts = findps(i);
361 mchbits();
365 int findps(int i)
367 int j, k;
369 for (j = k = 0; pstab[j] != 0; j++)
370 if (abs(pstab[j]-i) < abs(pstab[k]-i))
371 k = j;
373 return pstab[k];
377 void t_mchbits(void)
379 int i, j, k;
381 i = pts;
382 for (j = 0; i > (k = pstab[j]); j++)
383 if (!k) {
384 j--;
385 break;
387 chbits = 0;
388 setsbits(chbits, ++j);
389 setfbits(chbits, font);
390 sps = width(' ' | chbits);
391 zapwcache(1);
394 void t_setps(void)
396 int i, j;
398 i = cbits(getch());
399 if (isdigit(i)) { /* \sd or \sdd */
400 i -= '0';
401 if (i == 0) /* \s0 */
402 j = apts1;
403 else if (i <= 3 && (ch=getch()) && isdigit(j = cbits(ch))) { /* \sdd */
404 j = 10 * i + j - '0';
405 ch = 0;
406 } else /* \sd */
407 j = i;
408 } else if (i == '(') { /* \s(dd */
409 j = cbits(getch()) - '0';
410 j = 10 * j + cbits(getch()) - '0';
411 if (j == 0) /* \s(00 */
412 j = apts1;
413 } else if (i == '+' || i == '-') { /* \s+, \s- */
414 j = cbits(getch());
415 if (isdigit(j)) { /* \s+d, \s-d */
416 j -= '0';
417 } else if (j == '(') { /* \s+(dd, \s-(dd */
418 j = cbits(getch()) - '0';
419 j = 10 * j + cbits(getch()) - '0';
421 if (i == '-')
422 j = -j;
423 j += apts;
425 casps1(j);
429 Tchar t_setht(void) /* set character height from \H'...' */
431 int n;
432 Tchar c;
434 getch();
435 n = inumb(&apts);
436 getch();
437 if (n == 0 || nonumb)
438 n = apts; /* does this work? */
439 c = CHARHT;
440 c |= ZBIT;
441 setsbits(c, n);
442 setfbits(c, pts); /* sneaky, CHARHT font bits are size bits */
443 return(c);
446 Tchar t_setslant(void) /* set slant from \S'...' */
448 int n;
449 Tchar c;
451 getch();
452 n = 0;
453 n = inumb(&n);
454 getch();
455 if (nonumb)
456 n = 0;
457 c = SLANT;
458 c |= ZBIT;
459 setsfbits(c, n+180);
460 return c;
464 void caseft(void)
466 if (!TROFF) {
467 n_caseft();
468 return;
470 skip();
471 setfont(1);
475 void t_setfont(int a)
477 int i, j;
479 if (a)
480 i = getrq();
481 else
482 i = getsn();
483 if (!i || i == 'P') {
484 j = font1;
485 goto s0;
487 if (/* i == 'S' || */ i == '0') /* an experiment -- why can't we change to it? */
488 return;
489 if ((j = findft(i)) == -1)
490 if ((j = setfp(0, i, (char*) 0, 1)) == -1) /* try to put it in position 0 */
491 return;
493 font1 = font;
494 font = j;
495 mchbits();
499 void t_setwd(void)
501 int base, wid;
502 Tchar i;
503 int delim, emsz, k;
504 int savhp, savapts, savapts1, savfont, savfont1, savpts, savpts1;
506 base = numtabp[ST].val = numtabp[SB].val = wid = numtabp[CT].val = 0;
507 if (ismot(i = getch()))
508 return;
509 delim = cbits(i);
510 savhp = numtabp[HP].val;
511 numtabp[HP].val = 0;
512 savapts = apts;
513 savapts1 = apts1;
514 savfont = font;
515 savfont1 = font1;
516 savpts = pts;
517 savpts1 = pts1;
518 setwdf++;
519 while (cbits(i = getch()) != delim && !nlflg) {
520 k = width(i);
521 wid += k;
522 numtabp[HP].val += k;
523 if (!ismot(i)) {
524 emsz = (INCH/72) * xpts;
525 } else if (isvmot(i)) {
526 k = absmot(i);
527 if (isnmot(i))
528 k = -k;
529 base -= k;
530 emsz = 0;
531 } else
532 continue;
533 if (base < numtabp[SB].val)
534 numtabp[SB].val = base;
535 if ((k = base + emsz) > numtabp[ST].val)
536 numtabp[ST].val = k;
538 setn1(wid, 0, (Tchar) 0);
539 numtabp[HP].val = savhp;
540 apts = savapts;
541 apts1 = savapts1;
542 font = savfont;
543 font1 = savfont1;
544 pts = savpts;
545 pts1 = savpts1;
546 mchbits();
547 setwdf = 0;
551 Tchar t_vmot(void)
553 dfact = lss;
554 vflag++;
555 return t_mot();
559 Tchar t_hmot(void)
561 dfact = EM;
562 return t_mot();
566 Tchar t_mot(void)
568 int j, n;
569 Tchar i;
571 j = HOR;
572 getch(); /*eat delim*/
573 if (n = atoi0()) {
574 if (vflag)
575 j = VERT;
576 i = makem(quant(n, j));
577 } else
578 i = 0;
579 getch();
580 vflag = 0;
581 dfact = 1;
582 return i;
586 Tchar t_sethl(int k)
588 int j;
589 Tchar i;
591 j = EM / 2;
592 if (k == 'u')
593 j = -j;
594 else if (k == 'r')
595 j = -2 * j;
596 vflag++;
597 i = makem(j);
598 vflag = 0;
599 return i;
603 Tchar t_makem(int i)
605 Tchar j;
607 if (i >= 0)
608 j = i;
609 else
610 j = -i;
611 if (Hor > 1 && !vflag)
612 j = (j + Hor/2)/Hor * Hor;
613 j |= MOT;
614 if (i < 0)
615 j |= NMOT;
616 if (vflag)
617 j |= VMOT;
618 return j;
622 Tchar getlg(Tchar i)
624 Tchar j, k;
625 int lf;
627 if (!TROFF)
628 return i;
629 if ((lf = fonts[fbits(i)].ligfont) == 0) /* font lacks ligatures */
630 return(i);
631 j = getch0();
632 if (cbits(j) == 'i' && (lf & LFI))
633 j = LIG_FI;
634 else if (cbits(j) == 'l' && (lf & LFL))
635 j = LIG_FL;
636 else if (cbits(j) == 'f' && (lf & LFF)) {
637 if ((lf & (LFFI|LFFL)) && lg != 2) {
638 k = getch0();
639 if (cbits(k)=='i' && (lf&LFFI))
640 j = LIG_FFI;
641 else if (cbits(k)=='l' && (lf&LFFL))
642 j = LIG_FFL;
643 else {
644 *pbp++ = k;
645 j = LIG_FF;
647 } else
648 j = LIG_FF;
649 } else {
650 *pbp++ = j;
651 j = i;
653 return(i & SFMASK | j);
657 void caselg(void)
660 if(TROFF) {
661 skip();
662 lg = atoi0();
663 if (nonumb)
664 lg = 1;
668 void casefp(void)
670 int i, j;
672 if (!TROFF) {
673 n_casefp();
674 return;
676 skip();
677 i = cbits(getch());
678 if (isdigit(i)) {
679 i -= '0';
680 j = cbits(getch());
681 if (isdigit(j))
682 i = 10 * i + j - '0';
684 if (i <= 0 || i > nfonts)
685 ERROR "fp: bad font position %d", i WARN;
686 else if (skip() || !(j = getrq()))
687 ERROR "fp: no font name" WARN;
688 else if (skip() || !getname())
689 setfp(i, j, (char*) 0, 1);
690 else /* 3rd argument = filename */
691 setfp(i, j, nextf, 1);
694 char *strdupl(const char *s) /* make a copy of s */
696 char *t;
698 t = (char *) malloc(strlen(s) + 1);
699 if (t == NULL)
700 ERROR "out of space in strdupl(%s)", s FATAL;
701 strcpy(t, s);
702 return t;
705 int setfp(int pos, int f, char *truename, int print) /* mount font f at position pos[0...nfonts] */
707 char pathname[NS], shortname[NS];
709 zapwcache(0);
710 if (truename)
711 strcpy(shortname, truename);
712 else
713 strcpy(shortname, (char *) unpair(f));
714 if (truename && strrchr(truename, '/')) { /* .fp 1 R dir/file: use verbatim */
715 sprintf(pathname, "%s", truename);
716 if (fonts[pos].truename)
717 free(fonts[pos].truename);
718 fonts[pos].truename = strdupl(truename);
719 } else if (truename) { /* synonym: .fp 1 R Avant */
720 sprintf(pathname, "%s/dev%s/%s", fontdir, devname, truename);
721 truename = 0; /* so doesn't get repeated by ptfpcmd */
722 } else /* vanilla: .fp 5 XX */
723 sprintf(pathname, "%s/dev%s/%s", fontdir, devname, shortname);
724 if (truename == 0 && fonts[pos].truename != 0) {
725 free(fonts[pos].truename);
726 fonts[pos].truename = 0;
728 if (getfont(pathname, pos) < 0) {
729 ERROR "Can't open font file %s", pathname WARN;
730 return -1;
732 if (print && !ascii) {
733 ptfpcmd(pos, fonts[pos].longname, truename);
734 ptfont();
736 if (pos == smnt) {
737 smnt = 0;
738 sbold = 0;
740 fontlab[pos] = f;
741 if (smnt == 0 && fonts[pos].specfont)
742 smnt = pos;
743 bdtab[pos] = cstab[pos] = ccstab[pos] = 0;
744 return pos;
748 * .cs request; don't check legality of optional arguments
750 void casecs(void)
752 int i, j;
754 if (TROFF) {
755 int savtr = trace;
757 trace = 0;
758 noscale++;
759 skip();
760 if (!(i = getrq()) || (i = findft(i)) < 0)
761 goto rtn;
762 skip();
763 cstab[i] = atoi0();
764 skip();
765 j = atoi0();
766 if(nonumb)
767 ccstab[i] = 0;
768 else
769 ccstab[i] = findps(j);
770 rtn:
771 zapwcache(0);
772 noscale = 0;
773 trace = savtr;
778 void casebd(void)
780 int i, j, k;
782 if (!TROFF) {
783 n_casebd();
784 return;
786 zapwcache(0);
787 k = 0;
788 bd0:
789 if (skip() || !(i = getrq()) || (j = findft(i)) == -1) {
790 if (k)
791 goto bd1;
792 else
793 return;
795 if (j == smnt) {
796 k = smnt;
797 goto bd0;
799 if (k) {
800 sbold = j;
801 j = k;
803 bd1:
804 skip();
805 noscale++;
806 bdtab[j] = atoi0();
807 noscale = 0;
811 void casevs(void)
813 int i;
815 if (!TROFF) {
816 n_casevs();
817 return;
819 skip();
820 vflag++;
821 dfact = INCH; /* default scaling is points! */
822 dfactd = 72;
823 res = VERT;
824 i = inumb(&lss);
825 if (nonumb)
826 i = lss1;
827 if (i < VERT)
828 i = VERT;
829 lss1 = lss;
830 lss = i;
834 void casess(void)
836 int i;
838 if(TROFF) {
839 noscale++;
840 skip();
841 if(i = atoi0()) {
842 spacesz = i & 0177;
843 zapwcache(0);
844 sps = width(' ' | chbits);
846 noscale = 0;
851 Tchar t_xlss(void)
853 /* stores \x'...' into two successive Tchars.
854 * the first contains HX, the second the value,
855 * encoded as a vertical motion.
856 * decoding is done in n2.c by pchar().
858 int i;
860 getch();
861 dfact = lss;
862 i = quant(atoi0(), VERT);
863 dfact = 1;
864 getch();
865 if (i >= 0)
866 *pbp++ = MOT | VMOT | i;
867 else
868 *pbp++ = MOT | VMOT | NMOT | -i;
869 return HX;
872 Uchar *unpair(int i)
874 static Uchar name[3];
876 name[0] = i & SHORTMASK;
877 name[1] = (i >> SHORT) & SHORTMASK;
878 name[2] = 0;
879 return name;