12c393a42Smrg/* 2a6844aabSmrg * fontconfig/src/fccfg.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 25c9710b42Smrg/* Objects MT-safe for readonly access. */ 26c9710b42Smrg 272c393a42Smrg#include "fcint.h" 287872e0a1Smrg#ifdef HAVE_DIRENT_H 292c393a42Smrg#include <dirent.h> 307872e0a1Smrg#endif 312c393a42Smrg#include <sys/types.h> 322c393a42Smrg 332c393a42Smrg#if defined (_WIN32) && !defined (R_OK) 342c393a42Smrg#define R_OK 4 352c393a42Smrg#endif 362c393a42Smrg 377872e0a1Smrg#if defined(_WIN32) && !defined(S_ISFIFO) 387872e0a1Smrg#define S_ISFIFO(m) 0 397872e0a1Smrg#endif 407872e0a1Smrg 41c9710b42Smrgstatic FcConfig *_fcConfig; /* MT-safe */ 427872e0a1Smrgstatic FcMutex *_lock; 437872e0a1Smrg 447872e0a1Smrgstatic void 457872e0a1Smrglock_config (void) 467872e0a1Smrg{ 477872e0a1Smrg FcMutex *lock; 487872e0a1Smrgretry: 497872e0a1Smrg lock = fc_atomic_ptr_get (&_lock); 507872e0a1Smrg if (!lock) 517872e0a1Smrg { 527872e0a1Smrg lock = (FcMutex *) malloc (sizeof (FcMutex)); 537872e0a1Smrg FcMutexInit (lock); 547872e0a1Smrg if (!fc_atomic_ptr_cmpexch (&_lock, NULL, lock)) 557872e0a1Smrg { 567872e0a1Smrg FcMutexFinish (lock); 577872e0a1Smrg free (lock); 587872e0a1Smrg goto retry; 597872e0a1Smrg } 607872e0a1Smrg FcMutexLock (lock); 617872e0a1Smrg /* Initialize random state */ 627872e0a1Smrg FcRandom (); 637872e0a1Smrg return; 647872e0a1Smrg } 657872e0a1Smrg FcMutexLock (lock); 667872e0a1Smrg} 677872e0a1Smrg 687872e0a1Smrgstatic void 697872e0a1Smrgunlock_config (void) 707872e0a1Smrg{ 717872e0a1Smrg FcMutex *lock; 727872e0a1Smrg lock = fc_atomic_ptr_get (&_lock); 737872e0a1Smrg FcMutexUnlock (lock); 747872e0a1Smrg} 757872e0a1Smrg 767872e0a1Smrgstatic void 777872e0a1Smrgfree_lock (void) 787872e0a1Smrg{ 797872e0a1Smrg FcMutex *lock; 807872e0a1Smrg lock = fc_atomic_ptr_get (&_lock); 817872e0a1Smrg if (lock && fc_atomic_ptr_cmpexch (&_lock, lock, NULL)) 827872e0a1Smrg { 837872e0a1Smrg FcMutexFinish (lock); 847872e0a1Smrg free (lock); 857872e0a1Smrg } 867872e0a1Smrg} 87c9710b42Smrg 88c9710b42Smrgstatic FcConfig * 89c9710b42SmrgFcConfigEnsure (void) 90c9710b42Smrg{ 91c9710b42Smrg FcConfig *config; 92c9710b42Smrgretry: 93c9710b42Smrg config = fc_atomic_ptr_get (&_fcConfig); 94c9710b42Smrg if (!config) 95c9710b42Smrg { 96c9710b42Smrg config = FcInitLoadConfigAndFonts (); 97c9710b42Smrg 987872e0a1Smrg if (!config || !fc_atomic_ptr_cmpexch (&_fcConfig, NULL, config)) { 997872e0a1Smrg if (config) 1007872e0a1Smrg FcConfigDestroy (config); 101c9710b42Smrg goto retry; 102c9710b42Smrg } 103c9710b42Smrg } 104c9710b42Smrg return config; 105c9710b42Smrg} 106c9710b42Smrg 1071887081fSmrgstatic void 1081887081fSmrgFcDestroyAsRule (void *data) 1091887081fSmrg{ 1101887081fSmrg FcRuleDestroy (data); 1111887081fSmrg} 1121887081fSmrg 1131887081fSmrgstatic void 1141887081fSmrgFcDestroyAsRuleSet (void *data) 1151887081fSmrg{ 1161887081fSmrg FcRuleSetDestroy (data); 1171887081fSmrg} 1181887081fSmrg 119c9710b42SmrgFcBool 120c9710b42SmrgFcConfigInit (void) 121c9710b42Smrg{ 122c9710b42Smrg return FcConfigEnsure () ? FcTrue : FcFalse; 123c9710b42Smrg} 124c9710b42Smrg 125c9710b42Smrgvoid 126c9710b42SmrgFcConfigFini (void) 127c9710b42Smrg{ 128c9710b42Smrg FcConfig *cfg = fc_atomic_ptr_get (&_fcConfig); 129c9710b42Smrg if (cfg && fc_atomic_ptr_cmpexch (&_fcConfig, cfg, NULL)) 130c9710b42Smrg FcConfigDestroy (cfg); 1317872e0a1Smrg free_lock (); 132c9710b42Smrg} 133c9710b42Smrg 1342c393a42SmrgFcConfig * 1352c393a42SmrgFcConfigCreate (void) 1362c393a42Smrg{ 1372c393a42Smrg FcSetName set; 1382c393a42Smrg FcConfig *config; 1391887081fSmrg FcMatchKind k; 1401887081fSmrg FcBool err = FcFalse; 1412c393a42Smrg 1422c393a42Smrg config = malloc (sizeof (FcConfig)); 1432c393a42Smrg if (!config) 1442c393a42Smrg goto bail0; 145ca08ab68Smrg 1462c393a42Smrg config->configDirs = FcStrSetCreate (); 1472c393a42Smrg if (!config->configDirs) 1482c393a42Smrg goto bail1; 149ca08ab68Smrg 1502c393a42Smrg config->configFiles = FcStrSetCreate (); 1512c393a42Smrg if (!config->configFiles) 1522c393a42Smrg goto bail2; 153ca08ab68Smrg 1542c393a42Smrg config->fontDirs = FcStrSetCreate (); 1552c393a42Smrg if (!config->fontDirs) 1562c393a42Smrg goto bail3; 157ca08ab68Smrg 1582c393a42Smrg config->acceptGlobs = FcStrSetCreate (); 1592c393a42Smrg if (!config->acceptGlobs) 1602c393a42Smrg goto bail4; 1612c393a42Smrg 1622c393a42Smrg config->rejectGlobs = FcStrSetCreate (); 1632c393a42Smrg if (!config->rejectGlobs) 1642c393a42Smrg goto bail5; 1652c393a42Smrg 1662c393a42Smrg config->acceptPatterns = FcFontSetCreate (); 1672c393a42Smrg if (!config->acceptPatterns) 1682c393a42Smrg goto bail6; 169ca08ab68Smrg 1702c393a42Smrg config->rejectPatterns = FcFontSetCreate (); 1712c393a42Smrg if (!config->rejectPatterns) 1722c393a42Smrg goto bail7; 1732c393a42Smrg 1742c393a42Smrg config->cacheDirs = FcStrSetCreate (); 1752c393a42Smrg if (!config->cacheDirs) 1762c393a42Smrg goto bail8; 177ca08ab68Smrg 1781887081fSmrg for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++) 1791887081fSmrg { 1801887081fSmrg config->subst[k] = FcPtrListCreate (FcDestroyAsRuleSet); 1811887081fSmrg if (!config->subst[k]) 1821887081fSmrg err = FcTrue; 1831887081fSmrg } 1841887081fSmrg if (err) 1851887081fSmrg goto bail9; 1862c393a42Smrg 1872c393a42Smrg config->maxObjects = 0; 1882c393a42Smrg for (set = FcSetSystem; set <= FcSetApplication; set++) 1892c393a42Smrg config->fonts[set] = 0; 1902c393a42Smrg 1912c393a42Smrg config->rescanTime = time(0); 192ca08ab68Smrg config->rescanInterval = 30; 193a6844aabSmrg 194a6844aabSmrg config->expr_pool = NULL; 195a6844aabSmrg 1967872e0a1Smrg config->sysRoot = FcStrRealPath ((const FcChar8 *) getenv("FONTCONFIG_SYSROOT")); 197c9710b42Smrg 1981887081fSmrg config->rulesetList = FcPtrListCreate (FcDestroyAsRuleSet); 1991887081fSmrg if (!config->rulesetList) 2001887081fSmrg goto bail9; 2011887081fSmrg config->availConfigFiles = FcStrSetCreate (); 2021887081fSmrg if (!config->availConfigFiles) 2031887081fSmrg goto bail10; 2041887081fSmrg 205c9710b42Smrg FcRefInit (&config->ref, 1); 206ca08ab68Smrg 2072c393a42Smrg return config; 2082c393a42Smrg 2091887081fSmrgbail10: 2101887081fSmrg FcPtrListDestroy (config->rulesetList); 2111887081fSmrgbail9: 2121887081fSmrg for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++) 2131887081fSmrg if (config->subst[k]) 2141887081fSmrg FcPtrListDestroy (config->subst[k]); 2151887081fSmrg FcStrSetDestroy (config->cacheDirs); 2162c393a42Smrgbail8: 2172c393a42Smrg FcFontSetDestroy (config->rejectPatterns); 2182c393a42Smrgbail7: 2192c393a42Smrg FcFontSetDestroy (config->acceptPatterns); 2202c393a42Smrgbail6: 2212c393a42Smrg FcStrSetDestroy (config->rejectGlobs); 2222c393a42Smrgbail5: 2232c393a42Smrg FcStrSetDestroy (config->acceptGlobs); 2242c393a42Smrgbail4: 2252c393a42Smrg FcStrSetDestroy (config->fontDirs); 2262c393a42Smrgbail3: 2272c393a42Smrg FcStrSetDestroy (config->configFiles); 2282c393a42Smrgbail2: 2292c393a42Smrg FcStrSetDestroy (config->configDirs); 2302c393a42Smrgbail1: 2312c393a42Smrg free (config); 2322c393a42Smrgbail0: 2332c393a42Smrg return 0; 2342c393a42Smrg} 2352c393a42Smrg 2362c393a42Smrgstatic FcFileTime 2372c393a42SmrgFcConfigNewestFile (FcStrSet *files) 2382c393a42Smrg{ 2392c393a42Smrg FcStrList *list = FcStrListCreate (files); 2402c393a42Smrg FcFileTime newest = { 0, FcFalse }; 2412c393a42Smrg FcChar8 *file; 2422c393a42Smrg struct stat statb; 2432c393a42Smrg 2442c393a42Smrg if (list) 2452c393a42Smrg { 2462c393a42Smrg while ((file = FcStrListNext (list))) 247ca08ab68Smrg if (FcStat (file, &statb) == 0) 2482c393a42Smrg if (!newest.set || statb.st_mtime - newest.time > 0) 2492c393a42Smrg { 2502c393a42Smrg newest.set = FcTrue; 2512c393a42Smrg newest.time = statb.st_mtime; 2522c393a42Smrg } 2532c393a42Smrg FcStrListDone (list); 2542c393a42Smrg } 2552c393a42Smrg return newest; 2562c393a42Smrg} 2572c393a42Smrg 2582c393a42SmrgFcBool 2592c393a42SmrgFcConfigUptoDate (FcConfig *config) 2602c393a42Smrg{ 2612c393a42Smrg FcFileTime config_time, config_dir_time, font_time; 2622c393a42Smrg time_t now = time(0); 2637872e0a1Smrg FcBool ret = FcTrue; 2647872e0a1Smrg 2657872e0a1Smrg config = FcConfigReference (config); 2662c393a42Smrg if (!config) 2677872e0a1Smrg return FcFalse; 2687872e0a1Smrg 2692c393a42Smrg config_time = FcConfigNewestFile (config->configFiles); 2702c393a42Smrg config_dir_time = FcConfigNewestFile (config->configDirs); 2712c393a42Smrg font_time = FcConfigNewestFile (config->fontDirs); 2722c393a42Smrg if ((config_time.set && config_time.time - config->rescanTime > 0) || 2732c393a42Smrg (config_dir_time.set && (config_dir_time.time - config->rescanTime) > 0) || 2742c393a42Smrg (font_time.set && (font_time.time - config->rescanTime) > 0)) 2752c393a42Smrg { 2762c393a42Smrg /* We need to check for potential clock problems here (OLPC ticket #6046) */ 2772c393a42Smrg if ((config_time.set && (config_time.time - now) > 0) || 2782c393a42Smrg (config_dir_time.set && (config_dir_time.time - now) > 0) || 2792c393a42Smrg (font_time.set && (font_time.time - now) > 0)) 2802c393a42Smrg { 2812c393a42Smrg fprintf (stderr, 282c9710b42Smrg "Fontconfig warning: Directory/file mtime in the future. New fonts may not be detected.\n"); 2832c393a42Smrg config->rescanTime = now; 2847872e0a1Smrg goto bail; 2852c393a42Smrg } 2862c393a42Smrg else 2877872e0a1Smrg { 2887872e0a1Smrg ret = FcFalse; 2897872e0a1Smrg goto bail; 2907872e0a1Smrg } 2912c393a42Smrg } 2922c393a42Smrg config->rescanTime = now; 2937872e0a1Smrgbail: 2947872e0a1Smrg FcConfigDestroy (config); 2957872e0a1Smrg 2967872e0a1Smrg return ret; 2972c393a42Smrg} 2982c393a42Smrg 299a6844aabSmrgFcExpr * 300a6844aabSmrgFcConfigAllocExpr (FcConfig *config) 301a6844aabSmrg{ 3026fc018e4Smrg if (!config->expr_pool || config->expr_pool->next == config->expr_pool->end) 3036fc018e4Smrg { 3046fc018e4Smrg FcExprPage *new_page; 305a6844aabSmrg 3066fc018e4Smrg new_page = malloc (sizeof (FcExprPage)); 3076fc018e4Smrg if (!new_page) 3086fc018e4Smrg return 0; 309a6844aabSmrg 3106fc018e4Smrg new_page->next_page = config->expr_pool; 3116fc018e4Smrg new_page->next = new_page->exprs; 3126fc018e4Smrg config->expr_pool = new_page; 3136fc018e4Smrg } 314a6844aabSmrg 3156fc018e4Smrg return config->expr_pool->next++; 316a6844aabSmrg} 317a6844aabSmrg 318a6844aabSmrgFcConfig * 319a6844aabSmrgFcConfigReference (FcConfig *config) 320a6844aabSmrg{ 321a6844aabSmrg if (!config) 322a6844aabSmrg { 3237872e0a1Smrg /* lock during obtaining the value from _fcConfig and count up refcount there, 3247872e0a1Smrg * there are the race between them. 3257872e0a1Smrg */ 3267872e0a1Smrg lock_config (); 3277872e0a1Smrg retry: 3287872e0a1Smrg config = fc_atomic_ptr_get (&_fcConfig); 329a6844aabSmrg if (!config) 3307872e0a1Smrg { 3317872e0a1Smrg unlock_config (); 332a6844aabSmrg 3337872e0a1Smrg config = FcInitLoadConfigAndFonts (); 3347872e0a1Smrg if (!config) 3357872e0a1Smrg goto retry; 3367872e0a1Smrg lock_config (); 3377872e0a1Smrg if (!fc_atomic_ptr_cmpexch (&_fcConfig, NULL, config)) 3387872e0a1Smrg { 3397872e0a1Smrg FcConfigDestroy (config); 3407872e0a1Smrg goto retry; 3417872e0a1Smrg } 3427872e0a1Smrg } 3437872e0a1Smrg FcRefInc (&config->ref); 3447872e0a1Smrg unlock_config (); 3457872e0a1Smrg } 3467872e0a1Smrg else 3477872e0a1Smrg FcRefInc (&config->ref); 348a6844aabSmrg 349a6844aabSmrg return config; 350a6844aabSmrg} 351a6844aabSmrg 3522c393a42Smrgvoid 3532c393a42SmrgFcConfigDestroy (FcConfig *config) 3542c393a42Smrg{ 3552c393a42Smrg FcSetName set; 356a6844aabSmrg FcExprPage *page; 3571887081fSmrg FcMatchKind k; 358a6844aabSmrg 35946bb3e47Smrg if (config) 36046bb3e47Smrg { 36146bb3e47Smrg if (FcRefDec (&config->ref) != 1) 36246bb3e47Smrg return; 3632c393a42Smrg 36446bb3e47Smrg (void) fc_atomic_ptr_cmpexch (&_fcConfig, config, NULL); 3652c393a42Smrg 36646bb3e47Smrg FcStrSetDestroy (config->configDirs); 36746bb3e47Smrg FcStrSetDestroy (config->fontDirs); 36846bb3e47Smrg FcStrSetDestroy (config->cacheDirs); 36946bb3e47Smrg FcStrSetDestroy (config->configFiles); 37046bb3e47Smrg FcStrSetDestroy (config->acceptGlobs); 37146bb3e47Smrg FcStrSetDestroy (config->rejectGlobs); 37246bb3e47Smrg FcFontSetDestroy (config->acceptPatterns); 37346bb3e47Smrg FcFontSetDestroy (config->rejectPatterns); 3742c393a42Smrg 37546bb3e47Smrg for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++) 37646bb3e47Smrg FcPtrListDestroy (config->subst[k]); 37746bb3e47Smrg FcPtrListDestroy (config->rulesetList); 37846bb3e47Smrg FcStrSetDestroy (config->availConfigFiles); 37946bb3e47Smrg for (set = FcSetSystem; set <= FcSetApplication; set++) 38046bb3e47Smrg if (config->fonts[set]) 38146bb3e47Smrg FcFontSetDestroy (config->fonts[set]); 38246bb3e47Smrg 38346bb3e47Smrg page = config->expr_pool; 38446bb3e47Smrg while (page) 38546bb3e47Smrg { 38646bb3e47Smrg FcExprPage *next = page->next_page; 38746bb3e47Smrg free (page); 38846bb3e47Smrg page = next; 38946bb3e47Smrg } 39046bb3e47Smrg if (config->sysRoot) 391c9710b42Smrg FcStrFree (config->sysRoot); 392a6844aabSmrg 39346bb3e47Smrg free (config); 39446bb3e47Smrg } 3952c393a42Smrg} 3962c393a42Smrg 3972c393a42Smrg/* 3982c393a42Smrg * Add cache to configuration, adding fonts and directories 3992c393a42Smrg */ 4002c393a42Smrg 4012c393a42SmrgFcBool 402ca08ab68SmrgFcConfigAddCache (FcConfig *config, FcCache *cache, 4031887081fSmrg FcSetName set, FcStrSet *dirSet, FcChar8 *forDir) 4042c393a42Smrg{ 4052c393a42Smrg FcFontSet *fs; 4062c393a42Smrg intptr_t *dirs; 4072c393a42Smrg int i; 4081887081fSmrg FcBool relocated = FcFalse; 4091887081fSmrg 4101887081fSmrg if (strcmp ((char *)FcCacheDir(cache), (char *)forDir) != 0) 4111887081fSmrg relocated = FcTrue; 4122c393a42Smrg 4132c393a42Smrg /* 4142c393a42Smrg * Add fonts 4152c393a42Smrg */ 4162c393a42Smrg fs = FcCacheSet (cache); 4172c393a42Smrg if (fs) 4182c393a42Smrg { 4192c393a42Smrg int nref = 0; 42046bb3e47Smrg 4212c393a42Smrg for (i = 0; i < fs->nfont; i++) 4222c393a42Smrg { 4232c393a42Smrg FcPattern *font = FcFontSetFont (fs, i); 4242c393a42Smrg FcChar8 *font_file; 4251887081fSmrg FcChar8 *relocated_font_file = NULL; 4262c393a42Smrg 4272c393a42Smrg if (FcPatternObjectGetString (font, FC_FILE_OBJECT, 4281887081fSmrg 0, &font_file) == FcResultMatch) 4292c393a42Smrg { 4301887081fSmrg if (relocated) 4311887081fSmrg { 4321887081fSmrg FcChar8 *slash = FcStrLastSlash (font_file); 4331887081fSmrg relocated_font_file = FcStrBuildFilename (forDir, slash + 1, NULL); 4341887081fSmrg font_file = relocated_font_file; 4351887081fSmrg } 4361887081fSmrg 4371887081fSmrg /* 4381887081fSmrg * Check to see if font is banned by filename 4391887081fSmrg */ 4401887081fSmrg if (!FcConfigAcceptFilename (config, font_file)) 4411887081fSmrg { 4421887081fSmrg free (relocated_font_file); 4431887081fSmrg continue; 4441887081fSmrg } 4452c393a42Smrg } 4461887081fSmrg 4472c393a42Smrg /* 4482c393a42Smrg * Check to see if font is banned by pattern 4492c393a42Smrg */ 4502c393a42Smrg if (!FcConfigAcceptFont (config, font)) 4511887081fSmrg { 4521887081fSmrg free (relocated_font_file); 4532c393a42Smrg continue; 4541887081fSmrg } 4551887081fSmrg 4561887081fSmrg if (relocated_font_file) 4571887081fSmrg { 4581887081fSmrg font = FcPatternCacheRewriteFile (font, cache, relocated_font_file); 4591887081fSmrg free (relocated_font_file); 4601887081fSmrg } 4611887081fSmrg 462c9710b42Smrg if (FcFontSetAdd (config->fonts[set], font)) 463c9710b42Smrg nref++; 4642c393a42Smrg } 4652c393a42Smrg FcDirCacheReference (cache, nref); 4662c393a42Smrg } 4672c393a42Smrg 4682c393a42Smrg /* 4692c393a42Smrg * Add directories 4702c393a42Smrg */ 4712c393a42Smrg dirs = FcCacheDirs (cache); 4722c393a42Smrg if (dirs) 4732c393a42Smrg { 4742c393a42Smrg for (i = 0; i < cache->dirs_count; i++) 4752c393a42Smrg { 4761887081fSmrg const FcChar8 *dir = FcCacheSubdir (cache, i); 4771887081fSmrg FcChar8 *s = NULL; 4781887081fSmrg 4791887081fSmrg if (relocated) 4801887081fSmrg { 4811887081fSmrg FcChar8 *base = FcStrBasename (dir); 4821887081fSmrg dir = s = FcStrBuildFilename (forDir, base, NULL); 4831887081fSmrg FcStrFree (base); 4841887081fSmrg } 4852c393a42Smrg if (FcConfigAcceptFilename (config, dir)) 4862c393a42Smrg FcStrSetAddFilename (dirSet, dir); 4871887081fSmrg if (s) 4881887081fSmrg FcStrFree (s); 4892c393a42Smrg } 4902c393a42Smrg } 4912c393a42Smrg return FcTrue; 4922c393a42Smrg} 4932c393a42Smrg 4942c393a42Smrgstatic FcBool 4952c393a42SmrgFcConfigAddDirList (FcConfig *config, FcSetName set, FcStrSet *dirSet) 4962c393a42Smrg{ 4972c393a42Smrg FcStrList *dirlist; 4982c393a42Smrg FcChar8 *dir; 4992c393a42Smrg FcCache *cache; 500ca08ab68Smrg 5012c393a42Smrg dirlist = FcStrListCreate (dirSet); 5022c393a42Smrg if (!dirlist) 5032c393a42Smrg return FcFalse; 50446bb3e47Smrg 5052c393a42Smrg while ((dir = FcStrListNext (dirlist))) 5062c393a42Smrg { 5072c393a42Smrg if (FcDebug () & FC_DBG_FONTSET) 50818bd4a06Smrg printf ("adding fonts from %s\n", dir); 5092c393a42Smrg cache = FcDirCacheRead (dir, FcFalse, config); 5102c393a42Smrg if (!cache) 5112c393a42Smrg continue; 5121887081fSmrg FcConfigAddCache (config, cache, set, dirSet, dir); 5132c393a42Smrg FcDirCacheUnload (cache); 5142c393a42Smrg } 5152c393a42Smrg FcStrListDone (dirlist); 5162c393a42Smrg return FcTrue; 5172c393a42Smrg} 5182c393a42Smrg 5192c393a42Smrg/* 5202c393a42Smrg * Scan the current list of directories in the configuration 5212c393a42Smrg * and build the set of available fonts. 5222c393a42Smrg */ 5232c393a42Smrg 5242c393a42SmrgFcBool 5252c393a42SmrgFcConfigBuildFonts (FcConfig *config) 5262c393a42Smrg{ 5272c393a42Smrg FcFontSet *fonts; 5287872e0a1Smrg FcBool ret = FcTrue; 5292c393a42Smrg 5307872e0a1Smrg config = FcConfigReference (config); 5312c393a42Smrg if (!config) 5327872e0a1Smrg return FcFalse; 53346bb3e47Smrg 5342c393a42Smrg fonts = FcFontSetCreate (); 5352c393a42Smrg if (!fonts) 5367872e0a1Smrg { 5377872e0a1Smrg ret = FcFalse; 5387872e0a1Smrg goto bail; 5397872e0a1Smrg } 540ca08ab68Smrg 5412c393a42Smrg FcConfigSetFonts (config, fonts, FcSetSystem); 542ca08ab68Smrg 5432c393a42Smrg if (!FcConfigAddDirList (config, FcSetSystem, config->fontDirs)) 5447872e0a1Smrg { 5457872e0a1Smrg ret = FcFalse; 5467872e0a1Smrg goto bail; 5477872e0a1Smrg } 5482c393a42Smrg if (FcDebug () & FC_DBG_FONTSET) 5492c393a42Smrg FcFontSetPrint (fonts); 5507872e0a1Smrgbail: 5517872e0a1Smrg FcConfigDestroy (config); 5527872e0a1Smrg 5537872e0a1Smrg return ret; 5542c393a42Smrg} 5552c393a42Smrg 5562c393a42SmrgFcBool 5572c393a42SmrgFcConfigSetCurrent (FcConfig *config) 5582c393a42Smrg{ 559c9710b42Smrg FcConfig *cfg; 560c9710b42Smrg 5617872e0a1Smrg if (config) 5627872e0a1Smrg { 5637872e0a1Smrg if (!config->fonts[FcSetSystem]) 5647872e0a1Smrg if (!FcConfigBuildFonts (config)) 5657872e0a1Smrg return FcFalse; 5667872e0a1Smrg FcRefInc (&config->ref); 5677872e0a1Smrg } 5687872e0a1Smrg 5697872e0a1Smrg lock_config (); 570c9710b42Smrgretry: 571c9710b42Smrg cfg = fc_atomic_ptr_get (&_fcConfig); 572c9710b42Smrg 573c9710b42Smrg if (config == cfg) 5747872e0a1Smrg { 5757872e0a1Smrg unlock_config (); 5767872e0a1Smrg if (config) 5777872e0a1Smrg FcConfigDestroy (config); 5782c393a42Smrg return FcTrue; 5797872e0a1Smrg } 5802c393a42Smrg 581c9710b42Smrg if (!fc_atomic_ptr_cmpexch (&_fcConfig, cfg, config)) 582c9710b42Smrg goto retry; 5837872e0a1Smrg unlock_config (); 584c9710b42Smrg if (cfg) 585c9710b42Smrg FcConfigDestroy (cfg); 586c9710b42Smrg 5872c393a42Smrg return FcTrue; 5882c393a42Smrg} 5892c393a42Smrg 5902c393a42SmrgFcConfig * 5912c393a42SmrgFcConfigGetCurrent (void) 5922c393a42Smrg{ 593c9710b42Smrg return FcConfigEnsure (); 5942c393a42Smrg} 5952c393a42Smrg 5962c393a42SmrgFcBool 5972c393a42SmrgFcConfigAddConfigDir (FcConfig *config, 5982c393a42Smrg const FcChar8 *d) 5992c393a42Smrg{ 6002c393a42Smrg return FcStrSetAddFilename (config->configDirs, d); 6012c393a42Smrg} 6022c393a42Smrg 6032c393a42SmrgFcStrList * 6042c393a42SmrgFcConfigGetConfigDirs (FcConfig *config) 6052c393a42Smrg{ 6067872e0a1Smrg FcStrList *ret; 6077872e0a1Smrg 6087872e0a1Smrg config = FcConfigReference (config); 6092c393a42Smrg if (!config) 6107872e0a1Smrg return NULL; 6117872e0a1Smrg ret = FcStrListCreate (config->configDirs); 6127872e0a1Smrg FcConfigDestroy (config); 6137872e0a1Smrg 6147872e0a1Smrg return ret; 6157872e0a1Smrg} 6167872e0a1Smrg 6177872e0a1SmrgFcBool 6187872e0a1SmrgFcConfigAddFontDir (FcConfig *config, 6197872e0a1Smrg const FcChar8 *d, 6207872e0a1Smrg const FcChar8 *m, 6217872e0a1Smrg const FcChar8 *salt) 6227872e0a1Smrg{ 6237872e0a1Smrg if (FcDebug() & FC_DBG_CACHE) 6242c393a42Smrg { 6257872e0a1Smrg if (m) 6267872e0a1Smrg { 6277872e0a1Smrg printf ("%s -> %s%s%s%s\n", d, m, salt ? " (salt: " : "", salt ? (const char *)salt : "", salt ? ")" : ""); 6287872e0a1Smrg } 6297872e0a1Smrg else if (salt) 6307872e0a1Smrg { 6317872e0a1Smrg printf ("%s%s%s%s\n", d, salt ? " (salt: " : "", salt ? (const char *)salt : "", salt ? ")" : ""); 6327872e0a1Smrg } 6332c393a42Smrg } 6347872e0a1Smrg return FcStrSetAddFilenamePairWithSalt (config->fontDirs, d, m, salt); 6352c393a42Smrg} 6362c393a42Smrg 6372c393a42SmrgFcBool 6387872e0a1SmrgFcConfigResetFontDirs (FcConfig *config) 6392c393a42Smrg{ 6407872e0a1Smrg if (FcDebug() & FC_DBG_CACHE) 6417872e0a1Smrg { 6427872e0a1Smrg printf ("Reset font directories!\n"); 6437872e0a1Smrg } 6447872e0a1Smrg return FcStrSetDeleteAll (config->fontDirs); 6452c393a42Smrg} 6462c393a42Smrg 6472c393a42SmrgFcStrList * 6482c393a42SmrgFcConfigGetFontDirs (FcConfig *config) 6492c393a42Smrg{ 6507872e0a1Smrg FcStrList *ret; 6517872e0a1Smrg 6527872e0a1Smrg config = FcConfigReference (config); 6532c393a42Smrg if (!config) 6547872e0a1Smrg return NULL; 6557872e0a1Smrg ret = FcStrListCreate (config->fontDirs); 6567872e0a1Smrg FcConfigDestroy (config); 6577872e0a1Smrg 6587872e0a1Smrg return ret; 6597872e0a1Smrg} 6607872e0a1Smrg 6617872e0a1Smrgstatic FcBool 6627872e0a1SmrgFcConfigPathStartsWith(const FcChar8 *path, 6637872e0a1Smrg const FcChar8 *start) 6647872e0a1Smrg{ 6657872e0a1Smrg int len = strlen((char *) start); 6667872e0a1Smrg 6677872e0a1Smrg if (strncmp((char *) path, (char *) start, len) != 0) 6687872e0a1Smrg return FcFalse; 6697872e0a1Smrg 6707872e0a1Smrg switch (path[len]) { 6717872e0a1Smrg case '\0': 6727872e0a1Smrg case FC_DIR_SEPARATOR: 6737872e0a1Smrg return FcTrue; 6747872e0a1Smrg default: 6757872e0a1Smrg return FcFalse; 6762c393a42Smrg } 6777872e0a1Smrg} 6787872e0a1Smrg 6797872e0a1SmrgFcChar8 * 6807872e0a1SmrgFcConfigMapFontPath(FcConfig *config, 6817872e0a1Smrg const FcChar8 *path) 6827872e0a1Smrg{ 6837872e0a1Smrg FcStrList *list; 6847872e0a1Smrg FcChar8 *dir; 6857872e0a1Smrg const FcChar8 *map, *rpath; 6867872e0a1Smrg FcChar8 *retval; 6877872e0a1Smrg 6887872e0a1Smrg list = FcConfigGetFontDirs(config); 6897872e0a1Smrg if (!list) 6907872e0a1Smrg return 0; 6917872e0a1Smrg while ((dir = FcStrListNext(list))) 6927872e0a1Smrg if (FcConfigPathStartsWith(path, dir)) 6937872e0a1Smrg break; 6947872e0a1Smrg FcStrListDone(list); 6957872e0a1Smrg if (!dir) 6967872e0a1Smrg return 0; 6977872e0a1Smrg map = FcStrTripleSecond(dir); 6987872e0a1Smrg if (!map) 6997872e0a1Smrg return 0; 7007872e0a1Smrg rpath = path + strlen ((char *) dir); 7017872e0a1Smrg while (*rpath == '/') 7027872e0a1Smrg rpath++; 7037872e0a1Smrg retval = FcStrBuildFilename(map, rpath, NULL); 7047872e0a1Smrg if (retval) 7057872e0a1Smrg { 7067872e0a1Smrg size_t len = strlen ((const char *) retval); 7077872e0a1Smrg while (len > 0 && retval[len-1] == '/') 7087872e0a1Smrg len--; 7097872e0a1Smrg /* trim the last slash */ 7107872e0a1Smrg retval[len] = 0; 7117872e0a1Smrg } 7127872e0a1Smrg return retval; 7137872e0a1Smrg} 7147872e0a1Smrg 7157872e0a1Smrgconst FcChar8 * 7167872e0a1SmrgFcConfigMapSalt (FcConfig *config, 7177872e0a1Smrg const FcChar8 *path) 7187872e0a1Smrg{ 7197872e0a1Smrg FcStrList *list; 7207872e0a1Smrg FcChar8 *dir; 7217872e0a1Smrg 7227872e0a1Smrg list = FcConfigGetFontDirs (config); 7237872e0a1Smrg if (!list) 7247872e0a1Smrg return NULL; 7257872e0a1Smrg while ((dir = FcStrListNext (list))) 7267872e0a1Smrg if (FcConfigPathStartsWith (path, dir)) 7277872e0a1Smrg break; 7287872e0a1Smrg FcStrListDone (list); 7297872e0a1Smrg if (!dir) 7307872e0a1Smrg return NULL; 7317872e0a1Smrg 7327872e0a1Smrg return FcStrTripleThird (dir); 7332c393a42Smrg} 7342c393a42Smrg 7352c393a42SmrgFcBool 7362c393a42SmrgFcConfigAddCacheDir (FcConfig *config, 7372c393a42Smrg const FcChar8 *d) 7382c393a42Smrg{ 7392c393a42Smrg return FcStrSetAddFilename (config->cacheDirs, d); 7402c393a42Smrg} 7412c393a42Smrg 7422c393a42SmrgFcStrList * 7437872e0a1SmrgFcConfigGetCacheDirs (FcConfig *config) 7442c393a42Smrg{ 7457872e0a1Smrg FcStrList *ret; 7467872e0a1Smrg 7477872e0a1Smrg config = FcConfigReference (config); 7482c393a42Smrg if (!config) 7497872e0a1Smrg return NULL; 7507872e0a1Smrg ret = FcStrListCreate (config->cacheDirs); 7517872e0a1Smrg FcConfigDestroy (config); 7527872e0a1Smrg 7537872e0a1Smrg return ret; 7542c393a42Smrg} 755ca08ab68Smrg 7562c393a42SmrgFcBool 7572c393a42SmrgFcConfigAddConfigFile (FcConfig *config, 7582c393a42Smrg const FcChar8 *f) 7592c393a42Smrg{ 7602c393a42Smrg FcBool ret; 7617872e0a1Smrg FcChar8 *file = FcConfigGetFilename (config, f); 762ca08ab68Smrg 7632c393a42Smrg if (!file) 7642c393a42Smrg return FcFalse; 765ca08ab68Smrg 7662c393a42Smrg ret = FcStrSetAdd (config->configFiles, file); 7672c393a42Smrg FcStrFree (file); 7682c393a42Smrg return ret; 7692c393a42Smrg} 7702c393a42Smrg 7712c393a42SmrgFcStrList * 7722c393a42SmrgFcConfigGetConfigFiles (FcConfig *config) 7732c393a42Smrg{ 7747872e0a1Smrg FcStrList *ret; 7757872e0a1Smrg 7767872e0a1Smrg config = FcConfigReference (config); 7772c393a42Smrg if (!config) 7787872e0a1Smrg return NULL; 7797872e0a1Smrg ret = FcStrListCreate (config->configFiles); 7807872e0a1Smrg FcConfigDestroy (config); 7817872e0a1Smrg 7827872e0a1Smrg return ret; 7832c393a42Smrg} 7842c393a42Smrg 7852c393a42SmrgFcChar8 * 786c9710b42SmrgFcConfigGetCache (FcConfig *config FC_UNUSED) 7872c393a42Smrg{ 7882c393a42Smrg return NULL; 7892c393a42Smrg} 7902c393a42Smrg 7912c393a42SmrgFcFontSet * 7922c393a42SmrgFcConfigGetFonts (FcConfig *config, 7932c393a42Smrg FcSetName set) 7942c393a42Smrg{ 7952c393a42Smrg if (!config) 7962c393a42Smrg { 7972c393a42Smrg config = FcConfigGetCurrent (); 7982c393a42Smrg if (!config) 7992c393a42Smrg return 0; 8002c393a42Smrg } 8012c393a42Smrg return config->fonts[set]; 8022c393a42Smrg} 8032c393a42Smrg 8042c393a42Smrgvoid 8052c393a42SmrgFcConfigSetFonts (FcConfig *config, 8062c393a42Smrg FcFontSet *fonts, 8072c393a42Smrg FcSetName set) 8082c393a42Smrg{ 8092c393a42Smrg if (config->fonts[set]) 8102c393a42Smrg FcFontSetDestroy (config->fonts[set]); 8112c393a42Smrg config->fonts[set] = fonts; 8122c393a42Smrg} 8132c393a42Smrg 8141887081fSmrg 8152c393a42SmrgFcBlanks * 8161887081fSmrgFcBlanksCreate (void) 8172c393a42Smrg{ 8181887081fSmrg /* Deprecated. */ 8191887081fSmrg return NULL; 8201887081fSmrg} 8211887081fSmrg 8221887081fSmrgvoid 8231887081fSmrgFcBlanksDestroy (FcBlanks *b FC_UNUSED) 8241887081fSmrg{ 8251887081fSmrg /* Deprecated. */ 8262c393a42Smrg} 8272c393a42Smrg 8282c393a42SmrgFcBool 8291887081fSmrgFcBlanksAdd (FcBlanks *b FC_UNUSED, FcChar32 ucs4 FC_UNUSED) 8302c393a42Smrg{ 8311887081fSmrg /* Deprecated. */ 8321887081fSmrg return FcFalse; 8331887081fSmrg} 834ca08ab68Smrg 8351887081fSmrgFcBool 8361887081fSmrgFcBlanksIsMember (FcBlanks *b FC_UNUSED, FcChar32 ucs4 FC_UNUSED) 8371887081fSmrg{ 8381887081fSmrg /* Deprecated. */ 8391887081fSmrg return FcFalse; 8401887081fSmrg} 8411887081fSmrg 8421887081fSmrgFcBlanks * 8431887081fSmrgFcConfigGetBlanks (FcConfig *config FC_UNUSED) 8441887081fSmrg{ 8451887081fSmrg /* Deprecated. */ 8461887081fSmrg return NULL; 8471887081fSmrg} 8481887081fSmrg 8491887081fSmrgFcBool 8501887081fSmrgFcConfigAddBlank (FcConfig *config FC_UNUSED, 8511887081fSmrg FcChar32 blank FC_UNUSED) 8521887081fSmrg{ 8531887081fSmrg /* Deprecated. */ 8541887081fSmrg return FcFalse; 8552c393a42Smrg} 8562c393a42Smrg 8571887081fSmrg 8582c393a42Smrgint 8592c393a42SmrgFcConfigGetRescanInterval (FcConfig *config) 8602c393a42Smrg{ 8617872e0a1Smrg int ret; 8627872e0a1Smrg 8637872e0a1Smrg config = FcConfigReference (config); 8642c393a42Smrg if (!config) 8657872e0a1Smrg return 0; 8667872e0a1Smrg ret = config->rescanInterval; 8677872e0a1Smrg FcConfigDestroy (config); 8687872e0a1Smrg 8697872e0a1Smrg return ret; 8702c393a42Smrg} 8712c393a42Smrg 8722c393a42SmrgFcBool 8732c393a42SmrgFcConfigSetRescanInterval (FcConfig *config, int rescanInterval) 8742c393a42Smrg{ 8757872e0a1Smrg config = FcConfigReference (config); 8762c393a42Smrg if (!config) 8777872e0a1Smrg return FcFalse; 8782c393a42Smrg config->rescanInterval = rescanInterval; 8797872e0a1Smrg FcConfigDestroy (config); 8807872e0a1Smrg 8812c393a42Smrg return FcTrue; 8822c393a42Smrg} 8832c393a42Smrg 8842c393a42Smrg/* 8852c393a42Smrg * A couple of typos escaped into the library 8862c393a42Smrg */ 8872c393a42Smrgint 8882c393a42SmrgFcConfigGetRescanInverval (FcConfig *config) 8892c393a42Smrg{ 8902c393a42Smrg return FcConfigGetRescanInterval (config); 8912c393a42Smrg} 8922c393a42Smrg 8932c393a42SmrgFcBool 8942c393a42SmrgFcConfigSetRescanInverval (FcConfig *config, int rescanInterval) 8952c393a42Smrg{ 8962c393a42Smrg return FcConfigSetRescanInterval (config, rescanInterval); 8972c393a42Smrg} 8982c393a42Smrg 8992c393a42SmrgFcBool 9006fc018e4SmrgFcConfigAddRule (FcConfig *config, 9016fc018e4Smrg FcRule *rule, 9022c393a42Smrg FcMatchKind kind) 9032c393a42Smrg{ 9041887081fSmrg /* deprecated */ 9051887081fSmrg return FcFalse; 9062c393a42Smrg} 9072c393a42Smrg 9082c393a42Smrgstatic FcValue 909c9710b42SmrgFcConfigPromote (FcValue v, FcValue u, FcValuePromotionBuffer *buf) 9102c393a42Smrg{ 9117872e0a1Smrg switch (v.type) 9127872e0a1Smrg { 9137872e0a1Smrg case FcTypeInteger: 9147872e0a1Smrg v.type = FcTypeDouble; 9157872e0a1Smrg v.u.d = (double) v.u.i; 9167872e0a1Smrg /* Fallthrough */ 9177872e0a1Smrg case FcTypeDouble: 9187872e0a1Smrg if (u.type == FcTypeRange && buf) 9197872e0a1Smrg { 9207872e0a1Smrg v.u.r = FcRangePromote (v.u.d, buf); 9217872e0a1Smrg v.type = FcTypeRange; 9227872e0a1Smrg } 9237872e0a1Smrg break; 9247872e0a1Smrg case FcTypeVoid: 9257872e0a1Smrg if (u.type == FcTypeMatrix) 9267872e0a1Smrg { 9277872e0a1Smrg v.u.m = &FcIdentityMatrix; 9287872e0a1Smrg v.type = FcTypeMatrix; 9297872e0a1Smrg } 9307872e0a1Smrg else if (u.type == FcTypeLangSet && buf) 9317872e0a1Smrg { 9327872e0a1Smrg v.u.l = FcLangSetPromote (NULL, buf); 9337872e0a1Smrg v.type = FcTypeLangSet; 9347872e0a1Smrg } 9357872e0a1Smrg else if (u.type == FcTypeCharSet && buf) 9367872e0a1Smrg { 9377872e0a1Smrg v.u.c = FcCharSetPromote (buf); 9387872e0a1Smrg v.type = FcTypeCharSet; 9397872e0a1Smrg } 9407872e0a1Smrg break; 9417872e0a1Smrg case FcTypeString: 9427872e0a1Smrg if (u.type == FcTypeLangSet && buf) 9437872e0a1Smrg { 9447872e0a1Smrg v.u.l = FcLangSetPromote (v.u.s, buf); 9457872e0a1Smrg v.type = FcTypeLangSet; 9467872e0a1Smrg } 9477872e0a1Smrg break; 9487872e0a1Smrg default: 9497872e0a1Smrg break; 95018bd4a06Smrg } 9512c393a42Smrg return v; 9522c393a42Smrg} 9532c393a42Smrg 9542c393a42SmrgFcBool 9552c393a42SmrgFcConfigCompareValue (const FcValue *left_o, 9566fc018e4Smrg unsigned int op_, 9572c393a42Smrg const FcValue *right_o) 9582c393a42Smrg{ 9597872e0a1Smrg FcValue left; 9607872e0a1Smrg FcValue right; 9612c393a42Smrg FcBool ret = FcFalse; 962ca08ab68Smrg FcOp op = FC_OP_GET_OP (op_); 963ca08ab68Smrg int flags = FC_OP_GET_FLAGS (op_); 964c9710b42Smrg FcValuePromotionBuffer buf1, buf2; 965ca08ab68Smrg 9667872e0a1Smrg if (left_o->type != right_o->type) 9677872e0a1Smrg { 9687872e0a1Smrg left = FcValueCanonicalize(left_o); 9697872e0a1Smrg right = FcValueCanonicalize(right_o); 9707872e0a1Smrg left = FcConfigPromote (left, right, &buf1); 9717872e0a1Smrg right = FcConfigPromote (right, left, &buf2); 9727872e0a1Smrg left_o = &left; 9737872e0a1Smrg right_o = &right; 9747872e0a1Smrg if (left_o->type != right_o->type) 9757872e0a1Smrg { 9767872e0a1Smrg if (op == FcOpNotEqual || op == FcOpNotContains) 9777872e0a1Smrg ret = FcTrue; 9787872e0a1Smrg return ret; 9797872e0a1Smrg } 9807872e0a1Smrg } 9817872e0a1Smrg switch (left_o->type) { 9827872e0a1Smrg case FcTypeUnknown: 9837872e0a1Smrg break; /* No way to guess how to compare for this object */ 9847872e0a1Smrg case FcTypeInteger: { 9857872e0a1Smrg int l = left_o->u.i; 9867872e0a1Smrg int r = right_o->u.i; 9877872e0a1Smrg switch ((int) op) { 9887872e0a1Smrg case FcOpEqual: 9897872e0a1Smrg case FcOpContains: 9907872e0a1Smrg case FcOpListing: 9917872e0a1Smrg ret = l == r; 9927872e0a1Smrg break; 9937872e0a1Smrg case FcOpNotEqual: 9947872e0a1Smrg case FcOpNotContains: 9957872e0a1Smrg ret = l != r; 9967872e0a1Smrg break; 9977872e0a1Smrg case FcOpLess: 9987872e0a1Smrg ret = l < r; 9997872e0a1Smrg break; 10007872e0a1Smrg case FcOpLessEqual: 10017872e0a1Smrg ret = l <= r; 10027872e0a1Smrg break; 10037872e0a1Smrg case FcOpMore: 10047872e0a1Smrg ret = l > r; 10057872e0a1Smrg break; 10067872e0a1Smrg case FcOpMoreEqual: 10077872e0a1Smrg ret = l >= r; 10087872e0a1Smrg break; 10097872e0a1Smrg default: 10107872e0a1Smrg break; 10117872e0a1Smrg } 10127872e0a1Smrg break; 10137872e0a1Smrg } 10147872e0a1Smrg case FcTypeDouble: { 10157872e0a1Smrg double l = left_o->u.d; 10167872e0a1Smrg double r = right_o->u.d; 10177872e0a1Smrg switch ((int) op) { 10187872e0a1Smrg case FcOpEqual: 10197872e0a1Smrg case FcOpContains: 10207872e0a1Smrg case FcOpListing: 10217872e0a1Smrg ret = l == r; 10227872e0a1Smrg break; 10237872e0a1Smrg case FcOpNotEqual: 10247872e0a1Smrg case FcOpNotContains: 10257872e0a1Smrg ret = l != r; 10267872e0a1Smrg break; 10277872e0a1Smrg case FcOpLess: 10287872e0a1Smrg ret = l < r; 10297872e0a1Smrg break; 10307872e0a1Smrg case FcOpLessEqual: 10317872e0a1Smrg ret = l <= r; 10327872e0a1Smrg break; 10337872e0a1Smrg case FcOpMore: 10347872e0a1Smrg ret = l > r; 10357872e0a1Smrg break; 10367872e0a1Smrg case FcOpMoreEqual: 10377872e0a1Smrg ret = l >= r; 10387872e0a1Smrg break; 10397872e0a1Smrg default: 10407872e0a1Smrg break; 10417872e0a1Smrg } 10427872e0a1Smrg break; 10437872e0a1Smrg } 10447872e0a1Smrg case FcTypeBool: { 10457872e0a1Smrg FcBool l = left_o->u.b; 10467872e0a1Smrg FcBool r = right_o->u.b; 10477872e0a1Smrg switch ((int) op) { 10487872e0a1Smrg case FcOpEqual: 10497872e0a1Smrg ret = l == r; 10507872e0a1Smrg break; 10517872e0a1Smrg case FcOpContains: 10527872e0a1Smrg case FcOpListing: 10537872e0a1Smrg ret = l == r || l >= FcDontCare; 10547872e0a1Smrg break; 10557872e0a1Smrg case FcOpNotEqual: 10567872e0a1Smrg ret = l != r; 10577872e0a1Smrg break; 10587872e0a1Smrg case FcOpNotContains: 10597872e0a1Smrg ret = !(l == r || l >= FcDontCare); 10607872e0a1Smrg break; 10617872e0a1Smrg case FcOpLess: 10627872e0a1Smrg ret = l != r && r >= FcDontCare; 10637872e0a1Smrg break; 10647872e0a1Smrg case FcOpLessEqual: 10657872e0a1Smrg ret = l == r || r >= FcDontCare; 10667872e0a1Smrg break; 10677872e0a1Smrg case FcOpMore: 10687872e0a1Smrg ret = l != r && l >= FcDontCare; 10697872e0a1Smrg break; 10707872e0a1Smrg case FcOpMoreEqual: 10717872e0a1Smrg ret = l == r || l >= FcDontCare; 10727872e0a1Smrg break; 10737872e0a1Smrg default: 10747872e0a1Smrg break; 10757872e0a1Smrg } 10767872e0a1Smrg break; 10777872e0a1Smrg } 10787872e0a1Smrg case FcTypeString: { 10797872e0a1Smrg const FcChar8 *l = FcValueString (left_o); 10807872e0a1Smrg const FcChar8 *r = FcValueString (right_o); 10817872e0a1Smrg switch ((int) op) { 10827872e0a1Smrg case FcOpEqual: 10837872e0a1Smrg case FcOpListing: 10847872e0a1Smrg if (flags & FcOpFlagIgnoreBlanks) 10857872e0a1Smrg ret = FcStrCmpIgnoreBlanksAndCase (l, r) == 0; 10867872e0a1Smrg else 10877872e0a1Smrg ret = FcStrCmpIgnoreCase (l, r) == 0; 10887872e0a1Smrg break; 10897872e0a1Smrg case FcOpContains: 10907872e0a1Smrg ret = FcStrStrIgnoreCase (l, r) != 0; 10917872e0a1Smrg break; 10927872e0a1Smrg case FcOpNotEqual: 10937872e0a1Smrg if (flags & FcOpFlagIgnoreBlanks) 10947872e0a1Smrg ret = FcStrCmpIgnoreBlanksAndCase (l, r) != 0; 10957872e0a1Smrg else 10967872e0a1Smrg ret = FcStrCmpIgnoreCase (l, r) != 0; 10977872e0a1Smrg break; 10987872e0a1Smrg case FcOpNotContains: 10997872e0a1Smrg ret = FcStrStrIgnoreCase (l, r) == 0; 11007872e0a1Smrg break; 11017872e0a1Smrg default: 11027872e0a1Smrg break; 11037872e0a1Smrg } 11047872e0a1Smrg break; 11057872e0a1Smrg } 11067872e0a1Smrg case FcTypeMatrix: { 11077872e0a1Smrg switch ((int) op) { 11087872e0a1Smrg case FcOpEqual: 11097872e0a1Smrg case FcOpContains: 11107872e0a1Smrg case FcOpListing: 11117872e0a1Smrg ret = FcMatrixEqual (left_o->u.m, right_o->u.m); 11127872e0a1Smrg break; 11137872e0a1Smrg case FcOpNotEqual: 11147872e0a1Smrg case FcOpNotContains: 11157872e0a1Smrg ret = !FcMatrixEqual (left_o->u.m, right_o->u.m); 11167872e0a1Smrg break; 11177872e0a1Smrg default: 11187872e0a1Smrg break; 11197872e0a1Smrg } 11207872e0a1Smrg break; 11217872e0a1Smrg } 11227872e0a1Smrg case FcTypeCharSet: { 11237872e0a1Smrg const FcCharSet *l = FcValueCharSet (left_o); 11247872e0a1Smrg const FcCharSet *r = FcValueCharSet (right_o); 11257872e0a1Smrg switch ((int) op) { 11267872e0a1Smrg case FcOpContains: 11277872e0a1Smrg case FcOpListing: 11287872e0a1Smrg /* left contains right if right is a subset of left */ 11297872e0a1Smrg ret = FcCharSetIsSubset (r, l); 11307872e0a1Smrg break; 11317872e0a1Smrg case FcOpNotContains: 11327872e0a1Smrg /* left contains right if right is a subset of left */ 11337872e0a1Smrg ret = !FcCharSetIsSubset (r, l); 11347872e0a1Smrg break; 11357872e0a1Smrg case FcOpEqual: 11367872e0a1Smrg ret = FcCharSetEqual (l, r); 11377872e0a1Smrg break; 11387872e0a1Smrg case FcOpNotEqual: 11397872e0a1Smrg ret = !FcCharSetEqual (l, r); 11407872e0a1Smrg break; 11417872e0a1Smrg default: 11427872e0a1Smrg break; 11437872e0a1Smrg } 11447872e0a1Smrg break; 11457872e0a1Smrg } 11467872e0a1Smrg case FcTypeLangSet: { 11477872e0a1Smrg const FcLangSet *l = FcValueLangSet (left_o); 11487872e0a1Smrg const FcLangSet *r = FcValueLangSet (right_o); 11497872e0a1Smrg switch ((int) op) { 11507872e0a1Smrg case FcOpContains: 11517872e0a1Smrg case FcOpListing: 11527872e0a1Smrg ret = FcLangSetContains (l, r); 11537872e0a1Smrg break; 11547872e0a1Smrg case FcOpNotContains: 11557872e0a1Smrg ret = !FcLangSetContains (l, r); 11567872e0a1Smrg break; 11577872e0a1Smrg case FcOpEqual: 11587872e0a1Smrg ret = FcLangSetEqual (l, r); 11597872e0a1Smrg break; 11607872e0a1Smrg case FcOpNotEqual: 11617872e0a1Smrg ret = !FcLangSetEqual (l, r); 11627872e0a1Smrg break; 11637872e0a1Smrg default: 11647872e0a1Smrg break; 11657872e0a1Smrg } 11667872e0a1Smrg break; 11677872e0a1Smrg } 11687872e0a1Smrg case FcTypeVoid: 11697872e0a1Smrg switch ((int) op) { 11707872e0a1Smrg case FcOpEqual: 11717872e0a1Smrg case FcOpContains: 11727872e0a1Smrg case FcOpListing: 11737872e0a1Smrg ret = FcTrue; 11747872e0a1Smrg break; 11757872e0a1Smrg default: 11767872e0a1Smrg break; 11777872e0a1Smrg } 11787872e0a1Smrg break; 11797872e0a1Smrg case FcTypeFTFace: 11807872e0a1Smrg switch ((int) op) { 11817872e0a1Smrg case FcOpEqual: 11827872e0a1Smrg case FcOpContains: 11837872e0a1Smrg case FcOpListing: 11847872e0a1Smrg ret = left_o->u.f == right_o->u.f; 11857872e0a1Smrg break; 11867872e0a1Smrg case FcOpNotEqual: 11877872e0a1Smrg case FcOpNotContains: 11887872e0a1Smrg ret = left_o->u.f != right_o->u.f; 11897872e0a1Smrg break; 11907872e0a1Smrg default: 11917872e0a1Smrg break; 11927872e0a1Smrg } 11937872e0a1Smrg break; 11947872e0a1Smrg case FcTypeRange: { 11957872e0a1Smrg const FcRange *l = FcValueRange (left_o); 11967872e0a1Smrg const FcRange *r = FcValueRange (right_o); 11977872e0a1Smrg ret = FcRangeCompare (op, l, r); 11987872e0a1Smrg break; 11992c393a42Smrg } 12002c393a42Smrg } 12012c393a42Smrg return ret; 12022c393a42Smrg} 12032c393a42Smrg 12042c393a42Smrg 12052c393a42Smrg#define _FcDoubleFloor(d) ((int) (d)) 12062c393a42Smrg#define _FcDoubleCeil(d) ((double) (int) (d) == (d) ? (int) (d) : (int) ((d) + 1)) 12072c393a42Smrg#define FcDoubleFloor(d) ((d) >= 0 ? _FcDoubleFloor(d) : -_FcDoubleCeil(-(d))) 12082c393a42Smrg#define FcDoubleCeil(d) ((d) >= 0 ? _FcDoubleCeil(d) : -_FcDoubleFloor(-(d))) 12092c393a42Smrg#define FcDoubleRound(d) FcDoubleFloor ((d) + 0.5) 12102c393a42Smrg#define FcDoubleTrunc(d) ((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d))) 12112c393a42Smrg 12122c393a42Smrgstatic FcValue 1213c9710b42SmrgFcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e) 12142c393a42Smrg{ 121518bd4a06Smrg FcValue v, vl, vr, vle, vre; 12162c393a42Smrg FcMatrix *m; 12172c393a42Smrg FcChar8 *str; 1218ca08ab68Smrg FcOp op = FC_OP_GET_OP (e->op); 121918bd4a06Smrg FcValuePromotionBuffer buf1, buf2; 1220ca08ab68Smrg 1221c9710b42Smrg switch ((int) op) { 12222c393a42Smrg case FcOpInteger: 12232c393a42Smrg v.type = FcTypeInteger; 12242c393a42Smrg v.u.i = e->u.ival; 12252c393a42Smrg break; 12262c393a42Smrg case FcOpDouble: 12272c393a42Smrg v.type = FcTypeDouble; 12282c393a42Smrg v.u.d = e->u.dval; 12292c393a42Smrg break; 12302c393a42Smrg case FcOpString: 12312c393a42Smrg v.type = FcTypeString; 1232a6844aabSmrg v.u.s = e->u.sval; 1233a6844aabSmrg v = FcValueSave (v); 12342c393a42Smrg break; 12352c393a42Smrg case FcOpMatrix: 1236c9710b42Smrg { 1237c9710b42Smrg FcMatrix m; 1238c9710b42Smrg FcValue xx, xy, yx, yy; 1239c9710b42Smrg v.type = FcTypeMatrix; 1240c9710b42Smrg xx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xx), v, NULL); 1241c9710b42Smrg xy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xy), v, NULL); 1242c9710b42Smrg yx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yx), v, NULL); 1243c9710b42Smrg yy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yy), v, NULL); 1244c9710b42Smrg if (xx.type == FcTypeDouble && xy.type == FcTypeDouble && 1245c9710b42Smrg yx.type == FcTypeDouble && yy.type == FcTypeDouble) 1246c9710b42Smrg { 1247c9710b42Smrg m.xx = xx.u.d; 1248c9710b42Smrg m.xy = xy.u.d; 1249c9710b42Smrg m.yx = yx.u.d; 1250c9710b42Smrg m.yy = yy.u.d; 1251c9710b42Smrg v.u.m = &m; 1252c9710b42Smrg } 1253c9710b42Smrg else 1254c9710b42Smrg v.type = FcTypeVoid; 1255c9710b42Smrg v = FcValueSave (v); 1256c9710b42Smrg } 12572c393a42Smrg break; 12582c393a42Smrg case FcOpCharSet: 12592c393a42Smrg v.type = FcTypeCharSet; 12602c393a42Smrg v.u.c = e->u.cval; 12612c393a42Smrg v = FcValueSave (v); 12622c393a42Smrg break; 1263ca08ab68Smrg case FcOpLangSet: 1264ca08ab68Smrg v.type = FcTypeLangSet; 1265ca08ab68Smrg v.u.l = e->u.lval; 1266ca08ab68Smrg v = FcValueSave (v); 1267ca08ab68Smrg break; 126818bd4a06Smrg case FcOpRange: 126918bd4a06Smrg v.type = FcTypeRange; 127018bd4a06Smrg v.u.r = e->u.rval; 127118bd4a06Smrg v = FcValueSave (v); 127218bd4a06Smrg break; 12732c393a42Smrg case FcOpBool: 12742c393a42Smrg v.type = FcTypeBool; 12752c393a42Smrg v.u.b = e->u.bval; 12762c393a42Smrg break; 12772c393a42Smrg case FcOpField: 1278c9710b42Smrg if (kind == FcMatchFont && e->u.name.kind == FcMatchPattern) 1279c9710b42Smrg { 1280c9710b42Smrg if (FcResultMatch != FcPatternObjectGet (p_pat, e->u.name.object, 0, &v)) 1281c9710b42Smrg v.type = FcTypeVoid; 1282c9710b42Smrg } 1283c9710b42Smrg else if (kind == FcMatchPattern && e->u.name.kind == FcMatchFont) 1284c9710b42Smrg { 1285c9710b42Smrg fprintf (stderr, 1286c9710b42Smrg "Fontconfig warning: <name> tag has target=\"font\" in a <match target=\"pattern\">.\n"); 12872c393a42Smrg v.type = FcTypeVoid; 1288c9710b42Smrg } 1289c9710b42Smrg else 1290c9710b42Smrg { 1291c9710b42Smrg if (FcResultMatch != FcPatternObjectGet (p, e->u.name.object, 0, &v)) 1292c9710b42Smrg v.type = FcTypeVoid; 1293c9710b42Smrg } 12942c393a42Smrg v = FcValueSave (v); 12952c393a42Smrg break; 12962c393a42Smrg case FcOpConst: 12972c393a42Smrg if (FcNameConstant (e->u.constant, &v.u.i)) 12982c393a42Smrg v.type = FcTypeInteger; 12992c393a42Smrg else 13002c393a42Smrg v.type = FcTypeVoid; 13012c393a42Smrg break; 13022c393a42Smrg case FcOpQuest: 1303c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 13042c393a42Smrg if (vl.type == FcTypeBool) 13052c393a42Smrg { 13062c393a42Smrg if (vl.u.b) 1307c9710b42Smrg v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.left); 13082c393a42Smrg else 1309c9710b42Smrg v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.right); 13102c393a42Smrg } 13112c393a42Smrg else 13122c393a42Smrg v.type = FcTypeVoid; 13132c393a42Smrg FcValueDestroy (vl); 13142c393a42Smrg break; 13152c393a42Smrg case FcOpEqual: 13162c393a42Smrg case FcOpNotEqual: 13172c393a42Smrg case FcOpLess: 13182c393a42Smrg case FcOpLessEqual: 13192c393a42Smrg case FcOpMore: 13202c393a42Smrg case FcOpMoreEqual: 13212c393a42Smrg case FcOpContains: 13222c393a42Smrg case FcOpNotContains: 13232c393a42Smrg case FcOpListing: 1324c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1325c9710b42Smrg vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right); 13262c393a42Smrg v.type = FcTypeBool; 13272c393a42Smrg v.u.b = FcConfigCompareValue (&vl, e->op, &vr); 13282c393a42Smrg FcValueDestroy (vl); 13292c393a42Smrg FcValueDestroy (vr); 133046bb3e47Smrg break; 13312c393a42Smrg case FcOpOr: 13322c393a42Smrg case FcOpAnd: 13332c393a42Smrg case FcOpPlus: 13342c393a42Smrg case FcOpMinus: 13352c393a42Smrg case FcOpTimes: 13362c393a42Smrg case FcOpDivide: 1337c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1338c9710b42Smrg vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right); 133918bd4a06Smrg vle = FcConfigPromote (vl, vr, &buf1); 134018bd4a06Smrg vre = FcConfigPromote (vr, vle, &buf2); 134118bd4a06Smrg if (vle.type == vre.type) 13422c393a42Smrg { 134318bd4a06Smrg switch ((int) vle.type) { 13442c393a42Smrg case FcTypeDouble: 1345c9710b42Smrg switch ((int) op) { 134646bb3e47Smrg case FcOpPlus: 13472c393a42Smrg v.type = FcTypeDouble; 134818bd4a06Smrg v.u.d = vle.u.d + vre.u.d; 13492c393a42Smrg break; 13502c393a42Smrg case FcOpMinus: 13512c393a42Smrg v.type = FcTypeDouble; 135218bd4a06Smrg v.u.d = vle.u.d - vre.u.d; 13532c393a42Smrg break; 13542c393a42Smrg case FcOpTimes: 13552c393a42Smrg v.type = FcTypeDouble; 135618bd4a06Smrg v.u.d = vle.u.d * vre.u.d; 13572c393a42Smrg break; 13582c393a42Smrg case FcOpDivide: 13592c393a42Smrg v.type = FcTypeDouble; 136018bd4a06Smrg v.u.d = vle.u.d / vre.u.d; 13612c393a42Smrg break; 13622c393a42Smrg default: 1363ca08ab68Smrg v.type = FcTypeVoid; 13642c393a42Smrg break; 13652c393a42Smrg } 13662c393a42Smrg if (v.type == FcTypeDouble && 13672c393a42Smrg v.u.d == (double) (int) v.u.d) 13682c393a42Smrg { 13692c393a42Smrg v.type = FcTypeInteger; 13702c393a42Smrg v.u.i = (int) v.u.d; 13712c393a42Smrg } 13722c393a42Smrg break; 13732c393a42Smrg case FcTypeBool: 1374c9710b42Smrg switch ((int) op) { 13752c393a42Smrg case FcOpOr: 13762c393a42Smrg v.type = FcTypeBool; 137718bd4a06Smrg v.u.b = vle.u.b || vre.u.b; 13782c393a42Smrg break; 13792c393a42Smrg case FcOpAnd: 13802c393a42Smrg v.type = FcTypeBool; 138118bd4a06Smrg v.u.b = vle.u.b && vre.u.b; 13822c393a42Smrg break; 13832c393a42Smrg default: 1384ca08ab68Smrg v.type = FcTypeVoid; 13852c393a42Smrg break; 13862c393a42Smrg } 13872c393a42Smrg break; 13882c393a42Smrg case FcTypeString: 1389c9710b42Smrg switch ((int) op) { 13902c393a42Smrg case FcOpPlus: 13912c393a42Smrg v.type = FcTypeString; 139218bd4a06Smrg str = FcStrPlus (vle.u.s, vre.u.s); 1393c9710b42Smrg v.u.s = FcStrdup (str); 13942c393a42Smrg FcStrFree (str); 139546bb3e47Smrg 13962c393a42Smrg if (!v.u.s) 13972c393a42Smrg v.type = FcTypeVoid; 13982c393a42Smrg break; 13992c393a42Smrg default: 14002c393a42Smrg v.type = FcTypeVoid; 14012c393a42Smrg break; 14022c393a42Smrg } 14032c393a42Smrg break; 14042c393a42Smrg case FcTypeMatrix: 1405c9710b42Smrg switch ((int) op) { 14062c393a42Smrg case FcOpTimes: 14072c393a42Smrg v.type = FcTypeMatrix; 14082c393a42Smrg m = malloc (sizeof (FcMatrix)); 14092c393a42Smrg if (m) 14102c393a42Smrg { 141118bd4a06Smrg FcMatrixMultiply (m, vle.u.m, vre.u.m); 14122c393a42Smrg v.u.m = m; 14132c393a42Smrg } 14142c393a42Smrg else 14152c393a42Smrg { 14162c393a42Smrg v.type = FcTypeVoid; 14172c393a42Smrg } 14182c393a42Smrg break; 14192c393a42Smrg default: 14202c393a42Smrg v.type = FcTypeVoid; 14212c393a42Smrg break; 14222c393a42Smrg } 14232c393a42Smrg break; 1424ca08ab68Smrg case FcTypeCharSet: 1425c9710b42Smrg switch ((int) op) { 1426ca08ab68Smrg case FcOpPlus: 1427ca08ab68Smrg v.type = FcTypeCharSet; 142818bd4a06Smrg v.u.c = FcCharSetUnion (vle.u.c, vre.u.c); 1429ca08ab68Smrg if (!v.u.c) 1430ca08ab68Smrg v.type = FcTypeVoid; 1431ca08ab68Smrg break; 1432ca08ab68Smrg case FcOpMinus: 1433ca08ab68Smrg v.type = FcTypeCharSet; 143418bd4a06Smrg v.u.c = FcCharSetSubtract (vle.u.c, vre.u.c); 1435ca08ab68Smrg if (!v.u.c) 1436ca08ab68Smrg v.type = FcTypeVoid; 1437ca08ab68Smrg break; 1438ca08ab68Smrg default: 1439ca08ab68Smrg v.type = FcTypeVoid; 1440ca08ab68Smrg break; 1441ca08ab68Smrg } 1442ca08ab68Smrg break; 1443ca08ab68Smrg case FcTypeLangSet: 1444c9710b42Smrg switch ((int) op) { 1445ca08ab68Smrg case FcOpPlus: 1446ca08ab68Smrg v.type = FcTypeLangSet; 144718bd4a06Smrg v.u.l = FcLangSetUnion (vle.u.l, vre.u.l); 1448ca08ab68Smrg if (!v.u.l) 1449ca08ab68Smrg v.type = FcTypeVoid; 1450ca08ab68Smrg break; 1451ca08ab68Smrg case FcOpMinus: 1452ca08ab68Smrg v.type = FcTypeLangSet; 145318bd4a06Smrg v.u.l = FcLangSetSubtract (vle.u.l, vre.u.l); 1454ca08ab68Smrg if (!v.u.l) 1455ca08ab68Smrg v.type = FcTypeVoid; 1456ca08ab68Smrg break; 1457ca08ab68Smrg default: 1458ca08ab68Smrg v.type = FcTypeVoid; 1459ca08ab68Smrg break; 1460ca08ab68Smrg } 1461ca08ab68Smrg break; 14622c393a42Smrg default: 14632c393a42Smrg v.type = FcTypeVoid; 14642c393a42Smrg break; 14652c393a42Smrg } 14662c393a42Smrg } 14672c393a42Smrg else 14682c393a42Smrg v.type = FcTypeVoid; 14692c393a42Smrg FcValueDestroy (vl); 14702c393a42Smrg FcValueDestroy (vr); 14712c393a42Smrg break; 14722c393a42Smrg case FcOpNot: 1473c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1474c9710b42Smrg switch ((int) vl.type) { 14752c393a42Smrg case FcTypeBool: 14762c393a42Smrg v.type = FcTypeBool; 14772c393a42Smrg v.u.b = !vl.u.b; 14782c393a42Smrg break; 14792c393a42Smrg default: 14802c393a42Smrg v.type = FcTypeVoid; 14812c393a42Smrg break; 14822c393a42Smrg } 14832c393a42Smrg FcValueDestroy (vl); 14842c393a42Smrg break; 14852c393a42Smrg case FcOpFloor: 1486c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1487c9710b42Smrg switch ((int) vl.type) { 14882c393a42Smrg case FcTypeInteger: 14892c393a42Smrg v = vl; 14902c393a42Smrg break; 14912c393a42Smrg case FcTypeDouble: 14922c393a42Smrg v.type = FcTypeInteger; 14932c393a42Smrg v.u.i = FcDoubleFloor (vl.u.d); 14942c393a42Smrg break; 14952c393a42Smrg default: 14962c393a42Smrg v.type = FcTypeVoid; 14972c393a42Smrg break; 14982c393a42Smrg } 14992c393a42Smrg FcValueDestroy (vl); 15002c393a42Smrg break; 15012c393a42Smrg case FcOpCeil: 1502c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1503c9710b42Smrg switch ((int) vl.type) { 15042c393a42Smrg case FcTypeInteger: 15052c393a42Smrg v = vl; 15062c393a42Smrg break; 15072c393a42Smrg case FcTypeDouble: 15082c393a42Smrg v.type = FcTypeInteger; 15092c393a42Smrg v.u.i = FcDoubleCeil (vl.u.d); 15102c393a42Smrg break; 15112c393a42Smrg default: 15122c393a42Smrg v.type = FcTypeVoid; 15132c393a42Smrg break; 15142c393a42Smrg } 15152c393a42Smrg FcValueDestroy (vl); 15162c393a42Smrg break; 15172c393a42Smrg case FcOpRound: 1518c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1519c9710b42Smrg switch ((int) vl.type) { 15202c393a42Smrg case FcTypeInteger: 15212c393a42Smrg v = vl; 15222c393a42Smrg break; 15232c393a42Smrg case FcTypeDouble: 15242c393a42Smrg v.type = FcTypeInteger; 15252c393a42Smrg v.u.i = FcDoubleRound (vl.u.d); 15262c393a42Smrg break; 15272c393a42Smrg default: 15282c393a42Smrg v.type = FcTypeVoid; 15292c393a42Smrg break; 15302c393a42Smrg } 15312c393a42Smrg FcValueDestroy (vl); 15322c393a42Smrg break; 15332c393a42Smrg case FcOpTrunc: 1534c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1535c9710b42Smrg switch ((int) vl.type) { 15362c393a42Smrg case FcTypeInteger: 15372c393a42Smrg v = vl; 15382c393a42Smrg break; 15392c393a42Smrg case FcTypeDouble: 15402c393a42Smrg v.type = FcTypeInteger; 15412c393a42Smrg v.u.i = FcDoubleTrunc (vl.u.d); 15422c393a42Smrg break; 15432c393a42Smrg default: 15442c393a42Smrg v.type = FcTypeVoid; 15452c393a42Smrg break; 15462c393a42Smrg } 15472c393a42Smrg FcValueDestroy (vl); 15482c393a42Smrg break; 15492c393a42Smrg default: 15502c393a42Smrg v.type = FcTypeVoid; 15512c393a42Smrg break; 15522c393a42Smrg } 15532c393a42Smrg return v; 15542c393a42Smrg} 15552c393a42Smrg 15567872e0a1Smrg/* The bulk of the time in FcConfigSubstitute is spent walking 15577872e0a1Smrg * lists of family names. We speed this up with a hash table. 15587872e0a1Smrg * Since we need to take the ignore-blanks option into account, 15597872e0a1Smrg * we use two separate hash tables. 15607872e0a1Smrg */ 15617872e0a1Smrgtypedef struct 15627872e0a1Smrg{ 15637872e0a1Smrg int count; 15647872e0a1Smrg} FamilyTableEntry; 15657872e0a1Smrg 15667872e0a1Smrg 15677872e0a1Smrgtypedef struct 15687872e0a1Smrg{ 15697872e0a1Smrg FcHashTable *family_blank_hash; 15707872e0a1Smrg FcHashTable *family_hash; 15717872e0a1Smrg} FamilyTable; 15727872e0a1Smrg 15737872e0a1Smrgstatic FcBool 15747872e0a1SmrgFamilyTableLookup (FamilyTable *table, 15757872e0a1Smrg FcOp _op, 15767872e0a1Smrg const FcChar8 *s) 15777872e0a1Smrg{ 15787872e0a1Smrg FamilyTableEntry *fe; 15797872e0a1Smrg int flags = FC_OP_GET_FLAGS (_op); 15807872e0a1Smrg FcHashTable *hash; 15817872e0a1Smrg 15827872e0a1Smrg if (flags & FcOpFlagIgnoreBlanks) 15837872e0a1Smrg hash = table->family_blank_hash; 15847872e0a1Smrg else 15857872e0a1Smrg hash = table->family_hash; 15867872e0a1Smrg 15877872e0a1Smrg return FcHashTableFind (hash, (const void *)s, (void **)&fe); 15887872e0a1Smrg} 15897872e0a1Smrg 15907872e0a1Smrgstatic void 15917872e0a1SmrgFamilyTableAdd (FamilyTable *table, 15927872e0a1Smrg FcValueListPtr values) 15937872e0a1Smrg{ 15947872e0a1Smrg FcValueListPtr ll; 15957872e0a1Smrg for (ll = values; ll; ll = FcValueListNext (ll)) 15967872e0a1Smrg { 15977872e0a1Smrg const FcChar8 *s = FcValueString (&ll->value); 15987872e0a1Smrg FamilyTableEntry *fe; 15997872e0a1Smrg 16007872e0a1Smrg if (!FcHashTableFind (table->family_hash, (const void *)s, (void **)&fe)) 16017872e0a1Smrg { 16027872e0a1Smrg fe = malloc (sizeof (FamilyTableEntry)); 16037872e0a1Smrg fe->count = 0; 16047872e0a1Smrg FcHashTableAdd (table->family_hash, (void *)s, fe); 16057872e0a1Smrg } 16067872e0a1Smrg fe->count++; 16077872e0a1Smrg 16087872e0a1Smrg if (!FcHashTableFind (table->family_blank_hash, (const void *)s, (void **)&fe)) 16097872e0a1Smrg { 16107872e0a1Smrg fe = malloc (sizeof (FamilyTableEntry)); 16117872e0a1Smrg fe->count = 0; 16127872e0a1Smrg FcHashTableAdd (table->family_blank_hash, (void *)s, fe); 16137872e0a1Smrg } 16147872e0a1Smrg fe->count++; 16157872e0a1Smrg } 16167872e0a1Smrg} 16177872e0a1Smrg 16187872e0a1Smrgstatic void 16197872e0a1SmrgFamilyTableDel (FamilyTable *table, 16207872e0a1Smrg const FcChar8 *s) 16217872e0a1Smrg{ 16227872e0a1Smrg FamilyTableEntry *fe; 16237872e0a1Smrg 16247872e0a1Smrg if (FcHashTableFind (table->family_hash, (void *)s, (void **)&fe)) 16257872e0a1Smrg { 16267872e0a1Smrg fe->count--; 16277872e0a1Smrg if (fe->count == 0) 16287872e0a1Smrg FcHashTableRemove (table->family_hash, (void *)s); 16297872e0a1Smrg } 16307872e0a1Smrg 16317872e0a1Smrg if (FcHashTableFind (table->family_blank_hash, (void *)s, (void **)&fe)) 16327872e0a1Smrg { 16337872e0a1Smrg fe->count--; 16347872e0a1Smrg if (fe->count == 0) 16357872e0a1Smrg FcHashTableRemove (table->family_blank_hash, (void *)s); 16367872e0a1Smrg } 16377872e0a1Smrg} 16387872e0a1Smrg 16397872e0a1Smrgstatic FcBool 16407872e0a1Smrgcopy_string (const void *src, void **dest) 16417872e0a1Smrg{ 16427872e0a1Smrg *dest = strdup ((char *)src); 16437872e0a1Smrg return FcTrue; 16447872e0a1Smrg} 16457872e0a1Smrg 16467872e0a1Smrgstatic void 16477872e0a1SmrgFamilyTableInit (FamilyTable *table, 16487872e0a1Smrg FcPattern *p) 16497872e0a1Smrg{ 16507872e0a1Smrg FcPatternElt *e; 16517872e0a1Smrg 16527872e0a1Smrg table->family_blank_hash = FcHashTableCreate ((FcHashFunc)FcStrHashIgnoreBlanksAndCase, 16537872e0a1Smrg (FcCompareFunc)FcStrCmpIgnoreBlanksAndCase, 16547872e0a1Smrg (FcCopyFunc)copy_string, 16557872e0a1Smrg NULL, 16567872e0a1Smrg free, 16577872e0a1Smrg free); 16587872e0a1Smrg table->family_hash = FcHashTableCreate ((FcHashFunc)FcStrHashIgnoreCase, 16597872e0a1Smrg (FcCompareFunc)FcStrCmpIgnoreCase, 16607872e0a1Smrg (FcCopyFunc)copy_string, 16617872e0a1Smrg NULL, 16627872e0a1Smrg free, 16637872e0a1Smrg free); 16647872e0a1Smrg e = FcPatternObjectFindElt (p, FC_FAMILY_OBJECT); 16657872e0a1Smrg if (e) 16667872e0a1Smrg FamilyTableAdd (table, FcPatternEltValues (e)); 16677872e0a1Smrg} 16687872e0a1Smrg 16697872e0a1Smrgstatic void 16707872e0a1SmrgFamilyTableClear (FamilyTable *table) 16717872e0a1Smrg{ 16727872e0a1Smrg if (table->family_blank_hash) 16737872e0a1Smrg FcHashTableDestroy (table->family_blank_hash); 16747872e0a1Smrg if (table->family_hash) 16757872e0a1Smrg FcHashTableDestroy (table->family_hash); 16767872e0a1Smrg} 16777872e0a1Smrg 16782c393a42Smrgstatic FcValueList * 16792c393a42SmrgFcConfigMatchValueList (FcPattern *p, 1680c9710b42Smrg FcPattern *p_pat, 1681c9710b42Smrg FcMatchKind kind, 16822c393a42Smrg FcTest *t, 16837872e0a1Smrg FcValueList *values, 16847872e0a1Smrg FamilyTable *table) 16852c393a42Smrg{ 16862c393a42Smrg FcValueList *ret = 0; 16872c393a42Smrg FcExpr *e = t->expr; 16882c393a42Smrg FcValue value; 16892c393a42Smrg FcValueList *v; 16907872e0a1Smrg FcOp op; 1691ca08ab68Smrg 16922c393a42Smrg while (e) 16932c393a42Smrg { 16942c393a42Smrg /* Compute the value of the match expression */ 1695ca08ab68Smrg if (FC_OP_GET_OP (e->op) == FcOpComma) 16962c393a42Smrg { 1697c9710b42Smrg value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 16982c393a42Smrg e = e->u.tree.right; 16992c393a42Smrg } 17002c393a42Smrg else 17012c393a42Smrg { 1702c9710b42Smrg value = FcConfigEvaluate (p, p_pat, kind, e); 17032c393a42Smrg e = 0; 17042c393a42Smrg } 17052c393a42Smrg 17067872e0a1Smrg if (t->object == FC_FAMILY_OBJECT && table) 17077872e0a1Smrg { 17087872e0a1Smrg op = FC_OP_GET_OP (t->op); 17097872e0a1Smrg if (op == FcOpEqual || op == FcOpListing) 17107872e0a1Smrg { 17117872e0a1Smrg if (!FamilyTableLookup (table, t->op, FcValueString (&value))) 17127872e0a1Smrg { 17137872e0a1Smrg ret = 0; 17147872e0a1Smrg goto done; 17157872e0a1Smrg } 17167872e0a1Smrg } 17177872e0a1Smrg if (op == FcOpNotEqual && t->qual == FcQualAll) 17187872e0a1Smrg { 17197872e0a1Smrg ret = 0; 17207872e0a1Smrg if (!FamilyTableLookup (table, t->op, FcValueString (&value))) 17217872e0a1Smrg { 17227872e0a1Smrg ret = values; 17237872e0a1Smrg } 17247872e0a1Smrg goto done; 17257872e0a1Smrg } 17267872e0a1Smrg } 17272c393a42Smrg for (v = values; v; v = FcValueListNext(v)) 17282c393a42Smrg { 17292c393a42Smrg /* Compare the pattern value to the match expression value */ 17302c393a42Smrg if (FcConfigCompareValue (&v->value, t->op, &value)) 17312c393a42Smrg { 17322c393a42Smrg if (!ret) 17332c393a42Smrg ret = v; 17347872e0a1Smrg if (t->qual != FcQualAll) 17357872e0a1Smrg break; 17362c393a42Smrg } 17372c393a42Smrg else 17382c393a42Smrg { 17392c393a42Smrg if (t->qual == FcQualAll) 17402c393a42Smrg { 17412c393a42Smrg ret = 0; 17422c393a42Smrg break; 17432c393a42Smrg } 17442c393a42Smrg } 17452c393a42Smrg } 17467872e0a1Smrgdone: 17472c393a42Smrg FcValueDestroy (value); 17482c393a42Smrg } 17492c393a42Smrg return ret; 17502c393a42Smrg} 17512c393a42Smrg 17522c393a42Smrgstatic FcValueList * 1753c9710b42SmrgFcConfigValues (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e, FcValueBinding binding) 17542c393a42Smrg{ 17552c393a42Smrg FcValueList *l; 1756ca08ab68Smrg 17572c393a42Smrg if (!e) 17582c393a42Smrg return 0; 17592c393a42Smrg l = (FcValueList *) malloc (sizeof (FcValueList)); 17602c393a42Smrg if (!l) 17612c393a42Smrg return 0; 1762ca08ab68Smrg if (FC_OP_GET_OP (e->op) == FcOpComma) 17632c393a42Smrg { 1764c9710b42Smrg l->value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1765c9710b42Smrg l->next = FcConfigValues (p, p_pat, kind, e->u.tree.right, binding); 17662c393a42Smrg } 17672c393a42Smrg else 17682c393a42Smrg { 1769c9710b42Smrg l->value = FcConfigEvaluate (p, p_pat, kind, e); 17702c393a42Smrg l->next = NULL; 17712c393a42Smrg } 17722c393a42Smrg l->binding = binding; 17732c393a42Smrg if (l->value.type == FcTypeVoid) 17742c393a42Smrg { 17752c393a42Smrg FcValueList *next = FcValueListNext(l); 17762c393a42Smrg 17772c393a42Smrg free (l); 17782c393a42Smrg l = next; 17792c393a42Smrg } 17802c393a42Smrg 17812c393a42Smrg return l; 17822c393a42Smrg} 17832c393a42Smrg 17842c393a42Smrgstatic FcBool 17852c393a42SmrgFcConfigAdd (FcValueListPtr *head, 17862c393a42Smrg FcValueList *position, 17872c393a42Smrg FcBool append, 1788c9710b42Smrg FcValueList *new, 17897872e0a1Smrg FcObject object, 17907872e0a1Smrg FamilyTable *table) 17912c393a42Smrg{ 1792c9710b42Smrg FcValueListPtr *prev, l, last, v; 17932c393a42Smrg FcValueBinding sameBinding; 1794ca08ab68Smrg 1795c9710b42Smrg /* 1796c9710b42Smrg * Make sure the stored type is valid for built-in objects 1797c9710b42Smrg */ 1798c9710b42Smrg for (l = new; l != NULL; l = FcValueListNext (l)) 1799c9710b42Smrg { 1800c9710b42Smrg if (!FcObjectValidType (object, l->value.type)) 1801c9710b42Smrg { 1802c9710b42Smrg fprintf (stderr, 1803c9710b42Smrg "Fontconfig warning: FcPattern object %s does not accept value", FcObjectName (object)); 1804c9710b42Smrg FcValuePrintFile (stderr, l->value); 1805c9710b42Smrg fprintf (stderr, "\n"); 1806c9710b42Smrg 1807c9710b42Smrg if (FcDebug () & FC_DBG_EDIT) 1808c9710b42Smrg { 1809c9710b42Smrg printf ("Not adding\n"); 1810c9710b42Smrg } 1811c9710b42Smrg 1812c9710b42Smrg return FcFalse; 1813c9710b42Smrg } 1814c9710b42Smrg } 1815c9710b42Smrg 18167872e0a1Smrg if (object == FC_FAMILY_OBJECT && table) 18177872e0a1Smrg { 18187872e0a1Smrg FamilyTableAdd (table, new); 18197872e0a1Smrg } 18207872e0a1Smrg 18212c393a42Smrg if (position) 18222c393a42Smrg sameBinding = position->binding; 18232c393a42Smrg else 18242c393a42Smrg sameBinding = FcValueBindingWeak; 18252c393a42Smrg for (v = new; v != NULL; v = FcValueListNext(v)) 18262c393a42Smrg if (v->binding == FcValueBindingSame) 18272c393a42Smrg v->binding = sameBinding; 18282c393a42Smrg if (append) 18292c393a42Smrg { 18302c393a42Smrg if (position) 18312c393a42Smrg prev = &position->next; 18322c393a42Smrg else 1833ca08ab68Smrg for (prev = head; *prev != NULL; 18342c393a42Smrg prev = &(*prev)->next) 18352c393a42Smrg ; 18362c393a42Smrg } 18372c393a42Smrg else 18382c393a42Smrg { 18392c393a42Smrg if (position) 18402c393a42Smrg { 1841ca08ab68Smrg for (prev = head; *prev != NULL; 18422c393a42Smrg prev = &(*prev)->next) 18432c393a42Smrg { 18442c393a42Smrg if (*prev == position) 18452c393a42Smrg break; 18462c393a42Smrg } 18472c393a42Smrg } 18482c393a42Smrg else 18492c393a42Smrg prev = head; 18502c393a42Smrg 18512c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 18522c393a42Smrg { 18532c393a42Smrg if (*prev == NULL) 18542c393a42Smrg printf ("position not on list\n"); 18552c393a42Smrg } 18562c393a42Smrg } 18572c393a42Smrg 18582c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 18592c393a42Smrg { 18602c393a42Smrg printf ("%s list before ", append ? "Append" : "Prepend"); 1861ca08ab68Smrg FcValueListPrintWithPosition (*head, *prev); 18622c393a42Smrg printf ("\n"); 18632c393a42Smrg } 1864ca08ab68Smrg 18652c393a42Smrg if (new) 18662c393a42Smrg { 18672c393a42Smrg last = new; 18682c393a42Smrg while (last->next != NULL) 18692c393a42Smrg last = last->next; 1870ca08ab68Smrg 18712c393a42Smrg last->next = *prev; 18722c393a42Smrg *prev = new; 18732c393a42Smrg } 1874ca08ab68Smrg 18752c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 18762c393a42Smrg { 18772c393a42Smrg printf ("%s list after ", append ? "Append" : "Prepend"); 18782c393a42Smrg FcValueListPrint (*head); 18792c393a42Smrg printf ("\n"); 18802c393a42Smrg } 1881ca08ab68Smrg 18822c393a42Smrg return FcTrue; 18832c393a42Smrg} 18842c393a42Smrg 18852c393a42Smrgstatic void 18862c393a42SmrgFcConfigDel (FcValueListPtr *head, 18877872e0a1Smrg FcValueList *position, 18887872e0a1Smrg FcObject object, 18897872e0a1Smrg FamilyTable *table) 18902c393a42Smrg{ 18912c393a42Smrg FcValueListPtr *prev; 18922c393a42Smrg 18937872e0a1Smrg if (object == FC_FAMILY_OBJECT && table) 18947872e0a1Smrg { 18957872e0a1Smrg FamilyTableDel (table, FcValueString (&position->value)); 18967872e0a1Smrg } 18977872e0a1Smrg 18982c393a42Smrg for (prev = head; *prev != NULL; prev = &(*prev)->next) 18992c393a42Smrg { 19002c393a42Smrg if (*prev == position) 19012c393a42Smrg { 19022c393a42Smrg *prev = position->next; 19032c393a42Smrg position->next = NULL; 19042c393a42Smrg FcValueListDestroy (position); 19052c393a42Smrg break; 19062c393a42Smrg } 19072c393a42Smrg } 19082c393a42Smrg} 19092c393a42Smrg 19102c393a42Smrgstatic void 19112c393a42SmrgFcConfigPatternAdd (FcPattern *p, 19127872e0a1Smrg FcObject object, 19132c393a42Smrg FcValueList *list, 19147872e0a1Smrg FcBool append, 19157872e0a1Smrg FamilyTable *table) 19162c393a42Smrg{ 19172c393a42Smrg if (list) 19182c393a42Smrg { 19192c393a42Smrg FcPatternElt *e = FcPatternObjectInsertElt (p, object); 1920ca08ab68Smrg 19212c393a42Smrg if (!e) 19222c393a42Smrg return; 19237872e0a1Smrg FcConfigAdd (&e->values, 0, append, list, object, table); 19242c393a42Smrg } 19252c393a42Smrg} 19262c393a42Smrg 19272c393a42Smrg/* 19282c393a42Smrg * Delete all values associated with a field 19292c393a42Smrg */ 19302c393a42Smrgstatic void 19312c393a42SmrgFcConfigPatternDel (FcPattern *p, 19327872e0a1Smrg FcObject object, 19337872e0a1Smrg FamilyTable *table) 19342c393a42Smrg{ 19352c393a42Smrg FcPatternElt *e = FcPatternObjectFindElt (p, object); 19362c393a42Smrg if (!e) 19372c393a42Smrg return; 19382c393a42Smrg while (e->values != NULL) 19397872e0a1Smrg FcConfigDel (&e->values, e->values, object, table); 19402c393a42Smrg} 19412c393a42Smrg 19422c393a42Smrgstatic void 19432c393a42SmrgFcConfigPatternCanon (FcPattern *p, 19442c393a42Smrg FcObject object) 19452c393a42Smrg{ 19462c393a42Smrg FcPatternElt *e = FcPatternObjectFindElt (p, object); 19472c393a42Smrg if (!e) 19482c393a42Smrg return; 19492c393a42Smrg if (e->values == NULL) 19502c393a42Smrg FcPatternObjectDel (p, object); 19512c393a42Smrg} 19522c393a42Smrg 19532c393a42SmrgFcBool 19542c393a42SmrgFcConfigSubstituteWithPat (FcConfig *config, 19552c393a42Smrg FcPattern *p, 19562c393a42Smrg FcPattern *p_pat, 19572c393a42Smrg FcMatchKind kind) 19582c393a42Smrg{ 1959c9710b42Smrg FcValue v; 19601887081fSmrg FcPtrList *s; 19611887081fSmrg FcPtrListIter iter, iter2; 19626fc018e4Smrg FcRule *r; 19631887081fSmrg FcRuleSet *rs; 19646fc018e4Smrg FcValueList *l, **value = NULL, *vl; 19652c393a42Smrg FcPattern *m; 1966ca08ab68Smrg FcStrSet *strs; 19676fc018e4Smrg FcObject object = FC_INVALID_OBJECT; 19686fc018e4Smrg FcPatternElt **elt = NULL, *e; 19696fc018e4Smrg int i, nobjs; 19706fc018e4Smrg FcBool retval = FcTrue; 19716fc018e4Smrg FcTest **tst = NULL; 19727872e0a1Smrg FamilyTable data; 19737872e0a1Smrg FamilyTable *table = &data; 19742c393a42Smrg 19751887081fSmrg if (kind < FcMatchKindBegin || kind >= FcMatchKindEnd) 19761887081fSmrg return FcFalse; 19777872e0a1Smrg 19787872e0a1Smrg config = FcConfigReference (config); 19797872e0a1Smrg if (!config) 19807872e0a1Smrg return FcFalse; 19817872e0a1Smrg 19821887081fSmrg s = config->subst[kind]; 19831887081fSmrg if (kind == FcMatchPattern) 19841887081fSmrg { 1985ca08ab68Smrg strs = FcGetDefaultLangs (); 1986ca08ab68Smrg if (strs) 1987ca08ab68Smrg { 1988ca08ab68Smrg FcStrList *l = FcStrListCreate (strs); 1989ca08ab68Smrg FcChar8 *lang; 1990ca08ab68Smrg FcValue v; 199118bd4a06Smrg FcLangSet *lsund = FcLangSetCreate (); 1992ca08ab68Smrg 199318bd4a06Smrg FcLangSetAdd (lsund, (const FcChar8 *)"und"); 1994ca08ab68Smrg FcStrSetDestroy (strs); 1995ca08ab68Smrg while (l && (lang = FcStrListNext (l))) 1996ca08ab68Smrg { 199718bd4a06Smrg FcPatternElt *e = FcPatternObjectFindElt (p, FC_LANG_OBJECT); 199818bd4a06Smrg 199918bd4a06Smrg if (e) 200018bd4a06Smrg { 200118bd4a06Smrg FcValueListPtr ll; 200218bd4a06Smrg 200318bd4a06Smrg for (ll = FcPatternEltValues (e); ll; ll = FcValueListNext (ll)) 200418bd4a06Smrg { 200518bd4a06Smrg FcValue vv = FcValueCanonicalize (&ll->value); 200618bd4a06Smrg 200718bd4a06Smrg if (vv.type == FcTypeLangSet) 200818bd4a06Smrg { 200918bd4a06Smrg FcLangSet *ls = FcLangSetCreate (); 201018bd4a06Smrg FcBool b; 201118bd4a06Smrg 201218bd4a06Smrg FcLangSetAdd (ls, lang); 201318bd4a06Smrg b = FcLangSetContains (vv.u.l, ls); 201418bd4a06Smrg FcLangSetDestroy (ls); 201518bd4a06Smrg if (b) 201618bd4a06Smrg goto bail_lang; 201718bd4a06Smrg if (FcLangSetContains (vv.u.l, lsund)) 201818bd4a06Smrg goto bail_lang; 201918bd4a06Smrg } 202018bd4a06Smrg else 202118bd4a06Smrg { 202218bd4a06Smrg if (FcStrCmpIgnoreCase (vv.u.s, lang) == 0) 202318bd4a06Smrg goto bail_lang; 202418bd4a06Smrg if (FcStrCmpIgnoreCase (vv.u.s, (const FcChar8 *)"und") == 0) 202518bd4a06Smrg goto bail_lang; 202618bd4a06Smrg } 202718bd4a06Smrg } 202818bd4a06Smrg } 2029ca08ab68Smrg v.type = FcTypeString; 2030ca08ab68Smrg v.u.s = lang; 203118bd4a06Smrg 2032ca08ab68Smrg FcPatternObjectAddWithBinding (p, FC_LANG_OBJECT, v, FcValueBindingWeak, FcTrue); 2033ca08ab68Smrg } 203418bd4a06Smrg bail_lang: 2035ca08ab68Smrg FcStrListDone (l); 203618bd4a06Smrg FcLangSetDestroy (lsund); 2037ca08ab68Smrg } 2038c9710b42Smrg if (FcPatternObjectGet (p, FC_PRGNAME_OBJECT, 0, &v) == FcResultNoMatch) 2039c9710b42Smrg { 2040c9710b42Smrg FcChar8 *prgname = FcGetPrgname (); 2041c9710b42Smrg if (prgname) 2042c9710b42Smrg FcPatternObjectAddString (p, FC_PRGNAME_OBJECT, prgname); 2043c9710b42Smrg } 20442c393a42Smrg } 20452c393a42Smrg 20466fc018e4Smrg nobjs = FC_MAX_BASE_OBJECT + config->maxObjects + 2; 2047cc1bebd6Smrg value = (FcValueList **) malloc (sizeof(void *) * nobjs); 20486fc018e4Smrg if (!value) 20496fc018e4Smrg { 20506fc018e4Smrg retval = FcFalse; 20516fc018e4Smrg goto bail1; 20526fc018e4Smrg } 2053cc1bebd6Smrg elt = (FcPatternElt **) malloc (sizeof(void *) * nobjs); 20546fc018e4Smrg if (!elt) 20556fc018e4Smrg { 20566fc018e4Smrg retval = FcFalse; 20576fc018e4Smrg goto bail1; 20586fc018e4Smrg } 2059cc1bebd6Smrg tst = (FcTest **) malloc (sizeof(void *) * nobjs); 20606fc018e4Smrg if (!tst) 20616fc018e4Smrg { 20626fc018e4Smrg retval = FcFalse; 20636fc018e4Smrg goto bail1; 20646fc018e4Smrg } 20652c393a42Smrg 20662c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 20672c393a42Smrg { 20682c393a42Smrg printf ("FcConfigSubstitute "); 20692c393a42Smrg FcPatternPrint (p); 20702c393a42Smrg } 20717872e0a1Smrg 20727872e0a1Smrg FamilyTableInit (&data, p); 20737872e0a1Smrg 20741887081fSmrg FcPtrListIterInit (s, &iter); 20751887081fSmrg for (; FcPtrListIterIsValid (s, &iter); FcPtrListIterNext (s, &iter)) 20762c393a42Smrg { 20771887081fSmrg rs = (FcRuleSet *) FcPtrListIterGetValue (s, &iter); 20781887081fSmrg if (FcDebug () & FC_DBG_EDIT) 20792c393a42Smrg { 20801887081fSmrg printf ("\nRule Set: %s\n", rs->name); 20816fc018e4Smrg } 20821887081fSmrg FcPtrListIterInit (rs->subst[kind], &iter2); 20831887081fSmrg for (; FcPtrListIterIsValid (rs->subst[kind], &iter2); FcPtrListIterNext (rs->subst[kind], &iter2)) 20846fc018e4Smrg { 20851887081fSmrg r = (FcRule *) FcPtrListIterGetValue (rs->subst[kind], &iter2); 20861887081fSmrg for (i = 0; i < nobjs; i++) 20871887081fSmrg { 20881887081fSmrg elt[i] = NULL; 20891887081fSmrg value[i] = NULL; 20901887081fSmrg tst[i] = NULL; 20911887081fSmrg } 20921887081fSmrg for (; r; r = r->next) 20931887081fSmrg { 20941887081fSmrg switch (r->type) { 20951887081fSmrg case FcRuleUnknown: 20961887081fSmrg /* shouldn't be reached */ 20971887081fSmrg break; 20981887081fSmrg case FcRuleTest: 20991887081fSmrg object = FC_OBJ_ID (r->u.test->object); 21001887081fSmrg /* 21011887081fSmrg * Check the tests to see if 21021887081fSmrg * they all match the pattern 21031887081fSmrg */ 21041887081fSmrg if (FcDebug () & FC_DBG_EDIT) 21056fc018e4Smrg { 21061887081fSmrg printf ("FcConfigSubstitute test "); 21071887081fSmrg FcTestPrint (r->u.test); 21086fc018e4Smrg } 21091887081fSmrg if (kind == FcMatchFont && r->u.test->kind == FcMatchPattern) 21107872e0a1Smrg { 21111887081fSmrg m = p_pat; 21127872e0a1Smrg table = NULL; 21137872e0a1Smrg } 21146fc018e4Smrg else 21157872e0a1Smrg { 21161887081fSmrg m = p; 21177872e0a1Smrg table = &data; 21187872e0a1Smrg } 21191887081fSmrg if (m) 21201887081fSmrg e = FcPatternObjectFindElt (m, r->u.test->object); 21211887081fSmrg else 21221887081fSmrg e = NULL; 21231887081fSmrg /* different 'kind' won't be the target of edit */ 21241887081fSmrg if (!elt[object] && kind == r->u.test->kind) 21251887081fSmrg { 21261887081fSmrg elt[object] = e; 21271887081fSmrg tst[object] = r->u.test; 21281887081fSmrg } 21291887081fSmrg /* 21301887081fSmrg * If there's no such field in the font, 21311887081fSmrg * then FcQualAll matches while FcQualAny does not 21321887081fSmrg */ 21331887081fSmrg if (!e) 21341887081fSmrg { 21351887081fSmrg if (r->u.test->qual == FcQualAll) 21361887081fSmrg { 21371887081fSmrg value[object] = NULL; 21381887081fSmrg continue; 21391887081fSmrg } 21401887081fSmrg else 21411887081fSmrg { 21421887081fSmrg if (FcDebug () & FC_DBG_EDIT) 21431887081fSmrg printf ("No match\n"); 21441887081fSmrg goto bail; 21451887081fSmrg } 21461887081fSmrg } 21471887081fSmrg /* 21481887081fSmrg * Check to see if there is a match, mark the location 21491887081fSmrg * to apply match-relative edits 21501887081fSmrg */ 21517872e0a1Smrg vl = FcConfigMatchValueList (m, p_pat, kind, r->u.test, e->values, table); 21521887081fSmrg /* different 'kind' won't be the target of edit */ 21531887081fSmrg if (!value[object] && kind == r->u.test->kind) 21541887081fSmrg value[object] = vl; 21551887081fSmrg if (!vl || 21561887081fSmrg (r->u.test->qual == FcQualFirst && vl != e->values) || 21571887081fSmrg (r->u.test->qual == FcQualNotFirst && vl == e->values)) 21586fc018e4Smrg { 21596fc018e4Smrg if (FcDebug () & FC_DBG_EDIT) 21606fc018e4Smrg printf ("No match\n"); 21616fc018e4Smrg goto bail; 21626fc018e4Smrg } 21631887081fSmrg break; 21641887081fSmrg case FcRuleEdit: 21651887081fSmrg object = FC_OBJ_ID (r->u.edit->object); 21666fc018e4Smrg if (FcDebug () & FC_DBG_EDIT) 21671887081fSmrg { 21681887081fSmrg printf ("Substitute "); 21691887081fSmrg FcEditPrint (r->u.edit); 21701887081fSmrg printf ("\n\n"); 21711887081fSmrg } 21722c393a42Smrg /* 21731887081fSmrg * Evaluate the list of expressions 21742c393a42Smrg */ 21757872e0a1Smrg l = FcConfigValues (p, p_pat, kind, r->u.edit->expr, r->u.edit->binding); 21761887081fSmrg if (tst[object] && (tst[object]->kind == FcMatchFont || kind == FcMatchPattern)) 21771887081fSmrg elt[object] = FcPatternObjectFindElt (p, tst[object]->object); 21786fc018e4Smrg 21791887081fSmrg switch (FC_OP_GET_OP (r->u.edit->op)) { 21801887081fSmrg case FcOpAssign: 21816fc018e4Smrg /* 21821887081fSmrg * If there was a test, then replace the matched 21831887081fSmrg * value with the new list of values 21846fc018e4Smrg */ 21851887081fSmrg if (value[object]) 21861887081fSmrg { 21871887081fSmrg FcValueList *thisValue = value[object]; 21881887081fSmrg FcValueList *nextValue = l; 21891887081fSmrg 21901887081fSmrg /* 21911887081fSmrg * Append the new list of values after the current value 21921887081fSmrg */ 21937872e0a1Smrg FcConfigAdd (&elt[object]->values, thisValue, FcTrue, l, r->u.edit->object, table); 21941887081fSmrg /* 21951887081fSmrg * Delete the marked value 21961887081fSmrg */ 21971887081fSmrg if (thisValue) 21987872e0a1Smrg FcConfigDel (&elt[object]->values, thisValue, object, table); 21991887081fSmrg /* 22001887081fSmrg * Adjust a pointer into the value list to ensure 22011887081fSmrg * future edits occur at the same place 22021887081fSmrg */ 22031887081fSmrg value[object] = nextValue; 22041887081fSmrg break; 22051887081fSmrg } 22061887081fSmrg /* fall through ... */ 22071887081fSmrg case FcOpAssignReplace: 22086fc018e4Smrg /* 22091887081fSmrg * Delete all of the values and insert 22101887081fSmrg * the new set 22116fc018e4Smrg */ 22127872e0a1Smrg FcConfigPatternDel (p, r->u.edit->object, table); 22137872e0a1Smrg FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue, table); 22146fc018e4Smrg /* 22151887081fSmrg * Adjust a pointer into the value list as they no 22161887081fSmrg * longer point to anything valid 22176fc018e4Smrg */ 22181887081fSmrg value[object] = NULL; 22196fc018e4Smrg break; 22201887081fSmrg case FcOpPrepend: 22211887081fSmrg if (value[object]) 22221887081fSmrg { 22237872e0a1Smrg FcConfigAdd (&elt[object]->values, value[object], FcFalse, l, r->u.edit->object, table); 22241887081fSmrg break; 22251887081fSmrg } 22261887081fSmrg /* fall through ... */ 22271887081fSmrg case FcOpPrependFirst: 22287872e0a1Smrg FcConfigPatternAdd (p, r->u.edit->object, l, FcFalse, table); 22296fc018e4Smrg break; 22301887081fSmrg case FcOpAppend: 22311887081fSmrg if (value[object]) 22321887081fSmrg { 22337872e0a1Smrg FcConfigAdd (&elt[object]->values, value[object], FcTrue, l, r->u.edit->object, table); 22341887081fSmrg break; 22351887081fSmrg } 22361887081fSmrg /* fall through ... */ 22371887081fSmrg case FcOpAppendLast: 22387872e0a1Smrg FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue, table); 22391887081fSmrg break; 22401887081fSmrg case FcOpDelete: 22411887081fSmrg if (value[object]) 22421887081fSmrg { 22437872e0a1Smrg FcConfigDel (&elt[object]->values, value[object], object, table); 22441887081fSmrg FcValueListDestroy (l); 22451887081fSmrg break; 22461887081fSmrg } 22471887081fSmrg /* fall through ... */ 22481887081fSmrg case FcOpDeleteAll: 22497872e0a1Smrg FcConfigPatternDel (p, r->u.edit->object, table); 22501887081fSmrg FcValueListDestroy (l); 22511887081fSmrg break; 22521887081fSmrg default: 22531887081fSmrg FcValueListDestroy (l); 22546fc018e4Smrg break; 22552c393a42Smrg } 22561887081fSmrg /* 22571887081fSmrg * Now go through the pattern and eliminate 22581887081fSmrg * any properties without data 22591887081fSmrg */ 22601887081fSmrg FcConfigPatternCanon (p, r->u.edit->object); 22611887081fSmrg 22621887081fSmrg if (FcDebug () & FC_DBG_EDIT) 22636fc018e4Smrg { 22641887081fSmrg printf ("FcConfigSubstitute edit"); 22651887081fSmrg FcPatternPrint (p); 22666fc018e4Smrg } 22672c393a42Smrg break; 22682c393a42Smrg } 22692c393a42Smrg } 22701887081fSmrg bail:; 22712c393a42Smrg } 22722c393a42Smrg } 22732c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 22742c393a42Smrg { 22752c393a42Smrg printf ("FcConfigSubstitute done"); 22762c393a42Smrg FcPatternPrint (p); 22772c393a42Smrg } 22787872e0a1Smrg FamilyTableClear (&data); 227932c2f8aeSmrgbail1: 22806fc018e4Smrg if (elt) 22816fc018e4Smrg free (elt); 22826fc018e4Smrg if (value) 22836fc018e4Smrg free (value); 22846fc018e4Smrg if (tst) 22856fc018e4Smrg free (tst); 22867872e0a1Smrg FcConfigDestroy (config); 22876fc018e4Smrg 22886fc018e4Smrg return retval; 22892c393a42Smrg} 22902c393a42Smrg 22912c393a42SmrgFcBool 22922c393a42SmrgFcConfigSubstitute (FcConfig *config, 22932c393a42Smrg FcPattern *p, 22942c393a42Smrg FcMatchKind kind) 22952c393a42Smrg{ 22962c393a42Smrg return FcConfigSubstituteWithPat (config, p, 0, kind); 22972c393a42Smrg} 22982c393a42Smrg 22992c393a42Smrg#if defined (_WIN32) 23002c393a42Smrg 2301c9710b42Smrgstatic FcChar8 fontconfig_path[1000] = ""; /* MT-dontcare */ 230218bd4a06SmrgFcChar8 fontconfig_instprefix[1000] = ""; /* MT-dontcare */ 23032c393a42Smrg 23042c393a42Smrg# if (defined (PIC) || defined (DLL_EXPORT)) 23052c393a42Smrg 2306c9710b42SmrgBOOL WINAPI 2307c9710b42SmrgDllMain (HINSTANCE hinstDLL, 2308c9710b42Smrg DWORD fdwReason, 2309c9710b42Smrg LPVOID lpvReserved); 2310c9710b42Smrg 23112c393a42SmrgBOOL WINAPI 23122c393a42SmrgDllMain (HINSTANCE hinstDLL, 23132c393a42Smrg DWORD fdwReason, 23142c393a42Smrg LPVOID lpvReserved) 23152c393a42Smrg{ 23162c393a42Smrg FcChar8 *p; 23172c393a42Smrg 23182c393a42Smrg switch (fdwReason) { 23192c393a42Smrg case DLL_PROCESS_ATTACH: 2320ca08ab68Smrg if (!GetModuleFileName ((HMODULE) hinstDLL, (LPCH) fontconfig_path, 23212c393a42Smrg sizeof (fontconfig_path))) 23222c393a42Smrg break; 23232c393a42Smrg 23242c393a42Smrg /* If the fontconfig DLL is in a "bin" or "lib" subfolder, 23252c393a42Smrg * assume it's a Unix-style installation tree, and use 23262c393a42Smrg * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the 23272c393a42Smrg * folder where the DLL is as FONTCONFIG_PATH. 23282c393a42Smrg */ 2329ca08ab68Smrg p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\'); 23302c393a42Smrg if (p) 23312c393a42Smrg { 23322c393a42Smrg *p = '\0'; 2333ca08ab68Smrg p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\'); 2334ca08ab68Smrg if (p && (FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "bin") == 0 || 2335ca08ab68Smrg FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "lib") == 0)) 23362c393a42Smrg *p = '\0'; 233718bd4a06Smrg strcat ((char *) fontconfig_instprefix, (char *) fontconfig_path); 2338ca08ab68Smrg strcat ((char *) fontconfig_path, "\\etc\\fonts"); 23392c393a42Smrg } 23402c393a42Smrg else 23412c393a42Smrg fontconfig_path[0] = '\0'; 2342ca08ab68Smrg 23432c393a42Smrg break; 23442c393a42Smrg } 23452c393a42Smrg 23462c393a42Smrg return TRUE; 23472c393a42Smrg} 23482c393a42Smrg 23492c393a42Smrg# endif /* !PIC */ 23502c393a42Smrg 23512c393a42Smrg#undef FONTCONFIG_PATH 23522c393a42Smrg#define FONTCONFIG_PATH fontconfig_path 23532c393a42Smrg 23542c393a42Smrg#endif /* !_WIN32 */ 23552c393a42Smrg 23562c393a42Smrg#ifndef FONTCONFIG_FILE 23572c393a42Smrg#define FONTCONFIG_FILE "fonts.conf" 23582c393a42Smrg#endif 23592c393a42Smrg 23602c393a42Smrgstatic FcChar8 * 23612c393a42SmrgFcConfigFileExists (const FcChar8 *dir, const FcChar8 *file) 23622c393a42Smrg{ 23632c393a42Smrg FcChar8 *path; 2364ca08ab68Smrg int size, osize; 23652c393a42Smrg 23662c393a42Smrg if (!dir) 23672c393a42Smrg dir = (FcChar8 *) ""; 2368ca08ab68Smrg 2369ca08ab68Smrg osize = strlen ((char *) dir) + 1 + strlen ((char *) file) + 1; 2370ca08ab68Smrg /* 2371ca08ab68Smrg * workaround valgrind warning because glibc takes advantage of how it knows memory is 2372ca08ab68Smrg * allocated to implement strlen by reading in groups of 4 2373ca08ab68Smrg */ 2374ca08ab68Smrg size = (osize + 3) & ~3; 2375ca08ab68Smrg 2376ca08ab68Smrg path = malloc (size); 23772c393a42Smrg if (!path) 23782c393a42Smrg return 0; 23792c393a42Smrg 23802c393a42Smrg strcpy ((char *) path, (const char *) dir); 23812c393a42Smrg /* make sure there's a single separator */ 23822c393a42Smrg#ifdef _WIN32 23832c393a42Smrg if ((!path[0] || (path[strlen((char *) path)-1] != '/' && 23842c393a42Smrg path[strlen((char *) path)-1] != '\\')) && 23852c393a42Smrg !(file[0] == '/' || 23862c393a42Smrg file[0] == '\\' || 23872c393a42Smrg (isalpha (file[0]) && file[1] == ':' && (file[2] == '/' || file[2] == '\\')))) 23882c393a42Smrg strcat ((char *) path, "\\"); 23892c393a42Smrg#else 23902c393a42Smrg if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/') 23912c393a42Smrg strcat ((char *) path, "/"); 2392c9710b42Smrg else 2393c9710b42Smrg osize--; 23942c393a42Smrg#endif 23952c393a42Smrg strcat ((char *) path, (char *) file); 23962c393a42Smrg 23972c393a42Smrg if (access ((char *) path, R_OK) == 0) 23982c393a42Smrg return path; 2399ca08ab68Smrg 24002c393a42Smrg FcStrFree (path); 2401ca08ab68Smrg 24022c393a42Smrg return 0; 24032c393a42Smrg} 24042c393a42Smrg 24052c393a42Smrgstatic FcChar8 ** 24062c393a42SmrgFcConfigGetPath (void) 24072c393a42Smrg{ 24082c393a42Smrg FcChar8 **path; 24092c393a42Smrg FcChar8 *env, *e, *colon; 24102c393a42Smrg FcChar8 *dir; 24112c393a42Smrg int npath; 24122c393a42Smrg int i; 24132c393a42Smrg 24142c393a42Smrg npath = 2; /* default dir + null */ 24152c393a42Smrg env = (FcChar8 *) getenv ("FONTCONFIG_PATH"); 24162c393a42Smrg if (env) 24172c393a42Smrg { 24182c393a42Smrg e = env; 24192c393a42Smrg npath++; 24202c393a42Smrg while (*e) 24212c393a42Smrg if (*e++ == FC_SEARCH_PATH_SEPARATOR) 24222c393a42Smrg npath++; 24232c393a42Smrg } 24242c393a42Smrg path = calloc (npath, sizeof (FcChar8 *)); 24252c393a42Smrg if (!path) 24262c393a42Smrg goto bail0; 24272c393a42Smrg i = 0; 24282c393a42Smrg 24292c393a42Smrg if (env) 24302c393a42Smrg { 24312c393a42Smrg e = env; 2432ca08ab68Smrg while (*e) 24332c393a42Smrg { 24342c393a42Smrg colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR); 24352c393a42Smrg if (!colon) 24362c393a42Smrg colon = e + strlen ((char *) e); 24372c393a42Smrg path[i] = malloc (colon - e + 1); 24382c393a42Smrg if (!path[i]) 24392c393a42Smrg goto bail1; 24402c393a42Smrg strncpy ((char *) path[i], (const char *) e, colon - e); 24412c393a42Smrg path[i][colon - e] = '\0'; 24422c393a42Smrg if (*colon) 24432c393a42Smrg e = colon + 1; 24442c393a42Smrg else 24452c393a42Smrg e = colon; 24462c393a42Smrg i++; 24472c393a42Smrg } 24482c393a42Smrg } 2449ca08ab68Smrg 24502c393a42Smrg#ifdef _WIN32 24512c393a42Smrg if (fontconfig_path[0] == '\0') 24522c393a42Smrg { 2453a6844aabSmrg char *p; 2454ca08ab68Smrg if(!GetModuleFileName(NULL, (LPCH) fontconfig_path, sizeof(fontconfig_path))) 24552c393a42Smrg goto bail1; 2456ca08ab68Smrg p = strrchr ((const char *) fontconfig_path, '\\'); 24572c393a42Smrg if (p) *p = '\0'; 2458ca08ab68Smrg strcat ((char *) fontconfig_path, "\\fonts"); 24592c393a42Smrg } 24602c393a42Smrg#endif 24612c393a42Smrg dir = (FcChar8 *) FONTCONFIG_PATH; 24622c393a42Smrg path[i] = malloc (strlen ((char *) dir) + 1); 24632c393a42Smrg if (!path[i]) 24642c393a42Smrg goto bail1; 24652c393a42Smrg strcpy ((char *) path[i], (const char *) dir); 24662c393a42Smrg return path; 24672c393a42Smrg 24682c393a42Smrgbail1: 24692c393a42Smrg for (i = 0; path[i]; i++) 24702c393a42Smrg free (path[i]); 24712c393a42Smrg free (path); 24722c393a42Smrgbail0: 24732c393a42Smrg return 0; 24742c393a42Smrg} 24752c393a42Smrg 24762c393a42Smrgstatic void 24772c393a42SmrgFcConfigFreePath (FcChar8 **path) 24782c393a42Smrg{ 24792c393a42Smrg FcChar8 **p; 24802c393a42Smrg 24812c393a42Smrg for (p = path; *p; p++) 24822c393a42Smrg free (*p); 24832c393a42Smrg free (path); 24842c393a42Smrg} 24852c393a42Smrg 2486c9710b42Smrgstatic FcBool _FcConfigHomeEnabled = FcTrue; /* MT-goodenough */ 24872c393a42Smrg 24882c393a42SmrgFcChar8 * 24892c393a42SmrgFcConfigHome (void) 24902c393a42Smrg{ 24912c393a42Smrg if (_FcConfigHomeEnabled) 24922c393a42Smrg { 24932c393a42Smrg char *home = getenv ("HOME"); 24942c393a42Smrg 24952c393a42Smrg#ifdef _WIN32 24962c393a42Smrg if (home == NULL) 24972c393a42Smrg home = getenv ("USERPROFILE"); 24982c393a42Smrg#endif 24992c393a42Smrg 25002c393a42Smrg return (FcChar8 *) home; 25012c393a42Smrg } 25022c393a42Smrg return 0; 25032c393a42Smrg} 25042c393a42Smrg 2505ca08ab68SmrgFcChar8 * 2506ca08ab68SmrgFcConfigXdgCacheHome (void) 2507ca08ab68Smrg{ 2508ca08ab68Smrg const char *env = getenv ("XDG_CACHE_HOME"); 2509ca08ab68Smrg FcChar8 *ret = NULL; 2510ca08ab68Smrg 251118bd4a06Smrg if (!_FcConfigHomeEnabled) 251218bd4a06Smrg return NULL; 25137872e0a1Smrg if (env && env[0]) 2514ca08ab68Smrg ret = FcStrCopy ((const FcChar8 *)env); 2515ca08ab68Smrg else 2516ca08ab68Smrg { 2517ca08ab68Smrg const FcChar8 *home = FcConfigHome (); 2518ca08ab68Smrg size_t len = home ? strlen ((const char *)home) : 0; 2519ca08ab68Smrg 2520ca08ab68Smrg ret = malloc (len + 7 + 1); 2521ca08ab68Smrg if (ret) 2522ca08ab68Smrg { 25231887081fSmrg if (home) 25241887081fSmrg memcpy (ret, home, len); 2525ca08ab68Smrg memcpy (&ret[len], FC_DIR_SEPARATOR_S ".cache", 7); 2526ca08ab68Smrg ret[len + 7] = 0; 2527ca08ab68Smrg } 2528ca08ab68Smrg } 2529ca08ab68Smrg 2530ca08ab68Smrg return ret; 2531ca08ab68Smrg} 2532ca08ab68Smrg 2533ca08ab68SmrgFcChar8 * 2534ca08ab68SmrgFcConfigXdgConfigHome (void) 2535ca08ab68Smrg{ 2536ca08ab68Smrg const char *env = getenv ("XDG_CONFIG_HOME"); 2537ca08ab68Smrg FcChar8 *ret = NULL; 2538ca08ab68Smrg 253918bd4a06Smrg if (!_FcConfigHomeEnabled) 254018bd4a06Smrg return NULL; 2541ca08ab68Smrg if (env) 2542ca08ab68Smrg ret = FcStrCopy ((const FcChar8 *)env); 2543ca08ab68Smrg else 2544ca08ab68Smrg { 2545ca08ab68Smrg const FcChar8 *home = FcConfigHome (); 2546ca08ab68Smrg size_t len = home ? strlen ((const char *)home) : 0; 2547ca08ab68Smrg 2548ca08ab68Smrg ret = malloc (len + 8 + 1); 2549ca08ab68Smrg if (ret) 2550ca08ab68Smrg { 25511887081fSmrg if (home) 25521887081fSmrg memcpy (ret, home, len); 2553ca08ab68Smrg memcpy (&ret[len], FC_DIR_SEPARATOR_S ".config", 8); 2554ca08ab68Smrg ret[len + 8] = 0; 2555ca08ab68Smrg } 2556ca08ab68Smrg } 2557ca08ab68Smrg 2558ca08ab68Smrg return ret; 2559ca08ab68Smrg} 2560ca08ab68Smrg 2561ca08ab68SmrgFcChar8 * 2562ca08ab68SmrgFcConfigXdgDataHome (void) 2563ca08ab68Smrg{ 2564ca08ab68Smrg const char *env = getenv ("XDG_DATA_HOME"); 2565ca08ab68Smrg FcChar8 *ret = NULL; 2566ca08ab68Smrg 256718bd4a06Smrg if (!_FcConfigHomeEnabled) 256818bd4a06Smrg return NULL; 2569ca08ab68Smrg if (env) 2570ca08ab68Smrg ret = FcStrCopy ((const FcChar8 *)env); 2571ca08ab68Smrg else 2572ca08ab68Smrg { 2573ca08ab68Smrg const FcChar8 *home = FcConfigHome (); 2574ca08ab68Smrg size_t len = home ? strlen ((const char *)home) : 0; 2575ca08ab68Smrg 2576ca08ab68Smrg ret = malloc (len + 13 + 1); 2577ca08ab68Smrg if (ret) 2578ca08ab68Smrg { 25791887081fSmrg if (home) 25801887081fSmrg memcpy (ret, home, len); 2581ca08ab68Smrg memcpy (&ret[len], FC_DIR_SEPARATOR_S ".local" FC_DIR_SEPARATOR_S "share", 13); 2582ca08ab68Smrg ret[len + 13] = 0; 2583ca08ab68Smrg } 2584ca08ab68Smrg } 2585ca08ab68Smrg 2586ca08ab68Smrg return ret; 2587ca08ab68Smrg} 2588ca08ab68Smrg 25897872e0a1SmrgFcStrSet * 25907872e0a1SmrgFcConfigXdgDataDirs (void) 25917872e0a1Smrg{ 25927872e0a1Smrg const char *env = getenv ("XDG_DATA_DIRS"); 25937872e0a1Smrg FcStrSet *ret = FcStrSetCreate (); 25947872e0a1Smrg 25957872e0a1Smrg if (env) 25967872e0a1Smrg { 25977872e0a1Smrg FcChar8 *ee, *e = ee = FcStrCopy ((const FcChar8 *) env); 25987872e0a1Smrg 25997872e0a1Smrg /* We don't intentionally use FC_SEARCH_PATH_SEPARATOR here because of: 26007872e0a1Smrg * The directories in $XDG_DATA_DIRS should be seperated with a colon ':'. 26017872e0a1Smrg * in doc. 26027872e0a1Smrg */ 26037872e0a1Smrg while (e) 26047872e0a1Smrg { 26057872e0a1Smrg FcChar8 *p = (FcChar8 *) strchr ((const char *) e, ':'); 26067872e0a1Smrg FcChar8 *s; 26077872e0a1Smrg size_t len; 26087872e0a1Smrg 26097872e0a1Smrg if (!p) 26107872e0a1Smrg { 26117872e0a1Smrg s = FcStrCopy (e); 26127872e0a1Smrg e = NULL; 26137872e0a1Smrg } 26147872e0a1Smrg else 26157872e0a1Smrg { 26167872e0a1Smrg *p = 0; 26177872e0a1Smrg s = FcStrCopy (e); 26187872e0a1Smrg e = p + 1; 26197872e0a1Smrg } 26207872e0a1Smrg len = strlen ((const char *) s); 26217872e0a1Smrg if (s[len - 1] == FC_DIR_SEPARATOR) 26227872e0a1Smrg { 26237872e0a1Smrg do 26247872e0a1Smrg { 26257872e0a1Smrg len--; 26267872e0a1Smrg } 26277872e0a1Smrg while (len > 1 && s[len - 1] == FC_DIR_SEPARATOR); 26287872e0a1Smrg s[len] = 0; 26297872e0a1Smrg } 26307872e0a1Smrg FcStrSetAdd (ret, s); 26317872e0a1Smrg FcStrFree (s); 26327872e0a1Smrg } 26337872e0a1Smrg FcStrFree (ee); 26347872e0a1Smrg } 26357872e0a1Smrg else 26367872e0a1Smrg { 26377872e0a1Smrg /* From spec doc at https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html#variables 26387872e0a1Smrg * 26397872e0a1Smrg * If $XDG_DATA_DIRS is either not set or empty, a value equal to /usr/local/share/:/usr/share/ should be used. 26407872e0a1Smrg */ 26417872e0a1Smrg FcStrSetAdd (ret, (const FcChar8 *) "/usr/local/share"); 26427872e0a1Smrg FcStrSetAdd (ret, (const FcChar8 *) "/usr/share"); 26437872e0a1Smrg } 26447872e0a1Smrg 26457872e0a1Smrg return ret; 26467872e0a1Smrg} 26477872e0a1Smrg 26482c393a42SmrgFcBool 26492c393a42SmrgFcConfigEnableHome (FcBool enable) 26502c393a42Smrg{ 26512c393a42Smrg FcBool prev = _FcConfigHomeEnabled; 26522c393a42Smrg _FcConfigHomeEnabled = enable; 26532c393a42Smrg return prev; 26542c393a42Smrg} 26552c393a42Smrg 26562c393a42SmrgFcChar8 * 26577872e0a1SmrgFcConfigGetFilename (FcConfig *config, 26587872e0a1Smrg const FcChar8 *url) 26592c393a42Smrg{ 26602c393a42Smrg FcChar8 *file, *dir, **path, **p; 26617872e0a1Smrg const FcChar8 *sysroot; 26622c393a42Smrg 26637872e0a1Smrg config = FcConfigReference (config); 26647872e0a1Smrg if (!config) 26657872e0a1Smrg return NULL; 26667872e0a1Smrg sysroot = FcConfigGetSysRoot (config); 26672c393a42Smrg if (!url || !*url) 26682c393a42Smrg { 26692c393a42Smrg url = (FcChar8 *) getenv ("FONTCONFIG_FILE"); 26702c393a42Smrg if (!url) 26712c393a42Smrg url = (FcChar8 *) FONTCONFIG_FILE; 26722c393a42Smrg } 26732c393a42Smrg file = 0; 26742c393a42Smrg 26751887081fSmrg if (FcStrIsAbsoluteFilename(url)) 26767872e0a1Smrg { 26777872e0a1Smrg if (sysroot) 26787872e0a1Smrg { 26797872e0a1Smrg size_t len = strlen ((const char *) sysroot); 26807872e0a1Smrg 26817872e0a1Smrg /* Workaround to avoid adding sysroot repeatedly */ 26827872e0a1Smrg if (strncmp ((const char *) url, (const char *) sysroot, len) == 0) 26837872e0a1Smrg sysroot = NULL; 26847872e0a1Smrg } 26857872e0a1Smrg file = FcConfigFileExists (sysroot, url); 26867872e0a1Smrg goto bail; 26877872e0a1Smrg } 26882c393a42Smrg 26891887081fSmrg if (*url == '~') 26901887081fSmrg { 26912c393a42Smrg dir = FcConfigHome (); 26922c393a42Smrg if (dir) 26937872e0a1Smrg { 26947872e0a1Smrg FcChar8 *s; 26957872e0a1Smrg 26967872e0a1Smrg if (sysroot) 26977872e0a1Smrg s = FcStrBuildFilename (sysroot, dir, NULL); 26987872e0a1Smrg else 26997872e0a1Smrg s = dir; 27007872e0a1Smrg file = FcConfigFileExists (s, url + 1); 27017872e0a1Smrg if (sysroot) 27027872e0a1Smrg FcStrFree (s); 27037872e0a1Smrg } 27042c393a42Smrg else 27052c393a42Smrg file = 0; 27061887081fSmrg } 27077872e0a1Smrg else 27081887081fSmrg { 27097872e0a1Smrg path = FcConfigGetPath (); 27107872e0a1Smrg if (!path) 27117872e0a1Smrg { 27127872e0a1Smrg file = NULL; 27137872e0a1Smrg goto bail; 27147872e0a1Smrg } 27157872e0a1Smrg for (p = path; *p; p++) 27167872e0a1Smrg { 27177872e0a1Smrg FcChar8 *s; 27187872e0a1Smrg 27197872e0a1Smrg if (sysroot) 27207872e0a1Smrg s = FcStrBuildFilename (sysroot, *p, NULL); 27217872e0a1Smrg else 27227872e0a1Smrg s = *p; 27237872e0a1Smrg file = FcConfigFileExists (s, url); 27247872e0a1Smrg if (sysroot) 27257872e0a1Smrg FcStrFree (s); 27267872e0a1Smrg if (file) 27277872e0a1Smrg break; 27287872e0a1Smrg } 27297872e0a1Smrg FcConfigFreePath (path); 27301887081fSmrg } 27317872e0a1Smrgbail: 27327872e0a1Smrg FcConfigDestroy (config); 27337872e0a1Smrg 27341887081fSmrg return file; 27351887081fSmrg} 27361887081fSmrg 27377872e0a1SmrgFcChar8 * 27387872e0a1SmrgFcConfigFilename (const FcChar8 *url) 27397872e0a1Smrg{ 27407872e0a1Smrg return FcConfigGetFilename (NULL, url); 27417872e0a1Smrg} 27427872e0a1Smrg 27431887081fSmrgFcChar8 * 27441887081fSmrgFcConfigRealFilename (FcConfig *config, 27451887081fSmrg const FcChar8 *url) 27461887081fSmrg{ 27477872e0a1Smrg FcChar8 *n = FcConfigGetFilename (config, url); 27481887081fSmrg 27491887081fSmrg if (n) 27501887081fSmrg { 27517872e0a1Smrg FcChar8 buf[FC_PATH_MAX]; 27521887081fSmrg ssize_t len; 27537872e0a1Smrg struct stat sb; 27541887081fSmrg 27557872e0a1Smrg if ((len = FcReadLink (n, buf, sizeof (buf) - 1)) != -1) 27562c393a42Smrg { 27571887081fSmrg buf[len] = 0; 27581887081fSmrg 27597872e0a1Smrg /* We try to pick up a config from FONTCONFIG_FILE 27607872e0a1Smrg * when url is null. don't try to address the real filename 27617872e0a1Smrg * if it is a named pipe. 27627872e0a1Smrg */ 27637872e0a1Smrg if (!url && FcStat (n, &sb) == 0 && S_ISFIFO (sb.st_mode)) 27647872e0a1Smrg return n; 27657872e0a1Smrg else if (!FcStrIsAbsoluteFilename (buf)) 27661887081fSmrg { 27677872e0a1Smrg FcChar8 *dirname = FcStrDirname (n); 27687872e0a1Smrg FcStrFree (n); 27691887081fSmrg if (!dirname) 27701887081fSmrg return NULL; 27711887081fSmrg 27721887081fSmrg FcChar8 *path = FcStrBuildFilename (dirname, buf, NULL); 27731887081fSmrg FcStrFree (dirname); 27741887081fSmrg if (!path) 27751887081fSmrg return NULL; 27761887081fSmrg 27777872e0a1Smrg n = FcStrCanonFilename (path); 27781887081fSmrg FcStrFree (path); 27791887081fSmrg } 27801887081fSmrg else 27811887081fSmrg { 27827872e0a1Smrg FcStrFree (n); 27837872e0a1Smrg n = FcStrdup (buf); 27841887081fSmrg } 27852c393a42Smrg } 27862c393a42Smrg } 2787ca08ab68Smrg 27887872e0a1Smrg return n; 27892c393a42Smrg} 27902c393a42Smrg 27912c393a42Smrg/* 27922c393a42Smrg * Manage the application-specific fonts 27932c393a42Smrg */ 27942c393a42Smrg 27952c393a42SmrgFcBool 27962c393a42SmrgFcConfigAppFontAddFile (FcConfig *config, 27972c393a42Smrg const FcChar8 *file) 27982c393a42Smrg{ 27992c393a42Smrg FcFontSet *set; 28002c393a42Smrg FcStrSet *subdirs; 28012c393a42Smrg FcStrList *sublist; 28022c393a42Smrg FcChar8 *subdir; 28037872e0a1Smrg FcBool ret = FcTrue; 28042c393a42Smrg 28057872e0a1Smrg config = FcConfigReference (config); 28062c393a42Smrg if (!config) 28077872e0a1Smrg return FcFalse; 28082c393a42Smrg 280918bd4a06Smrg subdirs = FcStrSetCreateEx (FCSS_GROW_BY_64); 28102c393a42Smrg if (!subdirs) 28117872e0a1Smrg { 28127872e0a1Smrg ret = FcFalse; 28137872e0a1Smrg goto bail; 28147872e0a1Smrg } 2815ca08ab68Smrg 28162c393a42Smrg set = FcConfigGetFonts (config, FcSetApplication); 28172c393a42Smrg if (!set) 28182c393a42Smrg { 28192c393a42Smrg set = FcFontSetCreate (); 28202c393a42Smrg if (!set) 28212c393a42Smrg { 28222c393a42Smrg FcStrSetDestroy (subdirs); 28237872e0a1Smrg ret = FcFalse; 28247872e0a1Smrg goto bail; 28252c393a42Smrg } 28262c393a42Smrg FcConfigSetFonts (config, set, FcSetApplication); 28272c393a42Smrg } 282846bb3e47Smrg 28291887081fSmrg if (!FcFileScanConfig (set, subdirs, file, config)) 28302c393a42Smrg { 28312c393a42Smrg FcStrSetDestroy (subdirs); 28327872e0a1Smrg ret = FcFalse; 28337872e0a1Smrg goto bail; 28342c393a42Smrg } 28352c393a42Smrg if ((sublist = FcStrListCreate (subdirs))) 28362c393a42Smrg { 28372c393a42Smrg while ((subdir = FcStrListNext (sublist))) 28382c393a42Smrg { 28392c393a42Smrg FcConfigAppFontAddDir (config, subdir); 28402c393a42Smrg } 28412c393a42Smrg FcStrListDone (sublist); 28422c393a42Smrg } 28432c393a42Smrg FcStrSetDestroy (subdirs); 28447872e0a1Smrgbail: 28457872e0a1Smrg FcConfigDestroy (config); 28467872e0a1Smrg 28477872e0a1Smrg return ret; 28482c393a42Smrg} 28492c393a42Smrg 28502c393a42SmrgFcBool 28512c393a42SmrgFcConfigAppFontAddDir (FcConfig *config, 28522c393a42Smrg const FcChar8 *dir) 28532c393a42Smrg{ 28542c393a42Smrg FcFontSet *set; 28552c393a42Smrg FcStrSet *dirs; 28567872e0a1Smrg FcBool ret = FcTrue; 2857ca08ab68Smrg 28587872e0a1Smrg config = FcConfigReference (config); 28592c393a42Smrg if (!config) 28607872e0a1Smrg return FcFalse; 28612c393a42Smrg 286218bd4a06Smrg dirs = FcStrSetCreateEx (FCSS_GROW_BY_64); 28632c393a42Smrg if (!dirs) 28647872e0a1Smrg { 28657872e0a1Smrg ret = FcFalse; 28667872e0a1Smrg goto bail; 28677872e0a1Smrg } 2868ca08ab68Smrg 28692c393a42Smrg set = FcConfigGetFonts (config, FcSetApplication); 28702c393a42Smrg if (!set) 28712c393a42Smrg { 28722c393a42Smrg set = FcFontSetCreate (); 28732c393a42Smrg if (!set) 28742c393a42Smrg { 28752c393a42Smrg FcStrSetDestroy (dirs); 28767872e0a1Smrg ret = FcFalse; 28777872e0a1Smrg goto bail; 28782c393a42Smrg } 28792c393a42Smrg FcConfigSetFonts (config, set, FcSetApplication); 28802c393a42Smrg } 2881ca08ab68Smrg 28822c393a42Smrg FcStrSetAddFilename (dirs, dir); 2883ca08ab68Smrg 28842c393a42Smrg if (!FcConfigAddDirList (config, FcSetApplication, dirs)) 28852c393a42Smrg { 28862c393a42Smrg FcStrSetDestroy (dirs); 28877872e0a1Smrg ret = FcFalse; 28887872e0a1Smrg goto bail; 28892c393a42Smrg } 28902c393a42Smrg FcStrSetDestroy (dirs); 28917872e0a1Smrgbail: 28927872e0a1Smrg FcConfigDestroy (config); 28937872e0a1Smrg 28947872e0a1Smrg return ret; 28952c393a42Smrg} 28962c393a42Smrg 28972c393a42Smrgvoid 28982c393a42SmrgFcConfigAppFontClear (FcConfig *config) 28992c393a42Smrg{ 29007872e0a1Smrg config = FcConfigReference (config); 29012c393a42Smrg if (!config) 29027872e0a1Smrg return; 29032c393a42Smrg 29042c393a42Smrg FcConfigSetFonts (config, 0, FcSetApplication); 29057872e0a1Smrg 29067872e0a1Smrg FcConfigDestroy (config); 29072c393a42Smrg} 29082c393a42Smrg 29092c393a42Smrg/* 29102c393a42Smrg * Manage filename-based font source selectors 29112c393a42Smrg */ 29122c393a42Smrg 29132c393a42SmrgFcBool 29142c393a42SmrgFcConfigGlobAdd (FcConfig *config, 29152c393a42Smrg const FcChar8 *glob, 29162c393a42Smrg FcBool accept) 29172c393a42Smrg{ 29182c393a42Smrg FcStrSet *set = accept ? config->acceptGlobs : config->rejectGlobs; 291946bb3e47Smrg FcChar8 *realglob = FcStrCopyFilename(glob); 292046bb3e47Smrg if (!realglob) 292146bb3e47Smrg return FcFalse; 29222c393a42Smrg 292346bb3e47Smrg FcBool ret = FcStrSetAdd (set, realglob); 292446bb3e47Smrg FcStrFree(realglob); 292546bb3e47Smrg return ret; 29262c393a42Smrg} 29272c393a42Smrg 29282c393a42Smrgstatic FcBool 29292c393a42SmrgFcConfigGlobsMatch (const FcStrSet *globs, 29302c393a42Smrg const FcChar8 *string) 29312c393a42Smrg{ 29322c393a42Smrg int i; 29332c393a42Smrg 29342c393a42Smrg for (i = 0; i < globs->num; i++) 2935c9710b42Smrg if (FcStrGlobMatch (globs->strs[i], string)) 29362c393a42Smrg return FcTrue; 29372c393a42Smrg return FcFalse; 29382c393a42Smrg} 29392c393a42Smrg 29402c393a42SmrgFcBool 29412c393a42SmrgFcConfigAcceptFilename (FcConfig *config, 29422c393a42Smrg const FcChar8 *filename) 29432c393a42Smrg{ 29442c393a42Smrg if (FcConfigGlobsMatch (config->acceptGlobs, filename)) 29452c393a42Smrg return FcTrue; 29462c393a42Smrg if (FcConfigGlobsMatch (config->rejectGlobs, filename)) 29472c393a42Smrg return FcFalse; 29482c393a42Smrg return FcTrue; 29492c393a42Smrg} 29502c393a42Smrg 29512c393a42Smrg/* 29522c393a42Smrg * Manage font-pattern based font source selectors 29532c393a42Smrg */ 29542c393a42Smrg 29552c393a42SmrgFcBool 29562c393a42SmrgFcConfigPatternsAdd (FcConfig *config, 29572c393a42Smrg FcPattern *pattern, 29582c393a42Smrg FcBool accept) 29592c393a42Smrg{ 29602c393a42Smrg FcFontSet *set = accept ? config->acceptPatterns : config->rejectPatterns; 29612c393a42Smrg 29622c393a42Smrg return FcFontSetAdd (set, pattern); 29632c393a42Smrg} 29642c393a42Smrg 29652c393a42Smrgstatic FcBool 29662c393a42SmrgFcConfigPatternsMatch (const FcFontSet *patterns, 29672c393a42Smrg const FcPattern *font) 29682c393a42Smrg{ 29692c393a42Smrg int i; 2970ca08ab68Smrg 29712c393a42Smrg for (i = 0; i < patterns->nfont; i++) 29722c393a42Smrg if (FcListPatternMatchAny (patterns->fonts[i], font)) 29732c393a42Smrg return FcTrue; 29742c393a42Smrg return FcFalse; 29752c393a42Smrg} 29762c393a42Smrg 29772c393a42SmrgFcBool 29782c393a42SmrgFcConfigAcceptFont (FcConfig *config, 29792c393a42Smrg const FcPattern *font) 29802c393a42Smrg{ 29812c393a42Smrg if (FcConfigPatternsMatch (config->acceptPatterns, font)) 29822c393a42Smrg return FcTrue; 29832c393a42Smrg if (FcConfigPatternsMatch (config->rejectPatterns, font)) 29842c393a42Smrg return FcFalse; 29852c393a42Smrg return FcTrue; 29862c393a42Smrg} 2987c9710b42Smrg 2988c9710b42Smrgconst FcChar8 * 2989c9710b42SmrgFcConfigGetSysRoot (const FcConfig *config) 2990c9710b42Smrg{ 2991c9710b42Smrg if (!config) 2992c9710b42Smrg { 2993c9710b42Smrg config = FcConfigGetCurrent (); 2994c9710b42Smrg if (!config) 2995c9710b42Smrg return NULL; 2996c9710b42Smrg } 29977872e0a1Smrg return config->sysRoot; 2998c9710b42Smrg} 2999c9710b42Smrg 3000c9710b42Smrgvoid 3001c9710b42SmrgFcConfigSetSysRoot (FcConfig *config, 3002c9710b42Smrg const FcChar8 *sysroot) 3003c9710b42Smrg{ 300418bd4a06Smrg FcChar8 *s = NULL; 3005c9710b42Smrg FcBool init = FcFalse; 30067872e0a1Smrg int nretry = 3; 3007c9710b42Smrg 30087872e0a1Smrgretry: 3009c9710b42Smrg if (!config) 3010c9710b42Smrg { 3011c9710b42Smrg /* We can't use FcConfigGetCurrent() here to ensure 3012c9710b42Smrg * the sysroot is set prior to initialize FcConfig, 3013c9710b42Smrg * to avoid loading caches from non-sysroot dirs. 3014c9710b42Smrg * So postpone the initialization later. 3015c9710b42Smrg */ 3016c9710b42Smrg config = fc_atomic_ptr_get (&_fcConfig); 3017c9710b42Smrg if (!config) 3018c9710b42Smrg { 3019c9710b42Smrg config = FcConfigCreate (); 3020c9710b42Smrg if (!config) 3021c9710b42Smrg return; 3022c9710b42Smrg init = FcTrue; 3023c9710b42Smrg } 3024c9710b42Smrg } 3025c9710b42Smrg 302618bd4a06Smrg if (sysroot) 302718bd4a06Smrg { 30287872e0a1Smrg s = FcStrRealPath (sysroot); 302918bd4a06Smrg if (!s) 303018bd4a06Smrg return; 303118bd4a06Smrg } 3032c9710b42Smrg 3033c9710b42Smrg if (config->sysRoot) 3034c9710b42Smrg FcStrFree (config->sysRoot); 3035c9710b42Smrg 3036c9710b42Smrg config->sysRoot = s; 3037c9710b42Smrg if (init) 3038c9710b42Smrg { 3039c9710b42Smrg config = FcInitLoadOwnConfigAndFonts (config); 30407872e0a1Smrg if (!config) 30417872e0a1Smrg { 30427872e0a1Smrg /* Something failed. this is usually unlikely. so retrying */ 30437872e0a1Smrg init = FcFalse; 30447872e0a1Smrg if (--nretry == 0) 30457872e0a1Smrg { 30467872e0a1Smrg fprintf (stderr, "Fontconfig warning: Unable to initialize config and retry limit exceeded. sysroot functionality may not work as expected.\n"); 30477872e0a1Smrg return; 30487872e0a1Smrg } 30497872e0a1Smrg goto retry; 30507872e0a1Smrg } 3051c9710b42Smrg FcConfigSetCurrent (config); 305218bd4a06Smrg /* FcConfigSetCurrent() increases the refcount. 305318bd4a06Smrg * decrease it here to avoid the memory leak. 305418bd4a06Smrg */ 305518bd4a06Smrg FcConfigDestroy (config); 3056c9710b42Smrg } 3057c9710b42Smrg} 3058c9710b42Smrg 30591887081fSmrgFcRuleSet * 30601887081fSmrgFcRuleSetCreate (const FcChar8 *name) 30611887081fSmrg{ 30621887081fSmrg FcRuleSet *ret = (FcRuleSet *) malloc (sizeof (FcRuleSet)); 30631887081fSmrg FcMatchKind k; 30641887081fSmrg const FcChar8 *p; 30651887081fSmrg 30661887081fSmrg if (!name) 30671887081fSmrg p = (const FcChar8 *)""; 30681887081fSmrg else 30691887081fSmrg p = name; 30701887081fSmrg 30711887081fSmrg if (ret) 30721887081fSmrg { 30731887081fSmrg ret->name = FcStrdup (p); 30741887081fSmrg ret->description = NULL; 30751887081fSmrg ret->domain = NULL; 30761887081fSmrg for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++) 30771887081fSmrg ret->subst[k] = FcPtrListCreate (FcDestroyAsRule); 30781887081fSmrg FcRefInit (&ret->ref, 1); 30791887081fSmrg } 30801887081fSmrg 30811887081fSmrg return ret; 30821887081fSmrg} 30831887081fSmrg 30841887081fSmrgvoid 30851887081fSmrgFcRuleSetDestroy (FcRuleSet *rs) 30861887081fSmrg{ 30871887081fSmrg FcMatchKind k; 30881887081fSmrg 30891887081fSmrg if (!rs) 30901887081fSmrg return; 30911887081fSmrg if (FcRefDec (&rs->ref) != 1) 30921887081fSmrg return; 30931887081fSmrg 30941887081fSmrg if (rs->name) 30951887081fSmrg FcStrFree (rs->name); 30961887081fSmrg if (rs->description) 30971887081fSmrg FcStrFree (rs->description); 30981887081fSmrg if (rs->domain) 30991887081fSmrg FcStrFree (rs->domain); 31001887081fSmrg for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++) 31011887081fSmrg FcPtrListDestroy (rs->subst[k]); 31021887081fSmrg 31031887081fSmrg free (rs); 31041887081fSmrg} 31051887081fSmrg 31061887081fSmrgvoid 31071887081fSmrgFcRuleSetReference (FcRuleSet *rs) 31081887081fSmrg{ 31091887081fSmrg if (!FcRefIsConst (&rs->ref)) 31101887081fSmrg FcRefInc (&rs->ref); 31111887081fSmrg} 31121887081fSmrg 31131887081fSmrgvoid 31141887081fSmrgFcRuleSetEnable (FcRuleSet *rs, 31151887081fSmrg FcBool flag) 31161887081fSmrg{ 31171887081fSmrg if (rs) 31181887081fSmrg { 31191887081fSmrg rs->enabled = flag; 31201887081fSmrg /* XXX: we may want to provide a feature 31211887081fSmrg * to enable/disable rulesets through API 31221887081fSmrg * in the future? 31231887081fSmrg */ 31241887081fSmrg } 31251887081fSmrg} 31261887081fSmrg 31271887081fSmrgvoid 31281887081fSmrgFcRuleSetAddDescription (FcRuleSet *rs, 31291887081fSmrg const FcChar8 *domain, 31301887081fSmrg const FcChar8 *description) 31311887081fSmrg{ 31321887081fSmrg if (rs->domain) 31331887081fSmrg FcStrFree (rs->domain); 31341887081fSmrg if (rs->description) 31351887081fSmrg FcStrFree (rs->description); 31361887081fSmrg 31371887081fSmrg rs->domain = domain ? FcStrdup (domain) : NULL; 31381887081fSmrg rs->description = description ? FcStrdup (description) : NULL; 31391887081fSmrg} 31401887081fSmrg 31411887081fSmrgint 31421887081fSmrgFcRuleSetAdd (FcRuleSet *rs, 31431887081fSmrg FcRule *rule, 31441887081fSmrg FcMatchKind kind) 31451887081fSmrg{ 31461887081fSmrg FcPtrListIter iter; 31471887081fSmrg FcRule *r; 31481887081fSmrg int n = 0, ret; 31491887081fSmrg 31501887081fSmrg if (!rs || 31511887081fSmrg kind < FcMatchKindBegin || kind >= FcMatchKindEnd) 31521887081fSmrg return -1; 31531887081fSmrg FcPtrListIterInitAtLast (rs->subst[kind], &iter); 31541887081fSmrg if (!FcPtrListIterAdd (rs->subst[kind], &iter, rule)) 31551887081fSmrg return -1; 31561887081fSmrg 31571887081fSmrg for (r = rule; r; r = r->next) 31581887081fSmrg { 31591887081fSmrg switch (r->type) 31601887081fSmrg { 31611887081fSmrg case FcRuleTest: 31621887081fSmrg if (r->u.test) 31631887081fSmrg { 31641887081fSmrg if (r->u.test->kind == FcMatchDefault) 31651887081fSmrg r->u.test->kind = kind; 31661887081fSmrg if (n < r->u.test->object) 31671887081fSmrg n = r->u.test->object; 31681887081fSmrg } 31691887081fSmrg break; 31701887081fSmrg case FcRuleEdit: 31711887081fSmrg if (n < r->u.edit->object) 31721887081fSmrg n = r->u.edit->object; 31731887081fSmrg break; 31741887081fSmrg default: 31751887081fSmrg break; 31761887081fSmrg } 31771887081fSmrg } 31781887081fSmrg if (FcDebug () & FC_DBG_EDIT) 31791887081fSmrg { 31801887081fSmrg printf ("Add Rule(kind:%d, name: %s) ", kind, rs->name); 31811887081fSmrg FcRulePrint (rule); 31821887081fSmrg } 31831887081fSmrg ret = FC_OBJ_ID (n) - FC_MAX_BASE_OBJECT; 31841887081fSmrg 31851887081fSmrg return ret < 0 ? 0 : ret; 31861887081fSmrg} 31871887081fSmrg 31881887081fSmrgvoid 31891887081fSmrgFcConfigFileInfoIterInit (FcConfig *config, 31901887081fSmrg FcConfigFileInfoIter *iter) 31911887081fSmrg{ 31921887081fSmrg FcConfig *c; 31931887081fSmrg FcPtrListIter *i = (FcPtrListIter *)iter; 31941887081fSmrg 31951887081fSmrg if (!config) 31961887081fSmrg c = FcConfigGetCurrent (); 31971887081fSmrg else 31981887081fSmrg c = config; 31991887081fSmrg FcPtrListIterInit (c->rulesetList, i); 32001887081fSmrg} 32011887081fSmrg 32021887081fSmrgFcBool 32031887081fSmrgFcConfigFileInfoIterNext (FcConfig *config, 32041887081fSmrg FcConfigFileInfoIter *iter) 32051887081fSmrg{ 32061887081fSmrg FcConfig *c; 32071887081fSmrg FcPtrListIter *i = (FcPtrListIter *)iter; 32081887081fSmrg 32091887081fSmrg if (!config) 32101887081fSmrg c = FcConfigGetCurrent (); 32111887081fSmrg else 32121887081fSmrg c = config; 32131887081fSmrg if (FcPtrListIterIsValid (c->rulesetList, i)) 32141887081fSmrg { 32151887081fSmrg FcPtrListIterNext (c->rulesetList, i); 32161887081fSmrg } 32171887081fSmrg else 32181887081fSmrg return FcFalse; 32191887081fSmrg 32201887081fSmrg return FcTrue; 32211887081fSmrg} 32221887081fSmrg 32231887081fSmrgFcBool 32241887081fSmrgFcConfigFileInfoIterGet (FcConfig *config, 32251887081fSmrg FcConfigFileInfoIter *iter, 32261887081fSmrg FcChar8 **name, 32271887081fSmrg FcChar8 **description, 32281887081fSmrg FcBool *enabled) 32291887081fSmrg{ 32301887081fSmrg FcConfig *c; 32311887081fSmrg FcRuleSet *r; 32321887081fSmrg FcPtrListIter *i = (FcPtrListIter *)iter; 32331887081fSmrg 32341887081fSmrg if (!config) 32351887081fSmrg c = FcConfigGetCurrent (); 32361887081fSmrg else 32371887081fSmrg c = config; 32381887081fSmrg if (!FcPtrListIterIsValid (c->rulesetList, i)) 32391887081fSmrg return FcFalse; 32401887081fSmrg r = FcPtrListIterGetValue (c->rulesetList, i); 32411887081fSmrg if (name) 32421887081fSmrg *name = FcStrdup (r->name && r->name[0] ? r->name : (const FcChar8 *) "fonts.conf"); 32431887081fSmrg if (description) 32441887081fSmrg *description = FcStrdup (!r->description ? _("No description") : 32451887081fSmrg dgettext (r->domain ? (const char *) r->domain : GETTEXT_PACKAGE "-conf", 32461887081fSmrg (const char *) r->description)); 32471887081fSmrg if (enabled) 32481887081fSmrg *enabled = r->enabled; 32491887081fSmrg 32501887081fSmrg return FcTrue; 32511887081fSmrg} 32521887081fSmrg 32532c393a42Smrg#define __fccfg__ 32542c393a42Smrg#include "fcaliastail.h" 32552c393a42Smrg#undef __fccfg__ 3256