fcdir.c revision b09479dc
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 FcBlanks *blanks, 652c393a42Smrg const FcChar8 *file, 662c393a42Smrg FcConfig *config) 672c393a42Smrg{ 682c393a42Smrg FcPattern *font; 692c393a42Smrg FcBool ret = FcTrue; 702c393a42Smrg int id; 712c393a42Smrg int count = 0; 72ca08ab68Smrg 732c393a42Smrg id = 0; 742c393a42Smrg do 752c393a42Smrg { 762c393a42Smrg font = 0; 772c393a42Smrg /* 782c393a42Smrg * Nothing in the cache, scan the file 792c393a42Smrg */ 802c393a42Smrg if (FcDebug () & FC_DBG_SCAN) 812c393a42Smrg { 822c393a42Smrg printf ("\tScanning file %s...", file); 832c393a42Smrg fflush (stdout); 842c393a42Smrg } 852c393a42Smrg font = FcFreeTypeQuery (file, id, blanks, &count); 862c393a42Smrg if (FcDebug () & FC_DBG_SCAN) 872c393a42Smrg printf ("done\n"); 882c393a42Smrg 892c393a42Smrg /* 902c393a42Smrg * Edit pattern with user-defined rules 912c393a42Smrg */ 92ca08ab68Smrg if (font && config && !FcConfigSubstitute (config, font, FcMatchScan)) 932c393a42Smrg { 942c393a42Smrg FcPatternDestroy (font); 952c393a42Smrg font = NULL; 962c393a42Smrg ret = FcFalse; 972c393a42Smrg } 982c393a42Smrg 992c393a42Smrg /* 1002c393a42Smrg * Add the font 1012c393a42Smrg */ 102ca08ab68Smrg if (font) 1032c393a42Smrg { 1042c393a42Smrg if (FcDebug() & FC_DBG_SCANV) 1052c393a42Smrg { 1062c393a42Smrg printf ("Final font pattern:\n"); 1072c393a42Smrg FcPatternPrint (font); 1082c393a42Smrg } 1092c393a42Smrg if (!FcFontSetAdd (set, font)) 1102c393a42Smrg { 1112c393a42Smrg FcPatternDestroy (font); 1122c393a42Smrg font = NULL; 1132c393a42Smrg ret = FcFalse; 1142c393a42Smrg } 1152c393a42Smrg } 1162c393a42Smrg else if (font) 1172c393a42Smrg FcPatternDestroy (font); 1182c393a42Smrg id++; 1192c393a42Smrg } while (font && ret && id < count); 1202c393a42Smrg return ret; 1212c393a42Smrg} 1222c393a42Smrg 1232c393a42SmrgFcBool 1242c393a42SmrgFcFileScanConfig (FcFontSet *set, 1252c393a42Smrg FcStrSet *dirs, 1262c393a42Smrg FcBlanks *blanks, 1272c393a42Smrg const FcChar8 *file, 1282c393a42Smrg FcConfig *config) 1292c393a42Smrg{ 1302c393a42Smrg if (FcFileIsDir (file)) 1312c393a42Smrg return FcStrSetAdd (dirs, file); 1322c393a42Smrg else 133b09479dcSmrg { 134b09479dcSmrg if (set) 135b09479dcSmrg return FcFileScanFontConfig (set, blanks, file, config); 136b09479dcSmrg else 137b09479dcSmrg return FcTrue; 138b09479dcSmrg } 1392c393a42Smrg} 1402c393a42Smrg 1412c393a42SmrgFcBool 1422c393a42SmrgFcFileScan (FcFontSet *set, 1432c393a42Smrg FcStrSet *dirs, 144c9710b42Smrg FcFileCache *cache FC_UNUSED, 1452c393a42Smrg FcBlanks *blanks, 1462c393a42Smrg const FcChar8 *file, 147c9710b42Smrg FcBool force FC_UNUSED) 1482c393a42Smrg{ 149a6844aabSmrg return FcFileScanConfig (set, dirs, blanks, file, FcConfigGetCurrent ()); 1502c393a42Smrg} 1512c393a42Smrg 1522c393a42Smrg/* 1532c393a42Smrg * Strcmp helper that takes pointers to pointers, copied from qsort(3) manpage 1542c393a42Smrg */ 1552c393a42Smrgstatic int 1562c393a42Smrgcmpstringp(const void *p1, const void *p2) 1572c393a42Smrg{ 1582c393a42Smrg return strcmp(* (char **) p1, * (char **) p2); 1592c393a42Smrg} 1602c393a42Smrg 161a6844aabSmrgFcBool 162a6844aabSmrgFcDirScanConfig (FcFontSet *set, 163a6844aabSmrg FcStrSet *dirs, 164a6844aabSmrg FcBlanks *blanks, 165a6844aabSmrg const FcChar8 *dir, 166a6844aabSmrg FcBool force, /* XXX unused */ 167a6844aabSmrg FcConfig *config) 1682c393a42Smrg{ 1692c393a42Smrg DIR *d; 1702c393a42Smrg struct dirent *e; 1712c393a42Smrg FcStrSet *files; 1722c393a42Smrg FcChar8 *file; 1732c393a42Smrg FcChar8 *base; 1742c393a42Smrg FcBool ret = FcTrue; 1752c393a42Smrg int i; 1762c393a42Smrg 177a6844aabSmrg if (!force) 178a6844aabSmrg return FcFalse; 179a6844aabSmrg 180a6844aabSmrg if (!set && !dirs) 181a6844aabSmrg return FcTrue; 182a6844aabSmrg 183a6844aabSmrg if (!blanks) 184a6844aabSmrg blanks = FcConfigGetBlanks (config); 1852c393a42Smrg 1862c393a42Smrg /* freed below */ 1872c393a42Smrg file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1); 1882c393a42Smrg if (!file) { 1892c393a42Smrg ret = FcFalse; 1902c393a42Smrg goto bail; 1912c393a42Smrg } 1922c393a42Smrg 1932c393a42Smrg strcpy ((char *) file, (char *) dir); 1942c393a42Smrg strcat ((char *) file, "/"); 1952c393a42Smrg base = file + strlen ((char *) file); 196ca08ab68Smrg 1972c393a42Smrg if (FcDebug () & FC_DBG_SCAN) 1982c393a42Smrg printf ("\tScanning dir %s\n", dir); 1992c393a42Smrg 2002c393a42Smrg d = opendir ((char *) dir); 2012c393a42Smrg if (!d) 2022c393a42Smrg { 2032c393a42Smrg /* Don't complain about missing directories */ 204a6844aabSmrg if (errno != ENOENT) 2052c393a42Smrg ret = FcFalse; 206a6844aabSmrg goto bail; 2072c393a42Smrg } 2082c393a42Smrg 2092c393a42Smrg files = FcStrSetCreate (); 2102c393a42Smrg if (!files) 2112c393a42Smrg { 2122c393a42Smrg ret = FcFalse; 2132c393a42Smrg goto bail1; 2142c393a42Smrg } 2152c393a42Smrg while ((e = readdir (d))) 2162c393a42Smrg { 2172c393a42Smrg if (e->d_name[0] != '.' && strlen (e->d_name) < FC_MAX_FILE_LEN) 2182c393a42Smrg { 2192c393a42Smrg strcpy ((char *) base, (char *) e->d_name); 2202c393a42Smrg if (!FcStrSetAdd (files, file)) { 2212c393a42Smrg ret = FcFalse; 2222c393a42Smrg goto bail2; 2232c393a42Smrg } 2242c393a42Smrg } 2252c393a42Smrg } 2262c393a42Smrg 2272c393a42Smrg /* 2282c393a42Smrg * Sort files to make things prettier 2292c393a42Smrg */ 2302c393a42Smrg qsort(files->strs, files->num, sizeof(FcChar8 *), cmpstringp); 231a6844aabSmrg 2322c393a42Smrg /* 2332c393a42Smrg * Scan file files to build font patterns 2342c393a42Smrg */ 2352c393a42Smrg for (i = 0; i < files->num; i++) 2362c393a42Smrg FcFileScanConfig (set, dirs, blanks, files->strs[i], config); 237ca08ab68Smrg 238a6844aabSmrgbail2: 239a6844aabSmrg FcStrSetDestroy (files); 240a6844aabSmrgbail1: 241a6844aabSmrg closedir (d); 242a6844aabSmrgbail: 243ca08ab68Smrg if (file) 244ca08ab68Smrg free (file); 245ca08ab68Smrg 246a6844aabSmrg return ret; 247a6844aabSmrg} 248a6844aabSmrg 249a6844aabSmrgFcBool 250a6844aabSmrgFcDirScan (FcFontSet *set, 251a6844aabSmrg FcStrSet *dirs, 252a6844aabSmrg FcFileCache *cache, /* XXX unused */ 253a6844aabSmrg FcBlanks *blanks, 254a6844aabSmrg const FcChar8 *dir, 255a6844aabSmrg FcBool force /* XXX unused */) 256a6844aabSmrg{ 257a6844aabSmrg if (cache || !force) 258a6844aabSmrg return FcFalse; 259a6844aabSmrg 260a6844aabSmrg return FcDirScanConfig (set, dirs, blanks, dir, force, FcConfigGetCurrent ()); 261a6844aabSmrg} 262a6844aabSmrg 263a6844aabSmrg/* 264a6844aabSmrg * Scan the specified directory and construct a cache of its contents 265a6844aabSmrg */ 266a6844aabSmrgFcCache * 267a6844aabSmrgFcDirCacheScan (const FcChar8 *dir, FcConfig *config) 268a6844aabSmrg{ 269a6844aabSmrg FcStrSet *dirs; 270a6844aabSmrg FcFontSet *set; 271a6844aabSmrg FcCache *cache = NULL; 272a6844aabSmrg struct stat dir_stat; 273a6844aabSmrg 274a6844aabSmrg if (FcDebug () & FC_DBG_FONTSET) 275a6844aabSmrg printf ("cache scan dir %s\n", dir); 276a6844aabSmrg 277ca08ab68Smrg if (FcStatChecksum (dir, &dir_stat) < 0) 278a6844aabSmrg goto bail; 279a6844aabSmrg 280a6844aabSmrg set = FcFontSetCreate(); 281a6844aabSmrg if (!set) 282a6844aabSmrg goto bail; 283a6844aabSmrg 284a6844aabSmrg dirs = FcStrSetCreate (); 285a6844aabSmrg if (!dirs) 286a6844aabSmrg goto bail1; 287a6844aabSmrg 288a6844aabSmrg /* 289a6844aabSmrg * Scan the dir 290a6844aabSmrg */ 291a6844aabSmrg if (!FcDirScanConfig (set, dirs, NULL, dir, FcTrue, config)) 292a6844aabSmrg goto bail2; 293a6844aabSmrg 2942c393a42Smrg /* 2952c393a42Smrg * Build the cache object 2962c393a42Smrg */ 2972c393a42Smrg cache = FcDirCacheBuild (set, dir, &dir_stat, dirs); 2982c393a42Smrg if (!cache) 299a6844aabSmrg goto bail2; 300ca08ab68Smrg 3012c393a42Smrg /* 3022c393a42Smrg * Write out the cache file, ignoring any troubles 3032c393a42Smrg */ 3042c393a42Smrg FcDirCacheWrite (cache, config); 305ca08ab68Smrg 3062c393a42Smrg bail2: 307a6844aabSmrg FcStrSetDestroy (dirs); 3082c393a42Smrg bail1: 3092c393a42Smrg FcFontSetDestroy (set); 3102c393a42Smrg bail: 3112c393a42Smrg return cache; 3122c393a42Smrg} 3132c393a42Smrg 314b09479dcSmrgFcCache * 315b09479dcSmrgFcDirCacheRescan (const FcChar8 *dir, FcConfig *config) 316b09479dcSmrg{ 317b09479dcSmrg FcCache *cache = FcDirCacheLoad (dir, config, NULL); 318b09479dcSmrg FcCache *new = NULL; 319b09479dcSmrg struct stat dir_stat; 320b09479dcSmrg FcStrSet *dirs; 321b09479dcSmrg 322b09479dcSmrg if (!cache) 323b09479dcSmrg return NULL; 324b09479dcSmrg if (FcStatChecksum (dir, &dir_stat) < 0) 325b09479dcSmrg goto bail; 326b09479dcSmrg dirs = FcStrSetCreate (); 327b09479dcSmrg if (!dirs) 328b09479dcSmrg goto bail; 329b09479dcSmrg 330b09479dcSmrg /* 331b09479dcSmrg * Scan the dir 332b09479dcSmrg */ 333b09479dcSmrg if (!FcDirScanConfig (NULL, dirs, NULL, dir, FcTrue, config)) 334b09479dcSmrg goto bail1; 335b09479dcSmrg /* 336b09479dcSmrg * Rebuild the cache object 337b09479dcSmrg */ 338b09479dcSmrg new = FcDirCacheRebuild (cache, &dir_stat, dirs); 339b09479dcSmrg if (!new) 340b09479dcSmrg goto bail1; 341b09479dcSmrg FcDirCacheUnload (cache); 342b09479dcSmrg /* 343b09479dcSmrg * Write out the cache file, ignoring any troubles 344b09479dcSmrg */ 345b09479dcSmrg FcDirCacheWrite (new, config); 346b09479dcSmrg 347b09479dcSmrgbail1: 348b09479dcSmrg FcStrSetDestroy (dirs); 349b09479dcSmrgbail: 350b09479dcSmrg return new; 351b09479dcSmrg} 352b09479dcSmrg 3532c393a42Smrg/* 3542c393a42Smrg * Read (or construct) the cache for a directory 3552c393a42Smrg */ 3562c393a42SmrgFcCache * 3572c393a42SmrgFcDirCacheRead (const FcChar8 *dir, FcBool force, FcConfig *config) 3582c393a42Smrg{ 3592c393a42Smrg FcCache *cache = NULL; 3602c393a42Smrg 3612c393a42Smrg /* Try to use existing cache file */ 3622c393a42Smrg if (!force) 3632c393a42Smrg cache = FcDirCacheLoad (dir, config, NULL); 364ca08ab68Smrg 3652c393a42Smrg /* Not using existing cache file, construct new cache */ 3662c393a42Smrg if (!cache) 3672c393a42Smrg cache = FcDirCacheScan (dir, config); 368ca08ab68Smrg 3692c393a42Smrg return cache; 3702c393a42Smrg} 3712c393a42Smrg 3722c393a42SmrgFcBool 373c9710b42SmrgFcDirSave (FcFontSet *set FC_UNUSED, FcStrSet * dirs FC_UNUSED, const FcChar8 *dir FC_UNUSED) 3742c393a42Smrg{ 3752c393a42Smrg return FcFalse; /* XXX deprecated */ 3762c393a42Smrg} 3772c393a42Smrg#define __fcdir__ 3782c393a42Smrg#include "fcaliastail.h" 3792c393a42Smrg#undef __fcdir__ 380