]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/troff/t6.c
sshfs: usage
[plan9front.git] / sys / src / cmd / troff / t6.c
1 /*
2  * t6.c
3  * 
4  * width functions, sizes and fonts
5  */
6
7 #include "tdef.h"
8 #include "fns.h"
9 #include "ext.h"
10
11 int     fontlab[MAXFONTS+1];
12 int     cstab[MAXFONTS+1];
13 int     ccstab[MAXFONTS+1];
14 int     bdtab[MAXFONTS+1];
15 int     sbold = 0;
16
17 t_width(Tchar j)
18 {
19         int i, k;
20
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);
30         }
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);
39         }
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;
58         }
59         widthp = k;
60         return(k);
61 }
62
63 /*
64  * clear width cache-- s means just space
65  */
66 void zapwcache(int s)
67 {
68         int i;
69
70         if (s) {
71                 widcache[' '].fontpts = 0;
72                 return;
73         }
74         for (i=0; i<NWIDCACHE; i++)
75                 widcache[i].fontpts = 0;
76 }
77
78 onfont(int n, int f)    /* is char n on font f? */
79 {
80         int i;
81         Font *fp = &fonts[f];
82         Chwid *cp, *ep;
83         char *np;
84
85         if (n < ALPHABET) {
86                 if (fp->wp[n].num == n) /* ascii at front */
87                         return n;
88                 else
89                         return -1;
90         }
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];
105                 }
106                 return -2;      /* a \N that doesn't have an entry */
107         }
108         return -1;      /* vanilla not found */
109 }
110
111 getcw(int i)
112 {
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 */
129                 
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;
144                                 }
145                         }
146                 }
147         }
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;
157         }
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;
167         }
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.
176         */
177 }
178
179 void xbits(Tchar i, int bitf)
180 {
181         int k;
182
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;
192                 }
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;
205                 }
206         }
207 }
208
209
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. */
213
214
215 Tchar t_setch(int c)
216 {
217         int j;
218         char temp[50];
219         char *s;
220
221         s = temp;
222         if (c == '(') { /* \(xx */
223                 if ((*s++ = getach()) == 0 || (*s++ = getach()) == 0)
224                         return(0);
225         } else {        /* \C'...' */
226                 c = getach();
227                 while ((*s = getach()) != c && *s != 0 && s < temp + sizeof(temp) - 1)
228                         s++;
229         }
230         *s = '\0';
231 #ifdef UNICODE
232         return chadd(temp, Troffchar, Install) | chbits; /* add name even if haven't seen it */
233 #else
234         if (NROFF) {
235                 j = chadd(temp, Troffchar, Lookup);
236                 if ( j == -1)
237                         return 0;
238                 else
239                         return j | chbits;
240         } else
241                 return chadd(temp, Troffchar, Install) | chbits; /* add name even if haven't seen it */
242                 
243 #endif /*UNICODE*/
244 }
245
246 Tchar t_setabs(void)            /* set absolute char from \N'...' */
247 {
248         int n;
249         char temp[10];
250
251         getch();        /* delim */
252         n = 0;
253         n = inumb(&n);
254         getch();        /* delim */
255         if (nonumb)
256                 return 0;
257         sprintf(temp, "%d", n); /* convert into "#n" */
258         n = chadd(temp, Number, Install);
259         return n | chbits;
260 }
261
262
263 /*
264  * fontlab[] is a cache that contains font information
265  * for each font.
266  * fontlab[] contains the 1- or 2-character name of the
267  * font current associated with that font.
268  * fonts 1..nfonts correspond to the mounted fonts;
269  * the last of these are the special fonts.
270  * If we don't use the (named) font in one of the
271  * standard positions, we install the name in the next
272  * free slot of fontlab[] and font[].
273  * Whenever we need info about the font, we
274  * read in the data into the next free slot with getfont.
275  * The ptfont() (t10.c) routine will tell
276  * the device filter to put the font always at position
277  * zero if xfont > nfonts, so no need to change these filters.
278  * Yes, this is a bit kludgy.
279  *
280  * This gives the new specs of findft:
281  *      find the font name i, where i also can be a number.
282  *      Installs the font(name) i when not present
283  *      returns -1 on error
284  */
285
286
287 t_findft(int i)
288 {
289         int k;
290         Uchar *p;
291
292         p = unpair(i);
293
294         if (isdigit(p[0])) {            /* first look for numbers */
295                 k = p[0] - '0';
296                 if (p[1] > 0 && isdigit(p[1]))
297                         k = 10 * k + p[1] - '0';
298                 if (k > 0 && k <= nfonts && k < smnt)
299                         return(k);      /* mounted font:  .ft 3 */
300                 if (fontlab[k] && k <= MAXFONTS) {      /* translate */
301                         return(k);                      /*number to a name */
302                 } else {
303                         fprintf(stderr, "troff: no font at position %d\n", k);
304                         return(-1);     /* wild number */
305                 }
306         }
307
308         /*
309          * Now we look for font names
310          */
311         for (k = 1; fontlab[k] != i; k++) {
312                 if (k > MAXFONTS)
313                         return(-1);     /* running out of fontlab space */
314                 if (fontlab[k] == 0) {  /* passed all existing names */
315                         if (setfp(k, i, (char *) 0, 1) == -1)
316                                 return(-1);
317                         else {
318                                 fontlab[k] = i; /* install the name */
319                                 return(k);
320                         }
321                 }
322         }
323         return(k);                      /* was one of the existing names */
324 }
325
326
327 void caseps(void)
328 {
329         int i;
330
331         if (TROFF) {
332                 if(skip())
333                         i = apts1;
334                 else {
335                         noscale++;
336                         i = inumb(&apts);       /* this is a disaster for fractional point sizes */
337                         noscale = 0;
338                         if(nonumb)
339                                 i = apts1;
340                 }
341                 casps1(i);
342         }
343 }
344
345
346 void casps1(int i)
347 {
348
349 /*
350  * in olden times, it used to ignore changes to 0 or negative.
351  * this is meant to allow the requested size to be anything,
352  * in particular so eqn can generate lots of \s-3's and still
353  * get back by matching \s+3's.
354
355         if (i <= 0)
356                 return;
357 */
358         apts1 = apts;
359         apts = i;
360         pts1 = pts;
361         pts = findps(i);
362         mchbits();
363 }
364
365
366 findps(int i)
367 {
368         int j, k;
369
370         for (j=k=0 ; pstab[j] != 0 ; j++)
371                 if (abs(pstab[j]-i) < abs(pstab[k]-i))
372                         k = j;
373
374         return(pstab[k]);
375 }
376
377
378 void t_mchbits(void)
379 {
380         int i, j, k;
381
382         i = pts;
383         for (j = 0; i > (k = pstab[j]); j++)
384                 if (!k) {
385                         j--;
386                         break;
387                 }
388         chbits = 0;
389         setsbits(chbits, ++j);
390         setfbits(chbits, font);
391         sps = width(' ' | chbits);
392         zapwcache(1);
393 }
394
395 void t_setps(void)
396 {
397         int i, j;
398
399         i = cbits(getch());
400         if (isdigit(i)) {               /* \sd or \sdd */
401                 i -= '0';
402                 if (i == 0)             /* \s0 */
403                         j = apts1;
404                 else if (i <= 3 && (ch=getch()) && isdigit(j = cbits(ch))) {    /* \sdd */
405                         j = 10 * i + j - '0';
406                         ch = 0;
407                 } else          /* \sd */
408                         j = i;
409         } else if (i == '(') {          /* \s(dd */
410                 j = cbits(getch()) - '0';
411                 j = 10 * j + cbits(getch()) - '0';
412                 if (j == 0)             /* \s(00 */
413                         j = apts1;
414         } else if (i == '+' || i == '-') {      /* \s+, \s- */
415                 j = cbits(getch());
416                 if (isdigit(j)) {               /* \s+d, \s-d */
417                         j -= '0';
418                 } else if (j == '(') {          /* \s+(dd, \s-(dd */
419                         j = cbits(getch()) - '0';
420                         j = 10 * j + cbits(getch()) - '0';
421                 }
422                 if (i == '-')
423                         j = -j;
424                 j += apts;
425         }
426         casps1(j);
427 }
428
429
430 Tchar t_setht(void)             /* set character height from \H'...' */
431 {
432         int n;
433         Tchar c;
434
435         getch();
436         n = inumb(&apts);
437         getch();
438         if (n == 0 || nonumb)
439                 n = apts;       /* does this work? */
440         c = CHARHT;
441         c |= ZBIT;
442         setsbits(c, n);
443         setfbits(c, pts);       /* sneaky, CHARHT font bits are size bits */
444         return(c);
445 }
446
447 Tchar t_setslant(void)          /* set slant from \S'...' */
448 {
449         int n;
450         Tchar c;
451
452         getch();
453         n = 0;
454         n = inumb(&n);
455         getch();
456         if (nonumb)
457                 n = 0;
458         c = SLANT;
459         c |= ZBIT;
460         setsfbits(c, n+180);
461         return(c);
462 }
463
464
465 void caseft(void)
466 {
467         if (!TROFF) {
468                 n_caseft();
469                 return;
470         }
471         skip();
472         setfont(1);
473 }
474
475
476 void t_setfont(int a)
477 {
478         int i, j;
479
480         if (a)
481                 i = getrq();
482         else 
483                 i = getsn();
484         if (!i || i == 'P') {
485                 j = font1;
486                 goto s0;
487         }
488         if (/* i == 'S' || */ i == '0') /* an experiment -- why can't we change to it? */
489                 return;
490         if ((j = findft(i)) == -1)
491                 if ((j = setfp(0, i, (char*) 0, 1)) == -1)      /* try to put it in position 0 */
492                         return;
493 s0:
494         font1 = font;
495         font = j;
496         mchbits();
497 }
498
499
500 void t_setwd(void)
501 {
502         int base, wid;
503         Tchar i;
504         int delim, emsz, k;
505         int savhp, savapts, savapts1, savfont, savfont1, savpts, savpts1;
506
507         base = numtabp[ST].val = numtabp[SB].val = wid = numtabp[CT].val = 0;
508         if (ismot(i = getch()))
509                 return;
510         delim = cbits(i);
511         savhp = numtabp[HP].val;
512         numtabp[HP].val = 0;
513         savapts = apts;
514         savapts1 = apts1;
515         savfont = font;
516         savfont1 = font1;
517         savpts = pts;
518         savpts1 = pts1;
519         setwdf++;
520         while (cbits(i = getch()) != delim && !nlflg) {
521                 k = width(i);
522                 wid += k;
523                 numtabp[HP].val += k;
524                 if (!ismot(i)) {
525                         emsz = (INCH/72) * xpts;
526                 } else if (isvmot(i)) {
527                         k = absmot(i);
528                         if (isnmot(i))
529                                 k = -k;
530                         base -= k;
531                         emsz = 0;
532                 } else 
533                         continue;
534                 if (base < numtabp[SB].val)
535                         numtabp[SB].val = base;
536                 if ((k = base + emsz) > numtabp[ST].val)
537                         numtabp[ST].val = k;
538         }
539         setn1(wid, 0, (Tchar) 0);
540         numtabp[HP].val = savhp;
541         apts = savapts;
542         apts1 = savapts1;
543         font = savfont;
544         font1 = savfont1;
545         pts = savpts;
546         pts1 = savpts1;
547         mchbits();
548         setwdf = 0;
549 }
550
551
552 Tchar t_vmot(void)
553 {
554         dfact = lss;
555         vflag++;
556         return t_mot();
557 }
558
559
560 Tchar t_hmot(void)
561 {
562         dfact = EM;
563         return t_mot();
564 }
565
566
567 Tchar t_mot(void)
568 {
569         int j, n;
570         Tchar i;
571
572         j = HOR;
573         getch(); /*eat delim*/
574         if (n = atoi0()) {
575                 if (vflag)
576                         j = VERT;
577                 i = makem(quant(n, j));
578         } else
579                 i = 0;
580         getch();
581         vflag = 0;
582         dfact = 1;
583         return(i);
584 }
585
586
587 Tchar t_sethl(int k)
588 {
589         int j;
590         Tchar i;
591
592         j = EM / 2;
593         if (k == 'u')
594                 j = -j;
595         else if (k == 'r')
596                 j = -2 * j;
597         vflag++;
598         i = makem(j);
599         vflag = 0;
600         return(i);
601 }
602
603
604 Tchar t_makem(int i)
605 {
606         Tchar j;
607
608         if (i >= 0)
609                 j = i;
610         else
611                 j = -i;
612         if (Hor > 1 && !vflag)
613                 j = (j + Hor/2)/Hor * Hor;
614         j |= MOT;
615         if (i < 0)
616                 j |= NMOT;
617         if (vflag)
618                 j |= VMOT;
619         return(j);
620 }
621
622
623 Tchar getlg(Tchar i)
624 {
625         Tchar j, k;
626         int lf;
627
628         if (!TROFF)
629                 return i;
630         if ((lf = fonts[fbits(i)].ligfont) == 0) /* font lacks ligatures */
631                 return(i);
632         j = getch0();
633         if (cbits(j) == 'i' && (lf & LFI))
634                 j = LIG_FI;
635         else if (cbits(j) == 'l' && (lf & LFL))
636                 j = LIG_FL;
637         else if (cbits(j) == 'f' && (lf & LFF)) {
638                 if ((lf & (LFFI|LFFL)) && lg != 2) {
639                         k = getch0();
640                         if (cbits(k)=='i' && (lf&LFFI))
641                                 j = LIG_FFI;
642                         else if (cbits(k)=='l' && (lf&LFFL))
643                                 j = LIG_FFL;
644                         else {
645                                 *pbp++ = k;
646                                 j = LIG_FF;
647                         }
648                 } else 
649                         j = LIG_FF;
650         } else {
651                 *pbp++ = j;
652                 j = i;
653         }
654         return(i & SFMASK | j);
655 }
656
657
658 void caselg(void)
659 {
660
661         if(TROFF) {
662                 skip();
663                 lg = atoi0();
664                 if (nonumb)
665                         lg = 1;
666         }
667 }
668
669 void casefp(void)
670 {
671         int i, j;
672
673         if (!TROFF) {
674                 n_casefp();
675                 return;
676         }
677         skip();
678         i = cbits(getch());
679         if (isdigit(i)) {
680                 i -= '0';
681                 j = cbits(getch());
682                 if (isdigit(j))
683                         i = 10 * i + j - '0';
684         }
685         if (i <= 0 || i > nfonts)
686                 ERROR "fp: bad font position %d", i WARN;
687         else if (skip() || !(j = getrq()))
688                 ERROR "fp: no font name" WARN; 
689         else if (skip() || !getname())
690                 setfp(i, j, (char*) 0, 1);
691         else            /* 3rd argument = filename */
692                 setfp(i, j, nextf, 1);
693 }
694
695 char *strdupl(const char *s)    /* make a copy of s */
696 {
697         char *t;
698
699         t = (char *) malloc(strlen(s) + 1);
700         if (t == NULL)
701                 ERROR "out of space in strdupl(%s)", s FATAL;
702         strcpy(t, s);
703         return t;
704 }
705
706 setfp(int pos, int f, char *truename, int print)        /* mount font f at position pos[0...nfonts] */
707 {
708         char pathname[NS], shortname[NS], *sl;
709
710         zapwcache(0);
711         if (truename)
712                 strcpy(shortname, truename);
713         else
714                 strcpy(shortname, (char *) unpair(f));
715         if (truename && strrchr(truename, '/')) {       /* .fp 1 R dir/file: use verbatim */
716                 sprintf(pathname, "%s", truename);
717                 if (fonts[pos].truename)
718                         free(fonts[pos].truename);
719                 fonts[pos].truename = strdupl(truename);
720         } else if (truename) {                  /* synonym: .fp 1 R Avant */
721                 sprintf(pathname, "%s/dev%s/%s", fontdir, devname, truename);
722                 truename = 0;   /* so doesn't get repeated by ptfpcmd */
723         } else                                  /* vanilla: .fp 5 XX */
724                 sprintf(pathname, "%s/dev%s/%s", fontdir, devname, shortname);
725         if (truename == 0 && fonts[pos].truename != 0) {
726                 free(fonts[pos].truename);
727                 fonts[pos].truename = 0;
728         }
729         if (getfont(pathname, pos) < 0) {
730                 ERROR "Can't open font file %s", pathname WARN;
731                 return -1;
732         }
733         if (print && !ascii) {
734                 ptfpcmd(pos, fonts[pos].longname, truename);
735                 ptfont();
736         }
737         if (pos == smnt) {
738                 smnt = 0; 
739                 sbold = 0; 
740         }
741         fontlab[pos] = f;
742         if (smnt == 0 && fonts[pos].specfont)
743                 smnt = pos;
744         bdtab[pos] = cstab[pos] = ccstab[pos] = 0;
745         return pos;
746 }
747
748 /*
749  * .cs request; don't check legality of optional arguments
750  */
751 void casecs(void)
752 {
753         int i, j;
754
755         if (TROFF) {
756                 int savtr = trace;
757
758                 trace = 0;
759                 noscale++;
760                 skip();
761                 if (!(i = getrq()) || (i = findft(i)) < 0)
762                         goto rtn;
763                 skip();
764                 cstab[i] = atoi0();
765                 skip();
766                 j = atoi0();
767                 if(nonumb)
768                         ccstab[i] = 0;
769                 else
770                         ccstab[i] = findps(j);
771         rtn:
772                 zapwcache(0);
773                 noscale = 0;
774                 trace = savtr;
775         }
776 }
777
778
779 void casebd(void)
780 {
781         int i, j, k;
782
783         if (!TROFF) {
784                 n_casebd();
785                 return;
786         }
787         zapwcache(0);
788         k = 0;
789 bd0:
790         if (skip() || !(i = getrq()) || (j = findft(i)) == -1) {
791                 if (k)
792                         goto bd1;
793                 else 
794                         return;
795         }
796         if (j == smnt) {
797                 k = smnt;
798                 goto bd0;
799         }
800         if (k) {
801                 sbold = j;
802                 j = k;
803         }
804 bd1:
805         skip();
806         noscale++;
807         bdtab[j] = atoi0();
808         noscale = 0;
809 }
810
811
812 void casevs(void)
813 {
814         int i;
815
816         if (!TROFF) {
817                 n_casevs();
818                 return;
819         }
820         skip();
821         vflag++;
822         dfact = INCH; /* default scaling is points! */
823         dfactd = 72;
824         res = VERT;
825         i = inumb(&lss);
826         if (nonumb)
827                 i = lss1;
828         if (i < VERT) 
829                 i = VERT;
830         lss1 = lss;
831         lss = i;
832 }
833
834
835 void casess(void)
836 {
837         int i;
838
839         if(TROFF) {
840                 noscale++;
841                 skip();
842                 if(i = atoi0()) {
843                         spacesz = i & 0177;
844                         zapwcache(0);
845                         sps = width(' ' | chbits);
846                 }
847                 noscale = 0;
848         }
849 }
850
851
852 Tchar t_xlss(void)
853 {
854         /* stores \x'...' into two successive Tchars.
855         /* the first contains HX, the second the value,
856         /* encoded as a vertical motion.
857         /* decoding is done in n2.c by pchar().
858         */
859         int i;
860
861         getch();
862         dfact = lss;
863         i = quant(atoi0(), VERT);
864         dfact = 1;
865         getch();
866         if (i >= 0)
867                 *pbp++ = MOT | VMOT | i;
868         else
869                 *pbp++ = MOT | VMOT | NMOT | -i;
870         return(HX);
871 }
872
873 Uchar *unpair(int i)
874 {
875         static Uchar name[3];
876
877         name[0] = i & SHORTMASK;
878         name[1] = (i >> SHORT) & SHORTMASK;
879         name[2] = 0;
880         return name;
881 }