fcdir.c revision 953daeba
1/* 2 * fontconfig/src/fcdir.c 3 * 4 * Copyright © 2000 Keith Packard 5 * 6 * Permission to use, copy, modify, distribute, and sell this software and its 7 * documentation for any purpose is hereby granted without fee, provided that 8 * the above copyright notice appear in all copies and that both that 9 * copyright notice and this permission notice appear in supporting 10 * documentation, and that the name of the author(s) not be used in 11 * advertising or publicity pertaining to distribution of the software without 12 * specific, written prior permission. The authors make no 13 * representations about the suitability of this software for any purpose. It 14 * is provided "as is" without express or implied warranty. 15 * 16 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 18 * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR 19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 22 * PERFORMANCE OF THIS SOFTWARE. 23 */ 24 25#include "fcint.h" 26#include "fcftint.h" 27#include <ft2build.h> 28#include FT_FREETYPE_H 29#include <dirent.h> 30 31FcBool 32FcFileIsDir (const FcChar8 *file) 33{ 34 struct stat statb; 35 36 if (FcStat (file, &statb) != 0) 37 return FcFalse; 38 return S_ISDIR(statb.st_mode); 39} 40 41FcBool 42FcFileIsLink (const FcChar8 *file) 43{ 44#if HAVE_LSTAT 45 struct stat statb; 46 47 if (lstat ((const char *)file, &statb) != 0) 48 return FcFalse; 49 return S_ISLNK (statb.st_mode); 50#else 51 return FcFalse; 52#endif 53} 54 55FcBool 56FcFileIsFile (const FcChar8 *file) 57{ 58 struct stat statb; 59 60 if (FcStat (file, &statb) != 0) 61 return FcFalse; 62 return S_ISREG (statb.st_mode); 63} 64 65static FcBool 66FcFileScanFontConfig (FcFontSet *set, 67 FcBlanks *blanks, 68 const FcChar8 *file, 69 FcConfig *config) 70{ 71 FT_Library ftLibrary; 72 FT_Face face; 73 FcPattern *font; 74 FcBool ret = FcTrue; 75 int num_faces = 0; 76 int num_instances = 0; 77 int face_num = 0; 78 int instance_num = 0; 79 int id; 80 const FcChar8 *sysroot = FcConfigGetSysRoot (config); 81 82 if (FT_Init_FreeType (&ftLibrary)) 83 return FcFalse; 84 85 do 86 { 87 font = 0; 88 /* 89 * Nothing in the cache, scan the file 90 */ 91 if (FcDebug () & FC_DBG_SCAN) 92 { 93 printf ("\tScanning file %s...", file); 94 fflush (stdout); 95 } 96 97 id = ((instance_num << 16) + face_num); 98 if (FT_New_Face (ftLibrary, (char *) file, id, &face)) 99 return FcFalse; 100 num_faces = face->num_faces; 101 num_instances = face->style_flags >> 16; 102 font = FcFreeTypeQueryFace (face, file, id, blanks); 103 FT_Done_Face (face); 104 105 if (FcDebug () & FC_DBG_SCAN) 106 printf ("done\n"); 107 /* 108 * Get rid of sysroot here so that targeting scan rule may contains FC_FILE pattern 109 * and they should usually expect without sysroot. 110 */ 111 if (font && sysroot) 112 { 113 size_t len = strlen ((const char *)sysroot); 114 FcChar8 *f = NULL; 115 116 if (FcPatternObjectGetString (font, FC_FILE_OBJECT, 0, &f) == FcResultMatch && 117 strncmp ((const char *)f, (const char *)sysroot, len) == 0) 118 { 119 FcChar8 *s = FcStrdup (f); 120 FcPatternObjectDel (font, FC_FILE_OBJECT); 121 if (s[len] != '/') 122 len--; 123 else if (s[len+1] == '/') 124 len++; 125 FcPatternObjectAddString (font, FC_FILE_OBJECT, &s[len]); 126 FcStrFree (s); 127 } 128 } 129 130 /* 131 * Edit pattern with user-defined rules 132 */ 133 if (font && config && !FcConfigSubstitute (config, font, FcMatchScan)) 134 { 135 FcPatternDestroy (font); 136 font = NULL; 137 ret = FcFalse; 138 } 139 140 /* 141 * Add the font 142 */ 143 if (font) 144 { 145 if (FcDebug() & FC_DBG_SCANV) 146 { 147 printf ("Final font pattern:\n"); 148 FcPatternPrint (font); 149 } 150 if (!FcFontSetAdd (set, font)) 151 { 152 FcPatternDestroy (font); 153 font = NULL; 154 ret = FcFalse; 155 } 156 } 157 else 158 ret = FcFalse; 159 160 if (instance_num < num_instances) 161 instance_num++; 162 else 163 { 164 face_num++; 165 instance_num = 0; 166 } 167 } while (font && ret && face_num < num_faces); 168 169 FT_Done_FreeType (ftLibrary); 170 171 return ret; 172} 173 174FcBool 175FcFileScanConfig (FcFontSet *set, 176 FcStrSet *dirs, 177 FcBlanks *blanks, 178 const FcChar8 *file, 179 FcConfig *config) 180{ 181 if (FcFileIsDir (file)) 182 { 183 const FcChar8 *sysroot = FcConfigGetSysRoot (config); 184 const FcChar8 *d = file; 185 size_t len; 186 187 if (sysroot) 188 { 189 len = strlen ((const char *)sysroot); 190 if (strncmp ((const char *)file, (const char *)sysroot, len) == 0) 191 { 192 if (file[len] != '/') 193 len--; 194 else if (file[len+1] == '/') 195 len++; 196 d = &file[len]; 197 } 198 } 199 return FcStrSetAdd (dirs, d); 200 } 201 else 202 { 203 if (set) 204 return FcFileScanFontConfig (set, blanks, file, config); 205 else 206 return FcTrue; 207 } 208} 209 210FcBool 211FcFileScan (FcFontSet *set, 212 FcStrSet *dirs, 213 FcFileCache *cache FC_UNUSED, 214 FcBlanks *blanks, 215 const FcChar8 *file, 216 FcBool force FC_UNUSED) 217{ 218 return FcFileScanConfig (set, dirs, blanks, file, FcConfigGetCurrent ()); 219} 220 221/* 222 * Strcmp helper that takes pointers to pointers, copied from qsort(3) manpage 223 */ 224static int 225cmpstringp(const void *p1, const void *p2) 226{ 227 return strcmp(* (char **) p1, * (char **) p2); 228} 229 230FcBool 231FcDirScanConfig (FcFontSet *set, 232 FcStrSet *dirs, 233 FcBlanks *blanks, 234 const FcChar8 *dir, 235 FcBool force, /* XXX unused */ 236 FcConfig *config) 237{ 238 DIR *d; 239 struct dirent *e; 240 FcStrSet *files; 241 FcChar8 *file; 242 FcChar8 *base; 243 FcBool ret = FcTrue; 244 int i; 245 246 if (!force) 247 return FcFalse; 248 249 if (!set && !dirs) 250 return FcTrue; 251 252 if (!blanks) 253 blanks = FcConfigGetBlanks (config); 254 255 /* freed below */ 256 file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1); 257 if (!file) { 258 ret = FcFalse; 259 goto bail; 260 } 261 262 strcpy ((char *) file, (char *) dir); 263 strcat ((char *) file, "/"); 264 base = file + strlen ((char *) file); 265 266 if (FcDebug () & FC_DBG_SCAN) 267 printf ("\tScanning dir %s\n", dir); 268 269 d = opendir ((char *) dir); 270 if (!d) 271 { 272 /* Don't complain about missing directories */ 273 if (errno != ENOENT) 274 ret = FcFalse; 275 goto bail; 276 } 277 278 files = FcStrSetCreateEx (FCSS_ALLOW_DUPLICATES | FCSS_GROW_BY_64); 279 if (!files) 280 { 281 ret = FcFalse; 282 goto bail1; 283 } 284 while ((e = readdir (d))) 285 { 286 if (e->d_name[0] != '.' && strlen (e->d_name) < FC_MAX_FILE_LEN) 287 { 288 strcpy ((char *) base, (char *) e->d_name); 289 if (!FcStrSetAdd (files, file)) { 290 ret = FcFalse; 291 goto bail2; 292 } 293 } 294 } 295 296 /* 297 * Sort files to make things prettier 298 */ 299 qsort(files->strs, files->num, sizeof(FcChar8 *), cmpstringp); 300 301 /* 302 * Scan file files to build font patterns 303 */ 304 for (i = 0; i < files->num; i++) 305 FcFileScanConfig (set, dirs, blanks, files->strs[i], config); 306 307bail2: 308 FcStrSetDestroy (files); 309bail1: 310 closedir (d); 311bail: 312 if (file) 313 free (file); 314 315 return ret; 316} 317 318FcBool 319FcDirScan (FcFontSet *set, 320 FcStrSet *dirs, 321 FcFileCache *cache, /* XXX unused */ 322 FcBlanks *blanks, 323 const FcChar8 *dir, 324 FcBool force /* XXX unused */) 325{ 326 if (cache || !force) 327 return FcFalse; 328 329 return FcDirScanConfig (set, dirs, blanks, dir, force, FcConfigGetCurrent ()); 330} 331 332/* 333 * Scan the specified directory and construct a cache of its contents 334 */ 335FcCache * 336FcDirCacheScan (const FcChar8 *dir, FcConfig *config) 337{ 338 FcStrSet *dirs; 339 FcFontSet *set; 340 FcCache *cache = NULL; 341 struct stat dir_stat; 342 const FcChar8 *sysroot = FcConfigGetSysRoot (config); 343 FcChar8 *d; 344 int fd = -1; 345 346 if (sysroot) 347 d = FcStrBuildFilename (sysroot, dir, NULL); 348 else 349 d = FcStrdup (dir); 350 351 if (FcDebug () & FC_DBG_FONTSET) 352 printf ("cache scan dir %s\n", d); 353 354 if (FcStatChecksum (d, &dir_stat) < 0) 355 goto bail; 356 357 set = FcFontSetCreate(); 358 if (!set) 359 goto bail; 360 361 dirs = FcStrSetCreateEx (FCSS_GROW_BY_64); 362 if (!dirs) 363 goto bail1; 364 365#ifndef _WIN32 366 fd = FcDirCacheLock (dir, config); 367#endif 368 /* 369 * Scan the dir 370 */ 371 if (!FcDirScanConfig (set, dirs, NULL, d, FcTrue, config)) 372 goto bail2; 373 374 /* 375 * Build the cache object 376 */ 377 cache = FcDirCacheBuild (set, dir, &dir_stat, dirs); 378 if (!cache) 379 goto bail2; 380 381 /* 382 * Write out the cache file, ignoring any troubles 383 */ 384 FcDirCacheWrite (cache, config); 385 386 bail2: 387#ifndef _WIN32 388 FcDirCacheUnlock (fd); 389#endif 390 FcStrSetDestroy (dirs); 391 bail1: 392 FcFontSetDestroy (set); 393 bail: 394 FcStrFree (d); 395 396 return cache; 397} 398 399FcCache * 400FcDirCacheRescan (const FcChar8 *dir, FcConfig *config) 401{ 402 FcCache *cache; 403 FcCache *new = NULL; 404 struct stat dir_stat; 405 FcStrSet *dirs; 406 const FcChar8 *sysroot = FcConfigGetSysRoot (config); 407 FcChar8 *d = NULL; 408 int fd = -1; 409 410 cache = FcDirCacheLoad (dir, config, NULL); 411 if (!cache) 412 goto bail; 413 414 if (sysroot) 415 d = FcStrBuildFilename (sysroot, dir, NULL); 416 else 417 d = FcStrdup (dir); 418 if (FcStatChecksum (d, &dir_stat) < 0) 419 goto bail; 420 dirs = FcStrSetCreateEx (FCSS_GROW_BY_64); 421 if (!dirs) 422 goto bail; 423 424#ifndef _WIN32 425 fd = FcDirCacheLock (dir, config); 426#endif 427 /* 428 * Scan the dir 429 */ 430 if (!FcDirScanConfig (NULL, dirs, NULL, d, FcTrue, config)) 431 goto bail1; 432 /* 433 * Rebuild the cache object 434 */ 435 new = FcDirCacheRebuild (cache, &dir_stat, dirs); 436 if (!new) 437 goto bail1; 438 FcDirCacheUnload (cache); 439 /* 440 * Write out the cache file, ignoring any troubles 441 */ 442 FcDirCacheWrite (new, config); 443 444bail1: 445#ifndef _WIN32 446 FcDirCacheUnlock (fd); 447#endif 448 FcStrSetDestroy (dirs); 449bail: 450 if (d) 451 FcStrFree (d); 452 453 return new; 454} 455 456/* 457 * Read (or construct) the cache for a directory 458 */ 459FcCache * 460FcDirCacheRead (const FcChar8 *dir, FcBool force, FcConfig *config) 461{ 462 FcCache *cache = NULL; 463 464 /* Try to use existing cache file */ 465 if (!force) 466 cache = FcDirCacheLoad (dir, config, NULL); 467 468 /* Not using existing cache file, construct new cache */ 469 if (!cache) 470 cache = FcDirCacheScan (dir, config); 471 472 return cache; 473} 474 475FcBool 476FcDirSave (FcFontSet *set FC_UNUSED, FcStrSet * dirs FC_UNUSED, const FcChar8 *dir FC_UNUSED) 477{ 478 return FcFalse; /* XXX deprecated */ 479} 480#define __fcdir__ 481#include "fcaliastail.h" 482#undef __fcdir__ 483