dirfile.c revision 0b332824
1/* 2 3Copyright 1991, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21Except as contained in this notice, the name of The Open Group shall not be 22used in advertising or otherwise to promote the sale, use or other dealings 23in this Software without prior written authorization from The Open Group. 24 25*/ 26 27/* 28 * Author: Keith Packard, MIT X Consortium 29 */ 30 31/* 32 * dirfile.c 33 * 34 * Read fonts.dir and fonts.alias files 35 */ 36 37#ifdef HAVE_CONFIG_H 38#include <config.h> 39#endif 40#include <X11/fonts/fntfilst.h> 41#include <stdio.h> 42#include <sys/types.h> 43#include <sys/stat.h> 44#include <errno.h> 45#include <limits.h> 46 47static Bool AddFileNameAliases ( FontDirectoryPtr dir ); 48static int ReadFontAlias ( char *directory, Bool isFile, 49 FontDirectoryPtr *pdir ); 50static int lexAlias ( FILE *file, char **lexToken ); 51static int lexc ( FILE *file ); 52 53#pragma GCC diagnostic ignored "-Wformat-nonliteral" 54 55int 56FontFileReadDirectory (const 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 if (tokenSize >= (INT_MAX >> 2)) 381 /* Stop before we overflow */ 382 return EALLOC; 383 nsize = tokenSize ? (tokenSize << 1) : 64; 384 nbuf = realloc(tokenBuf, nsize); 385 if (!nbuf) 386 return EALLOC; 387 tokenBuf = nbuf; 388 tokenSize = nsize; 389 t = tokenBuf + count; 390 } 391 c = lexc(file); 392 switch (charClass) { 393 case QUOTE: 394 switch (state) { 395 case Begin: 396 case Normal: 397 state = Quoted; 398 break; 399 case Quoted: 400 state = Normal; 401 break; 402 case Comment: 403 break; 404 } 405 break; 406 case WHITE: 407 switch (state) { 408 case Begin: 409 case Comment: 410 continue; 411 case Normal: 412 *t = '\0'; 413 *lexToken = tokenBuf; 414 return NAME; 415 case Quoted: 416 break; 417 } 418 /* fall through */ 419 case NORMAL: 420 switch (state) { 421 case Begin: 422 state = Normal; 423 break; 424 case Comment: 425 continue; 426 default: 427 break; 428 } 429 *t++ = c; 430 ++count; 431 break; 432 case END: 433 case NL: 434 switch (state) { 435 case Begin: 436 case Comment: 437 *lexToken = (char *) NULL; 438 return charClass == END ? DONE : NEWLINE; 439 default: 440 *t = '\0'; 441 *lexToken = tokenBuf; 442 ungetc(c, file); 443 return NAME; 444 } 445 break; 446 case BANG: 447 switch (state) { 448 case Begin: 449 state = Comment; 450 break; 451 case Comment: 452 break; 453 default: 454 *t++ = c; 455 ++count; 456 } 457 break; 458 } 459 } 460} 461 462static int 463lexc(FILE *file) 464{ 465 int c; 466 467 c = getc(file); 468 switch (c) { 469 case EOF: 470 charClass = END; 471 break; 472 case '\\': 473 c = getc(file); 474 if (c == EOF) 475 charClass = END; 476 else 477 charClass = NORMAL; 478 break; 479 case '"': 480 charClass = QUOTE; 481 break; 482 case ' ': 483 case '\t': 484 charClass = WHITE; 485 break; 486 case '\r': 487 case '\n': 488 charClass = NL; 489 break; 490 case '!': 491 charClass = BANG; 492 break; 493 default: 494 charClass = NORMAL; 495 break; 496 } 497 return c; 498} 499