fcdir.c revision 953daeba
12c393a42Smrg/* 2a6844aabSmrg * fontconfig/src/fcdir.c 32c393a42Smrg * 42c393a42Smrg * Copyright © 2000 Keith Packard 52c393a42Smrg * 62c393a42Smrg * Permission to use, copy, modify, distribute, and sell this software and its 72c393a42Smrg * documentation for any purpose is hereby granted without fee, provided that 82c393a42Smrg * the above copyright notice appear in all copies and that both that 92c393a42Smrg * copyright notice and this permission notice appear in supporting 10ca08ab68Smrg * documentation, and that the name of the author(s) not be used in 112c393a42Smrg * advertising or publicity pertaining to distribution of the software without 12ca08ab68Smrg * specific, written prior permission. The authors make no 132c393a42Smrg * representations about the suitability of this software for any purpose. It 142c393a42Smrg * is provided "as is" without express or implied warranty. 152c393a42Smrg * 16a6844aabSmrg * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 172c393a42Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 18a6844aabSmrg * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR 192c393a42Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 202c393a42Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 212c393a42Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 222c393a42Smrg * PERFORMANCE OF THIS SOFTWARE. 232c393a42Smrg */ 242c393a42Smrg 252c393a42Smrg#include "fcint.h" 26953daebaSmrg#include "fcftint.h" 27953daebaSmrg#include <ft2build.h> 28953daebaSmrg#include FT_FREETYPE_H 292c393a42Smrg#include <dirent.h> 302c393a42Smrg 312c393a42SmrgFcBool 322c393a42SmrgFcFileIsDir (const FcChar8 *file) 332c393a42Smrg{ 342c393a42Smrg struct stat statb; 352c393a42Smrg 36ca08ab68Smrg if (FcStat (file, &statb) != 0) 372c393a42Smrg return FcFalse; 382c393a42Smrg return S_ISDIR(statb.st_mode); 392c393a42Smrg} 402c393a42Smrg 41c9710b42SmrgFcBool 42c9710b42SmrgFcFileIsLink (const FcChar8 *file) 43c9710b42Smrg{ 44c9710b42Smrg#if HAVE_LSTAT 45c9710b42Smrg struct stat statb; 46c9710b42Smrg 47c9710b42Smrg if (lstat ((const char *)file, &statb) != 0) 48c9710b42Smrg return FcFalse; 49c9710b42Smrg return S_ISLNK (statb.st_mode); 50c9710b42Smrg#else 51c9710b42Smrg return FcFalse; 52c9710b42Smrg#endif 53c9710b42Smrg} 54c9710b42Smrg 556fc018e4SmrgFcBool 566fc018e4SmrgFcFileIsFile (const FcChar8 *file) 576fc018e4Smrg{ 586fc018e4Smrg struct stat statb; 596fc018e4Smrg 606fc018e4Smrg if (FcStat (file, &statb) != 0) 616fc018e4Smrg return FcFalse; 626fc018e4Smrg return S_ISREG (statb.st_mode); 636fc018e4Smrg} 646fc018e4Smrg 652c393a42Smrgstatic FcBool 662c393a42SmrgFcFileScanFontConfig (FcFontSet *set, 672c393a42Smrg FcBlanks *blanks, 682c393a42Smrg const FcChar8 *file, 692c393a42Smrg FcConfig *config) 702c393a42Smrg{ 71953daebaSmrg FT_Library ftLibrary; 72953daebaSmrg FT_Face face; 732c393a42Smrg FcPattern *font; 742c393a42Smrg FcBool ret = FcTrue; 75953daebaSmrg int num_faces = 0; 76953daebaSmrg int num_instances = 0; 77953daebaSmrg int face_num = 0; 78953daebaSmrg int instance_num = 0; 792c393a42Smrg int id; 80953daebaSmrg const FcChar8 *sysroot = FcConfigGetSysRoot (config); 81953daebaSmrg 82953daebaSmrg if (FT_Init_FreeType (&ftLibrary)) 83953daebaSmrg return FcFalse; 84ca08ab68Smrg 852c393a42Smrg do 862c393a42Smrg { 872c393a42Smrg font = 0; 882c393a42Smrg /* 892c393a42Smrg * Nothing in the cache, scan the file 902c393a42Smrg */ 912c393a42Smrg if (FcDebug () & FC_DBG_SCAN) 922c393a42Smrg { 932c393a42Smrg printf ("\tScanning file %s...", file); 942c393a42Smrg fflush (stdout); 952c393a42Smrg } 96953daebaSmrg 97953daebaSmrg id = ((instance_num << 16) + face_num); 98953daebaSmrg if (FT_New_Face (ftLibrary, (char *) file, id, &face)) 99953daebaSmrg return FcFalse; 100953daebaSmrg num_faces = face->num_faces; 101953daebaSmrg num_instances = face->style_flags >> 16; 102953daebaSmrg font = FcFreeTypeQueryFace (face, file, id, blanks); 103953daebaSmrg FT_Done_Face (face); 104953daebaSmrg 1052c393a42Smrg if (FcDebug () & FC_DBG_SCAN) 1062c393a42Smrg printf ("done\n"); 107953daebaSmrg /* 108953daebaSmrg * Get rid of sysroot here so that targeting scan rule may contains FC_FILE pattern 109953daebaSmrg * and they should usually expect without sysroot. 110953daebaSmrg */ 111953daebaSmrg if (font && sysroot) 112953daebaSmrg { 113953daebaSmrg size_t len = strlen ((const char *)sysroot); 114953daebaSmrg FcChar8 *f = NULL; 115953daebaSmrg 116953daebaSmrg if (FcPatternObjectGetString (font, FC_FILE_OBJECT, 0, &f) == FcResultMatch && 117953daebaSmrg strncmp ((const char *)f, (const char *)sysroot, len) == 0) 118953daebaSmrg { 119953daebaSmrg FcChar8 *s = FcStrdup (f); 120953daebaSmrg FcPatternObjectDel (font, FC_FILE_OBJECT); 121953daebaSmrg if (s[len] != '/') 122953daebaSmrg len--; 123953daebaSmrg else if (s[len+1] == '/') 124953daebaSmrg len++; 125953daebaSmrg FcPatternObjectAddString (font, FC_FILE_OBJECT, &s[len]); 126953daebaSmrg FcStrFree (s); 127953daebaSmrg } 128953daebaSmrg } 1292c393a42Smrg 1302c393a42Smrg /* 1312c393a42Smrg * Edit pattern with user-defined rules 1322c393a42Smrg */ 133ca08ab68Smrg if (font && config && !FcConfigSubstitute (config, font, FcMatchScan)) 1342c393a42Smrg { 1352c393a42Smrg FcPatternDestroy (font); 1362c393a42Smrg font = NULL; 1372c393a42Smrg ret = FcFalse; 1382c393a42Smrg } 1392c393a42Smrg 1402c393a42Smrg /* 1412c393a42Smrg * Add the font 1422c393a42Smrg */ 143ca08ab68Smrg if (font) 1442c393a42Smrg { 1452c393a42Smrg if (FcDebug() & FC_DBG_SCANV) 1462c393a42Smrg { 1472c393a42Smrg printf ("Final font pattern:\n"); 1482c393a42Smrg FcPatternPrint (font); 1492c393a42Smrg } 1502c393a42Smrg if (!FcFontSetAdd (set, font)) 1512c393a42Smrg { 1522c393a42Smrg FcPatternDestroy (font); 1532c393a42Smrg font = NULL; 1542c393a42Smrg ret = FcFalse; 1552c393a42Smrg } 1562c393a42Smrg } 157953daebaSmrg else 158953daebaSmrg ret = FcFalse; 159953daebaSmrg 160953daebaSmrg if (instance_num < num_instances) 161953daebaSmrg instance_num++; 162953daebaSmrg else 163953daebaSmrg { 164953daebaSmrg face_num++; 165953daebaSmrg instance_num = 0; 166953daebaSmrg } 167953daebaSmrg } while (font && ret && face_num < num_faces); 168953daebaSmrg 169953daebaSmrg FT_Done_FreeType (ftLibrary); 170953daebaSmrg 1712c393a42Smrg return ret; 1722c393a42Smrg} 1732c393a42Smrg 1742c393a42SmrgFcBool 1752c393a42SmrgFcFileScanConfig (FcFontSet *set, 1762c393a42Smrg FcStrSet *dirs, 1772c393a42Smrg FcBlanks *blanks, 1782c393a42Smrg const FcChar8 *file, 1792c393a42Smrg FcConfig *config) 1802c393a42Smrg{ 1812c393a42Smrg if (FcFileIsDir (file)) 182953daebaSmrg { 183953daebaSmrg const FcChar8 *sysroot = FcConfigGetSysRoot (config); 184953daebaSmrg const FcChar8 *d = file; 185953daebaSmrg size_t len; 186953daebaSmrg 187953daebaSmrg if (sysroot) 188953daebaSmrg { 189953daebaSmrg len = strlen ((const char *)sysroot); 190953daebaSmrg if (strncmp ((const char *)file, (const char *)sysroot, len) == 0) 191953daebaSmrg { 192953daebaSmrg if (file[len] != '/') 193953daebaSmrg len--; 194953daebaSmrg else if (file[len+1] == '/') 195953daebaSmrg len++; 196953daebaSmrg d = &file[len]; 197953daebaSmrg } 198953daebaSmrg } 199953daebaSmrg return FcStrSetAdd (dirs, d); 200953daebaSmrg } 2012c393a42Smrg else 202b09479dcSmrg { 203b09479dcSmrg if (set) 204b09479dcSmrg return FcFileScanFontConfig (set, blanks, file, config); 205b09479dcSmrg else 206b09479dcSmrg return FcTrue; 207b09479dcSmrg } 2082c393a42Smrg} 2092c393a42Smrg 2102c393a42SmrgFcBool 2112c393a42SmrgFcFileScan (FcFontSet *set, 2122c393a42Smrg FcStrSet *dirs, 213c9710b42Smrg FcFileCache *cache FC_UNUSED, 2142c393a42Smrg FcBlanks *blanks, 2152c393a42Smrg const FcChar8 *file, 216c9710b42Smrg FcBool force FC_UNUSED) 2172c393a42Smrg{ 218a6844aabSmrg return FcFileScanConfig (set, dirs, blanks, file, FcConfigGetCurrent ()); 2192c393a42Smrg} 2202c393a42Smrg 2212c393a42Smrg/* 2222c393a42Smrg * Strcmp helper that takes pointers to pointers, copied from qsort(3) manpage 2232c393a42Smrg */ 2242c393a42Smrgstatic int 2252c393a42Smrgcmpstringp(const void *p1, const void *p2) 2262c393a42Smrg{ 2272c393a42Smrg return strcmp(* (char **) p1, * (char **) p2); 2282c393a42Smrg} 2292c393a42Smrg 230a6844aabSmrgFcBool 231a6844aabSmrgFcDirScanConfig (FcFontSet *set, 232a6844aabSmrg FcStrSet *dirs, 233a6844aabSmrg FcBlanks *blanks, 234a6844aabSmrg const FcChar8 *dir, 235a6844aabSmrg FcBool force, /* XXX unused */ 236a6844aabSmrg FcConfig *config) 2372c393a42Smrg{ 2382c393a42Smrg DIR *d; 2392c393a42Smrg struct dirent *e; 2402c393a42Smrg FcStrSet *files; 2412c393a42Smrg FcChar8 *file; 2422c393a42Smrg FcChar8 *base; 2432c393a42Smrg FcBool ret = FcTrue; 2442c393a42Smrg int i; 2452c393a42Smrg 246a6844aabSmrg if (!force) 247a6844aabSmrg return FcFalse; 248a6844aabSmrg 249a6844aabSmrg if (!set && !dirs) 250a6844aabSmrg return FcTrue; 251a6844aabSmrg 252a6844aabSmrg if (!blanks) 253a6844aabSmrg blanks = FcConfigGetBlanks (config); 2542c393a42Smrg 2552c393a42Smrg /* freed below */ 2562c393a42Smrg file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1); 2572c393a42Smrg if (!file) { 2582c393a42Smrg ret = FcFalse; 2592c393a42Smrg goto bail; 2602c393a42Smrg } 2612c393a42Smrg 2622c393a42Smrg strcpy ((char *) file, (char *) dir); 2632c393a42Smrg strcat ((char *) file, "/"); 2642c393a42Smrg base = file + strlen ((char *) file); 265ca08ab68Smrg 2662c393a42Smrg if (FcDebug () & FC_DBG_SCAN) 2672c393a42Smrg printf ("\tScanning dir %s\n", dir); 2682c393a42Smrg 2692c393a42Smrg d = opendir ((char *) dir); 2702c393a42Smrg if (!d) 2712c393a42Smrg { 2722c393a42Smrg /* Don't complain about missing directories */ 273a6844aabSmrg if (errno != ENOENT) 2742c393a42Smrg ret = FcFalse; 275a6844aabSmrg goto bail; 2762c393a42Smrg } 2772c393a42Smrg 278953daebaSmrg files = FcStrSetCreateEx (FCSS_ALLOW_DUPLICATES | FCSS_GROW_BY_64); 2792c393a42Smrg if (!files) 2802c393a42Smrg { 2812c393a42Smrg ret = FcFalse; 2822c393a42Smrg goto bail1; 2832c393a42Smrg } 2842c393a42Smrg while ((e = readdir (d))) 2852c393a42Smrg { 2862c393a42Smrg if (e->d_name[0] != '.' && strlen (e->d_name) < FC_MAX_FILE_LEN) 2872c393a42Smrg { 2882c393a42Smrg strcpy ((char *) base, (char *) e->d_name); 2892c393a42Smrg if (!FcStrSetAdd (files, file)) { 2902c393a42Smrg ret = FcFalse; 2912c393a42Smrg goto bail2; 2922c393a42Smrg } 2932c393a42Smrg } 2942c393a42Smrg } 2952c393a42Smrg 2962c393a42Smrg /* 2972c393a42Smrg * Sort files to make things prettier 2982c393a42Smrg */ 2992c393a42Smrg qsort(files->strs, files->num, sizeof(FcChar8 *), cmpstringp); 300a6844aabSmrg 3012c393a42Smrg /* 3022c393a42Smrg * Scan file files to build font patterns 3032c393a42Smrg */ 3042c393a42Smrg for (i = 0; i < files->num; i++) 3052c393a42Smrg FcFileScanConfig (set, dirs, blanks, files->strs[i], config); 306ca08ab68Smrg 307a6844aabSmrgbail2: 308a6844aabSmrg FcStrSetDestroy (files); 309a6844aabSmrgbail1: 310a6844aabSmrg closedir (d); 311a6844aabSmrgbail: 312ca08ab68Smrg if (file) 313ca08ab68Smrg free (file); 314ca08ab68Smrg 315a6844aabSmrg return ret; 316a6844aabSmrg} 317a6844aabSmrg 318a6844aabSmrgFcBool 319a6844aabSmrgFcDirScan (FcFontSet *set, 320a6844aabSmrg FcStrSet *dirs, 321a6844aabSmrg FcFileCache *cache, /* XXX unused */ 322a6844aabSmrg FcBlanks *blanks, 323a6844aabSmrg const FcChar8 *dir, 324a6844aabSmrg FcBool force /* XXX unused */) 325a6844aabSmrg{ 326a6844aabSmrg if (cache || !force) 327a6844aabSmrg return FcFalse; 328a6844aabSmrg 329a6844aabSmrg return FcDirScanConfig (set, dirs, blanks, dir, force, FcConfigGetCurrent ()); 330a6844aabSmrg} 331a6844aabSmrg 332a6844aabSmrg/* 333a6844aabSmrg * Scan the specified directory and construct a cache of its contents 334a6844aabSmrg */ 335a6844aabSmrgFcCache * 336a6844aabSmrgFcDirCacheScan (const FcChar8 *dir, FcConfig *config) 337a6844aabSmrg{ 338a6844aabSmrg FcStrSet *dirs; 339a6844aabSmrg FcFontSet *set; 340a6844aabSmrg FcCache *cache = NULL; 341a6844aabSmrg struct stat dir_stat; 342953daebaSmrg const FcChar8 *sysroot = FcConfigGetSysRoot (config); 343953daebaSmrg FcChar8 *d; 344953daebaSmrg int fd = -1; 345953daebaSmrg 346953daebaSmrg if (sysroot) 347953daebaSmrg d = FcStrBuildFilename (sysroot, dir, NULL); 348953daebaSmrg else 349953daebaSmrg d = FcStrdup (dir); 350a6844aabSmrg 351a6844aabSmrg if (FcDebug () & FC_DBG_FONTSET) 352953daebaSmrg printf ("cache scan dir %s\n", d); 353a6844aabSmrg 354953daebaSmrg if (FcStatChecksum (d, &dir_stat) < 0) 355a6844aabSmrg goto bail; 356a6844aabSmrg 357a6844aabSmrg set = FcFontSetCreate(); 358a6844aabSmrg if (!set) 359a6844aabSmrg goto bail; 360a6844aabSmrg 361953daebaSmrg dirs = FcStrSetCreateEx (FCSS_GROW_BY_64); 362a6844aabSmrg if (!dirs) 363a6844aabSmrg goto bail1; 364a6844aabSmrg 365953daebaSmrg#ifndef _WIN32 366953daebaSmrg fd = FcDirCacheLock (dir, config); 367953daebaSmrg#endif 368a6844aabSmrg /* 369a6844aabSmrg * Scan the dir 370a6844aabSmrg */ 371953daebaSmrg if (!FcDirScanConfig (set, dirs, NULL, d, FcTrue, config)) 372a6844aabSmrg goto bail2; 373a6844aabSmrg 3742c393a42Smrg /* 3752c393a42Smrg * Build the cache object 3762c393a42Smrg */ 3772c393a42Smrg cache = FcDirCacheBuild (set, dir, &dir_stat, dirs); 3782c393a42Smrg if (!cache) 379a6844aabSmrg goto bail2; 380ca08ab68Smrg 3812c393a42Smrg /* 3822c393a42Smrg * Write out the cache file, ignoring any troubles 3832c393a42Smrg */ 3842c393a42Smrg FcDirCacheWrite (cache, config); 385ca08ab68Smrg 3862c393a42Smrg bail2: 387953daebaSmrg#ifndef _WIN32 388953daebaSmrg FcDirCacheUnlock (fd); 389953daebaSmrg#endif 390a6844aabSmrg FcStrSetDestroy (dirs); 3912c393a42Smrg bail1: 3922c393a42Smrg FcFontSetDestroy (set); 3932c393a42Smrg bail: 394953daebaSmrg FcStrFree (d); 395953daebaSmrg 3962c393a42Smrg return cache; 3972c393a42Smrg} 3982c393a42Smrg 399b09479dcSmrgFcCache * 400b09479dcSmrgFcDirCacheRescan (const FcChar8 *dir, FcConfig *config) 401b09479dcSmrg{ 402953daebaSmrg FcCache *cache; 403b09479dcSmrg FcCache *new = NULL; 404b09479dcSmrg struct stat dir_stat; 405b09479dcSmrg FcStrSet *dirs; 406953daebaSmrg const FcChar8 *sysroot = FcConfigGetSysRoot (config); 407953daebaSmrg FcChar8 *d = NULL; 408953daebaSmrg int fd = -1; 409b09479dcSmrg 410953daebaSmrg cache = FcDirCacheLoad (dir, config, NULL); 411b09479dcSmrg if (!cache) 412b09479dcSmrg goto bail; 413953daebaSmrg 414953daebaSmrg if (sysroot) 415953daebaSmrg d = FcStrBuildFilename (sysroot, dir, NULL); 416953daebaSmrg else 417953daebaSmrg d = FcStrdup (dir); 418953daebaSmrg if (FcStatChecksum (d, &dir_stat) < 0) 419953daebaSmrg goto bail; 420953daebaSmrg dirs = FcStrSetCreateEx (FCSS_GROW_BY_64); 421b09479dcSmrg if (!dirs) 422b09479dcSmrg goto bail; 423b09479dcSmrg 424953daebaSmrg#ifndef _WIN32 425953daebaSmrg fd = FcDirCacheLock (dir, config); 426953daebaSmrg#endif 427b09479dcSmrg /* 428b09479dcSmrg * Scan the dir 429b09479dcSmrg */ 430953daebaSmrg if (!FcDirScanConfig (NULL, dirs, NULL, d, FcTrue, config)) 431b09479dcSmrg goto bail1; 432b09479dcSmrg /* 433b09479dcSmrg * Rebuild the cache object 434b09479dcSmrg */ 435b09479dcSmrg new = FcDirCacheRebuild (cache, &dir_stat, dirs); 436b09479dcSmrg if (!new) 437b09479dcSmrg goto bail1; 438b09479dcSmrg FcDirCacheUnload (cache); 439b09479dcSmrg /* 440b09479dcSmrg * Write out the cache file, ignoring any troubles 441b09479dcSmrg */ 442b09479dcSmrg FcDirCacheWrite (new, config); 443b09479dcSmrg 444b09479dcSmrgbail1: 445953daebaSmrg#ifndef _WIN32 446953daebaSmrg FcDirCacheUnlock (fd); 447953daebaSmrg#endif 448b09479dcSmrg FcStrSetDestroy (dirs); 449b09479dcSmrgbail: 450953daebaSmrg if (d) 451953daebaSmrg FcStrFree (d); 452953daebaSmrg 453b09479dcSmrg return new; 454b09479dcSmrg} 455b09479dcSmrg 4562c393a42Smrg/* 4572c393a42Smrg * Read (or construct) the cache for a directory 4582c393a42Smrg */ 4592c393a42SmrgFcCache * 4602c393a42SmrgFcDirCacheRead (const FcChar8 *dir, FcBool force, FcConfig *config) 4612c393a42Smrg{ 4622c393a42Smrg FcCache *cache = NULL; 4632c393a42Smrg 4642c393a42Smrg /* Try to use existing cache file */ 4652c393a42Smrg if (!force) 4662c393a42Smrg cache = FcDirCacheLoad (dir, config, NULL); 467ca08ab68Smrg 4682c393a42Smrg /* Not using existing cache file, construct new cache */ 4692c393a42Smrg if (!cache) 4702c393a42Smrg cache = FcDirCacheScan (dir, config); 471ca08ab68Smrg 4722c393a42Smrg return cache; 4732c393a42Smrg} 4742c393a42Smrg 4752c393a42SmrgFcBool 476c9710b42SmrgFcDirSave (FcFontSet *set FC_UNUSED, FcStrSet * dirs FC_UNUSED, const FcChar8 *dir FC_UNUSED) 4772c393a42Smrg{ 4782c393a42Smrg return FcFalse; /* XXX deprecated */ 4792c393a42Smrg} 4802c393a42Smrg#define __fcdir__ 4812c393a42Smrg#include "fcaliastail.h" 4822c393a42Smrg#undef __fcdir__ 483