fccfg.c revision 18bd4a06
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> 3018bd4a06Smrg#include "../fc-blanks/fcblanks.h" 312c393a42Smrg 322c393a42Smrg#if defined (_WIN32) && !defined (R_OK) 332c393a42Smrg#define R_OK 4 342c393a42Smrg#endif 352c393a42Smrg 36c9710b42Smrgstatic FcConfig *_fcConfig; /* MT-safe */ 37c9710b42Smrg 38c9710b42Smrgstatic FcConfig * 39c9710b42SmrgFcConfigEnsure (void) 40c9710b42Smrg{ 41c9710b42Smrg FcConfig *config; 42c9710b42Smrgretry: 43c9710b42Smrg config = fc_atomic_ptr_get (&_fcConfig); 44c9710b42Smrg if (!config) 45c9710b42Smrg { 46c9710b42Smrg config = FcInitLoadConfigAndFonts (); 47c9710b42Smrg 48c9710b42Smrg if (!fc_atomic_ptr_cmpexch (&_fcConfig, NULL, config)) { 49c9710b42Smrg FcConfigDestroy (config); 50c9710b42Smrg goto retry; 51c9710b42Smrg } 52c9710b42Smrg } 53c9710b42Smrg return config; 54c9710b42Smrg} 55c9710b42Smrg 56c9710b42SmrgFcBool 57c9710b42SmrgFcConfigInit (void) 58c9710b42Smrg{ 59c9710b42Smrg return FcConfigEnsure () ? FcTrue : FcFalse; 60c9710b42Smrg} 61c9710b42Smrg 62c9710b42Smrgvoid 63c9710b42SmrgFcConfigFini (void) 64c9710b42Smrg{ 65c9710b42Smrg FcConfig *cfg = fc_atomic_ptr_get (&_fcConfig); 66c9710b42Smrg if (cfg && fc_atomic_ptr_cmpexch (&_fcConfig, cfg, NULL)) 67c9710b42Smrg FcConfigDestroy (cfg); 68c9710b42Smrg} 69c9710b42Smrg 702c393a42Smrg 712c393a42SmrgFcConfig * 722c393a42SmrgFcConfigCreate (void) 732c393a42Smrg{ 742c393a42Smrg FcSetName set; 752c393a42Smrg FcConfig *config; 762c393a42Smrg 772c393a42Smrg config = malloc (sizeof (FcConfig)); 782c393a42Smrg if (!config) 792c393a42Smrg goto bail0; 80ca08ab68Smrg 812c393a42Smrg config->configDirs = FcStrSetCreate (); 822c393a42Smrg if (!config->configDirs) 832c393a42Smrg goto bail1; 84ca08ab68Smrg 852c393a42Smrg config->configFiles = FcStrSetCreate (); 862c393a42Smrg if (!config->configFiles) 872c393a42Smrg goto bail2; 88ca08ab68Smrg 892c393a42Smrg config->fontDirs = FcStrSetCreate (); 902c393a42Smrg if (!config->fontDirs) 912c393a42Smrg goto bail3; 92ca08ab68Smrg 932c393a42Smrg config->acceptGlobs = FcStrSetCreate (); 942c393a42Smrg if (!config->acceptGlobs) 952c393a42Smrg goto bail4; 962c393a42Smrg 972c393a42Smrg config->rejectGlobs = FcStrSetCreate (); 982c393a42Smrg if (!config->rejectGlobs) 992c393a42Smrg goto bail5; 1002c393a42Smrg 1012c393a42Smrg config->acceptPatterns = FcFontSetCreate (); 1022c393a42Smrg if (!config->acceptPatterns) 1032c393a42Smrg goto bail6; 104ca08ab68Smrg 1052c393a42Smrg config->rejectPatterns = FcFontSetCreate (); 1062c393a42Smrg if (!config->rejectPatterns) 1072c393a42Smrg goto bail7; 1082c393a42Smrg 1092c393a42Smrg config->cacheDirs = FcStrSetCreate (); 1102c393a42Smrg if (!config->cacheDirs) 1112c393a42Smrg goto bail8; 112ca08ab68Smrg 11318bd4a06Smrg config->blanks = &fcBlanks; 1142c393a42Smrg 1152c393a42Smrg config->substPattern = 0; 1162c393a42Smrg config->substFont = 0; 1172c393a42Smrg config->substScan = 0; 1182c393a42Smrg config->maxObjects = 0; 1192c393a42Smrg for (set = FcSetSystem; set <= FcSetApplication; set++) 1202c393a42Smrg config->fonts[set] = 0; 1212c393a42Smrg 1222c393a42Smrg config->rescanTime = time(0); 123ca08ab68Smrg config->rescanInterval = 30; 124a6844aabSmrg 125a6844aabSmrg config->expr_pool = NULL; 126a6844aabSmrg 127c9710b42Smrg config->sysRoot = NULL; 128c9710b42Smrg 129c9710b42Smrg FcRefInit (&config->ref, 1); 130ca08ab68Smrg 1312c393a42Smrg return config; 1322c393a42Smrg 1332c393a42Smrgbail8: 1342c393a42Smrg FcFontSetDestroy (config->rejectPatterns); 1352c393a42Smrgbail7: 1362c393a42Smrg FcFontSetDestroy (config->acceptPatterns); 1372c393a42Smrgbail6: 1382c393a42Smrg FcStrSetDestroy (config->rejectGlobs); 1392c393a42Smrgbail5: 1402c393a42Smrg FcStrSetDestroy (config->acceptGlobs); 1412c393a42Smrgbail4: 1422c393a42Smrg FcStrSetDestroy (config->fontDirs); 1432c393a42Smrgbail3: 1442c393a42Smrg FcStrSetDestroy (config->configFiles); 1452c393a42Smrgbail2: 1462c393a42Smrg FcStrSetDestroy (config->configDirs); 1472c393a42Smrgbail1: 1482c393a42Smrg free (config); 1492c393a42Smrgbail0: 1502c393a42Smrg return 0; 1512c393a42Smrg} 1522c393a42Smrg 1532c393a42Smrgstatic FcFileTime 1542c393a42SmrgFcConfigNewestFile (FcStrSet *files) 1552c393a42Smrg{ 1562c393a42Smrg FcStrList *list = FcStrListCreate (files); 1572c393a42Smrg FcFileTime newest = { 0, FcFalse }; 1582c393a42Smrg FcChar8 *file; 1592c393a42Smrg struct stat statb; 1602c393a42Smrg 1612c393a42Smrg if (list) 1622c393a42Smrg { 1632c393a42Smrg while ((file = FcStrListNext (list))) 164ca08ab68Smrg if (FcStat (file, &statb) == 0) 1652c393a42Smrg if (!newest.set || statb.st_mtime - newest.time > 0) 1662c393a42Smrg { 1672c393a42Smrg newest.set = FcTrue; 1682c393a42Smrg newest.time = statb.st_mtime; 1692c393a42Smrg } 1702c393a42Smrg FcStrListDone (list); 1712c393a42Smrg } 1722c393a42Smrg return newest; 1732c393a42Smrg} 1742c393a42Smrg 1752c393a42SmrgFcBool 1762c393a42SmrgFcConfigUptoDate (FcConfig *config) 1772c393a42Smrg{ 1782c393a42Smrg FcFileTime config_time, config_dir_time, font_time; 1792c393a42Smrg time_t now = time(0); 1802c393a42Smrg if (!config) 1812c393a42Smrg { 1822c393a42Smrg config = FcConfigGetCurrent (); 1832c393a42Smrg if (!config) 1842c393a42Smrg return FcFalse; 1852c393a42Smrg } 1862c393a42Smrg config_time = FcConfigNewestFile (config->configFiles); 1872c393a42Smrg config_dir_time = FcConfigNewestFile (config->configDirs); 1882c393a42Smrg font_time = FcConfigNewestFile (config->fontDirs); 1892c393a42Smrg if ((config_time.set && config_time.time - config->rescanTime > 0) || 1902c393a42Smrg (config_dir_time.set && (config_dir_time.time - config->rescanTime) > 0) || 1912c393a42Smrg (font_time.set && (font_time.time - config->rescanTime) > 0)) 1922c393a42Smrg { 1932c393a42Smrg /* We need to check for potential clock problems here (OLPC ticket #6046) */ 1942c393a42Smrg if ((config_time.set && (config_time.time - now) > 0) || 1952c393a42Smrg (config_dir_time.set && (config_dir_time.time - now) > 0) || 1962c393a42Smrg (font_time.set && (font_time.time - now) > 0)) 1972c393a42Smrg { 1982c393a42Smrg fprintf (stderr, 199c9710b42Smrg "Fontconfig warning: Directory/file mtime in the future. New fonts may not be detected.\n"); 2002c393a42Smrg config->rescanTime = now; 2012c393a42Smrg return FcTrue; 2022c393a42Smrg } 2032c393a42Smrg else 2042c393a42Smrg return FcFalse; 2052c393a42Smrg } 2062c393a42Smrg config->rescanTime = now; 2072c393a42Smrg return FcTrue; 2082c393a42Smrg} 2092c393a42Smrg 2102c393a42Smrgstatic void 2112c393a42SmrgFcSubstDestroy (FcSubst *s) 2122c393a42Smrg{ 2132c393a42Smrg FcSubst *n; 214ca08ab68Smrg 2152c393a42Smrg while (s) 2162c393a42Smrg { 2172c393a42Smrg n = s->next; 2186fc018e4Smrg if (s->rule) 2196fc018e4Smrg FcRuleDestroy (s->rule); 2202c393a42Smrg free (s); 2212c393a42Smrg s = n; 2222c393a42Smrg } 2232c393a42Smrg} 2242c393a42Smrg 225a6844aabSmrgFcExpr * 226a6844aabSmrgFcConfigAllocExpr (FcConfig *config) 227a6844aabSmrg{ 2286fc018e4Smrg if (!config->expr_pool || config->expr_pool->next == config->expr_pool->end) 2296fc018e4Smrg { 2306fc018e4Smrg FcExprPage *new_page; 231a6844aabSmrg 2326fc018e4Smrg new_page = malloc (sizeof (FcExprPage)); 2336fc018e4Smrg if (!new_page) 2346fc018e4Smrg return 0; 235a6844aabSmrg 2366fc018e4Smrg new_page->next_page = config->expr_pool; 2376fc018e4Smrg new_page->next = new_page->exprs; 2386fc018e4Smrg config->expr_pool = new_page; 2396fc018e4Smrg } 240a6844aabSmrg 2416fc018e4Smrg return config->expr_pool->next++; 242a6844aabSmrg} 243a6844aabSmrg 244a6844aabSmrgFcConfig * 245a6844aabSmrgFcConfigReference (FcConfig *config) 246a6844aabSmrg{ 247a6844aabSmrg if (!config) 248a6844aabSmrg { 249a6844aabSmrg config = FcConfigGetCurrent (); 250a6844aabSmrg if (!config) 251a6844aabSmrg return 0; 252a6844aabSmrg } 253a6844aabSmrg 254c9710b42Smrg FcRefInc (&config->ref); 255a6844aabSmrg 256a6844aabSmrg return config; 257a6844aabSmrg} 258a6844aabSmrg 2592c393a42Smrgvoid 2602c393a42SmrgFcConfigDestroy (FcConfig *config) 2612c393a42Smrg{ 2622c393a42Smrg FcSetName set; 263a6844aabSmrg FcExprPage *page; 264a6844aabSmrg 265c9710b42Smrg if (FcRefDec (&config->ref) != 1) 266a6844aabSmrg return; 2672c393a42Smrg 268c9710b42Smrg (void) fc_atomic_ptr_cmpexch (&_fcConfig, config, NULL); 2692c393a42Smrg 2702c393a42Smrg FcStrSetDestroy (config->configDirs); 2712c393a42Smrg FcStrSetDestroy (config->fontDirs); 2722c393a42Smrg FcStrSetDestroy (config->cacheDirs); 2732c393a42Smrg FcStrSetDestroy (config->configFiles); 2742c393a42Smrg FcStrSetDestroy (config->acceptGlobs); 2752c393a42Smrg FcStrSetDestroy (config->rejectGlobs); 2762c393a42Smrg FcFontSetDestroy (config->acceptPatterns); 2772c393a42Smrg FcFontSetDestroy (config->rejectPatterns); 2782c393a42Smrg 2792c393a42Smrg if (config->blanks) 2802c393a42Smrg FcBlanksDestroy (config->blanks); 2812c393a42Smrg 2822c393a42Smrg FcSubstDestroy (config->substPattern); 2832c393a42Smrg FcSubstDestroy (config->substFont); 2842c393a42Smrg FcSubstDestroy (config->substScan); 2852c393a42Smrg for (set = FcSetSystem; set <= FcSetApplication; set++) 2862c393a42Smrg if (config->fonts[set]) 2872c393a42Smrg FcFontSetDestroy (config->fonts[set]); 2882c393a42Smrg 289a6844aabSmrg page = config->expr_pool; 290a6844aabSmrg while (page) 291a6844aabSmrg { 292a6844aabSmrg FcExprPage *next = page->next_page; 293a6844aabSmrg free (page); 294a6844aabSmrg page = next; 295a6844aabSmrg } 296c9710b42Smrg if (config->sysRoot) 297c9710b42Smrg FcStrFree (config->sysRoot); 298a6844aabSmrg 2992c393a42Smrg free (config); 3002c393a42Smrg} 3012c393a42Smrg 3022c393a42Smrg/* 3032c393a42Smrg * Add cache to configuration, adding fonts and directories 3042c393a42Smrg */ 3052c393a42Smrg 3062c393a42SmrgFcBool 307ca08ab68SmrgFcConfigAddCache (FcConfig *config, FcCache *cache, 3082c393a42Smrg FcSetName set, FcStrSet *dirSet) 3092c393a42Smrg{ 3102c393a42Smrg FcFontSet *fs; 3112c393a42Smrg intptr_t *dirs; 3122c393a42Smrg int i; 3132c393a42Smrg 3142c393a42Smrg /* 3152c393a42Smrg * Add fonts 3162c393a42Smrg */ 3172c393a42Smrg fs = FcCacheSet (cache); 3182c393a42Smrg if (fs) 3192c393a42Smrg { 3202c393a42Smrg int nref = 0; 3212c393a42Smrg 3222c393a42Smrg for (i = 0; i < fs->nfont; i++) 3232c393a42Smrg { 3242c393a42Smrg FcPattern *font = FcFontSetFont (fs, i); 3252c393a42Smrg FcChar8 *font_file; 3262c393a42Smrg 3272c393a42Smrg /* 3282c393a42Smrg * Check to see if font is banned by filename 3292c393a42Smrg */ 3302c393a42Smrg if (FcPatternObjectGetString (font, FC_FILE_OBJECT, 3312c393a42Smrg 0, &font_file) == FcResultMatch && 3322c393a42Smrg !FcConfigAcceptFilename (config, font_file)) 3332c393a42Smrg { 3342c393a42Smrg continue; 3352c393a42Smrg } 3362c393a42Smrg 3372c393a42Smrg /* 3382c393a42Smrg * Check to see if font is banned by pattern 3392c393a42Smrg */ 3402c393a42Smrg if (!FcConfigAcceptFont (config, font)) 3412c393a42Smrg continue; 3422c393a42Smrg 343c9710b42Smrg if (FcFontSetAdd (config->fonts[set], font)) 344c9710b42Smrg nref++; 3452c393a42Smrg } 3462c393a42Smrg FcDirCacheReference (cache, nref); 3472c393a42Smrg } 3482c393a42Smrg 3492c393a42Smrg /* 3502c393a42Smrg * Add directories 3512c393a42Smrg */ 3522c393a42Smrg dirs = FcCacheDirs (cache); 3532c393a42Smrg if (dirs) 3542c393a42Smrg { 3552c393a42Smrg for (i = 0; i < cache->dirs_count; i++) 3562c393a42Smrg { 3572c393a42Smrg FcChar8 *dir = FcOffsetToPtr (dirs, dirs[i], FcChar8); 3582c393a42Smrg if (FcConfigAcceptFilename (config, dir)) 3592c393a42Smrg FcStrSetAddFilename (dirSet, dir); 3602c393a42Smrg } 3612c393a42Smrg } 3622c393a42Smrg return FcTrue; 3632c393a42Smrg} 3642c393a42Smrg 3652c393a42Smrgstatic FcBool 3662c393a42SmrgFcConfigAddDirList (FcConfig *config, FcSetName set, FcStrSet *dirSet) 3672c393a42Smrg{ 3682c393a42Smrg FcStrList *dirlist; 3692c393a42Smrg FcChar8 *dir; 3702c393a42Smrg FcCache *cache; 371ca08ab68Smrg 3722c393a42Smrg dirlist = FcStrListCreate (dirSet); 3732c393a42Smrg if (!dirlist) 3742c393a42Smrg return FcFalse; 3752c393a42Smrg 3762c393a42Smrg while ((dir = FcStrListNext (dirlist))) 3772c393a42Smrg { 3782c393a42Smrg if (FcDebug () & FC_DBG_FONTSET) 37918bd4a06Smrg printf ("adding fonts from %s\n", dir); 3802c393a42Smrg cache = FcDirCacheRead (dir, FcFalse, config); 3812c393a42Smrg if (!cache) 3822c393a42Smrg continue; 3832c393a42Smrg FcConfigAddCache (config, cache, set, dirSet); 3842c393a42Smrg FcDirCacheUnload (cache); 3852c393a42Smrg } 3862c393a42Smrg FcStrListDone (dirlist); 3872c393a42Smrg return FcTrue; 3882c393a42Smrg} 3892c393a42Smrg 3902c393a42Smrg/* 3912c393a42Smrg * Scan the current list of directories in the configuration 3922c393a42Smrg * and build the set of available fonts. 3932c393a42Smrg */ 3942c393a42Smrg 3952c393a42SmrgFcBool 3962c393a42SmrgFcConfigBuildFonts (FcConfig *config) 3972c393a42Smrg{ 3982c393a42Smrg FcFontSet *fonts; 3992c393a42Smrg 4002c393a42Smrg if (!config) 4012c393a42Smrg { 4022c393a42Smrg config = FcConfigGetCurrent (); 4032c393a42Smrg if (!config) 4042c393a42Smrg return FcFalse; 4052c393a42Smrg } 4062c393a42Smrg 4072c393a42Smrg fonts = FcFontSetCreate (); 4082c393a42Smrg if (!fonts) 4092c393a42Smrg return FcFalse; 410ca08ab68Smrg 4112c393a42Smrg FcConfigSetFonts (config, fonts, FcSetSystem); 412ca08ab68Smrg 4132c393a42Smrg if (!FcConfigAddDirList (config, FcSetSystem, config->fontDirs)) 4142c393a42Smrg return FcFalse; 4152c393a42Smrg if (FcDebug () & FC_DBG_FONTSET) 4162c393a42Smrg FcFontSetPrint (fonts); 4172c393a42Smrg return FcTrue; 4182c393a42Smrg} 4192c393a42Smrg 4202c393a42SmrgFcBool 4212c393a42SmrgFcConfigSetCurrent (FcConfig *config) 4222c393a42Smrg{ 423c9710b42Smrg FcConfig *cfg; 424c9710b42Smrg 425c9710b42Smrgretry: 426c9710b42Smrg cfg = fc_atomic_ptr_get (&_fcConfig); 427c9710b42Smrg 428c9710b42Smrg if (config == cfg) 4292c393a42Smrg return FcTrue; 4302c393a42Smrg 431c9710b42Smrg if (config && !config->fonts[FcSetSystem]) 4322c393a42Smrg if (!FcConfigBuildFonts (config)) 4332c393a42Smrg return FcFalse; 4342c393a42Smrg 435c9710b42Smrg if (!fc_atomic_ptr_cmpexch (&_fcConfig, cfg, config)) 436c9710b42Smrg goto retry; 437c9710b42Smrg 43818bd4a06Smrg FcConfigReference (config); 439c9710b42Smrg if (cfg) 440c9710b42Smrg FcConfigDestroy (cfg); 441c9710b42Smrg 4422c393a42Smrg return FcTrue; 4432c393a42Smrg} 4442c393a42Smrg 4452c393a42SmrgFcConfig * 4462c393a42SmrgFcConfigGetCurrent (void) 4472c393a42Smrg{ 448c9710b42Smrg return FcConfigEnsure (); 4492c393a42Smrg} 4502c393a42Smrg 4512c393a42SmrgFcBool 4522c393a42SmrgFcConfigAddConfigDir (FcConfig *config, 4532c393a42Smrg const FcChar8 *d) 4542c393a42Smrg{ 4552c393a42Smrg return FcStrSetAddFilename (config->configDirs, d); 4562c393a42Smrg} 4572c393a42Smrg 4582c393a42SmrgFcStrList * 4592c393a42SmrgFcConfigGetConfigDirs (FcConfig *config) 4602c393a42Smrg{ 4612c393a42Smrg if (!config) 4622c393a42Smrg { 4632c393a42Smrg config = FcConfigGetCurrent (); 4642c393a42Smrg if (!config) 4652c393a42Smrg return 0; 4662c393a42Smrg } 4672c393a42Smrg return FcStrListCreate (config->configDirs); 4682c393a42Smrg} 4692c393a42Smrg 4702c393a42SmrgFcBool 4712c393a42SmrgFcConfigAddFontDir (FcConfig *config, 4722c393a42Smrg const FcChar8 *d) 4732c393a42Smrg{ 4742c393a42Smrg return FcStrSetAddFilename (config->fontDirs, d); 4752c393a42Smrg} 4762c393a42Smrg 4772c393a42SmrgFcBool 4782c393a42SmrgFcConfigAddDir (FcConfig *config, 4792c393a42Smrg const FcChar8 *d) 4802c393a42Smrg{ 481ca08ab68Smrg return (FcConfigAddConfigDir (config, d) && 4822c393a42Smrg FcConfigAddFontDir (config, d)); 4832c393a42Smrg} 4842c393a42Smrg 4852c393a42SmrgFcStrList * 4862c393a42SmrgFcConfigGetFontDirs (FcConfig *config) 4872c393a42Smrg{ 4882c393a42Smrg if (!config) 4892c393a42Smrg { 4902c393a42Smrg config = FcConfigGetCurrent (); 4912c393a42Smrg if (!config) 4922c393a42Smrg return 0; 4932c393a42Smrg } 4942c393a42Smrg return FcStrListCreate (config->fontDirs); 4952c393a42Smrg} 4962c393a42Smrg 4972c393a42SmrgFcBool 4982c393a42SmrgFcConfigAddCacheDir (FcConfig *config, 4992c393a42Smrg const FcChar8 *d) 5002c393a42Smrg{ 5012c393a42Smrg return FcStrSetAddFilename (config->cacheDirs, d); 5022c393a42Smrg} 5032c393a42Smrg 5042c393a42SmrgFcStrList * 505ca08ab68SmrgFcConfigGetCacheDirs (const FcConfig *config) 5062c393a42Smrg{ 5072c393a42Smrg if (!config) 5082c393a42Smrg { 5092c393a42Smrg config = FcConfigGetCurrent (); 5102c393a42Smrg if (!config) 5112c393a42Smrg return 0; 5122c393a42Smrg } 5132c393a42Smrg return FcStrListCreate (config->cacheDirs); 5142c393a42Smrg} 515ca08ab68Smrg 5162c393a42SmrgFcBool 5172c393a42SmrgFcConfigAddConfigFile (FcConfig *config, 5182c393a42Smrg const FcChar8 *f) 5192c393a42Smrg{ 5202c393a42Smrg FcBool ret; 5212c393a42Smrg FcChar8 *file = FcConfigFilename (f); 522ca08ab68Smrg 5232c393a42Smrg if (!file) 5242c393a42Smrg return FcFalse; 525ca08ab68Smrg 5262c393a42Smrg ret = FcStrSetAdd (config->configFiles, file); 5272c393a42Smrg FcStrFree (file); 5282c393a42Smrg return ret; 5292c393a42Smrg} 5302c393a42Smrg 5312c393a42SmrgFcStrList * 5322c393a42SmrgFcConfigGetConfigFiles (FcConfig *config) 5332c393a42Smrg{ 5342c393a42Smrg if (!config) 5352c393a42Smrg { 5362c393a42Smrg config = FcConfigGetCurrent (); 5372c393a42Smrg if (!config) 5382c393a42Smrg return 0; 5392c393a42Smrg } 5402c393a42Smrg return FcStrListCreate (config->configFiles); 5412c393a42Smrg} 5422c393a42Smrg 5432c393a42SmrgFcChar8 * 544c9710b42SmrgFcConfigGetCache (FcConfig *config FC_UNUSED) 5452c393a42Smrg{ 5462c393a42Smrg return NULL; 5472c393a42Smrg} 5482c393a42Smrg 5492c393a42SmrgFcFontSet * 5502c393a42SmrgFcConfigGetFonts (FcConfig *config, 5512c393a42Smrg FcSetName set) 5522c393a42Smrg{ 5532c393a42Smrg if (!config) 5542c393a42Smrg { 5552c393a42Smrg config = FcConfigGetCurrent (); 5562c393a42Smrg if (!config) 5572c393a42Smrg return 0; 5582c393a42Smrg } 5592c393a42Smrg return config->fonts[set]; 5602c393a42Smrg} 5612c393a42Smrg 5622c393a42Smrgvoid 5632c393a42SmrgFcConfigSetFonts (FcConfig *config, 5642c393a42Smrg FcFontSet *fonts, 5652c393a42Smrg FcSetName set) 5662c393a42Smrg{ 5672c393a42Smrg if (config->fonts[set]) 5682c393a42Smrg FcFontSetDestroy (config->fonts[set]); 5692c393a42Smrg config->fonts[set] = fonts; 5702c393a42Smrg} 5712c393a42Smrg 5722c393a42SmrgFcBlanks * 5732c393a42SmrgFcConfigGetBlanks (FcConfig *config) 5742c393a42Smrg{ 5752c393a42Smrg if (!config) 5762c393a42Smrg { 5772c393a42Smrg config = FcConfigGetCurrent (); 5782c393a42Smrg if (!config) 5792c393a42Smrg return 0; 5802c393a42Smrg } 5812c393a42Smrg return config->blanks; 5822c393a42Smrg} 5832c393a42Smrg 5842c393a42SmrgFcBool 5852c393a42SmrgFcConfigAddBlank (FcConfig *config, 5862c393a42Smrg FcChar32 blank) 5872c393a42Smrg{ 5882c393a42Smrg FcBlanks *b, *freeme = 0; 589ca08ab68Smrg 5902c393a42Smrg b = config->blanks; 5912c393a42Smrg if (!b) 5922c393a42Smrg { 5932c393a42Smrg freeme = b = FcBlanksCreate (); 5942c393a42Smrg if (!b) 5952c393a42Smrg return FcFalse; 5962c393a42Smrg } 5972c393a42Smrg if (!FcBlanksAdd (b, blank)) 5982c393a42Smrg { 5992c393a42Smrg if (freeme) 6002c393a42Smrg FcBlanksDestroy (freeme); 6012c393a42Smrg return FcFalse; 6022c393a42Smrg } 6032c393a42Smrg config->blanks = b; 6042c393a42Smrg return FcTrue; 6052c393a42Smrg} 6062c393a42Smrg 6072c393a42Smrgint 6082c393a42SmrgFcConfigGetRescanInterval (FcConfig *config) 6092c393a42Smrg{ 6102c393a42Smrg if (!config) 6112c393a42Smrg { 6122c393a42Smrg config = FcConfigGetCurrent (); 6132c393a42Smrg if (!config) 6142c393a42Smrg return 0; 6152c393a42Smrg } 6162c393a42Smrg return config->rescanInterval; 6172c393a42Smrg} 6182c393a42Smrg 6192c393a42SmrgFcBool 6202c393a42SmrgFcConfigSetRescanInterval (FcConfig *config, int rescanInterval) 6212c393a42Smrg{ 6222c393a42Smrg if (!config) 6232c393a42Smrg { 6242c393a42Smrg config = FcConfigGetCurrent (); 6252c393a42Smrg if (!config) 6262c393a42Smrg return FcFalse; 6272c393a42Smrg } 6282c393a42Smrg config->rescanInterval = rescanInterval; 6292c393a42Smrg return FcTrue; 6302c393a42Smrg} 6312c393a42Smrg 6322c393a42Smrg/* 6332c393a42Smrg * A couple of typos escaped into the library 6342c393a42Smrg */ 6352c393a42Smrgint 6362c393a42SmrgFcConfigGetRescanInverval (FcConfig *config) 6372c393a42Smrg{ 6382c393a42Smrg return FcConfigGetRescanInterval (config); 6392c393a42Smrg} 6402c393a42Smrg 6412c393a42SmrgFcBool 6422c393a42SmrgFcConfigSetRescanInverval (FcConfig *config, int rescanInterval) 6432c393a42Smrg{ 6442c393a42Smrg return FcConfigSetRescanInterval (config, rescanInterval); 6452c393a42Smrg} 6462c393a42Smrg 6472c393a42SmrgFcBool 6486fc018e4SmrgFcConfigAddRule (FcConfig *config, 6496fc018e4Smrg FcRule *rule, 6502c393a42Smrg FcMatchKind kind) 6512c393a42Smrg{ 6522c393a42Smrg FcSubst *subst, **prev; 6536fc018e4Smrg FcRule *r; 6546fc018e4Smrg int n = 0; 6552c393a42Smrg 6566fc018e4Smrg if (!rule) 6576fc018e4Smrg return FcFalse; 6582c393a42Smrg switch (kind) { 6592c393a42Smrg case FcMatchPattern: 6602c393a42Smrg prev = &config->substPattern; 6612c393a42Smrg break; 6622c393a42Smrg case FcMatchFont: 6632c393a42Smrg prev = &config->substFont; 6642c393a42Smrg break; 6652c393a42Smrg case FcMatchScan: 6662c393a42Smrg prev = &config->substScan; 6672c393a42Smrg break; 6682c393a42Smrg default: 6692c393a42Smrg return FcFalse; 6702c393a42Smrg } 6712c393a42Smrg subst = (FcSubst *) malloc (sizeof (FcSubst)); 6722c393a42Smrg if (!subst) 6732c393a42Smrg return FcFalse; 6742c393a42Smrg for (; *prev; prev = &(*prev)->next); 6752c393a42Smrg *prev = subst; 6766fc018e4Smrg subst->next = NULL; 6776fc018e4Smrg subst->rule = rule; 6786fc018e4Smrg for (r = rule; r; r = r->next) 6792c393a42Smrg { 6806fc018e4Smrg switch (r->type) 6816fc018e4Smrg { 6826fc018e4Smrg case FcRuleTest: 6836fc018e4Smrg if (r->u.test && 6846fc018e4Smrg r->u.test->kind == FcMatchDefault) 6856fc018e4Smrg r->u.test->kind = kind; 6866fc018e4Smrg 6876fc018e4Smrg if (n < r->u.test->object) 6886fc018e4Smrg n = r->u.test->object; 6896fc018e4Smrg break; 6906fc018e4Smrg case FcRuleEdit: 6916fc018e4Smrg if (n < r->u.edit->object) 6926fc018e4Smrg n = r->u.edit->object; 6936fc018e4Smrg break; 6946fc018e4Smrg default: 6956fc018e4Smrg break; 6966fc018e4Smrg } 6972c393a42Smrg } 6986fc018e4Smrg n = FC_OBJ_ID (n) - FC_MAX_BASE_OBJECT; 6996fc018e4Smrg if (config->maxObjects < n) 7006fc018e4Smrg config->maxObjects = n; 7012c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 7022c393a42Smrg { 7032c393a42Smrg printf ("Add Subst "); 7042c393a42Smrg FcSubstPrint (subst); 7052c393a42Smrg } 7062c393a42Smrg return FcTrue; 7072c393a42Smrg} 7082c393a42Smrg 7092c393a42Smrgstatic FcValue 710c9710b42SmrgFcConfigPromote (FcValue v, FcValue u, FcValuePromotionBuffer *buf) 7112c393a42Smrg{ 7122c393a42Smrg if (v.type == FcTypeInteger) 7132c393a42Smrg { 7142c393a42Smrg v.type = FcTypeDouble; 7152c393a42Smrg v.u.d = (double) v.u.i; 7162c393a42Smrg } 7172c393a42Smrg else if (v.type == FcTypeVoid && u.type == FcTypeMatrix) 7182c393a42Smrg { 7192c393a42Smrg v.u.m = &FcIdentityMatrix; 7202c393a42Smrg v.type = FcTypeMatrix; 7212c393a42Smrg } 722c9710b42Smrg else if (buf && v.type == FcTypeString && u.type == FcTypeLangSet) 7232c393a42Smrg { 724c9710b42Smrg v.u.l = FcLangSetPromote (v.u.s, buf); 7252c393a42Smrg v.type = FcTypeLangSet; 7262c393a42Smrg } 72718bd4a06Smrg else if (v.type == FcTypeVoid && u.type == FcTypeLangSet) 72818bd4a06Smrg { 72918bd4a06Smrg v.u.l = FcLangSetPromote (NULL, buf); 73018bd4a06Smrg v.type = FcTypeLangSet; 73118bd4a06Smrg } 73218bd4a06Smrg else if (v.type == FcTypeVoid && u.type == FcTypeCharSet) 73318bd4a06Smrg { 73418bd4a06Smrg v.u.c = FcCharSetPromote (buf); 73518bd4a06Smrg v.type = FcTypeCharSet; 73618bd4a06Smrg } 73718bd4a06Smrg if (buf && v.type == FcTypeDouble && u.type == FcTypeRange) 73818bd4a06Smrg { 73918bd4a06Smrg v.u.r = FcRangePromote (v.u.d, buf); 74018bd4a06Smrg v.type = FcTypeRange; 74118bd4a06Smrg } 7422c393a42Smrg return v; 7432c393a42Smrg} 7442c393a42Smrg 7452c393a42SmrgFcBool 7462c393a42SmrgFcConfigCompareValue (const FcValue *left_o, 7476fc018e4Smrg unsigned int op_, 7482c393a42Smrg const FcValue *right_o) 7492c393a42Smrg{ 7502c393a42Smrg FcValue left = FcValueCanonicalize(left_o); 7512c393a42Smrg FcValue right = FcValueCanonicalize(right_o); 7522c393a42Smrg FcBool ret = FcFalse; 753ca08ab68Smrg FcOp op = FC_OP_GET_OP (op_); 754ca08ab68Smrg int flags = FC_OP_GET_FLAGS (op_); 755c9710b42Smrg FcValuePromotionBuffer buf1, buf2; 756ca08ab68Smrg 757c9710b42Smrg left = FcConfigPromote (left, right, &buf1); 758c9710b42Smrg right = FcConfigPromote (right, left, &buf2); 759ca08ab68Smrg if (left.type == right.type) 7602c393a42Smrg { 7612c393a42Smrg switch (left.type) { 7626fc018e4Smrg case FcTypeUnknown: 7636fc018e4Smrg break; /* No way to guess how to compare for this object */ 7642c393a42Smrg case FcTypeInteger: 7652c393a42Smrg break; /* FcConfigPromote prevents this from happening */ 7662c393a42Smrg case FcTypeDouble: 767c9710b42Smrg switch ((int) op) { 7682c393a42Smrg case FcOpEqual: 7692c393a42Smrg case FcOpContains: 7702c393a42Smrg case FcOpListing: 7712c393a42Smrg ret = left.u.d == right.u.d; 7722c393a42Smrg break; 7732c393a42Smrg case FcOpNotEqual: 7742c393a42Smrg case FcOpNotContains: 7752c393a42Smrg ret = left.u.d != right.u.d; 7762c393a42Smrg break; 777ca08ab68Smrg case FcOpLess: 7782c393a42Smrg ret = left.u.d < right.u.d; 7792c393a42Smrg break; 780ca08ab68Smrg case FcOpLessEqual: 7812c393a42Smrg ret = left.u.d <= right.u.d; 7822c393a42Smrg break; 783ca08ab68Smrg case FcOpMore: 7842c393a42Smrg ret = left.u.d > right.u.d; 7852c393a42Smrg break; 786ca08ab68Smrg case FcOpMoreEqual: 7872c393a42Smrg ret = left.u.d >= right.u.d; 7882c393a42Smrg break; 7892c393a42Smrg default: 7902c393a42Smrg break; 7912c393a42Smrg } 7922c393a42Smrg break; 7932c393a42Smrg case FcTypeBool: 794c9710b42Smrg switch ((int) op) { 795ca08ab68Smrg case FcOpEqual: 7962c393a42Smrg case FcOpContains: 7972c393a42Smrg case FcOpListing: 7982c393a42Smrg ret = left.u.b == right.u.b; 7992c393a42Smrg break; 8002c393a42Smrg case FcOpNotEqual: 8012c393a42Smrg case FcOpNotContains: 8022c393a42Smrg ret = left.u.b != right.u.b; 8032c393a42Smrg break; 8042c393a42Smrg default: 8052c393a42Smrg break; 8062c393a42Smrg } 8072c393a42Smrg break; 8082c393a42Smrg case FcTypeString: 809c9710b42Smrg switch ((int) op) { 810ca08ab68Smrg case FcOpEqual: 8112c393a42Smrg case FcOpListing: 812ca08ab68Smrg if (flags & FcOpFlagIgnoreBlanks) 813ca08ab68Smrg ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) == 0; 814ca08ab68Smrg else 815ca08ab68Smrg ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0; 8162c393a42Smrg break; 8172c393a42Smrg case FcOpContains: 8182c393a42Smrg ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0; 8192c393a42Smrg break; 8202c393a42Smrg case FcOpNotEqual: 821ca08ab68Smrg if (flags & FcOpFlagIgnoreBlanks) 822ca08ab68Smrg ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) != 0; 823ca08ab68Smrg else 824ca08ab68Smrg ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0; 8252c393a42Smrg break; 8262c393a42Smrg case FcOpNotContains: 8272c393a42Smrg ret = FcStrStrIgnoreCase (left.u.s, right.u.s) == 0; 8282c393a42Smrg break; 8292c393a42Smrg default: 8302c393a42Smrg break; 8312c393a42Smrg } 8322c393a42Smrg break; 8332c393a42Smrg case FcTypeMatrix: 834c9710b42Smrg switch ((int) op) { 8352c393a42Smrg case FcOpEqual: 8362c393a42Smrg case FcOpContains: 8372c393a42Smrg case FcOpListing: 8382c393a42Smrg ret = FcMatrixEqual (left.u.m, right.u.m); 8392c393a42Smrg break; 8402c393a42Smrg case FcOpNotEqual: 8412c393a42Smrg case FcOpNotContains: 8422c393a42Smrg ret = !FcMatrixEqual (left.u.m, right.u.m); 8432c393a42Smrg break; 8442c393a42Smrg default: 8452c393a42Smrg break; 8462c393a42Smrg } 8472c393a42Smrg break; 8482c393a42Smrg case FcTypeCharSet: 849c9710b42Smrg switch ((int) op) { 8502c393a42Smrg case FcOpContains: 8512c393a42Smrg case FcOpListing: 8522c393a42Smrg /* left contains right if right is a subset of left */ 8532c393a42Smrg ret = FcCharSetIsSubset (right.u.c, left.u.c); 8542c393a42Smrg break; 8552c393a42Smrg case FcOpNotContains: 8562c393a42Smrg /* left contains right if right is a subset of left */ 8572c393a42Smrg ret = !FcCharSetIsSubset (right.u.c, left.u.c); 8582c393a42Smrg break; 8592c393a42Smrg case FcOpEqual: 8602c393a42Smrg ret = FcCharSetEqual (left.u.c, right.u.c); 8612c393a42Smrg break; 8622c393a42Smrg case FcOpNotEqual: 8632c393a42Smrg ret = !FcCharSetEqual (left.u.c, right.u.c); 8642c393a42Smrg break; 8652c393a42Smrg default: 8662c393a42Smrg break; 8672c393a42Smrg } 8682c393a42Smrg break; 8692c393a42Smrg case FcTypeLangSet: 870c9710b42Smrg switch ((int) op) { 8712c393a42Smrg case FcOpContains: 8722c393a42Smrg case FcOpListing: 8732c393a42Smrg ret = FcLangSetContains (left.u.l, right.u.l); 8742c393a42Smrg break; 8752c393a42Smrg case FcOpNotContains: 8762c393a42Smrg ret = !FcLangSetContains (left.u.l, right.u.l); 8772c393a42Smrg break; 8782c393a42Smrg case FcOpEqual: 8792c393a42Smrg ret = FcLangSetEqual (left.u.l, right.u.l); 8802c393a42Smrg break; 8812c393a42Smrg case FcOpNotEqual: 8822c393a42Smrg ret = !FcLangSetEqual (left.u.l, right.u.l); 8832c393a42Smrg break; 8842c393a42Smrg default: 8852c393a42Smrg break; 8862c393a42Smrg } 8872c393a42Smrg break; 8882c393a42Smrg case FcTypeVoid: 889c9710b42Smrg switch ((int) op) { 8902c393a42Smrg case FcOpEqual: 8912c393a42Smrg case FcOpContains: 8922c393a42Smrg case FcOpListing: 8932c393a42Smrg ret = FcTrue; 8942c393a42Smrg break; 8952c393a42Smrg default: 8962c393a42Smrg break; 8972c393a42Smrg } 8982c393a42Smrg break; 8992c393a42Smrg case FcTypeFTFace: 900c9710b42Smrg switch ((int) op) { 9012c393a42Smrg case FcOpEqual: 9022c393a42Smrg case FcOpContains: 9032c393a42Smrg case FcOpListing: 9042c393a42Smrg ret = left.u.f == right.u.f; 9052c393a42Smrg break; 9062c393a42Smrg case FcOpNotEqual: 9072c393a42Smrg case FcOpNotContains: 9082c393a42Smrg ret = left.u.f != right.u.f; 9092c393a42Smrg break; 9102c393a42Smrg default: 9112c393a42Smrg break; 9122c393a42Smrg } 9132c393a42Smrg break; 91418bd4a06Smrg case FcTypeRange: 91518bd4a06Smrg ret = FcRangeCompare (op, left.u.r, right.u.r); 91618bd4a06Smrg break; 9172c393a42Smrg } 9182c393a42Smrg } 9192c393a42Smrg else 9202c393a42Smrg { 9212c393a42Smrg if (op == FcOpNotEqual || op == FcOpNotContains) 9222c393a42Smrg ret = FcTrue; 9232c393a42Smrg } 9242c393a42Smrg return ret; 9252c393a42Smrg} 9262c393a42Smrg 9272c393a42Smrg 9282c393a42Smrg#define _FcDoubleFloor(d) ((int) (d)) 9292c393a42Smrg#define _FcDoubleCeil(d) ((double) (int) (d) == (d) ? (int) (d) : (int) ((d) + 1)) 9302c393a42Smrg#define FcDoubleFloor(d) ((d) >= 0 ? _FcDoubleFloor(d) : -_FcDoubleCeil(-(d))) 9312c393a42Smrg#define FcDoubleCeil(d) ((d) >= 0 ? _FcDoubleCeil(d) : -_FcDoubleFloor(-(d))) 9322c393a42Smrg#define FcDoubleRound(d) FcDoubleFloor ((d) + 0.5) 9332c393a42Smrg#define FcDoubleTrunc(d) ((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d))) 9342c393a42Smrg 9352c393a42Smrgstatic FcValue 936c9710b42SmrgFcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e) 9372c393a42Smrg{ 93818bd4a06Smrg FcValue v, vl, vr, vle, vre; 9392c393a42Smrg FcMatrix *m; 9402c393a42Smrg FcChar8 *str; 941ca08ab68Smrg FcOp op = FC_OP_GET_OP (e->op); 94218bd4a06Smrg FcValuePromotionBuffer buf1, buf2; 943ca08ab68Smrg 944c9710b42Smrg switch ((int) op) { 9452c393a42Smrg case FcOpInteger: 9462c393a42Smrg v.type = FcTypeInteger; 9472c393a42Smrg v.u.i = e->u.ival; 9482c393a42Smrg break; 9492c393a42Smrg case FcOpDouble: 9502c393a42Smrg v.type = FcTypeDouble; 9512c393a42Smrg v.u.d = e->u.dval; 9522c393a42Smrg break; 9532c393a42Smrg case FcOpString: 9542c393a42Smrg v.type = FcTypeString; 955a6844aabSmrg v.u.s = e->u.sval; 956a6844aabSmrg v = FcValueSave (v); 9572c393a42Smrg break; 9582c393a42Smrg case FcOpMatrix: 959c9710b42Smrg { 960c9710b42Smrg FcMatrix m; 961c9710b42Smrg FcValue xx, xy, yx, yy; 962c9710b42Smrg v.type = FcTypeMatrix; 963c9710b42Smrg xx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xx), v, NULL); 964c9710b42Smrg xy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xy), v, NULL); 965c9710b42Smrg yx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yx), v, NULL); 966c9710b42Smrg yy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yy), v, NULL); 967c9710b42Smrg if (xx.type == FcTypeDouble && xy.type == FcTypeDouble && 968c9710b42Smrg yx.type == FcTypeDouble && yy.type == FcTypeDouble) 969c9710b42Smrg { 970c9710b42Smrg m.xx = xx.u.d; 971c9710b42Smrg m.xy = xy.u.d; 972c9710b42Smrg m.yx = yx.u.d; 973c9710b42Smrg m.yy = yy.u.d; 974c9710b42Smrg v.u.m = &m; 975c9710b42Smrg } 976c9710b42Smrg else 977c9710b42Smrg v.type = FcTypeVoid; 978c9710b42Smrg v = FcValueSave (v); 979c9710b42Smrg } 9802c393a42Smrg break; 9812c393a42Smrg case FcOpCharSet: 9822c393a42Smrg v.type = FcTypeCharSet; 9832c393a42Smrg v.u.c = e->u.cval; 9842c393a42Smrg v = FcValueSave (v); 9852c393a42Smrg break; 986ca08ab68Smrg case FcOpLangSet: 987ca08ab68Smrg v.type = FcTypeLangSet; 988ca08ab68Smrg v.u.l = e->u.lval; 989ca08ab68Smrg v = FcValueSave (v); 990ca08ab68Smrg break; 99118bd4a06Smrg case FcOpRange: 99218bd4a06Smrg v.type = FcTypeRange; 99318bd4a06Smrg v.u.r = e->u.rval; 99418bd4a06Smrg v = FcValueSave (v); 99518bd4a06Smrg break; 9962c393a42Smrg case FcOpBool: 9972c393a42Smrg v.type = FcTypeBool; 9982c393a42Smrg v.u.b = e->u.bval; 9992c393a42Smrg break; 10002c393a42Smrg case FcOpField: 1001c9710b42Smrg if (kind == FcMatchFont && e->u.name.kind == FcMatchPattern) 1002c9710b42Smrg { 1003c9710b42Smrg if (FcResultMatch != FcPatternObjectGet (p_pat, e->u.name.object, 0, &v)) 1004c9710b42Smrg v.type = FcTypeVoid; 1005c9710b42Smrg } 1006c9710b42Smrg else if (kind == FcMatchPattern && e->u.name.kind == FcMatchFont) 1007c9710b42Smrg { 1008c9710b42Smrg fprintf (stderr, 1009c9710b42Smrg "Fontconfig warning: <name> tag has target=\"font\" in a <match target=\"pattern\">.\n"); 10102c393a42Smrg v.type = FcTypeVoid; 1011c9710b42Smrg } 1012c9710b42Smrg else 1013c9710b42Smrg { 1014c9710b42Smrg if (FcResultMatch != FcPatternObjectGet (p, e->u.name.object, 0, &v)) 1015c9710b42Smrg v.type = FcTypeVoid; 1016c9710b42Smrg } 10172c393a42Smrg v = FcValueSave (v); 10182c393a42Smrg break; 10192c393a42Smrg case FcOpConst: 10202c393a42Smrg if (FcNameConstant (e->u.constant, &v.u.i)) 10212c393a42Smrg v.type = FcTypeInteger; 10222c393a42Smrg else 10232c393a42Smrg v.type = FcTypeVoid; 10242c393a42Smrg break; 10252c393a42Smrg case FcOpQuest: 1026c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 10272c393a42Smrg if (vl.type == FcTypeBool) 10282c393a42Smrg { 10292c393a42Smrg if (vl.u.b) 1030c9710b42Smrg v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.left); 10312c393a42Smrg else 1032c9710b42Smrg v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.right); 10332c393a42Smrg } 10342c393a42Smrg else 10352c393a42Smrg v.type = FcTypeVoid; 10362c393a42Smrg FcValueDestroy (vl); 10372c393a42Smrg break; 10382c393a42Smrg case FcOpEqual: 10392c393a42Smrg case FcOpNotEqual: 10402c393a42Smrg case FcOpLess: 10412c393a42Smrg case FcOpLessEqual: 10422c393a42Smrg case FcOpMore: 10432c393a42Smrg case FcOpMoreEqual: 10442c393a42Smrg case FcOpContains: 10452c393a42Smrg case FcOpNotContains: 10462c393a42Smrg case FcOpListing: 1047c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1048c9710b42Smrg vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right); 10492c393a42Smrg v.type = FcTypeBool; 10502c393a42Smrg v.u.b = FcConfigCompareValue (&vl, e->op, &vr); 10512c393a42Smrg FcValueDestroy (vl); 10522c393a42Smrg FcValueDestroy (vr); 10532c393a42Smrg break; 10542c393a42Smrg case FcOpOr: 10552c393a42Smrg case FcOpAnd: 10562c393a42Smrg case FcOpPlus: 10572c393a42Smrg case FcOpMinus: 10582c393a42Smrg case FcOpTimes: 10592c393a42Smrg case FcOpDivide: 1060c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1061c9710b42Smrg vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right); 106218bd4a06Smrg vle = FcConfigPromote (vl, vr, &buf1); 106318bd4a06Smrg vre = FcConfigPromote (vr, vle, &buf2); 106418bd4a06Smrg if (vle.type == vre.type) 10652c393a42Smrg { 106618bd4a06Smrg switch ((int) vle.type) { 10672c393a42Smrg case FcTypeDouble: 1068c9710b42Smrg switch ((int) op) { 1069ca08ab68Smrg case FcOpPlus: 10702c393a42Smrg v.type = FcTypeDouble; 107118bd4a06Smrg v.u.d = vle.u.d + vre.u.d; 10722c393a42Smrg break; 10732c393a42Smrg case FcOpMinus: 10742c393a42Smrg v.type = FcTypeDouble; 107518bd4a06Smrg v.u.d = vle.u.d - vre.u.d; 10762c393a42Smrg break; 10772c393a42Smrg case FcOpTimes: 10782c393a42Smrg v.type = FcTypeDouble; 107918bd4a06Smrg v.u.d = vle.u.d * vre.u.d; 10802c393a42Smrg break; 10812c393a42Smrg case FcOpDivide: 10822c393a42Smrg v.type = FcTypeDouble; 108318bd4a06Smrg v.u.d = vle.u.d / vre.u.d; 10842c393a42Smrg break; 10852c393a42Smrg default: 1086ca08ab68Smrg v.type = FcTypeVoid; 10872c393a42Smrg break; 10882c393a42Smrg } 10892c393a42Smrg if (v.type == FcTypeDouble && 10902c393a42Smrg v.u.d == (double) (int) v.u.d) 10912c393a42Smrg { 10922c393a42Smrg v.type = FcTypeInteger; 10932c393a42Smrg v.u.i = (int) v.u.d; 10942c393a42Smrg } 10952c393a42Smrg break; 10962c393a42Smrg case FcTypeBool: 1097c9710b42Smrg switch ((int) op) { 10982c393a42Smrg case FcOpOr: 10992c393a42Smrg v.type = FcTypeBool; 110018bd4a06Smrg v.u.b = vle.u.b || vre.u.b; 11012c393a42Smrg break; 11022c393a42Smrg case FcOpAnd: 11032c393a42Smrg v.type = FcTypeBool; 110418bd4a06Smrg v.u.b = vle.u.b && vre.u.b; 11052c393a42Smrg break; 11062c393a42Smrg default: 1107ca08ab68Smrg v.type = FcTypeVoid; 11082c393a42Smrg break; 11092c393a42Smrg } 11102c393a42Smrg break; 11112c393a42Smrg case FcTypeString: 1112c9710b42Smrg switch ((int) op) { 11132c393a42Smrg case FcOpPlus: 11142c393a42Smrg v.type = FcTypeString; 111518bd4a06Smrg str = FcStrPlus (vle.u.s, vre.u.s); 1116c9710b42Smrg v.u.s = FcStrdup (str); 11172c393a42Smrg FcStrFree (str); 1118ca08ab68Smrg 11192c393a42Smrg if (!v.u.s) 11202c393a42Smrg v.type = FcTypeVoid; 11212c393a42Smrg break; 11222c393a42Smrg default: 11232c393a42Smrg v.type = FcTypeVoid; 11242c393a42Smrg break; 11252c393a42Smrg } 11262c393a42Smrg break; 11272c393a42Smrg case FcTypeMatrix: 1128c9710b42Smrg switch ((int) op) { 11292c393a42Smrg case FcOpTimes: 11302c393a42Smrg v.type = FcTypeMatrix; 11312c393a42Smrg m = malloc (sizeof (FcMatrix)); 11322c393a42Smrg if (m) 11332c393a42Smrg { 113418bd4a06Smrg FcMatrixMultiply (m, vle.u.m, vre.u.m); 11352c393a42Smrg v.u.m = m; 11362c393a42Smrg } 11372c393a42Smrg else 11382c393a42Smrg { 11392c393a42Smrg v.type = FcTypeVoid; 11402c393a42Smrg } 11412c393a42Smrg break; 11422c393a42Smrg default: 11432c393a42Smrg v.type = FcTypeVoid; 11442c393a42Smrg break; 11452c393a42Smrg } 11462c393a42Smrg break; 1147ca08ab68Smrg case FcTypeCharSet: 1148c9710b42Smrg switch ((int) op) { 1149ca08ab68Smrg case FcOpPlus: 1150ca08ab68Smrg v.type = FcTypeCharSet; 115118bd4a06Smrg v.u.c = FcCharSetUnion (vle.u.c, vre.u.c); 1152ca08ab68Smrg if (!v.u.c) 1153ca08ab68Smrg v.type = FcTypeVoid; 1154ca08ab68Smrg break; 1155ca08ab68Smrg case FcOpMinus: 1156ca08ab68Smrg v.type = FcTypeCharSet; 115718bd4a06Smrg v.u.c = FcCharSetSubtract (vle.u.c, vre.u.c); 1158ca08ab68Smrg if (!v.u.c) 1159ca08ab68Smrg v.type = FcTypeVoid; 1160ca08ab68Smrg break; 1161ca08ab68Smrg default: 1162ca08ab68Smrg v.type = FcTypeVoid; 1163ca08ab68Smrg break; 1164ca08ab68Smrg } 1165ca08ab68Smrg break; 1166ca08ab68Smrg case FcTypeLangSet: 1167c9710b42Smrg switch ((int) op) { 1168ca08ab68Smrg case FcOpPlus: 1169ca08ab68Smrg v.type = FcTypeLangSet; 117018bd4a06Smrg v.u.l = FcLangSetUnion (vle.u.l, vre.u.l); 1171ca08ab68Smrg if (!v.u.l) 1172ca08ab68Smrg v.type = FcTypeVoid; 1173ca08ab68Smrg break; 1174ca08ab68Smrg case FcOpMinus: 1175ca08ab68Smrg v.type = FcTypeLangSet; 117618bd4a06Smrg v.u.l = FcLangSetSubtract (vle.u.l, vre.u.l); 1177ca08ab68Smrg if (!v.u.l) 1178ca08ab68Smrg v.type = FcTypeVoid; 1179ca08ab68Smrg break; 1180ca08ab68Smrg default: 1181ca08ab68Smrg v.type = FcTypeVoid; 1182ca08ab68Smrg break; 1183ca08ab68Smrg } 1184ca08ab68Smrg break; 11852c393a42Smrg default: 11862c393a42Smrg v.type = FcTypeVoid; 11872c393a42Smrg break; 11882c393a42Smrg } 11892c393a42Smrg } 11902c393a42Smrg else 11912c393a42Smrg v.type = FcTypeVoid; 11922c393a42Smrg FcValueDestroy (vl); 11932c393a42Smrg FcValueDestroy (vr); 11942c393a42Smrg break; 11952c393a42Smrg case FcOpNot: 1196c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1197c9710b42Smrg switch ((int) vl.type) { 11982c393a42Smrg case FcTypeBool: 11992c393a42Smrg v.type = FcTypeBool; 12002c393a42Smrg v.u.b = !vl.u.b; 12012c393a42Smrg break; 12022c393a42Smrg default: 12032c393a42Smrg v.type = FcTypeVoid; 12042c393a42Smrg break; 12052c393a42Smrg } 12062c393a42Smrg FcValueDestroy (vl); 12072c393a42Smrg break; 12082c393a42Smrg case FcOpFloor: 1209c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1210c9710b42Smrg switch ((int) vl.type) { 12112c393a42Smrg case FcTypeInteger: 12122c393a42Smrg v = vl; 12132c393a42Smrg break; 12142c393a42Smrg case FcTypeDouble: 12152c393a42Smrg v.type = FcTypeInteger; 12162c393a42Smrg v.u.i = FcDoubleFloor (vl.u.d); 12172c393a42Smrg break; 12182c393a42Smrg default: 12192c393a42Smrg v.type = FcTypeVoid; 12202c393a42Smrg break; 12212c393a42Smrg } 12222c393a42Smrg FcValueDestroy (vl); 12232c393a42Smrg break; 12242c393a42Smrg case FcOpCeil: 1225c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1226c9710b42Smrg switch ((int) vl.type) { 12272c393a42Smrg case FcTypeInteger: 12282c393a42Smrg v = vl; 12292c393a42Smrg break; 12302c393a42Smrg case FcTypeDouble: 12312c393a42Smrg v.type = FcTypeInteger; 12322c393a42Smrg v.u.i = FcDoubleCeil (vl.u.d); 12332c393a42Smrg break; 12342c393a42Smrg default: 12352c393a42Smrg v.type = FcTypeVoid; 12362c393a42Smrg break; 12372c393a42Smrg } 12382c393a42Smrg FcValueDestroy (vl); 12392c393a42Smrg break; 12402c393a42Smrg case FcOpRound: 1241c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1242c9710b42Smrg switch ((int) vl.type) { 12432c393a42Smrg case FcTypeInteger: 12442c393a42Smrg v = vl; 12452c393a42Smrg break; 12462c393a42Smrg case FcTypeDouble: 12472c393a42Smrg v.type = FcTypeInteger; 12482c393a42Smrg v.u.i = FcDoubleRound (vl.u.d); 12492c393a42Smrg break; 12502c393a42Smrg default: 12512c393a42Smrg v.type = FcTypeVoid; 12522c393a42Smrg break; 12532c393a42Smrg } 12542c393a42Smrg FcValueDestroy (vl); 12552c393a42Smrg break; 12562c393a42Smrg case FcOpTrunc: 1257c9710b42Smrg vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1258c9710b42Smrg switch ((int) vl.type) { 12592c393a42Smrg case FcTypeInteger: 12602c393a42Smrg v = vl; 12612c393a42Smrg break; 12622c393a42Smrg case FcTypeDouble: 12632c393a42Smrg v.type = FcTypeInteger; 12642c393a42Smrg v.u.i = FcDoubleTrunc (vl.u.d); 12652c393a42Smrg break; 12662c393a42Smrg default: 12672c393a42Smrg v.type = FcTypeVoid; 12682c393a42Smrg break; 12692c393a42Smrg } 12702c393a42Smrg FcValueDestroy (vl); 12712c393a42Smrg break; 12722c393a42Smrg default: 12732c393a42Smrg v.type = FcTypeVoid; 12742c393a42Smrg break; 12752c393a42Smrg } 12762c393a42Smrg return v; 12772c393a42Smrg} 12782c393a42Smrg 12792c393a42Smrgstatic FcValueList * 12802c393a42SmrgFcConfigMatchValueList (FcPattern *p, 1281c9710b42Smrg FcPattern *p_pat, 1282c9710b42Smrg FcMatchKind kind, 12832c393a42Smrg FcTest *t, 12842c393a42Smrg FcValueList *values) 12852c393a42Smrg{ 12862c393a42Smrg FcValueList *ret = 0; 12872c393a42Smrg FcExpr *e = t->expr; 12882c393a42Smrg FcValue value; 12892c393a42Smrg FcValueList *v; 1290ca08ab68Smrg 12912c393a42Smrg while (e) 12922c393a42Smrg { 12932c393a42Smrg /* Compute the value of the match expression */ 1294ca08ab68Smrg if (FC_OP_GET_OP (e->op) == FcOpComma) 12952c393a42Smrg { 1296c9710b42Smrg value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 12972c393a42Smrg e = e->u.tree.right; 12982c393a42Smrg } 12992c393a42Smrg else 13002c393a42Smrg { 1301c9710b42Smrg value = FcConfigEvaluate (p, p_pat, kind, e); 13022c393a42Smrg e = 0; 13032c393a42Smrg } 13042c393a42Smrg 13052c393a42Smrg for (v = values; v; v = FcValueListNext(v)) 13062c393a42Smrg { 13072c393a42Smrg /* Compare the pattern value to the match expression value */ 13082c393a42Smrg if (FcConfigCompareValue (&v->value, t->op, &value)) 13092c393a42Smrg { 13102c393a42Smrg if (!ret) 13112c393a42Smrg ret = v; 13122c393a42Smrg } 13132c393a42Smrg else 13142c393a42Smrg { 13152c393a42Smrg if (t->qual == FcQualAll) 13162c393a42Smrg { 13172c393a42Smrg ret = 0; 13182c393a42Smrg break; 13192c393a42Smrg } 13202c393a42Smrg } 13212c393a42Smrg } 13222c393a42Smrg FcValueDestroy (value); 13232c393a42Smrg } 13242c393a42Smrg return ret; 13252c393a42Smrg} 13262c393a42Smrg 13272c393a42Smrgstatic FcValueList * 1328c9710b42SmrgFcConfigValues (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e, FcValueBinding binding) 13292c393a42Smrg{ 13302c393a42Smrg FcValueList *l; 1331ca08ab68Smrg 13322c393a42Smrg if (!e) 13332c393a42Smrg return 0; 13342c393a42Smrg l = (FcValueList *) malloc (sizeof (FcValueList)); 13352c393a42Smrg if (!l) 13362c393a42Smrg return 0; 1337ca08ab68Smrg if (FC_OP_GET_OP (e->op) == FcOpComma) 13382c393a42Smrg { 1339c9710b42Smrg l->value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left); 1340c9710b42Smrg l->next = FcConfigValues (p, p_pat, kind, e->u.tree.right, binding); 13412c393a42Smrg } 13422c393a42Smrg else 13432c393a42Smrg { 1344c9710b42Smrg l->value = FcConfigEvaluate (p, p_pat, kind, e); 13452c393a42Smrg l->next = NULL; 13462c393a42Smrg } 13472c393a42Smrg l->binding = binding; 13482c393a42Smrg if (l->value.type == FcTypeVoid) 13492c393a42Smrg { 13502c393a42Smrg FcValueList *next = FcValueListNext(l); 13512c393a42Smrg 13522c393a42Smrg free (l); 13532c393a42Smrg l = next; 13542c393a42Smrg } 13552c393a42Smrg 13562c393a42Smrg return l; 13572c393a42Smrg} 13582c393a42Smrg 13592c393a42Smrgstatic FcBool 13602c393a42SmrgFcConfigAdd (FcValueListPtr *head, 13612c393a42Smrg FcValueList *position, 13622c393a42Smrg FcBool append, 1363c9710b42Smrg FcValueList *new, 1364c9710b42Smrg FcObject object) 13652c393a42Smrg{ 1366c9710b42Smrg FcValueListPtr *prev, l, last, v; 13672c393a42Smrg FcValueBinding sameBinding; 1368ca08ab68Smrg 1369c9710b42Smrg /* 1370c9710b42Smrg * Make sure the stored type is valid for built-in objects 1371c9710b42Smrg */ 1372c9710b42Smrg for (l = new; l != NULL; l = FcValueListNext (l)) 1373c9710b42Smrg { 1374c9710b42Smrg if (!FcObjectValidType (object, l->value.type)) 1375c9710b42Smrg { 1376c9710b42Smrg fprintf (stderr, 1377c9710b42Smrg "Fontconfig warning: FcPattern object %s does not accept value", FcObjectName (object)); 1378c9710b42Smrg FcValuePrintFile (stderr, l->value); 1379c9710b42Smrg fprintf (stderr, "\n"); 1380c9710b42Smrg 1381c9710b42Smrg if (FcDebug () & FC_DBG_EDIT) 1382c9710b42Smrg { 1383c9710b42Smrg printf ("Not adding\n"); 1384c9710b42Smrg } 1385c9710b42Smrg 1386c9710b42Smrg return FcFalse; 1387c9710b42Smrg } 1388c9710b42Smrg } 1389c9710b42Smrg 13902c393a42Smrg if (position) 13912c393a42Smrg sameBinding = position->binding; 13922c393a42Smrg else 13932c393a42Smrg sameBinding = FcValueBindingWeak; 13942c393a42Smrg for (v = new; v != NULL; v = FcValueListNext(v)) 13952c393a42Smrg if (v->binding == FcValueBindingSame) 13962c393a42Smrg v->binding = sameBinding; 13972c393a42Smrg if (append) 13982c393a42Smrg { 13992c393a42Smrg if (position) 14002c393a42Smrg prev = &position->next; 14012c393a42Smrg else 1402ca08ab68Smrg for (prev = head; *prev != NULL; 14032c393a42Smrg prev = &(*prev)->next) 14042c393a42Smrg ; 14052c393a42Smrg } 14062c393a42Smrg else 14072c393a42Smrg { 14082c393a42Smrg if (position) 14092c393a42Smrg { 1410ca08ab68Smrg for (prev = head; *prev != NULL; 14112c393a42Smrg prev = &(*prev)->next) 14122c393a42Smrg { 14132c393a42Smrg if (*prev == position) 14142c393a42Smrg break; 14152c393a42Smrg } 14162c393a42Smrg } 14172c393a42Smrg else 14182c393a42Smrg prev = head; 14192c393a42Smrg 14202c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 14212c393a42Smrg { 14222c393a42Smrg if (*prev == NULL) 14232c393a42Smrg printf ("position not on list\n"); 14242c393a42Smrg } 14252c393a42Smrg } 14262c393a42Smrg 14272c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 14282c393a42Smrg { 14292c393a42Smrg printf ("%s list before ", append ? "Append" : "Prepend"); 1430ca08ab68Smrg FcValueListPrintWithPosition (*head, *prev); 14312c393a42Smrg printf ("\n"); 14322c393a42Smrg } 1433ca08ab68Smrg 14342c393a42Smrg if (new) 14352c393a42Smrg { 14362c393a42Smrg last = new; 14372c393a42Smrg while (last->next != NULL) 14382c393a42Smrg last = last->next; 1439ca08ab68Smrg 14402c393a42Smrg last->next = *prev; 14412c393a42Smrg *prev = new; 14422c393a42Smrg } 1443ca08ab68Smrg 14442c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 14452c393a42Smrg { 14462c393a42Smrg printf ("%s list after ", append ? "Append" : "Prepend"); 14472c393a42Smrg FcValueListPrint (*head); 14482c393a42Smrg printf ("\n"); 14492c393a42Smrg } 1450ca08ab68Smrg 14512c393a42Smrg return FcTrue; 14522c393a42Smrg} 14532c393a42Smrg 14542c393a42Smrgstatic void 14552c393a42SmrgFcConfigDel (FcValueListPtr *head, 14562c393a42Smrg FcValueList *position) 14572c393a42Smrg{ 14582c393a42Smrg FcValueListPtr *prev; 14592c393a42Smrg 14602c393a42Smrg for (prev = head; *prev != NULL; prev = &(*prev)->next) 14612c393a42Smrg { 14622c393a42Smrg if (*prev == position) 14632c393a42Smrg { 14642c393a42Smrg *prev = position->next; 14652c393a42Smrg position->next = NULL; 14662c393a42Smrg FcValueListDestroy (position); 14672c393a42Smrg break; 14682c393a42Smrg } 14692c393a42Smrg } 14702c393a42Smrg} 14712c393a42Smrg 14722c393a42Smrgstatic void 14732c393a42SmrgFcConfigPatternAdd (FcPattern *p, 14742c393a42Smrg FcObject object, 14752c393a42Smrg FcValueList *list, 14762c393a42Smrg FcBool append) 14772c393a42Smrg{ 14782c393a42Smrg if (list) 14792c393a42Smrg { 14802c393a42Smrg FcPatternElt *e = FcPatternObjectInsertElt (p, object); 1481ca08ab68Smrg 14822c393a42Smrg if (!e) 14832c393a42Smrg return; 1484c9710b42Smrg FcConfigAdd (&e->values, 0, append, list, object); 14852c393a42Smrg } 14862c393a42Smrg} 14872c393a42Smrg 14882c393a42Smrg/* 14892c393a42Smrg * Delete all values associated with a field 14902c393a42Smrg */ 14912c393a42Smrgstatic void 14922c393a42SmrgFcConfigPatternDel (FcPattern *p, 14932c393a42Smrg FcObject object) 14942c393a42Smrg{ 14952c393a42Smrg FcPatternElt *e = FcPatternObjectFindElt (p, object); 14962c393a42Smrg if (!e) 14972c393a42Smrg return; 14982c393a42Smrg while (e->values != NULL) 14992c393a42Smrg FcConfigDel (&e->values, e->values); 15002c393a42Smrg} 15012c393a42Smrg 15022c393a42Smrgstatic void 15032c393a42SmrgFcConfigPatternCanon (FcPattern *p, 15042c393a42Smrg FcObject object) 15052c393a42Smrg{ 15062c393a42Smrg FcPatternElt *e = FcPatternObjectFindElt (p, object); 15072c393a42Smrg if (!e) 15082c393a42Smrg return; 15092c393a42Smrg if (e->values == NULL) 15102c393a42Smrg FcPatternObjectDel (p, object); 15112c393a42Smrg} 15122c393a42Smrg 15132c393a42SmrgFcBool 15142c393a42SmrgFcConfigSubstituteWithPat (FcConfig *config, 15152c393a42Smrg FcPattern *p, 15162c393a42Smrg FcPattern *p_pat, 15172c393a42Smrg FcMatchKind kind) 15182c393a42Smrg{ 1519c9710b42Smrg FcValue v; 15202c393a42Smrg FcSubst *s; 15216fc018e4Smrg FcRule *r; 15226fc018e4Smrg FcValueList *l, **value = NULL, *vl; 15232c393a42Smrg FcPattern *m; 1524ca08ab68Smrg FcStrSet *strs; 15256fc018e4Smrg FcObject object = FC_INVALID_OBJECT; 15266fc018e4Smrg FcPatternElt **elt = NULL, *e; 15276fc018e4Smrg int i, nobjs; 15286fc018e4Smrg FcBool retval = FcTrue; 15296fc018e4Smrg FcTest **tst = NULL; 15302c393a42Smrg 15312c393a42Smrg if (!config) 15322c393a42Smrg { 15332c393a42Smrg config = FcConfigGetCurrent (); 15342c393a42Smrg if (!config) 15352c393a42Smrg return FcFalse; 15362c393a42Smrg } 15372c393a42Smrg 15382c393a42Smrg switch (kind) { 15392c393a42Smrg case FcMatchPattern: 15402c393a42Smrg s = config->substPattern; 1541ca08ab68Smrg strs = FcGetDefaultLangs (); 1542ca08ab68Smrg if (strs) 1543ca08ab68Smrg { 1544ca08ab68Smrg FcStrList *l = FcStrListCreate (strs); 1545ca08ab68Smrg FcChar8 *lang; 1546ca08ab68Smrg FcValue v; 154718bd4a06Smrg FcLangSet *lsund = FcLangSetCreate (); 1548ca08ab68Smrg 154918bd4a06Smrg FcLangSetAdd (lsund, (const FcChar8 *)"und"); 1550ca08ab68Smrg FcStrSetDestroy (strs); 1551ca08ab68Smrg while (l && (lang = FcStrListNext (l))) 1552ca08ab68Smrg { 155318bd4a06Smrg FcPatternElt *e = FcPatternObjectFindElt (p, FC_LANG_OBJECT); 155418bd4a06Smrg 155518bd4a06Smrg if (e) 155618bd4a06Smrg { 155718bd4a06Smrg FcValueListPtr ll; 155818bd4a06Smrg 155918bd4a06Smrg for (ll = FcPatternEltValues (e); ll; ll = FcValueListNext (ll)) 156018bd4a06Smrg { 156118bd4a06Smrg FcValue vv = FcValueCanonicalize (&ll->value); 156218bd4a06Smrg 156318bd4a06Smrg if (vv.type == FcTypeLangSet) 156418bd4a06Smrg { 156518bd4a06Smrg FcLangSet *ls = FcLangSetCreate (); 156618bd4a06Smrg FcBool b; 156718bd4a06Smrg 156818bd4a06Smrg FcLangSetAdd (ls, lang); 156918bd4a06Smrg b = FcLangSetContains (vv.u.l, ls); 157018bd4a06Smrg FcLangSetDestroy (ls); 157118bd4a06Smrg if (b) 157218bd4a06Smrg goto bail_lang; 157318bd4a06Smrg if (FcLangSetContains (vv.u.l, lsund)) 157418bd4a06Smrg goto bail_lang; 157518bd4a06Smrg } 157618bd4a06Smrg else 157718bd4a06Smrg { 157818bd4a06Smrg if (FcStrCmpIgnoreCase (vv.u.s, lang) == 0) 157918bd4a06Smrg goto bail_lang; 158018bd4a06Smrg if (FcStrCmpIgnoreCase (vv.u.s, (const FcChar8 *)"und") == 0) 158118bd4a06Smrg goto bail_lang; 158218bd4a06Smrg } 158318bd4a06Smrg } 158418bd4a06Smrg } 1585ca08ab68Smrg v.type = FcTypeString; 1586ca08ab68Smrg v.u.s = lang; 158718bd4a06Smrg 1588ca08ab68Smrg FcPatternObjectAddWithBinding (p, FC_LANG_OBJECT, v, FcValueBindingWeak, FcTrue); 1589ca08ab68Smrg } 159018bd4a06Smrg bail_lang: 1591ca08ab68Smrg FcStrListDone (l); 159218bd4a06Smrg FcLangSetDestroy (lsund); 1593ca08ab68Smrg } 1594c9710b42Smrg if (FcPatternObjectGet (p, FC_PRGNAME_OBJECT, 0, &v) == FcResultNoMatch) 1595c9710b42Smrg { 1596c9710b42Smrg FcChar8 *prgname = FcGetPrgname (); 1597c9710b42Smrg if (prgname) 1598c9710b42Smrg FcPatternObjectAddString (p, FC_PRGNAME_OBJECT, prgname); 1599c9710b42Smrg } 16002c393a42Smrg break; 16012c393a42Smrg case FcMatchFont: 16022c393a42Smrg s = config->substFont; 16032c393a42Smrg break; 16042c393a42Smrg case FcMatchScan: 16052c393a42Smrg s = config->substScan; 16062c393a42Smrg break; 16072c393a42Smrg default: 16082c393a42Smrg return FcFalse; 16092c393a42Smrg } 16102c393a42Smrg 16116fc018e4Smrg nobjs = FC_MAX_BASE_OBJECT + config->maxObjects + 2; 1612cc1bebd6Smrg value = (FcValueList **) malloc (sizeof(void *) * nobjs); 16136fc018e4Smrg if (!value) 16146fc018e4Smrg { 16156fc018e4Smrg retval = FcFalse; 16166fc018e4Smrg goto bail1; 16176fc018e4Smrg } 1618cc1bebd6Smrg elt = (FcPatternElt **) malloc (sizeof(void *) * nobjs); 16196fc018e4Smrg if (!elt) 16206fc018e4Smrg { 16216fc018e4Smrg retval = FcFalse; 16226fc018e4Smrg goto bail1; 16236fc018e4Smrg } 1624cc1bebd6Smrg tst = (FcTest **) malloc (sizeof(void *) * nobjs); 16256fc018e4Smrg if (!tst) 16266fc018e4Smrg { 16276fc018e4Smrg retval = FcFalse; 16286fc018e4Smrg goto bail1; 16296fc018e4Smrg } 16302c393a42Smrg 16312c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 16322c393a42Smrg { 16332c393a42Smrg printf ("FcConfigSubstitute "); 16342c393a42Smrg FcPatternPrint (p); 16352c393a42Smrg } 16362c393a42Smrg for (; s; s = s->next) 16372c393a42Smrg { 16386fc018e4Smrg r = s->rule; 16396fc018e4Smrg for (i = 0; i < nobjs; i++) 16402c393a42Smrg { 16416fc018e4Smrg elt[i] = NULL; 16426fc018e4Smrg value[i] = NULL; 16436fc018e4Smrg tst[i] = NULL; 16446fc018e4Smrg } 16456fc018e4Smrg for (; r; r = r->next) 16466fc018e4Smrg { 16476fc018e4Smrg switch (r->type) { 16486fc018e4Smrg case FcRuleUnknown: 16496fc018e4Smrg /* shouldn't be reached */ 16506fc018e4Smrg break; 16516fc018e4Smrg case FcRuleTest: 16526fc018e4Smrg object = FC_OBJ_ID (r->u.test->object); 16536fc018e4Smrg /* 16546fc018e4Smrg * Check the tests to see if 16556fc018e4Smrg * they all match the pattern 16566fc018e4Smrg */ 16576fc018e4Smrg if (FcDebug () & FC_DBG_EDIT) 16582c393a42Smrg { 16596fc018e4Smrg printf ("FcConfigSubstitute test "); 16606fc018e4Smrg FcTestPrint (r->u.test); 16612c393a42Smrg } 16626fc018e4Smrg if (kind == FcMatchFont && r->u.test->kind == FcMatchPattern) 16636fc018e4Smrg m = p_pat; 16642c393a42Smrg else 16656fc018e4Smrg m = p; 16666fc018e4Smrg if (m) 16676fc018e4Smrg e = FcPatternObjectFindElt (m, r->u.test->object); 16686fc018e4Smrg else 16696fc018e4Smrg e = NULL; 16706fc018e4Smrg /* different 'kind' won't be the target of edit */ 16716fc018e4Smrg if (!elt[object] && kind == r->u.test->kind) 16722c393a42Smrg { 16736fc018e4Smrg elt[object] = e; 16746fc018e4Smrg tst[object] = r->u.test; 16752c393a42Smrg } 16762c393a42Smrg /* 16776fc018e4Smrg * If there's no such field in the font, 16786fc018e4Smrg * then FcQualAll matches while FcQualAny does not 16792c393a42Smrg */ 16806fc018e4Smrg if (!e) 16812c393a42Smrg { 16826fc018e4Smrg if (r->u.test->qual == FcQualAll) 16836fc018e4Smrg { 16846fc018e4Smrg value[object] = NULL; 16856fc018e4Smrg continue; 16866fc018e4Smrg } 16876fc018e4Smrg else 16886fc018e4Smrg { 16896fc018e4Smrg if (FcDebug () & FC_DBG_EDIT) 16906fc018e4Smrg printf ("No match\n"); 16916fc018e4Smrg goto bail; 16926fc018e4Smrg } 16936fc018e4Smrg } 16946fc018e4Smrg /* 16956fc018e4Smrg * Check to see if there is a match, mark the location 16966fc018e4Smrg * to apply match-relative edits 16976fc018e4Smrg */ 16986fc018e4Smrg vl = FcConfigMatchValueList (m, p_pat, kind, r->u.test, e->values); 16996fc018e4Smrg /* different 'kind' won't be the target of edit */ 17006fc018e4Smrg if (!value[object] && kind == r->u.test->kind) 17016fc018e4Smrg value[object] = vl; 17026fc018e4Smrg if (!vl || 17036fc018e4Smrg (r->u.test->qual == FcQualFirst && vl != e->values) || 17046fc018e4Smrg (r->u.test->qual == FcQualNotFirst && vl == e->values)) 17056fc018e4Smrg { 17066fc018e4Smrg if (FcDebug () & FC_DBG_EDIT) 17076fc018e4Smrg printf ("No match\n"); 17086fc018e4Smrg goto bail; 17096fc018e4Smrg } 17106fc018e4Smrg break; 17116fc018e4Smrg case FcRuleEdit: 17126fc018e4Smrg object = FC_OBJ_ID (r->u.edit->object); 17136fc018e4Smrg if (FcDebug () & FC_DBG_EDIT) 17146fc018e4Smrg { 17156fc018e4Smrg printf ("Substitute "); 17166fc018e4Smrg FcEditPrint (r->u.edit); 17176fc018e4Smrg printf ("\n\n"); 17186fc018e4Smrg } 17196fc018e4Smrg /* 17206fc018e4Smrg * Evaluate the list of expressions 17216fc018e4Smrg */ 17226fc018e4Smrg l = FcConfigValues (p, p_pat,kind, r->u.edit->expr, r->u.edit->binding); 17236fc018e4Smrg if (tst[object] && (tst[object]->kind == FcMatchFont || kind == FcMatchPattern)) 17246fc018e4Smrg elt[object] = FcPatternObjectFindElt (p, tst[object]->object); 17256fc018e4Smrg 17266fc018e4Smrg switch (FC_OP_GET_OP (r->u.edit->op)) { 17276fc018e4Smrg case FcOpAssign: 17282c393a42Smrg /* 17296fc018e4Smrg * If there was a test, then replace the matched 17306fc018e4Smrg * value with the new list of values 17312c393a42Smrg */ 17326fc018e4Smrg if (value[object]) 17336fc018e4Smrg { 17346fc018e4Smrg FcValueList *thisValue = value[object]; 17356fc018e4Smrg FcValueList *nextValue = l; 17366fc018e4Smrg 17376fc018e4Smrg /* 17386fc018e4Smrg * Append the new list of values after the current value 17396fc018e4Smrg */ 17406fc018e4Smrg FcConfigAdd (&elt[object]->values, thisValue, FcTrue, l, r->u.edit->object); 17416fc018e4Smrg /* 17426fc018e4Smrg * Delete the marked value 17436fc018e4Smrg */ 17446fc018e4Smrg if (thisValue) 17456fc018e4Smrg FcConfigDel (&elt[object]->values, thisValue); 17466fc018e4Smrg /* 17476fc018e4Smrg * Adjust a pointer into the value list to ensure 17486fc018e4Smrg * future edits occur at the same place 17496fc018e4Smrg */ 17506fc018e4Smrg value[object] = nextValue; 17516fc018e4Smrg break; 17526fc018e4Smrg } 17536fc018e4Smrg /* fall through ... */ 17546fc018e4Smrg case FcOpAssignReplace: 17552c393a42Smrg /* 17566fc018e4Smrg * Delete all of the values and insert 17576fc018e4Smrg * the new set 17582c393a42Smrg */ 17596fc018e4Smrg FcConfigPatternDel (p, r->u.edit->object); 17606fc018e4Smrg FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue); 17612c393a42Smrg /* 17626fc018e4Smrg * Adjust a pointer into the value list as they no 17636fc018e4Smrg * longer point to anything valid 17642c393a42Smrg */ 17656fc018e4Smrg value[object] = NULL; 17666fc018e4Smrg break; 17676fc018e4Smrg case FcOpPrepend: 17686fc018e4Smrg if (value[object]) 17692c393a42Smrg { 17706fc018e4Smrg FcConfigAdd (&elt[object]->values, value[object], FcFalse, l, r->u.edit->object); 17716fc018e4Smrg break; 17722c393a42Smrg } 17736fc018e4Smrg /* fall through ... */ 17746fc018e4Smrg case FcOpPrependFirst: 17756fc018e4Smrg FcConfigPatternAdd (p, r->u.edit->object, l, FcFalse); 17762c393a42Smrg break; 17776fc018e4Smrg case FcOpAppend: 17786fc018e4Smrg if (value[object]) 17792c393a42Smrg { 17806fc018e4Smrg FcConfigAdd (&elt[object]->values, value[object], FcTrue, l, r->u.edit->object); 17816fc018e4Smrg break; 17822c393a42Smrg } 17836fc018e4Smrg /* fall through ... */ 17846fc018e4Smrg case FcOpAppendLast: 17856fc018e4Smrg FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue); 17862c393a42Smrg break; 17876fc018e4Smrg case FcOpDelete: 17886fc018e4Smrg if (value[object]) 17896fc018e4Smrg { 17906fc018e4Smrg FcConfigDel (&elt[object]->values, value[object]); 17916fc018e4Smrg break; 17926fc018e4Smrg } 17936fc018e4Smrg /* fall through ... */ 17946fc018e4Smrg case FcOpDeleteAll: 17956fc018e4Smrg FcConfigPatternDel (p, r->u.edit->object); 17966fc018e4Smrg break; 17976fc018e4Smrg default: 17986fc018e4Smrg FcValueListDestroy (l); 17992c393a42Smrg break; 18002c393a42Smrg } 18016fc018e4Smrg /* 18026fc018e4Smrg * Now go through the pattern and eliminate 18036fc018e4Smrg * any properties without data 18046fc018e4Smrg */ 18056fc018e4Smrg FcConfigPatternCanon (p, r->u.edit->object); 18066fc018e4Smrg 18076fc018e4Smrg if (FcDebug () & FC_DBG_EDIT) 1808c9710b42Smrg { 18096fc018e4Smrg printf ("FcConfigSubstitute edit"); 18106fc018e4Smrg FcPatternPrint (p); 1811c9710b42Smrg } 18122c393a42Smrg break; 18132c393a42Smrg } 18142c393a42Smrg } 18156fc018e4Smrg bail:; 18162c393a42Smrg } 18172c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 18182c393a42Smrg { 18192c393a42Smrg printf ("FcConfigSubstitute done"); 18202c393a42Smrg FcPatternPrint (p); 18212c393a42Smrg } 18226fc018e4Smrgbail1: 18236fc018e4Smrg if (elt) 18246fc018e4Smrg free (elt); 18256fc018e4Smrg if (value) 18266fc018e4Smrg free (value); 18276fc018e4Smrg if (tst) 18286fc018e4Smrg free (tst); 18296fc018e4Smrg 18306fc018e4Smrg return retval; 18312c393a42Smrg} 18322c393a42Smrg 18332c393a42SmrgFcBool 18342c393a42SmrgFcConfigSubstitute (FcConfig *config, 18352c393a42Smrg FcPattern *p, 18362c393a42Smrg FcMatchKind kind) 18372c393a42Smrg{ 18382c393a42Smrg return FcConfigSubstituteWithPat (config, p, 0, kind); 18392c393a42Smrg} 18402c393a42Smrg 18412c393a42Smrg#if defined (_WIN32) 18422c393a42Smrg 1843c9710b42Smrgstatic FcChar8 fontconfig_path[1000] = ""; /* MT-dontcare */ 184418bd4a06SmrgFcChar8 fontconfig_instprefix[1000] = ""; /* MT-dontcare */ 18452c393a42Smrg 18462c393a42Smrg# if (defined (PIC) || defined (DLL_EXPORT)) 18472c393a42Smrg 1848c9710b42SmrgBOOL WINAPI 1849c9710b42SmrgDllMain (HINSTANCE hinstDLL, 1850c9710b42Smrg DWORD fdwReason, 1851c9710b42Smrg LPVOID lpvReserved); 1852c9710b42Smrg 18532c393a42SmrgBOOL WINAPI 18542c393a42SmrgDllMain (HINSTANCE hinstDLL, 18552c393a42Smrg DWORD fdwReason, 18562c393a42Smrg LPVOID lpvReserved) 18572c393a42Smrg{ 18582c393a42Smrg FcChar8 *p; 18592c393a42Smrg 18602c393a42Smrg switch (fdwReason) { 18612c393a42Smrg case DLL_PROCESS_ATTACH: 1862ca08ab68Smrg if (!GetModuleFileName ((HMODULE) hinstDLL, (LPCH) fontconfig_path, 18632c393a42Smrg sizeof (fontconfig_path))) 18642c393a42Smrg break; 18652c393a42Smrg 18662c393a42Smrg /* If the fontconfig DLL is in a "bin" or "lib" subfolder, 18672c393a42Smrg * assume it's a Unix-style installation tree, and use 18682c393a42Smrg * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the 18692c393a42Smrg * folder where the DLL is as FONTCONFIG_PATH. 18702c393a42Smrg */ 1871ca08ab68Smrg p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\'); 18722c393a42Smrg if (p) 18732c393a42Smrg { 18742c393a42Smrg *p = '\0'; 1875ca08ab68Smrg p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\'); 1876ca08ab68Smrg if (p && (FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "bin") == 0 || 1877ca08ab68Smrg FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "lib") == 0)) 18782c393a42Smrg *p = '\0'; 187918bd4a06Smrg strcat ((char *) fontconfig_instprefix, (char *) fontconfig_path); 1880ca08ab68Smrg strcat ((char *) fontconfig_path, "\\etc\\fonts"); 18812c393a42Smrg } 18822c393a42Smrg else 18832c393a42Smrg fontconfig_path[0] = '\0'; 1884ca08ab68Smrg 18852c393a42Smrg break; 18862c393a42Smrg } 18872c393a42Smrg 18882c393a42Smrg return TRUE; 18892c393a42Smrg} 18902c393a42Smrg 18912c393a42Smrg# endif /* !PIC */ 18922c393a42Smrg 18932c393a42Smrg#undef FONTCONFIG_PATH 18942c393a42Smrg#define FONTCONFIG_PATH fontconfig_path 18952c393a42Smrg 18962c393a42Smrg#endif /* !_WIN32 */ 18972c393a42Smrg 18982c393a42Smrg#ifndef FONTCONFIG_FILE 18992c393a42Smrg#define FONTCONFIG_FILE "fonts.conf" 19002c393a42Smrg#endif 19012c393a42Smrg 19022c393a42Smrgstatic FcChar8 * 19032c393a42SmrgFcConfigFileExists (const FcChar8 *dir, const FcChar8 *file) 19042c393a42Smrg{ 19052c393a42Smrg FcChar8 *path; 1906ca08ab68Smrg int size, osize; 19072c393a42Smrg 19082c393a42Smrg if (!dir) 19092c393a42Smrg dir = (FcChar8 *) ""; 1910ca08ab68Smrg 1911ca08ab68Smrg osize = strlen ((char *) dir) + 1 + strlen ((char *) file) + 1; 1912ca08ab68Smrg /* 1913ca08ab68Smrg * workaround valgrind warning because glibc takes advantage of how it knows memory is 1914ca08ab68Smrg * allocated to implement strlen by reading in groups of 4 1915ca08ab68Smrg */ 1916ca08ab68Smrg size = (osize + 3) & ~3; 1917ca08ab68Smrg 1918ca08ab68Smrg path = malloc (size); 19192c393a42Smrg if (!path) 19202c393a42Smrg return 0; 19212c393a42Smrg 19222c393a42Smrg strcpy ((char *) path, (const char *) dir); 19232c393a42Smrg /* make sure there's a single separator */ 19242c393a42Smrg#ifdef _WIN32 19252c393a42Smrg if ((!path[0] || (path[strlen((char *) path)-1] != '/' && 19262c393a42Smrg path[strlen((char *) path)-1] != '\\')) && 19272c393a42Smrg !(file[0] == '/' || 19282c393a42Smrg file[0] == '\\' || 19292c393a42Smrg (isalpha (file[0]) && file[1] == ':' && (file[2] == '/' || file[2] == '\\')))) 19302c393a42Smrg strcat ((char *) path, "\\"); 19312c393a42Smrg#else 19322c393a42Smrg if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/') 19332c393a42Smrg strcat ((char *) path, "/"); 1934c9710b42Smrg else 1935c9710b42Smrg osize--; 19362c393a42Smrg#endif 19372c393a42Smrg strcat ((char *) path, (char *) file); 19382c393a42Smrg 19392c393a42Smrg if (access ((char *) path, R_OK) == 0) 19402c393a42Smrg return path; 1941ca08ab68Smrg 19422c393a42Smrg FcStrFree (path); 1943ca08ab68Smrg 19442c393a42Smrg return 0; 19452c393a42Smrg} 19462c393a42Smrg 19472c393a42Smrgstatic FcChar8 ** 19482c393a42SmrgFcConfigGetPath (void) 19492c393a42Smrg{ 19502c393a42Smrg FcChar8 **path; 19512c393a42Smrg FcChar8 *env, *e, *colon; 19522c393a42Smrg FcChar8 *dir; 19532c393a42Smrg int npath; 19542c393a42Smrg int i; 19552c393a42Smrg 19562c393a42Smrg npath = 2; /* default dir + null */ 19572c393a42Smrg env = (FcChar8 *) getenv ("FONTCONFIG_PATH"); 19582c393a42Smrg if (env) 19592c393a42Smrg { 19602c393a42Smrg e = env; 19612c393a42Smrg npath++; 19622c393a42Smrg while (*e) 19632c393a42Smrg if (*e++ == FC_SEARCH_PATH_SEPARATOR) 19642c393a42Smrg npath++; 19652c393a42Smrg } 19662c393a42Smrg path = calloc (npath, sizeof (FcChar8 *)); 19672c393a42Smrg if (!path) 19682c393a42Smrg goto bail0; 19692c393a42Smrg i = 0; 19702c393a42Smrg 19712c393a42Smrg if (env) 19722c393a42Smrg { 19732c393a42Smrg e = env; 1974ca08ab68Smrg while (*e) 19752c393a42Smrg { 19762c393a42Smrg colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR); 19772c393a42Smrg if (!colon) 19782c393a42Smrg colon = e + strlen ((char *) e); 19792c393a42Smrg path[i] = malloc (colon - e + 1); 19802c393a42Smrg if (!path[i]) 19812c393a42Smrg goto bail1; 19822c393a42Smrg strncpy ((char *) path[i], (const char *) e, colon - e); 19832c393a42Smrg path[i][colon - e] = '\0'; 19842c393a42Smrg if (*colon) 19852c393a42Smrg e = colon + 1; 19862c393a42Smrg else 19872c393a42Smrg e = colon; 19882c393a42Smrg i++; 19892c393a42Smrg } 19902c393a42Smrg } 1991ca08ab68Smrg 19922c393a42Smrg#ifdef _WIN32 19932c393a42Smrg if (fontconfig_path[0] == '\0') 19942c393a42Smrg { 1995a6844aabSmrg char *p; 1996ca08ab68Smrg if(!GetModuleFileName(NULL, (LPCH) fontconfig_path, sizeof(fontconfig_path))) 19972c393a42Smrg goto bail1; 1998ca08ab68Smrg p = strrchr ((const char *) fontconfig_path, '\\'); 19992c393a42Smrg if (p) *p = '\0'; 2000ca08ab68Smrg strcat ((char *) fontconfig_path, "\\fonts"); 20012c393a42Smrg } 20022c393a42Smrg#endif 20032c393a42Smrg dir = (FcChar8 *) FONTCONFIG_PATH; 20042c393a42Smrg path[i] = malloc (strlen ((char *) dir) + 1); 20052c393a42Smrg if (!path[i]) 20062c393a42Smrg goto bail1; 20072c393a42Smrg strcpy ((char *) path[i], (const char *) dir); 20082c393a42Smrg return path; 20092c393a42Smrg 20102c393a42Smrgbail1: 20112c393a42Smrg for (i = 0; path[i]; i++) 20122c393a42Smrg free (path[i]); 20132c393a42Smrg free (path); 20142c393a42Smrgbail0: 20152c393a42Smrg return 0; 20162c393a42Smrg} 20172c393a42Smrg 20182c393a42Smrgstatic void 20192c393a42SmrgFcConfigFreePath (FcChar8 **path) 20202c393a42Smrg{ 20212c393a42Smrg FcChar8 **p; 20222c393a42Smrg 20232c393a42Smrg for (p = path; *p; p++) 20242c393a42Smrg free (*p); 20252c393a42Smrg free (path); 20262c393a42Smrg} 20272c393a42Smrg 2028c9710b42Smrgstatic FcBool _FcConfigHomeEnabled = FcTrue; /* MT-goodenough */ 20292c393a42Smrg 20302c393a42SmrgFcChar8 * 20312c393a42SmrgFcConfigHome (void) 20322c393a42Smrg{ 20332c393a42Smrg if (_FcConfigHomeEnabled) 20342c393a42Smrg { 20352c393a42Smrg char *home = getenv ("HOME"); 20362c393a42Smrg 20372c393a42Smrg#ifdef _WIN32 20382c393a42Smrg if (home == NULL) 20392c393a42Smrg home = getenv ("USERPROFILE"); 20402c393a42Smrg#endif 20412c393a42Smrg 20422c393a42Smrg return (FcChar8 *) home; 20432c393a42Smrg } 20442c393a42Smrg return 0; 20452c393a42Smrg} 20462c393a42Smrg 2047ca08ab68SmrgFcChar8 * 2048ca08ab68SmrgFcConfigXdgCacheHome (void) 2049ca08ab68Smrg{ 2050ca08ab68Smrg const char *env = getenv ("XDG_CACHE_HOME"); 2051ca08ab68Smrg FcChar8 *ret = NULL; 2052ca08ab68Smrg 205318bd4a06Smrg if (!_FcConfigHomeEnabled) 205418bd4a06Smrg return NULL; 2055ca08ab68Smrg if (env) 2056ca08ab68Smrg ret = FcStrCopy ((const FcChar8 *)env); 2057ca08ab68Smrg else 2058ca08ab68Smrg { 2059ca08ab68Smrg const FcChar8 *home = FcConfigHome (); 2060ca08ab68Smrg size_t len = home ? strlen ((const char *)home) : 0; 2061ca08ab68Smrg 2062ca08ab68Smrg ret = malloc (len + 7 + 1); 2063ca08ab68Smrg if (ret) 2064ca08ab68Smrg { 2065ca08ab68Smrg memcpy (ret, home, len); 2066ca08ab68Smrg memcpy (&ret[len], FC_DIR_SEPARATOR_S ".cache", 7); 2067ca08ab68Smrg ret[len + 7] = 0; 2068ca08ab68Smrg } 2069ca08ab68Smrg } 2070ca08ab68Smrg 2071ca08ab68Smrg return ret; 2072ca08ab68Smrg} 2073ca08ab68Smrg 2074ca08ab68SmrgFcChar8 * 2075ca08ab68SmrgFcConfigXdgConfigHome (void) 2076ca08ab68Smrg{ 2077ca08ab68Smrg const char *env = getenv ("XDG_CONFIG_HOME"); 2078ca08ab68Smrg FcChar8 *ret = NULL; 2079ca08ab68Smrg 208018bd4a06Smrg if (!_FcConfigHomeEnabled) 208118bd4a06Smrg return NULL; 2082ca08ab68Smrg if (env) 2083ca08ab68Smrg ret = FcStrCopy ((const FcChar8 *)env); 2084ca08ab68Smrg else 2085ca08ab68Smrg { 2086ca08ab68Smrg const FcChar8 *home = FcConfigHome (); 2087ca08ab68Smrg size_t len = home ? strlen ((const char *)home) : 0; 2088ca08ab68Smrg 2089ca08ab68Smrg ret = malloc (len + 8 + 1); 2090ca08ab68Smrg if (ret) 2091ca08ab68Smrg { 2092ca08ab68Smrg memcpy (ret, home, len); 2093ca08ab68Smrg memcpy (&ret[len], FC_DIR_SEPARATOR_S ".config", 8); 2094ca08ab68Smrg ret[len + 8] = 0; 2095ca08ab68Smrg } 2096ca08ab68Smrg } 2097ca08ab68Smrg 2098ca08ab68Smrg return ret; 2099ca08ab68Smrg} 2100ca08ab68Smrg 2101ca08ab68SmrgFcChar8 * 2102ca08ab68SmrgFcConfigXdgDataHome (void) 2103ca08ab68Smrg{ 2104ca08ab68Smrg const char *env = getenv ("XDG_DATA_HOME"); 2105ca08ab68Smrg FcChar8 *ret = NULL; 2106ca08ab68Smrg 210718bd4a06Smrg if (!_FcConfigHomeEnabled) 210818bd4a06Smrg return NULL; 2109ca08ab68Smrg if (env) 2110ca08ab68Smrg ret = FcStrCopy ((const FcChar8 *)env); 2111ca08ab68Smrg else 2112ca08ab68Smrg { 2113ca08ab68Smrg const FcChar8 *home = FcConfigHome (); 2114ca08ab68Smrg size_t len = home ? strlen ((const char *)home) : 0; 2115ca08ab68Smrg 2116ca08ab68Smrg ret = malloc (len + 13 + 1); 2117ca08ab68Smrg if (ret) 2118ca08ab68Smrg { 2119ca08ab68Smrg memcpy (ret, home, len); 2120ca08ab68Smrg memcpy (&ret[len], FC_DIR_SEPARATOR_S ".local" FC_DIR_SEPARATOR_S "share", 13); 2121ca08ab68Smrg ret[len + 13] = 0; 2122ca08ab68Smrg } 2123ca08ab68Smrg } 2124ca08ab68Smrg 2125ca08ab68Smrg return ret; 2126ca08ab68Smrg} 2127ca08ab68Smrg 21282c393a42SmrgFcBool 21292c393a42SmrgFcConfigEnableHome (FcBool enable) 21302c393a42Smrg{ 21312c393a42Smrg FcBool prev = _FcConfigHomeEnabled; 21322c393a42Smrg _FcConfigHomeEnabled = enable; 21332c393a42Smrg return prev; 21342c393a42Smrg} 21352c393a42Smrg 21362c393a42SmrgFcChar8 * 21372c393a42SmrgFcConfigFilename (const FcChar8 *url) 21382c393a42Smrg{ 21392c393a42Smrg FcChar8 *file, *dir, **path, **p; 21402c393a42Smrg 21412c393a42Smrg if (!url || !*url) 21422c393a42Smrg { 21432c393a42Smrg url = (FcChar8 *) getenv ("FONTCONFIG_FILE"); 21442c393a42Smrg if (!url) 21452c393a42Smrg url = (FcChar8 *) FONTCONFIG_FILE; 21462c393a42Smrg } 21472c393a42Smrg file = 0; 21482c393a42Smrg 21492c393a42Smrg#ifdef _WIN32 21502c393a42Smrg if (isalpha (*url) && 21512c393a42Smrg url[1] == ':' && 21522c393a42Smrg (url[2] == '/' || url[2] == '\\')) 21532c393a42Smrg goto absolute_path; 21542c393a42Smrg#endif 21552c393a42Smrg 21562c393a42Smrg switch (*url) { 21572c393a42Smrg case '~': 21582c393a42Smrg dir = FcConfigHome (); 21592c393a42Smrg if (dir) 21602c393a42Smrg file = FcConfigFileExists (dir, url + 1); 21612c393a42Smrg else 21622c393a42Smrg file = 0; 21632c393a42Smrg break; 21642c393a42Smrg#ifdef _WIN32 21652c393a42Smrg case '\\': 21662c393a42Smrg absolute_path: 21672c393a42Smrg#endif 21682c393a42Smrg case '/': 21692c393a42Smrg file = FcConfigFileExists (0, url); 21702c393a42Smrg break; 21712c393a42Smrg default: 21722c393a42Smrg path = FcConfigGetPath (); 21732c393a42Smrg if (!path) 2174ca08ab68Smrg return NULL; 21752c393a42Smrg for (p = path; *p; p++) 21762c393a42Smrg { 21772c393a42Smrg file = FcConfigFileExists (*p, url); 21782c393a42Smrg if (file) 21792c393a42Smrg break; 21802c393a42Smrg } 21812c393a42Smrg FcConfigFreePath (path); 21822c393a42Smrg break; 21832c393a42Smrg } 2184ca08ab68Smrg 21852c393a42Smrg return file; 21862c393a42Smrg} 21872c393a42Smrg 21882c393a42Smrg/* 21892c393a42Smrg * Manage the application-specific fonts 21902c393a42Smrg */ 21912c393a42Smrg 21922c393a42SmrgFcBool 21932c393a42SmrgFcConfigAppFontAddFile (FcConfig *config, 21942c393a42Smrg const FcChar8 *file) 21952c393a42Smrg{ 21962c393a42Smrg FcFontSet *set; 21972c393a42Smrg FcStrSet *subdirs; 21982c393a42Smrg FcStrList *sublist; 21992c393a42Smrg FcChar8 *subdir; 22002c393a42Smrg 22012c393a42Smrg if (!config) 22022c393a42Smrg { 22032c393a42Smrg config = FcConfigGetCurrent (); 22042c393a42Smrg if (!config) 22052c393a42Smrg return FcFalse; 22062c393a42Smrg } 22072c393a42Smrg 220818bd4a06Smrg subdirs = FcStrSetCreateEx (FCSS_GROW_BY_64); 22092c393a42Smrg if (!subdirs) 22102c393a42Smrg return FcFalse; 2211ca08ab68Smrg 22122c393a42Smrg set = FcConfigGetFonts (config, FcSetApplication); 22132c393a42Smrg if (!set) 22142c393a42Smrg { 22152c393a42Smrg set = FcFontSetCreate (); 22162c393a42Smrg if (!set) 22172c393a42Smrg { 22182c393a42Smrg FcStrSetDestroy (subdirs); 22192c393a42Smrg return FcFalse; 22202c393a42Smrg } 22212c393a42Smrg FcConfigSetFonts (config, set, FcSetApplication); 22222c393a42Smrg } 22232c393a42Smrg 22242c393a42Smrg if (!FcFileScanConfig (set, subdirs, config->blanks, file, config)) 22252c393a42Smrg { 22262c393a42Smrg FcStrSetDestroy (subdirs); 22272c393a42Smrg return FcFalse; 22282c393a42Smrg } 22292c393a42Smrg if ((sublist = FcStrListCreate (subdirs))) 22302c393a42Smrg { 22312c393a42Smrg while ((subdir = FcStrListNext (sublist))) 22322c393a42Smrg { 22332c393a42Smrg FcConfigAppFontAddDir (config, subdir); 22342c393a42Smrg } 22352c393a42Smrg FcStrListDone (sublist); 22362c393a42Smrg } 22372c393a42Smrg FcStrSetDestroy (subdirs); 22382c393a42Smrg return FcTrue; 22392c393a42Smrg} 22402c393a42Smrg 22412c393a42SmrgFcBool 22422c393a42SmrgFcConfigAppFontAddDir (FcConfig *config, 22432c393a42Smrg const FcChar8 *dir) 22442c393a42Smrg{ 22452c393a42Smrg FcFontSet *set; 22462c393a42Smrg FcStrSet *dirs; 2247ca08ab68Smrg 22482c393a42Smrg if (!config) 22492c393a42Smrg { 22502c393a42Smrg config = FcConfigGetCurrent (); 22512c393a42Smrg if (!config) 22522c393a42Smrg return FcFalse; 22532c393a42Smrg } 22542c393a42Smrg 225518bd4a06Smrg dirs = FcStrSetCreateEx (FCSS_GROW_BY_64); 22562c393a42Smrg if (!dirs) 22572c393a42Smrg return FcFalse; 2258ca08ab68Smrg 22592c393a42Smrg set = FcConfigGetFonts (config, FcSetApplication); 22602c393a42Smrg if (!set) 22612c393a42Smrg { 22622c393a42Smrg set = FcFontSetCreate (); 22632c393a42Smrg if (!set) 22642c393a42Smrg { 22652c393a42Smrg FcStrSetDestroy (dirs); 22662c393a42Smrg return FcFalse; 22672c393a42Smrg } 22682c393a42Smrg FcConfigSetFonts (config, set, FcSetApplication); 22692c393a42Smrg } 2270ca08ab68Smrg 22712c393a42Smrg FcStrSetAddFilename (dirs, dir); 2272ca08ab68Smrg 22732c393a42Smrg if (!FcConfigAddDirList (config, FcSetApplication, dirs)) 22742c393a42Smrg { 22752c393a42Smrg FcStrSetDestroy (dirs); 22762c393a42Smrg return FcFalse; 22772c393a42Smrg } 22782c393a42Smrg FcStrSetDestroy (dirs); 22792c393a42Smrg return FcTrue; 22802c393a42Smrg} 22812c393a42Smrg 22822c393a42Smrgvoid 22832c393a42SmrgFcConfigAppFontClear (FcConfig *config) 22842c393a42Smrg{ 22852c393a42Smrg if (!config) 22862c393a42Smrg { 22872c393a42Smrg config = FcConfigGetCurrent (); 22882c393a42Smrg if (!config) 22892c393a42Smrg return; 22902c393a42Smrg } 22912c393a42Smrg 22922c393a42Smrg FcConfigSetFonts (config, 0, FcSetApplication); 22932c393a42Smrg} 22942c393a42Smrg 22952c393a42Smrg/* 22962c393a42Smrg * Manage filename-based font source selectors 22972c393a42Smrg */ 22982c393a42Smrg 22992c393a42SmrgFcBool 23002c393a42SmrgFcConfigGlobAdd (FcConfig *config, 23012c393a42Smrg const FcChar8 *glob, 23022c393a42Smrg FcBool accept) 23032c393a42Smrg{ 23042c393a42Smrg FcStrSet *set = accept ? config->acceptGlobs : config->rejectGlobs; 23052c393a42Smrg 23062c393a42Smrg return FcStrSetAdd (set, glob); 23072c393a42Smrg} 23082c393a42Smrg 23092c393a42Smrgstatic FcBool 23102c393a42SmrgFcConfigGlobsMatch (const FcStrSet *globs, 23112c393a42Smrg const FcChar8 *string) 23122c393a42Smrg{ 23132c393a42Smrg int i; 23142c393a42Smrg 23152c393a42Smrg for (i = 0; i < globs->num; i++) 2316c9710b42Smrg if (FcStrGlobMatch (globs->strs[i], string)) 23172c393a42Smrg return FcTrue; 23182c393a42Smrg return FcFalse; 23192c393a42Smrg} 23202c393a42Smrg 23212c393a42SmrgFcBool 23222c393a42SmrgFcConfigAcceptFilename (FcConfig *config, 23232c393a42Smrg const FcChar8 *filename) 23242c393a42Smrg{ 23252c393a42Smrg if (FcConfigGlobsMatch (config->acceptGlobs, filename)) 23262c393a42Smrg return FcTrue; 23272c393a42Smrg if (FcConfigGlobsMatch (config->rejectGlobs, filename)) 23282c393a42Smrg return FcFalse; 23292c393a42Smrg return FcTrue; 23302c393a42Smrg} 23312c393a42Smrg 23322c393a42Smrg/* 23332c393a42Smrg * Manage font-pattern based font source selectors 23342c393a42Smrg */ 23352c393a42Smrg 23362c393a42SmrgFcBool 23372c393a42SmrgFcConfigPatternsAdd (FcConfig *config, 23382c393a42Smrg FcPattern *pattern, 23392c393a42Smrg FcBool accept) 23402c393a42Smrg{ 23412c393a42Smrg FcFontSet *set = accept ? config->acceptPatterns : config->rejectPatterns; 23422c393a42Smrg 23432c393a42Smrg return FcFontSetAdd (set, pattern); 23442c393a42Smrg} 23452c393a42Smrg 23462c393a42Smrgstatic FcBool 23472c393a42SmrgFcConfigPatternsMatch (const FcFontSet *patterns, 23482c393a42Smrg const FcPattern *font) 23492c393a42Smrg{ 23502c393a42Smrg int i; 2351ca08ab68Smrg 23522c393a42Smrg for (i = 0; i < patterns->nfont; i++) 23532c393a42Smrg if (FcListPatternMatchAny (patterns->fonts[i], font)) 23542c393a42Smrg return FcTrue; 23552c393a42Smrg return FcFalse; 23562c393a42Smrg} 23572c393a42Smrg 23582c393a42SmrgFcBool 23592c393a42SmrgFcConfigAcceptFont (FcConfig *config, 23602c393a42Smrg const FcPattern *font) 23612c393a42Smrg{ 23622c393a42Smrg if (FcConfigPatternsMatch (config->acceptPatterns, font)) 23632c393a42Smrg return FcTrue; 23642c393a42Smrg if (FcConfigPatternsMatch (config->rejectPatterns, font)) 23652c393a42Smrg return FcFalse; 23662c393a42Smrg return FcTrue; 23672c393a42Smrg} 2368c9710b42Smrg 2369c9710b42Smrgconst FcChar8 * 2370c9710b42SmrgFcConfigGetSysRoot (const FcConfig *config) 2371c9710b42Smrg{ 2372c9710b42Smrg if (!config) 2373c9710b42Smrg { 2374c9710b42Smrg config = FcConfigGetCurrent (); 2375c9710b42Smrg if (!config) 2376c9710b42Smrg return NULL; 2377c9710b42Smrg } 2378c9710b42Smrg 2379c9710b42Smrg return config->sysRoot; 2380c9710b42Smrg} 2381c9710b42Smrg 2382c9710b42Smrgvoid 2383c9710b42SmrgFcConfigSetSysRoot (FcConfig *config, 2384c9710b42Smrg const FcChar8 *sysroot) 2385c9710b42Smrg{ 238618bd4a06Smrg FcChar8 *s = NULL; 2387c9710b42Smrg FcBool init = FcFalse; 2388c9710b42Smrg 2389c9710b42Smrg if (!config) 2390c9710b42Smrg { 2391c9710b42Smrg /* We can't use FcConfigGetCurrent() here to ensure 2392c9710b42Smrg * the sysroot is set prior to initialize FcConfig, 2393c9710b42Smrg * to avoid loading caches from non-sysroot dirs. 2394c9710b42Smrg * So postpone the initialization later. 2395c9710b42Smrg */ 2396c9710b42Smrg config = fc_atomic_ptr_get (&_fcConfig); 2397c9710b42Smrg if (!config) 2398c9710b42Smrg { 2399c9710b42Smrg config = FcConfigCreate (); 2400c9710b42Smrg if (!config) 2401c9710b42Smrg return; 2402c9710b42Smrg init = FcTrue; 2403c9710b42Smrg } 2404c9710b42Smrg } 2405c9710b42Smrg 240618bd4a06Smrg if (sysroot) 240718bd4a06Smrg { 240818bd4a06Smrg s = FcStrCopyFilename (sysroot); 240918bd4a06Smrg if (!s) 241018bd4a06Smrg return; 241118bd4a06Smrg } 2412c9710b42Smrg 2413c9710b42Smrg if (config->sysRoot) 2414c9710b42Smrg FcStrFree (config->sysRoot); 2415c9710b42Smrg 2416c9710b42Smrg config->sysRoot = s; 2417c9710b42Smrg if (init) 2418c9710b42Smrg { 2419c9710b42Smrg config = FcInitLoadOwnConfigAndFonts (config); 2420c9710b42Smrg FcConfigSetCurrent (config); 242118bd4a06Smrg /* FcConfigSetCurrent() increases the refcount. 242218bd4a06Smrg * decrease it here to avoid the memory leak. 242318bd4a06Smrg */ 242418bd4a06Smrg FcConfigDestroy (config); 2425c9710b42Smrg } 2426c9710b42Smrg} 2427c9710b42Smrg 24282c393a42Smrg#define __fccfg__ 24292c393a42Smrg#include "fcaliastail.h" 24302c393a42Smrg#undef __fccfg__ 2431