fcdir.c revision 37d6d98f
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 <dirent.h> 27 28FcBool 29FcFileIsDir (const FcChar8 *file) 30{ 31 struct stat statb; 32 33 if (FcStat (file, &statb) != 0) 34 return FcFalse; 35 return S_ISDIR(statb.st_mode); 36} 37 38FcBool 39FcFileIsLink (const FcChar8 *file) 40{ 41#if HAVE_LSTAT 42 struct stat statb; 43 44 if (lstat ((const char *)file, &statb) != 0) 45 return FcFalse; 46 return S_ISLNK (statb.st_mode); 47#else 48 return FcFalse; 49#endif 50} 51 52FcBool 53FcFileIsFile (const FcChar8 *file) 54{ 55 struct stat statb; 56 57 if (FcStat (file, &statb) != 0) 58 return FcFalse; 59 return S_ISREG (statb.st_mode); 60} 61 62static FcBool 63FcFileScanFontConfig (FcFontSet *set, 64 const FcChar8 *file, 65 FcConfig *config) 66{ 67 int i; 68 FcBool ret = FcTrue; 69 int old_nfont = set->nfont; 70 const FcChar8 *sysroot = FcConfigGetSysRoot (config); 71 72 if (FcDebug () & FC_DBG_SCAN) 73 { 74 printf ("\tScanning file %s...", file); 75 fflush (stdout); 76 } 77 78 if (!FcFreeTypeQueryAll (file, -1, NULL, NULL, set)) 79 return FcFalse; 80 81 if (FcDebug () & FC_DBG_SCAN) 82 printf ("done\n"); 83 84 for (i = old_nfont; i < set->nfont; i++) 85 { 86 FcPattern *font = set->fonts[i]; 87 88 /* 89 * Get rid of sysroot here so that targeting scan rule may contains FC_FILE pattern 90 * and they should usually expect without sysroot. 91 */ 92 if (sysroot) 93 { 94 size_t len = strlen ((const char *)sysroot); 95 FcChar8 *f = NULL; 96 97 if (FcPatternObjectGetString (font, FC_FILE_OBJECT, 0, &f) == FcResultMatch && 98 strncmp ((const char *)f, (const char *)sysroot, len) == 0) 99 { 100 FcChar8 *s = FcStrdup (f); 101 FcPatternObjectDel (font, FC_FILE_OBJECT); 102 if (s[len] != '/') 103 len--; 104 else if (s[len+1] == '/') 105 len++; 106 FcPatternObjectAddString (font, FC_FILE_OBJECT, &s[len]); 107 FcStrFree (s); 108 } 109 } 110 111 /* 112 * Edit pattern with user-defined rules 113 */ 114 if (config && !FcConfigSubstitute (config, font, FcMatchScan)) 115 ret = FcFalse; 116 117 if (FcDebug() & FC_DBG_SCANV) 118 { 119 printf ("Final font pattern:\n"); 120 FcPatternPrint (font); 121 } 122 } 123 124 return ret; 125} 126 127FcBool 128FcFileScanConfig (FcFontSet *set, 129 FcStrSet *dirs, 130 const FcChar8 *file, 131 FcConfig *config) 132{ 133 if (FcFileIsDir (file)) 134 { 135 const FcChar8 *sysroot = FcConfigGetSysRoot (config); 136 const FcChar8 *d = file; 137 size_t len; 138 139 if (sysroot) 140 { 141 len = strlen ((const char *)sysroot); 142 if (strncmp ((const char *)file, (const char *)sysroot, len) == 0) 143 { 144 if (file[len] != '/') 145 len--; 146 else if (file[len+1] == '/') 147 len++; 148 d = &file[len]; 149 } 150 } 151 return FcStrSetAdd (dirs, d); 152 } 153 else 154 { 155 if (set) 156 return FcFileScanFontConfig (set, file, config); 157 else 158 return FcTrue; 159 } 160} 161 162FcBool 163FcFileScan (FcFontSet *set, 164 FcStrSet *dirs, 165 FcFileCache *cache FC_UNUSED, 166 FcBlanks *blanks FC_UNUSED, 167 const FcChar8 *file, 168 FcBool force FC_UNUSED) 169{ 170 return FcFileScanConfig (set, dirs, file, FcConfigGetCurrent ()); 171} 172 173/* 174 * Strcmp helper that takes pointers to pointers, copied from qsort(3) manpage 175 */ 176static int 177cmpstringp(const void *p1, const void *p2) 178{ 179 return strcmp(* (char **) p1, * (char **) p2); 180} 181 182FcBool 183FcDirScanConfig (FcFontSet *set, 184 FcStrSet *dirs, 185 const FcChar8 *dir, 186 FcBool force, /* XXX unused */ 187 FcConfig *config) 188{ 189 DIR *d; 190 struct dirent *e; 191 FcStrSet *files; 192 FcChar8 *file; 193 FcChar8 *base; 194 FcBool ret = FcTrue; 195 int i; 196 197 if (!force) 198 return FcFalse; 199 200 if (!set && !dirs) 201 return FcTrue; 202 203 /* freed below */ 204 file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1); 205 if (!file) { 206 ret = FcFalse; 207 goto bail; 208 } 209 210 strcpy ((char *) file, (char *) dir); 211 strcat ((char *) file, "/"); 212 base = file + strlen ((char *) file); 213 214 if (FcDebug () & FC_DBG_SCAN) 215 printf ("\tScanning dir %s\n", dir); 216 217 d = opendir ((char *) dir); 218 if (!d) 219 { 220 /* Don't complain about missing directories */ 221 if (errno != ENOENT) 222 ret = FcFalse; 223 goto bail; 224 } 225 226 files = FcStrSetCreateEx (FCSS_ALLOW_DUPLICATES | FCSS_GROW_BY_64); 227 if (!files) 228 { 229 ret = FcFalse; 230 goto bail1; 231 } 232 while ((e = readdir (d))) 233 { 234 if (e->d_name[0] != '.' && strlen (e->d_name) < FC_MAX_FILE_LEN) 235 { 236 strcpy ((char *) base, (char *) e->d_name); 237 if (!FcStrSetAdd (files, file)) { 238 ret = FcFalse; 239 goto bail2; 240 } 241 } 242 } 243 244 /* 245 * Sort files to make things prettier 246 */ 247 qsort(files->strs, files->num, sizeof(FcChar8 *), cmpstringp); 248 249 /* 250 * Scan file files to build font patterns 251 */ 252 for (i = 0; i < files->num; i++) 253 FcFileScanConfig (set, dirs, files->strs[i], config); 254 255bail2: 256 FcStrSetDestroy (files); 257bail1: 258 closedir (d); 259bail: 260 if (file) 261 free (file); 262 263 return ret; 264} 265 266FcBool 267FcDirScan (FcFontSet *set, 268 FcStrSet *dirs, 269 FcFileCache *cache FC_UNUSED, 270 FcBlanks *blanks FC_UNUSED, 271 const FcChar8 *dir, 272 FcBool force FC_UNUSED) 273{ 274 if (cache || !force) 275 return FcFalse; 276 277 return FcDirScanConfig (set, dirs, dir, force, FcConfigGetCurrent ()); 278} 279 280/* 281 * Scan the specified directory and construct a cache of its contents 282 */ 283FcCache * 284FcDirCacheScan (const FcChar8 *dir, FcConfig *config) 285{ 286 FcStrSet *dirs; 287 FcFontSet *set; 288 FcCache *cache = NULL; 289 struct stat dir_stat; 290 const FcChar8 *sysroot = FcConfigGetSysRoot (config); 291 FcChar8 *d; 292#ifndef _WIN32 293 int fd = -1; 294#endif 295 296 if (sysroot) 297 d = FcStrBuildFilename (sysroot, dir, NULL); 298 else 299 d = FcStrdup (dir); 300 301 if (FcDebug () & FC_DBG_FONTSET) 302 printf ("cache scan dir %s\n", d); 303 304 if (FcStatChecksum (d, &dir_stat) < 0) 305 goto bail; 306 307 set = FcFontSetCreate(); 308 if (!set) 309 goto bail; 310 311 dirs = FcStrSetCreateEx (FCSS_GROW_BY_64); 312 if (!dirs) 313 goto bail1; 314 315#ifndef _WIN32 316 fd = FcDirCacheLock (dir, config); 317#endif 318 /* 319 * Scan the dir 320 */ 321 if (!FcDirScanConfig (set, dirs, d, FcTrue, config)) 322 goto bail2; 323 324 /* 325 * Build the cache object 326 */ 327 cache = FcDirCacheBuild (set, dir, &dir_stat, dirs); 328 if (!cache) 329 goto bail2; 330 331 /* 332 * Write out the cache file, ignoring any troubles 333 */ 334 FcDirCacheWrite (cache, config); 335 336 bail2: 337#ifndef _WIN32 338 FcDirCacheUnlock (fd); 339#endif 340 FcStrSetDestroy (dirs); 341 bail1: 342 FcFontSetDestroy (set); 343 bail: 344 FcStrFree (d); 345 346 return cache; 347} 348 349FcCache * 350FcDirCacheRescan (const FcChar8 *dir, FcConfig *config) 351{ 352 FcCache *cache; 353 FcCache *new = NULL; 354 struct stat dir_stat; 355 FcStrSet *dirs; 356 const FcChar8 *sysroot = FcConfigGetSysRoot (config); 357 FcChar8 *d = NULL; 358#ifndef _WIN32 359 int fd = -1; 360#endif 361 362 cache = FcDirCacheLoad (dir, config, NULL); 363 if (!cache) 364 goto bail; 365 366 if (sysroot) 367 d = FcStrBuildFilename (sysroot, dir, NULL); 368 else 369 d = FcStrdup (dir); 370 if (FcStatChecksum (d, &dir_stat) < 0) 371 goto bail; 372 dirs = FcStrSetCreateEx (FCSS_GROW_BY_64); 373 if (!dirs) 374 goto bail; 375 376#ifndef _WIN32 377 fd = FcDirCacheLock (dir, config); 378#endif 379 /* 380 * Scan the dir 381 */ 382 if (!FcDirScanConfig (NULL, dirs, d, FcTrue, config)) 383 goto bail1; 384 /* 385 * Rebuild the cache object 386 */ 387 new = FcDirCacheRebuild (cache, &dir_stat, dirs); 388 if (!new) 389 goto bail1; 390 FcDirCacheUnload (cache); 391 /* 392 * Write out the cache file, ignoring any troubles 393 */ 394 FcDirCacheWrite (new, config); 395 396bail1: 397#ifndef _WIN32 398 FcDirCacheUnlock (fd); 399#endif 400 FcStrSetDestroy (dirs); 401bail: 402 if (d) 403 FcStrFree (d); 404 405 return new; 406} 407 408/* 409 * Read (or construct) the cache for a directory 410 */ 411FcCache * 412FcDirCacheRead (const FcChar8 *dir, FcBool force, FcConfig *config) 413{ 414 FcCache *cache = NULL; 415 416 FcDirCacheCreateUUID ((FcChar8 *) dir, FcFalse, config); 417 /* Try to use existing cache file */ 418 if (!force) 419 cache = FcDirCacheLoad (dir, config, NULL); 420 421 /* Not using existing cache file, construct new cache */ 422 if (!cache) 423 cache = FcDirCacheScan (dir, config); 424 425 return cache; 426} 427 428FcBool 429FcDirSave (FcFontSet *set FC_UNUSED, FcStrSet * dirs FC_UNUSED, const FcChar8 *dir FC_UNUSED) 430{ 431 return FcFalse; /* XXX deprecated */ 432} 433#define __fcdir__ 434#include "fcaliastail.h" 435#undef __fcdir__ 436