1 #ifndef lint
2 static char sccsid[] = "@(#)t6.c 2.2 (CWI) 87/07/10";
3 #endif lint
4 /*
5 * t6.c
6 *
7 * width functions, sizes and fonts
8 */
9
10 #include "tdef.h"
11 #include "dev.h"
12 #include <sgtty.h>
13 #include <ctype.h>
14 #include "ext.h"
15
16 /* fitab[f][c] is 0 if c is not on font f
17 /* if it's non-zero, c is in fontab[f] at position
18 /* fitab[f][c].
19 */
20 extern struct Font *fontbase[NFONT+1];
21 extern char *codetab[NFONT+1];
22 extern int nchtab;
23
24 int fontlab[MAXFONTS+1];
25 short *pstab;
26 int cstab[MAXFONTS+1];
27 int ccstab[MAXFONTS+1];
28 int bdtab[MAXFONTS+1];
29 int sbold = 0;
30
width(j)31 width(j)
32 register tchar j;
33 {
34 register i, k;
35
36 if (j & (ZBIT|MOT)) {
37 if (iszbit(j))
38 return(0);
39 if (isvmot(j))
40 return(0);
41 k = absmot(j);
42 if (isnmot(j))
43 k = -k;
44 return(k);
45 }
46 i = cbits(j);
47 if (i < ' ') {
48 if (i == '\b')
49 return(-widthp);
50 if (i == PRESC)
51 i = eschar;
52 else if (iscontrol(i))
53 return(0);
54 }
55 if (i==ohc)
56 return(0);
57 i = trtab[i];
58 if (i < 32)
59 return(0);
60 if (sfbits(j) == oldbits) {
61 xfont = pfont;
62 xpts = ppts;
63 } else
64 xbits(j, 0);
65 if (widcache[i-32].fontpts == (xfont<<8) + xpts && !setwdf)
66 k = widcache[i-32].width;
67 else {
68 k = getcw(i-32);
69 if (bd)
70 k += (bd - 1) * HOR;
71 if (cs)
72 k = cs;
73 }
74 widthp = k;
75 return(k);
76 }
77
78 /*
79 * clear width cache-- s means just space
80 */
zapwcache(s)81 zapwcache(s)
82 {
83 register i;
84
85 if (s) {
86 widcache[0].fontpts = 0;
87 return;
88 }
89 for (i=0; i<NWIDCACHE; i++)
90 widcache[i].fontpts = 0;
91 }
92
getcw(i)93 getcw(i)
94 register int i;
95 {
96 register int k;
97 register char *p;
98 register int x, j;
99 int nocache = 0;
100 int savxfont = 0, savsbold = 0, savulfont = 0;
101
102 /*
103 * Here comes first part of bug fix
104 */
105
106 if( xfont > nfonts) { /* font is not mounted */
107 savxfont = xfont;
108 if( xfont == sbold) {
109 savsbold = sbold;
110 sbold = 0;
111 }
112 if( xfont == ulfont) {
113 savulfont = ulfont;
114 ulfont = 0;
115 }
116 xfont = 0;
117 setfp(0, fontlab[savxfont], 0);
118 bdtab[0] = bdtab[savxfont]; /* Save */
119 cstab[0] = cstab[savxfont]; /* as */
120 ccstab[0] = ccstab[savxfont]; /* well */
121 }
122 /* End */
123
124
125 bd = 0;
126 if (i >= nchtab + 128-32) {
127 j = abscw(i + 32 - (nchtab+128));
128 goto g0;
129 }
130 if (i == 0) { /* a blank */
131 k = (fontab[xfont][0] * spacesz + 6) / 12;
132 /* this nonsense because .ss cmd uses 1/36 em as its units */
133 /* and default is 12 */
134 goto g1;
135 }
136 if ((j = fitab[xfont][i] & BYTEMASK) == 0) { /* it's not on current font */
137 /* search through search list of xfont
138 /* to see what font it ought to be on.
139 /* searches S, then remaining fonts in wraparound order.
140 */
141 nocache = 1;
142 if (smnt) {
143 int ii, jj;
144 for (ii=smnt, jj=0; jj < nfonts; jj++, ii=ii % nfonts + 1) {
145 j = fitab[ii][i] & BYTEMASK;
146 if (j != 0) {
147 p = fontab[ii];
148 k = *(p + j);
149 if (xfont == sbold)
150 bd = bdtab[ii];
151 if (setwdf)
152 numtab[CT].val |= kerntab[ii][j];
153 goto g1;
154 }
155 }
156 }
157 k = fontab[xfont][0]; /* leave a space-size space */
158 goto g1;
159 }
160 g0:
161 p = fontab[xfont];
162 if (setwdf)
163 numtab[CT].val |= kerntab[xfont][j];
164 k = *(p + j);
165 g1:
166 if (!bd)
167 bd = bdtab[xfont];
168 if (cs = cstab[xfont]) {
169 nocache = 1;
170 if (ccs = ccstab[xfont])
171 x = ccs;
172 else
173 x = xpts;
174 cs = (cs * EMPTS(x)) / 36;
175 }
176 k = ((k&BYTEMASK) * xpts + (Unitwidth / 2)) / Unitwidth;
177 /*
178 * undo the fontswap
179 */
180 if(savxfont) {
181 xfont = savxfont;
182 if(savsbold)
183 sbold = savsbold;
184 if(savulfont)
185 ulfont = savulfont;
186 /*
187 * H'm, I guess we should not put
188 * this width in the cache
189 */
190 nocache = 1;
191 }
192 if (nocache|bd)
193 widcache[i].fontpts = 0;
194 else {
195 widcache[i].fontpts = (xfont<<8) + xpts;
196 widcache[i].width = k;
197 }
198 return(k);
199 /* Unitwidth is Units/Point, where
200 /* Units is the fundamental digitization
201 /* of the character set widths, and
202 /* Point is the number of goobies in a point
203 /* e.g., for cat, Units=36, Point=6, so Unitwidth=36/6=6
204 /* In effect, it's the size at which the widths
205 /* translate directly into units.
206 */
207 }
208
abscw(n)209 abscw(n) /* return index of abs char n in fontab[], etc. */
210 { register int i, ncf;
211
212 ncf = fontbase[xfont]->nwfont & BYTEMASK;
213 for (i = 0; i < ncf; i++)
214 if (codetab[xfont][i] == n)
215 return i;
216 return 0;
217 }
218
xbits(i,bitf)219 xbits(i, bitf)
220 register tchar i;
221 {
222 register k;
223
224 xfont = fbits(i);
225 k = sbits(i);
226 if (k) {
227 xpts = pstab[--k];
228 oldbits = sfbits(i);
229 pfont = xfont;
230 ppts = xpts;
231 return;
232 }
233 switch (bitf) {
234 case 0:
235 xfont = font;
236 xpts = pts;
237 break;
238 case 1:
239 xfont = pfont;
240 xpts = ppts;
241 break;
242 case 2:
243 xfont = mfont;
244 xpts = mpts;
245 }
246 }
247
248
setch()249 tchar setch()
250 {
251 register j;
252 char temp[10];
253 register char *s;
254 extern char *chname;
255 extern short *chtab;
256 extern int nchtab;
257
258 s = temp;
259 if ((*s++ = getach()) == 0 || (*s++ = getach()) == 0)
260 return(0);
261 *s = '\0';
262 for (j = 0; j < nchtab; j++)
263 if (strcmp(&chname[chtab[j]], temp) == 0)
264 return(j + 128 | chbits);
265 return(0);
266 }
267
setabs()268 tchar setabs() /* set absolute char from \C'...' */
269 {
270 int i, n, nf;
271 extern int nchtab;
272
273 getch();
274 n = 0;
275 n = inumb(&n);
276 getch();
277 if (nonumb)
278 return 0;
279 return n + nchtab + 128;
280 }
281 /*
282 * I (jaap) expand fontlab to the maximum of fonts troff can
283 * handle. The maximum number i, due to the two chars
284 * fontname limit, is 99.
285 * If we don't use the (named) font in one of the
286 * standard position, we install the name in the next
287 * free slot. Whenever we need info about the font, we
288 * read in the data at position zero, and secretly use
289 * the data (actually only necessary for the width
290 * and ligature info). The ptfont() (t10.c) routine will tell
291 * the device filter to put the font always at position
292 * zero if xfont > physfonts, so no need to change these filters.
293 * Yes, this is a bit kludgy.
294 *
295 * This gives the new specs of findft:
296 *
297 * find the font name i, where i also can be a number.
298 *
299 * Installs the font(name) i when not present
300 *
301 * returns -1 on error
302 */
303
findft(i)304 findft(i)
305 register int i;
306 {
307 register k;
308 register char *p;
309 extern char * unpair();
310
311 p = unpair(i);
312
313 /* first look for numbers */
314 if( isdigit(p[0]) && (p[1] == 0 || isdigit(p[1]))) {
315 k = p[0] - '0';
316 if( p[1] > 0 && isdigit(p[1]))
317 k = 10 * k + ( p[1] - '0');
318
319 /*
320 fprintf(ptid, "x xxx it's a number: %d\n", k);
321 */
322 if( k > 0 && k <= nfonts && fontbase[k]->specfont == 0 ) {
323 /*
324 fprintf(ptid, "x xxx it's a mounted font\n");
325 */
326 return(k); /* mounted font */
327 }
328 if( fontlab[k] && k <= MAXFONTS) { /* translate */
329 /*
330 fprintf(ptid, "x xxx font exists\n");
331 */
332 return(k); /*number to a name */
333 }
334 else {
335 fprintf(stderr, "troff: no font at position %d\n", k);
336 return(-1); /* wild number */
337 }
338 }
339
340 /*
341 * Now we look for font names
342 */
343 for (k = 1; fontlab[k] != i; k++) {
344 if (k > MAXFONTS +1) /* the +1 is for the ``font cache'' */
345 return(-1); /* running out of fontlab space */
346 if ( !fontlab[k] ) { /* passed all existing names */
347 if (k <= NFONT) {
348 if(setfp(k, i, 0) < 0)
349 return(-1);
350 nfonts = k;
351 } else
352 if(setfp(0, i, 0) < 0)
353 return(-1);
354 /*
355 fprintf(ptid, "x xxx installed %s on %d\n", name ,k);
356 */
357 /* now install the name */
358 fontlab[k] = i;
359 /*
360 * and remember accociated with
361 * this font, ligature info etc.
362 */
363 return(k);
364 }
365 }
366 return(k); /* was one of the existing names */
367 }
368
369
caseps()370 caseps()
371 {
372 register i;
373
374 if (skip())
375 i = apts1;
376 else {
377 noscale++;
378 i = inumb(&apts); /* this is a disaster for fractional point sizes */
379 noscale = 0;
380 if (nonumb)
381 return;
382 }
383 casps1(i);
384 }
385
386
casps1(i)387 casps1(i)
388 register int i;
389 {
390
391 /*
392 * in olden times, it used to ignore changes to 0 or negative.
393 * this is meant to allow the requested size to be anything,
394 * in particular so eqn can generate lots of \s-3's and still
395 * get back by matching \s+3's.
396
397 if (i <= 0)
398 return;
399 */
400 apts1 = apts;
401 apts = i;
402 pts1 = pts;
403 pts = findps(i);
404 mchbits();
405 }
406
407
findps(i)408 findps(i)
409 register int i;
410 {
411 register j, k;
412
413 for (j=k=0 ; pstab[j] != 0 ; j++)
414 if (abs(pstab[j]-i) < abs(pstab[k]-i))
415 k = j;
416
417 return(pstab[k]);
418 }
419
420
mchbits()421 mchbits()
422 {
423 register i, j, k;
424
425 i = pts;
426 for (j = 0; i > (k = pstab[j]); j++)
427 if (!k) {
428 k = pstab[--j];
429 break;
430 }
431 chbits = 0;
432 setsbits(chbits, ++j);
433 setfbits(chbits, font);
434 sps = width(' ' | chbits);
435 zapwcache(1);
436 }
437
setps()438 setps()
439 {
440 register int i, j;
441
442 i = cbits(getch());
443 if (isdigit(i)) { /* \sd or \sdd */
444 i -= '0';
445 if (i == 0) /* \s0 */
446 j = apts1;
447 else if (i <= 3 && isdigit(j = cbits(ch=getch()))) { /* \sdd */
448 j = 10 * i + j - '0';
449 ch = 0;
450 } else /* \sd */
451 j = i;
452 } else if (i == '(') { /* \s(dd */
453 j = cbits(getch()) - '0';
454 j = 10 * j + cbits(getch()) - '0';
455 if (j == 0) /* \s(00 */
456 j = apts1;
457 } else if (i == '+' || i == '-') { /* \s+, \s- */
458 j = cbits(getch());
459 if (isdigit(j)) { /* \s+d, \s-d */
460 j -= '0';
461 } else if (j == '(') { /* \s+(dd, \s-(dd */
462 j = cbits(getch()) - '0';
463 j = 10 * j + cbits(getch()) - '0';
464 }
465 if (i == '-')
466 j = -j;
467 j += apts;
468 }
469 casps1(j);
470 }
471
472
setht()473 tchar setht() /* set character height from \H'...' */
474 {
475 int n;
476 tchar c;
477
478 getch();
479 n = inumb(&apts);
480 getch();
481 if (n == 0 || nonumb)
482 n = apts; /* does this work? */
483 c = CHARHT;
484 c |= ZBIT;
485 setsbits(c, n);
486 return(c);
487 }
488
setslant()489 tchar setslant() /* set slant from \S'...' */
490 {
491 int n;
492 tchar c;
493
494 getch();
495 n = 0;
496 n = inumb(&n);
497 getch();
498 if (nonumb)
499 n = 0;
500 c = SLANT;
501 c |= ZBIT;
502 setsfbits(c, n+180);
503 return(c);
504 }
505
506
casest()507 casest()
508 {
509 register i, j;
510 register char last;
511
512 skip();
513 i = getrq();
514 if (!i || i == 'P') {
515 stip = stip1;
516 return;
517 }
518 if (i == '0')
519 goto sterr;
520
521 last = cbits(i) >> BYTE;
522 if ((j = (i & BYTEMASK) - '0') >= 0 && j <= 9) {/* digit - see if two */
523 if (last)
524 if ((last -= '0') < 0 || last > 9)
525 goto sterr;
526 if (j > nstips)
527 goto sterr;
528 } else { /* stipple name */
529 for (j = 0; stiplab[j] != i; j++)
530 if (j > nstips)
531 goto sterr;
532 }
533 stip1 = stip;
534 stip = j;
535 return;
536 sterr:
537 fprintf(stderr, "troff: Can't find stipple %c%c\n", i & BYTEMASK, last);
538 }
539
540
caseft()541 caseft()
542 {
543 skip();
544 setfont(1);
545 }
546
547
setfont(a)548 setfont(a)
549 int a;
550 {
551 register i, j;
552
553 if (a)
554 i = getrq();
555 else
556 i = getsn();
557 if (!i || i == 'P') {
558 j = font1;
559 goto s0;
560 }
561 if (i == 'S' || i == '0')
562 return;
563 if ((j = findft(i)) == -1)
564 #ifdef notdef
565 /* findft does the setfp if possible */
566 if ((j = setfp(0, i, 0)) == -1) /* try to put it in position 0 */
567 #endif
568 return;
569 s0:
570 font1 = font;
571 font = j;
572 mchbits();
573 }
574
575
setwd()576 setwd()
577 {
578 register base, wid;
579 register tchar i;
580 int delim, emsz, k;
581 int savhp, savapts, savapts1, savfont, savfont1, savpts, savpts1;
582
583 base = numtab[ST].val = numtab[ST].val = wid = numtab[CT].val = 0;
584 if (ismot(i = getch()))
585 return;
586 delim = cbits(i);
587 savhp = numtab[HP].val;
588 numtab[HP].val = 0;
589 savapts = apts;
590 savapts1 = apts1;
591 savfont = font;
592 savfont1 = font1;
593 savpts = pts;
594 savpts1 = pts1;
595 setwdf++;
596 while (cbits(i = getch()) != delim && !nlflg) {
597 k = width(i);
598 wid += k;
599 numtab[HP].val += k;
600 if (!ismot(i)) {
601 emsz = POINT * xpts;
602 } else if (isvmot(i)) {
603 k = absmot(i);
604 if (isnmot(i))
605 k = -k;
606 base -= k;
607 emsz = 0;
608 } else
609 continue;
610 if (base < numtab[SB].val)
611 numtab[SB].val = base;
612 if ((k = base + emsz) > numtab[ST].val)
613 numtab[ST].val = k;
614 }
615 setn1(wid, 0, (tchar) 0);
616 numtab[HP].val = savhp;
617 apts = savapts;
618 apts1 = savapts1;
619 font = savfont;
620 font1 = savfont1;
621 pts = savpts;
622 pts1 = savpts1;
623 mchbits();
624 setwdf = 0;
625 }
626
627
vmot()628 tchar vmot()
629 {
630 dfact = lss;
631 vflag++;
632 return(mot());
633 }
634
635
hmot()636 tchar hmot()
637 {
638 dfact = EM;
639 return(mot());
640 }
641
642
mot()643 tchar mot()
644 {
645 register int j, n;
646 register tchar i;
647
648 j = HOR;
649 getch(); /*eat delim*/
650 if (n = atoi()) {
651 if (vflag)
652 j = VERT;
653 i = makem(quant(n, j));
654 } else
655 i = 0;
656 getch();
657 vflag = 0;
658 dfact = 1;
659 return(i);
660 }
661
662
sethl(k)663 tchar sethl(k)
664 int k;
665 {
666 register j;
667 tchar i;
668
669 j = EM / 2;
670 if (k == 'u')
671 j = -j;
672 else if (k == 'r')
673 j = -2 * j;
674 vflag++;
675 i = makem(j);
676 vflag = 0;
677 return(i);
678 }
679
680
makem(i)681 tchar makem(i)
682 register int i;
683 {
684 register tchar j;
685
686 if ((j = i) < 0)
687 j = -j;
688 j |= MOT;
689 if (i < 0)
690 j |= NMOT;
691 if (vflag)
692 j |= VMOT;
693 return(j);
694 }
695
696
getlg(i)697 tchar getlg(i)
698 tchar i;
699 {
700 tchar j, k;
701 register int lf;
702
703 /* remember to map the font */
704 if ((lf = fontbase[fbits(i) > nfonts ? 0 : fbits(i)]->ligfont) == 0) {
705 /* font lacks ligatures */
706 return(i);
707 }
708 j = getch0();
709 if (cbits(j) == 'i' && (lf & LFI))
710 j = LIG_FI;
711 else if (cbits(j) == 'l' && (lf & LFL))
712 j = LIG_FL;
713 else if (cbits(j) == 'f' && (lf & LFF)) {
714 if ((lf & (LFFI|LFFL)) && lg != 2) {
715 k = getch0();
716 if (cbits(k)=='i' && (lf&LFFI))
717 j = LIG_FFI;
718 else if (cbits(k)=='l' && (lf&LFFL))
719 j = LIG_FFL;
720 else {
721 *pbp++ = k;
722 j = LIG_FF;
723 }
724 } else
725 j = LIG_FF;
726 } else {
727 *pbp++ = j;
728 j = i;
729 }
730 return(i & SFMASK | j);
731 }
732
733
caselg()734 caselg()
735 {
736
737 lg = 1;
738 if (skip())
739 return;
740 lg = atoi();
741 }
742
743
casefp()744 casefp()
745 {
746 register int i, j;
747 register char *s;
748
749 skip();
750 /* allow .fp for fonts >nfonts, <NFONTS? */
751 if ((i = cbits(getch()) - '0') <= 0 || i > nfonts)
752 errprint("fp: bad font position %d", i);
753 else if (skip() || !(j = getrq()))
754 errprint("fp: no font name");
755 else if (skip() || !getname())
756 setfp(i, j, 0);
757 else /* 3rd argument = filename */
758 setfp(i, j, nextf);
759 }
760
setfp(pos,f,truename)761 setfp(pos, f, truename) /* mount font f at position pos[0...NFONTS] */
762 register pos;
763 int f;
764 char *truename;
765 {
766 register k;
767 register struct Font *ft;
768 int n;
769 char longname[NS], shortname[20];
770 extern int nchtab;
771 extern struct dev dev;
772
773 if (fontlab[pos] == f) /* if f already mounted at pos, */
774 return(pos); /* don't remount it */
775 zapwcache(0);
776 if (truename)
777 strcpy(shortname, truename);
778 else {
779 shortname[0] = f & BYTEMASK;
780 shortname[1] = f >> BYTE;
781 shortname[2] = '\0';
782 }
783 sprintf(longname, "%s/dev%s/%s.out", fontfile, devname, shortname);
784 if ((k = open(longname, 0)) < 0) {
785 errprint("Can't open %s", longname);
786 return(-1);
787 }
788 if ((ft = fontbase[pos]) == 0) {
789 ft = fontbase[pos] = (struct Font *) malloc(EXTRAFONT);
790 ft->nwfont = MAXCHARS;
791 fontab[pos] = (char *)(ft + 1);
792 }
793 n = ft->nwfont;
794 read(k, (char *) ft, 3*n + nchtab + 128 - 32 + sizeof(struct Font));
795 close(k);
796
797 k = ft->nwfont;
798 kerntab[pos] = (char *) fontab[pos] + k;
799 codetab[pos] = (char *) fontab[pos] + 2 * k;
800 /* have to reset the fitab pointer because the width may be different */
801 fitab[pos] = (char *) fontab[pos] + 3 * k;
802 ft->nwfont = n; /* so can load a larger one again later */
803 if (k > n) {
804 errprint("Font %s too big for position %d", shortname, pos);
805 return(-1);
806 }
807 if (pos == smnt) {
808 smnt = 0;
809 sbold = 0;
810 }
811 if ((fontlab[pos] = f) == 'S')
812 smnt = pos;
813 bdtab[pos] = cstab[pos] = ccstab[pos] = 0;
814 /* if there is a directory, no place to store its name. */
815 /* if position isn't zero, no place to store its value. */
816 /* only time a FONTPOS is pushed back is if it's a */
817 /* standard font on position 0 (i.e., mounted implicitly. */
818 /* there's a bug here: if there are several input lines */
819 /* that look like .ft XX in short successtion, the output */
820 /* will all be in the last one because the "x font ..." */
821 /* comes out too soon. pushing back FONTPOS doesn't work */
822 /* with .ft commands because input is flushed after .xx cmds */
823
824 /*
825 * Trying to fix this FONTPOS problem: See findft()
826 */
827 if ( pos > 0 && pos <= physfonts)
828 ptfpcmd(pos, shortname);
829 return(pos);
830 }
831
832
casecs()833 casecs()
834 {
835 register i, j;
836
837 noscale++;
838 skip();
839 if (!(i = getrq()) || (i = findft(i)) < 0)
840 goto rtn;
841 skip();
842 cstab[i] = atoi();
843 skip();
844 j = atoi();
845 if (nonumb)
846 ccstab[i] = 0;
847 else
848 ccstab[i] = findps(j);
849 rtn:
850 zapwcache(0);
851 noscale = 0;
852 }
853
854
casebd()855 casebd()
856 {
857 register i, j, k;
858
859 zapwcache(0);
860 k = 0;
861 bd0:
862 if (skip() || !(i = getrq()) || (j = findft(i)) == -1) {
863 if (k)
864 goto bd1;
865 else
866 return;
867 }
868 if (j == smnt) {
869 k = smnt;
870 goto bd0;
871 }
872 if (k) {
873 sbold = j;
874 j = k;
875 }
876 bd1:
877 skip();
878 noscale++;
879 bdtab[j] = atoi();
880 noscale = 0;
881 }
882
883
casevs()884 casevs()
885 {
886 register i;
887
888 skip();
889 vflag++;
890 dfact = INCH; /* default scaling is points! */
891 dfactd = 72;
892 res = VERT;
893 i = inumb(&lss);
894 if (nonumb)
895 i = lss1;
896 /* if(i < VERT)i = VERT; */
897 if (i < VERT)
898 i = 0;
899 lss1 = lss;
900 lss = i;
901 }
902
903
casess()904 casess()
905 {
906 register i;
907
908 noscale++;
909 skip();
910 if (i = atoi()) {
911 spacesz = i & 0177;
912 zapwcache(0);
913 sps = width(' ' | chbits);
914 }
915 noscale = 0;
916 }
917
918
xlss()919 tchar xlss()
920 {
921 /* stores \x'...' into
922 /* two successive tchars.
923 /* the first contains HX, the second the value,
924 /* encoded as a vertical motion.
925 /* decoding is done in n2.c by pchar().
926 */
927 int i;
928
929 getch();
930 dfact = lss;
931 i = quant(atoi(), VERT);
932 dfact = 1;
933 getch();
934 if (i >= 0)
935 *pbp++ = MOT | VMOT | i;
936 else
937 *pbp++ = MOT | VMOT | NMOT | -i;
938 return(HX);
939 }
940
941 char *
unpair(i)942 unpair(i)
943 register int i;
944 { static char name[3];
945
946 name[0] = i & BYTEMASK;
947 name[1] = i >> BYTE;
948 name[2] = 0;
949 return (name);
950 }
951