fccfg.c revision cc1bebd6
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" 282c393a42Smrg#include <dirent.h> 292c393a42Smrg#include <sys/types.h> 302c393a42Smrg 312c393a42Smrg#if defined (_WIN32) && !defined (R_OK) 322c393a42Smrg#define R_OK 4 332c393a42Smrg#endif 342c393a42Smrg 35c9710b42Smrgstatic FcConfig *_fcConfig; /* MT-safe */ 36c9710b42Smrg 37c9710b42Smrgstatic FcConfig * 38c9710b42SmrgFcConfigEnsure (void) 39c9710b42Smrg{ 40c9710b42Smrg FcConfig *config; 41c9710b42Smrgretry: 42c9710b42Smrg config = fc_atomic_ptr_get (&_fcConfig); 43c9710b42Smrg if (!config) 44c9710b42Smrg { 45c9710b42Smrg config = FcInitLoadConfigAndFonts (); 46c9710b42Smrg 47c9710b42Smrg if (!fc_atomic_ptr_cmpexch (&_fcConfig, NULL, config)) { 48c9710b42Smrg FcConfigDestroy (config); 49c9710b42Smrg goto retry; 50c9710b42Smrg } 51c9710b42Smrg } 52c9710b42Smrg return config; 53c9710b42Smrg} 54c9710b42Smrg 55c9710b42SmrgFcBool 56c9710b42SmrgFcConfigInit (void) 57c9710b42Smrg{ 58c9710b42Smrg return FcConfigEnsure () ? FcTrue : FcFalse; 59c9710b42Smrg} 60c9710b42Smrg 61c9710b42Smrgvoid 62c9710b42SmrgFcConfigFini (void) 63c9710b42Smrg{ 64c9710b42Smrg FcConfig *cfg = fc_atomic_ptr_get (&_fcConfig); 65c9710b42Smrg if (cfg && fc_atomic_ptr_cmpexch (&_fcConfig, cfg, NULL)) 66c9710b42Smrg FcConfigDestroy (cfg); 67c9710b42Smrg} 68c9710b42Smrg 692c393a42Smrg 702c393a42SmrgFcConfig * 712c393a42SmrgFcConfigCreate (void) 722c393a42Smrg{ 732c393a42Smrg FcSetName set; 742c393a42Smrg FcConfig *config; 752c393a42Smrg 762c393a42Smrg config = malloc (sizeof (FcConfig)); 772c393a42Smrg if (!config) 782c393a42Smrg goto bail0; 79ca08ab68Smrg 802c393a42Smrg config->configDirs = FcStrSetCreate (); 812c393a42Smrg if (!config->configDirs) 822c393a42Smrg goto bail1; 83ca08ab68Smrg 842c393a42Smrg config->configFiles = FcStrSetCreate (); 852c393a42Smrg if (!config->configFiles) 862c393a42Smrg goto bail2; 87ca08ab68Smrg 882c393a42Smrg config->fontDirs = FcStrSetCreate (); 892c393a42Smrg if (!config->fontDirs) 902c393a42Smrg goto bail3; 91ca08ab68Smrg 922c393a42Smrg config->acceptGlobs = FcStrSetCreate (); 932c393a42Smrg if (!config->acceptGlobs) 942c393a42Smrg goto bail4; 952c393a42Smrg 962c393a42Smrg config->rejectGlobs = FcStrSetCreate (); 972c393a42Smrg if (!config->rejectGlobs) 982c393a42Smrg goto bail5; 992c393a42Smrg 1002c393a42Smrg config->acceptPatterns = FcFontSetCreate (); 1012c393a42Smrg if (!config->acceptPatterns) 1022c393a42Smrg goto bail6; 103ca08ab68Smrg 1042c393a42Smrg config->rejectPatterns = FcFontSetCreate (); 1052c393a42Smrg if (!config->rejectPatterns) 1062c393a42Smrg goto bail7; 1072c393a42Smrg 1082c393a42Smrg config->cacheDirs = FcStrSetCreate (); 1092c393a42Smrg if (!config->cacheDirs) 1102c393a42Smrg goto bail8; 111ca08ab68Smrg 1122c393a42Smrg config->blanks = 0; 1132c393a42Smrg 1142c393a42Smrg config->substPattern = 0; 1152c393a42Smrg config->substFont = 0; 1162c393a42Smrg config->substScan = 0; 1172c393a42Smrg config->maxObjects = 0; 1182c393a42Smrg for (set = FcSetSystem; set <= FcSetApplication; set++) 1192c393a42Smrg config->fonts[set] = 0; 1202c393a42Smrg 1212c393a42Smrg config->rescanTime = time(0); 122ca08ab68Smrg config->rescanInterval = 30; 123a6844aabSmrg 124a6844aabSmrg config->expr_pool = NULL; 125a6844aabSmrg 126c9710b42Smrg config->sysRoot = NULL; 127c9710b42Smrg 128c9710b42Smrg FcRefInit (&config->ref, 1); 129ca08ab68Smrg 1302c393a42Smrg return config; 1312c393a42Smrg 1322c393a42Smrgbail8: 1332c393a42Smrg FcFontSetDestroy (config->rejectPatterns); 1342c393a42Smrgbail7: 1352c393a42Smrg FcFontSetDestroy (config->acceptPatterns); 1362c393a42Smrgbail6: 1372c393a42Smrg FcStrSetDestroy (config->rejectGlobs); 1382c393a42Smrgbail5: 1392c393a42Smrg FcStrSetDestroy (config->acceptGlobs); 1402c393a42Smrgbail4: 1412c393a42Smrg FcStrSetDestroy (config->fontDirs); 1422c393a42Smrgbail3: 1432c393a42Smrg FcStrSetDestroy (config->configFiles); 1442c393a42Smrgbail2: 1452c393a42Smrg FcStrSetDestroy (config->configDirs); 1462c393a42Smrgbail1: 1472c393a42Smrg free (config); 1482c393a42Smrgbail0: 1492c393a42Smrg return 0; 1502c393a42Smrg} 1512c393a42Smrg 1522c393a42Smrgstatic FcFileTime 1532c393a42SmrgFcConfigNewestFile (FcStrSet *files) 1542c393a42Smrg{ 1552c393a42Smrg FcStrList *list = FcStrListCreate (files); 1562c393a42Smrg FcFileTime newest = { 0, FcFalse }; 1572c393a42Smrg FcChar8 *file; 1582c393a42Smrg struct stat statb; 1592c393a42Smrg 1602c393a42Smrg if (list) 1612c393a42Smrg { 1622c393a42Smrg while ((file = FcStrListNext (list))) 163ca08ab68Smrg if (FcStat (file, &statb) == 0) 1642c393a42Smrg if (!newest.set || statb.st_mtime - newest.time > 0) 1652c393a42Smrg { 1662c393a42Smrg newest.set = FcTrue; 1672c393a42Smrg newest.time = statb.st_mtime; 1682c393a42Smrg } 1692c393a42Smrg FcStrListDone (list); 1702c393a42Smrg } 1712c393a42Smrg return newest; 1722c393a42Smrg} 1732c393a42Smrg 1742c393a42SmrgFcBool 1752c393a42SmrgFcConfigUptoDate (FcConfig *config) 1762c393a42Smrg{ 1772c393a42Smrg FcFileTime config_time, config_dir_time, font_time; 1782c393a42Smrg time_t now = time(0); 1792c393a42Smrg if (!config) 1802c393a42Smrg { 1812c393a42Smrg config = FcConfigGetCurrent (); 1822c393a42Smrg if (!config) 1832c393a42Smrg return FcFalse; 1842c393a42Smrg } 1852c393a42Smrg config_time = FcConfigNewestFile (config->configFiles); 1862c393a42Smrg config_dir_time = FcConfigNewestFile (config->configDirs); 1872c393a42Smrg font_time = FcConfigNewestFile (config->fontDirs); 1882c393a42Smrg if ((config_time.set && config_time.time - config->rescanTime > 0) || 1892c393a42Smrg (config_dir_time.set && (config_dir_time.time - config->rescanTime) > 0) || 1902c393a42Smrg (font_time.set && (font_time.time - config->rescanTime) > 0)) 1912c393a42Smrg { 1922c393a42Smrg /* We need to check for potential clock problems here (OLPC ticket #6046) */ 1932c393a42Smrg if ((config_time.set && (config_time.time - now) > 0) || 1942c393a42Smrg (config_dir_time.set && (config_dir_time.time - now) > 0) || 1952c393a42Smrg (font_time.set && (font_time.time - now) > 0)) 1962c393a42Smrg { 1972c393a42Smrg fprintf (stderr, 198c9710b42Smrg "Fontconfig warning: Directory/file mtime in the future. New fonts may not be detected.\n"); 1992c393a42Smrg config->rescanTime = now; 2002c393a42Smrg return FcTrue; 2012c393a42Smrg } 2022c393a42Smrg else 2032c393a42Smrg return FcFalse; 2042c393a42Smrg } 2052c393a42Smrg config->rescanTime = now; 2062c393a42Smrg return FcTrue; 2072c393a42Smrg} 2082c393a42Smrg 2092c393a42Smrgstatic void 2102c393a42SmrgFcSubstDestroy (FcSubst *s) 2112c393a42Smrg{ 2122c393a42Smrg FcSubst *n; 213ca08ab68Smrg 2142c393a42Smrg while (s) 2152c393a42Smrg { 2162c393a42Smrg n = s->next; 2176fc018e4Smrg if (s->rule) 2186fc018e4Smrg FcRuleDestroy (s->rule); 2192c393a42Smrg free (s); 2202c393a42Smrg s = n; 2212c393a42Smrg } 2222c393a42Smrg} 2232c393a42Smrg 224a6844aabSmrgFcExpr * 225a6844aabSmrgFcConfigAllocExpr (FcConfig *config) 226a6844aabSmrg{ 2276fc018e4Smrg if (!config->expr_pool || config->expr_pool->next == config->expr_pool->end) 2286fc018e4Smrg { 2296fc018e4Smrg FcExprPage *new_page; 230a6844aabSmrg 2316fc018e4Smrg new_page = malloc (sizeof (FcExprPage)); 2326fc018e4Smrg if (!new_page) 2336fc018e4Smrg return 0; 234a6844aabSmrg 2356fc018e4Smrg new_page->next_page = config->expr_pool; 2366fc018e4Smrg new_page->next = new_page->exprs; 2376fc018e4Smrg config->expr_pool = new_page; 2386fc018e4Smrg } 239a6844aabSmrg 2406fc018e4Smrg return config->expr_pool->next++; 241a6844aabSmrg} 242a6844aabSmrg 243a6844aabSmrgFcConfig * 244a6844aabSmrgFcConfigReference (FcConfig *config) 245a6844aabSmrg{ 246a6844aabSmrg if (!config) 247a6844aabSmrg { 248a6844aabSmrg config = FcConfigGetCurrent (); 249a6844aabSmrg if (!config) 250a6844aabSmrg return 0; 251a6844aabSmrg } 252a6844aabSmrg 253c9710b42Smrg FcRefInc (&config->ref); 254a6844aabSmrg 255a6844aabSmrg return config; 256a6844aabSmrg} 257a6844aabSmrg 2582c393a42Smrgvoid 2592c393a42SmrgFcConfigDestroy (FcConfig *config) 2602c393a42Smrg{ 2612c393a42Smrg FcSetName set; 262a6844aabSmrg FcExprPage *page; 263a6844aabSmrg 264c9710b42Smrg if (FcRefDec (&config->ref) != 1) 265a6844aabSmrg return; 2662c393a42Smrg 267c9710b42Smrg (void) fc_atomic_ptr_cmpexch (&_fcConfig, config, NULL); 2682c393a42Smrg 2692c393a42Smrg FcStrSetDestroy (config->configDirs); 2702c393a42Smrg FcStrSetDestroy (config->fontDirs); 2712c393a42Smrg FcStrSetDestroy (config->cacheDirs); 2722c393a42Smrg FcStrSetDestroy (config->configFiles); 2732c393a42Smrg FcStrSetDestroy (config->acceptGlobs); 2742c393a42Smrg FcStrSetDestroy (config->rejectGlobs); 2752c393a42Smrg FcFontSetDestroy (config->acceptPatterns); 2762c393a42Smrg FcFontSetDestroy (config->rejectPatterns); 2772c393a42Smrg 2782c393a42Smrg if (config->blanks) 2792c393a42Smrg FcBlanksDestroy (config->blanks); 2802c393a42Smrg 2812c393a42Smrg FcSubstDestroy (config->substPattern); 2822c393a42Smrg FcSubstDestroy (config->substFont); 2832c393a42Smrg FcSubstDestroy (config->substScan); 2842c393a42Smrg for (set = FcSetSystem; set <= FcSetApplication; set++) 2852c393a42Smrg if (config->fonts[set]) 2862c393a42Smrg FcFontSetDestroy (config->fonts[set]); 2872c393a42Smrg 288a6844aabSmrg page = config->expr_pool; 289a6844aabSmrg while (page) 290a6844aabSmrg { 291a6844aabSmrg FcExprPage *next = page->next_page; 292a6844aabSmrg free (page); 293a6844aabSmrg page = next; 294a6844aabSmrg } 295c9710b42Smrg if (config->sysRoot) 296c9710b42Smrg FcStrFree (config->sysRoot); 297a6844aabSmrg 2982c393a42Smrg free (config); 2992c393a42Smrg} 3002c393a42Smrg 3012c393a42Smrg/* 3022c393a42Smrg * Add cache to configuration, adding fonts and directories 3032c393a42Smrg */ 3042c393a42Smrg 3052c393a42SmrgFcBool 306ca08ab68SmrgFcConfigAddCache (FcConfig *config, FcCache *cache, 3072c393a42Smrg FcSetName set, FcStrSet *dirSet) 3082c393a42Smrg{ 3092c393a42Smrg FcFontSet *fs; 3102c393a42Smrg intptr_t *dirs; 3112c393a42Smrg int i; 3122c393a42Smrg 3132c393a42Smrg /* 3142c393a42Smrg * Add fonts 3152c393a42Smrg */ 3162c393a42Smrg fs = FcCacheSet (cache); 3172c393a42Smrg if (fs) 3182c393a42Smrg { 3192c393a42Smrg int nref = 0; 3202c393a42Smrg 3212c393a42Smrg for (i = 0; i < fs->nfont; i++) 3222c393a42Smrg { 3232c393a42Smrg FcPattern *font = FcFontSetFont (fs, i); 3242c393a42Smrg FcChar8 *font_file; 3252c393a42Smrg 3262c393a42Smrg /* 3272c393a42Smrg * Check to see if font is banned by filename 3282c393a42Smrg */ 3292c393a42Smrg if (FcPatternObjectGetString (font, FC_FILE_OBJECT, 3302c393a42Smrg 0, &font_file) == FcResultMatch && 3312c393a42Smrg !FcConfigAcceptFilename (config, font_file)) 3322c393a42Smrg { 3332c393a42Smrg continue; 3342c393a42Smrg } 3352c393a42Smrg 3362c393a42Smrg /* 3372c393a42Smrg * Check to see if font is banned by pattern 3382c393a42Smrg */ 3392c393a42Smrg if (!FcConfigAcceptFont (config, font)) 3402c393a42Smrg continue; 3412c393a42Smrg 342c9710b42Smrg if (FcFontSetAdd (config->fonts[set], font)) 343c9710b42Smrg nref++; 3442c393a42Smrg } 3452c393a42Smrg FcDirCacheReference (cache, nref); 3462c393a42Smrg } 3472c393a42Smrg 3482c393a42Smrg /* 3492c393a42Smrg * Add directories 3502c393a42Smrg */ 3512c393a42Smrg dirs = FcCacheDirs (cache); 3522c393a42Smrg if (dirs) 3532c393a42Smrg { 3542c393a42Smrg for (i = 0; i < cache->dirs_count; i++) 3552c393a42Smrg { 3562c393a42Smrg FcChar8 *dir = FcOffsetToPtr (dirs, dirs[i], FcChar8); 3572c393a42Smrg if (FcConfigAcceptFilename (config, dir)) 3582c393a42Smrg FcStrSetAddFilename (dirSet, dir); 3592c393a42Smrg } 3602c393a42Smrg } 3612c393a42Smrg return FcTrue; 3622c393a42Smrg} 3632c393a42Smrg 3642c393a42Smrgstatic FcBool 3652c393a42SmrgFcConfigAddDirList (FcConfig *config, FcSetName set, FcStrSet *dirSet) 3662c393a42Smrg{ 3672c393a42Smrg FcStrList *dirlist; 3682c393a42Smrg FcChar8 *dir; 3692c393a42Smrg FcCache *cache; 370ca08ab68Smrg 3712c393a42Smrg dirlist = FcStrListCreate (dirSet); 3722c393a42Smrg if (!dirlist) 3732c393a42Smrg return FcFalse; 3742c393a42Smrg 3752c393a42Smrg while ((dir = FcStrListNext (dirlist))) 3762c393a42Smrg { 3772c393a42Smrg if (FcDebug () & FC_DBG_FONTSET) 3782c393a42Smrg printf ("adding fonts from%s\n", dir); 3792c393a42Smrg cache = FcDirCacheRead (dir, FcFalse, config); 3802c393a42Smrg if (!cache) 3812c393a42Smrg continue; 3822c393a42Smrg FcConfigAddCache (config, cache, set, dirSet); 3832c393a42Smrg FcDirCacheUnload (cache); 3842c393a42Smrg } 3852c393a42Smrg FcStrListDone (dirlist); 3862c393a42Smrg return FcTrue; 3872c393a42Smrg} 3882c393a42Smrg 3892c393a42Smrg/* 3902c393a42Smrg * Scan the current list of directories in the configuration 3912c393a42Smrg * and build the set of available fonts. 3922c393a42Smrg */ 3932c393a42Smrg 3942c393a42SmrgFcBool 3952c393a42SmrgFcConfigBuildFonts (FcConfig *config) 3962c393a42Smrg{ 3972c393a42Smrg FcFontSet *fonts; 3982c393a42Smrg 3992c393a42Smrg if (!config) 4002c393a42Smrg { 4012c393a42Smrg config = FcConfigGetCurrent (); 4022c393a42Smrg if (!config) 4032c393a42Smrg return FcFalse; 4042c393a42Smrg } 4052c393a42Smrg 4062c393a42Smrg fonts = FcFontSetCreate (); 4072c393a42Smrg if (!fonts) 4082c393a42Smrg return FcFalse; 409ca08ab68Smrg 4102c393a42Smrg FcConfigSetFonts (config, fonts, FcSetSystem); 411ca08ab68Smrg 4122c393a42Smrg if (!FcConfigAddDirList (config, FcSetSystem, config->fontDirs)) 4132c393a42Smrg return FcFalse; 4142c393a42Smrg if (FcDebug () & FC_DBG_FONTSET) 4152c393a42Smrg FcFontSetPrint (fonts); 4162c393a42Smrg return FcTrue; 4172c393a42Smrg} 4182c393a42Smrg 4192c393a42SmrgFcBool 4202c393a42SmrgFcConfigSetCurrent (FcConfig *config) 4212c393a42Smrg{ 422c9710b42Smrg FcConfig *cfg; 423c9710b42Smrg 424c9710b42Smrgretry: 425c9710b42Smrg cfg = fc_atomic_ptr_get (&_fcConfig); 426c9710b42Smrg 427c9710b42Smrg if (config == cfg) 4282c393a42Smrg return FcTrue; 4292c393a42Smrg 430c9710b42Smrg if (config && !config->fonts[FcSetSystem]) 4312c393a42Smrg if (!FcConfigBuildFonts (config)) 4322c393a42Smrg return FcFalse; 4332c393a42Smrg 434c9710b42Smrg if (!fc_atomic_ptr_cmpexch (&_fcConfig, cfg, config)) 435c9710b42Smrg goto retry; 436c9710b42Smrg 437c9710b42Smrg if (cfg) 438c9710b42Smrg FcConfigDestroy (cfg); 439c9710b42Smrg 4402c393a42Smrg return FcTrue; 4412c393a42Smrg} 4422c393a42Smrg 4432c393a42SmrgFcConfig * 4442c393a42SmrgFcConfigGetCurrent (void) 4452c393a42Smrg{ 446c9710b42Smrg return FcConfigEnsure (); 4472c393a42Smrg} 4482c393a42Smrg 4492c393a42SmrgFcBool 4502c393a42SmrgFcConfigAddConfigDir (FcConfig *config, 4512c393a42Smrg const FcChar8 *d) 4522c393a42Smrg{ 4532c393a42Smrg return FcStrSetAddFilename (config->configDirs, d); 4542c393a42Smrg} 4552c393a42Smrg 4562c393a42SmrgFcStrList * 4572c393a42SmrgFcConfigGetConfigDirs (FcConfig *config) 4582c393a42Smrg{ 4592c393a42Smrg if (!config) 4602c393a42Smrg { 4612c393a42Smrg config = FcConfigGetCurrent (); 4622c393a42Smrg if (!config) 4632c393a42Smrg return 0; 4642c393a42Smrg } 4652c393a42Smrg return FcStrListCreate (config->configDirs); 4662c393a42Smrg} 4672c393a42Smrg 4682c393a42SmrgFcBool 4692c393a42SmrgFcConfigAddFontDir (FcConfig *config, 4702c393a42Smrg const FcChar8 *d) 4712c393a42Smrg{ 4722c393a42Smrg return FcStrSetAddFilename (config->fontDirs, d); 4732c393a42Smrg} 4742c393a42Smrg 4752c393a42SmrgFcBool 4762c393a42SmrgFcConfigAddDir (FcConfig *config, 4772c393a42Smrg const FcChar8 *d) 4782c393a42Smrg{ 479ca08ab68Smrg return (FcConfigAddConfigDir (config, d) && 4802c393a42Smrg FcConfigAddFontDir (config, d)); 4812c393a42Smrg} 4822c393a42Smrg 4832c393a42SmrgFcStrList * 4842c393a42SmrgFcConfigGetFontDirs (FcConfig *config) 4852c393a42Smrg{ 4862c393a42Smrg if (!config) 4872c393a42Smrg { 4882c393a42Smrg config = FcConfigGetCurrent (); 4892c393a42Smrg if (!config) 4902c393a42Smrg return 0; 4912c393a42Smrg } 4922c393a42Smrg return FcStrListCreate (config->fontDirs); 4932c393a42Smrg} 4942c393a42Smrg 4952c393a42SmrgFcBool 4962c393a42SmrgFcConfigAddCacheDir (FcConfig *config, 4972c393a42Smrg const FcChar8 *d) 4982c393a42Smrg{ 4992c393a42Smrg return FcStrSetAddFilename (config->cacheDirs, d); 5002c393a42Smrg} 5012c393a42Smrg 5022c393a42SmrgFcStrList * 503ca08ab68SmrgFcConfigGetCacheDirs (const FcConfig *config) 5042c393a42Smrg{ 5052c393a42Smrg if (!config) 5062c393a42Smrg { 5072c393a42Smrg config = FcConfigGetCurrent (); 5082c393a42Smrg if (!config) 5092c393a42Smrg return 0; 5102c393a42Smrg } 5112c393a42Smrg return FcStrListCreate (config->cacheDirs); 5122c393a42Smrg} 513ca08ab68Smrg 5142c393a42SmrgFcBool 5152c393a42SmrgFcConfigAddConfigFile (FcConfig *config, 5162c393a42Smrg const FcChar8 *f) 5172c393a42Smrg{ 5182c393a42Smrg FcBool ret; 5192c393a42Smrg FcChar8 *file = FcConfigFilename (f); 520ca08ab68Smrg 5212c393a42Smrg if (!file) 5222c393a42Smrg return FcFalse; 523ca08ab68Smrg 5242c393a42Smrg ret = FcStrSetAdd (config->configFiles, file); 5252c393a42Smrg FcStrFree (file); 5262c393a42Smrg return ret; 5272c393a42Smrg} 5282c393a42Smrg 5292c393a42SmrgFcStrList * 5302c393a42SmrgFcConfigGetConfigFiles (FcConfig *config) 5312c393a42Smrg{ 5322c393a42Smrg if (!config) 5332c393a42Smrg { 5342c393a42Smrg config = FcConfigGetCurrent (); 5352c393a42Smrg if (!config) 5362c393a42Smrg return 0; 5372c393a42Smrg } 5382c393a42Smrg return FcStrListCreate (config->configFiles); 5392c393a42Smrg} 5402c393a42Smrg 5412c393a42SmrgFcChar8 * 542c9710b42SmrgFcConfigGetCache (FcConfig *config FC_UNUSED) 5432c393a42Smrg{ 5442c393a42Smrg return NULL; 5452c393a42Smrg} 5462c393a42Smrg 5472c393a42SmrgFcFontSet * 5482c393a42SmrgFcConfigGetFonts (FcConfig *config, 5492c393a42Smrg FcSetName set) 5502c393a42Smrg{ 5512c393a42Smrg if (!config) 5522c393a42Smrg { 5532c393a42Smrg config = FcConfigGetCurrent (); 5542c393a42Smrg if (!config) 5552c393a42Smrg return 0; 5562c393a42Smrg } 5572c393a42Smrg return config->fonts[set]; 5582c393a42Smrg} 5592c393a42Smrg 5602c393a42Smrgvoid 5612c393a42SmrgFcConfigSetFonts (FcConfig *config, 5622c393a42Smrg FcFontSet *fonts, 5632c393a42Smrg FcSetName set) 5642c393a42Smrg{ 5652c393a42Smrg if (config->fonts[set]) 5662c393a42Smrg FcFontSetDestroy (config->fonts[set]); 5672c393a42Smrg config->fonts[set] = fonts; 5682c393a42Smrg} 5692c393a42Smrg 5702c393a42SmrgFcBlanks * 5712c393a42SmrgFcConfigGetBlanks (FcConfig *config) 5722c393a42Smrg{ 5732c393a42Smrg if (!config) 5742c393a42Smrg { 5752c393a42Smrg config = FcConfigGetCurrent (); 5762c393a42Smrg if (!config) 5772c393a42Smrg return 0; 5782c393a42Smrg } 5792c393a42Smrg return config->blanks; 5802c393a42Smrg} 5812c393a42Smrg 5822c393a42SmrgFcBool 5832c393a42SmrgFcConfigAddBlank (FcConfig *config, 5842c393a42Smrg FcChar32 blank) 5852c393a42Smrg{ 5862c393a42Smrg FcBlanks *b, *freeme = 0; 587ca08ab68Smrg 5882c393a42Smrg b = config->blanks; 5892c393a42Smrg if (!b) 5902c393a42Smrg { 5912c393a42Smrg freeme = b = FcBlanksCreate (); 5922c393a42Smrg if (!b) 5932c393a42Smrg return FcFalse; 5942c393a42Smrg } 5952c393a42Smrg if (!FcBlanksAdd (b, blank)) 5962c393a42Smrg { 5972c393a42Smrg if (freeme) 5982c393a42Smrg FcBlanksDestroy (freeme); 5992c393a42Smrg return FcFalse; 6002c393a42Smrg } 6012c393a42Smrg config->blanks = b; 6022c393a42Smrg return FcTrue; 6032c393a42Smrg} 6042c393a42Smrg 6052c393a42Smrgint 6062c393a42SmrgFcConfigGetRescanInterval (FcConfig *config) 6072c393a42Smrg{ 6082c393a42Smrg if (!config) 6092c393a42Smrg { 6102c393a42Smrg config = FcConfigGetCurrent (); 6112c393a42Smrg if (!config) 6122c393a42Smrg return 0; 6132c393a42Smrg } 6142c393a42Smrg return config->rescanInterval; 6152c393a42Smrg} 6162c393a42Smrg 6172c393a42SmrgFcBool 6182c393a42SmrgFcConfigSetRescanInterval (FcConfig *config, int rescanInterval) 6192c393a42Smrg{ 6202c393a42Smrg if (!config) 6212c393a42Smrg { 6222c393a42Smrg config = FcConfigGetCurrent (); 6232c393a42Smrg if (!config) 6242c393a42Smrg return FcFalse; 6252c393a42Smrg } 6262c393a42Smrg config->rescanInterval = rescanInterval; 6272c393a42Smrg return FcTrue; 6282c393a42Smrg} 6292c393a42Smrg 6302c393a42Smrg/* 6312c393a42Smrg * A couple of typos escaped into the library 6322c393a42Smrg */ 6332c393a42Smrgint 6342c393a42SmrgFcConfigGetRescanInverval (FcConfig *config) 6352c393a42Smrg{ 6362c393a42Smrg return FcConfigGetRescanInterval (config); 6372c393a42Smrg} 6382c393a42Smrg 6392c393a42SmrgFcBool 6402c393a42SmrgFcConfigSetRescanInverval (FcConfig *config, int rescanInterval) 6412c393a42Smrg{ 6422c393a42Smrg return FcConfigSetRescanInterval (config, rescanInterval); 6432c393a42Smrg} 6442c393a42Smrg 6452c393a42SmrgFcBool 6466fc018e4SmrgFcConfigAddRule (FcConfig *config, 6476fc018e4Smrg FcRule *rule, 6482c393a42Smrg FcMatchKind kind) 6492c393a42Smrg{ 6502c393a42Smrg FcSubst *subst, **prev; 6516fc018e4Smrg FcRule *r; 6526fc018e4Smrg int n = 0; 6532c393a42Smrg 6546fc018e4Smrg if (!rule) 6556fc018e4Smrg return FcFalse; 6562c393a42Smrg switch (kind) { 6572c393a42Smrg case FcMatchPattern: 6582c393a42Smrg prev = &config->substPattern; 6592c393a42Smrg break; 6602c393a42Smrg case FcMatchFont: 6612c393a42Smrg prev = &config->substFont; 6622c393a42Smrg break; 6632c393a42Smrg case FcMatchScan: 6642c393a42Smrg prev = &config->substScan; 6652c393a42Smrg break; 6662c393a42Smrg default: 6672c393a42Smrg return FcFalse; 6682c393a42Smrg } 6692c393a42Smrg subst = (FcSubst *) malloc (sizeof (FcSubst)); 6702c393a42Smrg if (!subst) 6712c393a42Smrg return FcFalse; 6722c393a42Smrg for (; *prev; prev = &(*prev)->next); 6732c393a42Smrg *prev = subst; 6746fc018e4Smrg subst->next = NULL; 6756fc018e4Smrg subst->rule = rule; 6766fc018e4Smrg for (r = rule; r; r = r->next) 6772c393a42Smrg { 6786fc018e4Smrg switch (r->type) 6796fc018e4Smrg { 6806fc018e4Smrg case FcRuleTest: 6816fc018e4Smrg if (r->u.test && 6826fc018e4Smrg r->u.test->kind == FcMatchDefault) 6836fc018e4Smrg r->u.test->kind = kind; 6846fc018e4Smrg 6856fc018e4Smrg if (n < r->u.test->object) 6866fc018e4Smrg n = r->u.test->object; 6876fc018e4Smrg break; 6886fc018e4Smrg case FcRuleEdit: 6896fc018e4Smrg if (n < r->u.edit->object) 6906fc018e4Smrg n = r->u.edit->object; 6916fc018e4Smrg break; 6926fc018e4Smrg default: 6936fc018e4Smrg break; 6946fc018e4Smrg } 6952c393a42Smrg } 6966fc018e4Smrg n = FC_OBJ_ID (n) - FC_MAX_BASE_OBJECT; 6976fc018e4Smrg if (config->maxObjects < n) 6986fc018e4Smrg config->maxObjects = n; 6992c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 7002c393a42Smrg { 7012c393a42Smrg printf ("Add Subst "); 7022c393a42Smrg FcSubstPrint (subst); 7032c393a42Smrg } 7042c393a42Smrg return FcTrue; 7052c393a42Smrg} 7062c393a42Smrg 7072c393a42Smrgstatic FcValue 708c9710b42SmrgFcConfigPromote (FcValue v, FcValue u, FcValuePromotionBuffer *buf) 7092c393a42Smrg{ 7102c393a42Smrg if (v.type == FcTypeInteger) 7112c393a42Smrg { 7122c393a42Smrg v.type = FcTypeDouble; 7132c393a42Smrg v.u.d = (double) v.u.i; 7142c393a42Smrg } 7152c393a42Smrg else if (v.type == FcTypeVoid && u.type == FcTypeMatrix) 7162c393a42Smrg { 7172c393a42Smrg v.u.m = &FcIdentityMatrix; 7182c393a42Smrg v.type = FcTypeMatrix; 7192c393a42Smrg } 720c9710b42Smrg else if (buf && v.type == FcTypeString && u.type == FcTypeLangSet) 7212c393a42Smrg { 722c9710b42Smrg v.u.l = FcLangSetPromote (v.u.s, buf); 7232c393a42Smrg v.type = FcTypeLangSet; 7242c393a42Smrg } 7252c393a42Smrg return v; 7262c393a42Smrg} 7272c393a42Smrg 7282c393a42SmrgFcBool 7292c393a42SmrgFcConfigCompareValue (const FcValue *left_o, 7306fc018e4Smrg unsigned int op_, 7312c393a42Smrg const FcValue *right_o) 7322c393a42Smrg{ 7332c393a42Smrg FcValue left = FcValueCanonicalize(left_o); 7342c393a42Smrg FcValue right = FcValueCanonicalize(right_o); 7352c393a42Smrg FcBool ret = FcFalse; 736ca08ab68Smrg FcOp op = FC_OP_GET_OP (op_); 737ca08ab68Smrg int flags = FC_OP_GET_FLAGS (op_); 738c9710b42Smrg FcValuePromotionBuffer buf1, buf2; 739ca08ab68Smrg 740c9710b42Smrg left = FcConfigPromote (left, right, &buf1); 741c9710b42Smrg right = FcConfigPromote (right, left, &buf2); 742ca08ab68Smrg if (left.type == right.type) 7432c393a42Smrg { 7442c393a42Smrg switch (left.type) { 7456fc018e4Smrg case FcTypeUnknown: 7466fc018e4Smrg break; /* No way to guess how to compare for this object */ 7472c393a42Smrg case FcTypeInteger: 7482c393a42Smrg break; /* FcConfigPromote prevents this from happening */ 7492c393a42Smrg case FcTypeDouble: 750c9710b42Smrg switch ((int) op) { 7512c393a42Smrg case FcOpEqual: 7522c393a42Smrg case FcOpContains: 7532c393a42Smrg case FcOpListing: 7542c393a42Smrg ret = left.u.d == right.u.d; 7552c393a42Smrg break; 7562c393a42Smrg case FcOpNotEqual: 7572c393a42Smrg case FcOpNotContains: 7582c393a42Smrg ret = left.u.d != right.u.d; 7592c393a42Smrg break; 760ca08ab68Smrg case FcOpLess: 7612c393a42Smrg ret = left.u.d < right.u.d; 7622c393a42Smrg break; 763ca08ab68Smrg case FcOpLessEqual: 7642c393a42Smrg ret = left.u.d <= right.u.d; 7652c393a42Smrg break; 766ca08ab68Smrg case FcOpMore: 7672c393a42Smrg ret = left.u.d > right.u.d; 7682c393a42Smrg break; 769ca08ab68Smrg case FcOpMoreEqual: 7702c393a42Smrg ret = left.u.d >= right.u.d; 7712c393a42Smrg break; 7722c393a42Smrg default: 7732c393a42Smrg break; 7742c393a42Smrg } 7752c393a42Smrg break; 7762c393a42Smrg case FcTypeBool: 777c9710b42Smrg switch ((int) op) { 778ca08ab68Smrg case FcOpEqual: 7792c393a42Smrg case FcOpContains: 7802c393a42Smrg case FcOpListing: 7812c393a42Smrg ret = left.u.b == right.u.b; 7822c393a42Smrg break; 7832c393a42Smrg case FcOpNotEqual: 7842c393a42Smrg case FcOpNotContains: 7852c393a42Smrg ret = left.u.b != right.u.b; 7862c393a42Smrg break; 7872c393a42Smrg default: 7882c393a42Smrg break; 7892c393a42Smrg } 7902c393a42Smrg break; 7912c393a42Smrg case FcTypeString: 792c9710b42Smrg switch ((int) op) { 793ca08ab68Smrg case FcOpEqual: 7942c393a42Smrg case FcOpListing: 795ca08ab68Smrg if (flags & FcOpFlagIgnoreBlanks) 796ca08ab68Smrg ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) == 0; 797ca08ab68Smrg else 798ca08ab68Smrg ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0; 7992c393a42Smrg break; 8002c393a42Smrg case FcOpContains: 8012c393a42Smrg ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0; 8022c393a42Smrg break; 8032c393a42Smrg case FcOpNotEqual: 804ca08ab68Smrg if (flags & FcOpFlagIgnoreBlanks) 805ca08ab68Smrg ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) != 0; 806ca08ab68Smrg else 807ca08ab68Smrg ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0; 8082c393a42Smrg break; 8092c393a42Smrg case FcOpNotContains: 8102c393a42Smrg ret = FcStrStrIgnoreCase (left.u.s, right.u.s) == 0; 8112c393a42Smrg break; 8122c393a42Smrg default: 8132c393a42Smrg break; 8142c393a42Smrg } 8152c393a42Smrg break; 8162c393a42Smrg case FcTypeMatrix: 817c9710b42Smrg switch ((int) op) { 8182c393a42Smrg case FcOpEqual: 8192c393a42Smrg case FcOpContains: 8202c393a42Smrg case FcOpListing: 8212c393a42Smrg ret = FcMatrixEqual (left.u.m, right.u.m); 8222c393a42Smrg break; 8232c393a42Smrg case FcOpNotEqual: 8242c393a42Smrg case FcOpNotContains: 8252c393a42Smrg ret = !FcMatrixEqual (left.u.m, right.u.m); 8262c393a42Smrg break; 8272c393a42Smrg default: 8282c393a42Smrg break; 8292c393a42Smrg } 8302c393a42Smrg break; 8312c393a42Smrg case FcTypeCharSet: 832c9710b42Smrg switch ((int) op) { 8332c393a42Smrg case FcOpContains: 8342c393a42Smrg case FcOpListing: 8352c393a42Smrg /* left contains right if right is a subset of left */ 8362c393a42Smrg ret = FcCharSetIsSubset (right.u.c, left.u.c); 8372c393a42Smrg break; 8382c393a42Smrg case FcOpNotContains: 8392c393a42Smrg /* left contains right if right is a subset of left */ 8402c393a42Smrg ret = !FcCharSetIsSubset (right.u.c, left.u.c); 8412c393a42Smrg break; 8422c393a42Smrg case FcOpEqual: 8432c393a42Smrg ret = FcCharSetEqual (left.u.c, right.u.c); 8442c393a42Smrg break; 8452c393a42Smrg case FcOpNotEqual: 8462c393a42Smrg ret = !FcCharSetEqual (left.u.c, right.u.c); 8472c393a42Smrg break; 8482c393a42Smrg default: 8492c393a42Smrg break; 8502c393a42Smrg } 8512c393a42Smrg break; 8522c393a42Smrg case FcTypeLangSet: 853c9710b42Smrg switch ((int) op) { 8542c393a42Smrg case FcOpContains: 8552c393a42Smrg case FcOpListing: 8562c393a42Smrg ret = FcLangSetContains (left.u.l, right.u.l); 8572c393a42Smrg break; 8582c393a42Smrg case FcOpNotContains: 8592c393a42Smrg ret = !FcLangSetContains (left.u.l, right.u.l); 8602c393a42Smrg break; 8612c393a42Smrg case FcOpEqual: 8622c393a42Smrg ret = FcLangSetEqual (left.u.l, right.u.l); 8632c393a42Smrg break; 8642c393a42Smrg case FcOpNotEqual: 8652c393a42Smrg ret = !FcLangSetEqual (left.u.l, right.u.l); 8662c393a42Smrg break; 8672c393a42Smrg default: 8682c393a42Smrg break; 8692c393a42Smrg } 8702c393a42Smrg break; 8712c393a42Smrg case FcTypeVoid: 872c9710b42Smrg switch ((int) op) { 8732c393a42Smrg case FcOpEqual: 8742c393a42Smrg case FcOpContains: 8752c393a42Smrg case FcOpListing: 8762c393a42Smrg ret = FcTrue; 8772c393a42Smrg break; 8782c393a42Smrg default: 8792c393a42Smrg break; 8802c393a42Smrg } 8812c393a42Smrg break; 8822c393a42Smrg case FcTypeFTFace: 883c9710b42Smrg switch ((int) op) { 8842c393a42Smrg case FcOpEqual: 8852c393a42Smrg case FcOpContains: 8862c393a42Smrg case FcOpListing: 8872c393a42Smrg ret = left.u.f == right.u.f; 8882c393a42Smrg break; 8892c393a42Smrg case FcOpNotEqual: 8902c393a42Smrg case FcOpNotContains: 8912c393a42Smrg ret = left.u.f != right.u.f; 8922c393a42Smrg break; 8932c393a42Smrg default: 8942c393a42Smrg break; 8952c393a42Smrg } 8962c393a42Smrg break; 8972c393a42Smrg } 8982c393a42Smrg } 8992c393a42Smrg else 9002c393a42Smrg { 9012c393a42Smrg if (op == FcOpNotEqual || op == FcOpNotContains) 9022c393a42Smrg ret = FcTrue; 9032c393a42Smrg } 9042c393a42Smrg return ret; 9052c393a42Smrg} 9062c393a42Smrg 9072c393a42Smrg 9082c393a42Smrg#define _FcDoubleFloor(d) ((int) (d)) 9092c393a42Smrg#define _FcDoubleCeil(d) ((double) (int) (d) == (d) ? (int) (d) : (int) ((d) + 1)) 9102c393a42Smrg#define FcDoubleFloor(d) ((d) >= 0 ? _FcDoubleFloor(d) : -_FcDoubleCeil(-(d))) 9112c393a42Smrg#define FcDoubleCeil(d) ((d) >= 0 ? _FcDoubleCeil(d) : -_FcDoubleFloor(-(d))) 9122c393a42Smrg#define FcDoubleRound(d) FcDoubleFloor ((d) + 0.5) 9132c393a42Smrg#define FcDoubleTrunc(d) ((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d))) 9142c393a42Smrg 9152c393a42Smrgstatic FcValue 916c9710b42SmrgFcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e) 9172c393a42Smrg{ 9182c393a42Smrg FcValue v, vl, vr; 9192c393a42Smrg FcMatrix *m; 9202c393a42Smrg FcChar8 *str; 921ca08ab68Smrg FcOp op = FC_OP_GET_OP (e->op); 922ca08ab68Smrg 923c9710b42Smrg switch ((int) op) { 9242c393a42Smrg case FcOpInteger: 9252c393a42Smrg v.type = FcTypeInteger; 9262c393a42Smrg v.u.i = e->u.ival; 9272c393a42Smrg break; 9282c393a42Smrg case FcOpDouble: 9292c393a42Smrg v.type = FcTypeDouble; 9302c393a42Smrg v.u.d = e->u.dval; 9312c393a42Smrg break; 9322c393a42Smrg case FcOpString: 9332c393a42Smrg v.type = FcTypeString; 934a6844aabSmrg v.u.s = e->u.sval; 935a6844aabSmrg v = FcValueSave (v); 9362c393a42Smrg break; 9372c393a42Smrg case FcOpMatrix: 938c9710b42Smrg { 939c9710b42Smrg FcMatrix m; 940c9710b42Smrg FcValue xx, xy, yx, yy; 941c9710b42Smrg v.type = FcTypeMatrix; 942c9710b42Smrg xx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xx), v, NULL); 943c9710b42Smrg xy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xy), v, NULL); 944c9710b42Smrg yx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yx), v, NULL); 945c9710b42Smrg yy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yy), v, NULL); 946c9710b42Smrg if (xx.type == FcTypeDouble && xy.type == FcTypeDouble && 947c9710b42Smrg yx.type == FcTypeDouble && yy.type == FcTypeDouble) 948c9710b42Smrg { 949c9710b42Smrg m.xx = xx.u.d; 950c9710b42Smrg m.xy = xy.u.d; 951c9710b42Smrg m.yx = yx.u.d; 952c9710b42Smrg m.yy = yy.u.d; 953c9710b42Smrg v.u.m = &m; 954c9710b42Smrg } 955c9710b42Smrg else 956c9710b42Smrg v.type = FcTypeVoid; 957c9710b42Smrg v = FcValueSave (v); 958c9710b42Smrg } 9592c393a42Smrg break; 9602c393a42Smrg case FcOpCharSet: 9612c393a42Smrg v.type = FcTypeCharSet; 9622c393a42Smrg v.u.c = e->u.cval; 9632c393a42Smrg v = FcValueSave (v); 9642c393a42Smrg break; 965ca08ab68Smrg case FcOpLangSet: 966ca08ab68Smrg v.type = FcTypeLangSet; 967ca08ab68Smrg v.u.l = e->u.lval; 968ca08ab68Smrg v = FcValueSave (v); 969ca08ab68Smrg break; 9702c393a42Smrg case FcOpBool: 9712c393a42Smrg v.type = FcTypeBool; 9722c393a42Smrg v.u.b = e->u.bval; 9732c393a42Smrg break; 9742c393a42Smrg case FcOpField: 975c9710b42Smrg if (kind == FcMatchFont && e->u.name.kind == FcMatchPattern) 976c9710b42Smrg { 977c9710b42Smrg if (FcResultMatch != FcPatternObjectGet (p_pat, e->u.name.object, 0, &v)) 978c9710b42Smrg v.type = FcTypeVoid; 979c9710b42Smrg } 980c9710b42Smrg else if (kind == FcMatchPattern && e->u.name.kind == FcMatchFont) 981c9710b42Smrg { 982c9710b42Smrg fprintf (stderr, 983c9710b42Smrg "Fontconfig warning: <name> tag has target=\"font\" in a <match target=\"pattern\">.\n"); 9842c393a42Smrg v.type = FcTypeVoid; 985c9710b42Smrg } 986c9710b42Smrg else 987c9710b42Smrg { 988c9710b42Smrg if (FcResultMatch != FcPatternObjectGet (p, e->u.name.object, 0, &v)) 989c9710b42Smrg v.type = FcTypeVoid; 990c9710b42Smrg } 9912c393a42Smrg v = FcValueSave (v); 9922c393a42Smrg break; 9932c393a42Smrg case FcOpConst: 9942c393a42Smrg if (FcNameConstant (e->u.constant, &v.u.i)) 9952c393a42Smrg v.type = FcTypeInteger; 9962c393a42Smrg else 9972c393a42Smrg v.type = FcTypeVoid; 9982c393a42Smrg break; 9992c393a42Smrg case FcOpQuest: 1000c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 10012c393a42Smrg if (vl.type == FcTypeBool) 10022c393a42Smrg { 10032c393a42Smrg if (vl.u.b) 1004c9710b42Smrg v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.left); 10052c393a42Smrg else 1006c9710b42Smrg v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.right); 10072c393a42Smrg } 10082c393a42Smrg else 10092c393a42Smrg v.type = FcTypeVoid; 10102c393a42Smrg FcValueDestroy (vl); 10112c393a42Smrg break; 10122c393a42Smrg case FcOpEqual: 10132c393a42Smrg case FcOpNotEqual: 10142c393a42Smrg case FcOpLess: 10152c393a42Smrg case FcOpLessEqual: 10162c393a42Smrg case FcOpMore: 10172c393a42Smrg case FcOpMoreEqual: 10182c393a42Smrg case FcOpContains: 10192c393a42Smrg case FcOpNotContains: 10202c393a42Smrg case FcOpListing: 1021c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1022c9710b42Smrg vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right); 10232c393a42Smrg v.type = FcTypeBool; 10242c393a42Smrg v.u.b = FcConfigCompareValue (&vl, e->op, &vr); 10252c393a42Smrg FcValueDestroy (vl); 10262c393a42Smrg FcValueDestroy (vr); 10272c393a42Smrg break; 10282c393a42Smrg case FcOpOr: 10292c393a42Smrg case FcOpAnd: 10302c393a42Smrg case FcOpPlus: 10312c393a42Smrg case FcOpMinus: 10322c393a42Smrg case FcOpTimes: 10332c393a42Smrg case FcOpDivide: 1034c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1035c9710b42Smrg vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right); 1036c9710b42Smrg vl = FcConfigPromote (vl, vr, NULL); 1037c9710b42Smrg vr = FcConfigPromote (vr, vl, NULL); 10382c393a42Smrg if (vl.type == vr.type) 10392c393a42Smrg { 1040c9710b42Smrg switch ((int) vl.type) { 10412c393a42Smrg case FcTypeDouble: 1042c9710b42Smrg switch ((int) op) { 1043ca08ab68Smrg case FcOpPlus: 10442c393a42Smrg v.type = FcTypeDouble; 1045ca08ab68Smrg v.u.d = vl.u.d + vr.u.d; 10462c393a42Smrg break; 10472c393a42Smrg case FcOpMinus: 10482c393a42Smrg v.type = FcTypeDouble; 1049ca08ab68Smrg v.u.d = vl.u.d - vr.u.d; 10502c393a42Smrg break; 10512c393a42Smrg case FcOpTimes: 10522c393a42Smrg v.type = FcTypeDouble; 1053ca08ab68Smrg v.u.d = vl.u.d * vr.u.d; 10542c393a42Smrg break; 10552c393a42Smrg case FcOpDivide: 10562c393a42Smrg v.type = FcTypeDouble; 1057ca08ab68Smrg v.u.d = vl.u.d / vr.u.d; 10582c393a42Smrg break; 10592c393a42Smrg default: 1060ca08ab68Smrg v.type = FcTypeVoid; 10612c393a42Smrg break; 10622c393a42Smrg } 10632c393a42Smrg if (v.type == FcTypeDouble && 10642c393a42Smrg v.u.d == (double) (int) v.u.d) 10652c393a42Smrg { 10662c393a42Smrg v.type = FcTypeInteger; 10672c393a42Smrg v.u.i = (int) v.u.d; 10682c393a42Smrg } 10692c393a42Smrg break; 10702c393a42Smrg case FcTypeBool: 1071c9710b42Smrg switch ((int) op) { 10722c393a42Smrg case FcOpOr: 10732c393a42Smrg v.type = FcTypeBool; 10742c393a42Smrg v.u.b = vl.u.b || vr.u.b; 10752c393a42Smrg break; 10762c393a42Smrg case FcOpAnd: 10772c393a42Smrg v.type = FcTypeBool; 10782c393a42Smrg v.u.b = vl.u.b && vr.u.b; 10792c393a42Smrg break; 10802c393a42Smrg default: 1081ca08ab68Smrg v.type = FcTypeVoid; 10822c393a42Smrg break; 10832c393a42Smrg } 10842c393a42Smrg break; 10852c393a42Smrg case FcTypeString: 1086c9710b42Smrg switch ((int) op) { 10872c393a42Smrg case FcOpPlus: 10882c393a42Smrg v.type = FcTypeString; 10892c393a42Smrg str = FcStrPlus (vl.u.s, vr.u.s); 1090c9710b42Smrg v.u.s = FcStrdup (str); 10912c393a42Smrg FcStrFree (str); 1092ca08ab68Smrg 10932c393a42Smrg if (!v.u.s) 10942c393a42Smrg v.type = FcTypeVoid; 10952c393a42Smrg break; 10962c393a42Smrg default: 10972c393a42Smrg v.type = FcTypeVoid; 10982c393a42Smrg break; 10992c393a42Smrg } 11002c393a42Smrg break; 11012c393a42Smrg case FcTypeMatrix: 1102c9710b42Smrg switch ((int) op) { 11032c393a42Smrg case FcOpTimes: 11042c393a42Smrg v.type = FcTypeMatrix; 11052c393a42Smrg m = malloc (sizeof (FcMatrix)); 11062c393a42Smrg if (m) 11072c393a42Smrg { 11082c393a42Smrg FcMatrixMultiply (m, vl.u.m, vr.u.m); 11092c393a42Smrg v.u.m = m; 11102c393a42Smrg } 11112c393a42Smrg else 11122c393a42Smrg { 11132c393a42Smrg v.type = FcTypeVoid; 11142c393a42Smrg } 11152c393a42Smrg break; 11162c393a42Smrg default: 11172c393a42Smrg v.type = FcTypeVoid; 11182c393a42Smrg break; 11192c393a42Smrg } 11202c393a42Smrg break; 1121ca08ab68Smrg case FcTypeCharSet: 1122c9710b42Smrg switch ((int) op) { 1123ca08ab68Smrg case FcOpPlus: 1124ca08ab68Smrg v.type = FcTypeCharSet; 1125ca08ab68Smrg v.u.c = FcCharSetUnion (vl.u.c, vr.u.c); 1126ca08ab68Smrg if (!v.u.c) 1127ca08ab68Smrg v.type = FcTypeVoid; 1128ca08ab68Smrg break; 1129ca08ab68Smrg case FcOpMinus: 1130ca08ab68Smrg v.type = FcTypeCharSet; 1131ca08ab68Smrg v.u.c = FcCharSetSubtract (vl.u.c, vr.u.c); 1132ca08ab68Smrg if (!v.u.c) 1133ca08ab68Smrg v.type = FcTypeVoid; 1134ca08ab68Smrg break; 1135ca08ab68Smrg default: 1136ca08ab68Smrg v.type = FcTypeVoid; 1137ca08ab68Smrg break; 1138ca08ab68Smrg } 1139ca08ab68Smrg break; 1140ca08ab68Smrg case FcTypeLangSet: 1141c9710b42Smrg switch ((int) op) { 1142ca08ab68Smrg case FcOpPlus: 1143ca08ab68Smrg v.type = FcTypeLangSet; 1144ca08ab68Smrg v.u.l = FcLangSetUnion (vl.u.l, vr.u.l); 1145ca08ab68Smrg if (!v.u.l) 1146ca08ab68Smrg v.type = FcTypeVoid; 1147ca08ab68Smrg break; 1148ca08ab68Smrg case FcOpMinus: 1149ca08ab68Smrg v.type = FcTypeLangSet; 1150ca08ab68Smrg v.u.l = FcLangSetSubtract (vl.u.l, vr.u.l); 1151ca08ab68Smrg if (!v.u.l) 1152ca08ab68Smrg v.type = FcTypeVoid; 1153ca08ab68Smrg break; 1154ca08ab68Smrg default: 1155ca08ab68Smrg v.type = FcTypeVoid; 1156ca08ab68Smrg break; 1157ca08ab68Smrg } 1158ca08ab68Smrg break; 11592c393a42Smrg default: 11602c393a42Smrg v.type = FcTypeVoid; 11612c393a42Smrg break; 11622c393a42Smrg } 11632c393a42Smrg } 11642c393a42Smrg else 11652c393a42Smrg v.type = FcTypeVoid; 11662c393a42Smrg FcValueDestroy (vl); 11672c393a42Smrg FcValueDestroy (vr); 11682c393a42Smrg break; 11692c393a42Smrg case FcOpNot: 1170c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1171c9710b42Smrg switch ((int) vl.type) { 11722c393a42Smrg case FcTypeBool: 11732c393a42Smrg v.type = FcTypeBool; 11742c393a42Smrg v.u.b = !vl.u.b; 11752c393a42Smrg break; 11762c393a42Smrg default: 11772c393a42Smrg v.type = FcTypeVoid; 11782c393a42Smrg break; 11792c393a42Smrg } 11802c393a42Smrg FcValueDestroy (vl); 11812c393a42Smrg break; 11822c393a42Smrg case FcOpFloor: 1183c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1184c9710b42Smrg switch ((int) vl.type) { 11852c393a42Smrg case FcTypeInteger: 11862c393a42Smrg v = vl; 11872c393a42Smrg break; 11882c393a42Smrg case FcTypeDouble: 11892c393a42Smrg v.type = FcTypeInteger; 11902c393a42Smrg v.u.i = FcDoubleFloor (vl.u.d); 11912c393a42Smrg break; 11922c393a42Smrg default: 11932c393a42Smrg v.type = FcTypeVoid; 11942c393a42Smrg break; 11952c393a42Smrg } 11962c393a42Smrg FcValueDestroy (vl); 11972c393a42Smrg break; 11982c393a42Smrg case FcOpCeil: 1199c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1200c9710b42Smrg switch ((int) vl.type) { 12012c393a42Smrg case FcTypeInteger: 12022c393a42Smrg v = vl; 12032c393a42Smrg break; 12042c393a42Smrg case FcTypeDouble: 12052c393a42Smrg v.type = FcTypeInteger; 12062c393a42Smrg v.u.i = FcDoubleCeil (vl.u.d); 12072c393a42Smrg break; 12082c393a42Smrg default: 12092c393a42Smrg v.type = FcTypeVoid; 12102c393a42Smrg break; 12112c393a42Smrg } 12122c393a42Smrg FcValueDestroy (vl); 12132c393a42Smrg break; 12142c393a42Smrg case FcOpRound: 1215c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1216c9710b42Smrg switch ((int) vl.type) { 12172c393a42Smrg case FcTypeInteger: 12182c393a42Smrg v = vl; 12192c393a42Smrg break; 12202c393a42Smrg case FcTypeDouble: 12212c393a42Smrg v.type = FcTypeInteger; 12222c393a42Smrg v.u.i = FcDoubleRound (vl.u.d); 12232c393a42Smrg break; 12242c393a42Smrg default: 12252c393a42Smrg v.type = FcTypeVoid; 12262c393a42Smrg break; 12272c393a42Smrg } 12282c393a42Smrg FcValueDestroy (vl); 12292c393a42Smrg break; 12302c393a42Smrg case FcOpTrunc: 1231c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1232c9710b42Smrg switch ((int) vl.type) { 12332c393a42Smrg case FcTypeInteger: 12342c393a42Smrg v = vl; 12352c393a42Smrg break; 12362c393a42Smrg case FcTypeDouble: 12372c393a42Smrg v.type = FcTypeInteger; 12382c393a42Smrg v.u.i = FcDoubleTrunc (vl.u.d); 12392c393a42Smrg break; 12402c393a42Smrg default: 12412c393a42Smrg v.type = FcTypeVoid; 12422c393a42Smrg break; 12432c393a42Smrg } 12442c393a42Smrg FcValueDestroy (vl); 12452c393a42Smrg break; 12462c393a42Smrg default: 12472c393a42Smrg v.type = FcTypeVoid; 12482c393a42Smrg break; 12492c393a42Smrg } 12502c393a42Smrg return v; 12512c393a42Smrg} 12522c393a42Smrg 12532c393a42Smrgstatic FcValueList * 12542c393a42SmrgFcConfigMatchValueList (FcPattern *p, 1255c9710b42Smrg FcPattern *p_pat, 1256c9710b42Smrg FcMatchKind kind, 12572c393a42Smrg FcTest *t, 12582c393a42Smrg FcValueList *values) 12592c393a42Smrg{ 12602c393a42Smrg FcValueList *ret = 0; 12612c393a42Smrg FcExpr *e = t->expr; 12622c393a42Smrg FcValue value; 12632c393a42Smrg FcValueList *v; 1264ca08ab68Smrg 12652c393a42Smrg while (e) 12662c393a42Smrg { 12672c393a42Smrg /* Compute the value of the match expression */ 1268ca08ab68Smrg if (FC_OP_GET_OP (e->op) == FcOpComma) 12692c393a42Smrg { 1270c9710b42Smrg value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 12712c393a42Smrg e = e->u.tree.right; 12722c393a42Smrg } 12732c393a42Smrg else 12742c393a42Smrg { 1275c9710b42Smrg value = FcConfigEvaluate (p, p_pat, kind, e); 12762c393a42Smrg e = 0; 12772c393a42Smrg } 12782c393a42Smrg 12792c393a42Smrg for (v = values; v; v = FcValueListNext(v)) 12802c393a42Smrg { 12812c393a42Smrg /* Compare the pattern value to the match expression value */ 12822c393a42Smrg if (FcConfigCompareValue (&v->value, t->op, &value)) 12832c393a42Smrg { 12842c393a42Smrg if (!ret) 12852c393a42Smrg ret = v; 12862c393a42Smrg } 12872c393a42Smrg else 12882c393a42Smrg { 12892c393a42Smrg if (t->qual == FcQualAll) 12902c393a42Smrg { 12912c393a42Smrg ret = 0; 12922c393a42Smrg break; 12932c393a42Smrg } 12942c393a42Smrg } 12952c393a42Smrg } 12962c393a42Smrg FcValueDestroy (value); 12972c393a42Smrg } 12982c393a42Smrg return ret; 12992c393a42Smrg} 13002c393a42Smrg 13012c393a42Smrgstatic FcValueList * 1302c9710b42SmrgFcConfigValues (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e, FcValueBinding binding) 13032c393a42Smrg{ 13042c393a42Smrg FcValueList *l; 1305ca08ab68Smrg 13062c393a42Smrg if (!e) 13072c393a42Smrg return 0; 13082c393a42Smrg l = (FcValueList *) malloc (sizeof (FcValueList)); 13092c393a42Smrg if (!l) 13102c393a42Smrg return 0; 1311ca08ab68Smrg if (FC_OP_GET_OP (e->op) == FcOpComma) 13122c393a42Smrg { 1313c9710b42Smrg l->value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1314c9710b42Smrg l->next = FcConfigValues (p, p_pat, kind, e->u.tree.right, binding); 13152c393a42Smrg } 13162c393a42Smrg else 13172c393a42Smrg { 1318c9710b42Smrg l->value = FcConfigEvaluate (p, p_pat, kind, e); 13192c393a42Smrg l->next = NULL; 13202c393a42Smrg } 13212c393a42Smrg l->binding = binding; 13222c393a42Smrg if (l->value.type == FcTypeVoid) 13232c393a42Smrg { 13242c393a42Smrg FcValueList *next = FcValueListNext(l); 13252c393a42Smrg 13262c393a42Smrg free (l); 13272c393a42Smrg l = next; 13282c393a42Smrg } 13292c393a42Smrg 13302c393a42Smrg return l; 13312c393a42Smrg} 13322c393a42Smrg 13332c393a42Smrgstatic FcBool 13342c393a42SmrgFcConfigAdd (FcValueListPtr *head, 13352c393a42Smrg FcValueList *position, 13362c393a42Smrg FcBool append, 1337c9710b42Smrg FcValueList *new, 1338c9710b42Smrg FcObject object) 13392c393a42Smrg{ 1340c9710b42Smrg FcValueListPtr *prev, l, last, v; 13412c393a42Smrg FcValueBinding sameBinding; 1342ca08ab68Smrg 1343c9710b42Smrg /* 1344c9710b42Smrg * Make sure the stored type is valid for built-in objects 1345c9710b42Smrg */ 1346c9710b42Smrg for (l = new; l != NULL; l = FcValueListNext (l)) 1347c9710b42Smrg { 1348c9710b42Smrg if (!FcObjectValidType (object, l->value.type)) 1349c9710b42Smrg { 1350c9710b42Smrg fprintf (stderr, 1351c9710b42Smrg "Fontconfig warning: FcPattern object %s does not accept value", FcObjectName (object)); 1352c9710b42Smrg FcValuePrintFile (stderr, l->value); 1353c9710b42Smrg fprintf (stderr, "\n"); 1354c9710b42Smrg 1355c9710b42Smrg if (FcDebug () & FC_DBG_EDIT) 1356c9710b42Smrg { 1357c9710b42Smrg printf ("Not adding\n"); 1358c9710b42Smrg } 1359c9710b42Smrg 1360c9710b42Smrg return FcFalse; 1361c9710b42Smrg } 1362c9710b42Smrg } 1363c9710b42Smrg 13642c393a42Smrg if (position) 13652c393a42Smrg sameBinding = position->binding; 13662c393a42Smrg else 13672c393a42Smrg sameBinding = FcValueBindingWeak; 13682c393a42Smrg for (v = new; v != NULL; v = FcValueListNext(v)) 13692c393a42Smrg if (v->binding == FcValueBindingSame) 13702c393a42Smrg v->binding = sameBinding; 13712c393a42Smrg if (append) 13722c393a42Smrg { 13732c393a42Smrg if (position) 13742c393a42Smrg prev = &position->next; 13752c393a42Smrg else 1376ca08ab68Smrg for (prev = head; *prev != NULL; 13772c393a42Smrg prev = &(*prev)->next) 13782c393a42Smrg ; 13792c393a42Smrg } 13802c393a42Smrg else 13812c393a42Smrg { 13822c393a42Smrg if (position) 13832c393a42Smrg { 1384ca08ab68Smrg for (prev = head; *prev != NULL; 13852c393a42Smrg prev = &(*prev)->next) 13862c393a42Smrg { 13872c393a42Smrg if (*prev == position) 13882c393a42Smrg break; 13892c393a42Smrg } 13902c393a42Smrg } 13912c393a42Smrg else 13922c393a42Smrg prev = head; 13932c393a42Smrg 13942c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 13952c393a42Smrg { 13962c393a42Smrg if (*prev == NULL) 13972c393a42Smrg printf ("position not on list\n"); 13982c393a42Smrg } 13992c393a42Smrg } 14002c393a42Smrg 14012c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 14022c393a42Smrg { 14032c393a42Smrg printf ("%s list before ", append ? "Append" : "Prepend"); 1404ca08ab68Smrg FcValueListPrintWithPosition (*head, *prev); 14052c393a42Smrg printf ("\n"); 14062c393a42Smrg } 1407ca08ab68Smrg 14082c393a42Smrg if (new) 14092c393a42Smrg { 14102c393a42Smrg last = new; 14112c393a42Smrg while (last->next != NULL) 14122c393a42Smrg last = last->next; 1413ca08ab68Smrg 14142c393a42Smrg last->next = *prev; 14152c393a42Smrg *prev = new; 14162c393a42Smrg } 1417ca08ab68Smrg 14182c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 14192c393a42Smrg { 14202c393a42Smrg printf ("%s list after ", append ? "Append" : "Prepend"); 14212c393a42Smrg FcValueListPrint (*head); 14222c393a42Smrg printf ("\n"); 14232c393a42Smrg } 1424ca08ab68Smrg 14252c393a42Smrg return FcTrue; 14262c393a42Smrg} 14272c393a42Smrg 14282c393a42Smrgstatic void 14292c393a42SmrgFcConfigDel (FcValueListPtr *head, 14302c393a42Smrg FcValueList *position) 14312c393a42Smrg{ 14322c393a42Smrg FcValueListPtr *prev; 14332c393a42Smrg 14342c393a42Smrg for (prev = head; *prev != NULL; prev = &(*prev)->next) 14352c393a42Smrg { 14362c393a42Smrg if (*prev == position) 14372c393a42Smrg { 14382c393a42Smrg *prev = position->next; 14392c393a42Smrg position->next = NULL; 14402c393a42Smrg FcValueListDestroy (position); 14412c393a42Smrg break; 14422c393a42Smrg } 14432c393a42Smrg } 14442c393a42Smrg} 14452c393a42Smrg 14462c393a42Smrgstatic void 14472c393a42SmrgFcConfigPatternAdd (FcPattern *p, 14482c393a42Smrg FcObject object, 14492c393a42Smrg FcValueList *list, 14502c393a42Smrg FcBool append) 14512c393a42Smrg{ 14522c393a42Smrg if (list) 14532c393a42Smrg { 14542c393a42Smrg FcPatternElt *e = FcPatternObjectInsertElt (p, object); 1455ca08ab68Smrg 14562c393a42Smrg if (!e) 14572c393a42Smrg return; 1458c9710b42Smrg FcConfigAdd (&e->values, 0, append, list, object); 14592c393a42Smrg } 14602c393a42Smrg} 14612c393a42Smrg 14622c393a42Smrg/* 14632c393a42Smrg * Delete all values associated with a field 14642c393a42Smrg */ 14652c393a42Smrgstatic void 14662c393a42SmrgFcConfigPatternDel (FcPattern *p, 14672c393a42Smrg FcObject object) 14682c393a42Smrg{ 14692c393a42Smrg FcPatternElt *e = FcPatternObjectFindElt (p, object); 14702c393a42Smrg if (!e) 14712c393a42Smrg return; 14722c393a42Smrg while (e->values != NULL) 14732c393a42Smrg FcConfigDel (&e->values, e->values); 14742c393a42Smrg} 14752c393a42Smrg 14762c393a42Smrgstatic void 14772c393a42SmrgFcConfigPatternCanon (FcPattern *p, 14782c393a42Smrg FcObject object) 14792c393a42Smrg{ 14802c393a42Smrg FcPatternElt *e = FcPatternObjectFindElt (p, object); 14812c393a42Smrg if (!e) 14822c393a42Smrg return; 14832c393a42Smrg if (e->values == NULL) 14842c393a42Smrg FcPatternObjectDel (p, object); 14852c393a42Smrg} 14862c393a42Smrg 14872c393a42SmrgFcBool 14882c393a42SmrgFcConfigSubstituteWithPat (FcConfig *config, 14892c393a42Smrg FcPattern *p, 14902c393a42Smrg FcPattern *p_pat, 14912c393a42Smrg FcMatchKind kind) 14922c393a42Smrg{ 1493c9710b42Smrg FcValue v; 14942c393a42Smrg FcSubst *s; 14956fc018e4Smrg FcRule *r; 14966fc018e4Smrg FcValueList *l, **value = NULL, *vl; 14972c393a42Smrg FcPattern *m; 1498ca08ab68Smrg FcStrSet *strs; 14996fc018e4Smrg FcObject object = FC_INVALID_OBJECT; 15006fc018e4Smrg FcPatternElt **elt = NULL, *e; 15016fc018e4Smrg int i, nobjs; 15026fc018e4Smrg FcBool retval = FcTrue; 15036fc018e4Smrg FcTest **tst = NULL; 15042c393a42Smrg 15052c393a42Smrg if (!config) 15062c393a42Smrg { 15072c393a42Smrg config = FcConfigGetCurrent (); 15082c393a42Smrg if (!config) 15092c393a42Smrg return FcFalse; 15102c393a42Smrg } 15112c393a42Smrg 15122c393a42Smrg switch (kind) { 15132c393a42Smrg case FcMatchPattern: 15142c393a42Smrg s = config->substPattern; 1515ca08ab68Smrg strs = FcGetDefaultLangs (); 1516ca08ab68Smrg if (strs) 1517ca08ab68Smrg { 1518ca08ab68Smrg FcStrList *l = FcStrListCreate (strs); 1519ca08ab68Smrg FcChar8 *lang; 1520ca08ab68Smrg FcValue v; 1521ca08ab68Smrg 1522ca08ab68Smrg FcStrSetDestroy (strs); 1523ca08ab68Smrg while (l && (lang = FcStrListNext (l))) 1524ca08ab68Smrg { 1525ca08ab68Smrg v.type = FcTypeString; 1526ca08ab68Smrg v.u.s = lang; 1527ca08ab68Smrg FcPatternObjectAddWithBinding (p, FC_LANG_OBJECT, v, FcValueBindingWeak, FcTrue); 1528ca08ab68Smrg } 1529ca08ab68Smrg FcStrListDone (l); 1530ca08ab68Smrg } 1531c9710b42Smrg if (FcPatternObjectGet (p, FC_PRGNAME_OBJECT, 0, &v) == FcResultNoMatch) 1532c9710b42Smrg { 1533c9710b42Smrg FcChar8 *prgname = FcGetPrgname (); 1534c9710b42Smrg if (prgname) 1535c9710b42Smrg FcPatternObjectAddString (p, FC_PRGNAME_OBJECT, prgname); 1536c9710b42Smrg } 15372c393a42Smrg break; 15382c393a42Smrg case FcMatchFont: 15392c393a42Smrg s = config->substFont; 15402c393a42Smrg break; 15412c393a42Smrg case FcMatchScan: 15422c393a42Smrg s = config->substScan; 15432c393a42Smrg break; 15442c393a42Smrg default: 15452c393a42Smrg return FcFalse; 15462c393a42Smrg } 15472c393a42Smrg 15486fc018e4Smrg nobjs = FC_MAX_BASE_OBJECT + config->maxObjects + 2; 1549cc1bebd6Smrg value = (FcValueList **) malloc (sizeof(void *) * nobjs); 15506fc018e4Smrg if (!value) 15516fc018e4Smrg { 15526fc018e4Smrg retval = FcFalse; 15536fc018e4Smrg goto bail1; 15546fc018e4Smrg } 1555cc1bebd6Smrg elt = (FcPatternElt **) malloc (sizeof(void *) * nobjs); 15566fc018e4Smrg if (!elt) 15576fc018e4Smrg { 15586fc018e4Smrg retval = FcFalse; 15596fc018e4Smrg goto bail1; 15606fc018e4Smrg } 1561cc1bebd6Smrg tst = (FcTest **) malloc (sizeof(void *) * nobjs); 15626fc018e4Smrg if (!tst) 15636fc018e4Smrg { 15646fc018e4Smrg retval = FcFalse; 15656fc018e4Smrg goto bail1; 15666fc018e4Smrg } 15672c393a42Smrg 15682c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 15692c393a42Smrg { 15702c393a42Smrg printf ("FcConfigSubstitute "); 15712c393a42Smrg FcPatternPrint (p); 15722c393a42Smrg } 15732c393a42Smrg for (; s; s = s->next) 15742c393a42Smrg { 15756fc018e4Smrg r = s->rule; 15766fc018e4Smrg for (i = 0; i < nobjs; i++) 15772c393a42Smrg { 15786fc018e4Smrg elt[i] = NULL; 15796fc018e4Smrg value[i] = NULL; 15806fc018e4Smrg tst[i] = NULL; 15816fc018e4Smrg } 15826fc018e4Smrg for (; r; r = r->next) 15836fc018e4Smrg { 15846fc018e4Smrg switch (r->type) { 15856fc018e4Smrg case FcRuleUnknown: 15866fc018e4Smrg /* shouldn't be reached */ 15876fc018e4Smrg break; 15886fc018e4Smrg case FcRuleTest: 15896fc018e4Smrg object = FC_OBJ_ID (r->u.test->object); 15906fc018e4Smrg /* 15916fc018e4Smrg * Check the tests to see if 15926fc018e4Smrg * they all match the pattern 15936fc018e4Smrg */ 15946fc018e4Smrg if (FcDebug () & FC_DBG_EDIT) 15952c393a42Smrg { 15966fc018e4Smrg printf ("FcConfigSubstitute test "); 15976fc018e4Smrg FcTestPrint (r->u.test); 15982c393a42Smrg } 15996fc018e4Smrg if (kind == FcMatchFont && r->u.test->kind == FcMatchPattern) 16006fc018e4Smrg m = p_pat; 16012c393a42Smrg else 16026fc018e4Smrg m = p; 16036fc018e4Smrg if (m) 16046fc018e4Smrg e = FcPatternObjectFindElt (m, r->u.test->object); 16056fc018e4Smrg else 16066fc018e4Smrg e = NULL; 16076fc018e4Smrg /* different 'kind' won't be the target of edit */ 16086fc018e4Smrg if (!elt[object] && kind == r->u.test->kind) 16092c393a42Smrg { 16106fc018e4Smrg elt[object] = e; 16116fc018e4Smrg tst[object] = r->u.test; 16122c393a42Smrg } 16132c393a42Smrg /* 16146fc018e4Smrg * If there's no such field in the font, 16156fc018e4Smrg * then FcQualAll matches while FcQualAny does not 16162c393a42Smrg */ 16176fc018e4Smrg if (!e) 16182c393a42Smrg { 16196fc018e4Smrg if (r->u.test->qual == FcQualAll) 16206fc018e4Smrg { 16216fc018e4Smrg value[object] = NULL; 16226fc018e4Smrg continue; 16236fc018e4Smrg } 16246fc018e4Smrg else 16256fc018e4Smrg { 16266fc018e4Smrg if (FcDebug () & FC_DBG_EDIT) 16276fc018e4Smrg printf ("No match\n"); 16286fc018e4Smrg goto bail; 16296fc018e4Smrg } 16306fc018e4Smrg } 16316fc018e4Smrg /* 16326fc018e4Smrg * Check to see if there is a match, mark the location 16336fc018e4Smrg * to apply match-relative edits 16346fc018e4Smrg */ 16356fc018e4Smrg vl = FcConfigMatchValueList (m, p_pat, kind, r->u.test, e->values); 16366fc018e4Smrg /* different 'kind' won't be the target of edit */ 16376fc018e4Smrg if (!value[object] && kind == r->u.test->kind) 16386fc018e4Smrg value[object] = vl; 16396fc018e4Smrg if (!vl || 16406fc018e4Smrg (r->u.test->qual == FcQualFirst && vl != e->values) || 16416fc018e4Smrg (r->u.test->qual == FcQualNotFirst && vl == e->values)) 16426fc018e4Smrg { 16436fc018e4Smrg if (FcDebug () & FC_DBG_EDIT) 16446fc018e4Smrg printf ("No match\n"); 16456fc018e4Smrg goto bail; 16466fc018e4Smrg } 16476fc018e4Smrg break; 16486fc018e4Smrg case FcRuleEdit: 16496fc018e4Smrg object = FC_OBJ_ID (r->u.edit->object); 16506fc018e4Smrg if (FcDebug () & FC_DBG_EDIT) 16516fc018e4Smrg { 16526fc018e4Smrg printf ("Substitute "); 16536fc018e4Smrg FcEditPrint (r->u.edit); 16546fc018e4Smrg printf ("\n\n"); 16556fc018e4Smrg } 16566fc018e4Smrg /* 16576fc018e4Smrg * Evaluate the list of expressions 16586fc018e4Smrg */ 16596fc018e4Smrg l = FcConfigValues (p, p_pat,kind, r->u.edit->expr, r->u.edit->binding); 16606fc018e4Smrg if (tst[object] && (tst[object]->kind == FcMatchFont || kind == FcMatchPattern)) 16616fc018e4Smrg elt[object] = FcPatternObjectFindElt (p, tst[object]->object); 16626fc018e4Smrg 16636fc018e4Smrg switch (FC_OP_GET_OP (r->u.edit->op)) { 16646fc018e4Smrg case FcOpAssign: 16652c393a42Smrg /* 16666fc018e4Smrg * If there was a test, then replace the matched 16676fc018e4Smrg * value with the new list of values 16682c393a42Smrg */ 16696fc018e4Smrg if (value[object]) 16706fc018e4Smrg { 16716fc018e4Smrg FcValueList *thisValue = value[object]; 16726fc018e4Smrg FcValueList *nextValue = l; 16736fc018e4Smrg 16746fc018e4Smrg /* 16756fc018e4Smrg * Append the new list of values after the current value 16766fc018e4Smrg */ 16776fc018e4Smrg FcConfigAdd (&elt[object]->values, thisValue, FcTrue, l, r->u.edit->object); 16786fc018e4Smrg /* 16796fc018e4Smrg * Delete the marked value 16806fc018e4Smrg */ 16816fc018e4Smrg if (thisValue) 16826fc018e4Smrg FcConfigDel (&elt[object]->values, thisValue); 16836fc018e4Smrg /* 16846fc018e4Smrg * Adjust a pointer into the value list to ensure 16856fc018e4Smrg * future edits occur at the same place 16866fc018e4Smrg */ 16876fc018e4Smrg value[object] = nextValue; 16886fc018e4Smrg break; 16896fc018e4Smrg } 16906fc018e4Smrg /* fall through ... */ 16916fc018e4Smrg case FcOpAssignReplace: 16922c393a42Smrg /* 16936fc018e4Smrg * Delete all of the values and insert 16946fc018e4Smrg * the new set 16952c393a42Smrg */ 16966fc018e4Smrg FcConfigPatternDel (p, r->u.edit->object); 16976fc018e4Smrg FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue); 16982c393a42Smrg /* 16996fc018e4Smrg * Adjust a pointer into the value list as they no 17006fc018e4Smrg * longer point to anything valid 17012c393a42Smrg */ 17026fc018e4Smrg value[object] = NULL; 17036fc018e4Smrg break; 17046fc018e4Smrg case FcOpPrepend: 17056fc018e4Smrg if (value[object]) 17062c393a42Smrg { 17076fc018e4Smrg FcConfigAdd (&elt[object]->values, value[object], FcFalse, l, r->u.edit->object); 17086fc018e4Smrg break; 17092c393a42Smrg } 17106fc018e4Smrg /* fall through ... */ 17116fc018e4Smrg case FcOpPrependFirst: 17126fc018e4Smrg FcConfigPatternAdd (p, r->u.edit->object, l, FcFalse); 17132c393a42Smrg break; 17146fc018e4Smrg case FcOpAppend: 17156fc018e4Smrg if (value[object]) 17162c393a42Smrg { 17176fc018e4Smrg FcConfigAdd (&elt[object]->values, value[object], FcTrue, l, r->u.edit->object); 17186fc018e4Smrg break; 17192c393a42Smrg } 17206fc018e4Smrg /* fall through ... */ 17216fc018e4Smrg case FcOpAppendLast: 17226fc018e4Smrg FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue); 17232c393a42Smrg break; 17246fc018e4Smrg case FcOpDelete: 17256fc018e4Smrg if (value[object]) 17266fc018e4Smrg { 17276fc018e4Smrg FcConfigDel (&elt[object]->values, value[object]); 17286fc018e4Smrg break; 17296fc018e4Smrg } 17306fc018e4Smrg /* fall through ... */ 17316fc018e4Smrg case FcOpDeleteAll: 17326fc018e4Smrg FcConfigPatternDel (p, r->u.edit->object); 17336fc018e4Smrg break; 17346fc018e4Smrg default: 17356fc018e4Smrg FcValueListDestroy (l); 17362c393a42Smrg break; 17372c393a42Smrg } 17386fc018e4Smrg /* 17396fc018e4Smrg * Now go through the pattern and eliminate 17406fc018e4Smrg * any properties without data 17416fc018e4Smrg */ 17426fc018e4Smrg FcConfigPatternCanon (p, r->u.edit->object); 17436fc018e4Smrg 17446fc018e4Smrg if (FcDebug () & FC_DBG_EDIT) 1745c9710b42Smrg { 17466fc018e4Smrg printf ("FcConfigSubstitute edit"); 17476fc018e4Smrg FcPatternPrint (p); 1748c9710b42Smrg } 17492c393a42Smrg break; 17502c393a42Smrg } 17512c393a42Smrg } 17526fc018e4Smrg bail:; 17532c393a42Smrg } 17542c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 17552c393a42Smrg { 17562c393a42Smrg printf ("FcConfigSubstitute done"); 17572c393a42Smrg FcPatternPrint (p); 17582c393a42Smrg } 17596fc018e4Smrgbail1: 17606fc018e4Smrg if (elt) 17616fc018e4Smrg free (elt); 17626fc018e4Smrg if (value) 17636fc018e4Smrg free (value); 17646fc018e4Smrg if (tst) 17656fc018e4Smrg free (tst); 17666fc018e4Smrg 17676fc018e4Smrg return retval; 17682c393a42Smrg} 17692c393a42Smrg 17702c393a42SmrgFcBool 17712c393a42SmrgFcConfigSubstitute (FcConfig *config, 17722c393a42Smrg FcPattern *p, 17732c393a42Smrg FcMatchKind kind) 17742c393a42Smrg{ 17752c393a42Smrg return FcConfigSubstituteWithPat (config, p, 0, kind); 17762c393a42Smrg} 17772c393a42Smrg 17782c393a42Smrg#if defined (_WIN32) 17792c393a42Smrg 1780c9710b42Smrgstatic FcChar8 fontconfig_path[1000] = ""; /* MT-dontcare */ 17812c393a42Smrg 17822c393a42Smrg# if (defined (PIC) || defined (DLL_EXPORT)) 17832c393a42Smrg 1784c9710b42SmrgBOOL WINAPI 1785c9710b42SmrgDllMain (HINSTANCE hinstDLL, 1786c9710b42Smrg DWORD fdwReason, 1787c9710b42Smrg LPVOID lpvReserved); 1788c9710b42Smrg 17892c393a42SmrgBOOL WINAPI 17902c393a42SmrgDllMain (HINSTANCE hinstDLL, 17912c393a42Smrg DWORD fdwReason, 17922c393a42Smrg LPVOID lpvReserved) 17932c393a42Smrg{ 17942c393a42Smrg FcChar8 *p; 17952c393a42Smrg 17962c393a42Smrg switch (fdwReason) { 17972c393a42Smrg case DLL_PROCESS_ATTACH: 1798ca08ab68Smrg if (!GetModuleFileName ((HMODULE) hinstDLL, (LPCH) fontconfig_path, 17992c393a42Smrg sizeof (fontconfig_path))) 18002c393a42Smrg break; 18012c393a42Smrg 18022c393a42Smrg /* If the fontconfig DLL is in a "bin" or "lib" subfolder, 18032c393a42Smrg * assume it's a Unix-style installation tree, and use 18042c393a42Smrg * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the 18052c393a42Smrg * folder where the DLL is as FONTCONFIG_PATH. 18062c393a42Smrg */ 1807ca08ab68Smrg p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\'); 18082c393a42Smrg if (p) 18092c393a42Smrg { 18102c393a42Smrg *p = '\0'; 1811ca08ab68Smrg p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\'); 1812ca08ab68Smrg if (p && (FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "bin") == 0 || 1813ca08ab68Smrg FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "lib") == 0)) 18142c393a42Smrg *p = '\0'; 1815ca08ab68Smrg strcat ((char *) fontconfig_path, "\\etc\\fonts"); 18162c393a42Smrg } 18172c393a42Smrg else 18182c393a42Smrg fontconfig_path[0] = '\0'; 1819ca08ab68Smrg 18202c393a42Smrg break; 18212c393a42Smrg } 18222c393a42Smrg 18232c393a42Smrg return TRUE; 18242c393a42Smrg} 18252c393a42Smrg 18262c393a42Smrg# endif /* !PIC */ 18272c393a42Smrg 18282c393a42Smrg#undef FONTCONFIG_PATH 18292c393a42Smrg#define FONTCONFIG_PATH fontconfig_path 18302c393a42Smrg 18312c393a42Smrg#endif /* !_WIN32 */ 18322c393a42Smrg 18332c393a42Smrg#ifndef FONTCONFIG_FILE 18342c393a42Smrg#define FONTCONFIG_FILE "fonts.conf" 18352c393a42Smrg#endif 18362c393a42Smrg 18372c393a42Smrgstatic FcChar8 * 18382c393a42SmrgFcConfigFileExists (const FcChar8 *dir, const FcChar8 *file) 18392c393a42Smrg{ 18402c393a42Smrg FcChar8 *path; 1841ca08ab68Smrg int size, osize; 18422c393a42Smrg 18432c393a42Smrg if (!dir) 18442c393a42Smrg dir = (FcChar8 *) ""; 1845ca08ab68Smrg 1846ca08ab68Smrg osize = strlen ((char *) dir) + 1 + strlen ((char *) file) + 1; 1847ca08ab68Smrg /* 1848ca08ab68Smrg * workaround valgrind warning because glibc takes advantage of how it knows memory is 1849ca08ab68Smrg * allocated to implement strlen by reading in groups of 4 1850ca08ab68Smrg */ 1851ca08ab68Smrg size = (osize + 3) & ~3; 1852ca08ab68Smrg 1853ca08ab68Smrg path = malloc (size); 18542c393a42Smrg if (!path) 18552c393a42Smrg return 0; 18562c393a42Smrg 18572c393a42Smrg strcpy ((char *) path, (const char *) dir); 18582c393a42Smrg /* make sure there's a single separator */ 18592c393a42Smrg#ifdef _WIN32 18602c393a42Smrg if ((!path[0] || (path[strlen((char *) path)-1] != '/' && 18612c393a42Smrg path[strlen((char *) path)-1] != '\\')) && 18622c393a42Smrg !(file[0] == '/' || 18632c393a42Smrg file[0] == '\\' || 18642c393a42Smrg (isalpha (file[0]) && file[1] == ':' && (file[2] == '/' || file[2] == '\\')))) 18652c393a42Smrg strcat ((char *) path, "\\"); 18662c393a42Smrg#else 18672c393a42Smrg if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/') 18682c393a42Smrg strcat ((char *) path, "/"); 1869c9710b42Smrg else 1870c9710b42Smrg osize--; 18712c393a42Smrg#endif 18722c393a42Smrg strcat ((char *) path, (char *) file); 18732c393a42Smrg 18742c393a42Smrg if (access ((char *) path, R_OK) == 0) 18752c393a42Smrg return path; 1876ca08ab68Smrg 18772c393a42Smrg FcStrFree (path); 1878ca08ab68Smrg 18792c393a42Smrg return 0; 18802c393a42Smrg} 18812c393a42Smrg 18822c393a42Smrgstatic FcChar8 ** 18832c393a42SmrgFcConfigGetPath (void) 18842c393a42Smrg{ 18852c393a42Smrg FcChar8 **path; 18862c393a42Smrg FcChar8 *env, *e, *colon; 18872c393a42Smrg FcChar8 *dir; 18882c393a42Smrg int npath; 18892c393a42Smrg int i; 18902c393a42Smrg 18912c393a42Smrg npath = 2; /* default dir + null */ 18922c393a42Smrg env = (FcChar8 *) getenv ("FONTCONFIG_PATH"); 18932c393a42Smrg if (env) 18942c393a42Smrg { 18952c393a42Smrg e = env; 18962c393a42Smrg npath++; 18972c393a42Smrg while (*e) 18982c393a42Smrg if (*e++ == FC_SEARCH_PATH_SEPARATOR) 18992c393a42Smrg npath++; 19002c393a42Smrg } 19012c393a42Smrg path = calloc (npath, sizeof (FcChar8 *)); 19022c393a42Smrg if (!path) 19032c393a42Smrg goto bail0; 19042c393a42Smrg i = 0; 19052c393a42Smrg 19062c393a42Smrg if (env) 19072c393a42Smrg { 19082c393a42Smrg e = env; 1909ca08ab68Smrg while (*e) 19102c393a42Smrg { 19112c393a42Smrg colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR); 19122c393a42Smrg if (!colon) 19132c393a42Smrg colon = e + strlen ((char *) e); 19142c393a42Smrg path[i] = malloc (colon - e + 1); 19152c393a42Smrg if (!path[i]) 19162c393a42Smrg goto bail1; 19172c393a42Smrg strncpy ((char *) path[i], (const char *) e, colon - e); 19182c393a42Smrg path[i][colon - e] = '\0'; 19192c393a42Smrg if (*colon) 19202c393a42Smrg e = colon + 1; 19212c393a42Smrg else 19222c393a42Smrg e = colon; 19232c393a42Smrg i++; 19242c393a42Smrg } 19252c393a42Smrg } 1926ca08ab68Smrg 19272c393a42Smrg#ifdef _WIN32 19282c393a42Smrg if (fontconfig_path[0] == '\0') 19292c393a42Smrg { 1930a6844aabSmrg char *p; 1931ca08ab68Smrg if(!GetModuleFileName(NULL, (LPCH) fontconfig_path, sizeof(fontconfig_path))) 19322c393a42Smrg goto bail1; 1933ca08ab68Smrg p = strrchr ((const char *) fontconfig_path, '\\'); 19342c393a42Smrg if (p) *p = '\0'; 1935ca08ab68Smrg strcat ((char *) fontconfig_path, "\\fonts"); 19362c393a42Smrg } 19372c393a42Smrg#endif 19382c393a42Smrg dir = (FcChar8 *) FONTCONFIG_PATH; 19392c393a42Smrg path[i] = malloc (strlen ((char *) dir) + 1); 19402c393a42Smrg if (!path[i]) 19412c393a42Smrg goto bail1; 19422c393a42Smrg strcpy ((char *) path[i], (const char *) dir); 19432c393a42Smrg return path; 19442c393a42Smrg 19452c393a42Smrgbail1: 19462c393a42Smrg for (i = 0; path[i]; i++) 19472c393a42Smrg free (path[i]); 19482c393a42Smrg free (path); 19492c393a42Smrgbail0: 19502c393a42Smrg return 0; 19512c393a42Smrg} 19522c393a42Smrg 19532c393a42Smrgstatic void 19542c393a42SmrgFcConfigFreePath (FcChar8 **path) 19552c393a42Smrg{ 19562c393a42Smrg FcChar8 **p; 19572c393a42Smrg 19582c393a42Smrg for (p = path; *p; p++) 19592c393a42Smrg free (*p); 19602c393a42Smrg free (path); 19612c393a42Smrg} 19622c393a42Smrg 1963c9710b42Smrgstatic FcBool _FcConfigHomeEnabled = FcTrue; /* MT-goodenough */ 19642c393a42Smrg 19652c393a42SmrgFcChar8 * 19662c393a42SmrgFcConfigHome (void) 19672c393a42Smrg{ 19682c393a42Smrg if (_FcConfigHomeEnabled) 19692c393a42Smrg { 19702c393a42Smrg char *home = getenv ("HOME"); 19712c393a42Smrg 19722c393a42Smrg#ifdef _WIN32 19732c393a42Smrg if (home == NULL) 19742c393a42Smrg home = getenv ("USERPROFILE"); 19752c393a42Smrg#endif 19762c393a42Smrg 19772c393a42Smrg return (FcChar8 *) home; 19782c393a42Smrg } 19792c393a42Smrg return 0; 19802c393a42Smrg} 19812c393a42Smrg 1982ca08ab68SmrgFcChar8 * 1983ca08ab68SmrgFcConfigXdgCacheHome (void) 1984ca08ab68Smrg{ 1985ca08ab68Smrg const char *env = getenv ("XDG_CACHE_HOME"); 1986ca08ab68Smrg FcChar8 *ret = NULL; 1987ca08ab68Smrg 1988ca08ab68Smrg if (env) 1989ca08ab68Smrg ret = FcStrCopy ((const FcChar8 *)env); 1990ca08ab68Smrg else 1991ca08ab68Smrg { 1992ca08ab68Smrg const FcChar8 *home = FcConfigHome (); 1993ca08ab68Smrg size_t len = home ? strlen ((const char *)home) : 0; 1994ca08ab68Smrg 1995ca08ab68Smrg ret = malloc (len + 7 + 1); 1996ca08ab68Smrg if (ret) 1997ca08ab68Smrg { 1998ca08ab68Smrg memcpy (ret, home, len); 1999ca08ab68Smrg memcpy (&ret[len], FC_DIR_SEPARATOR_S ".cache", 7); 2000ca08ab68Smrg ret[len + 7] = 0; 2001ca08ab68Smrg } 2002ca08ab68Smrg } 2003ca08ab68Smrg 2004ca08ab68Smrg return ret; 2005ca08ab68Smrg} 2006ca08ab68Smrg 2007ca08ab68SmrgFcChar8 * 2008ca08ab68SmrgFcConfigXdgConfigHome (void) 2009ca08ab68Smrg{ 2010ca08ab68Smrg const char *env = getenv ("XDG_CONFIG_HOME"); 2011ca08ab68Smrg FcChar8 *ret = NULL; 2012ca08ab68Smrg 2013ca08ab68Smrg if (env) 2014ca08ab68Smrg ret = FcStrCopy ((const FcChar8 *)env); 2015ca08ab68Smrg else 2016ca08ab68Smrg { 2017ca08ab68Smrg const FcChar8 *home = FcConfigHome (); 2018ca08ab68Smrg size_t len = home ? strlen ((const char *)home) : 0; 2019ca08ab68Smrg 2020ca08ab68Smrg ret = malloc (len + 8 + 1); 2021ca08ab68Smrg if (ret) 2022ca08ab68Smrg { 2023ca08ab68Smrg memcpy (ret, home, len); 2024ca08ab68Smrg memcpy (&ret[len], FC_DIR_SEPARATOR_S ".config", 8); 2025ca08ab68Smrg ret[len + 8] = 0; 2026ca08ab68Smrg } 2027ca08ab68Smrg } 2028ca08ab68Smrg 2029ca08ab68Smrg return ret; 2030ca08ab68Smrg} 2031ca08ab68Smrg 2032ca08ab68SmrgFcChar8 * 2033ca08ab68SmrgFcConfigXdgDataHome (void) 2034ca08ab68Smrg{ 2035ca08ab68Smrg const char *env = getenv ("XDG_DATA_HOME"); 2036ca08ab68Smrg FcChar8 *ret = NULL; 2037ca08ab68Smrg 2038ca08ab68Smrg if (env) 2039ca08ab68Smrg ret = FcStrCopy ((const FcChar8 *)env); 2040ca08ab68Smrg else 2041ca08ab68Smrg { 2042ca08ab68Smrg const FcChar8 *home = FcConfigHome (); 2043ca08ab68Smrg size_t len = home ? strlen ((const char *)home) : 0; 2044ca08ab68Smrg 2045ca08ab68Smrg ret = malloc (len + 13 + 1); 2046ca08ab68Smrg if (ret) 2047ca08ab68Smrg { 2048ca08ab68Smrg memcpy (ret, home, len); 2049ca08ab68Smrg memcpy (&ret[len], FC_DIR_SEPARATOR_S ".local" FC_DIR_SEPARATOR_S "share", 13); 2050ca08ab68Smrg ret[len + 13] = 0; 2051ca08ab68Smrg } 2052ca08ab68Smrg } 2053ca08ab68Smrg 2054ca08ab68Smrg return ret; 2055ca08ab68Smrg} 2056ca08ab68Smrg 20572c393a42SmrgFcBool 20582c393a42SmrgFcConfigEnableHome (FcBool enable) 20592c393a42Smrg{ 20602c393a42Smrg FcBool prev = _FcConfigHomeEnabled; 20612c393a42Smrg _FcConfigHomeEnabled = enable; 20622c393a42Smrg return prev; 20632c393a42Smrg} 20642c393a42Smrg 20652c393a42SmrgFcChar8 * 20662c393a42SmrgFcConfigFilename (const FcChar8 *url) 20672c393a42Smrg{ 20682c393a42Smrg FcChar8 *file, *dir, **path, **p; 20692c393a42Smrg 20702c393a42Smrg if (!url || !*url) 20712c393a42Smrg { 20722c393a42Smrg url = (FcChar8 *) getenv ("FONTCONFIG_FILE"); 20732c393a42Smrg if (!url) 20742c393a42Smrg url = (FcChar8 *) FONTCONFIG_FILE; 20752c393a42Smrg } 20762c393a42Smrg file = 0; 20772c393a42Smrg 20782c393a42Smrg#ifdef _WIN32 20792c393a42Smrg if (isalpha (*url) && 20802c393a42Smrg url[1] == ':' && 20812c393a42Smrg (url[2] == '/' || url[2] == '\\')) 20822c393a42Smrg goto absolute_path; 20832c393a42Smrg#endif 20842c393a42Smrg 20852c393a42Smrg switch (*url) { 20862c393a42Smrg case '~': 20872c393a42Smrg dir = FcConfigHome (); 20882c393a42Smrg if (dir) 20892c393a42Smrg file = FcConfigFileExists (dir, url + 1); 20902c393a42Smrg else 20912c393a42Smrg file = 0; 20922c393a42Smrg break; 20932c393a42Smrg#ifdef _WIN32 20942c393a42Smrg case '\\': 20952c393a42Smrg absolute_path: 20962c393a42Smrg#endif 20972c393a42Smrg case '/': 20982c393a42Smrg file = FcConfigFileExists (0, url); 20992c393a42Smrg break; 21002c393a42Smrg default: 21012c393a42Smrg path = FcConfigGetPath (); 21022c393a42Smrg if (!path) 2103ca08ab68Smrg return NULL; 21042c393a42Smrg for (p = path; *p; p++) 21052c393a42Smrg { 21062c393a42Smrg file = FcConfigFileExists (*p, url); 21072c393a42Smrg if (file) 21082c393a42Smrg break; 21092c393a42Smrg } 21102c393a42Smrg FcConfigFreePath (path); 21112c393a42Smrg break; 21122c393a42Smrg } 2113ca08ab68Smrg 21142c393a42Smrg return file; 21152c393a42Smrg} 21162c393a42Smrg 21172c393a42Smrg/* 21182c393a42Smrg * Manage the application-specific fonts 21192c393a42Smrg */ 21202c393a42Smrg 21212c393a42SmrgFcBool 21222c393a42SmrgFcConfigAppFontAddFile (FcConfig *config, 21232c393a42Smrg const FcChar8 *file) 21242c393a42Smrg{ 21252c393a42Smrg FcFontSet *set; 21262c393a42Smrg FcStrSet *subdirs; 21272c393a42Smrg FcStrList *sublist; 21282c393a42Smrg FcChar8 *subdir; 21292c393a42Smrg 21302c393a42Smrg if (!config) 21312c393a42Smrg { 21322c393a42Smrg config = FcConfigGetCurrent (); 21332c393a42Smrg if (!config) 21342c393a42Smrg return FcFalse; 21352c393a42Smrg } 21362c393a42Smrg 21372c393a42Smrg subdirs = FcStrSetCreate (); 21382c393a42Smrg if (!subdirs) 21392c393a42Smrg return FcFalse; 2140ca08ab68Smrg 21412c393a42Smrg set = FcConfigGetFonts (config, FcSetApplication); 21422c393a42Smrg if (!set) 21432c393a42Smrg { 21442c393a42Smrg set = FcFontSetCreate (); 21452c393a42Smrg if (!set) 21462c393a42Smrg { 21472c393a42Smrg FcStrSetDestroy (subdirs); 21482c393a42Smrg return FcFalse; 21492c393a42Smrg } 21502c393a42Smrg FcConfigSetFonts (config, set, FcSetApplication); 21512c393a42Smrg } 21522c393a42Smrg 21532c393a42Smrg if (!FcFileScanConfig (set, subdirs, config->blanks, file, config)) 21542c393a42Smrg { 21552c393a42Smrg FcStrSetDestroy (subdirs); 21562c393a42Smrg return FcFalse; 21572c393a42Smrg } 21582c393a42Smrg if ((sublist = FcStrListCreate (subdirs))) 21592c393a42Smrg { 21602c393a42Smrg while ((subdir = FcStrListNext (sublist))) 21612c393a42Smrg { 21622c393a42Smrg FcConfigAppFontAddDir (config, subdir); 21632c393a42Smrg } 21642c393a42Smrg FcStrListDone (sublist); 21652c393a42Smrg } 21662c393a42Smrg FcStrSetDestroy (subdirs); 21672c393a42Smrg return FcTrue; 21682c393a42Smrg} 21692c393a42Smrg 21702c393a42SmrgFcBool 21712c393a42SmrgFcConfigAppFontAddDir (FcConfig *config, 21722c393a42Smrg const FcChar8 *dir) 21732c393a42Smrg{ 21742c393a42Smrg FcFontSet *set; 21752c393a42Smrg FcStrSet *dirs; 2176ca08ab68Smrg 21772c393a42Smrg if (!config) 21782c393a42Smrg { 21792c393a42Smrg config = FcConfigGetCurrent (); 21802c393a42Smrg if (!config) 21812c393a42Smrg return FcFalse; 21822c393a42Smrg } 21832c393a42Smrg 21842c393a42Smrg dirs = FcStrSetCreate (); 21852c393a42Smrg if (!dirs) 21862c393a42Smrg return FcFalse; 2187ca08ab68Smrg 21882c393a42Smrg set = FcConfigGetFonts (config, FcSetApplication); 21892c393a42Smrg if (!set) 21902c393a42Smrg { 21912c393a42Smrg set = FcFontSetCreate (); 21922c393a42Smrg if (!set) 21932c393a42Smrg { 21942c393a42Smrg FcStrSetDestroy (dirs); 21952c393a42Smrg return FcFalse; 21962c393a42Smrg } 21972c393a42Smrg FcConfigSetFonts (config, set, FcSetApplication); 21982c393a42Smrg } 2199ca08ab68Smrg 22002c393a42Smrg FcStrSetAddFilename (dirs, dir); 2201ca08ab68Smrg 22022c393a42Smrg if (!FcConfigAddDirList (config, FcSetApplication, dirs)) 22032c393a42Smrg { 22042c393a42Smrg FcStrSetDestroy (dirs); 22052c393a42Smrg return FcFalse; 22062c393a42Smrg } 22072c393a42Smrg FcStrSetDestroy (dirs); 22082c393a42Smrg return FcTrue; 22092c393a42Smrg} 22102c393a42Smrg 22112c393a42Smrgvoid 22122c393a42SmrgFcConfigAppFontClear (FcConfig *config) 22132c393a42Smrg{ 22142c393a42Smrg if (!config) 22152c393a42Smrg { 22162c393a42Smrg config = FcConfigGetCurrent (); 22172c393a42Smrg if (!config) 22182c393a42Smrg return; 22192c393a42Smrg } 22202c393a42Smrg 22212c393a42Smrg FcConfigSetFonts (config, 0, FcSetApplication); 22222c393a42Smrg} 22232c393a42Smrg 22242c393a42Smrg/* 22252c393a42Smrg * Manage filename-based font source selectors 22262c393a42Smrg */ 22272c393a42Smrg 22282c393a42SmrgFcBool 22292c393a42SmrgFcConfigGlobAdd (FcConfig *config, 22302c393a42Smrg const FcChar8 *glob, 22312c393a42Smrg FcBool accept) 22322c393a42Smrg{ 22332c393a42Smrg FcStrSet *set = accept ? config->acceptGlobs : config->rejectGlobs; 22342c393a42Smrg 22352c393a42Smrg return FcStrSetAdd (set, glob); 22362c393a42Smrg} 22372c393a42Smrg 22382c393a42Smrgstatic FcBool 22392c393a42SmrgFcConfigGlobsMatch (const FcStrSet *globs, 22402c393a42Smrg const FcChar8 *string) 22412c393a42Smrg{ 22422c393a42Smrg int i; 22432c393a42Smrg 22442c393a42Smrg for (i = 0; i < globs->num; i++) 2245c9710b42Smrg if (FcStrGlobMatch (globs->strs[i], string)) 22462c393a42Smrg return FcTrue; 22472c393a42Smrg return FcFalse; 22482c393a42Smrg} 22492c393a42Smrg 22502c393a42SmrgFcBool 22512c393a42SmrgFcConfigAcceptFilename (FcConfig *config, 22522c393a42Smrg const FcChar8 *filename) 22532c393a42Smrg{ 22542c393a42Smrg if (FcConfigGlobsMatch (config->acceptGlobs, filename)) 22552c393a42Smrg return FcTrue; 22562c393a42Smrg if (FcConfigGlobsMatch (config->rejectGlobs, filename)) 22572c393a42Smrg return FcFalse; 22582c393a42Smrg return FcTrue; 22592c393a42Smrg} 22602c393a42Smrg 22612c393a42Smrg/* 22622c393a42Smrg * Manage font-pattern based font source selectors 22632c393a42Smrg */ 22642c393a42Smrg 22652c393a42SmrgFcBool 22662c393a42SmrgFcConfigPatternsAdd (FcConfig *config, 22672c393a42Smrg FcPattern *pattern, 22682c393a42Smrg FcBool accept) 22692c393a42Smrg{ 22702c393a42Smrg FcFontSet *set = accept ? config->acceptPatterns : config->rejectPatterns; 22712c393a42Smrg 22722c393a42Smrg return FcFontSetAdd (set, pattern); 22732c393a42Smrg} 22742c393a42Smrg 22752c393a42Smrgstatic FcBool 22762c393a42SmrgFcConfigPatternsMatch (const FcFontSet *patterns, 22772c393a42Smrg const FcPattern *font) 22782c393a42Smrg{ 22792c393a42Smrg int i; 2280ca08ab68Smrg 22812c393a42Smrg for (i = 0; i < patterns->nfont; i++) 22822c393a42Smrg if (FcListPatternMatchAny (patterns->fonts[i], font)) 22832c393a42Smrg return FcTrue; 22842c393a42Smrg return FcFalse; 22852c393a42Smrg} 22862c393a42Smrg 22872c393a42SmrgFcBool 22882c393a42SmrgFcConfigAcceptFont (FcConfig *config, 22892c393a42Smrg const FcPattern *font) 22902c393a42Smrg{ 22912c393a42Smrg if (FcConfigPatternsMatch (config->acceptPatterns, font)) 22922c393a42Smrg return FcTrue; 22932c393a42Smrg if (FcConfigPatternsMatch (config->rejectPatterns, font)) 22942c393a42Smrg return FcFalse; 22952c393a42Smrg return FcTrue; 22962c393a42Smrg} 2297c9710b42Smrg 2298c9710b42Smrgconst FcChar8 * 2299c9710b42SmrgFcConfigGetSysRoot (const FcConfig *config) 2300c9710b42Smrg{ 2301c9710b42Smrg if (!config) 2302c9710b42Smrg { 2303c9710b42Smrg config = FcConfigGetCurrent (); 2304c9710b42Smrg if (!config) 2305c9710b42Smrg return NULL; 2306c9710b42Smrg } 2307c9710b42Smrg 2308c9710b42Smrg return config->sysRoot; 2309c9710b42Smrg} 2310c9710b42Smrg 2311c9710b42Smrgvoid 2312c9710b42SmrgFcConfigSetSysRoot (FcConfig *config, 2313c9710b42Smrg const FcChar8 *sysroot) 2314c9710b42Smrg{ 2315c9710b42Smrg FcChar8 *s; 2316c9710b42Smrg FcBool init = FcFalse; 2317c9710b42Smrg 2318c9710b42Smrg if (!config) 2319c9710b42Smrg { 2320c9710b42Smrg /* We can't use FcConfigGetCurrent() here to ensure 2321c9710b42Smrg * the sysroot is set prior to initialize FcConfig, 2322c9710b42Smrg * to avoid loading caches from non-sysroot dirs. 2323c9710b42Smrg * So postpone the initialization later. 2324c9710b42Smrg */ 2325c9710b42Smrg config = fc_atomic_ptr_get (&_fcConfig); 2326c9710b42Smrg if (!config) 2327c9710b42Smrg { 2328c9710b42Smrg config = FcConfigCreate (); 2329c9710b42Smrg if (!config) 2330c9710b42Smrg return; 2331c9710b42Smrg init = FcTrue; 2332c9710b42Smrg } 2333c9710b42Smrg } 2334c9710b42Smrg 2335c9710b42Smrg s = FcStrCopyFilename (sysroot); 2336c9710b42Smrg if (!s) 2337c9710b42Smrg return; 2338c9710b42Smrg 2339c9710b42Smrg if (config->sysRoot) 2340c9710b42Smrg FcStrFree (config->sysRoot); 2341c9710b42Smrg 2342c9710b42Smrg config->sysRoot = s; 2343c9710b42Smrg if (init) 2344c9710b42Smrg { 2345c9710b42Smrg config = FcInitLoadOwnConfigAndFonts (config); 2346c9710b42Smrg FcConfigSetCurrent (config); 2347c9710b42Smrg } 2348c9710b42Smrg} 2349c9710b42Smrg 23502c393a42Smrg#define __fccfg__ 23512c393a42Smrg#include "fcaliastail.h" 23522c393a42Smrg#undef __fccfg__ 2353