dirfile.c revision 7673729a
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 53int 54FontFileReadDirectory (char *directory, FontDirectoryPtr *pdir) 55{ 56 char file_name[MAXFONTFILENAMELEN]; 57 char font_name[MAXFONTNAMELEN]; 58 char dir_file[MAXFONTFILENAMELEN]; 59 char dir_path[MAXFONTFILENAMELEN]; 60 char *ptr; 61 FILE *file; 62 int count, 63 num_fonts, 64 status; 65 struct stat statb; 66 static char format[24] = ""; 67#if defined(WIN32) 68 int i; 69#endif 70 71 FontDirectoryPtr dir = NullFontDirectory; 72 73 if (strlen(directory) + 1 + sizeof(FontDirFile) > sizeof(dir_file)) 74 return BadFontPath; 75 76 /* Check for font directory attributes */ 77#if !defined(WIN32) 78 if ((ptr = strchr(directory, ':'))) { 79#else 80 /* OS/2 and WIN32 path might start with a drive letter, don't clip this */ 81 if ((ptr = strchr(directory+2, ':'))) { 82#endif 83 strncpy(dir_path, directory, ptr - directory); 84 dir_path[ptr - directory] = '\0'; 85 } else { 86 strcpy(dir_path, directory); 87 } 88 strcpy(dir_file, dir_path); 89 if (dir_file[strlen(dir_file) - 1] != '/') 90 strcat(dir_file, "/"); 91 strcat(dir_file, FontDirFile); 92 file = fopen(dir_file, "rt"); 93 if (file) { 94#ifndef WIN32 95 if (fstat (fileno(file), &statb) == -1) 96#else 97 if (stat (dir_file, &statb) == -1) 98#endif 99 { 100 fclose(file); 101 return BadFontPath; 102 } 103 count = fscanf(file, "%d\n", &num_fonts); 104 if ((count == EOF) || (count != 1)) { 105 fclose(file); 106 return BadFontPath; 107 } 108 dir = FontFileMakeDir(directory, num_fonts); 109 if (dir == NULL) { 110 fclose(file); 111 return BadFontPath; 112 } 113 dir->dir_mtime = statb.st_mtime; 114 if (format[0] == '\0') 115 sprintf(format, "%%%ds %%%d[^\n]\n", 116 MAXFONTFILENAMELEN-1, MAXFONTNAMELEN-1); 117 118 while ((count = fscanf(file, format, file_name, font_name)) != EOF) { 119#if defined(WIN32) 120 /* strip any existing trailing CR */ 121 for (i=0; i<strlen(font_name); i++) { 122 if (font_name[i]=='\r') font_name[i] = '\0'; 123 } 124#endif 125 if (count != 2) { 126 FontFileFreeDir (dir); 127 fclose(file); 128 return BadFontPath; 129 } 130 131 /* 132 * We blindly try to load all the font files specified. 133 * In theory, we might want to warn that some of the fonts 134 * couldn't be loaded. 135 */ 136 FontFileAddFontFile (dir, font_name, file_name); 137 } 138 fclose(file); 139 140 } else if (errno != ENOENT) { 141 return BadFontPath; 142 } 143 status = ReadFontAlias(dir_path, FALSE, &dir); 144 if (status != Successful) { 145 if (dir) 146 FontFileFreeDir (dir); 147 return status; 148 } 149 if (!dir) 150 return BadFontPath; 151 152 FontFileSortDir(dir); 153 154 *pdir = dir; 155 return Successful; 156} 157 158Bool 159FontFileDirectoryChanged(FontDirectoryPtr dir) 160{ 161 char dir_file[MAXFONTFILENAMELEN]; 162 struct stat statb; 163 164 if (strlen(dir->directory) + sizeof(FontDirFile) > sizeof(dir_file)) 165 return FALSE; 166 167 strcpy (dir_file, dir->directory); 168 strcat (dir_file, FontDirFile); 169 if (stat (dir_file, &statb) == -1) 170 { 171 if (errno != ENOENT || dir->dir_mtime != 0) 172 return TRUE; 173 return FALSE; /* doesn't exist and never did: no change */ 174 } 175 if (dir->dir_mtime != statb.st_mtime) 176 return TRUE; 177 178 if ((strlen(dir->directory) + sizeof(FontAliasFile)) > sizeof(dir_file)) 179 return FALSE; 180 strcpy (dir_file, dir->directory); 181 strcat (dir_file, FontAliasFile); 182 if (stat (dir_file, &statb) == -1) 183 { 184 if (errno != ENOENT || dir->alias_mtime != 0) 185 return TRUE; 186 return FALSE; /* doesn't exist and never did: no change */ 187 } 188 if (dir->alias_mtime != statb.st_mtime) 189 return TRUE; 190 return FALSE; 191} 192 193/* 194 * Make each of the file names an automatic alias for each of the files. 195 */ 196 197static Bool 198AddFileNameAliases(FontDirectoryPtr dir) 199{ 200 int i; 201 char copy[MAXFONTFILENAMELEN]; 202 char *fileName; 203 FontTablePtr table; 204 FontRendererPtr renderer; 205 int len; 206 FontNameRec name; 207 208 table = &dir->nonScalable; 209 for (i = 0; i < table->used; i++) { 210 if (table->entries[i].type != FONT_ENTRY_BITMAP) 211 continue; 212 fileName = table->entries[i].u.bitmap.fileName; 213 renderer = FontFileMatchRenderer (fileName); 214 if (!renderer) 215 continue; 216 217 len = strlen (fileName) - renderer->fileSuffixLen; 218 if (len >= sizeof(copy)) 219 continue; 220 CopyISOLatin1Lowered (copy, fileName, len); 221 copy[len] = '\0'; 222 name.name = copy; 223 name.length = len; 224 name.ndashes = FontFileCountDashes (copy, len); 225 226 if (!FontFileFindNameInDir(table, &name)) { 227 if (!FontFileAddFontAlias (dir, copy, table->entries[i].name.name)) 228 return FALSE; 229 } 230 } 231 return TRUE; 232} 233 234/* 235 * parse the font.alias file. Format is: 236 * 237 * alias font-name 238 * 239 * To imbed white-space in an alias name, enclose it like "font name" 240 * in double quotes. \ escapes and character, so 241 * "font name \"With Double Quotes\" \\ and \\ back-slashes" 242 * works just fine. 243 * 244 * A line beginning with a ! denotes a newline-terminated comment. 245 */ 246 247/* 248 * token types 249 */ 250 251#define NAME 0 252#define NEWLINE 1 253#define DONE 2 254#define EALLOC 3 255 256static int 257ReadFontAlias(char *directory, Bool isFile, FontDirectoryPtr *pdir) 258{ 259 char alias[MAXFONTNAMELEN]; 260 char font_name[MAXFONTNAMELEN]; 261 char alias_file[MAXFONTFILENAMELEN]; 262 FILE *file; 263 FontDirectoryPtr dir; 264 int token; 265 char *lexToken; 266 int status = Successful; 267 struct stat statb; 268 269 if (strlen(directory) >= sizeof(alias_file)) 270 return BadFontPath; 271 dir = *pdir; 272 strcpy(alias_file, directory); 273 if (!isFile) { 274 if (strlen(directory) + 1 + sizeof(FontAliasFile) > sizeof(alias_file)) 275 return BadFontPath; 276 if (directory[strlen(directory) - 1] != '/') 277 strcat(alias_file, "/"); 278 strcat(alias_file, FontAliasFile); 279 } 280 file = fopen(alias_file, "rt"); 281 if (!file) 282 return ((errno == ENOENT) ? Successful : BadFontPath); 283 if (!dir) 284 *pdir = dir = FontFileMakeDir(directory, 10); 285 if (!dir) 286 { 287 fclose (file); 288 return AllocError; 289 } 290#ifndef WIN32 291 if (fstat (fileno (file), &statb) == -1) 292#else 293 if (stat (alias_file, &statb) == -1) 294#endif 295 { 296 fclose (file); 297 return BadFontPath; 298 } 299 dir->alias_mtime = statb.st_mtime; 300 while (status == Successful) { 301 token = lexAlias(file, &lexToken); 302 switch (token) { 303 case NEWLINE: 304 break; 305 case DONE: 306 fclose(file); 307 return Successful; 308 case EALLOC: 309 status = AllocError; 310 break; 311 case NAME: 312 if (strlen(lexToken) >= sizeof(alias)) { 313 status = BadFontPath; 314 break; 315 } 316 strcpy(alias, lexToken); 317 token = lexAlias(file, &lexToken); 318 switch (token) { 319 case NEWLINE: 320 if (strcmp(alias, "FILE_NAMES_ALIASES")) 321 status = BadFontPath; 322 else if (!AddFileNameAliases(dir)) 323 status = AllocError; 324 break; 325 case DONE: 326 status = BadFontPath; 327 break; 328 case EALLOC: 329 status = AllocError; 330 break; 331 case NAME: 332 if (strlen(lexToken) >= sizeof(font_name)) { 333 status = BadFontPath; 334 break; 335 } 336 CopyISOLatin1Lowered(alias, alias, strlen(alias)); 337 CopyISOLatin1Lowered(font_name, lexToken, strlen(lexToken)); 338 if (!FontFileAddFontAlias (dir, alias, font_name)) 339 status = AllocError; 340 break; 341 } 342 } 343 } 344 fclose(file); 345 return status; 346} 347 348#define QUOTE 0 349#define WHITE 1 350#define NORMAL 2 351#define END 3 352#define NL 4 353#define BANG 5 354 355static int charClass; 356 357static int 358lexAlias(FILE *file, char **lexToken) 359{ 360 int c; 361 char *t; 362 enum state { 363 Begin, Normal, Quoted, Comment 364 } state; 365 int count; 366 367 static char *tokenBuf = (char *) NULL; 368 static int tokenSize = 0; 369 370 t = tokenBuf; 371 count = 0; 372 state = Begin; 373 for (;;) { 374 if (count == tokenSize) { 375 int nsize; 376 char *nbuf; 377 378 if (tokenSize >= (INT_MAX >> 2)) 379 /* Stop before we overflow */ 380 return EALLOC; 381 nsize = tokenSize ? (tokenSize << 1) : 64; 382 nbuf = realloc(tokenBuf, nsize); 383 if (!nbuf) 384 return EALLOC; 385 tokenBuf = nbuf; 386 tokenSize = nsize; 387 t = tokenBuf + count; 388 } 389 c = lexc(file); 390 switch (charClass) { 391 case QUOTE: 392 switch (state) { 393 case Begin: 394 case Normal: 395 state = Quoted; 396 break; 397 case Quoted: 398 state = Normal; 399 break; 400 case Comment: 401 break; 402 } 403 break; 404 case WHITE: 405 switch (state) { 406 case Begin: 407 case Comment: 408 continue; 409 case Normal: 410 *t = '\0'; 411 *lexToken = tokenBuf; 412 return NAME; 413 case Quoted: 414 break; 415 } 416 /* fall through */ 417 case NORMAL: 418 switch (state) { 419 case Begin: 420 state = Normal; 421 break; 422 case Comment: 423 continue; 424 default: 425 break; 426 } 427 *t++ = c; 428 ++count; 429 break; 430 case END: 431 case NL: 432 switch (state) { 433 case Begin: 434 case Comment: 435 *lexToken = (char *) NULL; 436 return charClass == END ? DONE : NEWLINE; 437 default: 438 *t = '\0'; 439 *lexToken = tokenBuf; 440 ungetc(c, file); 441 return NAME; 442 } 443 break; 444 case BANG: 445 switch (state) { 446 case Begin: 447 state = Comment; 448 break; 449 case Comment: 450 break; 451 default: 452 *t++ = c; 453 ++count; 454 } 455 break; 456 } 457 } 458} 459 460static int 461lexc(FILE *file) 462{ 463 int c; 464 465 c = getc(file); 466 switch (c) { 467 case EOF: 468 charClass = END; 469 break; 470 case '\\': 471 c = getc(file); 472 if (c == EOF) 473 charClass = END; 474 else 475 charClass = NORMAL; 476 break; 477 case '"': 478 charClass = QUOTE; 479 break; 480 case ' ': 481 case '\t': 482 charClass = WHITE; 483 break; 484 case '\r': 485 case '\n': 486 charClass = NL; 487 break; 488 case '!': 489 charClass = BANG; 490 break; 491 default: 492 charClass = NORMAL; 493 break; 494 } 495 return c; 496} 497