fcdir.c revision 7872e0a1
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" 267872e0a1Smrg 277872e0a1Smrg#ifdef HAVE_DIRENT_H 282c393a42Smrg#include <dirent.h> 297872e0a1Smrg#endif 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 const FcChar8 *file, 682c393a42Smrg FcConfig *config) 692c393a42Smrg{ 70a32e9e42Smrg int i; 712c393a42Smrg FcBool ret = FcTrue; 72a32e9e42Smrg int old_nfont = set->nfont; 73953daebaSmrg const FcChar8 *sysroot = FcConfigGetSysRoot (config); 74953daebaSmrg 75a32e9e42Smrg if (FcDebug () & FC_DBG_SCAN) 76a32e9e42Smrg { 77a32e9e42Smrg printf ("\tScanning file %s...", file); 78a32e9e42Smrg fflush (stdout); 79a32e9e42Smrg } 80a32e9e42Smrg 81a32e9e42Smrg if (!FcFreeTypeQueryAll (file, -1, NULL, NULL, set)) 82953daebaSmrg return FcFalse; 83ca08ab68Smrg 84a32e9e42Smrg if (FcDebug () & FC_DBG_SCAN) 85a32e9e42Smrg printf ("done\n"); 86953daebaSmrg 87a32e9e42Smrg for (i = old_nfont; i < set->nfont; i++) 88a32e9e42Smrg { 89a32e9e42Smrg FcPattern *font = set->fonts[i]; 90953daebaSmrg 91953daebaSmrg /* 92953daebaSmrg * Get rid of sysroot here so that targeting scan rule may contains FC_FILE pattern 93953daebaSmrg * and they should usually expect without sysroot. 94953daebaSmrg */ 95a32e9e42Smrg if (sysroot) 96953daebaSmrg { 97953daebaSmrg size_t len = strlen ((const char *)sysroot); 98953daebaSmrg FcChar8 *f = NULL; 99953daebaSmrg 100953daebaSmrg if (FcPatternObjectGetString (font, FC_FILE_OBJECT, 0, &f) == FcResultMatch && 101953daebaSmrg strncmp ((const char *)f, (const char *)sysroot, len) == 0) 102953daebaSmrg { 103953daebaSmrg FcChar8 *s = FcStrdup (f); 104953daebaSmrg FcPatternObjectDel (font, FC_FILE_OBJECT); 105953daebaSmrg if (s[len] != '/') 106953daebaSmrg len--; 107953daebaSmrg else if (s[len+1] == '/') 108953daebaSmrg len++; 109953daebaSmrg FcPatternObjectAddString (font, FC_FILE_OBJECT, &s[len]); 110953daebaSmrg FcStrFree (s); 111953daebaSmrg } 112953daebaSmrg } 1132c393a42Smrg 1142c393a42Smrg /* 1152c393a42Smrg * Edit pattern with user-defined rules 1162c393a42Smrg */ 117a32e9e42Smrg if (config && !FcConfigSubstitute (config, font, FcMatchScan)) 1182c393a42Smrg ret = FcFalse; 1192c393a42Smrg 120a32e9e42Smrg if (FcDebug() & FC_DBG_SCANV) 1212c393a42Smrg { 122a32e9e42Smrg printf ("Final font pattern:\n"); 123a32e9e42Smrg FcPatternPrint (font); 1242c393a42Smrg } 125a32e9e42Smrg } 126953daebaSmrg 1272c393a42Smrg return ret; 1282c393a42Smrg} 1292c393a42Smrg 1302c393a42SmrgFcBool 1312c393a42SmrgFcFileScanConfig (FcFontSet *set, 1322c393a42Smrg FcStrSet *dirs, 1332c393a42Smrg const FcChar8 *file, 1342c393a42Smrg FcConfig *config) 1352c393a42Smrg{ 1362c393a42Smrg if (FcFileIsDir (file)) 137953daebaSmrg { 138953daebaSmrg const FcChar8 *sysroot = FcConfigGetSysRoot (config); 139953daebaSmrg const FcChar8 *d = file; 140953daebaSmrg size_t len; 141953daebaSmrg 142953daebaSmrg if (sysroot) 143953daebaSmrg { 144953daebaSmrg len = strlen ((const char *)sysroot); 145953daebaSmrg if (strncmp ((const char *)file, (const char *)sysroot, len) == 0) 146953daebaSmrg { 147953daebaSmrg if (file[len] != '/') 148953daebaSmrg len--; 149953daebaSmrg else if (file[len+1] == '/') 150953daebaSmrg len++; 151953daebaSmrg d = &file[len]; 152953daebaSmrg } 153953daebaSmrg } 154953daebaSmrg return FcStrSetAdd (dirs, d); 155953daebaSmrg } 1562c393a42Smrg else 157b09479dcSmrg { 158b09479dcSmrg if (set) 159a32e9e42Smrg return FcFileScanFontConfig (set, file, config); 160b09479dcSmrg else 161b09479dcSmrg return FcTrue; 162b09479dcSmrg } 1632c393a42Smrg} 1642c393a42Smrg 1652c393a42SmrgFcBool 1662c393a42SmrgFcFileScan (FcFontSet *set, 1672c393a42Smrg FcStrSet *dirs, 168c9710b42Smrg FcFileCache *cache FC_UNUSED, 169a32e9e42Smrg FcBlanks *blanks FC_UNUSED, 1702c393a42Smrg const FcChar8 *file, 171c9710b42Smrg FcBool force FC_UNUSED) 1722c393a42Smrg{ 1737872e0a1Smrg FcConfig *config; 1747872e0a1Smrg FcBool ret; 1757872e0a1Smrg 1767872e0a1Smrg config = FcConfigReference (NULL); 1777872e0a1Smrg if (!config) 1787872e0a1Smrg return FcFalse; 1797872e0a1Smrg ret = FcFileScanConfig (set, dirs, file, config); 1807872e0a1Smrg FcConfigDestroy (config); 1817872e0a1Smrg 1827872e0a1Smrg return ret; 1832c393a42Smrg} 1842c393a42Smrg 1852c393a42Smrg/* 1862c393a42Smrg * Strcmp helper that takes pointers to pointers, copied from qsort(3) manpage 1872c393a42Smrg */ 1882c393a42Smrgstatic int 1892c393a42Smrgcmpstringp(const void *p1, const void *p2) 1902c393a42Smrg{ 1912c393a42Smrg return strcmp(* (char **) p1, * (char **) p2); 1922c393a42Smrg} 1932c393a42Smrg 194a6844aabSmrgFcBool 195a6844aabSmrgFcDirScanConfig (FcFontSet *set, 196a6844aabSmrg FcStrSet *dirs, 197a6844aabSmrg const FcChar8 *dir, 198a6844aabSmrg FcBool force, /* XXX unused */ 199a6844aabSmrg FcConfig *config) 2002c393a42Smrg{ 2012c393a42Smrg DIR *d; 2022c393a42Smrg struct dirent *e; 2032c393a42Smrg FcStrSet *files; 2047872e0a1Smrg FcChar8 *file_prefix, *s_dir = NULL; 2052c393a42Smrg FcChar8 *base; 2067872e0a1Smrg const FcChar8 *sysroot = FcConfigGetSysRoot (config); 2072c393a42Smrg FcBool ret = FcTrue; 2082c393a42Smrg int i; 2092c393a42Smrg 210a6844aabSmrg if (!force) 211a6844aabSmrg return FcFalse; 212a6844aabSmrg 213a6844aabSmrg if (!set && !dirs) 214a6844aabSmrg return FcTrue; 215a6844aabSmrg 2162c393a42Smrg /* freed below */ 2177872e0a1Smrg file_prefix = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1); 2187872e0a1Smrg if (!file_prefix) { 2192c393a42Smrg ret = FcFalse; 2202c393a42Smrg goto bail; 2212c393a42Smrg } 2227872e0a1Smrg strcpy ((char *) file_prefix, (char *) dir); 2237872e0a1Smrg strcat ((char *) file_prefix, FC_DIR_SEPARATOR_S); 2247872e0a1Smrg base = file_prefix + strlen ((char *) file_prefix); 2252c393a42Smrg 2267872e0a1Smrg if (sysroot) 2277872e0a1Smrg s_dir = FcStrBuildFilename (sysroot, dir, NULL); 2287872e0a1Smrg else 2297872e0a1Smrg s_dir = FcStrdup (dir); 2307872e0a1Smrg if (!s_dir) { 2317872e0a1Smrg ret = FcFalse; 2327872e0a1Smrg goto bail; 2337872e0a1Smrg } 234ca08ab68Smrg 2352c393a42Smrg if (FcDebug () & FC_DBG_SCAN) 2367872e0a1Smrg printf ("\tScanning dir %s\n", s_dir); 2372c393a42Smrg 2387872e0a1Smrg d = opendir ((char *) s_dir); 2392c393a42Smrg if (!d) 2402c393a42Smrg { 2412c393a42Smrg /* Don't complain about missing directories */ 242a6844aabSmrg if (errno != ENOENT) 2432c393a42Smrg ret = FcFalse; 244a6844aabSmrg goto bail; 2452c393a42Smrg } 2462c393a42Smrg 247953daebaSmrg files = FcStrSetCreateEx (FCSS_ALLOW_DUPLICATES | FCSS_GROW_BY_64); 2482c393a42Smrg if (!files) 2492c393a42Smrg { 2502c393a42Smrg ret = FcFalse; 2512c393a42Smrg goto bail1; 2522c393a42Smrg } 2532c393a42Smrg while ((e = readdir (d))) 2542c393a42Smrg { 2552c393a42Smrg if (e->d_name[0] != '.' && strlen (e->d_name) < FC_MAX_FILE_LEN) 2562c393a42Smrg { 2572c393a42Smrg strcpy ((char *) base, (char *) e->d_name); 2587872e0a1Smrg if (!FcStrSetAdd (files, file_prefix)) { 2592c393a42Smrg ret = FcFalse; 2602c393a42Smrg goto bail2; 2612c393a42Smrg } 2622c393a42Smrg } 2632c393a42Smrg } 2642c393a42Smrg 2652c393a42Smrg /* 2662c393a42Smrg * Sort files to make things prettier 2672c393a42Smrg */ 2682c393a42Smrg qsort(files->strs, files->num, sizeof(FcChar8 *), cmpstringp); 269a6844aabSmrg 2702c393a42Smrg /* 2712c393a42Smrg * Scan file files to build font patterns 2722c393a42Smrg */ 2732c393a42Smrg for (i = 0; i < files->num; i++) 274a32e9e42Smrg FcFileScanConfig (set, dirs, files->strs[i], config); 275ca08ab68Smrg 276a6844aabSmrgbail2: 277a6844aabSmrg FcStrSetDestroy (files); 278a6844aabSmrgbail1: 279a6844aabSmrg closedir (d); 280a6844aabSmrgbail: 2817872e0a1Smrg if (s_dir) 2827872e0a1Smrg free (s_dir); 2837872e0a1Smrg if (file_prefix) 2847872e0a1Smrg free (file_prefix); 285ca08ab68Smrg 286a6844aabSmrg return ret; 287a6844aabSmrg} 288a6844aabSmrg 289a6844aabSmrgFcBool 290a6844aabSmrgFcDirScan (FcFontSet *set, 291a6844aabSmrg FcStrSet *dirs, 292a32e9e42Smrg FcFileCache *cache FC_UNUSED, 293a32e9e42Smrg FcBlanks *blanks FC_UNUSED, 294a6844aabSmrg const FcChar8 *dir, 295a32e9e42Smrg FcBool force FC_UNUSED) 296a6844aabSmrg{ 2977872e0a1Smrg FcConfig *config; 2987872e0a1Smrg FcBool ret; 2997872e0a1Smrg 300a6844aabSmrg if (cache || !force) 301a6844aabSmrg return FcFalse; 302a6844aabSmrg 3037872e0a1Smrg config = FcConfigReference (NULL); 3047872e0a1Smrg if (!config) 3057872e0a1Smrg return FcFalse; 3067872e0a1Smrg ret = FcDirScanConfig (set, dirs, dir, force, config); 3077872e0a1Smrg FcConfigDestroy (config); 3087872e0a1Smrg 3097872e0a1Smrg return ret; 310a6844aabSmrg} 311a6844aabSmrg 312a6844aabSmrg/* 313a6844aabSmrg * Scan the specified directory and construct a cache of its contents 314a6844aabSmrg */ 315a6844aabSmrgFcCache * 316a6844aabSmrgFcDirCacheScan (const FcChar8 *dir, FcConfig *config) 317a6844aabSmrg{ 318a6844aabSmrg FcStrSet *dirs; 319a6844aabSmrg FcFontSet *set; 320a6844aabSmrg FcCache *cache = NULL; 321a6844aabSmrg struct stat dir_stat; 322953daebaSmrg const FcChar8 *sysroot = FcConfigGetSysRoot (config); 323953daebaSmrg FcChar8 *d; 324a32e9e42Smrg#ifndef _WIN32 325953daebaSmrg int fd = -1; 326a32e9e42Smrg#endif 327953daebaSmrg 328953daebaSmrg if (sysroot) 329953daebaSmrg d = FcStrBuildFilename (sysroot, dir, NULL); 330953daebaSmrg else 331953daebaSmrg d = FcStrdup (dir); 332a6844aabSmrg 333a6844aabSmrg if (FcDebug () & FC_DBG_FONTSET) 334953daebaSmrg printf ("cache scan dir %s\n", d); 335a6844aabSmrg 336953daebaSmrg if (FcStatChecksum (d, &dir_stat) < 0) 337a6844aabSmrg goto bail; 338a6844aabSmrg 339a6844aabSmrg set = FcFontSetCreate(); 340a6844aabSmrg if (!set) 341a6844aabSmrg goto bail; 342a6844aabSmrg 343953daebaSmrg dirs = FcStrSetCreateEx (FCSS_GROW_BY_64); 344a6844aabSmrg if (!dirs) 345a6844aabSmrg goto bail1; 346a6844aabSmrg 347953daebaSmrg#ifndef _WIN32 348953daebaSmrg fd = FcDirCacheLock (dir, config); 349953daebaSmrg#endif 350a6844aabSmrg /* 351a6844aabSmrg * Scan the dir 352a6844aabSmrg */ 3537872e0a1Smrg /* Do not pass sysroot here. FcDirScanConfig() do take care of it */ 3547872e0a1Smrg if (!FcDirScanConfig (set, dirs, dir, FcTrue, config)) 355a6844aabSmrg goto bail2; 356a6844aabSmrg 3572c393a42Smrg /* 3582c393a42Smrg * Build the cache object 3592c393a42Smrg */ 3602c393a42Smrg cache = FcDirCacheBuild (set, dir, &dir_stat, dirs); 3612c393a42Smrg if (!cache) 362a6844aabSmrg goto bail2; 363ca08ab68Smrg 3642c393a42Smrg /* 3652c393a42Smrg * Write out the cache file, ignoring any troubles 3662c393a42Smrg */ 3672c393a42Smrg FcDirCacheWrite (cache, config); 368ca08ab68Smrg 3692c393a42Smrg bail2: 370953daebaSmrg#ifndef _WIN32 371953daebaSmrg FcDirCacheUnlock (fd); 372953daebaSmrg#endif 373a6844aabSmrg FcStrSetDestroy (dirs); 3742c393a42Smrg bail1: 3752c393a42Smrg FcFontSetDestroy (set); 3762c393a42Smrg bail: 377953daebaSmrg FcStrFree (d); 378953daebaSmrg 3792c393a42Smrg return cache; 3802c393a42Smrg} 3812c393a42Smrg 382b09479dcSmrgFcCache * 383b09479dcSmrgFcDirCacheRescan (const FcChar8 *dir, FcConfig *config) 384b09479dcSmrg{ 385953daebaSmrg FcCache *cache; 386b09479dcSmrg FcCache *new = NULL; 387b09479dcSmrg struct stat dir_stat; 388b09479dcSmrg FcStrSet *dirs; 3897872e0a1Smrg const FcChar8 *sysroot; 390953daebaSmrg FcChar8 *d = NULL; 391a32e9e42Smrg#ifndef _WIN32 392953daebaSmrg int fd = -1; 393a32e9e42Smrg#endif 394b09479dcSmrg 3957872e0a1Smrg config = FcConfigReference (config); 3967872e0a1Smrg if (!config) 3977872e0a1Smrg return NULL; 3987872e0a1Smrg sysroot = FcConfigGetSysRoot (config); 399953daebaSmrg cache = FcDirCacheLoad (dir, config, NULL); 400b09479dcSmrg if (!cache) 401b09479dcSmrg goto bail; 402953daebaSmrg 403953daebaSmrg if (sysroot) 404953daebaSmrg d = FcStrBuildFilename (sysroot, dir, NULL); 405953daebaSmrg else 406953daebaSmrg d = FcStrdup (dir); 407953daebaSmrg if (FcStatChecksum (d, &dir_stat) < 0) 408953daebaSmrg goto bail; 409953daebaSmrg dirs = FcStrSetCreateEx (FCSS_GROW_BY_64); 410b09479dcSmrg if (!dirs) 411b09479dcSmrg goto bail; 412b09479dcSmrg 413953daebaSmrg#ifndef _WIN32 414953daebaSmrg fd = FcDirCacheLock (dir, config); 415953daebaSmrg#endif 416b09479dcSmrg /* 417b09479dcSmrg * Scan the dir 418b09479dcSmrg */ 4197872e0a1Smrg /* Do not pass sysroot here. FcDirScanConfig() do take care of it */ 4207872e0a1Smrg if (!FcDirScanConfig (NULL, dirs, dir, FcTrue, config)) 421b09479dcSmrg goto bail1; 422b09479dcSmrg /* 423b09479dcSmrg * Rebuild the cache object 424b09479dcSmrg */ 425b09479dcSmrg new = FcDirCacheRebuild (cache, &dir_stat, dirs); 426b09479dcSmrg if (!new) 427b09479dcSmrg goto bail1; 428b09479dcSmrg FcDirCacheUnload (cache); 429b09479dcSmrg /* 430b09479dcSmrg * Write out the cache file, ignoring any troubles 431b09479dcSmrg */ 432b09479dcSmrg FcDirCacheWrite (new, config); 433b09479dcSmrg 434b09479dcSmrgbail1: 435953daebaSmrg#ifndef _WIN32 436953daebaSmrg FcDirCacheUnlock (fd); 437953daebaSmrg#endif 438b09479dcSmrg FcStrSetDestroy (dirs); 439b09479dcSmrgbail: 440953daebaSmrg if (d) 441953daebaSmrg FcStrFree (d); 4427872e0a1Smrg FcConfigDestroy (config); 443953daebaSmrg 444b09479dcSmrg return new; 445b09479dcSmrg} 446b09479dcSmrg 4472c393a42Smrg/* 4482c393a42Smrg * Read (or construct) the cache for a directory 4492c393a42Smrg */ 4502c393a42SmrgFcCache * 4512c393a42SmrgFcDirCacheRead (const FcChar8 *dir, FcBool force, FcConfig *config) 4522c393a42Smrg{ 4532c393a42Smrg FcCache *cache = NULL; 4542c393a42Smrg 4557872e0a1Smrg config = FcConfigReference (config); 4562c393a42Smrg /* Try to use existing cache file */ 4572c393a42Smrg if (!force) 4582c393a42Smrg cache = FcDirCacheLoad (dir, config, NULL); 459ca08ab68Smrg 4602c393a42Smrg /* Not using existing cache file, construct new cache */ 4612c393a42Smrg if (!cache) 4622c393a42Smrg cache = FcDirCacheScan (dir, config); 4637872e0a1Smrg FcConfigDestroy (config); 464ca08ab68Smrg 4652c393a42Smrg return cache; 4662c393a42Smrg} 4672c393a42Smrg 4682c393a42SmrgFcBool 469c9710b42SmrgFcDirSave (FcFontSet *set FC_UNUSED, FcStrSet * dirs FC_UNUSED, const FcChar8 *dir FC_UNUSED) 4702c393a42Smrg{ 4712c393a42Smrg return FcFalse; /* XXX deprecated */ 4722c393a42Smrg} 4732c393a42Smrg#define __fcdir__ 4742c393a42Smrg#include "fcaliastail.h" 4752c393a42Smrg#undef __fcdir__ 476