fccfg.c revision c9710b42
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;
2172c393a42Smrg	if (s->test)
2182c393a42Smrg	    FcTestDestroy (s->test);
2192c393a42Smrg	if (s->edit)
2202c393a42Smrg	    FcEditDestroy (s->edit);
2212c393a42Smrg	free (s);
2222c393a42Smrg	s = n;
2232c393a42Smrg    }
2242c393a42Smrg}
2252c393a42Smrg
226a6844aabSmrgFcExpr *
227a6844aabSmrgFcConfigAllocExpr (FcConfig *config)
228a6844aabSmrg{
229a6844aabSmrg  if (!config->expr_pool || config->expr_pool->next == config->expr_pool->end)
230a6844aabSmrg  {
231a6844aabSmrg    FcExprPage *new_page;
232a6844aabSmrg
233a6844aabSmrg    new_page = malloc (sizeof (FcExprPage));
234a6844aabSmrg    if (!new_page)
235a6844aabSmrg      return 0;
236a6844aabSmrg
237a6844aabSmrg    new_page->next_page = config->expr_pool;
238a6844aabSmrg    new_page->next = new_page->exprs;
239a6844aabSmrg    config->expr_pool = new_page;
240a6844aabSmrg  }
241a6844aabSmrg
242a6844aabSmrg  return config->expr_pool->next++;
243a6844aabSmrg}
244a6844aabSmrg
245a6844aabSmrgFcConfig *
246a6844aabSmrgFcConfigReference (FcConfig *config)
247a6844aabSmrg{
248a6844aabSmrg    if (!config)
249a6844aabSmrg    {
250a6844aabSmrg	config = FcConfigGetCurrent ();
251a6844aabSmrg	if (!config)
252a6844aabSmrg	    return 0;
253a6844aabSmrg    }
254a6844aabSmrg
255c9710b42Smrg    FcRefInc (&config->ref);
256a6844aabSmrg
257a6844aabSmrg    return config;
258a6844aabSmrg}
259a6844aabSmrg
2602c393a42Smrgvoid
2612c393a42SmrgFcConfigDestroy (FcConfig *config)
2622c393a42Smrg{
2632c393a42Smrg    FcSetName	set;
264a6844aabSmrg    FcExprPage	*page;
265a6844aabSmrg
266c9710b42Smrg    if (FcRefDec (&config->ref) != 1)
267a6844aabSmrg	return;
2682c393a42Smrg
269c9710b42Smrg    (void) fc_atomic_ptr_cmpexch (&_fcConfig, config, NULL);
2702c393a42Smrg
2712c393a42Smrg    FcStrSetDestroy (config->configDirs);
2722c393a42Smrg    FcStrSetDestroy (config->fontDirs);
2732c393a42Smrg    FcStrSetDestroy (config->cacheDirs);
2742c393a42Smrg    FcStrSetDestroy (config->configFiles);
2752c393a42Smrg    FcStrSetDestroy (config->acceptGlobs);
2762c393a42Smrg    FcStrSetDestroy (config->rejectGlobs);
2772c393a42Smrg    FcFontSetDestroy (config->acceptPatterns);
2782c393a42Smrg    FcFontSetDestroy (config->rejectPatterns);
2792c393a42Smrg
2802c393a42Smrg    if (config->blanks)
2812c393a42Smrg	FcBlanksDestroy (config->blanks);
2822c393a42Smrg
2832c393a42Smrg    FcSubstDestroy (config->substPattern);
2842c393a42Smrg    FcSubstDestroy (config->substFont);
2852c393a42Smrg    FcSubstDestroy (config->substScan);
2862c393a42Smrg    for (set = FcSetSystem; set <= FcSetApplication; set++)
2872c393a42Smrg	if (config->fonts[set])
2882c393a42Smrg	    FcFontSetDestroy (config->fonts[set]);
2892c393a42Smrg
290a6844aabSmrg    page = config->expr_pool;
291a6844aabSmrg    while (page)
292a6844aabSmrg    {
293a6844aabSmrg      FcExprPage *next = page->next_page;
294a6844aabSmrg      free (page);
295a6844aabSmrg      page = next;
296a6844aabSmrg    }
297c9710b42Smrg    if (config->sysRoot)
298c9710b42Smrg	FcStrFree (config->sysRoot);
299a6844aabSmrg
3002c393a42Smrg    free (config);
3012c393a42Smrg}
3022c393a42Smrg
3032c393a42Smrg/*
3042c393a42Smrg * Add cache to configuration, adding fonts and directories
3052c393a42Smrg */
3062c393a42Smrg
3072c393a42SmrgFcBool
308ca08ab68SmrgFcConfigAddCache (FcConfig *config, FcCache *cache,
3092c393a42Smrg		  FcSetName set, FcStrSet *dirSet)
3102c393a42Smrg{
3112c393a42Smrg    FcFontSet	*fs;
3122c393a42Smrg    intptr_t	*dirs;
3132c393a42Smrg    int		i;
3142c393a42Smrg
3152c393a42Smrg    /*
3162c393a42Smrg     * Add fonts
3172c393a42Smrg     */
3182c393a42Smrg    fs = FcCacheSet (cache);
3192c393a42Smrg    if (fs)
3202c393a42Smrg    {
3212c393a42Smrg	int	nref = 0;
3222c393a42Smrg
3232c393a42Smrg	for (i = 0; i < fs->nfont; i++)
3242c393a42Smrg	{
3252c393a42Smrg	    FcPattern	*font = FcFontSetFont (fs, i);
3262c393a42Smrg	    FcChar8	*font_file;
3272c393a42Smrg
3282c393a42Smrg	    /*
3292c393a42Smrg	     * Check to see if font is banned by filename
3302c393a42Smrg	     */
3312c393a42Smrg	    if (FcPatternObjectGetString (font, FC_FILE_OBJECT,
3322c393a42Smrg					  0, &font_file) == FcResultMatch &&
3332c393a42Smrg		!FcConfigAcceptFilename (config, font_file))
3342c393a42Smrg	    {
3352c393a42Smrg		continue;
3362c393a42Smrg	    }
3372c393a42Smrg
3382c393a42Smrg	    /*
3392c393a42Smrg	     * Check to see if font is banned by pattern
3402c393a42Smrg	     */
3412c393a42Smrg	    if (!FcConfigAcceptFont (config, font))
3422c393a42Smrg		continue;
3432c393a42Smrg
344c9710b42Smrg	    if (FcFontSetAdd (config->fonts[set], font))
345c9710b42Smrg		nref++;
3462c393a42Smrg	}
3472c393a42Smrg	FcDirCacheReference (cache, nref);
3482c393a42Smrg    }
3492c393a42Smrg
3502c393a42Smrg    /*
3512c393a42Smrg     * Add directories
3522c393a42Smrg     */
3532c393a42Smrg    dirs = FcCacheDirs (cache);
3542c393a42Smrg    if (dirs)
3552c393a42Smrg    {
3562c393a42Smrg	for (i = 0; i < cache->dirs_count; i++)
3572c393a42Smrg	{
3582c393a42Smrg	    FcChar8	*dir = FcOffsetToPtr (dirs, dirs[i], FcChar8);
3592c393a42Smrg	    if (FcConfigAcceptFilename (config, dir))
3602c393a42Smrg		FcStrSetAddFilename (dirSet, dir);
3612c393a42Smrg	}
3622c393a42Smrg    }
3632c393a42Smrg    return FcTrue;
3642c393a42Smrg}
3652c393a42Smrg
3662c393a42Smrgstatic FcBool
3672c393a42SmrgFcConfigAddDirList (FcConfig *config, FcSetName set, FcStrSet *dirSet)
3682c393a42Smrg{
3692c393a42Smrg    FcStrList	    *dirlist;
3702c393a42Smrg    FcChar8	    *dir;
3712c393a42Smrg    FcCache	    *cache;
372ca08ab68Smrg
3732c393a42Smrg    dirlist = FcStrListCreate (dirSet);
3742c393a42Smrg    if (!dirlist)
3752c393a42Smrg        return FcFalse;
3762c393a42Smrg
3772c393a42Smrg    while ((dir = FcStrListNext (dirlist)))
3782c393a42Smrg    {
3792c393a42Smrg	if (FcDebug () & FC_DBG_FONTSET)
3802c393a42Smrg	    printf ("adding fonts from%s\n", dir);
3812c393a42Smrg	cache = FcDirCacheRead (dir, FcFalse, config);
3822c393a42Smrg	if (!cache)
3832c393a42Smrg	    continue;
3842c393a42Smrg	FcConfigAddCache (config, cache, set, dirSet);
3852c393a42Smrg	FcDirCacheUnload (cache);
3862c393a42Smrg    }
3872c393a42Smrg    FcStrListDone (dirlist);
3882c393a42Smrg    return FcTrue;
3892c393a42Smrg}
3902c393a42Smrg
3912c393a42Smrg/*
3922c393a42Smrg * Scan the current list of directories in the configuration
3932c393a42Smrg * and build the set of available fonts.
3942c393a42Smrg */
3952c393a42Smrg
3962c393a42SmrgFcBool
3972c393a42SmrgFcConfigBuildFonts (FcConfig *config)
3982c393a42Smrg{
3992c393a42Smrg    FcFontSet	    *fonts;
4002c393a42Smrg
4012c393a42Smrg    if (!config)
4022c393a42Smrg    {
4032c393a42Smrg	config = FcConfigGetCurrent ();
4042c393a42Smrg	if (!config)
4052c393a42Smrg	    return FcFalse;
4062c393a42Smrg    }
4072c393a42Smrg
4082c393a42Smrg    fonts = FcFontSetCreate ();
4092c393a42Smrg    if (!fonts)
4102c393a42Smrg	return FcFalse;
411ca08ab68Smrg
4122c393a42Smrg    FcConfigSetFonts (config, fonts, FcSetSystem);
413ca08ab68Smrg
4142c393a42Smrg    if (!FcConfigAddDirList (config, FcSetSystem, config->fontDirs))
4152c393a42Smrg	return FcFalse;
4162c393a42Smrg    if (FcDebug () & FC_DBG_FONTSET)
4172c393a42Smrg	FcFontSetPrint (fonts);
4182c393a42Smrg    return FcTrue;
4192c393a42Smrg}
4202c393a42Smrg
4212c393a42SmrgFcBool
4222c393a42SmrgFcConfigSetCurrent (FcConfig *config)
4232c393a42Smrg{
424c9710b42Smrg    FcConfig *cfg;
425c9710b42Smrg
426c9710b42Smrgretry:
427c9710b42Smrg    cfg = fc_atomic_ptr_get (&_fcConfig);
428c9710b42Smrg
429c9710b42Smrg    if (config == cfg)
4302c393a42Smrg	return FcTrue;
4312c393a42Smrg
432c9710b42Smrg    if (config && !config->fonts[FcSetSystem])
4332c393a42Smrg	if (!FcConfigBuildFonts (config))
4342c393a42Smrg	    return FcFalse;
4352c393a42Smrg
436c9710b42Smrg    if (!fc_atomic_ptr_cmpexch (&_fcConfig, cfg, config))
437c9710b42Smrg	goto retry;
438c9710b42Smrg
439c9710b42Smrg    if (cfg)
440c9710b42Smrg	FcConfigDestroy (cfg);
441c9710b42Smrg
4422c393a42Smrg    return FcTrue;
4432c393a42Smrg}
4442c393a42Smrg
4452c393a42SmrgFcConfig *
4462c393a42SmrgFcConfigGetCurrent (void)
4472c393a42Smrg{
448c9710b42Smrg    return FcConfigEnsure ();
4492c393a42Smrg}
4502c393a42Smrg
4512c393a42SmrgFcBool
4522c393a42SmrgFcConfigAddConfigDir (FcConfig	    *config,
4532c393a42Smrg		      const FcChar8 *d)
4542c393a42Smrg{
4552c393a42Smrg    return FcStrSetAddFilename (config->configDirs, d);
4562c393a42Smrg}
4572c393a42Smrg
4582c393a42SmrgFcStrList *
4592c393a42SmrgFcConfigGetConfigDirs (FcConfig   *config)
4602c393a42Smrg{
4612c393a42Smrg    if (!config)
4622c393a42Smrg    {
4632c393a42Smrg	config = FcConfigGetCurrent ();
4642c393a42Smrg	if (!config)
4652c393a42Smrg	    return 0;
4662c393a42Smrg    }
4672c393a42Smrg    return FcStrListCreate (config->configDirs);
4682c393a42Smrg}
4692c393a42Smrg
4702c393a42SmrgFcBool
4712c393a42SmrgFcConfigAddFontDir (FcConfig	    *config,
4722c393a42Smrg		    const FcChar8   *d)
4732c393a42Smrg{
4742c393a42Smrg    return FcStrSetAddFilename (config->fontDirs, d);
4752c393a42Smrg}
4762c393a42Smrg
4772c393a42SmrgFcBool
4782c393a42SmrgFcConfigAddDir (FcConfig	    *config,
4792c393a42Smrg		const FcChar8	    *d)
4802c393a42Smrg{
481ca08ab68Smrg    return (FcConfigAddConfigDir (config, d) &&
4822c393a42Smrg	    FcConfigAddFontDir (config, d));
4832c393a42Smrg}
4842c393a42Smrg
4852c393a42SmrgFcStrList *
4862c393a42SmrgFcConfigGetFontDirs (FcConfig	*config)
4872c393a42Smrg{
4882c393a42Smrg    if (!config)
4892c393a42Smrg    {
4902c393a42Smrg	config = FcConfigGetCurrent ();
4912c393a42Smrg	if (!config)
4922c393a42Smrg	    return 0;
4932c393a42Smrg    }
4942c393a42Smrg    return FcStrListCreate (config->fontDirs);
4952c393a42Smrg}
4962c393a42Smrg
4972c393a42SmrgFcBool
4982c393a42SmrgFcConfigAddCacheDir (FcConfig	    *config,
4992c393a42Smrg		     const FcChar8  *d)
5002c393a42Smrg{
5012c393a42Smrg    return FcStrSetAddFilename (config->cacheDirs, d);
5022c393a42Smrg}
5032c393a42Smrg
5042c393a42SmrgFcStrList *
505ca08ab68SmrgFcConfigGetCacheDirs (const FcConfig *config)
5062c393a42Smrg{
5072c393a42Smrg    if (!config)
5082c393a42Smrg    {
5092c393a42Smrg	config = FcConfigGetCurrent ();
5102c393a42Smrg	if (!config)
5112c393a42Smrg	    return 0;
5122c393a42Smrg    }
5132c393a42Smrg    return FcStrListCreate (config->cacheDirs);
5142c393a42Smrg}
515ca08ab68Smrg
5162c393a42SmrgFcBool
5172c393a42SmrgFcConfigAddConfigFile (FcConfig	    *config,
5182c393a42Smrg		       const FcChar8   *f)
5192c393a42Smrg{
5202c393a42Smrg    FcBool	ret;
5212c393a42Smrg    FcChar8	*file = FcConfigFilename (f);
522ca08ab68Smrg
5232c393a42Smrg    if (!file)
5242c393a42Smrg	return FcFalse;
525ca08ab68Smrg
5262c393a42Smrg    ret = FcStrSetAdd (config->configFiles, file);
5272c393a42Smrg    FcStrFree (file);
5282c393a42Smrg    return ret;
5292c393a42Smrg}
5302c393a42Smrg
5312c393a42SmrgFcStrList *
5322c393a42SmrgFcConfigGetConfigFiles (FcConfig    *config)
5332c393a42Smrg{
5342c393a42Smrg    if (!config)
5352c393a42Smrg    {
5362c393a42Smrg	config = FcConfigGetCurrent ();
5372c393a42Smrg	if (!config)
5382c393a42Smrg	    return 0;
5392c393a42Smrg    }
5402c393a42Smrg    return FcStrListCreate (config->configFiles);
5412c393a42Smrg}
5422c393a42Smrg
5432c393a42SmrgFcChar8 *
544c9710b42SmrgFcConfigGetCache (FcConfig  *config FC_UNUSED)
5452c393a42Smrg{
5462c393a42Smrg    return NULL;
5472c393a42Smrg}
5482c393a42Smrg
5492c393a42SmrgFcFontSet *
5502c393a42SmrgFcConfigGetFonts (FcConfig	*config,
5512c393a42Smrg		  FcSetName	set)
5522c393a42Smrg{
5532c393a42Smrg    if (!config)
5542c393a42Smrg    {
5552c393a42Smrg	config = FcConfigGetCurrent ();
5562c393a42Smrg	if (!config)
5572c393a42Smrg	    return 0;
5582c393a42Smrg    }
5592c393a42Smrg    return config->fonts[set];
5602c393a42Smrg}
5612c393a42Smrg
5622c393a42Smrgvoid
5632c393a42SmrgFcConfigSetFonts (FcConfig	*config,
5642c393a42Smrg		  FcFontSet	*fonts,
5652c393a42Smrg		  FcSetName	set)
5662c393a42Smrg{
5672c393a42Smrg    if (config->fonts[set])
5682c393a42Smrg	FcFontSetDestroy (config->fonts[set]);
5692c393a42Smrg    config->fonts[set] = fonts;
5702c393a42Smrg}
5712c393a42Smrg
5722c393a42SmrgFcBlanks *
5732c393a42SmrgFcConfigGetBlanks (FcConfig	*config)
5742c393a42Smrg{
5752c393a42Smrg    if (!config)
5762c393a42Smrg    {
5772c393a42Smrg	config = FcConfigGetCurrent ();
5782c393a42Smrg	if (!config)
5792c393a42Smrg	    return 0;
5802c393a42Smrg    }
5812c393a42Smrg    return config->blanks;
5822c393a42Smrg}
5832c393a42Smrg
5842c393a42SmrgFcBool
5852c393a42SmrgFcConfigAddBlank (FcConfig	*config,
5862c393a42Smrg		  FcChar32    	blank)
5872c393a42Smrg{
5882c393a42Smrg    FcBlanks	*b, *freeme = 0;
589ca08ab68Smrg
5902c393a42Smrg    b = config->blanks;
5912c393a42Smrg    if (!b)
5922c393a42Smrg    {
5932c393a42Smrg	freeme = b = FcBlanksCreate ();
5942c393a42Smrg	if (!b)
5952c393a42Smrg	    return FcFalse;
5962c393a42Smrg    }
5972c393a42Smrg    if (!FcBlanksAdd (b, blank))
5982c393a42Smrg    {
5992c393a42Smrg        if (freeme)
6002c393a42Smrg            FcBlanksDestroy (freeme);
6012c393a42Smrg	return FcFalse;
6022c393a42Smrg    }
6032c393a42Smrg    config->blanks = b;
6042c393a42Smrg    return FcTrue;
6052c393a42Smrg}
6062c393a42Smrg
6072c393a42Smrgint
6082c393a42SmrgFcConfigGetRescanInterval (FcConfig *config)
6092c393a42Smrg{
6102c393a42Smrg    if (!config)
6112c393a42Smrg    {
6122c393a42Smrg	config = FcConfigGetCurrent ();
6132c393a42Smrg	if (!config)
6142c393a42Smrg	    return 0;
6152c393a42Smrg    }
6162c393a42Smrg    return config->rescanInterval;
6172c393a42Smrg}
6182c393a42Smrg
6192c393a42SmrgFcBool
6202c393a42SmrgFcConfigSetRescanInterval (FcConfig *config, int rescanInterval)
6212c393a42Smrg{
6222c393a42Smrg    if (!config)
6232c393a42Smrg    {
6242c393a42Smrg	config = FcConfigGetCurrent ();
6252c393a42Smrg	if (!config)
6262c393a42Smrg	    return FcFalse;
6272c393a42Smrg    }
6282c393a42Smrg    config->rescanInterval = rescanInterval;
6292c393a42Smrg    return FcTrue;
6302c393a42Smrg}
6312c393a42Smrg
6322c393a42Smrg/*
6332c393a42Smrg * A couple of typos escaped into the library
6342c393a42Smrg */
6352c393a42Smrgint
6362c393a42SmrgFcConfigGetRescanInverval (FcConfig *config)
6372c393a42Smrg{
6382c393a42Smrg    return FcConfigGetRescanInterval (config);
6392c393a42Smrg}
6402c393a42Smrg
6412c393a42SmrgFcBool
6422c393a42SmrgFcConfigSetRescanInverval (FcConfig *config, int rescanInterval)
6432c393a42Smrg{
6442c393a42Smrg    return FcConfigSetRescanInterval (config, rescanInterval);
6452c393a42Smrg}
6462c393a42Smrg
647ca08ab68Smrg
6482c393a42SmrgFcBool
6492c393a42SmrgFcConfigAddEdit (FcConfig	*config,
6502c393a42Smrg		 FcTest		*test,
6512c393a42Smrg		 FcEdit		*edit,
6522c393a42Smrg		 FcMatchKind	kind)
6532c393a42Smrg{
6542c393a42Smrg    FcSubst	*subst, **prev;
6552c393a42Smrg    FcTest	*t;
6562c393a42Smrg    int		num;
6572c393a42Smrg
6582c393a42Smrg    switch (kind) {
6592c393a42Smrg    case FcMatchPattern:
6602c393a42Smrg	prev = &config->substPattern;
6612c393a42Smrg	break;
6622c393a42Smrg    case FcMatchFont:
6632c393a42Smrg	prev = &config->substFont;
6642c393a42Smrg	break;
6652c393a42Smrg    case FcMatchScan:
6662c393a42Smrg	prev = &config->substScan;
6672c393a42Smrg	break;
6682c393a42Smrg    default:
6692c393a42Smrg	return FcFalse;
6702c393a42Smrg    }
6712c393a42Smrg    subst = (FcSubst *) malloc (sizeof (FcSubst));
6722c393a42Smrg    if (!subst)
6732c393a42Smrg	return FcFalse;
6742c393a42Smrg    for (; *prev; prev = &(*prev)->next);
6752c393a42Smrg    *prev = subst;
6762c393a42Smrg    subst->next = 0;
6772c393a42Smrg    subst->test = test;
6782c393a42Smrg    subst->edit = edit;
6792c393a42Smrg    num = 0;
6802c393a42Smrg    for (t = test; t; t = t->next)
6812c393a42Smrg    {
6822c393a42Smrg	if (t->kind == FcMatchDefault)
6832c393a42Smrg	    t->kind = kind;
6842c393a42Smrg	num++;
6852c393a42Smrg    }
6862c393a42Smrg    if (config->maxObjects < num)
6872c393a42Smrg	config->maxObjects = num;
6882c393a42Smrg    if (FcDebug () & FC_DBG_EDIT)
6892c393a42Smrg    {
6902c393a42Smrg	printf ("Add Subst ");
6912c393a42Smrg	FcSubstPrint (subst);
6922c393a42Smrg    }
6932c393a42Smrg    return FcTrue;
6942c393a42Smrg}
6952c393a42Smrg
6962c393a42Smrgtypedef struct _FcSubState {
6972c393a42Smrg    FcPatternElt   *elt;
6982c393a42Smrg    FcValueList    *value;
6992c393a42Smrg} FcSubState;
7002c393a42Smrg
7012c393a42Smrgstatic FcValue
702c9710b42SmrgFcConfigPromote (FcValue v, FcValue u, FcValuePromotionBuffer *buf)
7032c393a42Smrg{
7042c393a42Smrg    if (v.type == FcTypeInteger)
7052c393a42Smrg    {
7062c393a42Smrg	v.type = FcTypeDouble;
7072c393a42Smrg	v.u.d = (double) v.u.i;
7082c393a42Smrg    }
7092c393a42Smrg    else if (v.type == FcTypeVoid && u.type == FcTypeMatrix)
7102c393a42Smrg    {
7112c393a42Smrg	v.u.m = &FcIdentityMatrix;
7122c393a42Smrg	v.type = FcTypeMatrix;
7132c393a42Smrg    }
714c9710b42Smrg    else if (buf && v.type == FcTypeString && u.type == FcTypeLangSet)
7152c393a42Smrg    {
716c9710b42Smrg	v.u.l = FcLangSetPromote (v.u.s, buf);
7172c393a42Smrg	v.type = FcTypeLangSet;
7182c393a42Smrg    }
7192c393a42Smrg    return v;
7202c393a42Smrg}
7212c393a42Smrg
7222c393a42SmrgFcBool
7232c393a42SmrgFcConfigCompareValue (const FcValue	*left_o,
724ca08ab68Smrg		      FcOp		op_,
7252c393a42Smrg		      const FcValue	*right_o)
7262c393a42Smrg{
7272c393a42Smrg    FcValue	left = FcValueCanonicalize(left_o);
7282c393a42Smrg    FcValue	right = FcValueCanonicalize(right_o);
7292c393a42Smrg    FcBool	ret = FcFalse;
730ca08ab68Smrg    FcOp	op = FC_OP_GET_OP (op_);
731ca08ab68Smrg    int		flags = FC_OP_GET_FLAGS (op_);
732c9710b42Smrg    FcValuePromotionBuffer buf1, buf2;
733ca08ab68Smrg
734c9710b42Smrg    left = FcConfigPromote (left, right, &buf1);
735c9710b42Smrg    right = FcConfigPromote (right, left, &buf2);
736ca08ab68Smrg    if (left.type == right.type)
7372c393a42Smrg    {
7382c393a42Smrg	switch (left.type) {
7392c393a42Smrg	case FcTypeInteger:
7402c393a42Smrg	    break;	/* FcConfigPromote prevents this from happening */
7412c393a42Smrg	case FcTypeDouble:
742c9710b42Smrg	    switch ((int) op) {
7432c393a42Smrg	    case FcOpEqual:
7442c393a42Smrg	    case FcOpContains:
7452c393a42Smrg	    case FcOpListing:
7462c393a42Smrg		ret = left.u.d == right.u.d;
7472c393a42Smrg		break;
7482c393a42Smrg	    case FcOpNotEqual:
7492c393a42Smrg	    case FcOpNotContains:
7502c393a42Smrg		ret = left.u.d != right.u.d;
7512c393a42Smrg		break;
752ca08ab68Smrg	    case FcOpLess:
7532c393a42Smrg		ret = left.u.d < right.u.d;
7542c393a42Smrg		break;
755ca08ab68Smrg	    case FcOpLessEqual:
7562c393a42Smrg		ret = left.u.d <= right.u.d;
7572c393a42Smrg		break;
758ca08ab68Smrg	    case FcOpMore:
7592c393a42Smrg		ret = left.u.d > right.u.d;
7602c393a42Smrg		break;
761ca08ab68Smrg	    case FcOpMoreEqual:
7622c393a42Smrg		ret = left.u.d >= right.u.d;
7632c393a42Smrg		break;
7642c393a42Smrg	    default:
7652c393a42Smrg		break;
7662c393a42Smrg	    }
7672c393a42Smrg	    break;
7682c393a42Smrg	case FcTypeBool:
769c9710b42Smrg	    switch ((int) op) {
770ca08ab68Smrg	    case FcOpEqual:
7712c393a42Smrg	    case FcOpContains:
7722c393a42Smrg	    case FcOpListing:
7732c393a42Smrg		ret = left.u.b == right.u.b;
7742c393a42Smrg		break;
7752c393a42Smrg	    case FcOpNotEqual:
7762c393a42Smrg	    case FcOpNotContains:
7772c393a42Smrg		ret = left.u.b != right.u.b;
7782c393a42Smrg		break;
7792c393a42Smrg	    default:
7802c393a42Smrg		break;
7812c393a42Smrg	    }
7822c393a42Smrg	    break;
7832c393a42Smrg	case FcTypeString:
784c9710b42Smrg	    switch ((int) op) {
785ca08ab68Smrg	    case FcOpEqual:
7862c393a42Smrg	    case FcOpListing:
787ca08ab68Smrg		if (flags & FcOpFlagIgnoreBlanks)
788ca08ab68Smrg		    ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) == 0;
789ca08ab68Smrg		else
790ca08ab68Smrg		    ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0;
7912c393a42Smrg		break;
7922c393a42Smrg	    case FcOpContains:
7932c393a42Smrg		ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0;
7942c393a42Smrg		break;
7952c393a42Smrg	    case FcOpNotEqual:
796ca08ab68Smrg		if (flags & FcOpFlagIgnoreBlanks)
797ca08ab68Smrg		    ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) != 0;
798ca08ab68Smrg		else
799ca08ab68Smrg		    ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0;
8002c393a42Smrg		break;
8012c393a42Smrg	    case FcOpNotContains:
8022c393a42Smrg		ret = FcStrStrIgnoreCase (left.u.s, right.u.s) == 0;
8032c393a42Smrg		break;
8042c393a42Smrg	    default:
8052c393a42Smrg		break;
8062c393a42Smrg	    }
8072c393a42Smrg	    break;
8082c393a42Smrg	case FcTypeMatrix:
809c9710b42Smrg	    switch ((int) op) {
8102c393a42Smrg	    case FcOpEqual:
8112c393a42Smrg	    case FcOpContains:
8122c393a42Smrg	    case FcOpListing:
8132c393a42Smrg		ret = FcMatrixEqual (left.u.m, right.u.m);
8142c393a42Smrg		break;
8152c393a42Smrg	    case FcOpNotEqual:
8162c393a42Smrg	    case FcOpNotContains:
8172c393a42Smrg		ret = !FcMatrixEqual (left.u.m, right.u.m);
8182c393a42Smrg		break;
8192c393a42Smrg	    default:
8202c393a42Smrg		break;
8212c393a42Smrg	    }
8222c393a42Smrg	    break;
8232c393a42Smrg	case FcTypeCharSet:
824c9710b42Smrg	    switch ((int) op) {
8252c393a42Smrg	    case FcOpContains:
8262c393a42Smrg	    case FcOpListing:
8272c393a42Smrg		/* left contains right if right is a subset of left */
8282c393a42Smrg		ret = FcCharSetIsSubset (right.u.c, left.u.c);
8292c393a42Smrg		break;
8302c393a42Smrg	    case FcOpNotContains:
8312c393a42Smrg		/* left contains right if right is a subset of left */
8322c393a42Smrg		ret = !FcCharSetIsSubset (right.u.c, left.u.c);
8332c393a42Smrg		break;
8342c393a42Smrg	    case FcOpEqual:
8352c393a42Smrg		ret = FcCharSetEqual (left.u.c, right.u.c);
8362c393a42Smrg		break;
8372c393a42Smrg	    case FcOpNotEqual:
8382c393a42Smrg		ret = !FcCharSetEqual (left.u.c, right.u.c);
8392c393a42Smrg		break;
8402c393a42Smrg	    default:
8412c393a42Smrg		break;
8422c393a42Smrg	    }
8432c393a42Smrg	    break;
8442c393a42Smrg	case FcTypeLangSet:
845c9710b42Smrg	    switch ((int) op) {
8462c393a42Smrg	    case FcOpContains:
8472c393a42Smrg	    case FcOpListing:
8482c393a42Smrg		ret = FcLangSetContains (left.u.l, right.u.l);
8492c393a42Smrg		break;
8502c393a42Smrg	    case FcOpNotContains:
8512c393a42Smrg		ret = !FcLangSetContains (left.u.l, right.u.l);
8522c393a42Smrg		break;
8532c393a42Smrg	    case FcOpEqual:
8542c393a42Smrg		ret = FcLangSetEqual (left.u.l, right.u.l);
8552c393a42Smrg		break;
8562c393a42Smrg	    case FcOpNotEqual:
8572c393a42Smrg		ret = !FcLangSetEqual (left.u.l, right.u.l);
8582c393a42Smrg		break;
8592c393a42Smrg	    default:
8602c393a42Smrg		break;
8612c393a42Smrg	    }
8622c393a42Smrg	    break;
8632c393a42Smrg	case FcTypeVoid:
864c9710b42Smrg	    switch ((int) op) {
8652c393a42Smrg	    case FcOpEqual:
8662c393a42Smrg	    case FcOpContains:
8672c393a42Smrg	    case FcOpListing:
8682c393a42Smrg		ret = FcTrue;
8692c393a42Smrg		break;
8702c393a42Smrg	    default:
8712c393a42Smrg		break;
8722c393a42Smrg	    }
8732c393a42Smrg	    break;
8742c393a42Smrg	case FcTypeFTFace:
875c9710b42Smrg	    switch ((int) op) {
8762c393a42Smrg	    case FcOpEqual:
8772c393a42Smrg	    case FcOpContains:
8782c393a42Smrg	    case FcOpListing:
8792c393a42Smrg		ret = left.u.f == right.u.f;
8802c393a42Smrg		break;
8812c393a42Smrg	    case FcOpNotEqual:
8822c393a42Smrg	    case FcOpNotContains:
8832c393a42Smrg		ret = left.u.f != right.u.f;
8842c393a42Smrg		break;
8852c393a42Smrg	    default:
8862c393a42Smrg		break;
8872c393a42Smrg	    }
8882c393a42Smrg	    break;
8892c393a42Smrg	}
8902c393a42Smrg    }
8912c393a42Smrg    else
8922c393a42Smrg    {
8932c393a42Smrg	if (op == FcOpNotEqual || op == FcOpNotContains)
8942c393a42Smrg	    ret = FcTrue;
8952c393a42Smrg    }
8962c393a42Smrg    return ret;
8972c393a42Smrg}
8982c393a42Smrg
8992c393a42Smrg
9002c393a42Smrg#define _FcDoubleFloor(d)	((int) (d))
9012c393a42Smrg#define _FcDoubleCeil(d)	((double) (int) (d) == (d) ? (int) (d) : (int) ((d) + 1))
9022c393a42Smrg#define FcDoubleFloor(d)	((d) >= 0 ? _FcDoubleFloor(d) : -_FcDoubleCeil(-(d)))
9032c393a42Smrg#define FcDoubleCeil(d)		((d) >= 0 ? _FcDoubleCeil(d) : -_FcDoubleFloor(-(d)))
9042c393a42Smrg#define FcDoubleRound(d)	FcDoubleFloor ((d) + 0.5)
9052c393a42Smrg#define FcDoubleTrunc(d)	((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d)))
9062c393a42Smrg
9072c393a42Smrgstatic FcValue
908c9710b42SmrgFcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e)
9092c393a42Smrg{
9102c393a42Smrg    FcValue	v, vl, vr;
9112c393a42Smrg    FcMatrix	*m;
9122c393a42Smrg    FcChar8     *str;
913ca08ab68Smrg    FcOp	op = FC_OP_GET_OP (e->op);
914ca08ab68Smrg
915c9710b42Smrg    switch ((int) op) {
9162c393a42Smrg    case FcOpInteger:
9172c393a42Smrg	v.type = FcTypeInteger;
9182c393a42Smrg	v.u.i = e->u.ival;
9192c393a42Smrg	break;
9202c393a42Smrg    case FcOpDouble:
9212c393a42Smrg	v.type = FcTypeDouble;
9222c393a42Smrg	v.u.d = e->u.dval;
9232c393a42Smrg	break;
9242c393a42Smrg    case FcOpString:
9252c393a42Smrg	v.type = FcTypeString;
926a6844aabSmrg	v.u.s = e->u.sval;
927a6844aabSmrg	v = FcValueSave (v);
9282c393a42Smrg	break;
9292c393a42Smrg    case FcOpMatrix:
930c9710b42Smrg	{
931c9710b42Smrg	  FcMatrix m;
932c9710b42Smrg	  FcValue xx, xy, yx, yy;
933c9710b42Smrg	  v.type = FcTypeMatrix;
934c9710b42Smrg	  xx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xx), v, NULL);
935c9710b42Smrg	  xy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xy), v, NULL);
936c9710b42Smrg	  yx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yx), v, NULL);
937c9710b42Smrg	  yy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yy), v, NULL);
938c9710b42Smrg	  if (xx.type == FcTypeDouble && xy.type == FcTypeDouble &&
939c9710b42Smrg	      yx.type == FcTypeDouble && yy.type == FcTypeDouble)
940c9710b42Smrg	  {
941c9710b42Smrg	    m.xx = xx.u.d;
942c9710b42Smrg	    m.xy = xy.u.d;
943c9710b42Smrg	    m.yx = yx.u.d;
944c9710b42Smrg	    m.yy = yy.u.d;
945c9710b42Smrg	    v.u.m = &m;
946c9710b42Smrg	  }
947c9710b42Smrg	  else
948c9710b42Smrg	    v.type = FcTypeVoid;
949c9710b42Smrg	  v = FcValueSave (v);
950c9710b42Smrg	}
9512c393a42Smrg	break;
9522c393a42Smrg    case FcOpCharSet:
9532c393a42Smrg	v.type = FcTypeCharSet;
9542c393a42Smrg	v.u.c = e->u.cval;
9552c393a42Smrg	v = FcValueSave (v);
9562c393a42Smrg	break;
957ca08ab68Smrg    case FcOpLangSet:
958ca08ab68Smrg	v.type = FcTypeLangSet;
959ca08ab68Smrg	v.u.l = e->u.lval;
960ca08ab68Smrg	v = FcValueSave (v);
961ca08ab68Smrg	break;
9622c393a42Smrg    case FcOpBool:
9632c393a42Smrg	v.type = FcTypeBool;
9642c393a42Smrg	v.u.b = e->u.bval;
9652c393a42Smrg	break;
9662c393a42Smrg    case FcOpField:
967c9710b42Smrg	if (kind == FcMatchFont && e->u.name.kind == FcMatchPattern)
968c9710b42Smrg	{
969c9710b42Smrg	    if (FcResultMatch != FcPatternObjectGet (p_pat, e->u.name.object, 0, &v))
970c9710b42Smrg		v.type = FcTypeVoid;
971c9710b42Smrg	}
972c9710b42Smrg	else if (kind == FcMatchPattern && e->u.name.kind == FcMatchFont)
973c9710b42Smrg	{
974c9710b42Smrg	    fprintf (stderr,
975c9710b42Smrg                    "Fontconfig warning: <name> tag has target=\"font\" in a <match target=\"pattern\">.\n");
9762c393a42Smrg	    v.type = FcTypeVoid;
977c9710b42Smrg	}
978c9710b42Smrg	else
979c9710b42Smrg	{
980c9710b42Smrg	    if (FcResultMatch != FcPatternObjectGet (p, e->u.name.object, 0, &v))
981c9710b42Smrg		v.type = FcTypeVoid;
982c9710b42Smrg	}
9832c393a42Smrg	v = FcValueSave (v);
9842c393a42Smrg	break;
9852c393a42Smrg    case FcOpConst:
9862c393a42Smrg	if (FcNameConstant (e->u.constant, &v.u.i))
9872c393a42Smrg	    v.type = FcTypeInteger;
9882c393a42Smrg	else
9892c393a42Smrg	    v.type = FcTypeVoid;
9902c393a42Smrg	break;
9912c393a42Smrg    case FcOpQuest:
992c9710b42Smrg	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
9932c393a42Smrg	if (vl.type == FcTypeBool)
9942c393a42Smrg	{
9952c393a42Smrg	    if (vl.u.b)
996c9710b42Smrg		v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.left);
9972c393a42Smrg	    else
998c9710b42Smrg		v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.right);
9992c393a42Smrg	}
10002c393a42Smrg	else
10012c393a42Smrg	    v.type = FcTypeVoid;
10022c393a42Smrg	FcValueDestroy (vl);
10032c393a42Smrg	break;
10042c393a42Smrg    case FcOpEqual:
10052c393a42Smrg    case FcOpNotEqual:
10062c393a42Smrg    case FcOpLess:
10072c393a42Smrg    case FcOpLessEqual:
10082c393a42Smrg    case FcOpMore:
10092c393a42Smrg    case FcOpMoreEqual:
10102c393a42Smrg    case FcOpContains:
10112c393a42Smrg    case FcOpNotContains:
10122c393a42Smrg    case FcOpListing:
1013c9710b42Smrg	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1014c9710b42Smrg	vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right);
10152c393a42Smrg	v.type = FcTypeBool;
10162c393a42Smrg	v.u.b = FcConfigCompareValue (&vl, e->op, &vr);
10172c393a42Smrg	FcValueDestroy (vl);
10182c393a42Smrg	FcValueDestroy (vr);
10192c393a42Smrg	break;
10202c393a42Smrg    case FcOpOr:
10212c393a42Smrg    case FcOpAnd:
10222c393a42Smrg    case FcOpPlus:
10232c393a42Smrg    case FcOpMinus:
10242c393a42Smrg    case FcOpTimes:
10252c393a42Smrg    case FcOpDivide:
1026c9710b42Smrg	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1027c9710b42Smrg	vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right);
1028c9710b42Smrg	vl = FcConfigPromote (vl, vr, NULL);
1029c9710b42Smrg	vr = FcConfigPromote (vr, vl, NULL);
10302c393a42Smrg	if (vl.type == vr.type)
10312c393a42Smrg	{
1032c9710b42Smrg	    switch ((int) vl.type) {
10332c393a42Smrg	    case FcTypeDouble:
1034c9710b42Smrg		switch ((int) op) {
1035ca08ab68Smrg		case FcOpPlus:
10362c393a42Smrg		    v.type = FcTypeDouble;
1037ca08ab68Smrg		    v.u.d = vl.u.d + vr.u.d;
10382c393a42Smrg		    break;
10392c393a42Smrg		case FcOpMinus:
10402c393a42Smrg		    v.type = FcTypeDouble;
1041ca08ab68Smrg		    v.u.d = vl.u.d - vr.u.d;
10422c393a42Smrg		    break;
10432c393a42Smrg		case FcOpTimes:
10442c393a42Smrg		    v.type = FcTypeDouble;
1045ca08ab68Smrg		    v.u.d = vl.u.d * vr.u.d;
10462c393a42Smrg		    break;
10472c393a42Smrg		case FcOpDivide:
10482c393a42Smrg		    v.type = FcTypeDouble;
1049ca08ab68Smrg		    v.u.d = vl.u.d / vr.u.d;
10502c393a42Smrg		    break;
10512c393a42Smrg		default:
1052ca08ab68Smrg		    v.type = FcTypeVoid;
10532c393a42Smrg		    break;
10542c393a42Smrg		}
10552c393a42Smrg		if (v.type == FcTypeDouble &&
10562c393a42Smrg		    v.u.d == (double) (int) v.u.d)
10572c393a42Smrg		{
10582c393a42Smrg		    v.type = FcTypeInteger;
10592c393a42Smrg		    v.u.i = (int) v.u.d;
10602c393a42Smrg		}
10612c393a42Smrg		break;
10622c393a42Smrg	    case FcTypeBool:
1063c9710b42Smrg		switch ((int) op) {
10642c393a42Smrg		case FcOpOr:
10652c393a42Smrg		    v.type = FcTypeBool;
10662c393a42Smrg		    v.u.b = vl.u.b || vr.u.b;
10672c393a42Smrg		    break;
10682c393a42Smrg		case FcOpAnd:
10692c393a42Smrg		    v.type = FcTypeBool;
10702c393a42Smrg		    v.u.b = vl.u.b && vr.u.b;
10712c393a42Smrg		    break;
10722c393a42Smrg		default:
1073ca08ab68Smrg		    v.type = FcTypeVoid;
10742c393a42Smrg		    break;
10752c393a42Smrg		}
10762c393a42Smrg		break;
10772c393a42Smrg	    case FcTypeString:
1078c9710b42Smrg		switch ((int) op) {
10792c393a42Smrg		case FcOpPlus:
10802c393a42Smrg		    v.type = FcTypeString;
10812c393a42Smrg		    str = FcStrPlus (vl.u.s, vr.u.s);
1082c9710b42Smrg		    v.u.s = FcStrdup (str);
10832c393a42Smrg		    FcStrFree (str);
1084ca08ab68Smrg
10852c393a42Smrg		    if (!v.u.s)
10862c393a42Smrg			v.type = FcTypeVoid;
10872c393a42Smrg		    break;
10882c393a42Smrg		default:
10892c393a42Smrg		    v.type = FcTypeVoid;
10902c393a42Smrg		    break;
10912c393a42Smrg		}
10922c393a42Smrg		break;
10932c393a42Smrg	    case FcTypeMatrix:
1094c9710b42Smrg		switch ((int) op) {
10952c393a42Smrg		case FcOpTimes:
10962c393a42Smrg		    v.type = FcTypeMatrix;
10972c393a42Smrg		    m = malloc (sizeof (FcMatrix));
10982c393a42Smrg		    if (m)
10992c393a42Smrg		    {
11002c393a42Smrg			FcMatrixMultiply (m, vl.u.m, vr.u.m);
11012c393a42Smrg			v.u.m = m;
11022c393a42Smrg		    }
11032c393a42Smrg		    else
11042c393a42Smrg		    {
11052c393a42Smrg			v.type = FcTypeVoid;
11062c393a42Smrg		    }
11072c393a42Smrg		    break;
11082c393a42Smrg		default:
11092c393a42Smrg		    v.type = FcTypeVoid;
11102c393a42Smrg		    break;
11112c393a42Smrg		}
11122c393a42Smrg		break;
1113ca08ab68Smrg	    case FcTypeCharSet:
1114c9710b42Smrg		switch ((int) op) {
1115ca08ab68Smrg		case FcOpPlus:
1116ca08ab68Smrg		    v.type = FcTypeCharSet;
1117ca08ab68Smrg		    v.u.c = FcCharSetUnion (vl.u.c, vr.u.c);
1118ca08ab68Smrg		    if (!v.u.c)
1119ca08ab68Smrg			v.type = FcTypeVoid;
1120ca08ab68Smrg		    break;
1121ca08ab68Smrg		case FcOpMinus:
1122ca08ab68Smrg		    v.type = FcTypeCharSet;
1123ca08ab68Smrg		    v.u.c = FcCharSetSubtract (vl.u.c, vr.u.c);
1124ca08ab68Smrg		    if (!v.u.c)
1125ca08ab68Smrg			v.type = FcTypeVoid;
1126ca08ab68Smrg		    break;
1127ca08ab68Smrg		default:
1128ca08ab68Smrg		    v.type = FcTypeVoid;
1129ca08ab68Smrg		    break;
1130ca08ab68Smrg		}
1131ca08ab68Smrg		break;
1132ca08ab68Smrg	    case FcTypeLangSet:
1133c9710b42Smrg		switch ((int) op) {
1134ca08ab68Smrg		case FcOpPlus:
1135ca08ab68Smrg		    v.type = FcTypeLangSet;
1136ca08ab68Smrg		    v.u.l = FcLangSetUnion (vl.u.l, vr.u.l);
1137ca08ab68Smrg		    if (!v.u.l)
1138ca08ab68Smrg			v.type = FcTypeVoid;
1139ca08ab68Smrg		    break;
1140ca08ab68Smrg		case FcOpMinus:
1141ca08ab68Smrg		    v.type = FcTypeLangSet;
1142ca08ab68Smrg		    v.u.l = FcLangSetSubtract (vl.u.l, vr.u.l);
1143ca08ab68Smrg		    if (!v.u.l)
1144ca08ab68Smrg			v.type = FcTypeVoid;
1145ca08ab68Smrg		    break;
1146ca08ab68Smrg		default:
1147ca08ab68Smrg		    v.type = FcTypeVoid;
1148ca08ab68Smrg		    break;
1149ca08ab68Smrg		}
1150ca08ab68Smrg		break;
11512c393a42Smrg	    default:
11522c393a42Smrg		v.type = FcTypeVoid;
11532c393a42Smrg		break;
11542c393a42Smrg	    }
11552c393a42Smrg	}
11562c393a42Smrg	else
11572c393a42Smrg	    v.type = FcTypeVoid;
11582c393a42Smrg	FcValueDestroy (vl);
11592c393a42Smrg	FcValueDestroy (vr);
11602c393a42Smrg	break;
11612c393a42Smrg    case FcOpNot:
1162c9710b42Smrg	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1163c9710b42Smrg	switch ((int) vl.type) {
11642c393a42Smrg	case FcTypeBool:
11652c393a42Smrg	    v.type = FcTypeBool;
11662c393a42Smrg	    v.u.b = !vl.u.b;
11672c393a42Smrg	    break;
11682c393a42Smrg	default:
11692c393a42Smrg	    v.type = FcTypeVoid;
11702c393a42Smrg	    break;
11712c393a42Smrg	}
11722c393a42Smrg	FcValueDestroy (vl);
11732c393a42Smrg	break;
11742c393a42Smrg    case FcOpFloor:
1175c9710b42Smrg	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1176c9710b42Smrg	switch ((int) vl.type) {
11772c393a42Smrg	case FcTypeInteger:
11782c393a42Smrg	    v = vl;
11792c393a42Smrg	    break;
11802c393a42Smrg	case FcTypeDouble:
11812c393a42Smrg	    v.type = FcTypeInteger;
11822c393a42Smrg	    v.u.i = FcDoubleFloor (vl.u.d);
11832c393a42Smrg	    break;
11842c393a42Smrg	default:
11852c393a42Smrg	    v.type = FcTypeVoid;
11862c393a42Smrg	    break;
11872c393a42Smrg	}
11882c393a42Smrg	FcValueDestroy (vl);
11892c393a42Smrg	break;
11902c393a42Smrg    case FcOpCeil:
1191c9710b42Smrg	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1192c9710b42Smrg	switch ((int) vl.type) {
11932c393a42Smrg	case FcTypeInteger:
11942c393a42Smrg	    v = vl;
11952c393a42Smrg	    break;
11962c393a42Smrg	case FcTypeDouble:
11972c393a42Smrg	    v.type = FcTypeInteger;
11982c393a42Smrg	    v.u.i = FcDoubleCeil (vl.u.d);
11992c393a42Smrg	    break;
12002c393a42Smrg	default:
12012c393a42Smrg	    v.type = FcTypeVoid;
12022c393a42Smrg	    break;
12032c393a42Smrg	}
12042c393a42Smrg	FcValueDestroy (vl);
12052c393a42Smrg	break;
12062c393a42Smrg    case FcOpRound:
1207c9710b42Smrg	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1208c9710b42Smrg	switch ((int) vl.type) {
12092c393a42Smrg	case FcTypeInteger:
12102c393a42Smrg	    v = vl;
12112c393a42Smrg	    break;
12122c393a42Smrg	case FcTypeDouble:
12132c393a42Smrg	    v.type = FcTypeInteger;
12142c393a42Smrg	    v.u.i = FcDoubleRound (vl.u.d);
12152c393a42Smrg	    break;
12162c393a42Smrg	default:
12172c393a42Smrg	    v.type = FcTypeVoid;
12182c393a42Smrg	    break;
12192c393a42Smrg	}
12202c393a42Smrg	FcValueDestroy (vl);
12212c393a42Smrg	break;
12222c393a42Smrg    case FcOpTrunc:
1223c9710b42Smrg	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1224c9710b42Smrg	switch ((int) vl.type) {
12252c393a42Smrg	case FcTypeInteger:
12262c393a42Smrg	    v = vl;
12272c393a42Smrg	    break;
12282c393a42Smrg	case FcTypeDouble:
12292c393a42Smrg	    v.type = FcTypeInteger;
12302c393a42Smrg	    v.u.i = FcDoubleTrunc (vl.u.d);
12312c393a42Smrg	    break;
12322c393a42Smrg	default:
12332c393a42Smrg	    v.type = FcTypeVoid;
12342c393a42Smrg	    break;
12352c393a42Smrg	}
12362c393a42Smrg	FcValueDestroy (vl);
12372c393a42Smrg	break;
12382c393a42Smrg    default:
12392c393a42Smrg	v.type = FcTypeVoid;
12402c393a42Smrg	break;
12412c393a42Smrg    }
12422c393a42Smrg    return v;
12432c393a42Smrg}
12442c393a42Smrg
12452c393a42Smrgstatic FcValueList *
12462c393a42SmrgFcConfigMatchValueList (FcPattern	*p,
1247c9710b42Smrg			FcPattern	*p_pat,
1248c9710b42Smrg			FcMatchKind      kind,
12492c393a42Smrg			FcTest		*t,
12502c393a42Smrg			FcValueList	*values)
12512c393a42Smrg{
12522c393a42Smrg    FcValueList	    *ret = 0;
12532c393a42Smrg    FcExpr	    *e = t->expr;
12542c393a42Smrg    FcValue	    value;
12552c393a42Smrg    FcValueList	    *v;
1256ca08ab68Smrg
12572c393a42Smrg    while (e)
12582c393a42Smrg    {
12592c393a42Smrg	/* Compute the value of the match expression */
1260ca08ab68Smrg	if (FC_OP_GET_OP (e->op) == FcOpComma)
12612c393a42Smrg	{
1262c9710b42Smrg	    value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
12632c393a42Smrg	    e = e->u.tree.right;
12642c393a42Smrg	}
12652c393a42Smrg	else
12662c393a42Smrg	{
1267c9710b42Smrg	    value = FcConfigEvaluate (p, p_pat, kind, e);
12682c393a42Smrg	    e = 0;
12692c393a42Smrg	}
12702c393a42Smrg
12712c393a42Smrg	for (v = values; v; v = FcValueListNext(v))
12722c393a42Smrg	{
12732c393a42Smrg	    /* Compare the pattern value to the match expression value */
12742c393a42Smrg	    if (FcConfigCompareValue (&v->value, t->op, &value))
12752c393a42Smrg	    {
12762c393a42Smrg		if (!ret)
12772c393a42Smrg		    ret = v;
12782c393a42Smrg	    }
12792c393a42Smrg	    else
12802c393a42Smrg	    {
12812c393a42Smrg		if (t->qual == FcQualAll)
12822c393a42Smrg		{
12832c393a42Smrg		    ret = 0;
12842c393a42Smrg		    break;
12852c393a42Smrg		}
12862c393a42Smrg	    }
12872c393a42Smrg	}
12882c393a42Smrg	FcValueDestroy (value);
12892c393a42Smrg    }
12902c393a42Smrg    return ret;
12912c393a42Smrg}
12922c393a42Smrg
12932c393a42Smrgstatic FcValueList *
1294c9710b42SmrgFcConfigValues (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e, FcValueBinding binding)
12952c393a42Smrg{
12962c393a42Smrg    FcValueList	*l;
1297ca08ab68Smrg
12982c393a42Smrg    if (!e)
12992c393a42Smrg	return 0;
13002c393a42Smrg    l = (FcValueList *) malloc (sizeof (FcValueList));
13012c393a42Smrg    if (!l)
13022c393a42Smrg	return 0;
1303ca08ab68Smrg    if (FC_OP_GET_OP (e->op) == FcOpComma)
13042c393a42Smrg    {
1305c9710b42Smrg	l->value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1306c9710b42Smrg	l->next = FcConfigValues (p, p_pat, kind, e->u.tree.right, binding);
13072c393a42Smrg    }
13082c393a42Smrg    else
13092c393a42Smrg    {
1310c9710b42Smrg	l->value = FcConfigEvaluate (p, p_pat, kind, e);
13112c393a42Smrg	l->next = NULL;
13122c393a42Smrg    }
13132c393a42Smrg    l->binding = binding;
13142c393a42Smrg    if (l->value.type == FcTypeVoid)
13152c393a42Smrg    {
13162c393a42Smrg	FcValueList  *next = FcValueListNext(l);
13172c393a42Smrg
13182c393a42Smrg	free (l);
13192c393a42Smrg	l = next;
13202c393a42Smrg    }
13212c393a42Smrg
13222c393a42Smrg    return l;
13232c393a42Smrg}
13242c393a42Smrg
13252c393a42Smrgstatic FcBool
13262c393a42SmrgFcConfigAdd (FcValueListPtr *head,
13272c393a42Smrg	     FcValueList    *position,
13282c393a42Smrg	     FcBool	    append,
1329c9710b42Smrg	     FcValueList    *new,
1330c9710b42Smrg	     FcObject        object)
13312c393a42Smrg{
1332c9710b42Smrg    FcValueListPtr  *prev, l, last, v;
13332c393a42Smrg    FcValueBinding  sameBinding;
1334ca08ab68Smrg
1335c9710b42Smrg    /*
1336c9710b42Smrg     * Make sure the stored type is valid for built-in objects
1337c9710b42Smrg     */
1338c9710b42Smrg    for (l = new; l != NULL; l = FcValueListNext (l))
1339c9710b42Smrg    {
1340c9710b42Smrg	if (!FcObjectValidType (object, l->value.type))
1341c9710b42Smrg	{
1342c9710b42Smrg	    fprintf (stderr,
1343c9710b42Smrg		     "Fontconfig warning: FcPattern object %s does not accept value", FcObjectName (object));
1344c9710b42Smrg	    FcValuePrintFile (stderr, l->value);
1345c9710b42Smrg	    fprintf (stderr, "\n");
1346c9710b42Smrg
1347c9710b42Smrg	    if (FcDebug () & FC_DBG_EDIT)
1348c9710b42Smrg	    {
1349c9710b42Smrg		printf ("Not adding\n");
1350c9710b42Smrg	    }
1351c9710b42Smrg
1352c9710b42Smrg	    return FcFalse;
1353c9710b42Smrg	}
1354c9710b42Smrg    }
1355c9710b42Smrg
13562c393a42Smrg    if (position)
13572c393a42Smrg	sameBinding = position->binding;
13582c393a42Smrg    else
13592c393a42Smrg	sameBinding = FcValueBindingWeak;
13602c393a42Smrg    for (v = new; v != NULL; v = FcValueListNext(v))
13612c393a42Smrg	if (v->binding == FcValueBindingSame)
13622c393a42Smrg	    v->binding = sameBinding;
13632c393a42Smrg    if (append)
13642c393a42Smrg    {
13652c393a42Smrg	if (position)
13662c393a42Smrg	    prev = &position->next;
13672c393a42Smrg	else
1368ca08ab68Smrg	    for (prev = head; *prev != NULL;
13692c393a42Smrg		 prev = &(*prev)->next)
13702c393a42Smrg		;
13712c393a42Smrg    }
13722c393a42Smrg    else
13732c393a42Smrg    {
13742c393a42Smrg	if (position)
13752c393a42Smrg	{
1376ca08ab68Smrg	    for (prev = head; *prev != NULL;
13772c393a42Smrg		 prev = &(*prev)->next)
13782c393a42Smrg	    {
13792c393a42Smrg		if (*prev == position)
13802c393a42Smrg		    break;
13812c393a42Smrg	    }
13822c393a42Smrg	}
13832c393a42Smrg	else
13842c393a42Smrg	    prev = head;
13852c393a42Smrg
13862c393a42Smrg	if (FcDebug () & FC_DBG_EDIT)
13872c393a42Smrg	{
13882c393a42Smrg	    if (*prev == NULL)
13892c393a42Smrg		printf ("position not on list\n");
13902c393a42Smrg	}
13912c393a42Smrg    }
13922c393a42Smrg
13932c393a42Smrg    if (FcDebug () & FC_DBG_EDIT)
13942c393a42Smrg    {
13952c393a42Smrg	printf ("%s list before ", append ? "Append" : "Prepend");
1396ca08ab68Smrg	FcValueListPrintWithPosition (*head, *prev);
13972c393a42Smrg	printf ("\n");
13982c393a42Smrg    }
1399ca08ab68Smrg
14002c393a42Smrg    if (new)
14012c393a42Smrg    {
14022c393a42Smrg	last = new;
14032c393a42Smrg	while (last->next != NULL)
14042c393a42Smrg	    last = last->next;
1405ca08ab68Smrg
14062c393a42Smrg	last->next = *prev;
14072c393a42Smrg	*prev = new;
14082c393a42Smrg    }
1409ca08ab68Smrg
14102c393a42Smrg    if (FcDebug () & FC_DBG_EDIT)
14112c393a42Smrg    {
14122c393a42Smrg	printf ("%s list after ", append ? "Append" : "Prepend");
14132c393a42Smrg	FcValueListPrint (*head);
14142c393a42Smrg	printf ("\n");
14152c393a42Smrg    }
1416ca08ab68Smrg
14172c393a42Smrg    return FcTrue;
14182c393a42Smrg}
14192c393a42Smrg
14202c393a42Smrgstatic void
14212c393a42SmrgFcConfigDel (FcValueListPtr *head,
14222c393a42Smrg	     FcValueList    *position)
14232c393a42Smrg{
14242c393a42Smrg    FcValueListPtr *prev;
14252c393a42Smrg
14262c393a42Smrg    for (prev = head; *prev != NULL; prev = &(*prev)->next)
14272c393a42Smrg    {
14282c393a42Smrg	if (*prev == position)
14292c393a42Smrg	{
14302c393a42Smrg	    *prev = position->next;
14312c393a42Smrg	    position->next = NULL;
14322c393a42Smrg	    FcValueListDestroy (position);
14332c393a42Smrg	    break;
14342c393a42Smrg	}
14352c393a42Smrg    }
14362c393a42Smrg}
14372c393a42Smrg
14382c393a42Smrgstatic void
14392c393a42SmrgFcConfigPatternAdd (FcPattern	*p,
14402c393a42Smrg		    FcObject	object,
14412c393a42Smrg		    FcValueList	*list,
14422c393a42Smrg		    FcBool	append)
14432c393a42Smrg{
14442c393a42Smrg    if (list)
14452c393a42Smrg    {
14462c393a42Smrg	FcPatternElt    *e = FcPatternObjectInsertElt (p, object);
1447ca08ab68Smrg
14482c393a42Smrg	if (!e)
14492c393a42Smrg	    return;
1450c9710b42Smrg	FcConfigAdd (&e->values, 0, append, list, object);
14512c393a42Smrg    }
14522c393a42Smrg}
14532c393a42Smrg
14542c393a42Smrg/*
14552c393a42Smrg * Delete all values associated with a field
14562c393a42Smrg */
14572c393a42Smrgstatic void
14582c393a42SmrgFcConfigPatternDel (FcPattern	*p,
14592c393a42Smrg		    FcObject	object)
14602c393a42Smrg{
14612c393a42Smrg    FcPatternElt    *e = FcPatternObjectFindElt (p, object);
14622c393a42Smrg    if (!e)
14632c393a42Smrg	return;
14642c393a42Smrg    while (e->values != NULL)
14652c393a42Smrg	FcConfigDel (&e->values, e->values);
14662c393a42Smrg}
14672c393a42Smrg
14682c393a42Smrgstatic void
14692c393a42SmrgFcConfigPatternCanon (FcPattern	    *p,
14702c393a42Smrg		      FcObject	    object)
14712c393a42Smrg{
14722c393a42Smrg    FcPatternElt    *e = FcPatternObjectFindElt (p, object);
14732c393a42Smrg    if (!e)
14742c393a42Smrg	return;
14752c393a42Smrg    if (e->values == NULL)
14762c393a42Smrg	FcPatternObjectDel (p, object);
14772c393a42Smrg}
14782c393a42Smrg
14792c393a42SmrgFcBool
14802c393a42SmrgFcConfigSubstituteWithPat (FcConfig    *config,
14812c393a42Smrg			   FcPattern   *p,
14822c393a42Smrg			   FcPattern   *p_pat,
14832c393a42Smrg			   FcMatchKind kind)
14842c393a42Smrg{
1485c9710b42Smrg    FcValue v;
14862c393a42Smrg    FcSubst	    *s;
14872c393a42Smrg    FcSubState	    *st;
14882c393a42Smrg    int		    i;
14892c393a42Smrg    FcTest	    *t;
14902c393a42Smrg    FcEdit	    *e;
14912c393a42Smrg    FcValueList	    *l;
14922c393a42Smrg    FcPattern	    *m;
1493ca08ab68Smrg    FcStrSet	    *strs;
14942c393a42Smrg
14952c393a42Smrg    if (!config)
14962c393a42Smrg    {
14972c393a42Smrg	config = FcConfigGetCurrent ();
14982c393a42Smrg	if (!config)
14992c393a42Smrg	    return FcFalse;
15002c393a42Smrg    }
15012c393a42Smrg
15022c393a42Smrg    switch (kind) {
15032c393a42Smrg    case FcMatchPattern:
15042c393a42Smrg	s = config->substPattern;
1505ca08ab68Smrg	strs = FcGetDefaultLangs ();
1506ca08ab68Smrg	if (strs)
1507ca08ab68Smrg	{
1508ca08ab68Smrg	    FcStrList *l = FcStrListCreate (strs);
1509ca08ab68Smrg	    FcChar8 *lang;
1510ca08ab68Smrg	    FcValue v;
1511ca08ab68Smrg
1512ca08ab68Smrg	    FcStrSetDestroy (strs);
1513ca08ab68Smrg	    while (l && (lang = FcStrListNext (l)))
1514ca08ab68Smrg	    {
1515ca08ab68Smrg		v.type = FcTypeString;
1516ca08ab68Smrg		v.u.s = lang;
1517ca08ab68Smrg		FcPatternObjectAddWithBinding (p, FC_LANG_OBJECT, v, FcValueBindingWeak, FcTrue);
1518ca08ab68Smrg	    }
1519ca08ab68Smrg	    FcStrListDone (l);
1520ca08ab68Smrg	}
1521c9710b42Smrg	if (FcPatternObjectGet (p, FC_PRGNAME_OBJECT, 0, &v) == FcResultNoMatch)
1522c9710b42Smrg	{
1523c9710b42Smrg	    FcChar8 *prgname = FcGetPrgname ();
1524c9710b42Smrg	    if (prgname)
1525c9710b42Smrg		FcPatternObjectAddString (p, FC_PRGNAME_OBJECT, prgname);
1526c9710b42Smrg	}
15272c393a42Smrg	break;
15282c393a42Smrg    case FcMatchFont:
15292c393a42Smrg	s = config->substFont;
15302c393a42Smrg	break;
15312c393a42Smrg    case FcMatchScan:
15322c393a42Smrg	s = config->substScan;
15332c393a42Smrg	break;
15342c393a42Smrg    default:
15352c393a42Smrg	return FcFalse;
15362c393a42Smrg    }
15372c393a42Smrg
15382c393a42Smrg    st = (FcSubState *) malloc (config->maxObjects * sizeof (FcSubState));
15392c393a42Smrg    if (!st && config->maxObjects)
15402c393a42Smrg	return FcFalse;
15412c393a42Smrg
15422c393a42Smrg    if (FcDebug () & FC_DBG_EDIT)
15432c393a42Smrg    {
15442c393a42Smrg	printf ("FcConfigSubstitute ");
15452c393a42Smrg	FcPatternPrint (p);
15462c393a42Smrg    }
15472c393a42Smrg    for (; s; s = s->next)
15482c393a42Smrg    {
15492c393a42Smrg	/*
15502c393a42Smrg	 * Check the tests to see if
15512c393a42Smrg	 * they all match the pattern
15522c393a42Smrg	 */
15532c393a42Smrg	for (t = s->test, i = 0; t; t = t->next, i++)
15542c393a42Smrg	{
15552c393a42Smrg	    if (FcDebug () & FC_DBG_EDIT)
15562c393a42Smrg	    {
15572c393a42Smrg		printf ("FcConfigSubstitute test ");
15582c393a42Smrg		FcTestPrint (t);
15592c393a42Smrg	    }
15602c393a42Smrg	    st[i].elt = 0;
15612c393a42Smrg	    if (kind == FcMatchFont && t->kind == FcMatchPattern)
15622c393a42Smrg		m = p_pat;
15632c393a42Smrg	    else
15642c393a42Smrg		m = p;
15652c393a42Smrg	    if (m)
15662c393a42Smrg		st[i].elt = FcPatternObjectFindElt (m, t->object);
15672c393a42Smrg	    else
15682c393a42Smrg		st[i].elt = 0;
15692c393a42Smrg	    /*
15702c393a42Smrg	     * If there's no such field in the font,
15712c393a42Smrg	     * then FcQualAll matches while FcQualAny does not
15722c393a42Smrg	     */
15732c393a42Smrg	    if (!st[i].elt)
15742c393a42Smrg	    {
15752c393a42Smrg		if (t->qual == FcQualAll)
15762c393a42Smrg		{
15772c393a42Smrg		    st[i].value = 0;
15782c393a42Smrg		    continue;
15792c393a42Smrg		}
15802c393a42Smrg		else
15812c393a42Smrg		    break;
15822c393a42Smrg	    }
15832c393a42Smrg	    /*
15842c393a42Smrg	     * Check to see if there is a match, mark the location
15852c393a42Smrg	     * to apply match-relative edits
15862c393a42Smrg	     */
1587c9710b42Smrg	    st[i].value = FcConfigMatchValueList (m, p_pat, kind, t, st[i].elt->values);
15882c393a42Smrg	    if (!st[i].value)
15892c393a42Smrg		break;
15902c393a42Smrg	    if (t->qual == FcQualFirst && st[i].value != st[i].elt->values)
15912c393a42Smrg		break;
15922c393a42Smrg	    if (t->qual == FcQualNotFirst && st[i].value == st[i].elt->values)
15932c393a42Smrg		break;
15942c393a42Smrg	}
15952c393a42Smrg	if (t)
15962c393a42Smrg	{
15972c393a42Smrg	    if (FcDebug () & FC_DBG_EDIT)
15982c393a42Smrg		printf ("No match\n");
15992c393a42Smrg	    continue;
16002c393a42Smrg	}
16012c393a42Smrg	if (FcDebug () & FC_DBG_EDIT)
16022c393a42Smrg	{
16032c393a42Smrg	    printf ("Substitute ");
16042c393a42Smrg	    FcSubstPrint (s);
16052c393a42Smrg	}
16062c393a42Smrg	for (e = s->edit; e; e = e->next)
16072c393a42Smrg	{
16082c393a42Smrg	    /*
16092c393a42Smrg	     * Evaluate the list of expressions
16102c393a42Smrg	     */
1611c9710b42Smrg	    l = FcConfigValues (p, p_pat,kind,  e->expr, e->binding);
16122c393a42Smrg	    /*
16132c393a42Smrg	     * Locate any test associated with this field, skipping
16142c393a42Smrg	     * tests associated with the pattern when substituting in
16152c393a42Smrg	     * the font
16162c393a42Smrg	     */
16172c393a42Smrg	    for (t = s->test, i = 0; t; t = t->next, i++)
16182c393a42Smrg	    {
16192c393a42Smrg		if ((t->kind == FcMatchFont || kind == FcMatchPattern) &&
16202c393a42Smrg		    t->object == e->object)
16212c393a42Smrg		{
1622ca08ab68Smrg		    /*
16232c393a42Smrg		     * KLUDGE - the pattern may have been reallocated or
16242c393a42Smrg		     * things may have been inserted or deleted above
16252c393a42Smrg		     * this element by other edits.  Go back and find
16262c393a42Smrg		     * the element again
16272c393a42Smrg		     */
16282c393a42Smrg		    if (e != s->edit && st[i].elt)
16292c393a42Smrg			st[i].elt = FcPatternObjectFindElt (p, t->object);
16302c393a42Smrg		    if (!st[i].elt)
16312c393a42Smrg			t = 0;
16322c393a42Smrg		    break;
16332c393a42Smrg		}
16342c393a42Smrg	    }
1635ca08ab68Smrg	    switch (FC_OP_GET_OP (e->op)) {
16362c393a42Smrg	    case FcOpAssign:
16372c393a42Smrg		/*
16382c393a42Smrg		 * If there was a test, then replace the matched
16392c393a42Smrg		 * value with the new list of values
16402c393a42Smrg		 */
16412c393a42Smrg		if (t)
16422c393a42Smrg		{
16432c393a42Smrg		    FcValueList	*thisValue = st[i].value;
16442c393a42Smrg		    FcValueList	*nextValue = thisValue;
1645ca08ab68Smrg
16462c393a42Smrg		    /*
16472c393a42Smrg		     * Append the new list of values after the current value
16482c393a42Smrg		     */
1649c9710b42Smrg		    FcConfigAdd (&st[i].elt->values, thisValue, FcTrue, l, e->object);
16502c393a42Smrg		    /*
16512c393a42Smrg		     * Delete the marked value
16522c393a42Smrg		     */
16532c393a42Smrg                    if (thisValue)
16542c393a42Smrg			FcConfigDel (&st[i].elt->values, thisValue);
16552c393a42Smrg		    /*
16562c393a42Smrg		     * Adjust any pointers into the value list to ensure
16572c393a42Smrg		     * future edits occur at the same place
16582c393a42Smrg		     */
16592c393a42Smrg		    for (t = s->test, i = 0; t; t = t->next, i++)
16602c393a42Smrg		    {
16612c393a42Smrg			if (st[i].value == thisValue)
16622c393a42Smrg			    st[i].value = nextValue;
16632c393a42Smrg		    }
16642c393a42Smrg		    break;
16652c393a42Smrg		}
16662c393a42Smrg		/* fall through ... */
16672c393a42Smrg	    case FcOpAssignReplace:
16682c393a42Smrg		/*
16692c393a42Smrg		 * Delete all of the values and insert
16702c393a42Smrg		 * the new set
16712c393a42Smrg		 */
16722c393a42Smrg		FcConfigPatternDel (p, e->object);
16732c393a42Smrg		FcConfigPatternAdd (p, e->object, l, FcTrue);
16742c393a42Smrg		/*
16752c393a42Smrg		 * Adjust any pointers into the value list as they no
16762c393a42Smrg		 * longer point to anything valid
16772c393a42Smrg		 */
16782c393a42Smrg		if (t)
16792c393a42Smrg		{
16802c393a42Smrg		    FcPatternElt    *thisElt = st[i].elt;
16812c393a42Smrg		    for (t = s->test, i = 0; t; t = t->next, i++)
16822c393a42Smrg		    {
16832c393a42Smrg			if (st[i].elt == thisElt)
16842c393a42Smrg			    st[i].value = 0;
16852c393a42Smrg		    }
16862c393a42Smrg		}
16872c393a42Smrg		break;
16882c393a42Smrg	    case FcOpPrepend:
16892c393a42Smrg		if (t)
16902c393a42Smrg		{
1691c9710b42Smrg		    FcConfigAdd (&st[i].elt->values, st[i].value, FcFalse, l, e->object);
16922c393a42Smrg		    break;
16932c393a42Smrg		}
16942c393a42Smrg		/* fall through ... */
16952c393a42Smrg	    case FcOpPrependFirst:
16962c393a42Smrg		FcConfigPatternAdd (p, e->object, l, FcFalse);
16972c393a42Smrg		break;
16982c393a42Smrg	    case FcOpAppend:
16992c393a42Smrg		if (t)
17002c393a42Smrg		{
1701c9710b42Smrg		    FcConfigAdd (&st[i].elt->values, st[i].value, FcTrue, l, e->object);
17022c393a42Smrg		    break;
17032c393a42Smrg		}
17042c393a42Smrg		/* fall through ... */
17052c393a42Smrg	    case FcOpAppendLast:
17062c393a42Smrg		FcConfigPatternAdd (p, e->object, l, FcTrue);
17072c393a42Smrg		break;
1708c9710b42Smrg	    case FcOpDelete:
1709c9710b42Smrg		if (t)
1710c9710b42Smrg		{
1711c9710b42Smrg		    FcConfigDel (&st[i].elt->values, st[i].value);
1712c9710b42Smrg		    break;
1713c9710b42Smrg		}
1714c9710b42Smrg		/* fall through ... */
1715c9710b42Smrg	    case FcOpDeleteAll:
1716c9710b42Smrg		FcConfigPatternDel (p, e->object);
1717c9710b42Smrg		break;
17182c393a42Smrg	    default:
17192c393a42Smrg                FcValueListDestroy (l);
17202c393a42Smrg		break;
17212c393a42Smrg	    }
17222c393a42Smrg	}
17232c393a42Smrg	/*
17242c393a42Smrg	 * Now go through the pattern and eliminate
17252c393a42Smrg	 * any properties without data
17262c393a42Smrg	 */
17272c393a42Smrg	for (e = s->edit; e; e = e->next)
17282c393a42Smrg	    FcConfigPatternCanon (p, e->object);
17292c393a42Smrg
17302c393a42Smrg	if (FcDebug () & FC_DBG_EDIT)
17312c393a42Smrg	{
17322c393a42Smrg	    printf ("FcConfigSubstitute edit");
17332c393a42Smrg	    FcPatternPrint (p);
17342c393a42Smrg	}
17352c393a42Smrg    }
17362c393a42Smrg    free (st);
17372c393a42Smrg    if (FcDebug () & FC_DBG_EDIT)
17382c393a42Smrg    {
17392c393a42Smrg	printf ("FcConfigSubstitute done");
17402c393a42Smrg	FcPatternPrint (p);
17412c393a42Smrg    }
17422c393a42Smrg    return FcTrue;
17432c393a42Smrg}
17442c393a42Smrg
17452c393a42SmrgFcBool
17462c393a42SmrgFcConfigSubstitute (FcConfig	*config,
17472c393a42Smrg		    FcPattern	*p,
17482c393a42Smrg		    FcMatchKind	kind)
17492c393a42Smrg{
17502c393a42Smrg    return FcConfigSubstituteWithPat (config, p, 0, kind);
17512c393a42Smrg}
17522c393a42Smrg
17532c393a42Smrg#if defined (_WIN32)
17542c393a42Smrg
1755c9710b42Smrgstatic FcChar8 fontconfig_path[1000] = ""; /* MT-dontcare */
17562c393a42Smrg
17572c393a42Smrg#  if (defined (PIC) || defined (DLL_EXPORT))
17582c393a42Smrg
1759c9710b42SmrgBOOL WINAPI
1760c9710b42SmrgDllMain (HINSTANCE hinstDLL,
1761c9710b42Smrg	 DWORD     fdwReason,
1762c9710b42Smrg	 LPVOID    lpvReserved);
1763c9710b42Smrg
17642c393a42SmrgBOOL WINAPI
17652c393a42SmrgDllMain (HINSTANCE hinstDLL,
17662c393a42Smrg	 DWORD     fdwReason,
17672c393a42Smrg	 LPVOID    lpvReserved)
17682c393a42Smrg{
17692c393a42Smrg  FcChar8 *p;
17702c393a42Smrg
17712c393a42Smrg  switch (fdwReason) {
17722c393a42Smrg  case DLL_PROCESS_ATTACH:
1773ca08ab68Smrg      if (!GetModuleFileName ((HMODULE) hinstDLL, (LPCH) fontconfig_path,
17742c393a42Smrg			      sizeof (fontconfig_path)))
17752c393a42Smrg	  break;
17762c393a42Smrg
17772c393a42Smrg      /* If the fontconfig DLL is in a "bin" or "lib" subfolder,
17782c393a42Smrg       * assume it's a Unix-style installation tree, and use
17792c393a42Smrg       * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the
17802c393a42Smrg       * folder where the DLL is as FONTCONFIG_PATH.
17812c393a42Smrg       */
1782ca08ab68Smrg      p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\');
17832c393a42Smrg      if (p)
17842c393a42Smrg      {
17852c393a42Smrg	  *p = '\0';
1786ca08ab68Smrg	  p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\');
1787ca08ab68Smrg	  if (p && (FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "bin") == 0 ||
1788ca08ab68Smrg		    FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "lib") == 0))
17892c393a42Smrg	      *p = '\0';
1790ca08ab68Smrg	  strcat ((char *) fontconfig_path, "\\etc\\fonts");
17912c393a42Smrg      }
17922c393a42Smrg      else
17932c393a42Smrg          fontconfig_path[0] = '\0';
1794ca08ab68Smrg
17952c393a42Smrg      break;
17962c393a42Smrg  }
17972c393a42Smrg
17982c393a42Smrg  return TRUE;
17992c393a42Smrg}
18002c393a42Smrg
18012c393a42Smrg#  endif /* !PIC */
18022c393a42Smrg
18032c393a42Smrg#undef FONTCONFIG_PATH
18042c393a42Smrg#define FONTCONFIG_PATH fontconfig_path
18052c393a42Smrg
18062c393a42Smrg#endif /* !_WIN32 */
18072c393a42Smrg
18082c393a42Smrg#ifndef FONTCONFIG_FILE
18092c393a42Smrg#define FONTCONFIG_FILE	"fonts.conf"
18102c393a42Smrg#endif
18112c393a42Smrg
18122c393a42Smrgstatic FcChar8 *
18132c393a42SmrgFcConfigFileExists (const FcChar8 *dir, const FcChar8 *file)
18142c393a42Smrg{
18152c393a42Smrg    FcChar8    *path;
1816ca08ab68Smrg    int         size, osize;
18172c393a42Smrg
18182c393a42Smrg    if (!dir)
18192c393a42Smrg	dir = (FcChar8 *) "";
1820ca08ab68Smrg
1821ca08ab68Smrg    osize = strlen ((char *) dir) + 1 + strlen ((char *) file) + 1;
1822ca08ab68Smrg    /*
1823ca08ab68Smrg     * workaround valgrind warning because glibc takes advantage of how it knows memory is
1824ca08ab68Smrg     * allocated to implement strlen by reading in groups of 4
1825ca08ab68Smrg     */
1826ca08ab68Smrg    size = (osize + 3) & ~3;
1827ca08ab68Smrg
1828ca08ab68Smrg    path = malloc (size);
18292c393a42Smrg    if (!path)
18302c393a42Smrg	return 0;
18312c393a42Smrg
18322c393a42Smrg    strcpy ((char *) path, (const char *) dir);
18332c393a42Smrg    /* make sure there's a single separator */
18342c393a42Smrg#ifdef _WIN32
18352c393a42Smrg    if ((!path[0] || (path[strlen((char *) path)-1] != '/' &&
18362c393a42Smrg		      path[strlen((char *) path)-1] != '\\')) &&
18372c393a42Smrg	!(file[0] == '/' ||
18382c393a42Smrg	  file[0] == '\\' ||
18392c393a42Smrg	  (isalpha (file[0]) && file[1] == ':' && (file[2] == '/' || file[2] == '\\'))))
18402c393a42Smrg	strcat ((char *) path, "\\");
18412c393a42Smrg#else
18422c393a42Smrg    if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/')
18432c393a42Smrg	strcat ((char *) path, "/");
1844c9710b42Smrg    else
1845c9710b42Smrg	osize--;
18462c393a42Smrg#endif
18472c393a42Smrg    strcat ((char *) path, (char *) file);
18482c393a42Smrg
18492c393a42Smrg    if (access ((char *) path, R_OK) == 0)
18502c393a42Smrg	return path;
1851ca08ab68Smrg
18522c393a42Smrg    FcStrFree (path);
1853ca08ab68Smrg
18542c393a42Smrg    return 0;
18552c393a42Smrg}
18562c393a42Smrg
18572c393a42Smrgstatic FcChar8 **
18582c393a42SmrgFcConfigGetPath (void)
18592c393a42Smrg{
18602c393a42Smrg    FcChar8    **path;
18612c393a42Smrg    FcChar8    *env, *e, *colon;
18622c393a42Smrg    FcChar8    *dir;
18632c393a42Smrg    int	    npath;
18642c393a42Smrg    int	    i;
18652c393a42Smrg
18662c393a42Smrg    npath = 2;	/* default dir + null */
18672c393a42Smrg    env = (FcChar8 *) getenv ("FONTCONFIG_PATH");
18682c393a42Smrg    if (env)
18692c393a42Smrg    {
18702c393a42Smrg	e = env;
18712c393a42Smrg	npath++;
18722c393a42Smrg	while (*e)
18732c393a42Smrg	    if (*e++ == FC_SEARCH_PATH_SEPARATOR)
18742c393a42Smrg		npath++;
18752c393a42Smrg    }
18762c393a42Smrg    path = calloc (npath, sizeof (FcChar8 *));
18772c393a42Smrg    if (!path)
18782c393a42Smrg	goto bail0;
18792c393a42Smrg    i = 0;
18802c393a42Smrg
18812c393a42Smrg    if (env)
18822c393a42Smrg    {
18832c393a42Smrg	e = env;
1884ca08ab68Smrg	while (*e)
18852c393a42Smrg	{
18862c393a42Smrg	    colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR);
18872c393a42Smrg	    if (!colon)
18882c393a42Smrg		colon = e + strlen ((char *) e);
18892c393a42Smrg	    path[i] = malloc (colon - e + 1);
18902c393a42Smrg	    if (!path[i])
18912c393a42Smrg		goto bail1;
18922c393a42Smrg	    strncpy ((char *) path[i], (const char *) e, colon - e);
18932c393a42Smrg	    path[i][colon - e] = '\0';
18942c393a42Smrg	    if (*colon)
18952c393a42Smrg		e = colon + 1;
18962c393a42Smrg	    else
18972c393a42Smrg		e = colon;
18982c393a42Smrg	    i++;
18992c393a42Smrg	}
19002c393a42Smrg    }
1901ca08ab68Smrg
19022c393a42Smrg#ifdef _WIN32
19032c393a42Smrg	if (fontconfig_path[0] == '\0')
19042c393a42Smrg	{
1905a6844aabSmrg		char *p;
1906ca08ab68Smrg		if(!GetModuleFileName(NULL, (LPCH) fontconfig_path, sizeof(fontconfig_path)))
19072c393a42Smrg			goto bail1;
1908ca08ab68Smrg		p = strrchr ((const char *) fontconfig_path, '\\');
19092c393a42Smrg		if (p) *p = '\0';
1910ca08ab68Smrg		strcat ((char *) fontconfig_path, "\\fonts");
19112c393a42Smrg	}
19122c393a42Smrg#endif
19132c393a42Smrg    dir = (FcChar8 *) FONTCONFIG_PATH;
19142c393a42Smrg    path[i] = malloc (strlen ((char *) dir) + 1);
19152c393a42Smrg    if (!path[i])
19162c393a42Smrg	goto bail1;
19172c393a42Smrg    strcpy ((char *) path[i], (const char *) dir);
19182c393a42Smrg    return path;
19192c393a42Smrg
19202c393a42Smrgbail1:
19212c393a42Smrg    for (i = 0; path[i]; i++)
19222c393a42Smrg	free (path[i]);
19232c393a42Smrg    free (path);
19242c393a42Smrgbail0:
19252c393a42Smrg    return 0;
19262c393a42Smrg}
19272c393a42Smrg
19282c393a42Smrgstatic void
19292c393a42SmrgFcConfigFreePath (FcChar8 **path)
19302c393a42Smrg{
19312c393a42Smrg    FcChar8    **p;
19322c393a42Smrg
19332c393a42Smrg    for (p = path; *p; p++)
19342c393a42Smrg	free (*p);
19352c393a42Smrg    free (path);
19362c393a42Smrg}
19372c393a42Smrg
1938c9710b42Smrgstatic FcBool	_FcConfigHomeEnabled = FcTrue; /* MT-goodenough */
19392c393a42Smrg
19402c393a42SmrgFcChar8 *
19412c393a42SmrgFcConfigHome (void)
19422c393a42Smrg{
19432c393a42Smrg    if (_FcConfigHomeEnabled)
19442c393a42Smrg    {
19452c393a42Smrg        char *home = getenv ("HOME");
19462c393a42Smrg
19472c393a42Smrg#ifdef _WIN32
19482c393a42Smrg	if (home == NULL)
19492c393a42Smrg	    home = getenv ("USERPROFILE");
19502c393a42Smrg#endif
19512c393a42Smrg
19522c393a42Smrg	return (FcChar8 *) home;
19532c393a42Smrg    }
19542c393a42Smrg    return 0;
19552c393a42Smrg}
19562c393a42Smrg
1957ca08ab68SmrgFcChar8 *
1958ca08ab68SmrgFcConfigXdgCacheHome (void)
1959ca08ab68Smrg{
1960ca08ab68Smrg    const char *env = getenv ("XDG_CACHE_HOME");
1961ca08ab68Smrg    FcChar8 *ret = NULL;
1962ca08ab68Smrg
1963ca08ab68Smrg    if (env)
1964ca08ab68Smrg	ret = FcStrCopy ((const FcChar8 *)env);
1965ca08ab68Smrg    else
1966ca08ab68Smrg    {
1967ca08ab68Smrg	const FcChar8 *home = FcConfigHome ();
1968ca08ab68Smrg	size_t len = home ? strlen ((const char *)home) : 0;
1969ca08ab68Smrg
1970ca08ab68Smrg	ret = malloc (len + 7 + 1);
1971ca08ab68Smrg	if (ret)
1972ca08ab68Smrg	{
1973ca08ab68Smrg	    memcpy (ret, home, len);
1974ca08ab68Smrg	    memcpy (&ret[len], FC_DIR_SEPARATOR_S ".cache", 7);
1975ca08ab68Smrg	    ret[len + 7] = 0;
1976ca08ab68Smrg	}
1977ca08ab68Smrg    }
1978ca08ab68Smrg
1979ca08ab68Smrg    return ret;
1980ca08ab68Smrg}
1981ca08ab68Smrg
1982ca08ab68SmrgFcChar8 *
1983ca08ab68SmrgFcConfigXdgConfigHome (void)
1984ca08ab68Smrg{
1985ca08ab68Smrg    const char *env = getenv ("XDG_CONFIG_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 + 8 + 1);
1996ca08ab68Smrg	if (ret)
1997ca08ab68Smrg	{
1998ca08ab68Smrg	    memcpy (ret, home, len);
1999ca08ab68Smrg	    memcpy (&ret[len], FC_DIR_SEPARATOR_S ".config", 8);
2000ca08ab68Smrg	    ret[len + 8] = 0;
2001ca08ab68Smrg	}
2002ca08ab68Smrg    }
2003ca08ab68Smrg
2004ca08ab68Smrg    return ret;
2005ca08ab68Smrg}
2006ca08ab68Smrg
2007ca08ab68SmrgFcChar8 *
2008ca08ab68SmrgFcConfigXdgDataHome (void)
2009ca08ab68Smrg{
2010ca08ab68Smrg    const char *env = getenv ("XDG_DATA_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 + 13 + 1);
2021ca08ab68Smrg	if (ret)
2022ca08ab68Smrg	{
2023ca08ab68Smrg	    memcpy (ret, home, len);
2024ca08ab68Smrg	    memcpy (&ret[len], FC_DIR_SEPARATOR_S ".local" FC_DIR_SEPARATOR_S "share", 13);
2025ca08ab68Smrg	    ret[len + 13] = 0;
2026ca08ab68Smrg	}
2027ca08ab68Smrg    }
2028ca08ab68Smrg
2029ca08ab68Smrg    return ret;
2030ca08ab68Smrg}
2031ca08ab68Smrg
20322c393a42SmrgFcBool
20332c393a42SmrgFcConfigEnableHome (FcBool enable)
20342c393a42Smrg{
20352c393a42Smrg    FcBool  prev = _FcConfigHomeEnabled;
20362c393a42Smrg    _FcConfigHomeEnabled = enable;
20372c393a42Smrg    return prev;
20382c393a42Smrg}
20392c393a42Smrg
20402c393a42SmrgFcChar8 *
20412c393a42SmrgFcConfigFilename (const FcChar8 *url)
20422c393a42Smrg{
20432c393a42Smrg    FcChar8    *file, *dir, **path, **p;
20442c393a42Smrg
20452c393a42Smrg    if (!url || !*url)
20462c393a42Smrg    {
20472c393a42Smrg	url = (FcChar8 *) getenv ("FONTCONFIG_FILE");
20482c393a42Smrg	if (!url)
20492c393a42Smrg	    url = (FcChar8 *) FONTCONFIG_FILE;
20502c393a42Smrg    }
20512c393a42Smrg    file = 0;
20522c393a42Smrg
20532c393a42Smrg#ifdef _WIN32
20542c393a42Smrg    if (isalpha (*url) &&
20552c393a42Smrg	url[1] == ':' &&
20562c393a42Smrg	(url[2] == '/' || url[2] == '\\'))
20572c393a42Smrg	goto absolute_path;
20582c393a42Smrg#endif
20592c393a42Smrg
20602c393a42Smrg    switch (*url) {
20612c393a42Smrg    case '~':
20622c393a42Smrg	dir = FcConfigHome ();
20632c393a42Smrg	if (dir)
20642c393a42Smrg	    file = FcConfigFileExists (dir, url + 1);
20652c393a42Smrg	else
20662c393a42Smrg	    file = 0;
20672c393a42Smrg	break;
20682c393a42Smrg#ifdef _WIN32
20692c393a42Smrg    case '\\':
20702c393a42Smrg    absolute_path:
20712c393a42Smrg#endif
20722c393a42Smrg    case '/':
20732c393a42Smrg	file = FcConfigFileExists (0, url);
20742c393a42Smrg	break;
20752c393a42Smrg    default:
20762c393a42Smrg	path = FcConfigGetPath ();
20772c393a42Smrg	if (!path)
2078ca08ab68Smrg	    return NULL;
20792c393a42Smrg	for (p = path; *p; p++)
20802c393a42Smrg	{
20812c393a42Smrg	    file = FcConfigFileExists (*p, url);
20822c393a42Smrg	    if (file)
20832c393a42Smrg		break;
20842c393a42Smrg	}
20852c393a42Smrg	FcConfigFreePath (path);
20862c393a42Smrg	break;
20872c393a42Smrg    }
2088ca08ab68Smrg
20892c393a42Smrg    return file;
20902c393a42Smrg}
20912c393a42Smrg
20922c393a42Smrg/*
20932c393a42Smrg * Manage the application-specific fonts
20942c393a42Smrg */
20952c393a42Smrg
20962c393a42SmrgFcBool
20972c393a42SmrgFcConfigAppFontAddFile (FcConfig    *config,
20982c393a42Smrg			const FcChar8  *file)
20992c393a42Smrg{
21002c393a42Smrg    FcFontSet	*set;
21012c393a42Smrg    FcStrSet	*subdirs;
21022c393a42Smrg    FcStrList	*sublist;
21032c393a42Smrg    FcChar8	*subdir;
21042c393a42Smrg
21052c393a42Smrg    if (!config)
21062c393a42Smrg    {
21072c393a42Smrg	config = FcConfigGetCurrent ();
21082c393a42Smrg	if (!config)
21092c393a42Smrg	    return FcFalse;
21102c393a42Smrg    }
21112c393a42Smrg
21122c393a42Smrg    subdirs = FcStrSetCreate ();
21132c393a42Smrg    if (!subdirs)
21142c393a42Smrg	return FcFalse;
2115ca08ab68Smrg
21162c393a42Smrg    set = FcConfigGetFonts (config, FcSetApplication);
21172c393a42Smrg    if (!set)
21182c393a42Smrg    {
21192c393a42Smrg	set = FcFontSetCreate ();
21202c393a42Smrg	if (!set)
21212c393a42Smrg	{
21222c393a42Smrg	    FcStrSetDestroy (subdirs);
21232c393a42Smrg	    return FcFalse;
21242c393a42Smrg	}
21252c393a42Smrg	FcConfigSetFonts (config, set, FcSetApplication);
21262c393a42Smrg    }
21272c393a42Smrg
21282c393a42Smrg    if (!FcFileScanConfig (set, subdirs, config->blanks, file, config))
21292c393a42Smrg    {
21302c393a42Smrg	FcStrSetDestroy (subdirs);
21312c393a42Smrg	return FcFalse;
21322c393a42Smrg    }
21332c393a42Smrg    if ((sublist = FcStrListCreate (subdirs)))
21342c393a42Smrg    {
21352c393a42Smrg	while ((subdir = FcStrListNext (sublist)))
21362c393a42Smrg	{
21372c393a42Smrg	    FcConfigAppFontAddDir (config, subdir);
21382c393a42Smrg	}
21392c393a42Smrg	FcStrListDone (sublist);
21402c393a42Smrg    }
21412c393a42Smrg    FcStrSetDestroy (subdirs);
21422c393a42Smrg    return FcTrue;
21432c393a42Smrg}
21442c393a42Smrg
21452c393a42SmrgFcBool
21462c393a42SmrgFcConfigAppFontAddDir (FcConfig	    *config,
21472c393a42Smrg		       const FcChar8   *dir)
21482c393a42Smrg{
21492c393a42Smrg    FcFontSet	*set;
21502c393a42Smrg    FcStrSet	*dirs;
2151ca08ab68Smrg
21522c393a42Smrg    if (!config)
21532c393a42Smrg    {
21542c393a42Smrg	config = FcConfigGetCurrent ();
21552c393a42Smrg	if (!config)
21562c393a42Smrg	    return FcFalse;
21572c393a42Smrg    }
21582c393a42Smrg
21592c393a42Smrg    dirs = FcStrSetCreate ();
21602c393a42Smrg    if (!dirs)
21612c393a42Smrg	return FcFalse;
2162ca08ab68Smrg
21632c393a42Smrg    set = FcConfigGetFonts (config, FcSetApplication);
21642c393a42Smrg    if (!set)
21652c393a42Smrg    {
21662c393a42Smrg	set = FcFontSetCreate ();
21672c393a42Smrg	if (!set)
21682c393a42Smrg	{
21692c393a42Smrg	    FcStrSetDestroy (dirs);
21702c393a42Smrg	    return FcFalse;
21712c393a42Smrg	}
21722c393a42Smrg	FcConfigSetFonts (config, set, FcSetApplication);
21732c393a42Smrg    }
2174ca08ab68Smrg
21752c393a42Smrg    FcStrSetAddFilename (dirs, dir);
2176ca08ab68Smrg
21772c393a42Smrg    if (!FcConfigAddDirList (config, FcSetApplication, dirs))
21782c393a42Smrg    {
21792c393a42Smrg	FcStrSetDestroy (dirs);
21802c393a42Smrg	return FcFalse;
21812c393a42Smrg    }
21822c393a42Smrg    FcStrSetDestroy (dirs);
21832c393a42Smrg    return FcTrue;
21842c393a42Smrg}
21852c393a42Smrg
21862c393a42Smrgvoid
21872c393a42SmrgFcConfigAppFontClear (FcConfig	    *config)
21882c393a42Smrg{
21892c393a42Smrg    if (!config)
21902c393a42Smrg    {
21912c393a42Smrg	config = FcConfigGetCurrent ();
21922c393a42Smrg	if (!config)
21932c393a42Smrg	    return;
21942c393a42Smrg    }
21952c393a42Smrg
21962c393a42Smrg    FcConfigSetFonts (config, 0, FcSetApplication);
21972c393a42Smrg}
21982c393a42Smrg
21992c393a42Smrg/*
22002c393a42Smrg * Manage filename-based font source selectors
22012c393a42Smrg */
22022c393a42Smrg
22032c393a42SmrgFcBool
22042c393a42SmrgFcConfigGlobAdd (FcConfig	*config,
22052c393a42Smrg		 const FcChar8  *glob,
22062c393a42Smrg		 FcBool		accept)
22072c393a42Smrg{
22082c393a42Smrg    FcStrSet	*set = accept ? config->acceptGlobs : config->rejectGlobs;
22092c393a42Smrg
22102c393a42Smrg    return FcStrSetAdd (set, glob);
22112c393a42Smrg}
22122c393a42Smrg
22132c393a42Smrgstatic FcBool
22142c393a42SmrgFcConfigGlobsMatch (const FcStrSet	*globs,
22152c393a42Smrg		    const FcChar8	*string)
22162c393a42Smrg{
22172c393a42Smrg    int	i;
22182c393a42Smrg
22192c393a42Smrg    for (i = 0; i < globs->num; i++)
2220c9710b42Smrg	if (FcStrGlobMatch (globs->strs[i], string))
22212c393a42Smrg	    return FcTrue;
22222c393a42Smrg    return FcFalse;
22232c393a42Smrg}
22242c393a42Smrg
22252c393a42SmrgFcBool
22262c393a42SmrgFcConfigAcceptFilename (FcConfig	*config,
22272c393a42Smrg			const FcChar8	*filename)
22282c393a42Smrg{
22292c393a42Smrg    if (FcConfigGlobsMatch (config->acceptGlobs, filename))
22302c393a42Smrg	return FcTrue;
22312c393a42Smrg    if (FcConfigGlobsMatch (config->rejectGlobs, filename))
22322c393a42Smrg	return FcFalse;
22332c393a42Smrg    return FcTrue;
22342c393a42Smrg}
22352c393a42Smrg
22362c393a42Smrg/*
22372c393a42Smrg * Manage font-pattern based font source selectors
22382c393a42Smrg */
22392c393a42Smrg
22402c393a42SmrgFcBool
22412c393a42SmrgFcConfigPatternsAdd (FcConfig	*config,
22422c393a42Smrg		     FcPattern	*pattern,
22432c393a42Smrg		     FcBool	accept)
22442c393a42Smrg{
22452c393a42Smrg    FcFontSet	*set = accept ? config->acceptPatterns : config->rejectPatterns;
22462c393a42Smrg
22472c393a42Smrg    return FcFontSetAdd (set, pattern);
22482c393a42Smrg}
22492c393a42Smrg
22502c393a42Smrgstatic FcBool
22512c393a42SmrgFcConfigPatternsMatch (const FcFontSet	*patterns,
22522c393a42Smrg		       const FcPattern	*font)
22532c393a42Smrg{
22542c393a42Smrg    int i;
2255ca08ab68Smrg
22562c393a42Smrg    for (i = 0; i < patterns->nfont; i++)
22572c393a42Smrg	if (FcListPatternMatchAny (patterns->fonts[i], font))
22582c393a42Smrg	    return FcTrue;
22592c393a42Smrg    return FcFalse;
22602c393a42Smrg}
22612c393a42Smrg
22622c393a42SmrgFcBool
22632c393a42SmrgFcConfigAcceptFont (FcConfig	    *config,
22642c393a42Smrg		    const FcPattern *font)
22652c393a42Smrg{
22662c393a42Smrg    if (FcConfigPatternsMatch (config->acceptPatterns, font))
22672c393a42Smrg	return FcTrue;
22682c393a42Smrg    if (FcConfigPatternsMatch (config->rejectPatterns, font))
22692c393a42Smrg	return FcFalse;
22702c393a42Smrg    return FcTrue;
22712c393a42Smrg}
2272c9710b42Smrg
2273c9710b42Smrgconst FcChar8 *
2274c9710b42SmrgFcConfigGetSysRoot (const FcConfig *config)
2275c9710b42Smrg{
2276c9710b42Smrg    if (!config)
2277c9710b42Smrg    {
2278c9710b42Smrg	config = FcConfigGetCurrent ();
2279c9710b42Smrg	if (!config)
2280c9710b42Smrg	    return NULL;
2281c9710b42Smrg    }
2282c9710b42Smrg
2283c9710b42Smrg    return config->sysRoot;
2284c9710b42Smrg}
2285c9710b42Smrg
2286c9710b42Smrgvoid
2287c9710b42SmrgFcConfigSetSysRoot (FcConfig      *config,
2288c9710b42Smrg		    const FcChar8 *sysroot)
2289c9710b42Smrg{
2290c9710b42Smrg    FcChar8 *s;
2291c9710b42Smrg    FcBool init = FcFalse;
2292c9710b42Smrg
2293c9710b42Smrg    if (!config)
2294c9710b42Smrg    {
2295c9710b42Smrg	/* We can't use FcConfigGetCurrent() here to ensure
2296c9710b42Smrg	 * the sysroot is set prior to initialize FcConfig,
2297c9710b42Smrg	 * to avoid loading caches from non-sysroot dirs.
2298c9710b42Smrg	 * So postpone the initialization later.
2299c9710b42Smrg	 */
2300c9710b42Smrg	config = fc_atomic_ptr_get (&_fcConfig);
2301c9710b42Smrg	if (!config)
2302c9710b42Smrg	{
2303c9710b42Smrg	    config = FcConfigCreate ();
2304c9710b42Smrg	    if (!config)
2305c9710b42Smrg		return;
2306c9710b42Smrg	    init = FcTrue;
2307c9710b42Smrg	}
2308c9710b42Smrg    }
2309c9710b42Smrg
2310c9710b42Smrg    s = FcStrCopyFilename (sysroot);
2311c9710b42Smrg    if (!s)
2312c9710b42Smrg	return;
2313c9710b42Smrg
2314c9710b42Smrg    if (config->sysRoot)
2315c9710b42Smrg	FcStrFree (config->sysRoot);
2316c9710b42Smrg
2317c9710b42Smrg    config->sysRoot = s;
2318c9710b42Smrg    if (init)
2319c9710b42Smrg    {
2320c9710b42Smrg	config = FcInitLoadOwnConfigAndFonts (config);
2321c9710b42Smrg	FcConfigSetCurrent (config);
2322c9710b42Smrg    }
2323c9710b42Smrg}
2324c9710b42Smrg
23252c393a42Smrg#define __fccfg__
23262c393a42Smrg#include "fcaliastail.h"
23272c393a42Smrg#undef __fccfg__
2328