xref: /plan9/sys/src/cmd/proof/font.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
33e12c5d1SDavid du Colombier #include <libg.h>
43e12c5d1SDavid du Colombier #include <bio.h>
53e12c5d1SDavid du Colombier #include "proof.h"
63e12c5d1SDavid du Colombier 
73e12c5d1SDavid du Colombier char	fname[NFONT][20];		/* font names */
83e12c5d1SDavid du Colombier Font	*fonttab[NFONT][NSIZE];	/* pointers to fonts */
93e12c5d1SDavid du Colombier int	fmap[NFONT];		/* what map to use with this font */
103e12c5d1SDavid du Colombier 
113e12c5d1SDavid du Colombier static void	bufchar(Point, Subfont *, uchar *);
123e12c5d1SDavid du Colombier static void	loadfont(int, int);
133e12c5d1SDavid du Colombier static void	fontlookup(int, char *);
14*219b2ee8SDavid du Colombier static void	buildxheight(Biobuf*);
153e12c5d1SDavid du Colombier static void	buildmap(Biobuf*);
163e12c5d1SDavid du Colombier static void	buildtroff(char *);
173e12c5d1SDavid du Colombier static void	addmap(int, char *, int);
18*219b2ee8SDavid du Colombier static char	*map(Rune*, int);
193e12c5d1SDavid du Colombier static void	scanstr(char *, char *, char **);
203e12c5d1SDavid du Colombier 
213e12c5d1SDavid du Colombier int	specfont;	/* somehow, number of special font */
223e12c5d1SDavid du Colombier 
23*219b2ee8SDavid du Colombier #define	NMAP	5
24*219b2ee8SDavid du Colombier #define	QUICK	2048	/* char values less than this are quick to look up */
25*219b2ee8SDavid du Colombier #define	eq(s,t)	strcmp((char *) s, (char *) t) == 0
26*219b2ee8SDavid du Colombier 
27*219b2ee8SDavid du Colombier int	curmap	= -1;	/* what map are we working on */
28*219b2ee8SDavid du Colombier 
29*219b2ee8SDavid du Colombier typedef struct Link Link;
30*219b2ee8SDavid du Colombier struct Link	/* link names together */
313e12c5d1SDavid du Colombier {
32*219b2ee8SDavid du Colombier 	uchar	*name;
33*219b2ee8SDavid du Colombier 	int	val;
34*219b2ee8SDavid du Colombier 	Link	*next;
35*219b2ee8SDavid du Colombier };
36*219b2ee8SDavid du Colombier 
37*219b2ee8SDavid du Colombier typedef struct Map Map;
38*219b2ee8SDavid du Colombier struct Map	/* holds a mapping from uchar name to index */
39*219b2ee8SDavid du Colombier {
40*219b2ee8SDavid du Colombier 	double	xheight;
41*219b2ee8SDavid du Colombier 	Rune	quick[QUICK];	/* low values get special treatment */
42*219b2ee8SDavid du Colombier 	Link	*slow;	/* other stuff goes into a link list */
43*219b2ee8SDavid du Colombier };
44*219b2ee8SDavid du Colombier 
45*219b2ee8SDavid du Colombier Map	charmap[5];
46*219b2ee8SDavid du Colombier 
47*219b2ee8SDavid du Colombier typedef struct Fontmap Fontmap;
48*219b2ee8SDavid du Colombier struct Fontmap	/* mapping from troff name to filename */
49*219b2ee8SDavid du Colombier {
50*219b2ee8SDavid du Colombier 	char	*troffname;
51*219b2ee8SDavid du Colombier 	char	*prefix;
52*219b2ee8SDavid du Colombier 	int	map;		/* which charmap to use for this font */
53*219b2ee8SDavid du Colombier 	char	*fallback;	/* font to look in if can't find char here */
54*219b2ee8SDavid du Colombier };
55*219b2ee8SDavid du Colombier 
56*219b2ee8SDavid du Colombier Fontmap	fontmap[100];
57*219b2ee8SDavid du Colombier int	pos2fontmap[NFONT];	/* indexed by troff font position, gives Fontmap */
58*219b2ee8SDavid du Colombier int	nfontmap	= 0;	/* how many are there */
59*219b2ee8SDavid du Colombier 
60*219b2ee8SDavid du Colombier 
61*219b2ee8SDavid du Colombier void
62*219b2ee8SDavid du Colombier dochar(Rune r[])
63*219b2ee8SDavid du Colombier {
64*219b2ee8SDavid du Colombier 	char *s, *fb;
653e12c5d1SDavid du Colombier 	Font *f;
663e12c5d1SDavid du Colombier 	Point p;
67*219b2ee8SDavid du Colombier 	int fontno, fm, i;
68*219b2ee8SDavid du Colombier 	char buf[10];
693e12c5d1SDavid du Colombier 
703e12c5d1SDavid du Colombier 	fontno = curfont;
71*219b2ee8SDavid du Colombier 	if((s = map(r, curfont)) == 0){		/* not on current font */
72*219b2ee8SDavid du Colombier 		if ((s = map(r, specfont)) != 0)	/* on special font */
733e12c5d1SDavid du Colombier 			fontno = specfont;
74*219b2ee8SDavid du Colombier 		else{
75*219b2ee8SDavid du Colombier 			/* look for fallback */
76*219b2ee8SDavid du Colombier 			fm = pos2fontmap[curfont];
77*219b2ee8SDavid du Colombier 			fb = fontmap[fm].fallback;
78*219b2ee8SDavid du Colombier 			if(fb){
79*219b2ee8SDavid du Colombier 				/* see if fallback is mounted */
80*219b2ee8SDavid du Colombier 				for(i = 0; i < NFONT; i++){
81*219b2ee8SDavid du Colombier 					if(eq(fb, fontmap[pos2fontmap[i]].troffname)){
82*219b2ee8SDavid du Colombier 						s = map(r, i);
83*219b2ee8SDavid du Colombier 						if(s){
84*219b2ee8SDavid du Colombier 							fontno = i;
85*219b2ee8SDavid du Colombier 							goto found;
86*219b2ee8SDavid du Colombier 						}
87*219b2ee8SDavid du Colombier 					}
88*219b2ee8SDavid du Colombier 				}
89*219b2ee8SDavid du Colombier 			}
903e12c5d1SDavid du Colombier 			/* no such char; use name itself on defont */
91*219b2ee8SDavid du Colombier 			/* this is not a general solution */
923e12c5d1SDavid du Colombier 			p.x = hpos/DIV + xyoffset.x + offset.x;
933e12c5d1SDavid du Colombier 			p.y = vpos/DIV + xyoffset.y + offset.y;
943e12c5d1SDavid du Colombier 			p.y -= font->ascent;
95*219b2ee8SDavid du Colombier 			sprint(buf, "%S", r);
96*219b2ee8SDavid du Colombier 			string(&screen, p, font, buf, S|D);
973e12c5d1SDavid du Colombier 			return;
983e12c5d1SDavid du Colombier 		}
993e12c5d1SDavid du Colombier 	}
100*219b2ee8SDavid du Colombier     found:
1013e12c5d1SDavid du Colombier 	p.x = hpos/DIV + xyoffset.x + offset.x;
1023e12c5d1SDavid du Colombier 	p.y = vpos/DIV + xyoffset.y + offset.y;
1033e12c5d1SDavid du Colombier 	while ((f = fonttab[fontno][cursize]) == 0)
1043e12c5d1SDavid du Colombier 		loadfont(fontno, cursize);
1053e12c5d1SDavid du Colombier 	p.y -= f->ascent;
106*219b2ee8SDavid du Colombier 	dprint(2, "putting %S at %d,%d font %d, size %d\n", r, p.x, p.y, fontno, cursize);
107*219b2ee8SDavid du Colombier 	string(&screen, p, f, s, S|D);
1083e12c5d1SDavid du Colombier }
1093e12c5d1SDavid du Colombier 
1103e12c5d1SDavid du Colombier 
1113e12c5d1SDavid du Colombier static void
1123e12c5d1SDavid du Colombier loadfont(int n, int s)
1133e12c5d1SDavid du Colombier {
1143e12c5d1SDavid du Colombier 	char file[100];
1153e12c5d1SDavid du Colombier 	int i, t, fd, deep;
1163e12c5d1SDavid du Colombier 	static char *try[3] = {"", "times/R.", "pelm/"};
1173e12c5d1SDavid du Colombier 	Subfont *f;
1183e12c5d1SDavid du Colombier 	Font *ff;
1193e12c5d1SDavid du Colombier 
1203e12c5d1SDavid du Colombier 	try[0] = fname[n];
1213e12c5d1SDavid du Colombier 	for (t = 0; t < 3; t++){
122*219b2ee8SDavid du Colombier 		i = s * mag * charmap[fmap[n]].xheight/0.72;	/* a pixel is 0.72 points */
1233e12c5d1SDavid du Colombier 		if (i < MINSIZE)
1243e12c5d1SDavid du Colombier 			i = MINSIZE;
1253e12c5d1SDavid du Colombier 		dprint(2, "size %d, i %d, mag %g\n", s, i, mag);
126*219b2ee8SDavid du Colombier 		for(; i >= MINSIZE; i--){
127*219b2ee8SDavid du Colombier 			/* if .font file exists, take that */
128*219b2ee8SDavid du Colombier 			sprint(file, "%s/%s%d.font", libfont, try[t], i);
129*219b2ee8SDavid du Colombier 			ff = rdfontfile(file, screen.ldepth);
130*219b2ee8SDavid du Colombier 			if(ff != 0){
131*219b2ee8SDavid du Colombier 				fonttab[n][s] = ff;
132*219b2ee8SDavid du Colombier 				dprint(2, "using %s for font %d %d\n", file, n, s);
133*219b2ee8SDavid du Colombier 				return;
134*219b2ee8SDavid du Colombier 			}
135*219b2ee8SDavid du Colombier 			/* else look for a subfont file */
1363e12c5d1SDavid du Colombier 			for (deep = screen.ldepth; deep >= 0; deep--){
1373e12c5d1SDavid du Colombier 				sprint(file, "%s/%s%d.%d", libfont, try[t], i, 1 /*deep*/);
1383e12c5d1SDavid du Colombier 				dprint(2, "trying %s for %d\n", file, i);
1393e12c5d1SDavid du Colombier 				if ((fd = open(file, 0)) >= 0){
1403e12c5d1SDavid du Colombier 					f = rdsubfontfile(fd, 0);
1413e12c5d1SDavid du Colombier 					if (f == 0) {
1423e12c5d1SDavid du Colombier 						fprint(2, "can't rdsubfontfile %s: %r\n", file);
1433e12c5d1SDavid du Colombier 						exits("rdsubfont");
1443e12c5d1SDavid du Colombier 					}
1453e12c5d1SDavid du Colombier 					close(fd);
1463e12c5d1SDavid du Colombier 					ff = mkfont(f, 0);
1473e12c5d1SDavid du Colombier 					if(ff == 0){
1483e12c5d1SDavid du Colombier 						fprint(2, "can't mkfont %s: %r\n", file);
1493e12c5d1SDavid du Colombier 						exits("rdsubfont");
1503e12c5d1SDavid du Colombier 					}
1513e12c5d1SDavid du Colombier 					fonttab[n][s] = ff;
1523e12c5d1SDavid du Colombier 					dprint(2, "using %s for font %d %d\n", file, n, s);
1533e12c5d1SDavid du Colombier 					return;
1543e12c5d1SDavid du Colombier 				}
1553e12c5d1SDavid du Colombier 			}
1563e12c5d1SDavid du Colombier 		}
157*219b2ee8SDavid du Colombier 	}
1583e12c5d1SDavid du Colombier 	fprint(2, "can't find font %s.%d or substitute, quitting\n", fname[n], s);
1593e12c5d1SDavid du Colombier 	exits("no font");
1603e12c5d1SDavid du Colombier }
1613e12c5d1SDavid du Colombier 
1623e12c5d1SDavid du Colombier void
1633e12c5d1SDavid du Colombier loadfontname(int n, char *s)
1643e12c5d1SDavid du Colombier {
1653e12c5d1SDavid du Colombier 	int i;
1663e12c5d1SDavid du Colombier 	Font *f, *g = 0;
1673e12c5d1SDavid du Colombier 
1683e12c5d1SDavid du Colombier 	if (strcmp(s, fname[n]) == 0)
1693e12c5d1SDavid du Colombier 		return;
1703e12c5d1SDavid du Colombier 	fontlookup(n, s);
1713e12c5d1SDavid du Colombier 	for (i = 0; i < NSIZE; i++)
1723e12c5d1SDavid du Colombier 		if (f = fonttab[n][i]){
1733e12c5d1SDavid du Colombier 			if (f != g) {
1743e12c5d1SDavid du Colombier 				ffree(f);
1753e12c5d1SDavid du Colombier 				g = f;
1763e12c5d1SDavid du Colombier 			}
1773e12c5d1SDavid du Colombier 			fonttab[n][i] = 0;
1783e12c5d1SDavid du Colombier 		}
1793e12c5d1SDavid du Colombier }
1803e12c5d1SDavid du Colombier 
1813e12c5d1SDavid du Colombier void
1823e12c5d1SDavid du Colombier allfree(void)
1833e12c5d1SDavid du Colombier {
1843e12c5d1SDavid du Colombier 	int i;
1853e12c5d1SDavid du Colombier 
1863e12c5d1SDavid du Colombier 	for (i=0; i<NFONT; i++)
1873e12c5d1SDavid du Colombier 		loadfontname(i, "??");
1883e12c5d1SDavid du Colombier }
1893e12c5d1SDavid du Colombier 
1903e12c5d1SDavid du Colombier 
1913e12c5d1SDavid du Colombier void
1923e12c5d1SDavid du Colombier readmapfile(char *file)
1933e12c5d1SDavid du Colombier {
1943e12c5d1SDavid du Colombier 	Biobuf *fp;
1953e12c5d1SDavid du Colombier 	char *p, cmd[100];
1963e12c5d1SDavid du Colombier 
1973e12c5d1SDavid du Colombier 	if ((fp=Bopen(file, OREAD)) == 0){
1983e12c5d1SDavid du Colombier 		fprint(2, "proof: can't open map file %s\n", file);
1993e12c5d1SDavid du Colombier 		exits("urk");
2003e12c5d1SDavid du Colombier 	}
2013e12c5d1SDavid du Colombier 	while((p=Brdline(fp, '\n')) != 0) {
2023e12c5d1SDavid du Colombier 		p[Blinelen(fp)-1] = 0;
2033e12c5d1SDavid du Colombier 		scanstr(p, cmd, 0);
2043e12c5d1SDavid du Colombier 		if(p[0]=='\0' || eq(cmd, "#"))	/* skip comments, empty */
2053e12c5d1SDavid du Colombier 			continue;
206*219b2ee8SDavid du Colombier 		else if(eq(cmd, "xheight"))
207*219b2ee8SDavid du Colombier 			buildxheight(fp);
2083e12c5d1SDavid du Colombier 		else if(eq(cmd, "map"))
2093e12c5d1SDavid du Colombier 			buildmap(fp);
2103e12c5d1SDavid du Colombier 		else if(eq(cmd, "special"))
2113e12c5d1SDavid du Colombier 			buildtroff(p);
2123e12c5d1SDavid du Colombier 		else if(eq(cmd, "troff"))
2133e12c5d1SDavid du Colombier 			buildtroff(p);
2143e12c5d1SDavid du Colombier 		else
2153e12c5d1SDavid du Colombier 			fprint(2, "weird map line %s\n", p);
2163e12c5d1SDavid du Colombier 	}
217*219b2ee8SDavid du Colombier 	Bterm(fp);
218*219b2ee8SDavid du Colombier }
219*219b2ee8SDavid du Colombier 
220*219b2ee8SDavid du Colombier static void
221*219b2ee8SDavid du Colombier buildxheight(Biobuf *fp)	/* map goes from char name to value to print via *string() */
222*219b2ee8SDavid du Colombier {
223*219b2ee8SDavid du Colombier 	char *line;
224*219b2ee8SDavid du Colombier 
225*219b2ee8SDavid du Colombier 	line = Brdline(fp, '\n');
226*219b2ee8SDavid du Colombier 	if(line == 0){
227*219b2ee8SDavid du Colombier 		fprint(2, "proof: bad map file\n");
228*219b2ee8SDavid du Colombier 		exits("map");
229*219b2ee8SDavid du Colombier 	}
230*219b2ee8SDavid du Colombier 	charmap[curmap].xheight = atof(line);
2313e12c5d1SDavid du Colombier }
2323e12c5d1SDavid du Colombier 
2333e12c5d1SDavid du Colombier static void
2343e12c5d1SDavid du Colombier buildmap(Biobuf *fp)	/* map goes from char name to value to print via *string() */
2353e12c5d1SDavid du Colombier {
2363e12c5d1SDavid du Colombier 	uchar *p, *line, ch[100];
2373e12c5d1SDavid du Colombier 	int val;
238*219b2ee8SDavid du Colombier 	Rune r;
2393e12c5d1SDavid du Colombier 
2403e12c5d1SDavid du Colombier 	curmap++;
241*219b2ee8SDavid du Colombier 	if(curmap >= NMAP){
242*219b2ee8SDavid du Colombier 		fprint(2, "proof: out of char maps; recompile\n");
243*219b2ee8SDavid du Colombier 		exits("charmap");
244*219b2ee8SDavid du Colombier 	}
2453e12c5d1SDavid du Colombier 	while ((line = Brdline(fp, '\n'))!= 0){
2463e12c5d1SDavid du Colombier 		if (line[0] == '\n')
2473e12c5d1SDavid du Colombier 			return;
2483e12c5d1SDavid du Colombier 		line[Blinelen(fp)-1] = 0;
2493e12c5d1SDavid du Colombier 		scanstr((char *) line, (char *) ch, (char **) &p);
2503e12c5d1SDavid du Colombier 		if (ch[0] == '\0') {
2513e12c5d1SDavid du Colombier 			fprint(2, "bad map file line '%s'\n", line);
2523e12c5d1SDavid du Colombier 			continue;
2533e12c5d1SDavid du Colombier 		}
2543e12c5d1SDavid du Colombier 		val = strtol((char *) p, 0, 10);
2553e12c5d1SDavid du Colombier dprint(2, "buildmap %s (%x %x) %s %d\n", ch, ch[0], ch[1], p, val);
256*219b2ee8SDavid du Colombier 		chartorune(&r, (char*)ch);
257*219b2ee8SDavid du Colombier 		if(utflen((char*)ch)==1 && r<QUICK)
258*219b2ee8SDavid du Colombier 			charmap[curmap].quick[r] = val;
259*219b2ee8SDavid du Colombier 		else
2603e12c5d1SDavid du Colombier 			addmap(curmap, strdup((char *) ch), val);	/* put somewhere else */
2613e12c5d1SDavid du Colombier 	}
2623e12c5d1SDavid du Colombier }
2633e12c5d1SDavid du Colombier 
2643e12c5d1SDavid du Colombier static void
2653e12c5d1SDavid du Colombier addmap(int n, char *s, int val)	/* stick a new link on */
2663e12c5d1SDavid du Colombier {
2673e12c5d1SDavid du Colombier 	Link *p = (Link *) malloc(sizeof(Link));
268*219b2ee8SDavid du Colombier 	Link *prev = charmap[n].slow;
2693e12c5d1SDavid du Colombier 
2703e12c5d1SDavid du Colombier 	if(p == 0)
2713e12c5d1SDavid du Colombier 		exits("out of memory in addmap");
2723e12c5d1SDavid du Colombier 	p->name = (uchar *) s;
2733e12c5d1SDavid du Colombier 	p->val = val;
274*219b2ee8SDavid du Colombier 	p->next = prev;
275*219b2ee8SDavid du Colombier 	charmap[n].slow = p;
2763e12c5d1SDavid du Colombier }
2773e12c5d1SDavid du Colombier 
2783e12c5d1SDavid du Colombier static void
2793e12c5d1SDavid du Colombier buildtroff(char *buf)	/* map troff names into bitmap filenames */
2803e12c5d1SDavid du Colombier {				/* e.g., R -> times/R., I -> times/I., etc. */
281*219b2ee8SDavid du Colombier 	char *p, cmd[100], name[200], prefix[400], fallback[100];
2823e12c5d1SDavid du Colombier 
2833e12c5d1SDavid du Colombier 	scanstr(buf, cmd, &p);
2843e12c5d1SDavid du Colombier 	scanstr(p, name, &p);
2853e12c5d1SDavid du Colombier 	scanstr(p, prefix, &p);
286*219b2ee8SDavid du Colombier 	while(*p!=0 && isspace(*p))
287*219b2ee8SDavid du Colombier 		p++;
288*219b2ee8SDavid du Colombier 	if(*p != 0){
289*219b2ee8SDavid du Colombier 		scanstr(p, fallback, &p);
290*219b2ee8SDavid du Colombier 		fontmap[nfontmap].fallback = strdup(fallback);
291*219b2ee8SDavid du Colombier 	}else
292*219b2ee8SDavid du Colombier 		fontmap[nfontmap].fallback = 0;
2933e12c5d1SDavid du Colombier 	fontmap[nfontmap].troffname = strdup(name);
2943e12c5d1SDavid du Colombier 	fontmap[nfontmap].prefix = strdup(prefix);
2953e12c5d1SDavid du Colombier 	fontmap[nfontmap].map = curmap;
296*219b2ee8SDavid du Colombier 	dprint(2, "troff name %s is bitmap %s map %d in slot %d fallback %s\n", name, prefix, curmap, nfontmap, fontmap[nfontmap].fallback? fontmap[nfontmap].fallback : "<null>");
2973e12c5d1SDavid du Colombier 	nfontmap++;
2983e12c5d1SDavid du Colombier }
2993e12c5d1SDavid du Colombier 
3003e12c5d1SDavid du Colombier static void
3013e12c5d1SDavid du Colombier fontlookup(int n, char *s)	/* map troff name of s into position n */
3023e12c5d1SDavid du Colombier {
3033e12c5d1SDavid du Colombier 	int i;
3043e12c5d1SDavid du Colombier 
3053e12c5d1SDavid du Colombier 	for(i = 0; i < nfontmap; i++)
3063e12c5d1SDavid du Colombier 		if (eq(s, fontmap[i].troffname)) {
3073e12c5d1SDavid du Colombier 			strcpy(fname[n], fontmap[i].prefix);
3083e12c5d1SDavid du Colombier 			fmap[n] = fontmap[i].map;
309*219b2ee8SDavid du Colombier 			pos2fontmap[n] = i;
3103e12c5d1SDavid du Colombier 			if (eq(s, "S"))
3113e12c5d1SDavid du Colombier 				specfont = n;
3123e12c5d1SDavid du Colombier 			dprint(2, "font %d %s is %s\n", n, s, fname[n]);
3133e12c5d1SDavid du Colombier 			return;
3143e12c5d1SDavid du Colombier 		}
3153e12c5d1SDavid du Colombier 	/* god help us if this font isn't there */
3163e12c5d1SDavid du Colombier }
3173e12c5d1SDavid du Colombier 
3183e12c5d1SDavid du Colombier 
319*219b2ee8SDavid du Colombier static char *
320*219b2ee8SDavid du Colombier map(Rune rp[], int font)	/* figure out mapping for char in this font */
3213e12c5d1SDavid du Colombier {
322*219b2ee8SDavid du Colombier 	static char s[100];
323*219b2ee8SDavid du Colombier 	char c[10];
3243e12c5d1SDavid du Colombier 	Link *p;
325*219b2ee8SDavid du Colombier 	Rune r;
3263e12c5d1SDavid du Colombier 
327*219b2ee8SDavid du Colombier 	if(rp[1]==0 &&  rp[0]<QUICK)	/* fast lookup */
328*219b2ee8SDavid du Colombier 		r = charmap[fmap[font]].quick[rp[0]];
329*219b2ee8SDavid du Colombier 	else {	/* high-valued or compound character name */
330*219b2ee8SDavid du Colombier 		sprint(c, "%S", rp);
331*219b2ee8SDavid du Colombier 		r = 0;
332*219b2ee8SDavid du Colombier 		for (p = charmap[fmap[font]].slow; p; p = p->next)
333*219b2ee8SDavid du Colombier 			if(eq(c, p->name)){
334*219b2ee8SDavid du Colombier 				r = p->val;
335*219b2ee8SDavid du Colombier 				break;
336*219b2ee8SDavid du Colombier 			}
337*219b2ee8SDavid du Colombier 	}
338*219b2ee8SDavid du Colombier 	if(r == 0){	/* not there */
339*219b2ee8SDavid du Colombier 		dprint(2, "didn't find %S font# %d\n", rp, font);
3403e12c5d1SDavid du Colombier 		return 0;
3413e12c5d1SDavid du Colombier 	}
342*219b2ee8SDavid du Colombier 	dprint(2, "map %S to %s font# %d\n", rp, s, font);
343*219b2ee8SDavid du Colombier 	s[runetochar(s, &r)] = 0;
3443e12c5d1SDavid du Colombier 	return s;
3453e12c5d1SDavid du Colombier }
3463e12c5d1SDavid du Colombier 
3473e12c5d1SDavid du Colombier static void
3483e12c5d1SDavid du Colombier scanstr(char *s, char *ans, char **ep)
3493e12c5d1SDavid du Colombier {
3503e12c5d1SDavid du Colombier 	for (; isspace((uchar) *s); s++)
3513e12c5d1SDavid du Colombier 		;
352*219b2ee8SDavid du Colombier 	for (; *s!=0 && !isspace((uchar) *s); )
3533e12c5d1SDavid du Colombier 		*ans++ = *s++;
3543e12c5d1SDavid du Colombier 	*ans = 0;
3553e12c5d1SDavid du Colombier 	if (ep)
3563e12c5d1SDavid du Colombier 		*ep = s;
3573e12c5d1SDavid du Colombier }
358