dirfile.c revision 7f7f5e4e
1/* $Xorg: dirfile.c,v 1.4 2001/02/09 02:04:03 xorgcvs Exp $ */ 2 3/* 4 5Copyright 1991, 1998 The Open Group 6 7Permission to use, copy, modify, distribute, and sell this software and its 8documentation for any purpose is hereby granted without fee, provided that 9the above copyright notice appear in all copies and that both that 10copyright notice and this permission notice appear in supporting 11documentation. 12 13The above copyright notice and this permission notice shall be included in 14all copies or substantial portions of the Software. 15 16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 20AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 23Except as contained in this notice, the name of The Open Group shall not be 24used in advertising or otherwise to promote the sale, use or other dealings 25in this Software without prior written authorization from The Open Group. 26 27*/ 28/* $XFree86: xc/lib/font/fontfile/dirfile.c,v 3.17 2004/02/08 01:52:27 dawes Exp $ */ 29 30/* 31 * Author: Keith Packard, MIT X Consortium 32 */ 33 34/* 35 * dirfile.c 36 * 37 * Read fonts.dir and fonts.alias files 38 */ 39 40#ifdef HAVE_CONFIG_H 41#include <config.h> 42#endif 43#include <X11/fonts/fntfilst.h> 44#include <stdio.h> 45#include <sys/types.h> 46#include <sys/stat.h> 47#include <errno.h> 48 49static Bool AddFileNameAliases ( FontDirectoryPtr dir ); 50static int ReadFontAlias ( char *directory, Bool isFile, 51 FontDirectoryPtr *pdir ); 52static int lexAlias ( FILE *file, char **lexToken ); 53static int lexc ( FILE *file ); 54 55int 56FontFileReadDirectory (char *directory, FontDirectoryPtr *pdir) 57{ 58 char file_name[MAXFONTFILENAMELEN]; 59 char font_name[MAXFONTNAMELEN]; 60 char dir_file[MAXFONTFILENAMELEN]; 61 char dir_path[MAXFONTFILENAMELEN]; 62 char *ptr; 63 FILE *file; 64 int count, 65 num_fonts, 66 status; 67 struct stat statb; 68 static char format[24] = ""; 69#if defined(WIN32) 70 int i; 71#endif 72 73 FontDirectoryPtr dir = NullFontDirectory; 74 75 if (strlen(directory) + 1 + sizeof(FontDirFile) > sizeof(dir_file)) 76 return BadFontPath; 77 78 /* Check for font directory attributes */ 79#if !defined(WIN32) 80 if ((ptr = strchr(directory, ':'))) { 81#else 82 /* OS/2 and WIN32 path might start with a drive letter, don't clip this */ 83 if ((ptr = strchr(directory+2, ':'))) { 84#endif 85 strncpy(dir_path, directory, ptr - directory); 86 dir_path[ptr - directory] = '\0'; 87 } else { 88 strcpy(dir_path, directory); 89 } 90 strcpy(dir_file, dir_path); 91 if (dir_file[strlen(dir_file) - 1] != '/') 92 strcat(dir_file, "/"); 93 strcat(dir_file, FontDirFile); 94 file = fopen(dir_file, "rt"); 95 if (file) { 96#ifndef WIN32 97 if (fstat (fileno(file), &statb) == -1) 98#else 99 if (stat (dir_file, &statb) == -1) 100#endif 101 { 102 fclose(file); 103 return BadFontPath; 104 } 105 count = fscanf(file, "%d\n", &num_fonts); 106 if ((count == EOF) || (count != 1)) { 107 fclose(file); 108 return BadFontPath; 109 } 110 dir = FontFileMakeDir(directory, num_fonts); 111 if (dir == NULL) { 112 fclose(file); 113 return BadFontPath; 114 } 115 dir->dir_mtime = statb.st_mtime; 116 if (format[0] == '\0') 117 sprintf(format, "%%%ds %%%d[^\n]\n", 118 MAXFONTFILENAMELEN-1, MAXFONTNAMELEN-1); 119 120 while ((count = fscanf(file, format, file_name, font_name)) != EOF) { 121#if defined(WIN32) 122 /* strip any existing trailing CR */ 123 for (i=0; i<strlen(font_name); i++) { 124 if (font_name[i]=='\r') font_name[i] = '\0'; 125 } 126#endif 127 if (count != 2) { 128 FontFileFreeDir (dir); 129 fclose(file); 130 return BadFontPath; 131 } 132 133 /* 134 * We blindly try to load all the font files specified. 135 * In theory, we might want to warn that some of the fonts 136 * couldn't be loaded. 137 */ 138 FontFileAddFontFile (dir, font_name, file_name); 139 } 140 fclose(file); 141 142 } else if (errno != ENOENT) { 143 return BadFontPath; 144 } 145 status = ReadFontAlias(dir_path, FALSE, &dir); 146 if (status != Successful) { 147 if (dir) 148 FontFileFreeDir (dir); 149 return status; 150 } 151 if (!dir) 152 return BadFontPath; 153 154 FontFileSortDir(dir); 155 156 *pdir = dir; 157 return Successful; 158} 159 160Bool 161FontFileDirectoryChanged(FontDirectoryPtr dir) 162{ 163 char dir_file[MAXFONTFILENAMELEN]; 164 struct stat statb; 165 166 if (strlen(dir->directory) + sizeof(FontDirFile) > sizeof(dir_file)) 167 return FALSE; 168 169 strcpy (dir_file, dir->directory); 170 strcat (dir_file, FontDirFile); 171 if (stat (dir_file, &statb) == -1) 172 { 173 if (errno != ENOENT || dir->dir_mtime != 0) 174 return TRUE; 175 return FALSE; /* doesn't exist and never did: no change */ 176 } 177 if (dir->dir_mtime != statb.st_mtime) 178 return TRUE; 179 180 if ((strlen(dir->directory) + sizeof(FontAliasFile)) > sizeof(dir_file)) 181 return FALSE; 182 strcpy (dir_file, dir->directory); 183 strcat (dir_file, FontAliasFile); 184 if (stat (dir_file, &statb) == -1) 185 { 186 if (errno != ENOENT || dir->alias_mtime != 0) 187 return TRUE; 188 return FALSE; /* doesn't exist and never did: no change */ 189 } 190 if (dir->alias_mtime != statb.st_mtime) 191 return TRUE; 192 return FALSE; 193} 194 195/* 196 * Make each of the file names an automatic alias for each of the files. 197 */ 198 199static Bool 200AddFileNameAliases(FontDirectoryPtr dir) 201{ 202 int i; 203 char copy[MAXFONTFILENAMELEN]; 204 char *fileName; 205 FontTablePtr table; 206 FontRendererPtr renderer; 207 int len; 208 FontNameRec name; 209 210 table = &dir->nonScalable; 211 for (i = 0; i < table->used; i++) { 212 if (table->entries[i].type != FONT_ENTRY_BITMAP) 213 continue; 214 fileName = table->entries[i].u.bitmap.fileName; 215 renderer = FontFileMatchRenderer (fileName); 216 if (!renderer) 217 continue; 218 219 len = strlen (fileName) - renderer->fileSuffixLen; 220 if (len >= sizeof(copy)) 221 continue; 222 CopyISOLatin1Lowered (copy, fileName, len); 223 copy[len] = '\0'; 224 name.name = copy; 225 name.length = len; 226 name.ndashes = FontFileCountDashes (copy, len); 227 228 if (!FontFileFindNameInDir(table, &name)) { 229 if (!FontFileAddFontAlias (dir, copy, table->entries[i].name.name)) 230 return FALSE; 231 } 232 } 233 return TRUE; 234} 235 236/* 237 * parse the font.alias file. Format is: 238 * 239 * alias font-name 240 * 241 * To imbed white-space in an alias name, enclose it like "font name" 242 * in double quotes. \ escapes and character, so 243 * "font name \"With Double Quotes\" \\ and \\ back-slashes" 244 * works just fine. 245 * 246 * A line beginning with a ! denotes a newline-terminated comment. 247 */ 248 249/* 250 * token types 251 */ 252 253#define NAME 0 254#define NEWLINE 1 255#define DONE 2 256#define EALLOC 3 257 258static int 259ReadFontAlias(char *directory, Bool isFile, FontDirectoryPtr *pdir) 260{ 261 char alias[MAXFONTNAMELEN]; 262 char font_name[MAXFONTNAMELEN]; 263 char alias_file[MAXFONTFILENAMELEN]; 264 FILE *file; 265 FontDirectoryPtr dir; 266 int token; 267 char *lexToken; 268 int status = Successful; 269 struct stat statb; 270 271 if (strlen(directory) >= sizeof(alias_file)) 272 return BadFontPath; 273 dir = *pdir; 274 strcpy(alias_file, directory); 275 if (!isFile) { 276 if (strlen(directory) + 1 + sizeof(FontAliasFile) > sizeof(alias_file)) 277 return BadFontPath; 278 if (directory[strlen(directory) - 1] != '/') 279 strcat(alias_file, "/"); 280 strcat(alias_file, FontAliasFile); 281 } 282 file = fopen(alias_file, "rt"); 283 if (!file) 284 return ((errno == ENOENT) ? Successful : BadFontPath); 285 if (!dir) 286 *pdir = dir = FontFileMakeDir(directory, 10); 287 if (!dir) 288 { 289 fclose (file); 290 return AllocError; 291 } 292#ifndef WIN32 293 if (fstat (fileno (file), &statb) == -1) 294#else 295 if (stat (alias_file, &statb) == -1) 296#endif 297 { 298 fclose (file); 299 return BadFontPath; 300 } 301 dir->alias_mtime = statb.st_mtime; 302 while (status == Successful) { 303 token = lexAlias(file, &lexToken); 304 switch (token) { 305 case NEWLINE: 306 break; 307 case DONE: 308 fclose(file); 309 return Successful; 310 case EALLOC: 311 status = AllocError; 312 break; 313 case NAME: 314 if (strlen(lexToken) >= sizeof(alias)) { 315 status = BadFontPath; 316 break; 317 } 318 strcpy(alias, lexToken); 319 token = lexAlias(file, &lexToken); 320 switch (token) { 321 case NEWLINE: 322 if (strcmp(alias, "FILE_NAMES_ALIASES")) 323 status = BadFontPath; 324 else if (!AddFileNameAliases(dir)) 325 status = AllocError; 326 break; 327 case DONE: 328 status = BadFontPath; 329 break; 330 case EALLOC: 331 status = AllocError; 332 break; 333 case NAME: 334 if (strlen(lexToken) >= sizeof(font_name)) { 335 status = BadFontPath; 336 break; 337 } 338 CopyISOLatin1Lowered(alias, alias, strlen(alias)); 339 CopyISOLatin1Lowered(font_name, lexToken, strlen(lexToken)); 340 if (!FontFileAddFontAlias (dir, alias, font_name)) 341 status = AllocError; 342 break; 343 } 344 } 345 } 346 fclose(file); 347 return status; 348} 349 350#define QUOTE 0 351#define WHITE 1 352#define NORMAL 2 353#define END 3 354#define NL 4 355#define BANG 5 356 357static int charClass; 358 359static int 360lexAlias(FILE *file, char **lexToken) 361{ 362 int c; 363 char *t; 364 enum state { 365 Begin, Normal, Quoted, Comment 366 } state; 367 int count; 368 369 static char *tokenBuf = (char *) NULL; 370 static int tokenSize = 0; 371 372 t = tokenBuf; 373 count = 0; 374 state = Begin; 375 for (;;) { 376 if (count == tokenSize) { 377 int nsize; 378 char *nbuf; 379 380 nsize = tokenSize ? (tokenSize << 1) : 64; 381 nbuf = realloc(tokenBuf, nsize); 382 if (!nbuf) 383 return EALLOC; 384 tokenBuf = nbuf; 385 tokenSize = nsize; 386 t = tokenBuf + count; 387 } 388 c = lexc(file); 389 switch (charClass) { 390 case QUOTE: 391 switch (state) { 392 case Begin: 393 case Normal: 394 state = Quoted; 395 break; 396 case Quoted: 397 state = Normal; 398 break; 399 case Comment: 400 break; 401 } 402 break; 403 case WHITE: 404 switch (state) { 405 case Begin: 406 case Comment: 407 continue; 408 case Normal: 409 *t = '\0'; 410 *lexToken = tokenBuf; 411 return NAME; 412 case Quoted: 413 break; 414 } 415 /* fall through */ 416 case NORMAL: 417 switch (state) { 418 case Begin: 419 state = Normal; 420 break; 421 case Comment: 422 continue; 423 default: 424 break; 425 } 426 *t++ = c; 427 ++count; 428 break; 429 case END: 430 case NL: 431 switch (state) { 432 case Begin: 433 case Comment: 434 *lexToken = (char *) NULL; 435 return charClass == END ? DONE : NEWLINE; 436 default: 437 *t = '\0'; 438 *lexToken = tokenBuf; 439 ungetc(c, file); 440 return NAME; 441 } 442 break; 443 case BANG: 444 switch (state) { 445 case Begin: 446 state = Comment; 447 break; 448 case Comment: 449 break; 450 default: 451 *t++ = c; 452 ++count; 453 } 454 break; 455 } 456 } 457} 458 459static int 460lexc(FILE *file) 461{ 462 int c; 463 464 c = getc(file); 465 switch (c) { 466 case EOF: 467 charClass = END; 468 break; 469 case '\\': 470 c = getc(file); 471 if (c == EOF) 472 charClass = END; 473 else 474 charClass = NORMAL; 475 break; 476 case '"': 477 charClass = QUOTE; 478 break; 479 case ' ': 480 case '\t': 481 charClass = WHITE; 482 break; 483 case '\r': 484 case '\n': 485 charClass = NL; 486 break; 487 case '!': 488 charClass = BANG; 489 break; 490 default: 491 charClass = NORMAL; 492 break; 493 } 494 return c; 495} 496