1 /*
2  * sf_fonts.c - SDL interface, generic font handling
3  *
4  * This file is part of Frotz.
5  *
6  * Frotz is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Frotz is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  * Or visit http://www.fsf.org/
20  */
21 
22 #include "sf_frotz.h"
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 
29 /* font handling */
30 
31 typedef struct {
32 	int refcount;
33 	word minchar, maxchar, defchar;
34 	byte ascent, descent;
35 	int glyphs[0];		/* offsets to glyphs from start of rec */
36 } SF_bdffont;
37 
38 char *m_fontfiles[9];
39 
40 extern z_header_t z_header;
41 
42 static char s[1026];
43 
starts(char * s,char * id)44 static char *starts(char *s, char *id)
45 {
46 	int len = strlen(id);
47 	while (*s == ' ')
48 		s++;
49 	if (memcmp(s, id, len) == 0)
50 		return (s + len);
51 	return NULL;
52 }
53 
54 
hexd(char c)55 static int hexd(char c)
56 {
57 	if (c >= '0' && c <= '9')
58 		return c - '0';
59 	if (c >= 'A' && c <= 'F')
60 		return c - 'A' + 10;
61 	if (c >= 'a' && c <= 'f')
62 		return c - 'a' + 10;
63 	return 0;
64 }
65 
66 
gethex(char * p,byte * dst,int n)67 static void gethex(char *p, byte * dst, int n)
68 {
69 	while (n--) {
70 		*dst++ = 16 * hexd(p[0]) + hexd(p[1]);
71 		p += 2;
72 	}
73 }
74 
75 
76 #define ERRET(n) { *err = n; return font;}
77 
sBDXload(FILE * f,int * err,int * size,int MAXCHAR)78 static SF_bdffont *sBDXload(FILE * f, int *err, int *size, int MAXCHAR)
79 {
80 	int totb, i, k = 0, wh[4];
81 	byte *po, *pbeg;
82 	char *p, *q;
83 	char *fontname = "", *copyright = "unknown";
84 	int fngot = 0, cpgot = 0;
85 	int hasenc, hasbbx;
86 	SF_bdffont *font = NULL;
87 	int foffs, minch, maxch, rejected = 0;
88 	int defchar = -1, descent = -1, ascent = -1, nprop, nchars;
89 	/* NOTE: file MUST be opened as binary on MSDOS, otherwise
90 	 * ftell() won't return correct values if the file does not
91 	 * have CR's (as is usually the case, since BDF files frequently
92 	 * come from Unix systems)
93 	 */
94 
95 	/* header */
96 	for (;;) {
97 		fgets(s, 1024, f);
98 		if (feof(f))
99 			ERRET(-1)	/* errorexit(99,"unexpected EOF\n"); */
100 			if ((p = starts(s, "FONT "))) {
101 				while (*p == ' ')
102 					p++;
103 				q = p;
104 				while (*p >= ' ')
105 					p++;
106 				*p = 0;
107 				fontname = strdup(q);
108 				fngot = 1;
109 			}
110 		if ((p = starts(s, "STARTPROPERTIES "))) {
111 			nprop = atoi(p);
112 			break;
113 		}
114 	}
115 	for (i = 0; i < nprop; i++) {
116 		fgets(s, 1024, f);
117 		if (feof(f))
118 			ERRET(-51)	/* errorexit(99,"unexpected EOF\n"); */
119 			if ((p = starts(s, "COPYRIGHT "))) {
120 				while (*p == ' ')
121 					p++;
122 				q = p;
123 				while (*p >= ' ')
124 					p++;
125 				*p = 0;
126 				copyright = strdup(q);
127 				cpgot = 1;
128 			}
129 		if ((p = starts(s, "DEFAULT_CHAR ")))
130 			defchar = atoi(p);
131 		if ((p = starts(s, "FONT_ASCENT ")))
132 			ascent = atoi(p);
133 		if ((p = starts(s, "FONT_DESCENT ")))
134 			descent = atoi(p);
135 	}
136 	for (;;) {
137 		fgets(s, 1024, f);
138 		if (feof(f))
139 			ERRET(-61)	/* errorexit(99,"unexpected EOF\n"); */
140 			if ((p = starts(s, "CHARS "))) {
141 				nchars = atoi(p);
142 				break;
143 			}
144 	}
145 	foffs = ftell(f);
146 
147 	/* first pass */
148 	totb = 0;
149 	minch = 65536;
150 	maxch = -1;
151 	hasenc = 0;
152 	for (i = 0; i < nchars;) {
153 		fgets(s, 1024, f);
154 		if (feof(f))
155 			ERRET(-71)	/* errorexit(99,"unexpected EOF\n"); */
156 			if ((p = starts(s, "ENCODING "))) {
157 				k = atoi(p);
158 				k &= 0xffff;
159 				if (k <= MAXCHAR) {
160 					if (k < minch)
161 						minch = k;
162 					if (k > maxch)
163 						maxch = k;
164 				} else
165 					rejected++;
166 				hasenc = 1;
167 			}
168 		if ((p = starts(s, "BBX "))) {
169 			if (!hasenc)
170 				ERRET(-10)
171 				sscanf(p, "%d %d", wh, wh + 1);
172 			if (k <= MAXCHAR) {
173 				totb +=
174 				    ((wh[0] + 7) / 8) * wh[1] +
175 				    sizeof(SF_glyph);
176 			}
177 			i++;
178 			hasenc = 0;
179 		}
180 	}
181 	if (ascent < 0 || descent < 0 || nchars != i)
182 		ERRET(-2)
183 		if (defchar < minch || defchar > maxch) {
184 			if (defchar < minch)
185 				defchar = minch;
186 			if (defchar > maxch)
187 				defchar = maxch;
188 		}
189 	totb +=
190 	    (maxch - minch + 1) * sizeof(int) + sizeof(SF_bdffont) +
191 	    strlen(fontname) + strlen(copyright) + 2;
192 	font = calloc(1, totb);
193 	if (!font)
194 		ERRET(-3)
195 	font->minchar = minch;
196 	font->maxchar = maxch;
197 	font->defchar = defchar;
198 	font->ascent = ascent;
199 	font->descent = descent;
200 	pbeg = (byte *) font;
201 	po = (byte *) (&(font->glyphs[maxch - minch + 1]));
202 	k = strlen(fontname) + 1;
203 	memmove(po, fontname, k);
204 	po += k;
205 	if (fngot)
206 		free(fontname);
207 	k = strlen(copyright) + 1;
208 	memmove(po, copyright, k);
209 	po += k;
210 	if (cpgot)
211 		free(copyright);
212 	for (i = minch; i <= maxch; i++)
213 		font->glyphs[i - minch] = 0;
214 
215 	/* second pass */
216 	fseek(f, foffs, 0);
217 	for (k = 0; k < nchars; k++) {
218 		SF_glyph *bg;
219 		int j;
220 		int dwid, w, h;
221 
222 		/* Unclear what the default for dwid should be */
223 		dwid = 0;
224 		bg = (SF_glyph *) po;
225 		hasenc = hasbbx = 0;
226 		for (;;) {
227 			fgets(s, 1024, f);
228 			if (feof(f))
229 				ERRET(-81)
230 				if ((p = starts(s, "ENCODING "))) {
231 					i = atoi(p);
232 					i &= 0xffff;
233 					if (i <= MAXCHAR)
234 						font->glyphs[i - minch] =
235 						    po - pbeg;
236 					hasenc = 1;
237 				}
238 			if ((p = starts(s, "DWIDTH "))) {
239 				if (!hasenc)
240 					ERRET(-11)
241 					    dwid = atoi(p);
242 			}
243 			if ((p = starts(s, "BBX "))) {
244 				if (!hasenc)
245 					ERRET(-12)
246 					    sscanf(p, "%d %d %d %d", wh, wh + 1,
247 						   wh + 2, wh + 3);
248 				hasbbx = 1;
249 			}
250 			if (starts(s, "BITMAP"))
251 				break;
252 		}
253 		if (!hasenc || !hasbbx)
254 			ERRET(-13)
255 			    if (i <= MAXCHAR) {
256 				bg->dx = dwid;
257 				bg->w = wh[0];
258 				w = (wh[0] + 7) / 8;
259 				bg->h = h = wh[1];
260 				bg->xof = wh[2];
261 				bg->yof = wh[3];
262 				po = (byte *) (&(bg->bitmap[0]));
263 				for (j = 0; j < h; j++) {
264 					fgets(s, 1024, f);
265 					if (feof(f))
266 						ERRET(-91)
267 						    gethex(s, po, w);
268 					po += w;
269 				}
270 			}
271 	}
272 	*err = 0;
273 	*size = totb;
274 	return font;
275 }
276 
277 
278 /* destructor for fonts with all dynamic data */
bdestroy(SFONT * s)279 static void bdestroy(SFONT * s)
280 {
281 	if (s) {
282 		if (s->data)
283 			free(s->data);
284 		free(s);
285 	}
286 }
287 
288 
bheight(SFONT * s)289 static int bheight(SFONT * s)
290 {
291 	if (s) {
292 		if (s->data) {
293 			SF_bdffont *f = s->data;
294 			return ((int)(f->ascent) + (int)(f->descent));
295 		}
296 	}
297 	return 0;
298 }
299 
300 
bascent(SFONT * s)301 static int bascent(SFONT * s)
302 {
303 	if (s) {
304 		if (s->data)
305 			return (int)((SF_bdffont *) (s->data))->ascent;
306 	}
307 	return 0;
308 }
309 
310 
bdescent(SFONT * s)311 static int bdescent(SFONT * s)
312 {
313 	if (s) {
314 		if (s->data)
315 			return (int)((SF_bdffont *) (s->data))->descent;
316 	}
317 	return 0;
318 }
319 
320 
bminchar(SFONT * s)321 static int bminchar(SFONT * s)
322 {
323 	if (s) {
324 		if (s->data)
325 			return (int)((SF_bdffont *) (s->data))->minchar;
326 	}
327 	return 0;
328 }
329 
bmaxchar(SFONT * s)330 static int bmaxchar(SFONT * s)
331 {
332 	if (s) {
333 		if (s->data)
334 			return (int)((SF_bdffont *) (s->data))->maxchar;
335 	}
336 	return 0;
337 }
338 
getglyph(SFONT * fo,word c,int allowdef)339 static SF_glyph *getglyph(SFONT * fo, word c, int allowdef)
340 {
341 	int m;
342 	SF_bdffont *b;
343 	if (!fo)
344 		return NULL;
345 	b = fo->data;
346 	if (!b)
347 		return NULL;
348 	if (c < b->minchar || c > b->maxchar) {
349 		if (allowdef)
350 			c = b->defchar;
351 		else
352 			return NULL;
353 	}
354 	m = b->glyphs[c - b->minchar];
355 	if (!m) {
356 		if (allowdef)
357 			m = b->glyphs[0];
358 		else
359 			return NULL;
360 	}
361 	return (SF_glyph *) (((byte *) b) + m);
362 }
363 
364 
hasglyph(SFONT * fo,word c,int allowdef)365 static int hasglyph(SFONT * fo, word c, int allowdef)
366 {
367 	return (getglyph(fo, c, allowdef) != NULL);
368 }
369 
370 
makefont(SF_bdffont * b)371 static SFONT *makefont(SF_bdffont * b)
372 {
373 	SFONT *res;
374 	if (!b)
375 		return NULL;
376 	res = calloc(1, sizeof(SFONT));
377 	if (!res) {
378 		free(b);
379 		return NULL;
380 	}
381 	res->destroy = bdestroy;
382 	res->height = bheight;
383 	res->data = b;
384 	res->ascent = bascent;
385 	res->descent = bdescent;
386 	res->minchar = bminchar;
387 	res->maxchar = bmaxchar;
388 	res->hasglyph = hasglyph;
389 	res->getglyph = getglyph;
390 	return res;
391 }
392 
393 
loadfont(char * fname,int * err,int * size)394 static SFONT *loadfont(char *fname, int *err, int *size)
395 {
396 	SF_bdffont *font;
397 	SFONT *res;
398 	FILE *f;
399 	*err = 0;
400 	if (!fname) {
401 		*err = -8;
402 		return NULL;
403 	}
404 	/* NOTE: file MUST be opened as binary on MSDOS, otherwise
405 	 * ftell() won't return correct values if the file does not
406 	 * have CR's (as is usually the case, since BDF files frequently
407 	 * come from Unix systems)
408 	 */
409 	f = fopen(fname, "rb");
410 	if (!f) {
411 		*err = -7;
412 		return NULL;
413 	}
414 	font = sBDXload(f, err, size, 65535);
415 	fclose(f);
416 	if (*err) {
417 		if (font)
418 			free(font);
419 		return NULL;
420 	}
421 	res = makefont(font);
422 	if (!res) {
423 		free(font);
424 		*err = -9999;
425 		return NULL;
426 	}
427 	return res;
428 }
429 
430 
431 /*
432  * these are the 8 fonts needed
433  * PROPORTIONAL FONT
434  *   ROMAN
435  *   ROMAN BOLD
436  *   ITALIC
437  *   ITALIC BOLD
438  * FIXED FONT
439  *   ROMAN
440  *   ROMAN BOLD
441  *   ITALIC
442  *   ITALIC BOLD
443  */
444 #define NUMFONTS 9
445 
446 static SFONT *myfonts[9] =
447 	{ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
448 
styleidx(int zfont,int style)449 static int styleidx(int zfont, int style)
450 {
451 	int k = 0;
452 	if (zfont == GRAPHICS_FONT)
453 		return 8;
454 	if (zfont != TEXT_FONT)
455 		zfont = FIXED_WIDTH_FONT;
456 	if (style & FIXED_WIDTH_STYLE)
457 		zfont = FIXED_WIDTH_FONT;
458 	if (z_header.flags & FIXED_FONT_FLAG)
459 		zfont = FIXED_WIDTH_FONT;
460 	if (zfont != TEXT_FONT)
461 		k += 4;
462 	if (style & EMPHASIS_STYLE)
463 		k += 2;
464 	if (style & BOLDFACE_STYLE)
465 		k++;
466 	return k;
467 }
468 
469 static SF_textsetting current;
470 #define MAXSTACK 16
471 static SF_textsetting tsstack[MAXSTACK];
472 static int tsstackptr = 0;
473 
474 /* does not increase the refcount of f - user must do that */
setfontk(int k,SFONT * f)475 static void setfontk(int k, SFONT * f)
476 {
477 	if (myfonts[k]) {
478 		myfonts[k]->refcount--;
479 		if (myfonts[k]->refcount == 0)
480 			myfonts[k]->destroy(myfonts[k]);
481 	}
482 	myfonts[k] = f;
483 }
484 
485 
cleanfonts()486 static void cleanfonts()
487 {
488 	int i;
489 	for (i = 0; i < 8; i++)
490 		setfontk(i, NULL);
491 /*  for (i=0;i<8;i++)
492 	if (m_fontfiles[i]){ free(m_fontfiles[i]); m_fontfiles[i] = NULL;}*/
493 }
494 
495 
sf_curtextsetting()496 SF_textsetting *sf_curtextsetting()
497 {
498 	return &current;
499 }
500 
501 
sf_pushtextsettings()502 void sf_pushtextsettings()
503 {
504 	if (tsstackptr < MAXSTACK) {
505 		tsstack[tsstackptr] = current;
506 		tsstackptr++;
507 	}
508 }
509 
510 
sf_poptextsettings()511 void sf_poptextsettings()
512 {
513 	if (tsstackptr) {
514 		tsstackptr--;
515 		current = tsstack[tsstackptr];
516 	}
517 }
518 
519 
520 /*
521  * os_check_unicode
522  *
523  * Return with bit 0 set if the Unicode character can be
524  * displayed, and bit 1 if it can be input.
525  *
526  *
527  */
os_check_unicode(int font,zchar c)528 int os_check_unicode(int font, zchar c)
529 {
530 	return ((current.font->hasglyph(current.font, c, 0) != 0) ? 3 : 2);
531 }
532 
533 
sf_charwidth(zword c,int * oh)534 int sf_charwidth(zword c, int *oh)
535 {
536 	SF_glyph *g;
537 	int ww = 0;
538 	if (c == ZC_INDENT)
539 		return (3 * sf_charwidth(' ', oh));
540 	if (c == ZC_GAP)
541 		return (2 * sf_charwidth(' ', oh));
542 	*oh = 0;
543 	g = current.font->getglyph(current.font, c, 1);
544 	if (g) {
545 		int ext = g->w + g->xof;
546 		if (ext > g->dx)
547 			*oh = ext - g->dx;
548 		ww = (g->dx);
549 	}
550 	return ww;
551 }
552 
553 
554 /*
555  * os_char_width
556  *
557  * Return the length of the character in screen units.
558  *
559  */
os_char_width(zchar c)560 int os_char_width(zchar c)
561 {
562 	int w, oh;
563 	w = sf_charwidth(c, &oh);
564 	return (w + oh);
565 }
566 
567 
setfont(int zfont)568 static void setfont(int zfont)
569 {
570 	int k = styleidx(zfont, current.style);
571 	current.font = myfonts[k];
572 	current.zfontnum = zfont;
573 	current.proportional = (k < 4);
574 }
575 
576 
setstyle(int style)577 static void setstyle(int style)
578 {
579 	current.style = style;
580 	setfont(current.zfontnum);
581 }
582 
583 
584 /*
585  * os_font_data
586  *
587  * Return true if the given font is available. The font can be
588  *
589  *    TEXT_FONT
590  *    PICTURE_FONT
591  *    GRAPHICS_FONT
592  *    FIXED_WIDTH_FONT
593  *
594  * The font size should be stored in "height" and "width". If
595  * the given font is unavailable then these values must _not_
596  * be changed.
597  *
598  * Font can also be 0 to query the size of the current font in the current
599  * style.  Not all front end support this.  Those that do return true.
600  */
os_font_data(int font,int * height,int * width)601 int os_font_data(int font, int *height, int *width)
602 {
603 	switch (font) {
604 	case TEXT_FONT:
605 	case FIXED_WIDTH_FONT:
606 	case GRAPHICS_FONT:
607 		sf_pushtextsettings();
608 		setfont(font);
609 		setstyle(0);
610 		*height = current.font->height(current.font);
611 		*width = os_char_width((zword) ('0'));
612 		sf_poptextsettings();
613 		return 1;
614 	case 0:
615 		*height = current.font->height(current.font);
616 		*width = os_char_width((zword) ('0'));
617 		return 1;
618 	default:
619 		return 0;
620 	}
621 }
622 
623 
624 /*
625  * os_set_font
626  *
627  * Set the font for text output. The interpreter takes care not to
628  * choose fonts which aren't supported by the interface.
629  *
630  */
os_set_font(int new_font)631 void os_set_font(int new_font)
632 {
633 	sf_flushtext();
634 	setfont(new_font);
635 }
636 
637 
638 /*
639  * os_set_text_style
640  *
641  * Set the current text style. Following flags can be set:
642  *
643  *     REVERSE_STYLE
644  *     BOLDFACE_STYLE
645  *     EMPHASIS_STYLE (aka underline aka italics)
646  *     FIXED_WIDTH_STYLE
647  *
648  */
os_set_text_style(int new_style)649 void os_set_text_style(int new_style)
650 {
651 	sf_flushtext();
652 	setstyle(new_style);
653 }
654 
655 
656 /*
657  * os_string_width
658  *
659  * Calculate the length of a word in screen units. Apart from letters,
660  * the word may contain special codes:
661  *
662  *    ZC_NEW_STYLE - next character is a new text style
663  *    ZC_NEW_FONT  - next character is a new font
664  *
665  */
os_string_width(const zchar * s)666 int os_string_width(const zchar * s)
667 {
668 	int width = 0, wacc = 0, oh = 0;
669 	zword c;
670 
671 	setfont(current.zfontnum);
672 	/* Look for style or font changes, or indents */
673 	sf_pushtextsettings();
674 	while ((c = *s++)) {
675 		if (c == ZC_NEW_STYLE) {
676 			wacc += oh;
677 			os_set_text_style(*s++);
678 		} else if (c == ZC_NEW_FONT) {
679 			wacc += oh;
680 			os_set_font(*s++);
681 		} else
682 			width += sf_charwidth(c, &oh);
683 	}
684 	sf_poptextsettings();
685 
686 	return (width + oh + wacc);
687 }
688 
689 
690 /*
691  * os_display_string
692  *
693  * Pass a string of characters to os_display_char.
694  *
695  */
os_display_string(const zchar * s)696 void os_display_string(const zchar * s)
697 {
698 	zword c;
699 	while ((c = *s++) != 0) {
700 		if (c == ZC_NEW_FONT)
701 			os_set_font(*s++);
702 		else if (c == ZC_NEW_STYLE)
703 			os_set_text_style(*s++);
704 		else
705 			os_display_char(c);
706 	}
707 }
708 
709 
710 /*
711  * os_display_char
712  *
713  * Display a character of the current font using the current colours and
714  * text style. The cursor moves to the next position. Printable codes are
715  * all ASCII values from 32 to 126, ISO Latin-1 characters from 160 to
716  * 255, ZC_GAP (gap between two sentences) and ZC_INDENT (paragraph
717  * indentation), and Unicode characters above 255. The screen should not
718  * be scrolled after printing to the bottom right corner.
719  *
720  */
os_display_char(zchar c)721 void os_display_char(zchar c)
722 {
723 	if (c == ZC_INDENT) {
724 		os_display_char(' ');
725 		os_display_char(' ');
726 		os_display_char(' ');
727 	} else if (c == ZC_GAP) {
728 		os_display_char(' ');
729 		os_display_char(' ');
730 	} else if ((c >= 32 && c <= 126) || (c >= 160)) {
731 		SF_glyph *g;
732 		setfont(current.zfontnum);
733 		g = current.font->getglyph(current.font, c, 1);
734 		if (g) {
735 			sf_writeglyph(g);
736 			m_exitPause = true;
737 		}
738 	}
739 }
740 
741 /*
742  * os_buffer_screen
743  *
744  * Set the screen buffering mode, and return the previous mode.
745  * Possible values for mode are:
746  *
747  *     0 - update the display to reflect changes when possible
748  *     1 - do not update the display
749  *    -1 - redraw the screen, do not change the mode
750  *
751  */
os_buffer_screen(int mode)752 int os_buffer_screen(int mode)
753 {
754 	if (mode == -1)
755 		sf_flushdisplay();
756 	return 0;
757 }
758 
759 
760 /*
761  * os_wrap_window
762  *
763  * Return non-zero if the window should have text wrapped.
764  *
765  */
os_wrap_window(int win)766 int os_wrap_window(int win)
767 {
768 	return 1;
769 }
770 
771 
772 /*
773  * os_window_height
774  *
775  * Called when the height of a window is changed.
776  *
777  */
os_window_height(int win,int height)778 void os_window_height(int win, int height)
779 {
780 }
781 
782 
783 /*
784  * os_set_cursor
785  *
786  * Place the text cursor at the given coordinates. Top left is (1,1).
787  *
788  */
os_set_cursor(int row,int col)789 void os_set_cursor(int row, int col)
790 {
791 	sf_flushtext();
792 	current.cx = col - 1;
793 	current.cy = row - 1;
794 }
795 
796 
797 extern SF_bdffont *SF_defaultfont;
798 extern int SF_defaultfontsize;
799 
destroySFonly(SFONT * f)800 static void destroySFonly(SFONT * f)
801 {
802 	if (f)
803 		free(f);
804 }
805 
806 extern SFONT *SF_font3, *SF_font3double;
807 
808 SFONT *(*ttfontloader)(char *fspec, SFONT * like, int *err) = NULL;
809 void (*ttfontsdone)() = NULL;
810 
811 
tryloadfont(char * fspec,SFONT * like)812 static SFONT *tryloadfont(char *fspec, SFONT * like)
813 {
814 	char buf[FILENAME_MAX];
815 	int err, size = DEFSIZE;
816 	char *fn = NULL;
817 	char *p, *at;
818 	int fnlen = -1;
819 	SFONT *b = NULL;
820 
821 	at = strchr(fspec, '@');
822 	if (at) {
823 		fnlen = at - fspec;
824 		size = atoi(at + 1);
825 	}
826 
827 	if (m_fontdir != NULL)
828 		fn = sf_searchfile(fspec, fnlen, buf, m_fontdir);
829 
830 	for (;;) {
831 		p = strchr(fspec, '|');
832 		if (p)
833 			*p = 0;
834 
835 		if (ttfontloader)
836 			b = ttfontloader(fspec, like, &err);
837 		if (!b)
838 			b = loadfont(fn, &err, &size);
839 		if (b)
840 			break;
841 		if (p) {
842 			*p = '|';
843 			fspec = p + 1;
844 		} else
845 			break;
846 	}
847 	return b;
848 }
849 
850 SFONT *sf_VGA_SFONT;
851 
852 
853 /* ensure a font loaded */
sf_initfonts()854 void sf_initfonts()
855 {
856 	int i, j, size = 0;
857 	byte *cfont, *bmp;
858 	SF_glyph *g;
859 	SF_bdffont *norm, *emph, *bold, *bemp;
860 	SFONT *Norm, *Emph = NULL, *Bold = NULL, *Bemp = NULL;
861 
862 	norm = SF_defaultfont;
863 	sf_VGA_SFONT = Norm = makefont(norm);
864 	if (!Norm)
865 		os_fatal("malloc() failure in initfonts()");
866 	Norm->destroy = destroySFonly;
867 
868 	/* get size of default font */
869 	size = SF_defaultfontsize;
870 
871 	/* copy norm to emphasized */
872 	emph = malloc(size);
873 	if (!emph)
874 		os_fatal("malloc() failure in initfonts()");
875 	Emph = makefont(emph);
876 	if (!Emph)
877 		os_fatal("malloc() failure in initfonts()");
878 	memmove(emph, norm, size);
879 	/* emphasize (underline)... */
880 	cfont = (byte *) emph;
881 	for (i = norm->minchar; i <= norm->maxchar; i++) {
882 		int m = norm->glyphs[i - norm->minchar];
883 		if (!m)
884 			continue;
885 		g = (SF_glyph *) (cfont + m);
886 		bmp = (byte *) (&(g->bitmap[0]));
887 		bmp[g->h - 2] = 0xff;
888 	}
889 	/* make a copy for bold */
890 	bold = malloc(size);
891 	if (!bold)
892 		os_fatal("malloc() failure in initfonts()");
893 	Bold = makefont(bold);
894 	if (!Bold)
895 		os_fatal("malloc() failure in initfonts()");
896 	memmove(bold, norm, size);
897 	/* boldify... */
898 	cfont = (byte *) bold;
899 	for (i = norm->minchar; i <= norm->maxchar; i++) {
900 		int h, m = norm->glyphs[i - norm->minchar];
901 		if (!m)
902 			continue;
903 		g = (SF_glyph *) (cfont + m);
904 		h = g->h;
905 		bmp = (byte *) (&(g->bitmap[0]));
906 		for (j = 0; j < h; j++) {
907 			int c = bmp[j];
908 			bmp[j] = (c) | (c >> 1);
909 		}
910 	}
911 	/* copy bold to bold, emphasized */
912 	bemp = malloc(size);
913 	if (!bemp)
914 		os_fatal("malloc() failure in initfonts()");
915 	Bemp = makefont(bemp);
916 	if (!Bemp)
917 		os_fatal("malloc() failure in initfonts()");
918 	memmove(bemp, bold, size);
919 	/* emphasize (underline)... */
920 	cfont = (byte *) bemp;
921 	for (i = norm->minchar; i <= norm->maxchar; i++) {
922 		int m = norm->glyphs[i - norm->minchar];
923 		if (!m)
924 			continue;
925 		g = (SF_glyph *) (cfont + m);
926 		bmp = (byte *) (&(g->bitmap[0]));
927 		bmp[g->h - 2] = 0xff;
928 	}
929 
930 	myfonts[0] = myfonts[4] = Norm;
931 	norm->refcount = 2;
932 	myfonts[1] = myfonts[5] = Bold;
933 	bold->refcount = 2;
934 	myfonts[2] = myfonts[6] = Emph;
935 	emph->refcount = 2;
936 	myfonts[3] = myfonts[7] = Bemp;
937 	bemp->refcount = 2;
938 
939 	CLEANREG(cleanfonts);
940 
941 	if (!m_vga_fonts) {
942 		for (i = 0; i <= 8; i++)
943 			if (m_fontfiles[i]) {
944 				SFONT *b = tryloadfont(m_fontfiles[i],
945 					i == 8 ? myfonts[FIXED_WIDTH_FONT]
946 						: NULL);
947 				if (!b)
948 					fprintf(stderr,
949 						"WARNING: could not load font%d [%s%c%s]\n",
950 						i, m_fontdir, PATH_SEPARATOR, m_fontfiles[i]);
951 				else {
952 					setfontk(i, b);
953 					b->refcount = 1;
954 				}
955 			}
956 	}
957 
958 	if (ttfontsdone)
959 		ttfontsdone();
960 	/* now set the graphics font */
961 	if (!myfonts[8]) {
962 		if (myfonts[4]->height(myfonts[4]) < 16)
963 			myfonts[8] = SF_font3;
964 		else
965 			myfonts[8] = SF_font3double;
966 	}
967 }
968 
969 
sf_searchfile(char * fn,int fnlen,char * buf,char * paths)970 char *sf_searchfile(char *fn, int fnlen, char *buf, char *paths)
971 {
972 	char *p;
973 	if (!fn)
974 		return NULL;
975 	if (!paths)
976 		paths = "";
977 	if (fnlen < 0)
978 		fnlen = strlen(fn);
979 	if (!fnlen)
980 		return NULL;
981 	for (;;) {
982 		int plen;
983 		p = strchr(paths, OS_PATHSEP);
984 		if (p)
985 			plen = p - paths;
986 		else
987 			plen = strlen(paths);
988 		if (plen)
989 			strncpy(buf, paths, plen);
990 		buf[plen] = 0;
991 		if ((plen) && (buf[plen - 1] != '\\') && (buf[plen - 1] != '/'))
992 			strcat(buf, "/");
993 		plen = strlen(buf);
994 		strncpy(buf + plen, fn, fnlen);
995 		buf[plen + fnlen] = 0;
996 		if (access(buf, F_OK) == 0)
997 			return buf;
998 		if (p)
999 			paths = p + 1;
1000 		else
1001 			break;
1002 	}
1003 	return NULL;
1004 }
1005