fccfg.c revision ca08ab68
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 252c393a42Smrg#include "fcint.h" 262c393a42Smrg#include <dirent.h> 272c393a42Smrg#include <sys/types.h> 282c393a42Smrg 292c393a42Smrg#if defined (_WIN32) && (defined (PIC) || defined (DLL_EXPORT)) 302c393a42Smrg#define STRICT 312c393a42Smrg#include <windows.h> 322c393a42Smrg#undef STRICT 332c393a42Smrg#endif 342c393a42Smrg 352c393a42Smrg#if defined (_WIN32) && !defined (R_OK) 362c393a42Smrg#define R_OK 4 372c393a42Smrg#endif 382c393a42Smrg 392c393a42SmrgFcConfig *_fcConfig; 402c393a42Smrg 412c393a42SmrgFcConfig * 422c393a42SmrgFcConfigCreate (void) 432c393a42Smrg{ 442c393a42Smrg FcSetName set; 452c393a42Smrg FcConfig *config; 462c393a42Smrg 472c393a42Smrg config = malloc (sizeof (FcConfig)); 482c393a42Smrg if (!config) 492c393a42Smrg goto bail0; 502c393a42Smrg FcMemAlloc (FC_MEM_CONFIG, sizeof (FcConfig)); 51ca08ab68Smrg 522c393a42Smrg config->configDirs = FcStrSetCreate (); 532c393a42Smrg if (!config->configDirs) 542c393a42Smrg goto bail1; 55ca08ab68Smrg 562c393a42Smrg config->configFiles = FcStrSetCreate (); 572c393a42Smrg if (!config->configFiles) 582c393a42Smrg goto bail2; 59ca08ab68Smrg 602c393a42Smrg config->fontDirs = FcStrSetCreate (); 612c393a42Smrg if (!config->fontDirs) 622c393a42Smrg goto bail3; 63ca08ab68Smrg 642c393a42Smrg config->acceptGlobs = FcStrSetCreate (); 652c393a42Smrg if (!config->acceptGlobs) 662c393a42Smrg goto bail4; 672c393a42Smrg 682c393a42Smrg config->rejectGlobs = FcStrSetCreate (); 692c393a42Smrg if (!config->rejectGlobs) 702c393a42Smrg goto bail5; 712c393a42Smrg 722c393a42Smrg config->acceptPatterns = FcFontSetCreate (); 732c393a42Smrg if (!config->acceptPatterns) 742c393a42Smrg goto bail6; 75ca08ab68Smrg 762c393a42Smrg config->rejectPatterns = FcFontSetCreate (); 772c393a42Smrg if (!config->rejectPatterns) 782c393a42Smrg goto bail7; 792c393a42Smrg 802c393a42Smrg config->cacheDirs = FcStrSetCreate (); 812c393a42Smrg if (!config->cacheDirs) 822c393a42Smrg goto bail8; 83ca08ab68Smrg 842c393a42Smrg config->blanks = 0; 852c393a42Smrg 862c393a42Smrg config->substPattern = 0; 872c393a42Smrg config->substFont = 0; 882c393a42Smrg config->substScan = 0; 892c393a42Smrg config->maxObjects = 0; 902c393a42Smrg for (set = FcSetSystem; set <= FcSetApplication; set++) 912c393a42Smrg config->fonts[set] = 0; 922c393a42Smrg 932c393a42Smrg config->rescanTime = time(0); 94ca08ab68Smrg config->rescanInterval = 30; 95a6844aabSmrg 96a6844aabSmrg config->expr_pool = NULL; 97a6844aabSmrg 98a6844aabSmrg config->ref = 1; 99ca08ab68Smrg 1002c393a42Smrg return config; 1012c393a42Smrg 1022c393a42Smrgbail8: 1032c393a42Smrg FcFontSetDestroy (config->rejectPatterns); 1042c393a42Smrgbail7: 1052c393a42Smrg FcFontSetDestroy (config->acceptPatterns); 1062c393a42Smrgbail6: 1072c393a42Smrg FcStrSetDestroy (config->rejectGlobs); 1082c393a42Smrgbail5: 1092c393a42Smrg FcStrSetDestroy (config->acceptGlobs); 1102c393a42Smrgbail4: 1112c393a42Smrg FcStrSetDestroy (config->fontDirs); 1122c393a42Smrgbail3: 1132c393a42Smrg FcStrSetDestroy (config->configFiles); 1142c393a42Smrgbail2: 1152c393a42Smrg FcStrSetDestroy (config->configDirs); 1162c393a42Smrgbail1: 1172c393a42Smrg free (config); 1182c393a42Smrg FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig)); 1192c393a42Smrgbail0: 1202c393a42Smrg return 0; 1212c393a42Smrg} 1222c393a42Smrg 1232c393a42Smrgstatic FcFileTime 1242c393a42SmrgFcConfigNewestFile (FcStrSet *files) 1252c393a42Smrg{ 1262c393a42Smrg FcStrList *list = FcStrListCreate (files); 1272c393a42Smrg FcFileTime newest = { 0, FcFalse }; 1282c393a42Smrg FcChar8 *file; 1292c393a42Smrg struct stat statb; 1302c393a42Smrg 1312c393a42Smrg if (list) 1322c393a42Smrg { 1332c393a42Smrg while ((file = FcStrListNext (list))) 134ca08ab68Smrg if (FcStat (file, &statb) == 0) 1352c393a42Smrg if (!newest.set || statb.st_mtime - newest.time > 0) 1362c393a42Smrg { 1372c393a42Smrg newest.set = FcTrue; 1382c393a42Smrg newest.time = statb.st_mtime; 1392c393a42Smrg } 1402c393a42Smrg FcStrListDone (list); 1412c393a42Smrg } 1422c393a42Smrg return newest; 1432c393a42Smrg} 1442c393a42Smrg 1452c393a42SmrgFcBool 1462c393a42SmrgFcConfigUptoDate (FcConfig *config) 1472c393a42Smrg{ 1482c393a42Smrg FcFileTime config_time, config_dir_time, font_time; 1492c393a42Smrg time_t now = time(0); 1502c393a42Smrg if (!config) 1512c393a42Smrg { 1522c393a42Smrg config = FcConfigGetCurrent (); 1532c393a42Smrg if (!config) 1542c393a42Smrg return FcFalse; 1552c393a42Smrg } 1562c393a42Smrg config_time = FcConfigNewestFile (config->configFiles); 1572c393a42Smrg config_dir_time = FcConfigNewestFile (config->configDirs); 1582c393a42Smrg font_time = FcConfigNewestFile (config->fontDirs); 1592c393a42Smrg if ((config_time.set && config_time.time - config->rescanTime > 0) || 1602c393a42Smrg (config_dir_time.set && (config_dir_time.time - config->rescanTime) > 0) || 1612c393a42Smrg (font_time.set && (font_time.time - config->rescanTime) > 0)) 1622c393a42Smrg { 1632c393a42Smrg /* We need to check for potential clock problems here (OLPC ticket #6046) */ 1642c393a42Smrg if ((config_time.set && (config_time.time - now) > 0) || 1652c393a42Smrg (config_dir_time.set && (config_dir_time.time - now) > 0) || 1662c393a42Smrg (font_time.set && (font_time.time - now) > 0)) 1672c393a42Smrg { 1682c393a42Smrg fprintf (stderr, 1692c393a42Smrg "Fontconfig warning: Directory/file mtime in the future. New fonts may not be detected\n"); 1702c393a42Smrg config->rescanTime = now; 1712c393a42Smrg return FcTrue; 1722c393a42Smrg } 1732c393a42Smrg else 1742c393a42Smrg return FcFalse; 1752c393a42Smrg } 1762c393a42Smrg config->rescanTime = now; 1772c393a42Smrg return FcTrue; 1782c393a42Smrg} 1792c393a42Smrg 1802c393a42Smrgstatic void 1812c393a42SmrgFcSubstDestroy (FcSubst *s) 1822c393a42Smrg{ 1832c393a42Smrg FcSubst *n; 184ca08ab68Smrg 1852c393a42Smrg while (s) 1862c393a42Smrg { 1872c393a42Smrg n = s->next; 1882c393a42Smrg if (s->test) 1892c393a42Smrg FcTestDestroy (s->test); 1902c393a42Smrg if (s->edit) 1912c393a42Smrg FcEditDestroy (s->edit); 1922c393a42Smrg free (s); 1932c393a42Smrg FcMemFree (FC_MEM_SUBST, sizeof (FcSubst)); 1942c393a42Smrg s = n; 1952c393a42Smrg } 1962c393a42Smrg} 1972c393a42Smrg 198a6844aabSmrgFcExpr * 199a6844aabSmrgFcConfigAllocExpr (FcConfig *config) 200a6844aabSmrg{ 201a6844aabSmrg if (!config->expr_pool || config->expr_pool->next == config->expr_pool->end) 202a6844aabSmrg { 203a6844aabSmrg FcExprPage *new_page; 204a6844aabSmrg 205a6844aabSmrg new_page = malloc (sizeof (FcExprPage)); 206a6844aabSmrg if (!new_page) 207a6844aabSmrg return 0; 208a6844aabSmrg FcMemAlloc (FC_MEM_EXPR, sizeof (FcExprPage)); 209a6844aabSmrg 210a6844aabSmrg new_page->next_page = config->expr_pool; 211a6844aabSmrg new_page->next = new_page->exprs; 212a6844aabSmrg config->expr_pool = new_page; 213a6844aabSmrg } 214a6844aabSmrg 215a6844aabSmrg return config->expr_pool->next++; 216a6844aabSmrg} 217a6844aabSmrg 218a6844aabSmrgFcConfig * 219a6844aabSmrgFcConfigReference (FcConfig *config) 220a6844aabSmrg{ 221a6844aabSmrg if (!config) 222a6844aabSmrg { 223a6844aabSmrg config = FcConfigGetCurrent (); 224a6844aabSmrg if (!config) 225a6844aabSmrg return 0; 226a6844aabSmrg } 227a6844aabSmrg 228a6844aabSmrg config->ref++; 229a6844aabSmrg 230a6844aabSmrg return config; 231a6844aabSmrg} 232a6844aabSmrg 2332c393a42Smrgvoid 2342c393a42SmrgFcConfigDestroy (FcConfig *config) 2352c393a42Smrg{ 2362c393a42Smrg FcSetName set; 237a6844aabSmrg FcExprPage *page; 238a6844aabSmrg 239a6844aabSmrg if (--config->ref > 0) 240a6844aabSmrg return; 2412c393a42Smrg 2422c393a42Smrg if (config == _fcConfig) 2432c393a42Smrg _fcConfig = 0; 2442c393a42Smrg 2452c393a42Smrg FcStrSetDestroy (config->configDirs); 2462c393a42Smrg FcStrSetDestroy (config->fontDirs); 2472c393a42Smrg FcStrSetDestroy (config->cacheDirs); 2482c393a42Smrg FcStrSetDestroy (config->configFiles); 2492c393a42Smrg FcStrSetDestroy (config->acceptGlobs); 2502c393a42Smrg FcStrSetDestroy (config->rejectGlobs); 2512c393a42Smrg FcFontSetDestroy (config->acceptPatterns); 2522c393a42Smrg FcFontSetDestroy (config->rejectPatterns); 2532c393a42Smrg 2542c393a42Smrg if (config->blanks) 2552c393a42Smrg FcBlanksDestroy (config->blanks); 2562c393a42Smrg 2572c393a42Smrg FcSubstDestroy (config->substPattern); 2582c393a42Smrg FcSubstDestroy (config->substFont); 2592c393a42Smrg FcSubstDestroy (config->substScan); 2602c393a42Smrg for (set = FcSetSystem; set <= FcSetApplication; set++) 2612c393a42Smrg if (config->fonts[set]) 2622c393a42Smrg FcFontSetDestroy (config->fonts[set]); 2632c393a42Smrg 264a6844aabSmrg page = config->expr_pool; 265a6844aabSmrg while (page) 266a6844aabSmrg { 267a6844aabSmrg FcExprPage *next = page->next_page; 268a6844aabSmrg FcMemFree (FC_MEM_EXPR, sizeof (FcExprPage)); 269a6844aabSmrg free (page); 270a6844aabSmrg page = next; 271a6844aabSmrg } 272a6844aabSmrg 2732c393a42Smrg free (config); 2742c393a42Smrg FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig)); 2752c393a42Smrg} 2762c393a42Smrg 2772c393a42Smrg/* 2782c393a42Smrg * Add cache to configuration, adding fonts and directories 2792c393a42Smrg */ 2802c393a42Smrg 2812c393a42SmrgFcBool 282ca08ab68SmrgFcConfigAddCache (FcConfig *config, FcCache *cache, 2832c393a42Smrg FcSetName set, FcStrSet *dirSet) 2842c393a42Smrg{ 2852c393a42Smrg FcFontSet *fs; 2862c393a42Smrg intptr_t *dirs; 2872c393a42Smrg int i; 2882c393a42Smrg 2892c393a42Smrg /* 2902c393a42Smrg * Add fonts 2912c393a42Smrg */ 2922c393a42Smrg fs = FcCacheSet (cache); 2932c393a42Smrg if (fs) 2942c393a42Smrg { 2952c393a42Smrg int nref = 0; 2962c393a42Smrg 2972c393a42Smrg for (i = 0; i < fs->nfont; i++) 2982c393a42Smrg { 2992c393a42Smrg FcPattern *font = FcFontSetFont (fs, i); 3002c393a42Smrg FcChar8 *font_file; 3012c393a42Smrg 3022c393a42Smrg /* 3032c393a42Smrg * Check to see if font is banned by filename 3042c393a42Smrg */ 3052c393a42Smrg if (FcPatternObjectGetString (font, FC_FILE_OBJECT, 3062c393a42Smrg 0, &font_file) == FcResultMatch && 3072c393a42Smrg !FcConfigAcceptFilename (config, font_file)) 3082c393a42Smrg { 3092c393a42Smrg continue; 3102c393a42Smrg } 3112c393a42Smrg 3122c393a42Smrg /* 3132c393a42Smrg * Check to see if font is banned by pattern 3142c393a42Smrg */ 3152c393a42Smrg if (!FcConfigAcceptFont (config, font)) 3162c393a42Smrg continue; 3172c393a42Smrg 3182c393a42Smrg nref++; 3192c393a42Smrg FcFontSetAdd (config->fonts[set], font); 3202c393a42Smrg } 3212c393a42Smrg FcDirCacheReference (cache, nref); 3222c393a42Smrg } 3232c393a42Smrg 3242c393a42Smrg /* 3252c393a42Smrg * Add directories 3262c393a42Smrg */ 3272c393a42Smrg dirs = FcCacheDirs (cache); 3282c393a42Smrg if (dirs) 3292c393a42Smrg { 3302c393a42Smrg for (i = 0; i < cache->dirs_count; i++) 3312c393a42Smrg { 3322c393a42Smrg FcChar8 *dir = FcOffsetToPtr (dirs, dirs[i], FcChar8); 3332c393a42Smrg if (FcConfigAcceptFilename (config, dir)) 3342c393a42Smrg FcStrSetAddFilename (dirSet, dir); 3352c393a42Smrg } 3362c393a42Smrg } 3372c393a42Smrg return FcTrue; 3382c393a42Smrg} 3392c393a42Smrg 3402c393a42Smrgstatic FcBool 3412c393a42SmrgFcConfigAddDirList (FcConfig *config, FcSetName set, FcStrSet *dirSet) 3422c393a42Smrg{ 3432c393a42Smrg FcStrList *dirlist; 3442c393a42Smrg FcChar8 *dir; 3452c393a42Smrg FcCache *cache; 346ca08ab68Smrg 3472c393a42Smrg dirlist = FcStrListCreate (dirSet); 3482c393a42Smrg if (!dirlist) 3492c393a42Smrg return FcFalse; 3502c393a42Smrg 3512c393a42Smrg while ((dir = FcStrListNext (dirlist))) 3522c393a42Smrg { 3532c393a42Smrg if (FcDebug () & FC_DBG_FONTSET) 3542c393a42Smrg printf ("adding fonts from%s\n", dir); 3552c393a42Smrg cache = FcDirCacheRead (dir, FcFalse, config); 3562c393a42Smrg if (!cache) 3572c393a42Smrg continue; 3582c393a42Smrg FcConfigAddCache (config, cache, set, dirSet); 3592c393a42Smrg FcDirCacheUnload (cache); 3602c393a42Smrg } 3612c393a42Smrg FcStrListDone (dirlist); 3622c393a42Smrg return FcTrue; 3632c393a42Smrg} 3642c393a42Smrg 3652c393a42Smrg/* 3662c393a42Smrg * Scan the current list of directories in the configuration 3672c393a42Smrg * and build the set of available fonts. 3682c393a42Smrg */ 3692c393a42Smrg 3702c393a42SmrgFcBool 3712c393a42SmrgFcConfigBuildFonts (FcConfig *config) 3722c393a42Smrg{ 3732c393a42Smrg FcFontSet *fonts; 3742c393a42Smrg 3752c393a42Smrg if (!config) 3762c393a42Smrg { 3772c393a42Smrg config = FcConfigGetCurrent (); 3782c393a42Smrg if (!config) 3792c393a42Smrg return FcFalse; 3802c393a42Smrg } 3812c393a42Smrg 3822c393a42Smrg fonts = FcFontSetCreate (); 3832c393a42Smrg if (!fonts) 3842c393a42Smrg return FcFalse; 385ca08ab68Smrg 3862c393a42Smrg FcConfigSetFonts (config, fonts, FcSetSystem); 387ca08ab68Smrg 3882c393a42Smrg if (!FcConfigAddDirList (config, FcSetSystem, config->fontDirs)) 3892c393a42Smrg return FcFalse; 3902c393a42Smrg if (FcDebug () & FC_DBG_FONTSET) 3912c393a42Smrg FcFontSetPrint (fonts); 3922c393a42Smrg return FcTrue; 3932c393a42Smrg} 3942c393a42Smrg 3952c393a42SmrgFcBool 3962c393a42SmrgFcConfigSetCurrent (FcConfig *config) 3972c393a42Smrg{ 3982c393a42Smrg if (config == _fcConfig) 3992c393a42Smrg return FcTrue; 4002c393a42Smrg 4012c393a42Smrg if (!config->fonts) 4022c393a42Smrg if (!FcConfigBuildFonts (config)) 4032c393a42Smrg return FcFalse; 4042c393a42Smrg 4052c393a42Smrg if (_fcConfig) 4062c393a42Smrg FcConfigDestroy (_fcConfig); 4072c393a42Smrg _fcConfig = config; 4082c393a42Smrg return FcTrue; 4092c393a42Smrg} 4102c393a42Smrg 4112c393a42SmrgFcConfig * 4122c393a42SmrgFcConfigGetCurrent (void) 4132c393a42Smrg{ 4142c393a42Smrg if (!_fcConfig) 4152c393a42Smrg if (!FcInit ()) 4162c393a42Smrg return 0; 4172c393a42Smrg return _fcConfig; 4182c393a42Smrg} 4192c393a42Smrg 4202c393a42SmrgFcBool 4212c393a42SmrgFcConfigAddConfigDir (FcConfig *config, 4222c393a42Smrg const FcChar8 *d) 4232c393a42Smrg{ 4242c393a42Smrg return FcStrSetAddFilename (config->configDirs, d); 4252c393a42Smrg} 4262c393a42Smrg 4272c393a42SmrgFcStrList * 4282c393a42SmrgFcConfigGetConfigDirs (FcConfig *config) 4292c393a42Smrg{ 4302c393a42Smrg if (!config) 4312c393a42Smrg { 4322c393a42Smrg config = FcConfigGetCurrent (); 4332c393a42Smrg if (!config) 4342c393a42Smrg return 0; 4352c393a42Smrg } 4362c393a42Smrg return FcStrListCreate (config->configDirs); 4372c393a42Smrg} 4382c393a42Smrg 4392c393a42SmrgFcBool 4402c393a42SmrgFcConfigAddFontDir (FcConfig *config, 4412c393a42Smrg const FcChar8 *d) 4422c393a42Smrg{ 4432c393a42Smrg return FcStrSetAddFilename (config->fontDirs, d); 4442c393a42Smrg} 4452c393a42Smrg 4462c393a42SmrgFcBool 4472c393a42SmrgFcConfigAddDir (FcConfig *config, 4482c393a42Smrg const FcChar8 *d) 4492c393a42Smrg{ 450ca08ab68Smrg return (FcConfigAddConfigDir (config, d) && 4512c393a42Smrg FcConfigAddFontDir (config, d)); 4522c393a42Smrg} 4532c393a42Smrg 4542c393a42SmrgFcStrList * 4552c393a42SmrgFcConfigGetFontDirs (FcConfig *config) 4562c393a42Smrg{ 4572c393a42Smrg if (!config) 4582c393a42Smrg { 4592c393a42Smrg config = FcConfigGetCurrent (); 4602c393a42Smrg if (!config) 4612c393a42Smrg return 0; 4622c393a42Smrg } 4632c393a42Smrg return FcStrListCreate (config->fontDirs); 4642c393a42Smrg} 4652c393a42Smrg 4662c393a42SmrgFcBool 4672c393a42SmrgFcConfigAddCacheDir (FcConfig *config, 4682c393a42Smrg const FcChar8 *d) 4692c393a42Smrg{ 4702c393a42Smrg return FcStrSetAddFilename (config->cacheDirs, d); 4712c393a42Smrg} 4722c393a42Smrg 4732c393a42SmrgFcStrList * 474ca08ab68SmrgFcConfigGetCacheDirs (const FcConfig *config) 4752c393a42Smrg{ 4762c393a42Smrg if (!config) 4772c393a42Smrg { 4782c393a42Smrg config = FcConfigGetCurrent (); 4792c393a42Smrg if (!config) 4802c393a42Smrg return 0; 4812c393a42Smrg } 4822c393a42Smrg return FcStrListCreate (config->cacheDirs); 4832c393a42Smrg} 484ca08ab68Smrg 4852c393a42SmrgFcBool 4862c393a42SmrgFcConfigAddConfigFile (FcConfig *config, 4872c393a42Smrg const FcChar8 *f) 4882c393a42Smrg{ 4892c393a42Smrg FcBool ret; 4902c393a42Smrg FcChar8 *file = FcConfigFilename (f); 491ca08ab68Smrg 4922c393a42Smrg if (!file) 4932c393a42Smrg return FcFalse; 494ca08ab68Smrg 4952c393a42Smrg ret = FcStrSetAdd (config->configFiles, file); 4962c393a42Smrg FcStrFree (file); 4972c393a42Smrg return ret; 4982c393a42Smrg} 4992c393a42Smrg 5002c393a42SmrgFcStrList * 5012c393a42SmrgFcConfigGetConfigFiles (FcConfig *config) 5022c393a42Smrg{ 5032c393a42Smrg if (!config) 5042c393a42Smrg { 5052c393a42Smrg config = FcConfigGetCurrent (); 5062c393a42Smrg if (!config) 5072c393a42Smrg return 0; 5082c393a42Smrg } 5092c393a42Smrg return FcStrListCreate (config->configFiles); 5102c393a42Smrg} 5112c393a42Smrg 5122c393a42SmrgFcChar8 * 5132c393a42SmrgFcConfigGetCache (FcConfig *config) 5142c393a42Smrg{ 5152c393a42Smrg return NULL; 5162c393a42Smrg} 5172c393a42Smrg 5182c393a42SmrgFcFontSet * 5192c393a42SmrgFcConfigGetFonts (FcConfig *config, 5202c393a42Smrg FcSetName set) 5212c393a42Smrg{ 5222c393a42Smrg if (!config) 5232c393a42Smrg { 5242c393a42Smrg config = FcConfigGetCurrent (); 5252c393a42Smrg if (!config) 5262c393a42Smrg return 0; 5272c393a42Smrg } 5282c393a42Smrg return config->fonts[set]; 5292c393a42Smrg} 5302c393a42Smrg 5312c393a42Smrgvoid 5322c393a42SmrgFcConfigSetFonts (FcConfig *config, 5332c393a42Smrg FcFontSet *fonts, 5342c393a42Smrg FcSetName set) 5352c393a42Smrg{ 5362c393a42Smrg if (config->fonts[set]) 5372c393a42Smrg FcFontSetDestroy (config->fonts[set]); 5382c393a42Smrg config->fonts[set] = fonts; 5392c393a42Smrg} 5402c393a42Smrg 5412c393a42SmrgFcBlanks * 5422c393a42SmrgFcConfigGetBlanks (FcConfig *config) 5432c393a42Smrg{ 5442c393a42Smrg if (!config) 5452c393a42Smrg { 5462c393a42Smrg config = FcConfigGetCurrent (); 5472c393a42Smrg if (!config) 5482c393a42Smrg return 0; 5492c393a42Smrg } 5502c393a42Smrg return config->blanks; 5512c393a42Smrg} 5522c393a42Smrg 5532c393a42SmrgFcBool 5542c393a42SmrgFcConfigAddBlank (FcConfig *config, 5552c393a42Smrg FcChar32 blank) 5562c393a42Smrg{ 5572c393a42Smrg FcBlanks *b, *freeme = 0; 558ca08ab68Smrg 5592c393a42Smrg b = config->blanks; 5602c393a42Smrg if (!b) 5612c393a42Smrg { 5622c393a42Smrg freeme = b = FcBlanksCreate (); 5632c393a42Smrg if (!b) 5642c393a42Smrg return FcFalse; 5652c393a42Smrg } 5662c393a42Smrg if (!FcBlanksAdd (b, blank)) 5672c393a42Smrg { 5682c393a42Smrg if (freeme) 5692c393a42Smrg FcBlanksDestroy (freeme); 5702c393a42Smrg return FcFalse; 5712c393a42Smrg } 5722c393a42Smrg config->blanks = b; 5732c393a42Smrg return FcTrue; 5742c393a42Smrg} 5752c393a42Smrg 5762c393a42Smrgint 5772c393a42SmrgFcConfigGetRescanInterval (FcConfig *config) 5782c393a42Smrg{ 5792c393a42Smrg if (!config) 5802c393a42Smrg { 5812c393a42Smrg config = FcConfigGetCurrent (); 5822c393a42Smrg if (!config) 5832c393a42Smrg return 0; 5842c393a42Smrg } 5852c393a42Smrg return config->rescanInterval; 5862c393a42Smrg} 5872c393a42Smrg 5882c393a42SmrgFcBool 5892c393a42SmrgFcConfigSetRescanInterval (FcConfig *config, int rescanInterval) 5902c393a42Smrg{ 5912c393a42Smrg if (!config) 5922c393a42Smrg { 5932c393a42Smrg config = FcConfigGetCurrent (); 5942c393a42Smrg if (!config) 5952c393a42Smrg return FcFalse; 5962c393a42Smrg } 5972c393a42Smrg config->rescanInterval = rescanInterval; 5982c393a42Smrg return FcTrue; 5992c393a42Smrg} 6002c393a42Smrg 6012c393a42Smrg/* 6022c393a42Smrg * A couple of typos escaped into the library 6032c393a42Smrg */ 6042c393a42Smrgint 6052c393a42SmrgFcConfigGetRescanInverval (FcConfig *config) 6062c393a42Smrg{ 6072c393a42Smrg return FcConfigGetRescanInterval (config); 6082c393a42Smrg} 6092c393a42Smrg 6102c393a42SmrgFcBool 6112c393a42SmrgFcConfigSetRescanInverval (FcConfig *config, int rescanInterval) 6122c393a42Smrg{ 6132c393a42Smrg return FcConfigSetRescanInterval (config, rescanInterval); 6142c393a42Smrg} 6152c393a42Smrg 616ca08ab68Smrg 6172c393a42SmrgFcBool 6182c393a42SmrgFcConfigAddEdit (FcConfig *config, 6192c393a42Smrg FcTest *test, 6202c393a42Smrg FcEdit *edit, 6212c393a42Smrg FcMatchKind kind) 6222c393a42Smrg{ 6232c393a42Smrg FcSubst *subst, **prev; 6242c393a42Smrg FcTest *t; 6252c393a42Smrg int num; 6262c393a42Smrg 6272c393a42Smrg switch (kind) { 6282c393a42Smrg case FcMatchPattern: 6292c393a42Smrg prev = &config->substPattern; 6302c393a42Smrg break; 6312c393a42Smrg case FcMatchFont: 6322c393a42Smrg prev = &config->substFont; 6332c393a42Smrg break; 6342c393a42Smrg case FcMatchScan: 6352c393a42Smrg prev = &config->substScan; 6362c393a42Smrg break; 6372c393a42Smrg default: 6382c393a42Smrg return FcFalse; 6392c393a42Smrg } 6402c393a42Smrg subst = (FcSubst *) malloc (sizeof (FcSubst)); 6412c393a42Smrg if (!subst) 6422c393a42Smrg return FcFalse; 6432c393a42Smrg FcMemAlloc (FC_MEM_SUBST, sizeof (FcSubst)); 6442c393a42Smrg for (; *prev; prev = &(*prev)->next); 6452c393a42Smrg *prev = subst; 6462c393a42Smrg subst->next = 0; 6472c393a42Smrg subst->test = test; 6482c393a42Smrg subst->edit = edit; 6492c393a42Smrg num = 0; 6502c393a42Smrg for (t = test; t; t = t->next) 6512c393a42Smrg { 6522c393a42Smrg if (t->kind == FcMatchDefault) 6532c393a42Smrg t->kind = kind; 6542c393a42Smrg num++; 6552c393a42Smrg } 6562c393a42Smrg if (config->maxObjects < num) 6572c393a42Smrg config->maxObjects = num; 6582c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 6592c393a42Smrg { 6602c393a42Smrg printf ("Add Subst "); 6612c393a42Smrg FcSubstPrint (subst); 6622c393a42Smrg } 6632c393a42Smrg return FcTrue; 6642c393a42Smrg} 6652c393a42Smrg 6662c393a42Smrgtypedef struct _FcSubState { 6672c393a42Smrg FcPatternElt *elt; 6682c393a42Smrg FcValueList *value; 6692c393a42Smrg} FcSubState; 6702c393a42Smrg 6712c393a42Smrgstatic FcValue 6722c393a42SmrgFcConfigPromote (FcValue v, FcValue u) 6732c393a42Smrg{ 6742c393a42Smrg if (v.type == FcTypeInteger) 6752c393a42Smrg { 6762c393a42Smrg v.type = FcTypeDouble; 6772c393a42Smrg v.u.d = (double) v.u.i; 6782c393a42Smrg } 6792c393a42Smrg else if (v.type == FcTypeVoid && u.type == FcTypeMatrix) 6802c393a42Smrg { 6812c393a42Smrg v.u.m = &FcIdentityMatrix; 6822c393a42Smrg v.type = FcTypeMatrix; 6832c393a42Smrg } 6842c393a42Smrg else if (v.type == FcTypeString && u.type == FcTypeLangSet) 6852c393a42Smrg { 6862c393a42Smrg v.u.l = FcLangSetPromote (v.u.s); 6872c393a42Smrg v.type = FcTypeLangSet; 6882c393a42Smrg } 6892c393a42Smrg return v; 6902c393a42Smrg} 6912c393a42Smrg 6922c393a42SmrgFcBool 6932c393a42SmrgFcConfigCompareValue (const FcValue *left_o, 694ca08ab68Smrg FcOp op_, 6952c393a42Smrg const FcValue *right_o) 6962c393a42Smrg{ 6972c393a42Smrg FcValue left = FcValueCanonicalize(left_o); 6982c393a42Smrg FcValue right = FcValueCanonicalize(right_o); 6992c393a42Smrg FcBool ret = FcFalse; 700ca08ab68Smrg FcOp op = FC_OP_GET_OP (op_); 701ca08ab68Smrg int flags = FC_OP_GET_FLAGS (op_); 702ca08ab68Smrg 7032c393a42Smrg left = FcConfigPromote (left, right); 7042c393a42Smrg right = FcConfigPromote (right, left); 705ca08ab68Smrg if (left.type == right.type) 7062c393a42Smrg { 7072c393a42Smrg switch (left.type) { 7082c393a42Smrg case FcTypeInteger: 7092c393a42Smrg break; /* FcConfigPromote prevents this from happening */ 7102c393a42Smrg case FcTypeDouble: 7112c393a42Smrg switch (op) { 7122c393a42Smrg case FcOpEqual: 7132c393a42Smrg case FcOpContains: 7142c393a42Smrg case FcOpListing: 7152c393a42Smrg ret = left.u.d == right.u.d; 7162c393a42Smrg break; 7172c393a42Smrg case FcOpNotEqual: 7182c393a42Smrg case FcOpNotContains: 7192c393a42Smrg ret = left.u.d != right.u.d; 7202c393a42Smrg break; 721ca08ab68Smrg case FcOpLess: 7222c393a42Smrg ret = left.u.d < right.u.d; 7232c393a42Smrg break; 724ca08ab68Smrg case FcOpLessEqual: 7252c393a42Smrg ret = left.u.d <= right.u.d; 7262c393a42Smrg break; 727ca08ab68Smrg case FcOpMore: 7282c393a42Smrg ret = left.u.d > right.u.d; 7292c393a42Smrg break; 730ca08ab68Smrg case FcOpMoreEqual: 7312c393a42Smrg ret = left.u.d >= right.u.d; 7322c393a42Smrg break; 7332c393a42Smrg default: 7342c393a42Smrg break; 7352c393a42Smrg } 7362c393a42Smrg break; 7372c393a42Smrg case FcTypeBool: 7382c393a42Smrg switch (op) { 739ca08ab68Smrg case FcOpEqual: 7402c393a42Smrg case FcOpContains: 7412c393a42Smrg case FcOpListing: 7422c393a42Smrg ret = left.u.b == right.u.b; 7432c393a42Smrg break; 7442c393a42Smrg case FcOpNotEqual: 7452c393a42Smrg case FcOpNotContains: 7462c393a42Smrg ret = left.u.b != right.u.b; 7472c393a42Smrg break; 7482c393a42Smrg default: 7492c393a42Smrg break; 7502c393a42Smrg } 7512c393a42Smrg break; 7522c393a42Smrg case FcTypeString: 7532c393a42Smrg switch (op) { 754ca08ab68Smrg case FcOpEqual: 7552c393a42Smrg case FcOpListing: 756ca08ab68Smrg if (flags & FcOpFlagIgnoreBlanks) 757ca08ab68Smrg ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) == 0; 758ca08ab68Smrg else 759ca08ab68Smrg ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0; 7602c393a42Smrg break; 7612c393a42Smrg case FcOpContains: 7622c393a42Smrg ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0; 7632c393a42Smrg break; 7642c393a42Smrg case FcOpNotEqual: 765ca08ab68Smrg if (flags & FcOpFlagIgnoreBlanks) 766ca08ab68Smrg ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) != 0; 767ca08ab68Smrg else 768ca08ab68Smrg ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0; 7692c393a42Smrg break; 7702c393a42Smrg case FcOpNotContains: 7712c393a42Smrg ret = FcStrStrIgnoreCase (left.u.s, right.u.s) == 0; 7722c393a42Smrg break; 7732c393a42Smrg default: 7742c393a42Smrg break; 7752c393a42Smrg } 7762c393a42Smrg break; 7772c393a42Smrg case FcTypeMatrix: 7782c393a42Smrg switch (op) { 7792c393a42Smrg case FcOpEqual: 7802c393a42Smrg case FcOpContains: 7812c393a42Smrg case FcOpListing: 7822c393a42Smrg ret = FcMatrixEqual (left.u.m, right.u.m); 7832c393a42Smrg break; 7842c393a42Smrg case FcOpNotEqual: 7852c393a42Smrg case FcOpNotContains: 7862c393a42Smrg ret = !FcMatrixEqual (left.u.m, right.u.m); 7872c393a42Smrg break; 7882c393a42Smrg default: 7892c393a42Smrg break; 7902c393a42Smrg } 7912c393a42Smrg break; 7922c393a42Smrg case FcTypeCharSet: 7932c393a42Smrg switch (op) { 7942c393a42Smrg case FcOpContains: 7952c393a42Smrg case FcOpListing: 7962c393a42Smrg /* left contains right if right is a subset of left */ 7972c393a42Smrg ret = FcCharSetIsSubset (right.u.c, left.u.c); 7982c393a42Smrg break; 7992c393a42Smrg case FcOpNotContains: 8002c393a42Smrg /* left contains right if right is a subset of left */ 8012c393a42Smrg ret = !FcCharSetIsSubset (right.u.c, left.u.c); 8022c393a42Smrg break; 8032c393a42Smrg case FcOpEqual: 8042c393a42Smrg ret = FcCharSetEqual (left.u.c, right.u.c); 8052c393a42Smrg break; 8062c393a42Smrg case FcOpNotEqual: 8072c393a42Smrg ret = !FcCharSetEqual (left.u.c, right.u.c); 8082c393a42Smrg break; 8092c393a42Smrg default: 8102c393a42Smrg break; 8112c393a42Smrg } 8122c393a42Smrg break; 8132c393a42Smrg case FcTypeLangSet: 8142c393a42Smrg switch (op) { 8152c393a42Smrg case FcOpContains: 8162c393a42Smrg case FcOpListing: 8172c393a42Smrg ret = FcLangSetContains (left.u.l, right.u.l); 8182c393a42Smrg break; 8192c393a42Smrg case FcOpNotContains: 8202c393a42Smrg ret = !FcLangSetContains (left.u.l, right.u.l); 8212c393a42Smrg break; 8222c393a42Smrg case FcOpEqual: 8232c393a42Smrg ret = FcLangSetEqual (left.u.l, right.u.l); 8242c393a42Smrg break; 8252c393a42Smrg case FcOpNotEqual: 8262c393a42Smrg ret = !FcLangSetEqual (left.u.l, right.u.l); 8272c393a42Smrg break; 8282c393a42Smrg default: 8292c393a42Smrg break; 8302c393a42Smrg } 8312c393a42Smrg break; 8322c393a42Smrg case FcTypeVoid: 8332c393a42Smrg switch (op) { 8342c393a42Smrg case FcOpEqual: 8352c393a42Smrg case FcOpContains: 8362c393a42Smrg case FcOpListing: 8372c393a42Smrg ret = FcTrue; 8382c393a42Smrg break; 8392c393a42Smrg default: 8402c393a42Smrg break; 8412c393a42Smrg } 8422c393a42Smrg break; 8432c393a42Smrg case FcTypeFTFace: 8442c393a42Smrg switch (op) { 8452c393a42Smrg case FcOpEqual: 8462c393a42Smrg case FcOpContains: 8472c393a42Smrg case FcOpListing: 8482c393a42Smrg ret = left.u.f == right.u.f; 8492c393a42Smrg break; 8502c393a42Smrg case FcOpNotEqual: 8512c393a42Smrg case FcOpNotContains: 8522c393a42Smrg ret = left.u.f != right.u.f; 8532c393a42Smrg break; 8542c393a42Smrg default: 8552c393a42Smrg break; 8562c393a42Smrg } 8572c393a42Smrg break; 8582c393a42Smrg } 8592c393a42Smrg } 8602c393a42Smrg else 8612c393a42Smrg { 8622c393a42Smrg if (op == FcOpNotEqual || op == FcOpNotContains) 8632c393a42Smrg ret = FcTrue; 8642c393a42Smrg } 8652c393a42Smrg return ret; 8662c393a42Smrg} 8672c393a42Smrg 8682c393a42Smrg 8692c393a42Smrg#define _FcDoubleFloor(d) ((int) (d)) 8702c393a42Smrg#define _FcDoubleCeil(d) ((double) (int) (d) == (d) ? (int) (d) : (int) ((d) + 1)) 8712c393a42Smrg#define FcDoubleFloor(d) ((d) >= 0 ? _FcDoubleFloor(d) : -_FcDoubleCeil(-(d))) 8722c393a42Smrg#define FcDoubleCeil(d) ((d) >= 0 ? _FcDoubleCeil(d) : -_FcDoubleFloor(-(d))) 8732c393a42Smrg#define FcDoubleRound(d) FcDoubleFloor ((d) + 0.5) 8742c393a42Smrg#define FcDoubleTrunc(d) ((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d))) 8752c393a42Smrg 8762c393a42Smrgstatic FcValue 8772c393a42SmrgFcConfigEvaluate (FcPattern *p, FcExpr *e) 8782c393a42Smrg{ 8792c393a42Smrg FcValue v, vl, vr; 8802c393a42Smrg FcResult r; 8812c393a42Smrg FcMatrix *m; 8822c393a42Smrg FcChar8 *str; 883ca08ab68Smrg FcOp op = FC_OP_GET_OP (e->op); 884ca08ab68Smrg 885ca08ab68Smrg switch (op) { 8862c393a42Smrg case FcOpInteger: 8872c393a42Smrg v.type = FcTypeInteger; 8882c393a42Smrg v.u.i = e->u.ival; 8892c393a42Smrg break; 8902c393a42Smrg case FcOpDouble: 8912c393a42Smrg v.type = FcTypeDouble; 8922c393a42Smrg v.u.d = e->u.dval; 8932c393a42Smrg break; 8942c393a42Smrg case FcOpString: 8952c393a42Smrg v.type = FcTypeString; 896a6844aabSmrg v.u.s = e->u.sval; 897a6844aabSmrg v = FcValueSave (v); 8982c393a42Smrg break; 8992c393a42Smrg case FcOpMatrix: 9002c393a42Smrg v.type = FcTypeMatrix; 9012c393a42Smrg v.u.m = e->u.mval; 9022c393a42Smrg v = FcValueSave (v); 9032c393a42Smrg break; 9042c393a42Smrg case FcOpCharSet: 9052c393a42Smrg v.type = FcTypeCharSet; 9062c393a42Smrg v.u.c = e->u.cval; 9072c393a42Smrg v = FcValueSave (v); 9082c393a42Smrg break; 909ca08ab68Smrg case FcOpLangSet: 910ca08ab68Smrg v.type = FcTypeLangSet; 911ca08ab68Smrg v.u.l = e->u.lval; 912ca08ab68Smrg v = FcValueSave (v); 913ca08ab68Smrg break; 9142c393a42Smrg case FcOpBool: 9152c393a42Smrg v.type = FcTypeBool; 9162c393a42Smrg v.u.b = e->u.bval; 9172c393a42Smrg break; 9182c393a42Smrg case FcOpField: 9192c393a42Smrg r = FcPatternObjectGet (p, e->u.object, 0, &v); 9202c393a42Smrg if (r != FcResultMatch) 9212c393a42Smrg v.type = FcTypeVoid; 9222c393a42Smrg v = FcValueSave (v); 9232c393a42Smrg break; 9242c393a42Smrg case FcOpConst: 9252c393a42Smrg if (FcNameConstant (e->u.constant, &v.u.i)) 9262c393a42Smrg v.type = FcTypeInteger; 9272c393a42Smrg else 9282c393a42Smrg v.type = FcTypeVoid; 9292c393a42Smrg break; 9302c393a42Smrg case FcOpQuest: 9312c393a42Smrg vl = FcConfigEvaluate (p, e->u.tree.left); 9322c393a42Smrg if (vl.type == FcTypeBool) 9332c393a42Smrg { 9342c393a42Smrg if (vl.u.b) 9352c393a42Smrg v = FcConfigEvaluate (p, e->u.tree.right->u.tree.left); 9362c393a42Smrg else 9372c393a42Smrg v = FcConfigEvaluate (p, e->u.tree.right->u.tree.right); 9382c393a42Smrg } 9392c393a42Smrg else 9402c393a42Smrg v.type = FcTypeVoid; 9412c393a42Smrg FcValueDestroy (vl); 9422c393a42Smrg break; 9432c393a42Smrg case FcOpEqual: 9442c393a42Smrg case FcOpNotEqual: 9452c393a42Smrg case FcOpLess: 9462c393a42Smrg case FcOpLessEqual: 9472c393a42Smrg case FcOpMore: 9482c393a42Smrg case FcOpMoreEqual: 9492c393a42Smrg case FcOpContains: 9502c393a42Smrg case FcOpNotContains: 9512c393a42Smrg case FcOpListing: 9522c393a42Smrg vl = FcConfigEvaluate (p, e->u.tree.left); 9532c393a42Smrg vr = FcConfigEvaluate (p, e->u.tree.right); 9542c393a42Smrg v.type = FcTypeBool; 9552c393a42Smrg v.u.b = FcConfigCompareValue (&vl, e->op, &vr); 9562c393a42Smrg FcValueDestroy (vl); 9572c393a42Smrg FcValueDestroy (vr); 9582c393a42Smrg break; 9592c393a42Smrg case FcOpOr: 9602c393a42Smrg case FcOpAnd: 9612c393a42Smrg case FcOpPlus: 9622c393a42Smrg case FcOpMinus: 9632c393a42Smrg case FcOpTimes: 9642c393a42Smrg case FcOpDivide: 9652c393a42Smrg vl = FcConfigEvaluate (p, e->u.tree.left); 9662c393a42Smrg vr = FcConfigEvaluate (p, e->u.tree.right); 9672c393a42Smrg vl = FcConfigPromote (vl, vr); 9682c393a42Smrg vr = FcConfigPromote (vr, vl); 9692c393a42Smrg if (vl.type == vr.type) 9702c393a42Smrg { 9712c393a42Smrg switch (vl.type) { 9722c393a42Smrg case FcTypeDouble: 973ca08ab68Smrg switch (op) { 974ca08ab68Smrg case FcOpPlus: 9752c393a42Smrg v.type = FcTypeDouble; 976ca08ab68Smrg v.u.d = vl.u.d + vr.u.d; 9772c393a42Smrg break; 9782c393a42Smrg case FcOpMinus: 9792c393a42Smrg v.type = FcTypeDouble; 980ca08ab68Smrg v.u.d = vl.u.d - vr.u.d; 9812c393a42Smrg break; 9822c393a42Smrg case FcOpTimes: 9832c393a42Smrg v.type = FcTypeDouble; 984ca08ab68Smrg v.u.d = vl.u.d * vr.u.d; 9852c393a42Smrg break; 9862c393a42Smrg case FcOpDivide: 9872c393a42Smrg v.type = FcTypeDouble; 988ca08ab68Smrg v.u.d = vl.u.d / vr.u.d; 9892c393a42Smrg break; 9902c393a42Smrg default: 991ca08ab68Smrg v.type = FcTypeVoid; 9922c393a42Smrg break; 9932c393a42Smrg } 9942c393a42Smrg if (v.type == FcTypeDouble && 9952c393a42Smrg v.u.d == (double) (int) v.u.d) 9962c393a42Smrg { 9972c393a42Smrg v.type = FcTypeInteger; 9982c393a42Smrg v.u.i = (int) v.u.d; 9992c393a42Smrg } 10002c393a42Smrg break; 10012c393a42Smrg case FcTypeBool: 1002ca08ab68Smrg switch (op) { 10032c393a42Smrg case FcOpOr: 10042c393a42Smrg v.type = FcTypeBool; 10052c393a42Smrg v.u.b = vl.u.b || vr.u.b; 10062c393a42Smrg break; 10072c393a42Smrg case FcOpAnd: 10082c393a42Smrg v.type = FcTypeBool; 10092c393a42Smrg v.u.b = vl.u.b && vr.u.b; 10102c393a42Smrg break; 10112c393a42Smrg default: 1012ca08ab68Smrg v.type = FcTypeVoid; 10132c393a42Smrg break; 10142c393a42Smrg } 10152c393a42Smrg break; 10162c393a42Smrg case FcTypeString: 1017ca08ab68Smrg switch (op) { 10182c393a42Smrg case FcOpPlus: 10192c393a42Smrg v.type = FcTypeString; 10202c393a42Smrg str = FcStrPlus (vl.u.s, vr.u.s); 1021ca08ab68Smrg v.u.s = FcSharedStr (str); 10222c393a42Smrg FcStrFree (str); 1023ca08ab68Smrg 10242c393a42Smrg if (!v.u.s) 10252c393a42Smrg v.type = FcTypeVoid; 10262c393a42Smrg break; 10272c393a42Smrg default: 10282c393a42Smrg v.type = FcTypeVoid; 10292c393a42Smrg break; 10302c393a42Smrg } 10312c393a42Smrg break; 10322c393a42Smrg case FcTypeMatrix: 1033ca08ab68Smrg switch (op) { 10342c393a42Smrg case FcOpTimes: 10352c393a42Smrg v.type = FcTypeMatrix; 10362c393a42Smrg m = malloc (sizeof (FcMatrix)); 10372c393a42Smrg if (m) 10382c393a42Smrg { 10392c393a42Smrg FcMemAlloc (FC_MEM_MATRIX, sizeof (FcMatrix)); 10402c393a42Smrg FcMatrixMultiply (m, vl.u.m, vr.u.m); 10412c393a42Smrg v.u.m = m; 10422c393a42Smrg } 10432c393a42Smrg else 10442c393a42Smrg { 10452c393a42Smrg v.type = FcTypeVoid; 10462c393a42Smrg } 10472c393a42Smrg break; 10482c393a42Smrg default: 10492c393a42Smrg v.type = FcTypeVoid; 10502c393a42Smrg break; 10512c393a42Smrg } 10522c393a42Smrg break; 1053ca08ab68Smrg case FcTypeCharSet: 1054ca08ab68Smrg switch (op) { 1055ca08ab68Smrg case FcOpPlus: 1056ca08ab68Smrg v.type = FcTypeCharSet; 1057ca08ab68Smrg v.u.c = FcCharSetUnion (vl.u.c, vr.u.c); 1058ca08ab68Smrg if (!v.u.c) 1059ca08ab68Smrg v.type = FcTypeVoid; 1060ca08ab68Smrg break; 1061ca08ab68Smrg case FcOpMinus: 1062ca08ab68Smrg v.type = FcTypeCharSet; 1063ca08ab68Smrg v.u.c = FcCharSetSubtract (vl.u.c, vr.u.c); 1064ca08ab68Smrg if (!v.u.c) 1065ca08ab68Smrg v.type = FcTypeVoid; 1066ca08ab68Smrg break; 1067ca08ab68Smrg default: 1068ca08ab68Smrg v.type = FcTypeVoid; 1069ca08ab68Smrg break; 1070ca08ab68Smrg } 1071ca08ab68Smrg break; 1072ca08ab68Smrg case FcTypeLangSet: 1073ca08ab68Smrg switch (op) { 1074ca08ab68Smrg case FcOpPlus: 1075ca08ab68Smrg v.type = FcTypeLangSet; 1076ca08ab68Smrg v.u.l = FcLangSetUnion (vl.u.l, vr.u.l); 1077ca08ab68Smrg if (!v.u.l) 1078ca08ab68Smrg v.type = FcTypeVoid; 1079ca08ab68Smrg break; 1080ca08ab68Smrg case FcOpMinus: 1081ca08ab68Smrg v.type = FcTypeLangSet; 1082ca08ab68Smrg v.u.l = FcLangSetSubtract (vl.u.l, vr.u.l); 1083ca08ab68Smrg if (!v.u.l) 1084ca08ab68Smrg v.type = FcTypeVoid; 1085ca08ab68Smrg break; 1086ca08ab68Smrg default: 1087ca08ab68Smrg v.type = FcTypeVoid; 1088ca08ab68Smrg break; 1089ca08ab68Smrg } 1090ca08ab68Smrg break; 10912c393a42Smrg default: 10922c393a42Smrg v.type = FcTypeVoid; 10932c393a42Smrg break; 10942c393a42Smrg } 10952c393a42Smrg } 10962c393a42Smrg else 10972c393a42Smrg v.type = FcTypeVoid; 10982c393a42Smrg FcValueDestroy (vl); 10992c393a42Smrg FcValueDestroy (vr); 11002c393a42Smrg break; 11012c393a42Smrg case FcOpNot: 11022c393a42Smrg vl = FcConfigEvaluate (p, e->u.tree.left); 11032c393a42Smrg switch (vl.type) { 11042c393a42Smrg case FcTypeBool: 11052c393a42Smrg v.type = FcTypeBool; 11062c393a42Smrg v.u.b = !vl.u.b; 11072c393a42Smrg break; 11082c393a42Smrg default: 11092c393a42Smrg v.type = FcTypeVoid; 11102c393a42Smrg break; 11112c393a42Smrg } 11122c393a42Smrg FcValueDestroy (vl); 11132c393a42Smrg break; 11142c393a42Smrg case FcOpFloor: 11152c393a42Smrg vl = FcConfigEvaluate (p, e->u.tree.left); 11162c393a42Smrg switch (vl.type) { 11172c393a42Smrg case FcTypeInteger: 11182c393a42Smrg v = vl; 11192c393a42Smrg break; 11202c393a42Smrg case FcTypeDouble: 11212c393a42Smrg v.type = FcTypeInteger; 11222c393a42Smrg v.u.i = FcDoubleFloor (vl.u.d); 11232c393a42Smrg break; 11242c393a42Smrg default: 11252c393a42Smrg v.type = FcTypeVoid; 11262c393a42Smrg break; 11272c393a42Smrg } 11282c393a42Smrg FcValueDestroy (vl); 11292c393a42Smrg break; 11302c393a42Smrg case FcOpCeil: 11312c393a42Smrg vl = FcConfigEvaluate (p, e->u.tree.left); 11322c393a42Smrg switch (vl.type) { 11332c393a42Smrg case FcTypeInteger: 11342c393a42Smrg v = vl; 11352c393a42Smrg break; 11362c393a42Smrg case FcTypeDouble: 11372c393a42Smrg v.type = FcTypeInteger; 11382c393a42Smrg v.u.i = FcDoubleCeil (vl.u.d); 11392c393a42Smrg break; 11402c393a42Smrg default: 11412c393a42Smrg v.type = FcTypeVoid; 11422c393a42Smrg break; 11432c393a42Smrg } 11442c393a42Smrg FcValueDestroy (vl); 11452c393a42Smrg break; 11462c393a42Smrg case FcOpRound: 11472c393a42Smrg vl = FcConfigEvaluate (p, e->u.tree.left); 11482c393a42Smrg switch (vl.type) { 11492c393a42Smrg case FcTypeInteger: 11502c393a42Smrg v = vl; 11512c393a42Smrg break; 11522c393a42Smrg case FcTypeDouble: 11532c393a42Smrg v.type = FcTypeInteger; 11542c393a42Smrg v.u.i = FcDoubleRound (vl.u.d); 11552c393a42Smrg break; 11562c393a42Smrg default: 11572c393a42Smrg v.type = FcTypeVoid; 11582c393a42Smrg break; 11592c393a42Smrg } 11602c393a42Smrg FcValueDestroy (vl); 11612c393a42Smrg break; 11622c393a42Smrg case FcOpTrunc: 11632c393a42Smrg vl = FcConfigEvaluate (p, e->u.tree.left); 11642c393a42Smrg switch (vl.type) { 11652c393a42Smrg case FcTypeInteger: 11662c393a42Smrg v = vl; 11672c393a42Smrg break; 11682c393a42Smrg case FcTypeDouble: 11692c393a42Smrg v.type = FcTypeInteger; 11702c393a42Smrg v.u.i = FcDoubleTrunc (vl.u.d); 11712c393a42Smrg break; 11722c393a42Smrg default: 11732c393a42Smrg v.type = FcTypeVoid; 11742c393a42Smrg break; 11752c393a42Smrg } 11762c393a42Smrg FcValueDestroy (vl); 11772c393a42Smrg break; 11782c393a42Smrg default: 11792c393a42Smrg v.type = FcTypeVoid; 11802c393a42Smrg break; 11812c393a42Smrg } 11822c393a42Smrg return v; 11832c393a42Smrg} 11842c393a42Smrg 11852c393a42Smrgstatic FcValueList * 11862c393a42SmrgFcConfigMatchValueList (FcPattern *p, 11872c393a42Smrg FcTest *t, 11882c393a42Smrg FcValueList *values) 11892c393a42Smrg{ 11902c393a42Smrg FcValueList *ret = 0; 11912c393a42Smrg FcExpr *e = t->expr; 11922c393a42Smrg FcValue value; 11932c393a42Smrg FcValueList *v; 1194ca08ab68Smrg 11952c393a42Smrg while (e) 11962c393a42Smrg { 11972c393a42Smrg /* Compute the value of the match expression */ 1198ca08ab68Smrg if (FC_OP_GET_OP (e->op) == FcOpComma) 11992c393a42Smrg { 12002c393a42Smrg value = FcConfigEvaluate (p, e->u.tree.left); 12012c393a42Smrg e = e->u.tree.right; 12022c393a42Smrg } 12032c393a42Smrg else 12042c393a42Smrg { 12052c393a42Smrg value = FcConfigEvaluate (p, e); 12062c393a42Smrg e = 0; 12072c393a42Smrg } 12082c393a42Smrg 12092c393a42Smrg for (v = values; v; v = FcValueListNext(v)) 12102c393a42Smrg { 12112c393a42Smrg /* Compare the pattern value to the match expression value */ 12122c393a42Smrg if (FcConfigCompareValue (&v->value, t->op, &value)) 12132c393a42Smrg { 12142c393a42Smrg if (!ret) 12152c393a42Smrg ret = v; 12162c393a42Smrg } 12172c393a42Smrg else 12182c393a42Smrg { 12192c393a42Smrg if (t->qual == FcQualAll) 12202c393a42Smrg { 12212c393a42Smrg ret = 0; 12222c393a42Smrg break; 12232c393a42Smrg } 12242c393a42Smrg } 12252c393a42Smrg } 12262c393a42Smrg FcValueDestroy (value); 12272c393a42Smrg } 12282c393a42Smrg return ret; 12292c393a42Smrg} 12302c393a42Smrg 12312c393a42Smrgstatic FcValueList * 12322c393a42SmrgFcConfigValues (FcPattern *p, FcExpr *e, FcValueBinding binding) 12332c393a42Smrg{ 12342c393a42Smrg FcValueList *l; 1235ca08ab68Smrg 12362c393a42Smrg if (!e) 12372c393a42Smrg return 0; 12382c393a42Smrg l = (FcValueList *) malloc (sizeof (FcValueList)); 12392c393a42Smrg if (!l) 12402c393a42Smrg return 0; 12412c393a42Smrg FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList)); 1242ca08ab68Smrg if (FC_OP_GET_OP (e->op) == FcOpComma) 12432c393a42Smrg { 12442c393a42Smrg l->value = FcConfigEvaluate (p, e->u.tree.left); 12452c393a42Smrg l->next = FcConfigValues (p, e->u.tree.right, binding); 12462c393a42Smrg } 12472c393a42Smrg else 12482c393a42Smrg { 12492c393a42Smrg l->value = FcConfigEvaluate (p, e); 12502c393a42Smrg l->next = NULL; 12512c393a42Smrg } 12522c393a42Smrg l->binding = binding; 12532c393a42Smrg if (l->value.type == FcTypeVoid) 12542c393a42Smrg { 12552c393a42Smrg FcValueList *next = FcValueListNext(l); 12562c393a42Smrg 12572c393a42Smrg FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList)); 12582c393a42Smrg free (l); 12592c393a42Smrg l = next; 12602c393a42Smrg } 12612c393a42Smrg 12622c393a42Smrg return l; 12632c393a42Smrg} 12642c393a42Smrg 12652c393a42Smrgstatic FcBool 12662c393a42SmrgFcConfigAdd (FcValueListPtr *head, 12672c393a42Smrg FcValueList *position, 12682c393a42Smrg FcBool append, 12692c393a42Smrg FcValueList *new) 12702c393a42Smrg{ 12712c393a42Smrg FcValueListPtr *prev, last, v; 12722c393a42Smrg FcValueBinding sameBinding; 1273ca08ab68Smrg 12742c393a42Smrg if (position) 12752c393a42Smrg sameBinding = position->binding; 12762c393a42Smrg else 12772c393a42Smrg sameBinding = FcValueBindingWeak; 12782c393a42Smrg for (v = new; v != NULL; v = FcValueListNext(v)) 12792c393a42Smrg if (v->binding == FcValueBindingSame) 12802c393a42Smrg v->binding = sameBinding; 12812c393a42Smrg if (append) 12822c393a42Smrg { 12832c393a42Smrg if (position) 12842c393a42Smrg prev = &position->next; 12852c393a42Smrg else 1286ca08ab68Smrg for (prev = head; *prev != NULL; 12872c393a42Smrg prev = &(*prev)->next) 12882c393a42Smrg ; 12892c393a42Smrg } 12902c393a42Smrg else 12912c393a42Smrg { 12922c393a42Smrg if (position) 12932c393a42Smrg { 1294ca08ab68Smrg for (prev = head; *prev != NULL; 12952c393a42Smrg prev = &(*prev)->next) 12962c393a42Smrg { 12972c393a42Smrg if (*prev == position) 12982c393a42Smrg break; 12992c393a42Smrg } 13002c393a42Smrg } 13012c393a42Smrg else 13022c393a42Smrg prev = head; 13032c393a42Smrg 13042c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 13052c393a42Smrg { 13062c393a42Smrg if (*prev == NULL) 13072c393a42Smrg printf ("position not on list\n"); 13082c393a42Smrg } 13092c393a42Smrg } 13102c393a42Smrg 13112c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 13122c393a42Smrg { 13132c393a42Smrg printf ("%s list before ", append ? "Append" : "Prepend"); 1314ca08ab68Smrg FcValueListPrintWithPosition (*head, *prev); 13152c393a42Smrg printf ("\n"); 13162c393a42Smrg } 1317ca08ab68Smrg 13182c393a42Smrg if (new) 13192c393a42Smrg { 13202c393a42Smrg last = new; 13212c393a42Smrg while (last->next != NULL) 13222c393a42Smrg last = last->next; 1323ca08ab68Smrg 13242c393a42Smrg last->next = *prev; 13252c393a42Smrg *prev = new; 13262c393a42Smrg } 1327ca08ab68Smrg 13282c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 13292c393a42Smrg { 13302c393a42Smrg printf ("%s list after ", append ? "Append" : "Prepend"); 13312c393a42Smrg FcValueListPrint (*head); 13322c393a42Smrg printf ("\n"); 13332c393a42Smrg } 1334ca08ab68Smrg 13352c393a42Smrg return FcTrue; 13362c393a42Smrg} 13372c393a42Smrg 13382c393a42Smrgstatic void 13392c393a42SmrgFcConfigDel (FcValueListPtr *head, 13402c393a42Smrg FcValueList *position) 13412c393a42Smrg{ 13422c393a42Smrg FcValueListPtr *prev; 13432c393a42Smrg 13442c393a42Smrg for (prev = head; *prev != NULL; prev = &(*prev)->next) 13452c393a42Smrg { 13462c393a42Smrg if (*prev == position) 13472c393a42Smrg { 13482c393a42Smrg *prev = position->next; 13492c393a42Smrg position->next = NULL; 13502c393a42Smrg FcValueListDestroy (position); 13512c393a42Smrg break; 13522c393a42Smrg } 13532c393a42Smrg } 13542c393a42Smrg} 13552c393a42Smrg 13562c393a42Smrgstatic void 13572c393a42SmrgFcConfigPatternAdd (FcPattern *p, 13582c393a42Smrg FcObject object, 13592c393a42Smrg FcValueList *list, 13602c393a42Smrg FcBool append) 13612c393a42Smrg{ 13622c393a42Smrg if (list) 13632c393a42Smrg { 13642c393a42Smrg FcPatternElt *e = FcPatternObjectInsertElt (p, object); 1365ca08ab68Smrg 13662c393a42Smrg if (!e) 13672c393a42Smrg return; 13682c393a42Smrg FcConfigAdd (&e->values, 0, append, list); 13692c393a42Smrg } 13702c393a42Smrg} 13712c393a42Smrg 13722c393a42Smrg/* 13732c393a42Smrg * Delete all values associated with a field 13742c393a42Smrg */ 13752c393a42Smrgstatic void 13762c393a42SmrgFcConfigPatternDel (FcPattern *p, 13772c393a42Smrg FcObject object) 13782c393a42Smrg{ 13792c393a42Smrg FcPatternElt *e = FcPatternObjectFindElt (p, object); 13802c393a42Smrg if (!e) 13812c393a42Smrg return; 13822c393a42Smrg while (e->values != NULL) 13832c393a42Smrg FcConfigDel (&e->values, e->values); 13842c393a42Smrg} 13852c393a42Smrg 13862c393a42Smrgstatic void 13872c393a42SmrgFcConfigPatternCanon (FcPattern *p, 13882c393a42Smrg FcObject object) 13892c393a42Smrg{ 13902c393a42Smrg FcPatternElt *e = FcPatternObjectFindElt (p, object); 13912c393a42Smrg if (!e) 13922c393a42Smrg return; 13932c393a42Smrg if (e->values == NULL) 13942c393a42Smrg FcPatternObjectDel (p, object); 13952c393a42Smrg} 13962c393a42Smrg 13972c393a42SmrgFcBool 13982c393a42SmrgFcConfigSubstituteWithPat (FcConfig *config, 13992c393a42Smrg FcPattern *p, 14002c393a42Smrg FcPattern *p_pat, 14012c393a42Smrg FcMatchKind kind) 14022c393a42Smrg{ 14032c393a42Smrg FcSubst *s; 14042c393a42Smrg FcSubState *st; 14052c393a42Smrg int i; 14062c393a42Smrg FcTest *t; 14072c393a42Smrg FcEdit *e; 14082c393a42Smrg FcValueList *l; 14092c393a42Smrg FcPattern *m; 1410ca08ab68Smrg FcStrSet *strs; 14112c393a42Smrg 14122c393a42Smrg if (!config) 14132c393a42Smrg { 14142c393a42Smrg config = FcConfigGetCurrent (); 14152c393a42Smrg if (!config) 14162c393a42Smrg return FcFalse; 14172c393a42Smrg } 14182c393a42Smrg 14192c393a42Smrg switch (kind) { 14202c393a42Smrg case FcMatchPattern: 14212c393a42Smrg s = config->substPattern; 1422ca08ab68Smrg strs = FcGetDefaultLangs (); 1423ca08ab68Smrg if (strs) 1424ca08ab68Smrg { 1425ca08ab68Smrg FcStrList *l = FcStrListCreate (strs); 1426ca08ab68Smrg FcChar8 *lang; 1427ca08ab68Smrg FcValue v; 1428ca08ab68Smrg 1429ca08ab68Smrg FcStrSetDestroy (strs); 1430ca08ab68Smrg while (l && (lang = FcStrListNext (l))) 1431ca08ab68Smrg { 1432ca08ab68Smrg v.type = FcTypeString; 1433ca08ab68Smrg v.u.s = lang; 1434ca08ab68Smrg FcPatternObjectAddWithBinding (p, FC_LANG_OBJECT, v, FcValueBindingWeak, FcTrue); 1435ca08ab68Smrg } 1436ca08ab68Smrg FcStrListDone (l); 1437ca08ab68Smrg } 14382c393a42Smrg break; 14392c393a42Smrg case FcMatchFont: 14402c393a42Smrg s = config->substFont; 14412c393a42Smrg break; 14422c393a42Smrg case FcMatchScan: 14432c393a42Smrg s = config->substScan; 14442c393a42Smrg break; 14452c393a42Smrg default: 14462c393a42Smrg return FcFalse; 14472c393a42Smrg } 14482c393a42Smrg 14492c393a42Smrg st = (FcSubState *) malloc (config->maxObjects * sizeof (FcSubState)); 14502c393a42Smrg if (!st && config->maxObjects) 14512c393a42Smrg return FcFalse; 14522c393a42Smrg FcMemAlloc (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState)); 14532c393a42Smrg 14542c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 14552c393a42Smrg { 14562c393a42Smrg printf ("FcConfigSubstitute "); 14572c393a42Smrg FcPatternPrint (p); 14582c393a42Smrg } 14592c393a42Smrg for (; s; s = s->next) 14602c393a42Smrg { 14612c393a42Smrg /* 14622c393a42Smrg * Check the tests to see if 14632c393a42Smrg * they all match the pattern 14642c393a42Smrg */ 14652c393a42Smrg for (t = s->test, i = 0; t; t = t->next, i++) 14662c393a42Smrg { 14672c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 14682c393a42Smrg { 14692c393a42Smrg printf ("FcConfigSubstitute test "); 14702c393a42Smrg FcTestPrint (t); 14712c393a42Smrg } 14722c393a42Smrg st[i].elt = 0; 14732c393a42Smrg if (kind == FcMatchFont && t->kind == FcMatchPattern) 14742c393a42Smrg m = p_pat; 14752c393a42Smrg else 14762c393a42Smrg m = p; 14772c393a42Smrg if (m) 14782c393a42Smrg st[i].elt = FcPatternObjectFindElt (m, t->object); 14792c393a42Smrg else 14802c393a42Smrg st[i].elt = 0; 14812c393a42Smrg /* 14822c393a42Smrg * If there's no such field in the font, 14832c393a42Smrg * then FcQualAll matches while FcQualAny does not 14842c393a42Smrg */ 14852c393a42Smrg if (!st[i].elt) 14862c393a42Smrg { 14872c393a42Smrg if (t->qual == FcQualAll) 14882c393a42Smrg { 14892c393a42Smrg st[i].value = 0; 14902c393a42Smrg continue; 14912c393a42Smrg } 14922c393a42Smrg else 14932c393a42Smrg break; 14942c393a42Smrg } 14952c393a42Smrg /* 14962c393a42Smrg * Check to see if there is a match, mark the location 14972c393a42Smrg * to apply match-relative edits 14982c393a42Smrg */ 14992c393a42Smrg st[i].value = FcConfigMatchValueList (m, t, st[i].elt->values); 15002c393a42Smrg if (!st[i].value) 15012c393a42Smrg break; 15022c393a42Smrg if (t->qual == FcQualFirst && st[i].value != st[i].elt->values) 15032c393a42Smrg break; 15042c393a42Smrg if (t->qual == FcQualNotFirst && st[i].value == st[i].elt->values) 15052c393a42Smrg break; 15062c393a42Smrg } 15072c393a42Smrg if (t) 15082c393a42Smrg { 15092c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 15102c393a42Smrg printf ("No match\n"); 15112c393a42Smrg continue; 15122c393a42Smrg } 15132c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 15142c393a42Smrg { 15152c393a42Smrg printf ("Substitute "); 15162c393a42Smrg FcSubstPrint (s); 15172c393a42Smrg } 15182c393a42Smrg for (e = s->edit; e; e = e->next) 15192c393a42Smrg { 15202c393a42Smrg /* 15212c393a42Smrg * Evaluate the list of expressions 15222c393a42Smrg */ 15232c393a42Smrg l = FcConfigValues (p, e->expr, e->binding); 15242c393a42Smrg /* 15252c393a42Smrg * Locate any test associated with this field, skipping 15262c393a42Smrg * tests associated with the pattern when substituting in 15272c393a42Smrg * the font 15282c393a42Smrg */ 15292c393a42Smrg for (t = s->test, i = 0; t; t = t->next, i++) 15302c393a42Smrg { 15312c393a42Smrg if ((t->kind == FcMatchFont || kind == FcMatchPattern) && 15322c393a42Smrg t->object == e->object) 15332c393a42Smrg { 1534ca08ab68Smrg /* 15352c393a42Smrg * KLUDGE - the pattern may have been reallocated or 15362c393a42Smrg * things may have been inserted or deleted above 15372c393a42Smrg * this element by other edits. Go back and find 15382c393a42Smrg * the element again 15392c393a42Smrg */ 15402c393a42Smrg if (e != s->edit && st[i].elt) 15412c393a42Smrg st[i].elt = FcPatternObjectFindElt (p, t->object); 15422c393a42Smrg if (!st[i].elt) 15432c393a42Smrg t = 0; 15442c393a42Smrg break; 15452c393a42Smrg } 15462c393a42Smrg } 1547ca08ab68Smrg switch (FC_OP_GET_OP (e->op)) { 15482c393a42Smrg case FcOpAssign: 15492c393a42Smrg /* 15502c393a42Smrg * If there was a test, then replace the matched 15512c393a42Smrg * value with the new list of values 15522c393a42Smrg */ 15532c393a42Smrg if (t) 15542c393a42Smrg { 15552c393a42Smrg FcValueList *thisValue = st[i].value; 15562c393a42Smrg FcValueList *nextValue = thisValue; 1557ca08ab68Smrg 15582c393a42Smrg /* 15592c393a42Smrg * Append the new list of values after the current value 15602c393a42Smrg */ 15612c393a42Smrg FcConfigAdd (&st[i].elt->values, thisValue, FcTrue, l); 15622c393a42Smrg /* 15632c393a42Smrg * Delete the marked value 15642c393a42Smrg */ 15652c393a42Smrg if (thisValue) 15662c393a42Smrg FcConfigDel (&st[i].elt->values, thisValue); 15672c393a42Smrg /* 15682c393a42Smrg * Adjust any pointers into the value list to ensure 15692c393a42Smrg * future edits occur at the same place 15702c393a42Smrg */ 15712c393a42Smrg for (t = s->test, i = 0; t; t = t->next, i++) 15722c393a42Smrg { 15732c393a42Smrg if (st[i].value == thisValue) 15742c393a42Smrg st[i].value = nextValue; 15752c393a42Smrg } 15762c393a42Smrg break; 15772c393a42Smrg } 15782c393a42Smrg /* fall through ... */ 15792c393a42Smrg case FcOpAssignReplace: 15802c393a42Smrg /* 15812c393a42Smrg * Delete all of the values and insert 15822c393a42Smrg * the new set 15832c393a42Smrg */ 15842c393a42Smrg FcConfigPatternDel (p, e->object); 15852c393a42Smrg FcConfigPatternAdd (p, e->object, l, FcTrue); 15862c393a42Smrg /* 15872c393a42Smrg * Adjust any pointers into the value list as they no 15882c393a42Smrg * longer point to anything valid 15892c393a42Smrg */ 15902c393a42Smrg if (t) 15912c393a42Smrg { 15922c393a42Smrg FcPatternElt *thisElt = st[i].elt; 15932c393a42Smrg for (t = s->test, i = 0; t; t = t->next, i++) 15942c393a42Smrg { 15952c393a42Smrg if (st[i].elt == thisElt) 15962c393a42Smrg st[i].value = 0; 15972c393a42Smrg } 15982c393a42Smrg } 15992c393a42Smrg break; 16002c393a42Smrg case FcOpPrepend: 16012c393a42Smrg if (t) 16022c393a42Smrg { 16032c393a42Smrg FcConfigAdd (&st[i].elt->values, st[i].value, FcFalse, l); 16042c393a42Smrg break; 16052c393a42Smrg } 16062c393a42Smrg /* fall through ... */ 16072c393a42Smrg case FcOpPrependFirst: 16082c393a42Smrg FcConfigPatternAdd (p, e->object, l, FcFalse); 16092c393a42Smrg break; 16102c393a42Smrg case FcOpAppend: 16112c393a42Smrg if (t) 16122c393a42Smrg { 16132c393a42Smrg FcConfigAdd (&st[i].elt->values, st[i].value, FcTrue, l); 16142c393a42Smrg break; 16152c393a42Smrg } 16162c393a42Smrg /* fall through ... */ 16172c393a42Smrg case FcOpAppendLast: 16182c393a42Smrg FcConfigPatternAdd (p, e->object, l, FcTrue); 16192c393a42Smrg break; 16202c393a42Smrg default: 16212c393a42Smrg FcValueListDestroy (l); 16222c393a42Smrg break; 16232c393a42Smrg } 16242c393a42Smrg } 16252c393a42Smrg /* 16262c393a42Smrg * Now go through the pattern and eliminate 16272c393a42Smrg * any properties without data 16282c393a42Smrg */ 16292c393a42Smrg for (e = s->edit; e; e = e->next) 16302c393a42Smrg FcConfigPatternCanon (p, e->object); 16312c393a42Smrg 16322c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 16332c393a42Smrg { 16342c393a42Smrg printf ("FcConfigSubstitute edit"); 16352c393a42Smrg FcPatternPrint (p); 16362c393a42Smrg } 16372c393a42Smrg } 16382c393a42Smrg FcMemFree (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState)); 16392c393a42Smrg free (st); 16402c393a42Smrg if (FcDebug () & FC_DBG_EDIT) 16412c393a42Smrg { 16422c393a42Smrg printf ("FcConfigSubstitute done"); 16432c393a42Smrg FcPatternPrint (p); 16442c393a42Smrg } 16452c393a42Smrg return FcTrue; 16462c393a42Smrg} 16472c393a42Smrg 16482c393a42SmrgFcBool 16492c393a42SmrgFcConfigSubstitute (FcConfig *config, 16502c393a42Smrg FcPattern *p, 16512c393a42Smrg FcMatchKind kind) 16522c393a42Smrg{ 16532c393a42Smrg return FcConfigSubstituteWithPat (config, p, 0, kind); 16542c393a42Smrg} 16552c393a42Smrg 16562c393a42Smrg#if defined (_WIN32) 16572c393a42Smrg 16582c393a42Smrg# define WIN32_LEAN_AND_MEAN 16592c393a42Smrg# define WIN32_EXTRA_LEAN 16602c393a42Smrg# include <windows.h> 16612c393a42Smrg 16622c393a42Smrgstatic FcChar8 fontconfig_path[1000] = ""; 16632c393a42Smrg 16642c393a42Smrg# if (defined (PIC) || defined (DLL_EXPORT)) 16652c393a42Smrg 16662c393a42SmrgBOOL WINAPI 16672c393a42SmrgDllMain (HINSTANCE hinstDLL, 16682c393a42Smrg DWORD fdwReason, 16692c393a42Smrg LPVOID lpvReserved) 16702c393a42Smrg{ 16712c393a42Smrg FcChar8 *p; 16722c393a42Smrg 16732c393a42Smrg switch (fdwReason) { 16742c393a42Smrg case DLL_PROCESS_ATTACH: 1675ca08ab68Smrg if (!GetModuleFileName ((HMODULE) hinstDLL, (LPCH) fontconfig_path, 16762c393a42Smrg sizeof (fontconfig_path))) 16772c393a42Smrg break; 16782c393a42Smrg 16792c393a42Smrg /* If the fontconfig DLL is in a "bin" or "lib" subfolder, 16802c393a42Smrg * assume it's a Unix-style installation tree, and use 16812c393a42Smrg * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the 16822c393a42Smrg * folder where the DLL is as FONTCONFIG_PATH. 16832c393a42Smrg */ 1684ca08ab68Smrg p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\'); 16852c393a42Smrg if (p) 16862c393a42Smrg { 16872c393a42Smrg *p = '\0'; 1688ca08ab68Smrg p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\'); 1689ca08ab68Smrg if (p && (FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "bin") == 0 || 1690ca08ab68Smrg FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "lib") == 0)) 16912c393a42Smrg *p = '\0'; 1692ca08ab68Smrg strcat ((char *) fontconfig_path, "\\etc\\fonts"); 16932c393a42Smrg } 16942c393a42Smrg else 16952c393a42Smrg fontconfig_path[0] = '\0'; 1696ca08ab68Smrg 16972c393a42Smrg break; 16982c393a42Smrg } 16992c393a42Smrg 17002c393a42Smrg return TRUE; 17012c393a42Smrg} 17022c393a42Smrg 17032c393a42Smrg# endif /* !PIC */ 17042c393a42Smrg 17052c393a42Smrg#undef FONTCONFIG_PATH 17062c393a42Smrg#define FONTCONFIG_PATH fontconfig_path 17072c393a42Smrg 17082c393a42Smrg#endif /* !_WIN32 */ 17092c393a42Smrg 17102c393a42Smrg#ifndef FONTCONFIG_FILE 17112c393a42Smrg#define FONTCONFIG_FILE "fonts.conf" 17122c393a42Smrg#endif 17132c393a42Smrg 17142c393a42Smrgstatic FcChar8 * 17152c393a42SmrgFcConfigFileExists (const FcChar8 *dir, const FcChar8 *file) 17162c393a42Smrg{ 17172c393a42Smrg FcChar8 *path; 1718ca08ab68Smrg int size, osize; 17192c393a42Smrg 17202c393a42Smrg if (!dir) 17212c393a42Smrg dir = (FcChar8 *) ""; 1722ca08ab68Smrg 1723ca08ab68Smrg osize = strlen ((char *) dir) + 1 + strlen ((char *) file) + 1; 1724ca08ab68Smrg /* 1725ca08ab68Smrg * workaround valgrind warning because glibc takes advantage of how it knows memory is 1726ca08ab68Smrg * allocated to implement strlen by reading in groups of 4 1727ca08ab68Smrg */ 1728ca08ab68Smrg size = (osize + 3) & ~3; 1729ca08ab68Smrg 1730ca08ab68Smrg path = malloc (size); 17312c393a42Smrg if (!path) 17322c393a42Smrg return 0; 17332c393a42Smrg 17342c393a42Smrg strcpy ((char *) path, (const char *) dir); 17352c393a42Smrg /* make sure there's a single separator */ 17362c393a42Smrg#ifdef _WIN32 17372c393a42Smrg if ((!path[0] || (path[strlen((char *) path)-1] != '/' && 17382c393a42Smrg path[strlen((char *) path)-1] != '\\')) && 17392c393a42Smrg !(file[0] == '/' || 17402c393a42Smrg file[0] == '\\' || 17412c393a42Smrg (isalpha (file[0]) && file[1] == ':' && (file[2] == '/' || file[2] == '\\')))) 17422c393a42Smrg strcat ((char *) path, "\\"); 17432c393a42Smrg#else 17442c393a42Smrg if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/') 17452c393a42Smrg strcat ((char *) path, "/"); 17462c393a42Smrg#endif 17472c393a42Smrg strcat ((char *) path, (char *) file); 17482c393a42Smrg 1749ca08ab68Smrg FcMemAlloc (FC_MEM_STRING, osize); 17502c393a42Smrg if (access ((char *) path, R_OK) == 0) 17512c393a42Smrg return path; 1752ca08ab68Smrg 17532c393a42Smrg FcStrFree (path); 1754ca08ab68Smrg 17552c393a42Smrg return 0; 17562c393a42Smrg} 17572c393a42Smrg 17582c393a42Smrgstatic FcChar8 ** 17592c393a42SmrgFcConfigGetPath (void) 17602c393a42Smrg{ 17612c393a42Smrg FcChar8 **path; 17622c393a42Smrg FcChar8 *env, *e, *colon; 17632c393a42Smrg FcChar8 *dir; 17642c393a42Smrg int npath; 17652c393a42Smrg int i; 17662c393a42Smrg 17672c393a42Smrg npath = 2; /* default dir + null */ 17682c393a42Smrg env = (FcChar8 *) getenv ("FONTCONFIG_PATH"); 17692c393a42Smrg if (env) 17702c393a42Smrg { 17712c393a42Smrg e = env; 17722c393a42Smrg npath++; 17732c393a42Smrg while (*e) 17742c393a42Smrg if (*e++ == FC_SEARCH_PATH_SEPARATOR) 17752c393a42Smrg npath++; 17762c393a42Smrg } 17772c393a42Smrg path = calloc (npath, sizeof (FcChar8 *)); 17782c393a42Smrg if (!path) 17792c393a42Smrg goto bail0; 17802c393a42Smrg i = 0; 17812c393a42Smrg 17822c393a42Smrg if (env) 17832c393a42Smrg { 17842c393a42Smrg e = env; 1785ca08ab68Smrg while (*e) 17862c393a42Smrg { 17872c393a42Smrg colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR); 17882c393a42Smrg if (!colon) 17892c393a42Smrg colon = e + strlen ((char *) e); 17902c393a42Smrg path[i] = malloc (colon - e + 1); 17912c393a42Smrg if (!path[i]) 17922c393a42Smrg goto bail1; 17932c393a42Smrg strncpy ((char *) path[i], (const char *) e, colon - e); 17942c393a42Smrg path[i][colon - e] = '\0'; 17952c393a42Smrg if (*colon) 17962c393a42Smrg e = colon + 1; 17972c393a42Smrg else 17982c393a42Smrg e = colon; 17992c393a42Smrg i++; 18002c393a42Smrg } 18012c393a42Smrg } 1802ca08ab68Smrg 18032c393a42Smrg#ifdef _WIN32 18042c393a42Smrg if (fontconfig_path[0] == '\0') 18052c393a42Smrg { 1806a6844aabSmrg char *p; 1807ca08ab68Smrg if(!GetModuleFileName(NULL, (LPCH) fontconfig_path, sizeof(fontconfig_path))) 18082c393a42Smrg goto bail1; 1809ca08ab68Smrg p = strrchr ((const char *) fontconfig_path, '\\'); 18102c393a42Smrg if (p) *p = '\0'; 1811ca08ab68Smrg strcat ((char *) fontconfig_path, "\\fonts"); 18122c393a42Smrg } 18132c393a42Smrg#endif 18142c393a42Smrg dir = (FcChar8 *) FONTCONFIG_PATH; 18152c393a42Smrg path[i] = malloc (strlen ((char *) dir) + 1); 18162c393a42Smrg if (!path[i]) 18172c393a42Smrg goto bail1; 18182c393a42Smrg strcpy ((char *) path[i], (const char *) dir); 18192c393a42Smrg return path; 18202c393a42Smrg 18212c393a42Smrgbail1: 18222c393a42Smrg for (i = 0; path[i]; i++) 18232c393a42Smrg free (path[i]); 18242c393a42Smrg free (path); 18252c393a42Smrgbail0: 18262c393a42Smrg return 0; 18272c393a42Smrg} 18282c393a42Smrg 18292c393a42Smrgstatic void 18302c393a42SmrgFcConfigFreePath (FcChar8 **path) 18312c393a42Smrg{ 18322c393a42Smrg FcChar8 **p; 18332c393a42Smrg 18342c393a42Smrg for (p = path; *p; p++) 18352c393a42Smrg free (*p); 18362c393a42Smrg free (path); 18372c393a42Smrg} 18382c393a42Smrg 18392c393a42Smrgstatic FcBool _FcConfigHomeEnabled = FcTrue; 18402c393a42Smrg 18412c393a42SmrgFcChar8 * 18422c393a42SmrgFcConfigHome (void) 18432c393a42Smrg{ 18442c393a42Smrg if (_FcConfigHomeEnabled) 18452c393a42Smrg { 18462c393a42Smrg char *home = getenv ("HOME"); 18472c393a42Smrg 18482c393a42Smrg#ifdef _WIN32 18492c393a42Smrg if (home == NULL) 18502c393a42Smrg home = getenv ("USERPROFILE"); 18512c393a42Smrg#endif 18522c393a42Smrg 18532c393a42Smrg return (FcChar8 *) home; 18542c393a42Smrg } 18552c393a42Smrg return 0; 18562c393a42Smrg} 18572c393a42Smrg 1858ca08ab68SmrgFcChar8 * 1859ca08ab68SmrgFcConfigXdgCacheHome (void) 1860ca08ab68Smrg{ 1861ca08ab68Smrg const char *env = getenv ("XDG_CACHE_HOME"); 1862ca08ab68Smrg FcChar8 *ret = NULL; 1863ca08ab68Smrg 1864ca08ab68Smrg if (env) 1865ca08ab68Smrg ret = FcStrCopy ((const FcChar8 *)env); 1866ca08ab68Smrg else 1867ca08ab68Smrg { 1868ca08ab68Smrg const FcChar8 *home = FcConfigHome (); 1869ca08ab68Smrg size_t len = home ? strlen ((const char *)home) : 0; 1870ca08ab68Smrg 1871ca08ab68Smrg ret = malloc (len + 7 + 1); 1872ca08ab68Smrg if (ret) 1873ca08ab68Smrg { 1874ca08ab68Smrg FcMemAlloc (FC_MEM_STRING, len + 7 + 1); 1875ca08ab68Smrg memcpy (ret, home, len); 1876ca08ab68Smrg memcpy (&ret[len], FC_DIR_SEPARATOR_S ".cache", 7); 1877ca08ab68Smrg ret[len + 7] = 0; 1878ca08ab68Smrg } 1879ca08ab68Smrg } 1880ca08ab68Smrg 1881ca08ab68Smrg return ret; 1882ca08ab68Smrg} 1883ca08ab68Smrg 1884ca08ab68SmrgFcChar8 * 1885ca08ab68SmrgFcConfigXdgConfigHome (void) 1886ca08ab68Smrg{ 1887ca08ab68Smrg const char *env = getenv ("XDG_CONFIG_HOME"); 1888ca08ab68Smrg FcChar8 *ret = NULL; 1889ca08ab68Smrg 1890ca08ab68Smrg if (env) 1891ca08ab68Smrg ret = FcStrCopy ((const FcChar8 *)env); 1892ca08ab68Smrg else 1893ca08ab68Smrg { 1894ca08ab68Smrg const FcChar8 *home = FcConfigHome (); 1895ca08ab68Smrg size_t len = home ? strlen ((const char *)home) : 0; 1896ca08ab68Smrg 1897ca08ab68Smrg ret = malloc (len + 8 + 1); 1898ca08ab68Smrg if (ret) 1899ca08ab68Smrg { 1900ca08ab68Smrg FcMemAlloc (FC_MEM_STRING, len + 8 + 1); 1901ca08ab68Smrg memcpy (ret, home, len); 1902ca08ab68Smrg memcpy (&ret[len], FC_DIR_SEPARATOR_S ".config", 8); 1903ca08ab68Smrg ret[len + 8] = 0; 1904ca08ab68Smrg } 1905ca08ab68Smrg } 1906ca08ab68Smrg 1907ca08ab68Smrg return ret; 1908ca08ab68Smrg} 1909ca08ab68Smrg 1910ca08ab68SmrgFcChar8 * 1911ca08ab68SmrgFcConfigXdgDataHome (void) 1912ca08ab68Smrg{ 1913ca08ab68Smrg const char *env = getenv ("XDG_DATA_HOME"); 1914ca08ab68Smrg FcChar8 *ret = NULL; 1915ca08ab68Smrg 1916ca08ab68Smrg if (env) 1917ca08ab68Smrg ret = FcStrCopy ((const FcChar8 *)env); 1918ca08ab68Smrg else 1919ca08ab68Smrg { 1920ca08ab68Smrg const FcChar8 *home = FcConfigHome (); 1921ca08ab68Smrg size_t len = home ? strlen ((const char *)home) : 0; 1922ca08ab68Smrg 1923ca08ab68Smrg ret = malloc (len + 13 + 1); 1924ca08ab68Smrg if (ret) 1925ca08ab68Smrg { 1926ca08ab68Smrg FcMemAlloc (FC_MEM_STRING, len + 13 + 1); 1927ca08ab68Smrg memcpy (ret, home, len); 1928ca08ab68Smrg memcpy (&ret[len], FC_DIR_SEPARATOR_S ".local" FC_DIR_SEPARATOR_S "share", 13); 1929ca08ab68Smrg ret[len + 13] = 0; 1930ca08ab68Smrg } 1931ca08ab68Smrg } 1932ca08ab68Smrg 1933ca08ab68Smrg return ret; 1934ca08ab68Smrg} 1935ca08ab68Smrg 19362c393a42SmrgFcBool 19372c393a42SmrgFcConfigEnableHome (FcBool enable) 19382c393a42Smrg{ 19392c393a42Smrg FcBool prev = _FcConfigHomeEnabled; 19402c393a42Smrg _FcConfigHomeEnabled = enable; 19412c393a42Smrg return prev; 19422c393a42Smrg} 19432c393a42Smrg 19442c393a42SmrgFcChar8 * 19452c393a42SmrgFcConfigFilename (const FcChar8 *url) 19462c393a42Smrg{ 19472c393a42Smrg FcChar8 *file, *dir, **path, **p; 19482c393a42Smrg 19492c393a42Smrg if (!url || !*url) 19502c393a42Smrg { 19512c393a42Smrg url = (FcChar8 *) getenv ("FONTCONFIG_FILE"); 19522c393a42Smrg if (!url) 19532c393a42Smrg url = (FcChar8 *) FONTCONFIG_FILE; 19542c393a42Smrg } 19552c393a42Smrg file = 0; 19562c393a42Smrg 19572c393a42Smrg#ifdef _WIN32 19582c393a42Smrg if (isalpha (*url) && 19592c393a42Smrg url[1] == ':' && 19602c393a42Smrg (url[2] == '/' || url[2] == '\\')) 19612c393a42Smrg goto absolute_path; 19622c393a42Smrg#endif 19632c393a42Smrg 19642c393a42Smrg switch (*url) { 19652c393a42Smrg case '~': 19662c393a42Smrg dir = FcConfigHome (); 19672c393a42Smrg if (dir) 19682c393a42Smrg file = FcConfigFileExists (dir, url + 1); 19692c393a42Smrg else 19702c393a42Smrg file = 0; 19712c393a42Smrg break; 19722c393a42Smrg#ifdef _WIN32 19732c393a42Smrg case '\\': 19742c393a42Smrg absolute_path: 19752c393a42Smrg#endif 19762c393a42Smrg case '/': 19772c393a42Smrg file = FcConfigFileExists (0, url); 19782c393a42Smrg break; 19792c393a42Smrg default: 19802c393a42Smrg path = FcConfigGetPath (); 19812c393a42Smrg if (!path) 1982ca08ab68Smrg return NULL; 19832c393a42Smrg for (p = path; *p; p++) 19842c393a42Smrg { 19852c393a42Smrg file = FcConfigFileExists (*p, url); 19862c393a42Smrg if (file) 19872c393a42Smrg break; 19882c393a42Smrg } 19892c393a42Smrg FcConfigFreePath (path); 19902c393a42Smrg break; 19912c393a42Smrg } 1992ca08ab68Smrg 19932c393a42Smrg return file; 19942c393a42Smrg} 19952c393a42Smrg 19962c393a42Smrg/* 19972c393a42Smrg * Manage the application-specific fonts 19982c393a42Smrg */ 19992c393a42Smrg 20002c393a42SmrgFcBool 20012c393a42SmrgFcConfigAppFontAddFile (FcConfig *config, 20022c393a42Smrg const FcChar8 *file) 20032c393a42Smrg{ 20042c393a42Smrg FcFontSet *set; 20052c393a42Smrg FcStrSet *subdirs; 20062c393a42Smrg FcStrList *sublist; 20072c393a42Smrg FcChar8 *subdir; 20082c393a42Smrg 20092c393a42Smrg if (!config) 20102c393a42Smrg { 20112c393a42Smrg config = FcConfigGetCurrent (); 20122c393a42Smrg if (!config) 20132c393a42Smrg return FcFalse; 20142c393a42Smrg } 20152c393a42Smrg 20162c393a42Smrg subdirs = FcStrSetCreate (); 20172c393a42Smrg if (!subdirs) 20182c393a42Smrg return FcFalse; 2019ca08ab68Smrg 20202c393a42Smrg set = FcConfigGetFonts (config, FcSetApplication); 20212c393a42Smrg if (!set) 20222c393a42Smrg { 20232c393a42Smrg set = FcFontSetCreate (); 20242c393a42Smrg if (!set) 20252c393a42Smrg { 20262c393a42Smrg FcStrSetDestroy (subdirs); 20272c393a42Smrg return FcFalse; 20282c393a42Smrg } 20292c393a42Smrg FcConfigSetFonts (config, set, FcSetApplication); 20302c393a42Smrg } 20312c393a42Smrg 20322c393a42Smrg if (!FcFileScanConfig (set, subdirs, config->blanks, file, config)) 20332c393a42Smrg { 20342c393a42Smrg FcStrSetDestroy (subdirs); 20352c393a42Smrg return FcFalse; 20362c393a42Smrg } 20372c393a42Smrg if ((sublist = FcStrListCreate (subdirs))) 20382c393a42Smrg { 20392c393a42Smrg while ((subdir = FcStrListNext (sublist))) 20402c393a42Smrg { 20412c393a42Smrg FcConfigAppFontAddDir (config, subdir); 20422c393a42Smrg } 20432c393a42Smrg FcStrListDone (sublist); 20442c393a42Smrg } 20452c393a42Smrg FcStrSetDestroy (subdirs); 20462c393a42Smrg return FcTrue; 20472c393a42Smrg} 20482c393a42Smrg 20492c393a42SmrgFcBool 20502c393a42SmrgFcConfigAppFontAddDir (FcConfig *config, 20512c393a42Smrg const FcChar8 *dir) 20522c393a42Smrg{ 20532c393a42Smrg FcFontSet *set; 20542c393a42Smrg FcStrSet *dirs; 2055ca08ab68Smrg 20562c393a42Smrg if (!config) 20572c393a42Smrg { 20582c393a42Smrg config = FcConfigGetCurrent (); 20592c393a42Smrg if (!config) 20602c393a42Smrg return FcFalse; 20612c393a42Smrg } 20622c393a42Smrg 20632c393a42Smrg dirs = FcStrSetCreate (); 20642c393a42Smrg if (!dirs) 20652c393a42Smrg return FcFalse; 2066ca08ab68Smrg 20672c393a42Smrg set = FcConfigGetFonts (config, FcSetApplication); 20682c393a42Smrg if (!set) 20692c393a42Smrg { 20702c393a42Smrg set = FcFontSetCreate (); 20712c393a42Smrg if (!set) 20722c393a42Smrg { 20732c393a42Smrg FcStrSetDestroy (dirs); 20742c393a42Smrg return FcFalse; 20752c393a42Smrg } 20762c393a42Smrg FcConfigSetFonts (config, set, FcSetApplication); 20772c393a42Smrg } 2078ca08ab68Smrg 20792c393a42Smrg FcStrSetAddFilename (dirs, dir); 2080ca08ab68Smrg 20812c393a42Smrg if (!FcConfigAddDirList (config, FcSetApplication, dirs)) 20822c393a42Smrg { 20832c393a42Smrg FcStrSetDestroy (dirs); 20842c393a42Smrg return FcFalse; 20852c393a42Smrg } 20862c393a42Smrg FcStrSetDestroy (dirs); 20872c393a42Smrg return FcTrue; 20882c393a42Smrg} 20892c393a42Smrg 20902c393a42Smrgvoid 20912c393a42SmrgFcConfigAppFontClear (FcConfig *config) 20922c393a42Smrg{ 20932c393a42Smrg if (!config) 20942c393a42Smrg { 20952c393a42Smrg config = FcConfigGetCurrent (); 20962c393a42Smrg if (!config) 20972c393a42Smrg return; 20982c393a42Smrg } 20992c393a42Smrg 21002c393a42Smrg FcConfigSetFonts (config, 0, FcSetApplication); 21012c393a42Smrg} 21022c393a42Smrg 21032c393a42Smrg/* 21042c393a42Smrg * Manage filename-based font source selectors 21052c393a42Smrg */ 21062c393a42Smrg 21072c393a42SmrgFcBool 21082c393a42SmrgFcConfigGlobAdd (FcConfig *config, 21092c393a42Smrg const FcChar8 *glob, 21102c393a42Smrg FcBool accept) 21112c393a42Smrg{ 21122c393a42Smrg FcStrSet *set = accept ? config->acceptGlobs : config->rejectGlobs; 21132c393a42Smrg 21142c393a42Smrg return FcStrSetAdd (set, glob); 21152c393a42Smrg} 21162c393a42Smrg 21172c393a42Smrgstatic FcBool 21182c393a42SmrgFcConfigGlobMatch (const FcChar8 *glob, 21192c393a42Smrg const FcChar8 *string) 21202c393a42Smrg{ 21212c393a42Smrg FcChar8 c; 21222c393a42Smrg 2123ca08ab68Smrg while ((c = *glob++)) 21242c393a42Smrg { 21252c393a42Smrg switch (c) { 21262c393a42Smrg case '*': 21272c393a42Smrg /* short circuit common case */ 21282c393a42Smrg if (!*glob) 21292c393a42Smrg return FcTrue; 21302c393a42Smrg /* short circuit another common case */ 21312c393a42Smrg if (strchr ((char *) glob, '*') == 0) 2132ca08ab68Smrg { 2133ca08ab68Smrg size_t l1, l2; 2134ca08ab68Smrg 2135ca08ab68Smrg l1 = strlen ((char *) string); 2136ca08ab68Smrg l2 = strlen ((char *) glob); 2137ca08ab68Smrg if (l1 < l2) 2138ca08ab68Smrg return FcFalse; 2139ca08ab68Smrg string += (l1 - l2); 2140ca08ab68Smrg } 21412c393a42Smrg while (*string) 21422c393a42Smrg { 21432c393a42Smrg if (FcConfigGlobMatch (glob, string)) 21442c393a42Smrg return FcTrue; 21452c393a42Smrg string++; 21462c393a42Smrg } 21472c393a42Smrg return FcFalse; 21482c393a42Smrg case '?': 21492c393a42Smrg if (*string++ == '\0') 21502c393a42Smrg return FcFalse; 21512c393a42Smrg break; 21522c393a42Smrg default: 21532c393a42Smrg if (*string++ != c) 21542c393a42Smrg return FcFalse; 21552c393a42Smrg break; 21562c393a42Smrg } 21572c393a42Smrg } 21582c393a42Smrg return *string == '\0'; 21592c393a42Smrg} 21602c393a42Smrg 21612c393a42Smrgstatic FcBool 21622c393a42SmrgFcConfigGlobsMatch (const FcStrSet *globs, 21632c393a42Smrg const FcChar8 *string) 21642c393a42Smrg{ 21652c393a42Smrg int i; 21662c393a42Smrg 21672c393a42Smrg for (i = 0; i < globs->num; i++) 21682c393a42Smrg if (FcConfigGlobMatch (globs->strs[i], string)) 21692c393a42Smrg return FcTrue; 21702c393a42Smrg return FcFalse; 21712c393a42Smrg} 21722c393a42Smrg 21732c393a42SmrgFcBool 21742c393a42SmrgFcConfigAcceptFilename (FcConfig *config, 21752c393a42Smrg const FcChar8 *filename) 21762c393a42Smrg{ 21772c393a42Smrg if (FcConfigGlobsMatch (config->acceptGlobs, filename)) 21782c393a42Smrg return FcTrue; 21792c393a42Smrg if (FcConfigGlobsMatch (config->rejectGlobs, filename)) 21802c393a42Smrg return FcFalse; 21812c393a42Smrg return FcTrue; 21822c393a42Smrg} 21832c393a42Smrg 21842c393a42Smrg/* 21852c393a42Smrg * Manage font-pattern based font source selectors 21862c393a42Smrg */ 21872c393a42Smrg 21882c393a42SmrgFcBool 21892c393a42SmrgFcConfigPatternsAdd (FcConfig *config, 21902c393a42Smrg FcPattern *pattern, 21912c393a42Smrg FcBool accept) 21922c393a42Smrg{ 21932c393a42Smrg FcFontSet *set = accept ? config->acceptPatterns : config->rejectPatterns; 21942c393a42Smrg 21952c393a42Smrg return FcFontSetAdd (set, pattern); 21962c393a42Smrg} 21972c393a42Smrg 21982c393a42Smrgstatic FcBool 21992c393a42SmrgFcConfigPatternsMatch (const FcFontSet *patterns, 22002c393a42Smrg const FcPattern *font) 22012c393a42Smrg{ 22022c393a42Smrg int i; 2203ca08ab68Smrg 22042c393a42Smrg for (i = 0; i < patterns->nfont; i++) 22052c393a42Smrg if (FcListPatternMatchAny (patterns->fonts[i], font)) 22062c393a42Smrg return FcTrue; 22072c393a42Smrg return FcFalse; 22082c393a42Smrg} 22092c393a42Smrg 22102c393a42SmrgFcBool 22112c393a42SmrgFcConfigAcceptFont (FcConfig *config, 22122c393a42Smrg const FcPattern *font) 22132c393a42Smrg{ 22142c393a42Smrg if (FcConfigPatternsMatch (config->acceptPatterns, font)) 22152c393a42Smrg return FcTrue; 22162c393a42Smrg if (FcConfigPatternsMatch (config->rejectPatterns, font)) 22172c393a42Smrg return FcFalse; 22182c393a42Smrg return FcTrue; 22192c393a42Smrg} 22202c393a42Smrg#define __fccfg__ 22212c393a42Smrg#include "fcaliastail.h" 22222c393a42Smrg#undef __fccfg__ 2223