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