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