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