fcdir.c revision a32e9e42
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" 262c393a42Smrg#include <dirent.h> 272c393a42Smrg 282c393a42SmrgFcBool 292c393a42SmrgFcFileIsDir (const FcChar8 *file) 302c393a42Smrg{ 312c393a42Smrg struct stat statb; 322c393a42Smrg 33ca08ab68Smrg if (FcStat (file, &statb) != 0) 342c393a42Smrg return FcFalse; 352c393a42Smrg return S_ISDIR(statb.st_mode); 362c393a42Smrg} 372c393a42Smrg 38c9710b42SmrgFcBool 39c9710b42SmrgFcFileIsLink (const FcChar8 *file) 40c9710b42Smrg{ 41c9710b42Smrg#if HAVE_LSTAT 42c9710b42Smrg struct stat statb; 43c9710b42Smrg 44c9710b42Smrg if (lstat ((const char *)file, &statb) != 0) 45c9710b42Smrg return FcFalse; 46c9710b42Smrg return S_ISLNK (statb.st_mode); 47c9710b42Smrg#else 48c9710b42Smrg return FcFalse; 49c9710b42Smrg#endif 50c9710b42Smrg} 51c9710b42Smrg 526fc018e4SmrgFcBool 536fc018e4SmrgFcFileIsFile (const FcChar8 *file) 546fc018e4Smrg{ 556fc018e4Smrg struct stat statb; 566fc018e4Smrg 576fc018e4Smrg if (FcStat (file, &statb) != 0) 586fc018e4Smrg return FcFalse; 596fc018e4Smrg return S_ISREG (statb.st_mode); 606fc018e4Smrg} 616fc018e4Smrg 622c393a42Smrgstatic FcBool 632c393a42SmrgFcFileScanFontConfig (FcFontSet *set, 642c393a42Smrg const FcChar8 *file, 652c393a42Smrg FcConfig *config) 662c393a42Smrg{ 67a32e9e42Smrg int i; 682c393a42Smrg FcBool ret = FcTrue; 69a32e9e42Smrg int old_nfont = set->nfont; 70953daebaSmrg const FcChar8 *sysroot = FcConfigGetSysRoot (config); 71953daebaSmrg 72a32e9e42Smrg if (FcDebug () & FC_DBG_SCAN) 73a32e9e42Smrg { 74a32e9e42Smrg printf ("\tScanning file %s...", file); 75a32e9e42Smrg fflush (stdout); 76a32e9e42Smrg } 77a32e9e42Smrg 78a32e9e42Smrg if (!FcFreeTypeQueryAll (file, -1, NULL, NULL, set)) 79953daebaSmrg return FcFalse; 80ca08ab68Smrg 81a32e9e42Smrg if (FcDebug () & FC_DBG_SCAN) 82a32e9e42Smrg printf ("done\n"); 83953daebaSmrg 84a32e9e42Smrg for (i = old_nfont; i < set->nfont; i++) 85a32e9e42Smrg { 86a32e9e42Smrg FcPattern *font = set->fonts[i]; 87953daebaSmrg 88953daebaSmrg /* 89953daebaSmrg * Get rid of sysroot here so that targeting scan rule may contains FC_FILE pattern 90953daebaSmrg * and they should usually expect without sysroot. 91953daebaSmrg */ 92a32e9e42Smrg if (sysroot) 93953daebaSmrg { 94953daebaSmrg size_t len = strlen ((const char *)sysroot); 95953daebaSmrg FcChar8 *f = NULL; 96953daebaSmrg 97953daebaSmrg if (FcPatternObjectGetString (font, FC_FILE_OBJECT, 0, &f) == FcResultMatch && 98953daebaSmrg strncmp ((const char *)f, (const char *)sysroot, len) == 0) 99953daebaSmrg { 100953daebaSmrg FcChar8 *s = FcStrdup (f); 101953daebaSmrg FcPatternObjectDel (font, FC_FILE_OBJECT); 102953daebaSmrg if (s[len] != '/') 103953daebaSmrg len--; 104953daebaSmrg else if (s[len+1] == '/') 105953daebaSmrg len++; 106953daebaSmrg FcPatternObjectAddString (font, FC_FILE_OBJECT, &s[len]); 107953daebaSmrg FcStrFree (s); 108953daebaSmrg } 109953daebaSmrg } 1102c393a42Smrg 1112c393a42Smrg /* 1122c393a42Smrg * Edit pattern with user-defined rules 1132c393a42Smrg */ 114a32e9e42Smrg if (config && !FcConfigSubstitute (config, font, FcMatchScan)) 1152c393a42Smrg ret = FcFalse; 1162c393a42Smrg 117a32e9e42Smrg if (FcDebug() & FC_DBG_SCANV) 1182c393a42Smrg { 119a32e9e42Smrg printf ("Final font pattern:\n"); 120a32e9e42Smrg FcPatternPrint (font); 1212c393a42Smrg } 122a32e9e42Smrg } 123953daebaSmrg 1242c393a42Smrg return ret; 1252c393a42Smrg} 1262c393a42Smrg 1272c393a42SmrgFcBool 1282c393a42SmrgFcFileScanConfig (FcFontSet *set, 1292c393a42Smrg FcStrSet *dirs, 1302c393a42Smrg const FcChar8 *file, 1312c393a42Smrg FcConfig *config) 1322c393a42Smrg{ 1332c393a42Smrg if (FcFileIsDir (file)) 134953daebaSmrg { 135953daebaSmrg const FcChar8 *sysroot = FcConfigGetSysRoot (config); 136953daebaSmrg const FcChar8 *d = file; 137953daebaSmrg size_t len; 138953daebaSmrg 139953daebaSmrg if (sysroot) 140953daebaSmrg { 141953daebaSmrg len = strlen ((const char *)sysroot); 142953daebaSmrg if (strncmp ((const char *)file, (const char *)sysroot, len) == 0) 143953daebaSmrg { 144953daebaSmrg if (file[len] != '/') 145953daebaSmrg len--; 146953daebaSmrg else if (file[len+1] == '/') 147953daebaSmrg len++; 148953daebaSmrg d = &file[len]; 149953daebaSmrg } 150953daebaSmrg } 151953daebaSmrg return FcStrSetAdd (dirs, d); 152953daebaSmrg } 1532c393a42Smrg else 154b09479dcSmrg { 155b09479dcSmrg if (set) 156a32e9e42Smrg return FcFileScanFontConfig (set, file, config); 157b09479dcSmrg else 158b09479dcSmrg return FcTrue; 159b09479dcSmrg } 1602c393a42Smrg} 1612c393a42Smrg 1622c393a42SmrgFcBool 1632c393a42SmrgFcFileScan (FcFontSet *set, 1642c393a42Smrg FcStrSet *dirs, 165c9710b42Smrg FcFileCache *cache FC_UNUSED, 166a32e9e42Smrg FcBlanks *blanks FC_UNUSED, 1672c393a42Smrg const FcChar8 *file, 168c9710b42Smrg FcBool force FC_UNUSED) 1692c393a42Smrg{ 170a32e9e42Smrg return FcFileScanConfig (set, dirs, file, FcConfigGetCurrent ()); 1712c393a42Smrg} 1722c393a42Smrg 1732c393a42Smrg/* 1742c393a42Smrg * Strcmp helper that takes pointers to pointers, copied from qsort(3) manpage 1752c393a42Smrg */ 1762c393a42Smrgstatic int 1772c393a42Smrgcmpstringp(const void *p1, const void *p2) 1782c393a42Smrg{ 1792c393a42Smrg return strcmp(* (char **) p1, * (char **) p2); 1802c393a42Smrg} 1812c393a42Smrg 182a6844aabSmrgFcBool 183a6844aabSmrgFcDirScanConfig (FcFontSet *set, 184a6844aabSmrg FcStrSet *dirs, 185a6844aabSmrg const FcChar8 *dir, 186a6844aabSmrg FcBool force, /* XXX unused */ 187a6844aabSmrg FcConfig *config) 1882c393a42Smrg{ 1892c393a42Smrg DIR *d; 1902c393a42Smrg struct dirent *e; 1912c393a42Smrg FcStrSet *files; 1922c393a42Smrg FcChar8 *file; 1932c393a42Smrg FcChar8 *base; 1942c393a42Smrg FcBool ret = FcTrue; 1952c393a42Smrg int i; 1962c393a42Smrg 197a6844aabSmrg if (!force) 198a6844aabSmrg return FcFalse; 199a6844aabSmrg 200a6844aabSmrg if (!set && !dirs) 201a6844aabSmrg return FcTrue; 202a6844aabSmrg 2032c393a42Smrg /* freed below */ 2042c393a42Smrg file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1); 2052c393a42Smrg if (!file) { 2062c393a42Smrg ret = FcFalse; 2072c393a42Smrg goto bail; 2082c393a42Smrg } 2092c393a42Smrg 2102c393a42Smrg strcpy ((char *) file, (char *) dir); 2112c393a42Smrg strcat ((char *) file, "/"); 2122c393a42Smrg base = file + strlen ((char *) file); 213ca08ab68Smrg 2142c393a42Smrg if (FcDebug () & FC_DBG_SCAN) 2152c393a42Smrg printf ("\tScanning dir %s\n", dir); 2162c393a42Smrg 2172c393a42Smrg d = opendir ((char *) dir); 2182c393a42Smrg if (!d) 2192c393a42Smrg { 2202c393a42Smrg /* Don't complain about missing directories */ 221a6844aabSmrg if (errno != ENOENT) 2222c393a42Smrg ret = FcFalse; 223a6844aabSmrg goto bail; 2242c393a42Smrg } 2252c393a42Smrg 226953daebaSmrg files = FcStrSetCreateEx (FCSS_ALLOW_DUPLICATES | FCSS_GROW_BY_64); 2272c393a42Smrg if (!files) 2282c393a42Smrg { 2292c393a42Smrg ret = FcFalse; 2302c393a42Smrg goto bail1; 2312c393a42Smrg } 2322c393a42Smrg while ((e = readdir (d))) 2332c393a42Smrg { 2342c393a42Smrg if (e->d_name[0] != '.' && strlen (e->d_name) < FC_MAX_FILE_LEN) 2352c393a42Smrg { 2362c393a42Smrg strcpy ((char *) base, (char *) e->d_name); 2372c393a42Smrg if (!FcStrSetAdd (files, file)) { 2382c393a42Smrg ret = FcFalse; 2392c393a42Smrg goto bail2; 2402c393a42Smrg } 2412c393a42Smrg } 2422c393a42Smrg } 2432c393a42Smrg 2442c393a42Smrg /* 2452c393a42Smrg * Sort files to make things prettier 2462c393a42Smrg */ 2472c393a42Smrg qsort(files->strs, files->num, sizeof(FcChar8 *), cmpstringp); 248a6844aabSmrg 2492c393a42Smrg /* 2502c393a42Smrg * Scan file files to build font patterns 2512c393a42Smrg */ 2522c393a42Smrg for (i = 0; i < files->num; i++) 253a32e9e42Smrg FcFileScanConfig (set, dirs, files->strs[i], config); 254ca08ab68Smrg 255a6844aabSmrgbail2: 256a6844aabSmrg FcStrSetDestroy (files); 257a6844aabSmrgbail1: 258a6844aabSmrg closedir (d); 259a6844aabSmrgbail: 260ca08ab68Smrg if (file) 261ca08ab68Smrg free (file); 262ca08ab68Smrg 263a6844aabSmrg return ret; 264a6844aabSmrg} 265a6844aabSmrg 266a6844aabSmrgFcBool 267a6844aabSmrgFcDirScan (FcFontSet *set, 268a6844aabSmrg FcStrSet *dirs, 269a32e9e42Smrg FcFileCache *cache FC_UNUSED, 270a32e9e42Smrg FcBlanks *blanks FC_UNUSED, 271a6844aabSmrg const FcChar8 *dir, 272a32e9e42Smrg FcBool force FC_UNUSED) 273a6844aabSmrg{ 274a6844aabSmrg if (cache || !force) 275a6844aabSmrg return FcFalse; 276a6844aabSmrg 277a32e9e42Smrg return FcDirScanConfig (set, dirs, dir, force, FcConfigGetCurrent ()); 278a6844aabSmrg} 279a6844aabSmrg 280a6844aabSmrg/* 281a6844aabSmrg * Scan the specified directory and construct a cache of its contents 282a6844aabSmrg */ 283a6844aabSmrgFcCache * 284a6844aabSmrgFcDirCacheScan (const FcChar8 *dir, FcConfig *config) 285a6844aabSmrg{ 286a6844aabSmrg FcStrSet *dirs; 287a6844aabSmrg FcFontSet *set; 288a6844aabSmrg FcCache *cache = NULL; 289a6844aabSmrg struct stat dir_stat; 290953daebaSmrg const FcChar8 *sysroot = FcConfigGetSysRoot (config); 291953daebaSmrg FcChar8 *d; 292a32e9e42Smrg#ifndef _WIN32 293953daebaSmrg int fd = -1; 294a32e9e42Smrg#endif 295953daebaSmrg 296953daebaSmrg if (sysroot) 297953daebaSmrg d = FcStrBuildFilename (sysroot, dir, NULL); 298953daebaSmrg else 299953daebaSmrg d = FcStrdup (dir); 300a6844aabSmrg 301a6844aabSmrg if (FcDebug () & FC_DBG_FONTSET) 302953daebaSmrg printf ("cache scan dir %s\n", d); 303a6844aabSmrg 304953daebaSmrg if (FcStatChecksum (d, &dir_stat) < 0) 305a6844aabSmrg goto bail; 306a6844aabSmrg 307a6844aabSmrg set = FcFontSetCreate(); 308a6844aabSmrg if (!set) 309a6844aabSmrg goto bail; 310a6844aabSmrg 311953daebaSmrg dirs = FcStrSetCreateEx (FCSS_GROW_BY_64); 312a6844aabSmrg if (!dirs) 313a6844aabSmrg goto bail1; 314a6844aabSmrg 315953daebaSmrg#ifndef _WIN32 316953daebaSmrg fd = FcDirCacheLock (dir, config); 317953daebaSmrg#endif 318a6844aabSmrg /* 319a6844aabSmrg * Scan the dir 320a6844aabSmrg */ 321a32e9e42Smrg if (!FcDirScanConfig (set, dirs, d, FcTrue, config)) 322a6844aabSmrg goto bail2; 323a6844aabSmrg 3242c393a42Smrg /* 3252c393a42Smrg * Build the cache object 3262c393a42Smrg */ 3272c393a42Smrg cache = FcDirCacheBuild (set, dir, &dir_stat, dirs); 3282c393a42Smrg if (!cache) 329a6844aabSmrg goto bail2; 330ca08ab68Smrg 3312c393a42Smrg /* 3322c393a42Smrg * Write out the cache file, ignoring any troubles 3332c393a42Smrg */ 3342c393a42Smrg FcDirCacheWrite (cache, config); 335ca08ab68Smrg 3362c393a42Smrg bail2: 337953daebaSmrg#ifndef _WIN32 338953daebaSmrg FcDirCacheUnlock (fd); 339953daebaSmrg#endif 340a6844aabSmrg FcStrSetDestroy (dirs); 3412c393a42Smrg bail1: 3422c393a42Smrg FcFontSetDestroy (set); 3432c393a42Smrg bail: 344953daebaSmrg FcStrFree (d); 345953daebaSmrg 3462c393a42Smrg return cache; 3472c393a42Smrg} 3482c393a42Smrg 349b09479dcSmrgFcCache * 350b09479dcSmrgFcDirCacheRescan (const FcChar8 *dir, FcConfig *config) 351b09479dcSmrg{ 352953daebaSmrg FcCache *cache; 353b09479dcSmrg FcCache *new = NULL; 354b09479dcSmrg struct stat dir_stat; 355b09479dcSmrg FcStrSet *dirs; 356953daebaSmrg const FcChar8 *sysroot = FcConfigGetSysRoot (config); 357953daebaSmrg FcChar8 *d = NULL; 358a32e9e42Smrg#ifndef _WIN32 359953daebaSmrg int fd = -1; 360a32e9e42Smrg#endif 361b09479dcSmrg 362953daebaSmrg cache = FcDirCacheLoad (dir, config, NULL); 363b09479dcSmrg if (!cache) 364b09479dcSmrg goto bail; 365953daebaSmrg 366953daebaSmrg if (sysroot) 367953daebaSmrg d = FcStrBuildFilename (sysroot, dir, NULL); 368953daebaSmrg else 369953daebaSmrg d = FcStrdup (dir); 370953daebaSmrg if (FcStatChecksum (d, &dir_stat) < 0) 371953daebaSmrg goto bail; 372953daebaSmrg dirs = FcStrSetCreateEx (FCSS_GROW_BY_64); 373b09479dcSmrg if (!dirs) 374b09479dcSmrg goto bail; 375b09479dcSmrg 376953daebaSmrg#ifndef _WIN32 377953daebaSmrg fd = FcDirCacheLock (dir, config); 378953daebaSmrg#endif 379b09479dcSmrg /* 380b09479dcSmrg * Scan the dir 381b09479dcSmrg */ 382a32e9e42Smrg if (!FcDirScanConfig (NULL, dirs, d, FcTrue, config)) 383b09479dcSmrg goto bail1; 384b09479dcSmrg /* 385b09479dcSmrg * Rebuild the cache object 386b09479dcSmrg */ 387b09479dcSmrg new = FcDirCacheRebuild (cache, &dir_stat, dirs); 388b09479dcSmrg if (!new) 389b09479dcSmrg goto bail1; 390b09479dcSmrg FcDirCacheUnload (cache); 391b09479dcSmrg /* 392b09479dcSmrg * Write out the cache file, ignoring any troubles 393b09479dcSmrg */ 394b09479dcSmrg FcDirCacheWrite (new, config); 395b09479dcSmrg 396b09479dcSmrgbail1: 397953daebaSmrg#ifndef _WIN32 398953daebaSmrg FcDirCacheUnlock (fd); 399953daebaSmrg#endif 400b09479dcSmrg FcStrSetDestroy (dirs); 401b09479dcSmrgbail: 402953daebaSmrg if (d) 403953daebaSmrg FcStrFree (d); 404953daebaSmrg 405b09479dcSmrg return new; 406b09479dcSmrg} 407b09479dcSmrg 4082c393a42Smrg/* 4092c393a42Smrg * Read (or construct) the cache for a directory 4102c393a42Smrg */ 4112c393a42SmrgFcCache * 4122c393a42SmrgFcDirCacheRead (const FcChar8 *dir, FcBool force, FcConfig *config) 4132c393a42Smrg{ 4142c393a42Smrg FcCache *cache = NULL; 4152c393a42Smrg 416a32e9e42Smrg FcDirCacheCreateUUID ((FcChar8 *) dir, FcFalse, config); 4172c393a42Smrg /* Try to use existing cache file */ 4182c393a42Smrg if (!force) 4192c393a42Smrg cache = FcDirCacheLoad (dir, config, NULL); 420ca08ab68Smrg 4212c393a42Smrg /* Not using existing cache file, construct new cache */ 4222c393a42Smrg if (!cache) 4232c393a42Smrg cache = FcDirCacheScan (dir, config); 424a32e9e42Smrg if (cache) 425a32e9e42Smrg { 426a32e9e42Smrg FcFontSet *fs = FcCacheSet (cache); 427a32e9e42Smrg 428a32e9e42Smrg if (cache->dirs_count == 0 && (!fs || fs->nfont == 0)) 429a32e9e42Smrg FcDirCacheDeleteUUID (dir, config); 430a32e9e42Smrg } 431ca08ab68Smrg 4322c393a42Smrg return cache; 4332c393a42Smrg} 4342c393a42Smrg 4352c393a42SmrgFcBool 436c9710b42SmrgFcDirSave (FcFontSet *set FC_UNUSED, FcStrSet * dirs FC_UNUSED, const FcChar8 *dir FC_UNUSED) 4372c393a42Smrg{ 4382c393a42Smrg return FcFalse; /* XXX deprecated */ 4392c393a42Smrg} 4402c393a42Smrg#define __fcdir__ 4412c393a42Smrg#include "fcaliastail.h" 4422c393a42Smrg#undef __fcdir__ 443