Continuing to track down the issue with a crash on startup on
[xcircuit.git] / fontfile.c
blobbf6d3130cb27955be69e20e83b342a530cf7eb95
1 /*-------------------------------------------------------------------------*/
2 /* fontfile.c --- Load font character and encoding defitions */
3 /* Copyright (c) 2001 Tim Edwards, Johns Hopkins University */
4 /*-------------------------------------------------------------------------*/
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <ctype.h>
9 #include <string.h>
11 #ifndef XC_WIN32
12 #include <X11/Intrinsic.h>
13 #include <X11/StringDefs.h>
14 #endif
16 #ifdef TCL_WRAPPER
17 #include <tk.h>
18 #else
19 #ifndef XC_WIN32
20 #include "Xw/Xw.h"
21 #endif
22 #endif
24 /*-------------------------------------------------------------------------*/
25 /* Local includes */
26 /*-------------------------------------------------------------------------*/
28 #include "xcircuit.h"
30 /*----------------------------------------------------------------------*/
31 /* Function prototype declarations */
32 /*----------------------------------------------------------------------*/
33 #include "prototypes.h"
35 /*-------------------------------------------------------------------------*/
36 /* Global Variable definitions */
37 /*-------------------------------------------------------------------------*/
39 extern char _STR2[250], _STR[150];
41 extern short fontcount;
42 extern fontinfo *fonts;
44 extern Globaldata xobjs;
45 extern short beeper;
46 #ifdef HAVE_CAIRO
47 extern XCWindowData *areawin;
48 extern const char *utf8encodings[][256];
49 #endif
51 extern char version[];
53 #ifdef TCL_WRAPPER
54 extern Tcl_Interp *xcinterp;
55 #endif
57 /*----------------------------------------------------------------------*/
58 /* Find the file containing the encoding for the given font */
59 /*----------------------------------------------------------------------*/
61 FILE *findfontfile(char *fontname)
63 size_t i;
64 char tempname[256];
65 FILE *fd;
67 /* Add subdirectory "fonts". We will try both with and */
68 /* without the subdirectory. */
70 sprintf(_STR, "fonts/%s", fontname);
72 /* change string to all lowercase and remove dashes */
74 for (i = 0; i < strlen(_STR); i++) {
75 _STR[i] = tolower(_STR[i]);
76 if (_STR[i] == '-') _STR[i] = '_';
79 /* Fprintf(stdout, "Searching for font file \"%s\"\n", _STR); */
81 /* Use the mechanism of "libopen" to find the encoding file */
82 /* in the search path */
84 fd = libopen(_STR + 6, FONTENCODING, NULL, 0);
86 if (fd == NULL) fd = libopen(_STR, FONTENCODING, NULL, 0);
88 /* Some other, probably futile, attempts (call findfontfile recursively) */
90 if (fd == NULL) {
91 char *dashptr;
93 /* If this font has a suffix, remove it and look for its root */
94 /* font on the supposition that this font is derived from the */
95 /* root font. */
97 strncpy(tempname, fontname, 99);
98 if ((dashptr = strrchr(tempname, '-')) != NULL) {
99 *dashptr = '\0';
100 if ((fd = findfontfile(tempname)) != NULL) return fd;
102 /* And finally, because it's a common case, try adding */
103 /* -Roman and trying again (but don't infinite loop!) */
105 if (strcmp(dashptr + 1, "Roman")) {
106 strcat(dashptr, "-Roman");
107 if ((fd = findfontfile(tempname)) != NULL) return fd;
111 Wprintf("No font encoding file found.");
112 if (fontcount > 0) { /* Make font substitution */
113 char *dchr, *psname = NULL;
114 short fval;
116 if ((dchr = strrchr(_STR, '.')) != NULL) *dchr = '\0';
117 if ((fval = findhelvetica()) == fontcount) {
118 /* This will cause some chaos. . . */
119 Fprintf(stderr, "Error: No fonts available! Check library path?\n");
120 exit(1);
123 psname = (char *)malloc((1 + strlen(fontname)) * sizeof(char));
124 strcpy(psname, fontname);
125 Wprintf("No encoding file found for font %s: substituting %s",
126 psname, fonts[fval].psname);
127 fonts = (fontinfo *)realloc(fonts, (fontcount + 1) * sizeof(fontinfo));
128 fonts[fontcount].psname = psname;
129 fonts[fontcount].family = psname;
130 fonts[fontcount].encoding = fonts[fval].encoding;
131 fonts[fontcount].flags = 0;
132 fonts[fontcount].scale = 1.0;
133 fontcount++;
134 makenewfontbutton();
136 else {
137 Fprintf(stderr, "Error: font encoding file missing for font \"%s\"\n",
138 fontname);
139 Fprintf(stderr, "No fonts exist for a subsitution. Make sure "
140 "fonts are installed or that\nenvironment variable "
141 "XCIRCUIT_LIB_DIR points to a directory of valid fonts.\n");
143 return (FILE *)NULL;
145 return fd;
148 /*----------------------------------------------------------------------*/
149 /* Load a named font */
150 /* Return 1 if successful, 0 if font is already present, and -1 if any */
151 /* other error occurred. */
152 /*----------------------------------------------------------------------*/
154 int loadfontfile(char *fname)
156 FILE *fd;
157 char temp[250], commandstr[30], tempname[100];
158 char *psname = NULL, *family = NULL;
159 char *cmdptr;
160 int flags = 0;
161 int i;
162 float fontscale = 1.0;
163 objectptr *j, *eptr;
164 objectptr *encoding = NULL;
165 char saveversion[20];
166 char *fontname = strdup(fname);
167 #ifdef HAVE_CAIRO
168 const char **utf8enc = NULL;
169 #endif /* HAVE_CAIRO */
171 strcpy(saveversion, version);
173 /* check to see if font name is in list of fonts */
175 for (i = 0; i < fontcount; i++) {
176 if (!strcmp(fonts[i].psname, fontname)) {
177 free(fontname);
178 return 0;
181 if ((fd = findfontfile(fontname)) == NULL) return -1;
183 while (fgets(temp, 249, fd) != NULL) {
184 if (*temp == '\n') continue;
185 sscanf(temp, "%29s", commandstr);
186 for(cmdptr = commandstr; isspace(*cmdptr); cmdptr++);
188 /* very liberal about comment line characters */
190 if (*cmdptr == '#' || *cmdptr == '%' || *cmdptr == ';');
192 else if (!strcmp(cmdptr, "name:")) {
193 sscanf(temp, "%*s %99s", tempname);
195 /* If font is already in list, ignore it */
196 /* This condition should be caught at the top of the routine. . . */
198 for (i = 0; i < fontcount; i++) {
199 if (!strcmp(fonts[i].psname, tempname)) {
200 /* Fprintf(stdout, "Font already loaded.\n"); */
201 fclose(fd);
202 free(fontname);
203 return 0;
206 psname = (char *)malloc((1 + strlen(tempname)) * sizeof(char));
207 strcpy(psname, tempname);
210 else if (!strcmp(cmdptr, "file:") || !strcmp(cmdptr, "load:")) {
211 /* Fprintf(stdout, "found file identifier in xfe file\n"); */
212 sscanf(temp, "%*s %149s", _STR);
214 /* since we can be in the middle of a file load, protect the */
215 /* current version number for the file load. */
217 strcpy(version, PROG_VERSION);
218 if (loadlibrary(FONTLIB) == FALSE) {
220 strcpy(version, saveversion);
223 else if (!strcmp(cmdptr, "family:")){
224 sscanf(temp, "%*s %99s", tempname);
225 family = (char *)malloc((1 + strlen(tempname)) * sizeof(char));
226 strcpy(family, tempname);
229 else if (!strcmp(cmdptr, "weight:")){
230 sscanf(temp, "%*s %99s", tempname);
231 tempname[0] = tolower(tempname[0]);
232 if (!strcmp(tempname, "bold"))
233 flags |= 0x01;
236 else if (!strcmp(cmdptr, "shape:")){
237 sscanf(temp, "%*s %99s", tempname);
238 tempname[0] = tolower(tempname[0]);
239 if (!strcmp(tempname, "italic") || !strcmp(tempname, "oblique")
240 || !strcmp(tempname, "slanted"))
241 flags |= 0x02;
244 else if (!strcmp(cmdptr, "scale:")){
245 sscanf(temp, "%*s %f", &fontscale);
248 else if (!strcmp(cmdptr, "type:")) {
249 sscanf(temp, "%*s %99s", tempname);
250 tempname[0] = tolower(tempname[0]);
251 if (!strcmp(tempname, "drawn") || !strcmp(tempname, "vectored"))
252 flags |= 0x08;
255 else if (!strcmp(cmdptr, "derived:")) {
256 if (encoding == NULL) {
257 Fprintf(stdout, "Font warning: \"derived\" statement must come "
258 "after encoding\n");
260 else {
261 char *psname2;
262 sscanf(temp, "%*s %99s", tempname);
263 psname2 = (char *)malloc((1 + strlen(tempname)) * sizeof(char));
264 strcpy(psname2, tempname);
265 flags &= 0xffe0; /* shares these flags with original */
266 flags |= 0x020; /* derived font flag */
268 /* determine rest of flags */
270 sscanf(temp, "%*s %*s %99s", tempname);
271 tempname[0] = tolower(tempname[0]);
272 if (!strcmp(tempname, "bold")) {
273 flags |= 0x1;
276 sscanf(temp, "%*s %*s %*s %99s", tempname);
277 tempname[0] = tolower(tempname[0]);
278 if (!strcmp(tempname, "italic") || !strcmp(tempname, "oblique"))
279 flags |= 0x2;
281 sscanf(temp, "%*s %*s %*s %*s %99s", tempname);
282 tempname[0] = tolower(tempname[0]);
283 if (!strcmp(tempname, "drawn") || !strcmp(tempname, "vectored"))
284 flags |= 0x08;
285 else if (!strcmp(tempname, "special"))
286 flags |= 0x10;
288 /* generate a new fontinfo entry for the derived font */
290 fonts = (fontinfo *) realloc (fonts, (fontcount + 1) * sizeof(fontinfo));
291 fonts[fontcount].psname = psname2;
292 if (family == NULL)
293 fonts[fontcount].family = psname;
294 else
295 fonts[fontcount].family = family;
296 fonts[fontcount].encoding = encoding; /* use original encoding */
297 fonts[fontcount].flags = flags;
298 fonts[fontcount].scale = fontscale;
299 #ifdef HAVE_CAIRO
300 fonts[fontcount].utf8encoding = utf8enc;
301 xc_cairo_set_fontinfo(fontcount);
302 #endif /* HAVE_CAIRO */
303 fontcount++;
307 else if (!strcmp(cmdptr, "encoding:")) {
308 #ifdef HAVE_CAIRO
309 const char *findencstr;
310 #endif /* HAVE_CAIRO */
311 sscanf(temp, "%*s %99s", tempname);
313 if (!strcmp(tempname, "special") || !strcmp(tempname, "Special")) {
314 flags |= 0x80;
315 #ifdef TCL_WRAPPER
316 XcInternalTagCall(xcinterp, 3, "label", "encoding", "Special");
317 #else
318 makenewencodingbutton("Special", (char)1);
319 #endif
322 #ifdef HAVE_CAIRO
323 utf8enc = utf8encodings[0];
324 /* treat encoding of symbol font in a special way */
325 if (!strcmp(family, "Symbol"))
326 findencstr = "Symbol";
327 else
328 findencstr = tempname;
330 /* Now try to find the encoding, */
331 /* default to the first encoding (stdenc) if not found */
332 utf8enc = utf8encodings[0];
333 for (i = 0; utf8encodings[i][0]; i++)
334 if (!strcmp(utf8encodings[i][0], findencstr)) {
335 utf8enc = utf8encodings[i];
336 break;
338 #endif /* HAVE_CAIRO */
340 /* ISO-LatinX encodings where X=1 to 6 */
342 if (strstr(tempname, "Latin") != NULL) {
343 char estr[12];
344 for (i = 0; i < 6; i++) {
345 if (strchr(tempname, '1' + (char)i) != NULL) {
346 flags |= ((i + 2) << 7);
347 #ifdef TCL_WRAPPER
348 snprintf(estr, sizeof(estr), "ISOLatin%d", i + 1);
349 XcInternalTagCall(xcinterp, 3, "label", "encoding", estr);
350 #else
351 snprintf(estr, sizeof(estr), "ISO-Latin%d", i + 1);
352 makenewencodingbutton(estr, (char)(i + 2));
353 #endif
354 break;
358 /* i == 6 maps to ISO8859-5 */
359 if (strstr(tempname, "8859-5") != NULL) {
360 #ifndef TCL_WRAPPER
361 char estr[12];
362 #endif
363 flags |= ((6 + 2) << 7);
364 #ifdef TCL_WRAPPER
365 XcInternalTagCall(xcinterp, 3, "label", "encoding", "ISO8859-5");
366 #else
367 snprintf(estr, sizeof(estr), "ISO-8859-5");
368 makenewencodingbutton(estr, (char)8);
369 #endif
372 /* Make space for the font encoding vector */
374 encoding = (objectptr *)malloc(256 * sizeof(objectptr));
375 eptr = encoding;
377 while (fgets(temp, 249, fd) != NULL) {
378 char *temp2 = temp;
379 while (*temp2 != '\0') {
380 if ((int)(eptr - encoding) == 256) break;
381 sscanf(temp2, "%99s", tempname);
382 *eptr = (objectptr) NULL;
383 for (j = xobjs.fontlib.library; j < xobjs.fontlib.library +
384 xobjs.fontlib.number; j++) {
385 if (!strcmp(tempname, (*j)->name)) {
386 *eptr = (*j);
387 break;
390 if (j == xobjs.fontlib.library + xobjs.fontlib.number) {
391 Fprintf(stdout, "Font load warning: character \"%s\" at code ",
392 tempname);
393 Fprintf(stdout, "position %d not found.\n", (int)(eptr - encoding));
395 eptr++;
396 while (*temp2 != ' ' && *temp2 != '\n' && *temp2 != '\0') temp2++;
397 while (*temp2 == ' ' || *temp2 == '\n') temp2++;
399 if ((int)(eptr - encoding) == 256) break;
401 if ((int)(eptr - encoding) != 256) {
402 Fprintf(stdout, "Font load warning: Only %d characters encoded.\n",
403 (int)(eptr - encoding));
404 while (eptr < encoding + 256)
405 *eptr++ = (objectptr) NULL;
408 /* If successful, register the font */
410 fonts = (fontinfo *) realloc (fonts, (fontcount + 1) * sizeof(fontinfo));
411 fonts[fontcount].psname = psname;
412 if (family == NULL)
413 fonts[fontcount].family = psname;
414 else
415 fonts[fontcount].family = family;
416 fonts[fontcount].encoding = encoding;
417 fonts[fontcount].flags = flags;
418 fonts[fontcount].scale = fontscale;
419 #ifdef HAVE_CAIRO
420 fonts[fontcount].utf8encoding = utf8enc;
421 xc_cairo_set_fontinfo(fontcount);
422 #endif /* HAVE_CAIRO */
423 fontcount++;
425 /* Create a new menu button for the font family, if this is the first */
426 /* (In Tcl, this just registers the family name for cycling through */
427 /* via Alt-F; the menu update is done via command tag callback). */
429 for (i = 0; i < fontcount - 1; i++)
430 if (!strcmp(fonts[i].family, fonts[fontcount - 1].family))
431 break;
433 if (i == fontcount - 1)
434 makenewfontbutton();
437 fclose(fd);
438 free(fontname);
439 return 1;