fccfg.c revision 1887081f
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
551887081fSmrgstatic FcChar32
561887081fSmrgFcHashAsStrIgnoreCase (const void *data)
571887081fSmrg{
581887081fSmrg    return FcStrHashIgnoreCase (data);
591887081fSmrg}
601887081fSmrg
611887081fSmrgstatic int
621887081fSmrgFcCompareAsStr (const void *v1, const void *v2)
631887081fSmrg{
641887081fSmrg    return FcStrCmp (v1, v2);
651887081fSmrg}
661887081fSmrg
671887081fSmrgstatic void
681887081fSmrgFcDestroyAsRule (void *data)
691887081fSmrg{
701887081fSmrg    FcRuleDestroy (data);
711887081fSmrg}
721887081fSmrg
731887081fSmrgstatic void
741887081fSmrgFcDestroyAsRuleSet (void *data)
751887081fSmrg{
761887081fSmrg    FcRuleSetDestroy (data);
771887081fSmrg}
781887081fSmrg
791887081fSmrgstatic void
801887081fSmrgFcDestroyAsStr (void *data)
811887081fSmrg{
821887081fSmrg    FcStrFree (data);
831887081fSmrg}
841887081fSmrg
85c9710b42SmrgFcBool
86c9710b42SmrgFcConfigInit (void)
87c9710b42Smrg{
88c9710b42Smrg  return FcConfigEnsure () ? FcTrue : FcFalse;
89c9710b42Smrg}
90c9710b42Smrg
91c9710b42Smrgvoid
92c9710b42SmrgFcConfigFini (void)
93c9710b42Smrg{
94c9710b42Smrg    FcConfig *cfg = fc_atomic_ptr_get (&_fcConfig);
95c9710b42Smrg    if (cfg && fc_atomic_ptr_cmpexch (&_fcConfig, cfg, NULL))
96c9710b42Smrg	FcConfigDestroy (cfg);
97c9710b42Smrg}
98c9710b42Smrg
992c393a42Smrg
1002c393a42SmrgFcConfig *
1012c393a42SmrgFcConfigCreate (void)
1022c393a42Smrg{
1032c393a42Smrg    FcSetName	set;
1042c393a42Smrg    FcConfig	*config;
1051887081fSmrg    FcMatchKind	k;
1061887081fSmrg    FcBool	err = FcFalse;
1072c393a42Smrg
1082c393a42Smrg    config = malloc (sizeof (FcConfig));
1092c393a42Smrg    if (!config)
1102c393a42Smrg	goto bail0;
111ca08ab68Smrg
1122c393a42Smrg    config->configDirs = FcStrSetCreate ();
1132c393a42Smrg    if (!config->configDirs)
1142c393a42Smrg	goto bail1;
115ca08ab68Smrg
1162c393a42Smrg    config->configFiles = FcStrSetCreate ();
1172c393a42Smrg    if (!config->configFiles)
1182c393a42Smrg	goto bail2;
119ca08ab68Smrg
1202c393a42Smrg    config->fontDirs = FcStrSetCreate ();
1212c393a42Smrg    if (!config->fontDirs)
1222c393a42Smrg	goto bail3;
123ca08ab68Smrg
1242c393a42Smrg    config->acceptGlobs = FcStrSetCreate ();
1252c393a42Smrg    if (!config->acceptGlobs)
1262c393a42Smrg	goto bail4;
1272c393a42Smrg
1282c393a42Smrg    config->rejectGlobs = FcStrSetCreate ();
1292c393a42Smrg    if (!config->rejectGlobs)
1302c393a42Smrg	goto bail5;
1312c393a42Smrg
1322c393a42Smrg    config->acceptPatterns = FcFontSetCreate ();
1332c393a42Smrg    if (!config->acceptPatterns)
1342c393a42Smrg	goto bail6;
135ca08ab68Smrg
1362c393a42Smrg    config->rejectPatterns = FcFontSetCreate ();
1372c393a42Smrg    if (!config->rejectPatterns)
1382c393a42Smrg	goto bail7;
1392c393a42Smrg
1402c393a42Smrg    config->cacheDirs = FcStrSetCreate ();
1412c393a42Smrg    if (!config->cacheDirs)
1422c393a42Smrg	goto bail8;
143ca08ab68Smrg
1441887081fSmrg    for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++)
1451887081fSmrg    {
1461887081fSmrg	config->subst[k] = FcPtrListCreate (FcDestroyAsRuleSet);
1471887081fSmrg	if (!config->subst[k])
1481887081fSmrg	    err = FcTrue;
1491887081fSmrg    }
1501887081fSmrg    if (err)
1511887081fSmrg	goto bail9;
1522c393a42Smrg
1532c393a42Smrg    config->maxObjects = 0;
1542c393a42Smrg    for (set = FcSetSystem; set <= FcSetApplication; set++)
1552c393a42Smrg	config->fonts[set] = 0;
1562c393a42Smrg
1572c393a42Smrg    config->rescanTime = time(0);
158ca08ab68Smrg    config->rescanInterval = 30;
159a6844aabSmrg
160a6844aabSmrg    config->expr_pool = NULL;
161a6844aabSmrg
162c9710b42Smrg    config->sysRoot = NULL;
163c9710b42Smrg
1641887081fSmrg    config->rulesetList = FcPtrListCreate (FcDestroyAsRuleSet);
1651887081fSmrg    if (!config->rulesetList)
1661887081fSmrg	goto bail9;
1671887081fSmrg    config->availConfigFiles = FcStrSetCreate ();
1681887081fSmrg    if (!config->availConfigFiles)
1691887081fSmrg	goto bail10;
1701887081fSmrg
1711887081fSmrg    config->uuid_table = FcHashTableCreate (FcHashAsStrIgnoreCase,
1721887081fSmrg					    FcCompareAsStr,
1731887081fSmrg					    FcHashStrCopy,
1741887081fSmrg					    FcHashUuidCopy,
1751887081fSmrg					    FcDestroyAsStr,
1761887081fSmrg					    FcHashUuidFree);
1771887081fSmrg
178c9710b42Smrg    FcRefInit (&config->ref, 1);
179ca08ab68Smrg
1802c393a42Smrg    return config;
1812c393a42Smrg
1821887081fSmrgbail10:
1831887081fSmrg    FcPtrListDestroy (config->rulesetList);
1841887081fSmrgbail9:
1851887081fSmrg    for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++)
1861887081fSmrg	if (config->subst[k])
1871887081fSmrg	    FcPtrListDestroy (config->subst[k]);
1881887081fSmrg    FcStrSetDestroy (config->cacheDirs);
1892c393a42Smrgbail8:
1902c393a42Smrg    FcFontSetDestroy (config->rejectPatterns);
1912c393a42Smrgbail7:
1922c393a42Smrg    FcFontSetDestroy (config->acceptPatterns);
1932c393a42Smrgbail6:
1942c393a42Smrg    FcStrSetDestroy (config->rejectGlobs);
1952c393a42Smrgbail5:
1962c393a42Smrg    FcStrSetDestroy (config->acceptGlobs);
1972c393a42Smrgbail4:
1982c393a42Smrg    FcStrSetDestroy (config->fontDirs);
1992c393a42Smrgbail3:
2002c393a42Smrg    FcStrSetDestroy (config->configFiles);
2012c393a42Smrgbail2:
2022c393a42Smrg    FcStrSetDestroy (config->configDirs);
2032c393a42Smrgbail1:
2042c393a42Smrg    free (config);
2052c393a42Smrgbail0:
2062c393a42Smrg    return 0;
2072c393a42Smrg}
2082c393a42Smrg
2092c393a42Smrgstatic FcFileTime
2102c393a42SmrgFcConfigNewestFile (FcStrSet *files)
2112c393a42Smrg{
2122c393a42Smrg    FcStrList	    *list = FcStrListCreate (files);
2132c393a42Smrg    FcFileTime	    newest = { 0, FcFalse };
2142c393a42Smrg    FcChar8	    *file;
2152c393a42Smrg    struct  stat    statb;
2162c393a42Smrg
2172c393a42Smrg    if (list)
2182c393a42Smrg    {
2192c393a42Smrg	while ((file = FcStrListNext (list)))
220ca08ab68Smrg	    if (FcStat (file, &statb) == 0)
2212c393a42Smrg		if (!newest.set || statb.st_mtime - newest.time > 0)
2222c393a42Smrg		{
2232c393a42Smrg		    newest.set = FcTrue;
2242c393a42Smrg		    newest.time = statb.st_mtime;
2252c393a42Smrg		}
2262c393a42Smrg	FcStrListDone (list);
2272c393a42Smrg    }
2282c393a42Smrg    return newest;
2292c393a42Smrg}
2302c393a42Smrg
2312c393a42SmrgFcBool
2322c393a42SmrgFcConfigUptoDate (FcConfig *config)
2332c393a42Smrg{
2342c393a42Smrg    FcFileTime	config_time, config_dir_time, font_time;
2352c393a42Smrg    time_t	now = time(0);
2362c393a42Smrg    if (!config)
2372c393a42Smrg    {
2382c393a42Smrg	config = FcConfigGetCurrent ();
2392c393a42Smrg	if (!config)
2402c393a42Smrg	    return FcFalse;
2412c393a42Smrg    }
2422c393a42Smrg    config_time = FcConfigNewestFile (config->configFiles);
2432c393a42Smrg    config_dir_time = FcConfigNewestFile (config->configDirs);
2442c393a42Smrg    font_time = FcConfigNewestFile (config->fontDirs);
2452c393a42Smrg    if ((config_time.set && config_time.time - config->rescanTime > 0) ||
2462c393a42Smrg	(config_dir_time.set && (config_dir_time.time - config->rescanTime) > 0) ||
2472c393a42Smrg	(font_time.set && (font_time.time - config->rescanTime) > 0))
2482c393a42Smrg    {
2492c393a42Smrg	/* We need to check for potential clock problems here (OLPC ticket #6046) */
2502c393a42Smrg	if ((config_time.set && (config_time.time - now) > 0) ||
2512c393a42Smrg    	(config_dir_time.set && (config_dir_time.time - now) > 0) ||
2522c393a42Smrg        (font_time.set && (font_time.time - now) > 0))
2532c393a42Smrg	{
2542c393a42Smrg	    fprintf (stderr,
255c9710b42Smrg                    "Fontconfig warning: Directory/file mtime in the future. New fonts may not be detected.\n");
2562c393a42Smrg	    config->rescanTime = now;
2572c393a42Smrg	    return FcTrue;
2582c393a42Smrg	}
2592c393a42Smrg	else
2602c393a42Smrg	    return FcFalse;
2612c393a42Smrg    }
2622c393a42Smrg    config->rescanTime = now;
2632c393a42Smrg    return FcTrue;
2642c393a42Smrg}
2652c393a42Smrg
266a6844aabSmrgFcExpr *
267a6844aabSmrgFcConfigAllocExpr (FcConfig *config)
268a6844aabSmrg{
2696fc018e4Smrg    if (!config->expr_pool || config->expr_pool->next == config->expr_pool->end)
2706fc018e4Smrg    {
2716fc018e4Smrg	FcExprPage *new_page;
272a6844aabSmrg
2736fc018e4Smrg	new_page = malloc (sizeof (FcExprPage));
2746fc018e4Smrg	if (!new_page)
2756fc018e4Smrg	    return 0;
276a6844aabSmrg
2776fc018e4Smrg	new_page->next_page = config->expr_pool;
2786fc018e4Smrg	new_page->next = new_page->exprs;
2796fc018e4Smrg	config->expr_pool = new_page;
2806fc018e4Smrg    }
281a6844aabSmrg
2826fc018e4Smrg    return config->expr_pool->next++;
283a6844aabSmrg}
284a6844aabSmrg
285a6844aabSmrgFcConfig *
286a6844aabSmrgFcConfigReference (FcConfig *config)
287a6844aabSmrg{
288a6844aabSmrg    if (!config)
289a6844aabSmrg    {
290a6844aabSmrg	config = FcConfigGetCurrent ();
291a6844aabSmrg	if (!config)
292a6844aabSmrg	    return 0;
293a6844aabSmrg    }
294a6844aabSmrg
295c9710b42Smrg    FcRefInc (&config->ref);
296a6844aabSmrg
297a6844aabSmrg    return config;
298a6844aabSmrg}
299a6844aabSmrg
3002c393a42Smrgvoid
3012c393a42SmrgFcConfigDestroy (FcConfig *config)
3022c393a42Smrg{
3032c393a42Smrg    FcSetName	set;
304a6844aabSmrg    FcExprPage	*page;
3051887081fSmrg    FcMatchKind	k;
306a6844aabSmrg
307c9710b42Smrg    if (FcRefDec (&config->ref) != 1)
308a6844aabSmrg	return;
3092c393a42Smrg
310c9710b42Smrg    (void) fc_atomic_ptr_cmpexch (&_fcConfig, config, NULL);
3112c393a42Smrg
3122c393a42Smrg    FcStrSetDestroy (config->configDirs);
3132c393a42Smrg    FcStrSetDestroy (config->fontDirs);
3142c393a42Smrg    FcStrSetDestroy (config->cacheDirs);
3152c393a42Smrg    FcStrSetDestroy (config->configFiles);
3162c393a42Smrg    FcStrSetDestroy (config->acceptGlobs);
3172c393a42Smrg    FcStrSetDestroy (config->rejectGlobs);
3182c393a42Smrg    FcFontSetDestroy (config->acceptPatterns);
3192c393a42Smrg    FcFontSetDestroy (config->rejectPatterns);
3202c393a42Smrg
3211887081fSmrg    for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++)
3221887081fSmrg	FcPtrListDestroy (config->subst[k]);
3231887081fSmrg    FcPtrListDestroy (config->rulesetList);
3241887081fSmrg    FcStrSetDestroy (config->availConfigFiles);
3252c393a42Smrg    for (set = FcSetSystem; set <= FcSetApplication; set++)
3262c393a42Smrg	if (config->fonts[set])
3272c393a42Smrg	    FcFontSetDestroy (config->fonts[set]);
3282c393a42Smrg
329a6844aabSmrg    page = config->expr_pool;
330a6844aabSmrg    while (page)
331a6844aabSmrg    {
332a6844aabSmrg      FcExprPage *next = page->next_page;
333a6844aabSmrg      free (page);
334a6844aabSmrg      page = next;
335a6844aabSmrg    }
336c9710b42Smrg    if (config->sysRoot)
337c9710b42Smrg	FcStrFree (config->sysRoot);
338a6844aabSmrg
3391887081fSmrg    FcHashTableDestroy (config->uuid_table);
3401887081fSmrg
3412c393a42Smrg    free (config);
3422c393a42Smrg}
3432c393a42Smrg
3442c393a42Smrg/*
3452c393a42Smrg * Add cache to configuration, adding fonts and directories
3462c393a42Smrg */
3472c393a42Smrg
3482c393a42SmrgFcBool
349ca08ab68SmrgFcConfigAddCache (FcConfig *config, FcCache *cache,
3501887081fSmrg		  FcSetName set, FcStrSet *dirSet, FcChar8 *forDir)
3512c393a42Smrg{
3522c393a42Smrg    FcFontSet	*fs;
3532c393a42Smrg    intptr_t	*dirs;
3542c393a42Smrg    int		i;
3551887081fSmrg    FcBool      relocated = FcFalse;
3561887081fSmrg
3571887081fSmrg    if (strcmp ((char *)FcCacheDir(cache), (char *)forDir) != 0)
3581887081fSmrg      relocated = FcTrue;
3592c393a42Smrg
3602c393a42Smrg    /*
3612c393a42Smrg     * Add fonts
3622c393a42Smrg     */
3632c393a42Smrg    fs = FcCacheSet (cache);
3642c393a42Smrg    if (fs)
3652c393a42Smrg    {
3662c393a42Smrg	int	nref = 0;
3672c393a42Smrg
3682c393a42Smrg	for (i = 0; i < fs->nfont; i++)
3692c393a42Smrg	{
3702c393a42Smrg	    FcPattern	*font = FcFontSetFont (fs, i);
3712c393a42Smrg	    FcChar8	*font_file;
3721887081fSmrg	    FcChar8	*relocated_font_file = NULL;
3732c393a42Smrg
3742c393a42Smrg	    if (FcPatternObjectGetString (font, FC_FILE_OBJECT,
3751887081fSmrg					  0, &font_file) == FcResultMatch)
3762c393a42Smrg	    {
3771887081fSmrg		if (relocated)
3781887081fSmrg		  {
3791887081fSmrg		    FcChar8 *slash = FcStrLastSlash (font_file);
3801887081fSmrg		    relocated_font_file = FcStrBuildFilename (forDir, slash + 1, NULL);
3811887081fSmrg		    font_file = relocated_font_file;
3821887081fSmrg		  }
3831887081fSmrg
3841887081fSmrg		/*
3851887081fSmrg		 * Check to see if font is banned by filename
3861887081fSmrg		 */
3871887081fSmrg		if (!FcConfigAcceptFilename (config, font_file))
3881887081fSmrg		{
3891887081fSmrg		    free (relocated_font_file);
3901887081fSmrg		    continue;
3911887081fSmrg		}
3922c393a42Smrg	    }
3931887081fSmrg
3942c393a42Smrg	    /*
3952c393a42Smrg	     * Check to see if font is banned by pattern
3962c393a42Smrg	     */
3972c393a42Smrg	    if (!FcConfigAcceptFont (config, font))
3981887081fSmrg	    {
3991887081fSmrg		free (relocated_font_file);
4002c393a42Smrg		continue;
4011887081fSmrg	    }
4021887081fSmrg
4031887081fSmrg	    if (relocated_font_file)
4041887081fSmrg	    {
4051887081fSmrg	      font = FcPatternCacheRewriteFile (font, cache, relocated_font_file);
4061887081fSmrg	      free (relocated_font_file);
4071887081fSmrg	    }
4081887081fSmrg
409c9710b42Smrg	    if (FcFontSetAdd (config->fonts[set], font))
410c9710b42Smrg		nref++;
4112c393a42Smrg	}
4122c393a42Smrg	FcDirCacheReference (cache, nref);
4132c393a42Smrg    }
4142c393a42Smrg
4152c393a42Smrg    /*
4162c393a42Smrg     * Add directories
4172c393a42Smrg     */
4182c393a42Smrg    dirs = FcCacheDirs (cache);
4192c393a42Smrg    if (dirs)
4202c393a42Smrg    {
4212c393a42Smrg	for (i = 0; i < cache->dirs_count; i++)
4222c393a42Smrg	{
4231887081fSmrg	    const FcChar8 *dir = FcCacheSubdir (cache, i);
4241887081fSmrg	    FcChar8 *s = NULL;
4251887081fSmrg
4261887081fSmrg	    if (relocated)
4271887081fSmrg	    {
4281887081fSmrg		FcChar8 *base = FcStrBasename (dir);
4291887081fSmrg		dir = s = FcStrBuildFilename (forDir, base, NULL);
4301887081fSmrg		FcStrFree (base);
4311887081fSmrg	    }
4322c393a42Smrg	    if (FcConfigAcceptFilename (config, dir))
4332c393a42Smrg		FcStrSetAddFilename (dirSet, dir);
4341887081fSmrg	    if (s)
4351887081fSmrg		FcStrFree (s);
4362c393a42Smrg	}
4372c393a42Smrg    }
4382c393a42Smrg    return FcTrue;
4392c393a42Smrg}
4402c393a42Smrg
4412c393a42Smrgstatic FcBool
4422c393a42SmrgFcConfigAddDirList (FcConfig *config, FcSetName set, FcStrSet *dirSet)
4432c393a42Smrg{
4442c393a42Smrg    FcStrList	    *dirlist;
4452c393a42Smrg    FcChar8	    *dir;
4462c393a42Smrg    FcCache	    *cache;
447ca08ab68Smrg
4482c393a42Smrg    dirlist = FcStrListCreate (dirSet);
4492c393a42Smrg    if (!dirlist)
4502c393a42Smrg        return FcFalse;
4512c393a42Smrg
4522c393a42Smrg    while ((dir = FcStrListNext (dirlist)))
4532c393a42Smrg    {
4542c393a42Smrg	if (FcDebug () & FC_DBG_FONTSET)
45518bd4a06Smrg	    printf ("adding fonts from %s\n", dir);
4562c393a42Smrg	cache = FcDirCacheRead (dir, FcFalse, config);
4572c393a42Smrg	if (!cache)
4582c393a42Smrg	    continue;
4591887081fSmrg	FcConfigAddCache (config, cache, set, dirSet, dir);
4602c393a42Smrg	FcDirCacheUnload (cache);
4612c393a42Smrg    }
4622c393a42Smrg    FcStrListDone (dirlist);
4632c393a42Smrg    return FcTrue;
4642c393a42Smrg}
4652c393a42Smrg
4662c393a42Smrg/*
4672c393a42Smrg * Scan the current list of directories in the configuration
4682c393a42Smrg * and build the set of available fonts.
4692c393a42Smrg */
4702c393a42Smrg
4712c393a42SmrgFcBool
4722c393a42SmrgFcConfigBuildFonts (FcConfig *config)
4732c393a42Smrg{
4742c393a42Smrg    FcFontSet	    *fonts;
4752c393a42Smrg
4762c393a42Smrg    if (!config)
4772c393a42Smrg    {
4782c393a42Smrg	config = FcConfigGetCurrent ();
4792c393a42Smrg	if (!config)
4802c393a42Smrg	    return FcFalse;
4812c393a42Smrg    }
4822c393a42Smrg
4832c393a42Smrg    fonts = FcFontSetCreate ();
4842c393a42Smrg    if (!fonts)
4852c393a42Smrg	return FcFalse;
486ca08ab68Smrg
4872c393a42Smrg    FcConfigSetFonts (config, fonts, FcSetSystem);
488ca08ab68Smrg
4892c393a42Smrg    if (!FcConfigAddDirList (config, FcSetSystem, config->fontDirs))
4902c393a42Smrg	return FcFalse;
4912c393a42Smrg    if (FcDebug () & FC_DBG_FONTSET)
4922c393a42Smrg	FcFontSetPrint (fonts);
4932c393a42Smrg    return FcTrue;
4942c393a42Smrg}
4952c393a42Smrg
4962c393a42SmrgFcBool
4972c393a42SmrgFcConfigSetCurrent (FcConfig *config)
4982c393a42Smrg{
499c9710b42Smrg    FcConfig *cfg;
500c9710b42Smrg
501c9710b42Smrgretry:
502c9710b42Smrg    cfg = fc_atomic_ptr_get (&_fcConfig);
503c9710b42Smrg
504c9710b42Smrg    if (config == cfg)
5052c393a42Smrg	return FcTrue;
5062c393a42Smrg
507c9710b42Smrg    if (config && !config->fonts[FcSetSystem])
5082c393a42Smrg	if (!FcConfigBuildFonts (config))
5092c393a42Smrg	    return FcFalse;
5102c393a42Smrg
511c9710b42Smrg    if (!fc_atomic_ptr_cmpexch (&_fcConfig, cfg, config))
512c9710b42Smrg	goto retry;
513c9710b42Smrg
51418bd4a06Smrg    FcConfigReference (config);
515c9710b42Smrg    if (cfg)
516c9710b42Smrg	FcConfigDestroy (cfg);
517c9710b42Smrg
5182c393a42Smrg    return FcTrue;
5192c393a42Smrg}
5202c393a42Smrg
5212c393a42SmrgFcConfig *
5222c393a42SmrgFcConfigGetCurrent (void)
5232c393a42Smrg{
524c9710b42Smrg    return FcConfigEnsure ();
5252c393a42Smrg}
5262c393a42Smrg
5272c393a42SmrgFcBool
5282c393a42SmrgFcConfigAddConfigDir (FcConfig	    *config,
5292c393a42Smrg		      const FcChar8 *d)
5302c393a42Smrg{
5312c393a42Smrg    return FcStrSetAddFilename (config->configDirs, d);
5322c393a42Smrg}
5332c393a42Smrg
5342c393a42SmrgFcStrList *
5352c393a42SmrgFcConfigGetConfigDirs (FcConfig   *config)
5362c393a42Smrg{
5372c393a42Smrg    if (!config)
5382c393a42Smrg    {
5392c393a42Smrg	config = FcConfigGetCurrent ();
5402c393a42Smrg	if (!config)
5412c393a42Smrg	    return 0;
5422c393a42Smrg    }
5432c393a42Smrg    return FcStrListCreate (config->configDirs);
5442c393a42Smrg}
5452c393a42Smrg
5462c393a42SmrgFcBool
5472c393a42SmrgFcConfigAddFontDir (FcConfig	    *config,
5482c393a42Smrg		    const FcChar8   *d)
5492c393a42Smrg{
5502c393a42Smrg    return FcStrSetAddFilename (config->fontDirs, d);
5512c393a42Smrg}
5522c393a42Smrg
5532c393a42SmrgFcStrList *
5542c393a42SmrgFcConfigGetFontDirs (FcConfig	*config)
5552c393a42Smrg{
5562c393a42Smrg    if (!config)
5572c393a42Smrg    {
5582c393a42Smrg	config = FcConfigGetCurrent ();
5592c393a42Smrg	if (!config)
5602c393a42Smrg	    return 0;
5612c393a42Smrg    }
5622c393a42Smrg    return FcStrListCreate (config->fontDirs);
5632c393a42Smrg}
5642c393a42Smrg
5652c393a42SmrgFcBool
5662c393a42SmrgFcConfigAddCacheDir (FcConfig	    *config,
5672c393a42Smrg		     const FcChar8  *d)
5682c393a42Smrg{
5692c393a42Smrg    return FcStrSetAddFilename (config->cacheDirs, d);
5702c393a42Smrg}
5712c393a42Smrg
5722c393a42SmrgFcStrList *
573ca08ab68SmrgFcConfigGetCacheDirs (const FcConfig *config)
5742c393a42Smrg{
5752c393a42Smrg    if (!config)
5762c393a42Smrg    {
5772c393a42Smrg	config = FcConfigGetCurrent ();
5782c393a42Smrg	if (!config)
5792c393a42Smrg	    return 0;
5802c393a42Smrg    }
5812c393a42Smrg    return FcStrListCreate (config->cacheDirs);
5822c393a42Smrg}
583ca08ab68Smrg
5842c393a42SmrgFcBool
5852c393a42SmrgFcConfigAddConfigFile (FcConfig	    *config,
5862c393a42Smrg		       const FcChar8   *f)
5872c393a42Smrg{
5882c393a42Smrg    FcBool	ret;
5892c393a42Smrg    FcChar8	*file = FcConfigFilename (f);
590ca08ab68Smrg
5912c393a42Smrg    if (!file)
5922c393a42Smrg	return FcFalse;
593ca08ab68Smrg
5942c393a42Smrg    ret = FcStrSetAdd (config->configFiles, file);
5952c393a42Smrg    FcStrFree (file);
5962c393a42Smrg    return ret;
5972c393a42Smrg}
5982c393a42Smrg
5992c393a42SmrgFcStrList *
6002c393a42SmrgFcConfigGetConfigFiles (FcConfig    *config)
6012c393a42Smrg{
6022c393a42Smrg    if (!config)
6032c393a42Smrg    {
6042c393a42Smrg	config = FcConfigGetCurrent ();
6052c393a42Smrg	if (!config)
6062c393a42Smrg	    return 0;
6072c393a42Smrg    }
6082c393a42Smrg    return FcStrListCreate (config->configFiles);
6092c393a42Smrg}
6102c393a42Smrg
6112c393a42SmrgFcChar8 *
612c9710b42SmrgFcConfigGetCache (FcConfig  *config FC_UNUSED)
6132c393a42Smrg{
6142c393a42Smrg    return NULL;
6152c393a42Smrg}
6162c393a42Smrg
6172c393a42SmrgFcFontSet *
6182c393a42SmrgFcConfigGetFonts (FcConfig	*config,
6192c393a42Smrg		  FcSetName	set)
6202c393a42Smrg{
6212c393a42Smrg    if (!config)
6222c393a42Smrg    {
6232c393a42Smrg	config = FcConfigGetCurrent ();
6242c393a42Smrg	if (!config)
6252c393a42Smrg	    return 0;
6262c393a42Smrg    }
6272c393a42Smrg    return config->fonts[set];
6282c393a42Smrg}
6292c393a42Smrg
6302c393a42Smrgvoid
6312c393a42SmrgFcConfigSetFonts (FcConfig	*config,
6322c393a42Smrg		  FcFontSet	*fonts,
6332c393a42Smrg		  FcSetName	set)
6342c393a42Smrg{
6352c393a42Smrg    if (config->fonts[set])
6362c393a42Smrg	FcFontSetDestroy (config->fonts[set]);
6372c393a42Smrg    config->fonts[set] = fonts;
6382c393a42Smrg}
6392c393a42Smrg
6401887081fSmrg
6412c393a42SmrgFcBlanks *
6421887081fSmrgFcBlanksCreate (void)
6432c393a42Smrg{
6441887081fSmrg    /* Deprecated. */
6451887081fSmrg    return NULL;
6461887081fSmrg}
6471887081fSmrg
6481887081fSmrgvoid
6491887081fSmrgFcBlanksDestroy (FcBlanks *b FC_UNUSED)
6501887081fSmrg{
6511887081fSmrg    /* Deprecated. */
6522c393a42Smrg}
6532c393a42Smrg
6542c393a42SmrgFcBool
6551887081fSmrgFcBlanksAdd (FcBlanks *b FC_UNUSED, FcChar32 ucs4 FC_UNUSED)
6562c393a42Smrg{
6571887081fSmrg    /* Deprecated. */
6581887081fSmrg    return FcFalse;
6591887081fSmrg}
660ca08ab68Smrg
6611887081fSmrgFcBool
6621887081fSmrgFcBlanksIsMember (FcBlanks *b FC_UNUSED, FcChar32 ucs4 FC_UNUSED)
6631887081fSmrg{
6641887081fSmrg    /* Deprecated. */
6651887081fSmrg    return FcFalse;
6661887081fSmrg}
6671887081fSmrg
6681887081fSmrgFcBlanks *
6691887081fSmrgFcConfigGetBlanks (FcConfig	*config FC_UNUSED)
6701887081fSmrg{
6711887081fSmrg    /* Deprecated. */
6721887081fSmrg    return NULL;
6731887081fSmrg}
6741887081fSmrg
6751887081fSmrgFcBool
6761887081fSmrgFcConfigAddBlank (FcConfig	*config FC_UNUSED,
6771887081fSmrg		  FcChar32    	blank FC_UNUSED)
6781887081fSmrg{
6791887081fSmrg    /* Deprecated. */
6801887081fSmrg    return FcFalse;
6812c393a42Smrg}
6822c393a42Smrg
6831887081fSmrg
6842c393a42Smrgint
6852c393a42SmrgFcConfigGetRescanInterval (FcConfig *config)
6862c393a42Smrg{
6872c393a42Smrg    if (!config)
6882c393a42Smrg    {
6892c393a42Smrg	config = FcConfigGetCurrent ();
6902c393a42Smrg	if (!config)
6912c393a42Smrg	    return 0;
6922c393a42Smrg    }
6932c393a42Smrg    return config->rescanInterval;
6942c393a42Smrg}
6952c393a42Smrg
6962c393a42SmrgFcBool
6972c393a42SmrgFcConfigSetRescanInterval (FcConfig *config, int rescanInterval)
6982c393a42Smrg{
6992c393a42Smrg    if (!config)
7002c393a42Smrg    {
7012c393a42Smrg	config = FcConfigGetCurrent ();
7022c393a42Smrg	if (!config)
7032c393a42Smrg	    return FcFalse;
7042c393a42Smrg    }
7052c393a42Smrg    config->rescanInterval = rescanInterval;
7062c393a42Smrg    return FcTrue;
7072c393a42Smrg}
7082c393a42Smrg
7092c393a42Smrg/*
7102c393a42Smrg * A couple of typos escaped into the library
7112c393a42Smrg */
7122c393a42Smrgint
7132c393a42SmrgFcConfigGetRescanInverval (FcConfig *config)
7142c393a42Smrg{
7152c393a42Smrg    return FcConfigGetRescanInterval (config);
7162c393a42Smrg}
7172c393a42Smrg
7182c393a42SmrgFcBool
7192c393a42SmrgFcConfigSetRescanInverval (FcConfig *config, int rescanInterval)
7202c393a42Smrg{
7212c393a42Smrg    return FcConfigSetRescanInterval (config, rescanInterval);
7222c393a42Smrg}
7232c393a42Smrg
7242c393a42SmrgFcBool
7256fc018e4SmrgFcConfigAddRule (FcConfig	*config,
7266fc018e4Smrg		 FcRule		*rule,
7272c393a42Smrg		 FcMatchKind	kind)
7282c393a42Smrg{
7291887081fSmrg    /* deprecated */
7301887081fSmrg    return FcFalse;
7312c393a42Smrg}
7322c393a42Smrg
7332c393a42Smrgstatic FcValue
734c9710b42SmrgFcConfigPromote (FcValue v, FcValue u, FcValuePromotionBuffer *buf)
7352c393a42Smrg{
7362c393a42Smrg    if (v.type == FcTypeInteger)
7372c393a42Smrg    {
7382c393a42Smrg	v.type = FcTypeDouble;
7392c393a42Smrg	v.u.d = (double) v.u.i;
7402c393a42Smrg    }
7412c393a42Smrg    else if (v.type == FcTypeVoid && u.type == FcTypeMatrix)
7422c393a42Smrg    {
7432c393a42Smrg	v.u.m = &FcIdentityMatrix;
7442c393a42Smrg	v.type = FcTypeMatrix;
7452c393a42Smrg    }
746c9710b42Smrg    else if (buf && v.type == FcTypeString && u.type == FcTypeLangSet)
7472c393a42Smrg    {
748c9710b42Smrg	v.u.l = FcLangSetPromote (v.u.s, buf);
7492c393a42Smrg	v.type = FcTypeLangSet;
7502c393a42Smrg    }
7511887081fSmrg    else if (buf && v.type == FcTypeVoid && u.type == FcTypeLangSet)
75218bd4a06Smrg    {
75318bd4a06Smrg	v.u.l = FcLangSetPromote (NULL, buf);
75418bd4a06Smrg	v.type = FcTypeLangSet;
75518bd4a06Smrg    }
7561887081fSmrg    else if (buf && v.type == FcTypeVoid && u.type == FcTypeCharSet)
75718bd4a06Smrg    {
75818bd4a06Smrg	v.u.c = FcCharSetPromote (buf);
75918bd4a06Smrg	v.type = FcTypeCharSet;
76018bd4a06Smrg    }
76118bd4a06Smrg    if (buf && v.type == FcTypeDouble && u.type == FcTypeRange)
76218bd4a06Smrg    {
76318bd4a06Smrg	v.u.r = FcRangePromote (v.u.d, buf);
76418bd4a06Smrg	v.type = FcTypeRange;
76518bd4a06Smrg    }
7662c393a42Smrg    return v;
7672c393a42Smrg}
7682c393a42Smrg
7692c393a42SmrgFcBool
7702c393a42SmrgFcConfigCompareValue (const FcValue	*left_o,
7716fc018e4Smrg		      unsigned int      op_,
7722c393a42Smrg		      const FcValue	*right_o)
7732c393a42Smrg{
7742c393a42Smrg    FcValue	left = FcValueCanonicalize(left_o);
7752c393a42Smrg    FcValue	right = FcValueCanonicalize(right_o);
7762c393a42Smrg    FcBool	ret = FcFalse;
777ca08ab68Smrg    FcOp	op = FC_OP_GET_OP (op_);
778ca08ab68Smrg    int		flags = FC_OP_GET_FLAGS (op_);
779c9710b42Smrg    FcValuePromotionBuffer buf1, buf2;
780ca08ab68Smrg
781c9710b42Smrg    left = FcConfigPromote (left, right, &buf1);
782c9710b42Smrg    right = FcConfigPromote (right, left, &buf2);
783ca08ab68Smrg    if (left.type == right.type)
7842c393a42Smrg    {
7852c393a42Smrg	switch (left.type) {
7866fc018e4Smrg	case FcTypeUnknown:
7876fc018e4Smrg	    break;	/* No way to guess how to compare for this object */
7882c393a42Smrg	case FcTypeInteger:
7892c393a42Smrg	    break;	/* FcConfigPromote prevents this from happening */
7902c393a42Smrg	case FcTypeDouble:
791c9710b42Smrg	    switch ((int) op) {
7922c393a42Smrg	    case FcOpEqual:
7932c393a42Smrg	    case FcOpContains:
7942c393a42Smrg	    case FcOpListing:
7952c393a42Smrg		ret = left.u.d == right.u.d;
7962c393a42Smrg		break;
7972c393a42Smrg	    case FcOpNotEqual:
7982c393a42Smrg	    case FcOpNotContains:
7992c393a42Smrg		ret = left.u.d != right.u.d;
8002c393a42Smrg		break;
801ca08ab68Smrg	    case FcOpLess:
8022c393a42Smrg		ret = left.u.d < right.u.d;
8032c393a42Smrg		break;
804ca08ab68Smrg	    case FcOpLessEqual:
8052c393a42Smrg		ret = left.u.d <= right.u.d;
8062c393a42Smrg		break;
807ca08ab68Smrg	    case FcOpMore:
8082c393a42Smrg		ret = left.u.d > right.u.d;
8092c393a42Smrg		break;
810ca08ab68Smrg	    case FcOpMoreEqual:
8112c393a42Smrg		ret = left.u.d >= right.u.d;
8122c393a42Smrg		break;
8132c393a42Smrg	    default:
8142c393a42Smrg		break;
8152c393a42Smrg	    }
8162c393a42Smrg	    break;
8172c393a42Smrg	case FcTypeBool:
818c9710b42Smrg	    switch ((int) op) {
819ca08ab68Smrg	    case FcOpEqual:
8201887081fSmrg		ret = left.u.b == right.u.b;
8211887081fSmrg		break;
8222c393a42Smrg	    case FcOpContains:
8232c393a42Smrg	    case FcOpListing:
8241887081fSmrg		ret = left.u.b == right.u.b || left.u.b == FcDontCare;
8252c393a42Smrg		break;
8262c393a42Smrg	    case FcOpNotEqual:
8272c393a42Smrg		ret = left.u.b != right.u.b;
8282c393a42Smrg		break;
8291887081fSmrg	    case FcOpNotContains:
8301887081fSmrg		ret = !(left.u.b == right.u.b || left.u.b == FcDontCare);
8311887081fSmrg		break;
8321887081fSmrg	    case FcOpLess:
8331887081fSmrg		ret = left.u.b != right.u.b && right.u.b == FcDontCare;
8341887081fSmrg		break;
8351887081fSmrg	    case FcOpLessEqual:
8361887081fSmrg		ret = left.u.b == right.u.b || right.u.b == FcDontCare;
8371887081fSmrg		break;
8381887081fSmrg	    case FcOpMore:
8391887081fSmrg		ret = left.u.b != right.u.b && left.u.b == FcDontCare;
8401887081fSmrg		break;
8411887081fSmrg	    case FcOpMoreEqual:
8421887081fSmrg		ret = left.u.b == right.u.b || left.u.b == FcDontCare;
8431887081fSmrg		break;
8442c393a42Smrg	    default:
8452c393a42Smrg		break;
8462c393a42Smrg	    }
8472c393a42Smrg	    break;
8482c393a42Smrg	case FcTypeString:
849c9710b42Smrg	    switch ((int) op) {
850ca08ab68Smrg	    case FcOpEqual:
8512c393a42Smrg	    case FcOpListing:
852ca08ab68Smrg		if (flags & FcOpFlagIgnoreBlanks)
853ca08ab68Smrg		    ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) == 0;
854ca08ab68Smrg		else
855ca08ab68Smrg		    ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0;
8562c393a42Smrg		break;
8572c393a42Smrg	    case FcOpContains:
8582c393a42Smrg		ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0;
8592c393a42Smrg		break;
8602c393a42Smrg	    case FcOpNotEqual:
861ca08ab68Smrg		if (flags & FcOpFlagIgnoreBlanks)
862ca08ab68Smrg		    ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) != 0;
863ca08ab68Smrg		else
864ca08ab68Smrg		    ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0;
8652c393a42Smrg		break;
8662c393a42Smrg	    case FcOpNotContains:
8672c393a42Smrg		ret = FcStrStrIgnoreCase (left.u.s, right.u.s) == 0;
8682c393a42Smrg		break;
8692c393a42Smrg	    default:
8702c393a42Smrg		break;
8712c393a42Smrg	    }
8722c393a42Smrg	    break;
8732c393a42Smrg	case FcTypeMatrix:
874c9710b42Smrg	    switch ((int) op) {
8752c393a42Smrg	    case FcOpEqual:
8762c393a42Smrg	    case FcOpContains:
8772c393a42Smrg	    case FcOpListing:
8782c393a42Smrg		ret = FcMatrixEqual (left.u.m, right.u.m);
8792c393a42Smrg		break;
8802c393a42Smrg	    case FcOpNotEqual:
8812c393a42Smrg	    case FcOpNotContains:
8822c393a42Smrg		ret = !FcMatrixEqual (left.u.m, right.u.m);
8832c393a42Smrg		break;
8842c393a42Smrg	    default:
8852c393a42Smrg		break;
8862c393a42Smrg	    }
8872c393a42Smrg	    break;
8882c393a42Smrg	case FcTypeCharSet:
889c9710b42Smrg	    switch ((int) op) {
8902c393a42Smrg	    case FcOpContains:
8912c393a42Smrg	    case FcOpListing:
8922c393a42Smrg		/* left contains right if right is a subset of left */
8932c393a42Smrg		ret = FcCharSetIsSubset (right.u.c, left.u.c);
8942c393a42Smrg		break;
8952c393a42Smrg	    case FcOpNotContains:
8962c393a42Smrg		/* left contains right if right is a subset of left */
8972c393a42Smrg		ret = !FcCharSetIsSubset (right.u.c, left.u.c);
8982c393a42Smrg		break;
8992c393a42Smrg	    case FcOpEqual:
9002c393a42Smrg		ret = FcCharSetEqual (left.u.c, right.u.c);
9012c393a42Smrg		break;
9022c393a42Smrg	    case FcOpNotEqual:
9032c393a42Smrg		ret = !FcCharSetEqual (left.u.c, right.u.c);
9042c393a42Smrg		break;
9052c393a42Smrg	    default:
9062c393a42Smrg		break;
9072c393a42Smrg	    }
9082c393a42Smrg	    break;
9092c393a42Smrg	case FcTypeLangSet:
910c9710b42Smrg	    switch ((int) op) {
9112c393a42Smrg	    case FcOpContains:
9122c393a42Smrg	    case FcOpListing:
9132c393a42Smrg		ret = FcLangSetContains (left.u.l, right.u.l);
9142c393a42Smrg		break;
9152c393a42Smrg	    case FcOpNotContains:
9162c393a42Smrg		ret = !FcLangSetContains (left.u.l, right.u.l);
9172c393a42Smrg		break;
9182c393a42Smrg	    case FcOpEqual:
9192c393a42Smrg		ret = FcLangSetEqual (left.u.l, right.u.l);
9202c393a42Smrg		break;
9212c393a42Smrg	    case FcOpNotEqual:
9222c393a42Smrg		ret = !FcLangSetEqual (left.u.l, right.u.l);
9232c393a42Smrg		break;
9242c393a42Smrg	    default:
9252c393a42Smrg		break;
9262c393a42Smrg	    }
9272c393a42Smrg	    break;
9282c393a42Smrg	case FcTypeVoid:
929c9710b42Smrg	    switch ((int) op) {
9302c393a42Smrg	    case FcOpEqual:
9312c393a42Smrg	    case FcOpContains:
9322c393a42Smrg	    case FcOpListing:
9332c393a42Smrg		ret = FcTrue;
9342c393a42Smrg		break;
9352c393a42Smrg	    default:
9362c393a42Smrg		break;
9372c393a42Smrg	    }
9382c393a42Smrg	    break;
9392c393a42Smrg	case FcTypeFTFace:
940c9710b42Smrg	    switch ((int) op) {
9412c393a42Smrg	    case FcOpEqual:
9422c393a42Smrg	    case FcOpContains:
9432c393a42Smrg	    case FcOpListing:
9442c393a42Smrg		ret = left.u.f == right.u.f;
9452c393a42Smrg		break;
9462c393a42Smrg	    case FcOpNotEqual:
9472c393a42Smrg	    case FcOpNotContains:
9482c393a42Smrg		ret = left.u.f != right.u.f;
9492c393a42Smrg		break;
9502c393a42Smrg	    default:
9512c393a42Smrg		break;
9522c393a42Smrg	    }
9532c393a42Smrg	    break;
95418bd4a06Smrg	case FcTypeRange:
95518bd4a06Smrg	    ret = FcRangeCompare (op, left.u.r, right.u.r);
95618bd4a06Smrg	    break;
9572c393a42Smrg	}
9582c393a42Smrg    }
9592c393a42Smrg    else
9602c393a42Smrg    {
9612c393a42Smrg	if (op == FcOpNotEqual || op == FcOpNotContains)
9622c393a42Smrg	    ret = FcTrue;
9632c393a42Smrg    }
9642c393a42Smrg    return ret;
9652c393a42Smrg}
9662c393a42Smrg
9672c393a42Smrg
9682c393a42Smrg#define _FcDoubleFloor(d)	((int) (d))
9692c393a42Smrg#define _FcDoubleCeil(d)	((double) (int) (d) == (d) ? (int) (d) : (int) ((d) + 1))
9702c393a42Smrg#define FcDoubleFloor(d)	((d) >= 0 ? _FcDoubleFloor(d) : -_FcDoubleCeil(-(d)))
9712c393a42Smrg#define FcDoubleCeil(d)		((d) >= 0 ? _FcDoubleCeil(d) : -_FcDoubleFloor(-(d)))
9722c393a42Smrg#define FcDoubleRound(d)	FcDoubleFloor ((d) + 0.5)
9732c393a42Smrg#define FcDoubleTrunc(d)	((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d)))
9742c393a42Smrg
9752c393a42Smrgstatic FcValue
976c9710b42SmrgFcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e)
9772c393a42Smrg{
97818bd4a06Smrg    FcValue	v, vl, vr, vle, vre;
9792c393a42Smrg    FcMatrix	*m;
9802c393a42Smrg    FcChar8     *str;
981ca08ab68Smrg    FcOp	op = FC_OP_GET_OP (e->op);
98218bd4a06Smrg    FcValuePromotionBuffer buf1, buf2;
983ca08ab68Smrg
984c9710b42Smrg    switch ((int) op) {
9852c393a42Smrg    case FcOpInteger:
9862c393a42Smrg	v.type = FcTypeInteger;
9872c393a42Smrg	v.u.i = e->u.ival;
9882c393a42Smrg	break;
9892c393a42Smrg    case FcOpDouble:
9902c393a42Smrg	v.type = FcTypeDouble;
9912c393a42Smrg	v.u.d = e->u.dval;
9922c393a42Smrg	break;
9932c393a42Smrg    case FcOpString:
9942c393a42Smrg	v.type = FcTypeString;
995a6844aabSmrg	v.u.s = e->u.sval;
996a6844aabSmrg	v = FcValueSave (v);
9972c393a42Smrg	break;
9982c393a42Smrg    case FcOpMatrix:
999c9710b42Smrg	{
1000c9710b42Smrg	  FcMatrix m;
1001c9710b42Smrg	  FcValue xx, xy, yx, yy;
1002c9710b42Smrg	  v.type = FcTypeMatrix;
1003c9710b42Smrg	  xx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xx), v, NULL);
1004c9710b42Smrg	  xy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xy), v, NULL);
1005c9710b42Smrg	  yx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yx), v, NULL);
1006c9710b42Smrg	  yy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yy), v, NULL);
1007c9710b42Smrg	  if (xx.type == FcTypeDouble && xy.type == FcTypeDouble &&
1008c9710b42Smrg	      yx.type == FcTypeDouble && yy.type == FcTypeDouble)
1009c9710b42Smrg	  {
1010c9710b42Smrg	    m.xx = xx.u.d;
1011c9710b42Smrg	    m.xy = xy.u.d;
1012c9710b42Smrg	    m.yx = yx.u.d;
1013c9710b42Smrg	    m.yy = yy.u.d;
1014c9710b42Smrg	    v.u.m = &m;
1015c9710b42Smrg	  }
1016c9710b42Smrg	  else
1017c9710b42Smrg	    v.type = FcTypeVoid;
1018c9710b42Smrg	  v = FcValueSave (v);
1019c9710b42Smrg	}
10202c393a42Smrg	break;
10212c393a42Smrg    case FcOpCharSet:
10222c393a42Smrg	v.type = FcTypeCharSet;
10232c393a42Smrg	v.u.c = e->u.cval;
10242c393a42Smrg	v = FcValueSave (v);
10252c393a42Smrg	break;
1026ca08ab68Smrg    case FcOpLangSet:
1027ca08ab68Smrg	v.type = FcTypeLangSet;
1028ca08ab68Smrg	v.u.l = e->u.lval;
1029ca08ab68Smrg	v = FcValueSave (v);
1030ca08ab68Smrg	break;
103118bd4a06Smrg    case FcOpRange:
103218bd4a06Smrg	v.type = FcTypeRange;
103318bd4a06Smrg	v.u.r = e->u.rval;
103418bd4a06Smrg	v = FcValueSave (v);
103518bd4a06Smrg	break;
10362c393a42Smrg    case FcOpBool:
10372c393a42Smrg	v.type = FcTypeBool;
10382c393a42Smrg	v.u.b = e->u.bval;
10392c393a42Smrg	break;
10402c393a42Smrg    case FcOpField:
1041c9710b42Smrg	if (kind == FcMatchFont && e->u.name.kind == FcMatchPattern)
1042c9710b42Smrg	{
1043c9710b42Smrg	    if (FcResultMatch != FcPatternObjectGet (p_pat, e->u.name.object, 0, &v))
1044c9710b42Smrg		v.type = FcTypeVoid;
1045c9710b42Smrg	}
1046c9710b42Smrg	else if (kind == FcMatchPattern && e->u.name.kind == FcMatchFont)
1047c9710b42Smrg	{
1048c9710b42Smrg	    fprintf (stderr,
1049c9710b42Smrg                    "Fontconfig warning: <name> tag has target=\"font\" in a <match target=\"pattern\">.\n");
10502c393a42Smrg	    v.type = FcTypeVoid;
1051c9710b42Smrg	}
1052c9710b42Smrg	else
1053c9710b42Smrg	{
1054c9710b42Smrg	    if (FcResultMatch != FcPatternObjectGet (p, e->u.name.object, 0, &v))
1055c9710b42Smrg		v.type = FcTypeVoid;
1056c9710b42Smrg	}
10572c393a42Smrg	v = FcValueSave (v);
10582c393a42Smrg	break;
10592c393a42Smrg    case FcOpConst:
10602c393a42Smrg	if (FcNameConstant (e->u.constant, &v.u.i))
10612c393a42Smrg	    v.type = FcTypeInteger;
10622c393a42Smrg	else
10632c393a42Smrg	    v.type = FcTypeVoid;
10642c393a42Smrg	break;
10652c393a42Smrg    case FcOpQuest:
1066c9710b42Smrg	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
10672c393a42Smrg	if (vl.type == FcTypeBool)
10682c393a42Smrg	{
10692c393a42Smrg	    if (vl.u.b)
1070c9710b42Smrg		v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.left);
10712c393a42Smrg	    else
1072c9710b42Smrg		v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.right);
10732c393a42Smrg	}
10742c393a42Smrg	else
10752c393a42Smrg	    v.type = FcTypeVoid;
10762c393a42Smrg	FcValueDestroy (vl);
10772c393a42Smrg	break;
10782c393a42Smrg    case FcOpEqual:
10792c393a42Smrg    case FcOpNotEqual:
10802c393a42Smrg    case FcOpLess:
10812c393a42Smrg    case FcOpLessEqual:
10822c393a42Smrg    case FcOpMore:
10832c393a42Smrg    case FcOpMoreEqual:
10842c393a42Smrg    case FcOpContains:
10852c393a42Smrg    case FcOpNotContains:
10862c393a42Smrg    case FcOpListing:
1087c9710b42Smrg	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1088c9710b42Smrg	vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right);
10892c393a42Smrg	v.type = FcTypeBool;
10902c393a42Smrg	v.u.b = FcConfigCompareValue (&vl, e->op, &vr);
10912c393a42Smrg	FcValueDestroy (vl);
10922c393a42Smrg	FcValueDestroy (vr);
10932c393a42Smrg	break;
10942c393a42Smrg    case FcOpOr:
10952c393a42Smrg    case FcOpAnd:
10962c393a42Smrg    case FcOpPlus:
10972c393a42Smrg    case FcOpMinus:
10982c393a42Smrg    case FcOpTimes:
10992c393a42Smrg    case FcOpDivide:
1100c9710b42Smrg	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1101c9710b42Smrg	vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right);
110218bd4a06Smrg	vle = FcConfigPromote (vl, vr, &buf1);
110318bd4a06Smrg	vre = FcConfigPromote (vr, vle, &buf2);
110418bd4a06Smrg	if (vle.type == vre.type)
11052c393a42Smrg	{
110618bd4a06Smrg	    switch ((int) vle.type) {
11072c393a42Smrg	    case FcTypeDouble:
1108c9710b42Smrg		switch ((int) op) {
1109ca08ab68Smrg		case FcOpPlus:
11102c393a42Smrg		    v.type = FcTypeDouble;
111118bd4a06Smrg		    v.u.d = vle.u.d + vre.u.d;
11122c393a42Smrg		    break;
11132c393a42Smrg		case FcOpMinus:
11142c393a42Smrg		    v.type = FcTypeDouble;
111518bd4a06Smrg		    v.u.d = vle.u.d - vre.u.d;
11162c393a42Smrg		    break;
11172c393a42Smrg		case FcOpTimes:
11182c393a42Smrg		    v.type = FcTypeDouble;
111918bd4a06Smrg		    v.u.d = vle.u.d * vre.u.d;
11202c393a42Smrg		    break;
11212c393a42Smrg		case FcOpDivide:
11222c393a42Smrg		    v.type = FcTypeDouble;
112318bd4a06Smrg		    v.u.d = vle.u.d / vre.u.d;
11242c393a42Smrg		    break;
11252c393a42Smrg		default:
1126ca08ab68Smrg		    v.type = FcTypeVoid;
11272c393a42Smrg		    break;
11282c393a42Smrg		}
11292c393a42Smrg		if (v.type == FcTypeDouble &&
11302c393a42Smrg		    v.u.d == (double) (int) v.u.d)
11312c393a42Smrg		{
11322c393a42Smrg		    v.type = FcTypeInteger;
11332c393a42Smrg		    v.u.i = (int) v.u.d;
11342c393a42Smrg		}
11352c393a42Smrg		break;
11362c393a42Smrg	    case FcTypeBool:
1137c9710b42Smrg		switch ((int) op) {
11382c393a42Smrg		case FcOpOr:
11392c393a42Smrg		    v.type = FcTypeBool;
114018bd4a06Smrg		    v.u.b = vle.u.b || vre.u.b;
11412c393a42Smrg		    break;
11422c393a42Smrg		case FcOpAnd:
11432c393a42Smrg		    v.type = FcTypeBool;
114418bd4a06Smrg		    v.u.b = vle.u.b && vre.u.b;
11452c393a42Smrg		    break;
11462c393a42Smrg		default:
1147ca08ab68Smrg		    v.type = FcTypeVoid;
11482c393a42Smrg		    break;
11492c393a42Smrg		}
11502c393a42Smrg		break;
11512c393a42Smrg	    case FcTypeString:
1152c9710b42Smrg		switch ((int) op) {
11532c393a42Smrg		case FcOpPlus:
11542c393a42Smrg		    v.type = FcTypeString;
115518bd4a06Smrg		    str = FcStrPlus (vle.u.s, vre.u.s);
1156c9710b42Smrg		    v.u.s = FcStrdup (str);
11572c393a42Smrg		    FcStrFree (str);
1158ca08ab68Smrg
11592c393a42Smrg		    if (!v.u.s)
11602c393a42Smrg			v.type = FcTypeVoid;
11612c393a42Smrg		    break;
11622c393a42Smrg		default:
11632c393a42Smrg		    v.type = FcTypeVoid;
11642c393a42Smrg		    break;
11652c393a42Smrg		}
11662c393a42Smrg		break;
11672c393a42Smrg	    case FcTypeMatrix:
1168c9710b42Smrg		switch ((int) op) {
11692c393a42Smrg		case FcOpTimes:
11702c393a42Smrg		    v.type = FcTypeMatrix;
11712c393a42Smrg		    m = malloc (sizeof (FcMatrix));
11722c393a42Smrg		    if (m)
11732c393a42Smrg		    {
117418bd4a06Smrg			FcMatrixMultiply (m, vle.u.m, vre.u.m);
11752c393a42Smrg			v.u.m = m;
11762c393a42Smrg		    }
11772c393a42Smrg		    else
11782c393a42Smrg		    {
11792c393a42Smrg			v.type = FcTypeVoid;
11802c393a42Smrg		    }
11812c393a42Smrg		    break;
11822c393a42Smrg		default:
11832c393a42Smrg		    v.type = FcTypeVoid;
11842c393a42Smrg		    break;
11852c393a42Smrg		}
11862c393a42Smrg		break;
1187ca08ab68Smrg	    case FcTypeCharSet:
1188c9710b42Smrg		switch ((int) op) {
1189ca08ab68Smrg		case FcOpPlus:
1190ca08ab68Smrg		    v.type = FcTypeCharSet;
119118bd4a06Smrg		    v.u.c = FcCharSetUnion (vle.u.c, vre.u.c);
1192ca08ab68Smrg		    if (!v.u.c)
1193ca08ab68Smrg			v.type = FcTypeVoid;
1194ca08ab68Smrg		    break;
1195ca08ab68Smrg		case FcOpMinus:
1196ca08ab68Smrg		    v.type = FcTypeCharSet;
119718bd4a06Smrg		    v.u.c = FcCharSetSubtract (vle.u.c, vre.u.c);
1198ca08ab68Smrg		    if (!v.u.c)
1199ca08ab68Smrg			v.type = FcTypeVoid;
1200ca08ab68Smrg		    break;
1201ca08ab68Smrg		default:
1202ca08ab68Smrg		    v.type = FcTypeVoid;
1203ca08ab68Smrg		    break;
1204ca08ab68Smrg		}
1205ca08ab68Smrg		break;
1206ca08ab68Smrg	    case FcTypeLangSet:
1207c9710b42Smrg		switch ((int) op) {
1208ca08ab68Smrg		case FcOpPlus:
1209ca08ab68Smrg		    v.type = FcTypeLangSet;
121018bd4a06Smrg		    v.u.l = FcLangSetUnion (vle.u.l, vre.u.l);
1211ca08ab68Smrg		    if (!v.u.l)
1212ca08ab68Smrg			v.type = FcTypeVoid;
1213ca08ab68Smrg		    break;
1214ca08ab68Smrg		case FcOpMinus:
1215ca08ab68Smrg		    v.type = FcTypeLangSet;
121618bd4a06Smrg		    v.u.l = FcLangSetSubtract (vle.u.l, vre.u.l);
1217ca08ab68Smrg		    if (!v.u.l)
1218ca08ab68Smrg			v.type = FcTypeVoid;
1219ca08ab68Smrg		    break;
1220ca08ab68Smrg		default:
1221ca08ab68Smrg		    v.type = FcTypeVoid;
1222ca08ab68Smrg		    break;
1223ca08ab68Smrg		}
1224ca08ab68Smrg		break;
12252c393a42Smrg	    default:
12262c393a42Smrg		v.type = FcTypeVoid;
12272c393a42Smrg		break;
12282c393a42Smrg	    }
12292c393a42Smrg	}
12302c393a42Smrg	else
12312c393a42Smrg	    v.type = FcTypeVoid;
12322c393a42Smrg	FcValueDestroy (vl);
12332c393a42Smrg	FcValueDestroy (vr);
12342c393a42Smrg	break;
12352c393a42Smrg    case FcOpNot:
1236c9710b42Smrg	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1237c9710b42Smrg	switch ((int) vl.type) {
12382c393a42Smrg	case FcTypeBool:
12392c393a42Smrg	    v.type = FcTypeBool;
12402c393a42Smrg	    v.u.b = !vl.u.b;
12412c393a42Smrg	    break;
12422c393a42Smrg	default:
12432c393a42Smrg	    v.type = FcTypeVoid;
12442c393a42Smrg	    break;
12452c393a42Smrg	}
12462c393a42Smrg	FcValueDestroy (vl);
12472c393a42Smrg	break;
12482c393a42Smrg    case FcOpFloor:
1249c9710b42Smrg	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1250c9710b42Smrg	switch ((int) vl.type) {
12512c393a42Smrg	case FcTypeInteger:
12522c393a42Smrg	    v = vl;
12532c393a42Smrg	    break;
12542c393a42Smrg	case FcTypeDouble:
12552c393a42Smrg	    v.type = FcTypeInteger;
12562c393a42Smrg	    v.u.i = FcDoubleFloor (vl.u.d);
12572c393a42Smrg	    break;
12582c393a42Smrg	default:
12592c393a42Smrg	    v.type = FcTypeVoid;
12602c393a42Smrg	    break;
12612c393a42Smrg	}
12622c393a42Smrg	FcValueDestroy (vl);
12632c393a42Smrg	break;
12642c393a42Smrg    case FcOpCeil:
1265c9710b42Smrg	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1266c9710b42Smrg	switch ((int) vl.type) {
12672c393a42Smrg	case FcTypeInteger:
12682c393a42Smrg	    v = vl;
12692c393a42Smrg	    break;
12702c393a42Smrg	case FcTypeDouble:
12712c393a42Smrg	    v.type = FcTypeInteger;
12722c393a42Smrg	    v.u.i = FcDoubleCeil (vl.u.d);
12732c393a42Smrg	    break;
12742c393a42Smrg	default:
12752c393a42Smrg	    v.type = FcTypeVoid;
12762c393a42Smrg	    break;
12772c393a42Smrg	}
12782c393a42Smrg	FcValueDestroy (vl);
12792c393a42Smrg	break;
12802c393a42Smrg    case FcOpRound:
1281c9710b42Smrg	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1282c9710b42Smrg	switch ((int) vl.type) {
12832c393a42Smrg	case FcTypeInteger:
12842c393a42Smrg	    v = vl;
12852c393a42Smrg	    break;
12862c393a42Smrg	case FcTypeDouble:
12872c393a42Smrg	    v.type = FcTypeInteger;
12882c393a42Smrg	    v.u.i = FcDoubleRound (vl.u.d);
12892c393a42Smrg	    break;
12902c393a42Smrg	default:
12912c393a42Smrg	    v.type = FcTypeVoid;
12922c393a42Smrg	    break;
12932c393a42Smrg	}
12942c393a42Smrg	FcValueDestroy (vl);
12952c393a42Smrg	break;
12962c393a42Smrg    case FcOpTrunc:
1297c9710b42Smrg	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1298c9710b42Smrg	switch ((int) vl.type) {
12992c393a42Smrg	case FcTypeInteger:
13002c393a42Smrg	    v = vl;
13012c393a42Smrg	    break;
13022c393a42Smrg	case FcTypeDouble:
13032c393a42Smrg	    v.type = FcTypeInteger;
13042c393a42Smrg	    v.u.i = FcDoubleTrunc (vl.u.d);
13052c393a42Smrg	    break;
13062c393a42Smrg	default:
13072c393a42Smrg	    v.type = FcTypeVoid;
13082c393a42Smrg	    break;
13092c393a42Smrg	}
13102c393a42Smrg	FcValueDestroy (vl);
13112c393a42Smrg	break;
13122c393a42Smrg    default:
13132c393a42Smrg	v.type = FcTypeVoid;
13142c393a42Smrg	break;
13152c393a42Smrg    }
13162c393a42Smrg    return v;
13172c393a42Smrg}
13182c393a42Smrg
13192c393a42Smrgstatic FcValueList *
13202c393a42SmrgFcConfigMatchValueList (FcPattern	*p,
1321c9710b42Smrg			FcPattern	*p_pat,
1322c9710b42Smrg			FcMatchKind      kind,
13232c393a42Smrg			FcTest		*t,
13242c393a42Smrg			FcValueList	*values)
13252c393a42Smrg{
13262c393a42Smrg    FcValueList	    *ret = 0;
13272c393a42Smrg    FcExpr	    *e = t->expr;
13282c393a42Smrg    FcValue	    value;
13292c393a42Smrg    FcValueList	    *v;
1330ca08ab68Smrg
13312c393a42Smrg    while (e)
13322c393a42Smrg    {
13332c393a42Smrg	/* Compute the value of the match expression */
1334ca08ab68Smrg	if (FC_OP_GET_OP (e->op) == FcOpComma)
13352c393a42Smrg	{
1336c9710b42Smrg	    value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
13372c393a42Smrg	    e = e->u.tree.right;
13382c393a42Smrg	}
13392c393a42Smrg	else
13402c393a42Smrg	{
1341c9710b42Smrg	    value = FcConfigEvaluate (p, p_pat, kind, e);
13422c393a42Smrg	    e = 0;
13432c393a42Smrg	}
13442c393a42Smrg
13452c393a42Smrg	for (v = values; v; v = FcValueListNext(v))
13462c393a42Smrg	{
13472c393a42Smrg	    /* Compare the pattern value to the match expression value */
13482c393a42Smrg	    if (FcConfigCompareValue (&v->value, t->op, &value))
13492c393a42Smrg	    {
13502c393a42Smrg		if (!ret)
13512c393a42Smrg		    ret = v;
13522c393a42Smrg	    }
13532c393a42Smrg	    else
13542c393a42Smrg	    {
13552c393a42Smrg		if (t->qual == FcQualAll)
13562c393a42Smrg		{
13572c393a42Smrg		    ret = 0;
13582c393a42Smrg		    break;
13592c393a42Smrg		}
13602c393a42Smrg	    }
13612c393a42Smrg	}
13622c393a42Smrg	FcValueDestroy (value);
13632c393a42Smrg    }
13642c393a42Smrg    return ret;
13652c393a42Smrg}
13662c393a42Smrg
13672c393a42Smrgstatic FcValueList *
1368c9710b42SmrgFcConfigValues (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e, FcValueBinding binding)
13692c393a42Smrg{
13702c393a42Smrg    FcValueList	*l;
1371ca08ab68Smrg
13722c393a42Smrg    if (!e)
13732c393a42Smrg	return 0;
13742c393a42Smrg    l = (FcValueList *) malloc (sizeof (FcValueList));
13752c393a42Smrg    if (!l)
13762c393a42Smrg	return 0;
1377ca08ab68Smrg    if (FC_OP_GET_OP (e->op) == FcOpComma)
13782c393a42Smrg    {
1379c9710b42Smrg	l->value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1380c9710b42Smrg	l->next = FcConfigValues (p, p_pat, kind, e->u.tree.right, binding);
13812c393a42Smrg    }
13822c393a42Smrg    else
13832c393a42Smrg    {
1384c9710b42Smrg	l->value = FcConfigEvaluate (p, p_pat, kind, e);
13852c393a42Smrg	l->next = NULL;
13862c393a42Smrg    }
13872c393a42Smrg    l->binding = binding;
13882c393a42Smrg    if (l->value.type == FcTypeVoid)
13892c393a42Smrg    {
13902c393a42Smrg	FcValueList  *next = FcValueListNext(l);
13912c393a42Smrg
13922c393a42Smrg	free (l);
13932c393a42Smrg	l = next;
13942c393a42Smrg    }
13952c393a42Smrg
13962c393a42Smrg    return l;
13972c393a42Smrg}
13982c393a42Smrg
13992c393a42Smrgstatic FcBool
14002c393a42SmrgFcConfigAdd (FcValueListPtr *head,
14012c393a42Smrg	     FcValueList    *position,
14022c393a42Smrg	     FcBool	    append,
1403c9710b42Smrg	     FcValueList    *new,
1404c9710b42Smrg	     FcObject        object)
14052c393a42Smrg{
1406c9710b42Smrg    FcValueListPtr  *prev, l, last, v;
14072c393a42Smrg    FcValueBinding  sameBinding;
1408ca08ab68Smrg
1409c9710b42Smrg    /*
1410c9710b42Smrg     * Make sure the stored type is valid for built-in objects
1411c9710b42Smrg     */
1412c9710b42Smrg    for (l = new; l != NULL; l = FcValueListNext (l))
1413c9710b42Smrg    {
1414c9710b42Smrg	if (!FcObjectValidType (object, l->value.type))
1415c9710b42Smrg	{
1416c9710b42Smrg	    fprintf (stderr,
1417c9710b42Smrg		     "Fontconfig warning: FcPattern object %s does not accept value", FcObjectName (object));
1418c9710b42Smrg	    FcValuePrintFile (stderr, l->value);
1419c9710b42Smrg	    fprintf (stderr, "\n");
1420c9710b42Smrg
1421c9710b42Smrg	    if (FcDebug () & FC_DBG_EDIT)
1422c9710b42Smrg	    {
1423c9710b42Smrg		printf ("Not adding\n");
1424c9710b42Smrg	    }
1425c9710b42Smrg
1426c9710b42Smrg	    return FcFalse;
1427c9710b42Smrg	}
1428c9710b42Smrg    }
1429c9710b42Smrg
14302c393a42Smrg    if (position)
14312c393a42Smrg	sameBinding = position->binding;
14322c393a42Smrg    else
14332c393a42Smrg	sameBinding = FcValueBindingWeak;
14342c393a42Smrg    for (v = new; v != NULL; v = FcValueListNext(v))
14352c393a42Smrg	if (v->binding == FcValueBindingSame)
14362c393a42Smrg	    v->binding = sameBinding;
14372c393a42Smrg    if (append)
14382c393a42Smrg    {
14392c393a42Smrg	if (position)
14402c393a42Smrg	    prev = &position->next;
14412c393a42Smrg	else
1442ca08ab68Smrg	    for (prev = head; *prev != NULL;
14432c393a42Smrg		 prev = &(*prev)->next)
14442c393a42Smrg		;
14452c393a42Smrg    }
14462c393a42Smrg    else
14472c393a42Smrg    {
14482c393a42Smrg	if (position)
14492c393a42Smrg	{
1450ca08ab68Smrg	    for (prev = head; *prev != NULL;
14512c393a42Smrg		 prev = &(*prev)->next)
14522c393a42Smrg	    {
14532c393a42Smrg		if (*prev == position)
14542c393a42Smrg		    break;
14552c393a42Smrg	    }
14562c393a42Smrg	}
14572c393a42Smrg	else
14582c393a42Smrg	    prev = head;
14592c393a42Smrg
14602c393a42Smrg	if (FcDebug () & FC_DBG_EDIT)
14612c393a42Smrg	{
14622c393a42Smrg	    if (*prev == NULL)
14632c393a42Smrg		printf ("position not on list\n");
14642c393a42Smrg	}
14652c393a42Smrg    }
14662c393a42Smrg
14672c393a42Smrg    if (FcDebug () & FC_DBG_EDIT)
14682c393a42Smrg    {
14692c393a42Smrg	printf ("%s list before ", append ? "Append" : "Prepend");
1470ca08ab68Smrg	FcValueListPrintWithPosition (*head, *prev);
14712c393a42Smrg	printf ("\n");
14722c393a42Smrg    }
1473ca08ab68Smrg
14742c393a42Smrg    if (new)
14752c393a42Smrg    {
14762c393a42Smrg	last = new;
14772c393a42Smrg	while (last->next != NULL)
14782c393a42Smrg	    last = last->next;
1479ca08ab68Smrg
14802c393a42Smrg	last->next = *prev;
14812c393a42Smrg	*prev = new;
14822c393a42Smrg    }
1483ca08ab68Smrg
14842c393a42Smrg    if (FcDebug () & FC_DBG_EDIT)
14852c393a42Smrg    {
14862c393a42Smrg	printf ("%s list after ", append ? "Append" : "Prepend");
14872c393a42Smrg	FcValueListPrint (*head);
14882c393a42Smrg	printf ("\n");
14892c393a42Smrg    }
1490ca08ab68Smrg
14912c393a42Smrg    return FcTrue;
14922c393a42Smrg}
14932c393a42Smrg
14942c393a42Smrgstatic void
14952c393a42SmrgFcConfigDel (FcValueListPtr *head,
14962c393a42Smrg	     FcValueList    *position)
14972c393a42Smrg{
14982c393a42Smrg    FcValueListPtr *prev;
14992c393a42Smrg
15002c393a42Smrg    for (prev = head; *prev != NULL; prev = &(*prev)->next)
15012c393a42Smrg    {
15022c393a42Smrg	if (*prev == position)
15032c393a42Smrg	{
15042c393a42Smrg	    *prev = position->next;
15052c393a42Smrg	    position->next = NULL;
15062c393a42Smrg	    FcValueListDestroy (position);
15072c393a42Smrg	    break;
15082c393a42Smrg	}
15092c393a42Smrg    }
15102c393a42Smrg}
15112c393a42Smrg
15122c393a42Smrgstatic void
15132c393a42SmrgFcConfigPatternAdd (FcPattern	*p,
15142c393a42Smrg		    FcObject	object,
15152c393a42Smrg		    FcValueList	*list,
15162c393a42Smrg		    FcBool	append)
15172c393a42Smrg{
15182c393a42Smrg    if (list)
15192c393a42Smrg    {
15202c393a42Smrg	FcPatternElt    *e = FcPatternObjectInsertElt (p, object);
1521ca08ab68Smrg
15222c393a42Smrg	if (!e)
15232c393a42Smrg	    return;
1524c9710b42Smrg	FcConfigAdd (&e->values, 0, append, list, object);
15252c393a42Smrg    }
15262c393a42Smrg}
15272c393a42Smrg
15282c393a42Smrg/*
15292c393a42Smrg * Delete all values associated with a field
15302c393a42Smrg */
15312c393a42Smrgstatic void
15322c393a42SmrgFcConfigPatternDel (FcPattern	*p,
15332c393a42Smrg		    FcObject	object)
15342c393a42Smrg{
15352c393a42Smrg    FcPatternElt    *e = FcPatternObjectFindElt (p, object);
15362c393a42Smrg    if (!e)
15372c393a42Smrg	return;
15382c393a42Smrg    while (e->values != NULL)
15392c393a42Smrg	FcConfigDel (&e->values, e->values);
15402c393a42Smrg}
15412c393a42Smrg
15422c393a42Smrgstatic void
15432c393a42SmrgFcConfigPatternCanon (FcPattern	    *p,
15442c393a42Smrg		      FcObject	    object)
15452c393a42Smrg{
15462c393a42Smrg    FcPatternElt    *e = FcPatternObjectFindElt (p, object);
15472c393a42Smrg    if (!e)
15482c393a42Smrg	return;
15492c393a42Smrg    if (e->values == NULL)
15502c393a42Smrg	FcPatternObjectDel (p, object);
15512c393a42Smrg}
15522c393a42Smrg
15532c393a42SmrgFcBool
15542c393a42SmrgFcConfigSubstituteWithPat (FcConfig    *config,
15552c393a42Smrg			   FcPattern   *p,
15562c393a42Smrg			   FcPattern   *p_pat,
15572c393a42Smrg			   FcMatchKind kind)
15582c393a42Smrg{
1559c9710b42Smrg    FcValue v;
15601887081fSmrg    FcPtrList	    *s;
15611887081fSmrg    FcPtrListIter    iter, iter2;
15626fc018e4Smrg    FcRule          *r;
15631887081fSmrg    FcRuleSet	    *rs;
15646fc018e4Smrg    FcValueList	    *l, **value = NULL, *vl;
15652c393a42Smrg    FcPattern	    *m;
1566ca08ab68Smrg    FcStrSet	    *strs;
15676fc018e4Smrg    FcObject	    object = FC_INVALID_OBJECT;
15686fc018e4Smrg    FcPatternElt    **elt = NULL, *e;
15696fc018e4Smrg    int		    i, nobjs;
15706fc018e4Smrg    FcBool	    retval = FcTrue;
15716fc018e4Smrg    FcTest	    **tst = NULL;
15722c393a42Smrg
15732c393a42Smrg    if (!config)
15742c393a42Smrg    {
15752c393a42Smrg	config = FcConfigGetCurrent ();
15762c393a42Smrg	if (!config)
15772c393a42Smrg	    return FcFalse;
15782c393a42Smrg    }
15792c393a42Smrg
15801887081fSmrg    if (kind < FcMatchKindBegin || kind >= FcMatchKindEnd)
15811887081fSmrg	return FcFalse;
15821887081fSmrg    s = config->subst[kind];
15831887081fSmrg    if (kind == FcMatchPattern)
15841887081fSmrg    {
1585ca08ab68Smrg	strs = FcGetDefaultLangs ();
1586ca08ab68Smrg	if (strs)
1587ca08ab68Smrg	{
1588ca08ab68Smrg	    FcStrList *l = FcStrListCreate (strs);
1589ca08ab68Smrg	    FcChar8 *lang;
1590ca08ab68Smrg	    FcValue v;
159118bd4a06Smrg	    FcLangSet *lsund = FcLangSetCreate ();
1592ca08ab68Smrg
159318bd4a06Smrg	    FcLangSetAdd (lsund, (const FcChar8 *)"und");
1594ca08ab68Smrg	    FcStrSetDestroy (strs);
1595ca08ab68Smrg	    while (l && (lang = FcStrListNext (l)))
1596ca08ab68Smrg	    {
159718bd4a06Smrg		FcPatternElt *e = FcPatternObjectFindElt (p, FC_LANG_OBJECT);
159818bd4a06Smrg
159918bd4a06Smrg		if (e)
160018bd4a06Smrg		{
160118bd4a06Smrg		    FcValueListPtr ll;
160218bd4a06Smrg
160318bd4a06Smrg		    for (ll = FcPatternEltValues (e); ll; ll = FcValueListNext (ll))
160418bd4a06Smrg		    {
160518bd4a06Smrg			FcValue vv = FcValueCanonicalize (&ll->value);
160618bd4a06Smrg
160718bd4a06Smrg			if (vv.type == FcTypeLangSet)
160818bd4a06Smrg			{
160918bd4a06Smrg			    FcLangSet *ls = FcLangSetCreate ();
161018bd4a06Smrg			    FcBool b;
161118bd4a06Smrg
161218bd4a06Smrg			    FcLangSetAdd (ls, lang);
161318bd4a06Smrg			    b = FcLangSetContains (vv.u.l, ls);
161418bd4a06Smrg			    FcLangSetDestroy (ls);
161518bd4a06Smrg			    if (b)
161618bd4a06Smrg				goto bail_lang;
161718bd4a06Smrg			    if (FcLangSetContains (vv.u.l, lsund))
161818bd4a06Smrg				goto bail_lang;
161918bd4a06Smrg			}
162018bd4a06Smrg			else
162118bd4a06Smrg			{
162218bd4a06Smrg			    if (FcStrCmpIgnoreCase (vv.u.s, lang) == 0)
162318bd4a06Smrg				goto bail_lang;
162418bd4a06Smrg			    if (FcStrCmpIgnoreCase (vv.u.s, (const FcChar8 *)"und") == 0)
162518bd4a06Smrg				goto bail_lang;
162618bd4a06Smrg			}
162718bd4a06Smrg		    }
162818bd4a06Smrg		}
1629ca08ab68Smrg		v.type = FcTypeString;
1630ca08ab68Smrg		v.u.s = lang;
163118bd4a06Smrg
1632ca08ab68Smrg		FcPatternObjectAddWithBinding (p, FC_LANG_OBJECT, v, FcValueBindingWeak, FcTrue);
1633ca08ab68Smrg	    }
163418bd4a06Smrg	bail_lang:
1635ca08ab68Smrg	    FcStrListDone (l);
163618bd4a06Smrg	    FcLangSetDestroy (lsund);
1637ca08ab68Smrg	}
1638c9710b42Smrg	if (FcPatternObjectGet (p, FC_PRGNAME_OBJECT, 0, &v) == FcResultNoMatch)
1639c9710b42Smrg	{
1640c9710b42Smrg	    FcChar8 *prgname = FcGetPrgname ();
1641c9710b42Smrg	    if (prgname)
1642c9710b42Smrg		FcPatternObjectAddString (p, FC_PRGNAME_OBJECT, prgname);
1643c9710b42Smrg	}
16442c393a42Smrg    }
16452c393a42Smrg
16466fc018e4Smrg    nobjs = FC_MAX_BASE_OBJECT + config->maxObjects + 2;
1647cc1bebd6Smrg    value = (FcValueList **) malloc (sizeof(void *) * nobjs);
16486fc018e4Smrg    if (!value)
16496fc018e4Smrg    {
16506fc018e4Smrg	retval = FcFalse;
16516fc018e4Smrg	goto bail1;
16526fc018e4Smrg    }
1653cc1bebd6Smrg    elt = (FcPatternElt **) malloc (sizeof(void *) * nobjs);
16546fc018e4Smrg    if (!elt)
16556fc018e4Smrg    {
16566fc018e4Smrg	retval = FcFalse;
16576fc018e4Smrg	goto bail1;
16586fc018e4Smrg    }
1659cc1bebd6Smrg    tst = (FcTest **) malloc (sizeof(void *) * nobjs);
16606fc018e4Smrg    if (!tst)
16616fc018e4Smrg    {
16626fc018e4Smrg	retval = FcFalse;
16636fc018e4Smrg	goto bail1;
16646fc018e4Smrg    }
16652c393a42Smrg
16662c393a42Smrg    if (FcDebug () & FC_DBG_EDIT)
16672c393a42Smrg    {
16682c393a42Smrg	printf ("FcConfigSubstitute ");
16692c393a42Smrg	FcPatternPrint (p);
16702c393a42Smrg    }
16711887081fSmrg    FcPtrListIterInit (s, &iter);
16721887081fSmrg    for (; FcPtrListIterIsValid (s, &iter); FcPtrListIterNext (s, &iter))
16732c393a42Smrg    {
16741887081fSmrg	rs = (FcRuleSet *) FcPtrListIterGetValue (s, &iter);
16751887081fSmrg	if (FcDebug () & FC_DBG_EDIT)
16762c393a42Smrg	{
16771887081fSmrg	    printf ("\nRule Set: %s\n", rs->name);
16786fc018e4Smrg	}
16791887081fSmrg	FcPtrListIterInit (rs->subst[kind], &iter2);
16801887081fSmrg	for (; FcPtrListIterIsValid (rs->subst[kind], &iter2); FcPtrListIterNext (rs->subst[kind], &iter2))
16816fc018e4Smrg	{
16821887081fSmrg	    r = (FcRule *) FcPtrListIterGetValue (rs->subst[kind], &iter2);
16831887081fSmrg	    for (i = 0; i < nobjs; i++)
16841887081fSmrg	    {
16851887081fSmrg		elt[i] = NULL;
16861887081fSmrg		value[i] = NULL;
16871887081fSmrg		tst[i] = NULL;
16881887081fSmrg	    }
16891887081fSmrg	    for (; r; r = r->next)
16901887081fSmrg	    {
16911887081fSmrg		switch (r->type) {
16921887081fSmrg		case FcRuleUnknown:
16931887081fSmrg		    /* shouldn't be reached */
16941887081fSmrg		    break;
16951887081fSmrg		case FcRuleTest:
16961887081fSmrg		    object = FC_OBJ_ID (r->u.test->object);
16971887081fSmrg		    /*
16981887081fSmrg		     * Check the tests to see if
16991887081fSmrg		     * they all match the pattern
17001887081fSmrg		     */
17011887081fSmrg		    if (FcDebug () & FC_DBG_EDIT)
17026fc018e4Smrg		    {
17031887081fSmrg			printf ("FcConfigSubstitute test ");
17041887081fSmrg			FcTestPrint (r->u.test);
17056fc018e4Smrg		    }
17061887081fSmrg		    if (kind == FcMatchFont && r->u.test->kind == FcMatchPattern)
17071887081fSmrg			m = p_pat;
17086fc018e4Smrg		    else
17091887081fSmrg			m = p;
17101887081fSmrg		    if (m)
17111887081fSmrg			e = FcPatternObjectFindElt (m, r->u.test->object);
17121887081fSmrg		    else
17131887081fSmrg			e = NULL;
17141887081fSmrg		    /* different 'kind' won't be the target of edit */
17151887081fSmrg		    if (!elt[object] && kind == r->u.test->kind)
17161887081fSmrg		    {
17171887081fSmrg			elt[object] = e;
17181887081fSmrg			tst[object] = r->u.test;
17191887081fSmrg		    }
17201887081fSmrg		    /*
17211887081fSmrg		     * If there's no such field in the font,
17221887081fSmrg		     * then FcQualAll matches while FcQualAny does not
17231887081fSmrg		     */
17241887081fSmrg		    if (!e)
17251887081fSmrg		    {
17261887081fSmrg			if (r->u.test->qual == FcQualAll)
17271887081fSmrg			{
17281887081fSmrg			    value[object] = NULL;
17291887081fSmrg			    continue;
17301887081fSmrg			}
17311887081fSmrg			else
17321887081fSmrg			{
17331887081fSmrg			    if (FcDebug () & FC_DBG_EDIT)
17341887081fSmrg				printf ("No match\n");
17351887081fSmrg			    goto bail;
17361887081fSmrg			}
17371887081fSmrg		    }
17381887081fSmrg		    /*
17391887081fSmrg		     * Check to see if there is a match, mark the location
17401887081fSmrg		     * to apply match-relative edits
17411887081fSmrg		     */
17421887081fSmrg		    vl = FcConfigMatchValueList (m, p_pat, kind, r->u.test, e->values);
17431887081fSmrg		    /* different 'kind' won't be the target of edit */
17441887081fSmrg		    if (!value[object] && kind == r->u.test->kind)
17451887081fSmrg			value[object] = vl;
17461887081fSmrg		    if (!vl ||
17471887081fSmrg			(r->u.test->qual == FcQualFirst && vl != e->values) ||
17481887081fSmrg			(r->u.test->qual == FcQualNotFirst && vl == e->values))
17496fc018e4Smrg		    {
17506fc018e4Smrg			if (FcDebug () & FC_DBG_EDIT)
17516fc018e4Smrg			    printf ("No match\n");
17526fc018e4Smrg			goto bail;
17536fc018e4Smrg		    }
17541887081fSmrg		    break;
17551887081fSmrg		case FcRuleEdit:
17561887081fSmrg		    object = FC_OBJ_ID (r->u.edit->object);
17576fc018e4Smrg		    if (FcDebug () & FC_DBG_EDIT)
17581887081fSmrg		    {
17591887081fSmrg			printf ("Substitute ");
17601887081fSmrg			FcEditPrint (r->u.edit);
17611887081fSmrg			printf ("\n\n");
17621887081fSmrg		    }
17632c393a42Smrg		    /*
17641887081fSmrg		     * Evaluate the list of expressions
17652c393a42Smrg		     */
17661887081fSmrg		    l = FcConfigValues (p, p_pat,kind,  r->u.edit->expr, r->u.edit->binding);
17671887081fSmrg		    if (tst[object] && (tst[object]->kind == FcMatchFont || kind == FcMatchPattern))
17681887081fSmrg			elt[object] = FcPatternObjectFindElt (p, tst[object]->object);
17696fc018e4Smrg
17701887081fSmrg		    switch (FC_OP_GET_OP (r->u.edit->op)) {
17711887081fSmrg		    case FcOpAssign:
17726fc018e4Smrg			/*
17731887081fSmrg			 * If there was a test, then replace the matched
17741887081fSmrg			 * value with the new list of values
17756fc018e4Smrg			 */
17761887081fSmrg			if (value[object])
17771887081fSmrg			{
17781887081fSmrg			    FcValueList	*thisValue = value[object];
17791887081fSmrg			    FcValueList	*nextValue = l;
17801887081fSmrg
17811887081fSmrg			    /*
17821887081fSmrg			     * Append the new list of values after the current value
17831887081fSmrg			     */
17841887081fSmrg			    FcConfigAdd (&elt[object]->values, thisValue, FcTrue, l, r->u.edit->object);
17851887081fSmrg			    /*
17861887081fSmrg			     * Delete the marked value
17871887081fSmrg			     */
17881887081fSmrg			    if (thisValue)
17891887081fSmrg				FcConfigDel (&elt[object]->values, thisValue);
17901887081fSmrg			    /*
17911887081fSmrg			     * Adjust a pointer into the value list to ensure
17921887081fSmrg			     * future edits occur at the same place
17931887081fSmrg			     */
17941887081fSmrg			    value[object] = nextValue;
17951887081fSmrg			    break;
17961887081fSmrg			}
17971887081fSmrg			/* fall through ... */
17981887081fSmrg		    case FcOpAssignReplace:
17996fc018e4Smrg			/*
18001887081fSmrg			 * Delete all of the values and insert
18011887081fSmrg			 * the new set
18026fc018e4Smrg			 */
18031887081fSmrg			FcConfigPatternDel (p, r->u.edit->object);
18041887081fSmrg			FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue);
18056fc018e4Smrg			/*
18061887081fSmrg			 * Adjust a pointer into the value list as they no
18071887081fSmrg			 * longer point to anything valid
18086fc018e4Smrg			 */
18091887081fSmrg			value[object] = NULL;
18106fc018e4Smrg			break;
18111887081fSmrg		    case FcOpPrepend:
18121887081fSmrg			if (value[object])
18131887081fSmrg			{
18141887081fSmrg			    FcConfigAdd (&elt[object]->values, value[object], FcFalse, l, r->u.edit->object);
18151887081fSmrg			    break;
18161887081fSmrg			}
18171887081fSmrg			/* fall through ... */
18181887081fSmrg		    case FcOpPrependFirst:
18191887081fSmrg			FcConfigPatternAdd (p, r->u.edit->object, l, FcFalse);
18206fc018e4Smrg			break;
18211887081fSmrg		    case FcOpAppend:
18221887081fSmrg			if (value[object])
18231887081fSmrg			{
18241887081fSmrg			    FcConfigAdd (&elt[object]->values, value[object], FcTrue, l, r->u.edit->object);
18251887081fSmrg			    break;
18261887081fSmrg			}
18271887081fSmrg			/* fall through ... */
18281887081fSmrg		    case FcOpAppendLast:
18291887081fSmrg			FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue);
18301887081fSmrg			break;
18311887081fSmrg		    case FcOpDelete:
18321887081fSmrg			if (value[object])
18331887081fSmrg			{
18341887081fSmrg			    FcConfigDel (&elt[object]->values, value[object]);
18351887081fSmrg			    FcValueListDestroy (l);
18361887081fSmrg			    break;
18371887081fSmrg			}
18381887081fSmrg			/* fall through ... */
18391887081fSmrg		    case FcOpDeleteAll:
18401887081fSmrg			FcConfigPatternDel (p, r->u.edit->object);
18411887081fSmrg			FcValueListDestroy (l);
18421887081fSmrg			break;
18431887081fSmrg		    default:
18441887081fSmrg			FcValueListDestroy (l);
18456fc018e4Smrg			break;
18462c393a42Smrg		    }
18471887081fSmrg		    /*
18481887081fSmrg		     * Now go through the pattern and eliminate
18491887081fSmrg		     * any properties without data
18501887081fSmrg		     */
18511887081fSmrg		    FcConfigPatternCanon (p, r->u.edit->object);
18521887081fSmrg
18531887081fSmrg		    if (FcDebug () & FC_DBG_EDIT)
18546fc018e4Smrg		    {
18551887081fSmrg			printf ("FcConfigSubstitute edit");
18561887081fSmrg			FcPatternPrint (p);
18576fc018e4Smrg		    }
18582c393a42Smrg		    break;
18592c393a42Smrg		}
18602c393a42Smrg	    }
18611887081fSmrg	bail:;
18622c393a42Smrg	}
18632c393a42Smrg    }
18642c393a42Smrg    if (FcDebug () & FC_DBG_EDIT)
18652c393a42Smrg    {
18662c393a42Smrg	printf ("FcConfigSubstitute done");
18672c393a42Smrg	FcPatternPrint (p);
18682c393a42Smrg    }
18696fc018e4Smrgbail1:
18706fc018e4Smrg    if (elt)
18716fc018e4Smrg	free (elt);
18726fc018e4Smrg    if (value)
18736fc018e4Smrg	free (value);
18746fc018e4Smrg    if (tst)
18756fc018e4Smrg	free (tst);
18766fc018e4Smrg
18776fc018e4Smrg    return retval;
18782c393a42Smrg}
18792c393a42Smrg
18802c393a42SmrgFcBool
18812c393a42SmrgFcConfigSubstitute (FcConfig	*config,
18822c393a42Smrg		    FcPattern	*p,
18832c393a42Smrg		    FcMatchKind	kind)
18842c393a42Smrg{
18852c393a42Smrg    return FcConfigSubstituteWithPat (config, p, 0, kind);
18862c393a42Smrg}
18872c393a42Smrg
18882c393a42Smrg#if defined (_WIN32)
18892c393a42Smrg
1890c9710b42Smrgstatic FcChar8 fontconfig_path[1000] = ""; /* MT-dontcare */
189118bd4a06SmrgFcChar8 fontconfig_instprefix[1000] = ""; /* MT-dontcare */
18922c393a42Smrg
18932c393a42Smrg#  if (defined (PIC) || defined (DLL_EXPORT))
18942c393a42Smrg
1895c9710b42SmrgBOOL WINAPI
1896c9710b42SmrgDllMain (HINSTANCE hinstDLL,
1897c9710b42Smrg	 DWORD     fdwReason,
1898c9710b42Smrg	 LPVOID    lpvReserved);
1899c9710b42Smrg
19002c393a42SmrgBOOL WINAPI
19012c393a42SmrgDllMain (HINSTANCE hinstDLL,
19022c393a42Smrg	 DWORD     fdwReason,
19032c393a42Smrg	 LPVOID    lpvReserved)
19042c393a42Smrg{
19052c393a42Smrg  FcChar8 *p;
19062c393a42Smrg
19072c393a42Smrg  switch (fdwReason) {
19082c393a42Smrg  case DLL_PROCESS_ATTACH:
1909ca08ab68Smrg      if (!GetModuleFileName ((HMODULE) hinstDLL, (LPCH) fontconfig_path,
19102c393a42Smrg			      sizeof (fontconfig_path)))
19112c393a42Smrg	  break;
19122c393a42Smrg
19132c393a42Smrg      /* If the fontconfig DLL is in a "bin" or "lib" subfolder,
19142c393a42Smrg       * assume it's a Unix-style installation tree, and use
19152c393a42Smrg       * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the
19162c393a42Smrg       * folder where the DLL is as FONTCONFIG_PATH.
19172c393a42Smrg       */
1918ca08ab68Smrg      p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\');
19192c393a42Smrg      if (p)
19202c393a42Smrg      {
19212c393a42Smrg	  *p = '\0';
1922ca08ab68Smrg	  p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\');
1923ca08ab68Smrg	  if (p && (FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "bin") == 0 ||
1924ca08ab68Smrg		    FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "lib") == 0))
19252c393a42Smrg	      *p = '\0';
192618bd4a06Smrg	  strcat ((char *) fontconfig_instprefix, (char *) fontconfig_path);
1927ca08ab68Smrg	  strcat ((char *) fontconfig_path, "\\etc\\fonts");
19282c393a42Smrg      }
19292c393a42Smrg      else
19302c393a42Smrg          fontconfig_path[0] = '\0';
1931ca08ab68Smrg
19322c393a42Smrg      break;
19332c393a42Smrg  }
19342c393a42Smrg
19352c393a42Smrg  return TRUE;
19362c393a42Smrg}
19372c393a42Smrg
19382c393a42Smrg#  endif /* !PIC */
19392c393a42Smrg
19402c393a42Smrg#undef FONTCONFIG_PATH
19412c393a42Smrg#define FONTCONFIG_PATH fontconfig_path
19422c393a42Smrg
19432c393a42Smrg#endif /* !_WIN32 */
19442c393a42Smrg
19452c393a42Smrg#ifndef FONTCONFIG_FILE
19462c393a42Smrg#define FONTCONFIG_FILE	"fonts.conf"
19472c393a42Smrg#endif
19482c393a42Smrg
19492c393a42Smrgstatic FcChar8 *
19502c393a42SmrgFcConfigFileExists (const FcChar8 *dir, const FcChar8 *file)
19512c393a42Smrg{
19522c393a42Smrg    FcChar8    *path;
1953ca08ab68Smrg    int         size, osize;
19542c393a42Smrg
19552c393a42Smrg    if (!dir)
19562c393a42Smrg	dir = (FcChar8 *) "";
1957ca08ab68Smrg
1958ca08ab68Smrg    osize = strlen ((char *) dir) + 1 + strlen ((char *) file) + 1;
1959ca08ab68Smrg    /*
1960ca08ab68Smrg     * workaround valgrind warning because glibc takes advantage of how it knows memory is
1961ca08ab68Smrg     * allocated to implement strlen by reading in groups of 4
1962ca08ab68Smrg     */
1963ca08ab68Smrg    size = (osize + 3) & ~3;
1964ca08ab68Smrg
1965ca08ab68Smrg    path = malloc (size);
19662c393a42Smrg    if (!path)
19672c393a42Smrg	return 0;
19682c393a42Smrg
19692c393a42Smrg    strcpy ((char *) path, (const char *) dir);
19702c393a42Smrg    /* make sure there's a single separator */
19712c393a42Smrg#ifdef _WIN32
19722c393a42Smrg    if ((!path[0] || (path[strlen((char *) path)-1] != '/' &&
19732c393a42Smrg		      path[strlen((char *) path)-1] != '\\')) &&
19742c393a42Smrg	!(file[0] == '/' ||
19752c393a42Smrg	  file[0] == '\\' ||
19762c393a42Smrg	  (isalpha (file[0]) && file[1] == ':' && (file[2] == '/' || file[2] == '\\'))))
19772c393a42Smrg	strcat ((char *) path, "\\");
19782c393a42Smrg#else
19792c393a42Smrg    if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/')
19802c393a42Smrg	strcat ((char *) path, "/");
1981c9710b42Smrg    else
1982c9710b42Smrg	osize--;
19832c393a42Smrg#endif
19842c393a42Smrg    strcat ((char *) path, (char *) file);
19852c393a42Smrg
19862c393a42Smrg    if (access ((char *) path, R_OK) == 0)
19872c393a42Smrg	return path;
1988ca08ab68Smrg
19892c393a42Smrg    FcStrFree (path);
1990ca08ab68Smrg
19912c393a42Smrg    return 0;
19922c393a42Smrg}
19932c393a42Smrg
19942c393a42Smrgstatic FcChar8 **
19952c393a42SmrgFcConfigGetPath (void)
19962c393a42Smrg{
19972c393a42Smrg    FcChar8    **path;
19982c393a42Smrg    FcChar8    *env, *e, *colon;
19992c393a42Smrg    FcChar8    *dir;
20002c393a42Smrg    int	    npath;
20012c393a42Smrg    int	    i;
20022c393a42Smrg
20032c393a42Smrg    npath = 2;	/* default dir + null */
20042c393a42Smrg    env = (FcChar8 *) getenv ("FONTCONFIG_PATH");
20052c393a42Smrg    if (env)
20062c393a42Smrg    {
20072c393a42Smrg	e = env;
20082c393a42Smrg	npath++;
20092c393a42Smrg	while (*e)
20102c393a42Smrg	    if (*e++ == FC_SEARCH_PATH_SEPARATOR)
20112c393a42Smrg		npath++;
20122c393a42Smrg    }
20132c393a42Smrg    path = calloc (npath, sizeof (FcChar8 *));
20142c393a42Smrg    if (!path)
20152c393a42Smrg	goto bail0;
20162c393a42Smrg    i = 0;
20172c393a42Smrg
20182c393a42Smrg    if (env)
20192c393a42Smrg    {
20202c393a42Smrg	e = env;
2021ca08ab68Smrg	while (*e)
20222c393a42Smrg	{
20232c393a42Smrg	    colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR);
20242c393a42Smrg	    if (!colon)
20252c393a42Smrg		colon = e + strlen ((char *) e);
20262c393a42Smrg	    path[i] = malloc (colon - e + 1);
20272c393a42Smrg	    if (!path[i])
20282c393a42Smrg		goto bail1;
20292c393a42Smrg	    strncpy ((char *) path[i], (const char *) e, colon - e);
20302c393a42Smrg	    path[i][colon - e] = '\0';
20312c393a42Smrg	    if (*colon)
20322c393a42Smrg		e = colon + 1;
20332c393a42Smrg	    else
20342c393a42Smrg		e = colon;
20352c393a42Smrg	    i++;
20362c393a42Smrg	}
20372c393a42Smrg    }
2038ca08ab68Smrg
20392c393a42Smrg#ifdef _WIN32
20402c393a42Smrg	if (fontconfig_path[0] == '\0')
20412c393a42Smrg	{
2042a6844aabSmrg		char *p;
2043ca08ab68Smrg		if(!GetModuleFileName(NULL, (LPCH) fontconfig_path, sizeof(fontconfig_path)))
20442c393a42Smrg			goto bail1;
2045ca08ab68Smrg		p = strrchr ((const char *) fontconfig_path, '\\');
20462c393a42Smrg		if (p) *p = '\0';
2047ca08ab68Smrg		strcat ((char *) fontconfig_path, "\\fonts");
20482c393a42Smrg	}
20492c393a42Smrg#endif
20502c393a42Smrg    dir = (FcChar8 *) FONTCONFIG_PATH;
20512c393a42Smrg    path[i] = malloc (strlen ((char *) dir) + 1);
20522c393a42Smrg    if (!path[i])
20532c393a42Smrg	goto bail1;
20542c393a42Smrg    strcpy ((char *) path[i], (const char *) dir);
20552c393a42Smrg    return path;
20562c393a42Smrg
20572c393a42Smrgbail1:
20582c393a42Smrg    for (i = 0; path[i]; i++)
20592c393a42Smrg	free (path[i]);
20602c393a42Smrg    free (path);
20612c393a42Smrgbail0:
20622c393a42Smrg    return 0;
20632c393a42Smrg}
20642c393a42Smrg
20652c393a42Smrgstatic void
20662c393a42SmrgFcConfigFreePath (FcChar8 **path)
20672c393a42Smrg{
20682c393a42Smrg    FcChar8    **p;
20692c393a42Smrg
20702c393a42Smrg    for (p = path; *p; p++)
20712c393a42Smrg	free (*p);
20722c393a42Smrg    free (path);
20732c393a42Smrg}
20742c393a42Smrg
2075c9710b42Smrgstatic FcBool	_FcConfigHomeEnabled = FcTrue; /* MT-goodenough */
20762c393a42Smrg
20772c393a42SmrgFcChar8 *
20782c393a42SmrgFcConfigHome (void)
20792c393a42Smrg{
20802c393a42Smrg    if (_FcConfigHomeEnabled)
20812c393a42Smrg    {
20822c393a42Smrg        char *home = getenv ("HOME");
20832c393a42Smrg
20842c393a42Smrg#ifdef _WIN32
20852c393a42Smrg	if (home == NULL)
20862c393a42Smrg	    home = getenv ("USERPROFILE");
20872c393a42Smrg#endif
20882c393a42Smrg
20892c393a42Smrg	return (FcChar8 *) home;
20902c393a42Smrg    }
20912c393a42Smrg    return 0;
20922c393a42Smrg}
20932c393a42Smrg
2094ca08ab68SmrgFcChar8 *
2095ca08ab68SmrgFcConfigXdgCacheHome (void)
2096ca08ab68Smrg{
2097ca08ab68Smrg    const char *env = getenv ("XDG_CACHE_HOME");
2098ca08ab68Smrg    FcChar8 *ret = NULL;
2099ca08ab68Smrg
210018bd4a06Smrg    if (!_FcConfigHomeEnabled)
210118bd4a06Smrg	return NULL;
2102ca08ab68Smrg    if (env)
2103ca08ab68Smrg	ret = FcStrCopy ((const FcChar8 *)env);
2104ca08ab68Smrg    else
2105ca08ab68Smrg    {
2106ca08ab68Smrg	const FcChar8 *home = FcConfigHome ();
2107ca08ab68Smrg	size_t len = home ? strlen ((const char *)home) : 0;
2108ca08ab68Smrg
2109ca08ab68Smrg	ret = malloc (len + 7 + 1);
2110ca08ab68Smrg	if (ret)
2111ca08ab68Smrg	{
21121887081fSmrg	    if (home)
21131887081fSmrg		memcpy (ret, home, len);
2114ca08ab68Smrg	    memcpy (&ret[len], FC_DIR_SEPARATOR_S ".cache", 7);
2115ca08ab68Smrg	    ret[len + 7] = 0;
2116ca08ab68Smrg	}
2117ca08ab68Smrg    }
2118ca08ab68Smrg
2119ca08ab68Smrg    return ret;
2120ca08ab68Smrg}
2121ca08ab68Smrg
2122ca08ab68SmrgFcChar8 *
2123ca08ab68SmrgFcConfigXdgConfigHome (void)
2124ca08ab68Smrg{
2125ca08ab68Smrg    const char *env = getenv ("XDG_CONFIG_HOME");
2126ca08ab68Smrg    FcChar8 *ret = NULL;
2127ca08ab68Smrg
212818bd4a06Smrg    if (!_FcConfigHomeEnabled)
212918bd4a06Smrg	return NULL;
2130ca08ab68Smrg    if (env)
2131ca08ab68Smrg	ret = FcStrCopy ((const FcChar8 *)env);
2132ca08ab68Smrg    else
2133ca08ab68Smrg    {
2134ca08ab68Smrg	const FcChar8 *home = FcConfigHome ();
2135ca08ab68Smrg	size_t len = home ? strlen ((const char *)home) : 0;
2136ca08ab68Smrg
2137ca08ab68Smrg	ret = malloc (len + 8 + 1);
2138ca08ab68Smrg	if (ret)
2139ca08ab68Smrg	{
21401887081fSmrg	    if (home)
21411887081fSmrg		memcpy (ret, home, len);
2142ca08ab68Smrg	    memcpy (&ret[len], FC_DIR_SEPARATOR_S ".config", 8);
2143ca08ab68Smrg	    ret[len + 8] = 0;
2144ca08ab68Smrg	}
2145ca08ab68Smrg    }
2146ca08ab68Smrg
2147ca08ab68Smrg    return ret;
2148ca08ab68Smrg}
2149ca08ab68Smrg
2150ca08ab68SmrgFcChar8 *
2151ca08ab68SmrgFcConfigXdgDataHome (void)
2152ca08ab68Smrg{
2153ca08ab68Smrg    const char *env = getenv ("XDG_DATA_HOME");
2154ca08ab68Smrg    FcChar8 *ret = NULL;
2155ca08ab68Smrg
215618bd4a06Smrg    if (!_FcConfigHomeEnabled)
215718bd4a06Smrg	return NULL;
2158ca08ab68Smrg    if (env)
2159ca08ab68Smrg	ret = FcStrCopy ((const FcChar8 *)env);
2160ca08ab68Smrg    else
2161ca08ab68Smrg    {
2162ca08ab68Smrg	const FcChar8 *home = FcConfigHome ();
2163ca08ab68Smrg	size_t len = home ? strlen ((const char *)home) : 0;
2164ca08ab68Smrg
2165ca08ab68Smrg	ret = malloc (len + 13 + 1);
2166ca08ab68Smrg	if (ret)
2167ca08ab68Smrg	{
21681887081fSmrg	    if (home)
21691887081fSmrg		memcpy (ret, home, len);
2170ca08ab68Smrg	    memcpy (&ret[len], FC_DIR_SEPARATOR_S ".local" FC_DIR_SEPARATOR_S "share", 13);
2171ca08ab68Smrg	    ret[len + 13] = 0;
2172ca08ab68Smrg	}
2173ca08ab68Smrg    }
2174ca08ab68Smrg
2175ca08ab68Smrg    return ret;
2176ca08ab68Smrg}
2177ca08ab68Smrg
21782c393a42SmrgFcBool
21792c393a42SmrgFcConfigEnableHome (FcBool enable)
21802c393a42Smrg{
21812c393a42Smrg    FcBool  prev = _FcConfigHomeEnabled;
21822c393a42Smrg    _FcConfigHomeEnabled = enable;
21832c393a42Smrg    return prev;
21842c393a42Smrg}
21852c393a42Smrg
21862c393a42SmrgFcChar8 *
21872c393a42SmrgFcConfigFilename (const FcChar8 *url)
21882c393a42Smrg{
21892c393a42Smrg    FcChar8    *file, *dir, **path, **p;
21902c393a42Smrg
21912c393a42Smrg    if (!url || !*url)
21922c393a42Smrg    {
21932c393a42Smrg	url = (FcChar8 *) getenv ("FONTCONFIG_FILE");
21942c393a42Smrg	if (!url)
21952c393a42Smrg	    url = (FcChar8 *) FONTCONFIG_FILE;
21962c393a42Smrg    }
21972c393a42Smrg    file = 0;
21982c393a42Smrg
21991887081fSmrg    if (FcStrIsAbsoluteFilename(url))
22001887081fSmrg	return FcConfigFileExists (0, url);
22012c393a42Smrg
22021887081fSmrg    if (*url == '~')
22031887081fSmrg    {
22042c393a42Smrg	dir = FcConfigHome ();
22052c393a42Smrg	if (dir)
22062c393a42Smrg	    file = FcConfigFileExists (dir, url + 1);
22072c393a42Smrg	else
22082c393a42Smrg	    file = 0;
22091887081fSmrg    }
22101887081fSmrg
22111887081fSmrg    path = FcConfigGetPath ();
22121887081fSmrg    if (!path)
22131887081fSmrg	return NULL;
22141887081fSmrg    for (p = path; *p; p++)
22151887081fSmrg    {
22161887081fSmrg	file = FcConfigFileExists (*p, url);
22171887081fSmrg	if (file)
22181887081fSmrg	    break;
22191887081fSmrg    }
22201887081fSmrg    FcConfigFreePath (path);
22211887081fSmrg    return file;
22221887081fSmrg}
22231887081fSmrg
22241887081fSmrgFcChar8 *
22251887081fSmrgFcConfigRealFilename (FcConfig		*config,
22261887081fSmrg		      const FcChar8	*url)
22271887081fSmrg{
22281887081fSmrg    const FcChar8 *sysroot = FcConfigGetSysRoot (config);
22291887081fSmrg    FcChar8 *n = FcConfigFilename (url);
22301887081fSmrg    FcChar8 *nn = NULL;
22311887081fSmrg
22321887081fSmrg    if (n)
22331887081fSmrg    {
22341887081fSmrg	FcChar8 buf[PATH_MAX];
22351887081fSmrg	ssize_t len;
22361887081fSmrg
22371887081fSmrg	if (sysroot)
22381887081fSmrg	    nn = FcStrBuildFilename (sysroot, n, NULL);
22391887081fSmrg	else
22401887081fSmrg	    nn = FcStrdup (n);
22411887081fSmrg	FcStrFree (n);
22421887081fSmrg
22431887081fSmrg	if ((len = FcReadLink (nn, buf, sizeof (buf) - 1)) != -1)
22442c393a42Smrg	{
22451887081fSmrg	    buf[len] = 0;
22461887081fSmrg
22471887081fSmrg	    if (!FcStrIsAbsoluteFilename (buf))
22481887081fSmrg	    {
22491887081fSmrg		FcChar8 *dirname = FcStrDirname (nn);
22501887081fSmrg		FcStrFree (nn);
22511887081fSmrg		if (!dirname)
22521887081fSmrg		    return NULL;
22531887081fSmrg
22541887081fSmrg		FcChar8 *path = FcStrBuildFilename (dirname, buf, NULL);
22551887081fSmrg		FcStrFree (dirname);
22561887081fSmrg		if (!path)
22571887081fSmrg		    return NULL;
22581887081fSmrg
22591887081fSmrg		nn = FcStrCanonFilename (path);
22601887081fSmrg		FcStrFree (path);
22611887081fSmrg	    }
22621887081fSmrg	    else
22631887081fSmrg	    {
22641887081fSmrg		FcStrFree (nn);
22651887081fSmrg		nn = FcStrdup (buf);
22661887081fSmrg	    }
22672c393a42Smrg	}
22682c393a42Smrg    }
2269ca08ab68Smrg
22701887081fSmrg    return nn;
22712c393a42Smrg}
22722c393a42Smrg
22732c393a42Smrg/*
22742c393a42Smrg * Manage the application-specific fonts
22752c393a42Smrg */
22762c393a42Smrg
22772c393a42SmrgFcBool
22782c393a42SmrgFcConfigAppFontAddFile (FcConfig    *config,
22792c393a42Smrg			const FcChar8  *file)
22802c393a42Smrg{
22812c393a42Smrg    FcFontSet	*set;
22822c393a42Smrg    FcStrSet	*subdirs;
22832c393a42Smrg    FcStrList	*sublist;
22842c393a42Smrg    FcChar8	*subdir;
22852c393a42Smrg
22862c393a42Smrg    if (!config)
22872c393a42Smrg    {
22882c393a42Smrg	config = FcConfigGetCurrent ();
22892c393a42Smrg	if (!config)
22902c393a42Smrg	    return FcFalse;
22912c393a42Smrg    }
22922c393a42Smrg
229318bd4a06Smrg    subdirs = FcStrSetCreateEx (FCSS_GROW_BY_64);
22942c393a42Smrg    if (!subdirs)
22952c393a42Smrg	return FcFalse;
2296ca08ab68Smrg
22972c393a42Smrg    set = FcConfigGetFonts (config, FcSetApplication);
22982c393a42Smrg    if (!set)
22992c393a42Smrg    {
23002c393a42Smrg	set = FcFontSetCreate ();
23012c393a42Smrg	if (!set)
23022c393a42Smrg	{
23032c393a42Smrg	    FcStrSetDestroy (subdirs);
23042c393a42Smrg	    return FcFalse;
23052c393a42Smrg	}
23062c393a42Smrg	FcConfigSetFonts (config, set, FcSetApplication);
23072c393a42Smrg    }
23082c393a42Smrg
23091887081fSmrg    if (!FcFileScanConfig (set, subdirs, file, config))
23102c393a42Smrg    {
23112c393a42Smrg	FcStrSetDestroy (subdirs);
23122c393a42Smrg	return FcFalse;
23132c393a42Smrg    }
23142c393a42Smrg    if ((sublist = FcStrListCreate (subdirs)))
23152c393a42Smrg    {
23162c393a42Smrg	while ((subdir = FcStrListNext (sublist)))
23172c393a42Smrg	{
23182c393a42Smrg	    FcConfigAppFontAddDir (config, subdir);
23192c393a42Smrg	}
23202c393a42Smrg	FcStrListDone (sublist);
23212c393a42Smrg    }
23222c393a42Smrg    FcStrSetDestroy (subdirs);
23232c393a42Smrg    return FcTrue;
23242c393a42Smrg}
23252c393a42Smrg
23262c393a42SmrgFcBool
23272c393a42SmrgFcConfigAppFontAddDir (FcConfig	    *config,
23282c393a42Smrg		       const FcChar8   *dir)
23292c393a42Smrg{
23302c393a42Smrg    FcFontSet	*set;
23312c393a42Smrg    FcStrSet	*dirs;
2332ca08ab68Smrg
23332c393a42Smrg    if (!config)
23342c393a42Smrg    {
23352c393a42Smrg	config = FcConfigGetCurrent ();
23362c393a42Smrg	if (!config)
23372c393a42Smrg	    return FcFalse;
23382c393a42Smrg    }
23392c393a42Smrg
234018bd4a06Smrg    dirs = FcStrSetCreateEx (FCSS_GROW_BY_64);
23412c393a42Smrg    if (!dirs)
23422c393a42Smrg	return FcFalse;
2343ca08ab68Smrg
23442c393a42Smrg    set = FcConfigGetFonts (config, FcSetApplication);
23452c393a42Smrg    if (!set)
23462c393a42Smrg    {
23472c393a42Smrg	set = FcFontSetCreate ();
23482c393a42Smrg	if (!set)
23492c393a42Smrg	{
23502c393a42Smrg	    FcStrSetDestroy (dirs);
23512c393a42Smrg	    return FcFalse;
23522c393a42Smrg	}
23532c393a42Smrg	FcConfigSetFonts (config, set, FcSetApplication);
23542c393a42Smrg    }
2355ca08ab68Smrg
23562c393a42Smrg    FcStrSetAddFilename (dirs, dir);
2357ca08ab68Smrg
23582c393a42Smrg    if (!FcConfigAddDirList (config, FcSetApplication, dirs))
23592c393a42Smrg    {
23602c393a42Smrg	FcStrSetDestroy (dirs);
23612c393a42Smrg	return FcFalse;
23622c393a42Smrg    }
23632c393a42Smrg    FcStrSetDestroy (dirs);
23642c393a42Smrg    return FcTrue;
23652c393a42Smrg}
23662c393a42Smrg
23672c393a42Smrgvoid
23682c393a42SmrgFcConfigAppFontClear (FcConfig	    *config)
23692c393a42Smrg{
23702c393a42Smrg    if (!config)
23712c393a42Smrg    {
23722c393a42Smrg	config = FcConfigGetCurrent ();
23732c393a42Smrg	if (!config)
23742c393a42Smrg	    return;
23752c393a42Smrg    }
23762c393a42Smrg
23772c393a42Smrg    FcConfigSetFonts (config, 0, FcSetApplication);
23782c393a42Smrg}
23792c393a42Smrg
23802c393a42Smrg/*
23812c393a42Smrg * Manage filename-based font source selectors
23822c393a42Smrg */
23832c393a42Smrg
23842c393a42SmrgFcBool
23852c393a42SmrgFcConfigGlobAdd (FcConfig	*config,
23862c393a42Smrg		 const FcChar8  *glob,
23872c393a42Smrg		 FcBool		accept)
23882c393a42Smrg{
23892c393a42Smrg    FcStrSet	*set = accept ? config->acceptGlobs : config->rejectGlobs;
23902c393a42Smrg
23912c393a42Smrg    return FcStrSetAdd (set, glob);
23922c393a42Smrg}
23932c393a42Smrg
23942c393a42Smrgstatic FcBool
23952c393a42SmrgFcConfigGlobsMatch (const FcStrSet	*globs,
23962c393a42Smrg		    const FcChar8	*string)
23972c393a42Smrg{
23982c393a42Smrg    int	i;
23992c393a42Smrg
24002c393a42Smrg    for (i = 0; i < globs->num; i++)
2401c9710b42Smrg	if (FcStrGlobMatch (globs->strs[i], string))
24022c393a42Smrg	    return FcTrue;
24032c393a42Smrg    return FcFalse;
24042c393a42Smrg}
24052c393a42Smrg
24062c393a42SmrgFcBool
24072c393a42SmrgFcConfigAcceptFilename (FcConfig	*config,
24082c393a42Smrg			const FcChar8	*filename)
24092c393a42Smrg{
24102c393a42Smrg    if (FcConfigGlobsMatch (config->acceptGlobs, filename))
24112c393a42Smrg	return FcTrue;
24122c393a42Smrg    if (FcConfigGlobsMatch (config->rejectGlobs, filename))
24132c393a42Smrg	return FcFalse;
24142c393a42Smrg    return FcTrue;
24152c393a42Smrg}
24162c393a42Smrg
24172c393a42Smrg/*
24182c393a42Smrg * Manage font-pattern based font source selectors
24192c393a42Smrg */
24202c393a42Smrg
24212c393a42SmrgFcBool
24222c393a42SmrgFcConfigPatternsAdd (FcConfig	*config,
24232c393a42Smrg		     FcPattern	*pattern,
24242c393a42Smrg		     FcBool	accept)
24252c393a42Smrg{
24262c393a42Smrg    FcFontSet	*set = accept ? config->acceptPatterns : config->rejectPatterns;
24272c393a42Smrg
24282c393a42Smrg    return FcFontSetAdd (set, pattern);
24292c393a42Smrg}
24302c393a42Smrg
24312c393a42Smrgstatic FcBool
24322c393a42SmrgFcConfigPatternsMatch (const FcFontSet	*patterns,
24332c393a42Smrg		       const FcPattern	*font)
24342c393a42Smrg{
24352c393a42Smrg    int i;
2436ca08ab68Smrg
24372c393a42Smrg    for (i = 0; i < patterns->nfont; i++)
24382c393a42Smrg	if (FcListPatternMatchAny (patterns->fonts[i], font))
24392c393a42Smrg	    return FcTrue;
24402c393a42Smrg    return FcFalse;
24412c393a42Smrg}
24422c393a42Smrg
24432c393a42SmrgFcBool
24442c393a42SmrgFcConfigAcceptFont (FcConfig	    *config,
24452c393a42Smrg		    const FcPattern *font)
24462c393a42Smrg{
24472c393a42Smrg    if (FcConfigPatternsMatch (config->acceptPatterns, font))
24482c393a42Smrg	return FcTrue;
24492c393a42Smrg    if (FcConfigPatternsMatch (config->rejectPatterns, font))
24502c393a42Smrg	return FcFalse;
24512c393a42Smrg    return FcTrue;
24522c393a42Smrg}
2453c9710b42Smrg
2454c9710b42Smrgconst FcChar8 *
2455c9710b42SmrgFcConfigGetSysRoot (const FcConfig *config)
2456c9710b42Smrg{
2457c9710b42Smrg    if (!config)
2458c9710b42Smrg    {
2459c9710b42Smrg	config = FcConfigGetCurrent ();
2460c9710b42Smrg	if (!config)
2461c9710b42Smrg	    return NULL;
2462c9710b42Smrg    }
2463c9710b42Smrg
24641887081fSmrg    if (config->sysRoot)
24651887081fSmrg        return config->sysRoot;
24661887081fSmrg
24671887081fSmrg    return (FcChar8 *) getenv ("FONTCONFIG_SYSROOT");
2468c9710b42Smrg}
2469c9710b42Smrg
2470c9710b42Smrgvoid
2471c9710b42SmrgFcConfigSetSysRoot (FcConfig      *config,
2472c9710b42Smrg		    const FcChar8 *sysroot)
2473c9710b42Smrg{
247418bd4a06Smrg    FcChar8 *s = NULL;
2475c9710b42Smrg    FcBool init = FcFalse;
2476c9710b42Smrg
2477c9710b42Smrg    if (!config)
2478c9710b42Smrg    {
2479c9710b42Smrg	/* We can't use FcConfigGetCurrent() here to ensure
2480c9710b42Smrg	 * the sysroot is set prior to initialize FcConfig,
2481c9710b42Smrg	 * to avoid loading caches from non-sysroot dirs.
2482c9710b42Smrg	 * So postpone the initialization later.
2483c9710b42Smrg	 */
2484c9710b42Smrg	config = fc_atomic_ptr_get (&_fcConfig);
2485c9710b42Smrg	if (!config)
2486c9710b42Smrg	{
2487c9710b42Smrg	    config = FcConfigCreate ();
2488c9710b42Smrg	    if (!config)
2489c9710b42Smrg		return;
2490c9710b42Smrg	    init = FcTrue;
2491c9710b42Smrg	}
2492c9710b42Smrg    }
2493c9710b42Smrg
249418bd4a06Smrg    if (sysroot)
249518bd4a06Smrg    {
249618bd4a06Smrg	s = FcStrCopyFilename (sysroot);
249718bd4a06Smrg	if (!s)
249818bd4a06Smrg	    return;
249918bd4a06Smrg    }
2500c9710b42Smrg
2501c9710b42Smrg    if (config->sysRoot)
2502c9710b42Smrg	FcStrFree (config->sysRoot);
2503c9710b42Smrg
2504c9710b42Smrg    config->sysRoot = s;
2505c9710b42Smrg    if (init)
2506c9710b42Smrg    {
2507c9710b42Smrg	config = FcInitLoadOwnConfigAndFonts (config);
2508c9710b42Smrg	FcConfigSetCurrent (config);
250918bd4a06Smrg	/* FcConfigSetCurrent() increases the refcount.
251018bd4a06Smrg	 * decrease it here to avoid the memory leak.
251118bd4a06Smrg	 */
251218bd4a06Smrg	FcConfigDestroy (config);
2513c9710b42Smrg    }
2514c9710b42Smrg}
2515c9710b42Smrg
25161887081fSmrgFcRuleSet *
25171887081fSmrgFcRuleSetCreate (const FcChar8 *name)
25181887081fSmrg{
25191887081fSmrg    FcRuleSet *ret = (FcRuleSet *) malloc (sizeof (FcRuleSet));
25201887081fSmrg    FcMatchKind k;
25211887081fSmrg    const FcChar8 *p;
25221887081fSmrg
25231887081fSmrg    if (!name)
25241887081fSmrg	p = (const FcChar8 *)"";
25251887081fSmrg    else
25261887081fSmrg	p = name;
25271887081fSmrg
25281887081fSmrg    if (ret)
25291887081fSmrg    {
25301887081fSmrg	ret->name = FcStrdup (p);
25311887081fSmrg	ret->description = NULL;
25321887081fSmrg	ret->domain = NULL;
25331887081fSmrg	for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++)
25341887081fSmrg	    ret->subst[k] = FcPtrListCreate (FcDestroyAsRule);
25351887081fSmrg	FcRefInit (&ret->ref, 1);
25361887081fSmrg    }
25371887081fSmrg
25381887081fSmrg    return ret;
25391887081fSmrg}
25401887081fSmrg
25411887081fSmrgvoid
25421887081fSmrgFcRuleSetDestroy (FcRuleSet *rs)
25431887081fSmrg{
25441887081fSmrg    FcMatchKind k;
25451887081fSmrg
25461887081fSmrg    if (!rs)
25471887081fSmrg	return;
25481887081fSmrg    if (FcRefDec (&rs->ref) != 1)
25491887081fSmrg	return;
25501887081fSmrg
25511887081fSmrg    if (rs->name)
25521887081fSmrg	FcStrFree (rs->name);
25531887081fSmrg    if (rs->description)
25541887081fSmrg	FcStrFree (rs->description);
25551887081fSmrg    if (rs->domain)
25561887081fSmrg	FcStrFree (rs->domain);
25571887081fSmrg    for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++)
25581887081fSmrg	FcPtrListDestroy (rs->subst[k]);
25591887081fSmrg
25601887081fSmrg    free (rs);
25611887081fSmrg}
25621887081fSmrg
25631887081fSmrgvoid
25641887081fSmrgFcRuleSetReference (FcRuleSet *rs)
25651887081fSmrg{
25661887081fSmrg    if (!FcRefIsConst (&rs->ref))
25671887081fSmrg	FcRefInc (&rs->ref);
25681887081fSmrg}
25691887081fSmrg
25701887081fSmrgvoid
25711887081fSmrgFcRuleSetEnable (FcRuleSet	*rs,
25721887081fSmrg		 FcBool		flag)
25731887081fSmrg{
25741887081fSmrg    if (rs)
25751887081fSmrg    {
25761887081fSmrg	rs->enabled = flag;
25771887081fSmrg	/* XXX: we may want to provide a feature
25781887081fSmrg	 * to enable/disable rulesets through API
25791887081fSmrg	 * in the future?
25801887081fSmrg	 */
25811887081fSmrg    }
25821887081fSmrg}
25831887081fSmrg
25841887081fSmrgvoid
25851887081fSmrgFcRuleSetAddDescription (FcRuleSet	*rs,
25861887081fSmrg			 const FcChar8	*domain,
25871887081fSmrg			 const FcChar8	*description)
25881887081fSmrg{
25891887081fSmrg    if (rs->domain)
25901887081fSmrg	FcStrFree (rs->domain);
25911887081fSmrg    if (rs->description)
25921887081fSmrg	FcStrFree (rs->description);
25931887081fSmrg
25941887081fSmrg    rs->domain = domain ? FcStrdup (domain) : NULL;
25951887081fSmrg    rs->description = description ? FcStrdup (description) : NULL;
25961887081fSmrg}
25971887081fSmrg
25981887081fSmrgint
25991887081fSmrgFcRuleSetAdd (FcRuleSet		*rs,
26001887081fSmrg	      FcRule		*rule,
26011887081fSmrg	      FcMatchKind	kind)
26021887081fSmrg{
26031887081fSmrg    FcPtrListIter iter;
26041887081fSmrg    FcRule *r;
26051887081fSmrg    int n = 0, ret;
26061887081fSmrg
26071887081fSmrg    if (!rs ||
26081887081fSmrg       kind < FcMatchKindBegin || kind >= FcMatchKindEnd)
26091887081fSmrg	return -1;
26101887081fSmrg    FcPtrListIterInitAtLast (rs->subst[kind], &iter);
26111887081fSmrg    if (!FcPtrListIterAdd (rs->subst[kind], &iter, rule))
26121887081fSmrg	return -1;
26131887081fSmrg
26141887081fSmrg    for (r = rule; r; r = r->next)
26151887081fSmrg    {
26161887081fSmrg	switch (r->type)
26171887081fSmrg	{
26181887081fSmrg	case FcRuleTest:
26191887081fSmrg	    if (r->u.test)
26201887081fSmrg	    {
26211887081fSmrg		if (r->u.test->kind == FcMatchDefault)
26221887081fSmrg		    r->u.test->kind = kind;
26231887081fSmrg		if (n < r->u.test->object)
26241887081fSmrg		    n = r->u.test->object;
26251887081fSmrg	    }
26261887081fSmrg	    break;
26271887081fSmrg	case FcRuleEdit:
26281887081fSmrg	    if (n < r->u.edit->object)
26291887081fSmrg		n = r->u.edit->object;
26301887081fSmrg	    break;
26311887081fSmrg	default:
26321887081fSmrg	    break;
26331887081fSmrg	}
26341887081fSmrg    }
26351887081fSmrg    if (FcDebug () & FC_DBG_EDIT)
26361887081fSmrg    {
26371887081fSmrg	printf ("Add Rule(kind:%d, name: %s) ", kind, rs->name);
26381887081fSmrg	FcRulePrint (rule);
26391887081fSmrg    }
26401887081fSmrg    ret = FC_OBJ_ID (n) - FC_MAX_BASE_OBJECT;
26411887081fSmrg
26421887081fSmrg    return ret < 0 ? 0 : ret;
26431887081fSmrg}
26441887081fSmrg
26451887081fSmrgvoid
26461887081fSmrgFcConfigFileInfoIterInit (FcConfig		*config,
26471887081fSmrg			  FcConfigFileInfoIter	*iter)
26481887081fSmrg{
26491887081fSmrg    FcConfig *c;
26501887081fSmrg    FcPtrListIter *i = (FcPtrListIter *)iter;
26511887081fSmrg
26521887081fSmrg    if (!config)
26531887081fSmrg	c = FcConfigGetCurrent ();
26541887081fSmrg    else
26551887081fSmrg	c = config;
26561887081fSmrg    FcPtrListIterInit (c->rulesetList, i);
26571887081fSmrg}
26581887081fSmrg
26591887081fSmrgFcBool
26601887081fSmrgFcConfigFileInfoIterNext (FcConfig		*config,
26611887081fSmrg			  FcConfigFileInfoIter	*iter)
26621887081fSmrg{
26631887081fSmrg    FcConfig *c;
26641887081fSmrg    FcPtrListIter *i = (FcPtrListIter *)iter;
26651887081fSmrg
26661887081fSmrg    if (!config)
26671887081fSmrg	c = FcConfigGetCurrent ();
26681887081fSmrg    else
26691887081fSmrg	c = config;
26701887081fSmrg    if (FcPtrListIterIsValid (c->rulesetList, i))
26711887081fSmrg    {
26721887081fSmrg	FcPtrListIterNext (c->rulesetList, i);
26731887081fSmrg    }
26741887081fSmrg    else
26751887081fSmrg	return FcFalse;
26761887081fSmrg
26771887081fSmrg    return FcTrue;
26781887081fSmrg}
26791887081fSmrg
26801887081fSmrgFcBool
26811887081fSmrgFcConfigFileInfoIterGet (FcConfig		*config,
26821887081fSmrg			 FcConfigFileInfoIter	*iter,
26831887081fSmrg			 FcChar8		**name,
26841887081fSmrg			 FcChar8		**description,
26851887081fSmrg			 FcBool			*enabled)
26861887081fSmrg{
26871887081fSmrg    FcConfig *c;
26881887081fSmrg    FcRuleSet *r;
26891887081fSmrg    FcPtrListIter *i = (FcPtrListIter *)iter;
26901887081fSmrg
26911887081fSmrg    if (!config)
26921887081fSmrg	c = FcConfigGetCurrent ();
26931887081fSmrg    else
26941887081fSmrg	c = config;
26951887081fSmrg    if (!FcPtrListIterIsValid (c->rulesetList, i))
26961887081fSmrg	return FcFalse;
26971887081fSmrg    r = FcPtrListIterGetValue (c->rulesetList, i);
26981887081fSmrg    if (name)
26991887081fSmrg	*name = FcStrdup (r->name && r->name[0] ? r->name : (const FcChar8 *) "fonts.conf");
27001887081fSmrg    if (description)
27011887081fSmrg	*description = FcStrdup (!r->description ? _("No description") :
27021887081fSmrg				 dgettext (r->domain ? (const char *) r->domain : GETTEXT_PACKAGE "-conf",
27031887081fSmrg					   (const char *) r->description));
27041887081fSmrg    if (enabled)
27051887081fSmrg	*enabled = r->enabled;
27061887081fSmrg
27071887081fSmrg    return FcTrue;
27081887081fSmrg}
27091887081fSmrg
27102c393a42Smrg#define __fccfg__
27112c393a42Smrg#include "fcaliastail.h"
27122c393a42Smrg#undef __fccfg__
2713