(root)/
fontconfig-2.14.2/
src/
fccfg.c
       1  /*
       2   * fontconfig/src/fccfg.c
       3   *
       4   * Copyright © 2000 Keith Packard
       5   *
       6   * Permission to use, copy, modify, distribute, and sell this software and its
       7   * documentation for any purpose is hereby granted without fee, provided that
       8   * the above copyright notice appear in all copies and that both that
       9   * copyright notice and this permission notice appear in supporting
      10   * documentation, and that the name of the author(s) not be used in
      11   * advertising or publicity pertaining to distribution of the software without
      12   * specific, written prior permission.  The authors make no
      13   * representations about the suitability of this software for any purpose.  It
      14   * is provided "as is" without express or implied warranty.
      15   *
      16   * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
      17   * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
      18   * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
      19   * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
      20   * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
      21   * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
      22   * PERFORMANCE OF THIS SOFTWARE.
      23   */
      24  
      25  /* Objects MT-safe for readonly access. */
      26  
      27  #include "fcint.h"
      28  #ifdef HAVE_DIRENT_H
      29  #include <dirent.h>
      30  #endif
      31  #include <sys/types.h>
      32  
      33  #if defined (_WIN32) && !defined (R_OK)
      34  #define R_OK 4
      35  #endif
      36  
      37  #if defined(_WIN32) && !defined(S_ISFIFO)
      38  #define S_ISFIFO(m) 0
      39  #endif
      40  
      41  static FcConfig    *_fcConfig; /* MT-safe */
      42  static FcMutex	   *_lock;
      43  
      44  static void
      45  lock_config (void)
      46  {
      47      FcMutex *lock;
      48  retry:
      49      lock = fc_atomic_ptr_get (&_lock);
      50      if (!lock)
      51      {
      52  	lock = (FcMutex *) malloc (sizeof (FcMutex));
      53  	FcMutexInit (lock);
      54  	if (!fc_atomic_ptr_cmpexch (&_lock, NULL, lock))
      55  	{
      56  	    FcMutexFinish (lock);
      57  	    free (lock);
      58  	    goto retry;
      59  	}
      60  	FcMutexLock (lock);
      61  	/* Initialize random state */
      62  	FcRandom ();
      63  	return;
      64      }
      65      FcMutexLock (lock);
      66  }
      67  
      68  static void
      69  unlock_config (void)
      70  {
      71      FcMutex *lock;
      72      lock = fc_atomic_ptr_get (&_lock);
      73      FcMutexUnlock (lock);
      74  }
      75  
      76  static void
      77  free_lock (void)
      78  {
      79      FcMutex *lock;
      80      lock = fc_atomic_ptr_get (&_lock);
      81      if (lock && fc_atomic_ptr_cmpexch (&_lock, lock, NULL))
      82      {
      83  	FcMutexFinish (lock);
      84  	free (lock);
      85      }
      86  }
      87  
      88  static FcConfig *
      89  FcConfigEnsure (void)
      90  {
      91      FcConfig	*config;
      92  retry:
      93      config = fc_atomic_ptr_get (&_fcConfig);
      94      if (!config)
      95      {
      96  	config = FcInitLoadConfigAndFonts ();
      97  
      98  	if (!config || !fc_atomic_ptr_cmpexch (&_fcConfig, NULL, config)) {
      99  	    if (config)
     100  		FcConfigDestroy (config);
     101  	    goto retry;
     102  	}
     103      }
     104      return config;
     105  }
     106  
     107  static void
     108  FcDestroyAsRule (void *data)
     109  {
     110      FcRuleDestroy (data);
     111  }
     112  
     113  static void
     114  FcDestroyAsRuleSet (void *data)
     115  {
     116      FcRuleSetDestroy (data);
     117  }
     118  
     119  FcBool
     120  FcConfigInit (void)
     121  {
     122    return FcConfigEnsure () ? FcTrue : FcFalse;
     123  }
     124  
     125  void
     126  FcConfigFini (void)
     127  {
     128      FcConfig *cfg = fc_atomic_ptr_get (&_fcConfig);
     129      if (cfg && fc_atomic_ptr_cmpexch (&_fcConfig, cfg, NULL))
     130  	FcConfigDestroy (cfg);
     131      free_lock ();
     132  }
     133  
     134  FcConfig *
     135  FcConfigCreate (void)
     136  {
     137      FcSetName	set;
     138      FcConfig	*config;
     139      FcMatchKind	k;
     140      FcBool	err = FcFalse;
     141  
     142      config = malloc (sizeof (FcConfig));
     143      if (!config)
     144  	goto bail0;
     145  
     146      config->configDirs = FcStrSetCreate ();
     147      if (!config->configDirs)
     148  	goto bail1;
     149  
     150      config->configMapDirs = FcStrSetCreate();
     151      if (!config->configMapDirs)
     152  	goto bail1_5;
     153  
     154      config->configFiles = FcStrSetCreate ();
     155      if (!config->configFiles)
     156  	goto bail2;
     157  
     158      config->fontDirs = FcStrSetCreate ();
     159      if (!config->fontDirs)
     160  	goto bail3;
     161  
     162      config->acceptGlobs = FcStrSetCreate ();
     163      if (!config->acceptGlobs)
     164  	goto bail4;
     165  
     166      config->rejectGlobs = FcStrSetCreate ();
     167      if (!config->rejectGlobs)
     168  	goto bail5;
     169  
     170      config->acceptPatterns = FcFontSetCreate ();
     171      if (!config->acceptPatterns)
     172  	goto bail6;
     173  
     174      config->rejectPatterns = FcFontSetCreate ();
     175      if (!config->rejectPatterns)
     176  	goto bail7;
     177  
     178      config->cacheDirs = FcStrSetCreate ();
     179      if (!config->cacheDirs)
     180  	goto bail8;
     181  
     182      for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++)
     183      {
     184  	config->subst[k] = FcPtrListCreate (FcDestroyAsRuleSet);
     185  	if (!config->subst[k])
     186  	    err = FcTrue;
     187      }
     188      if (err)
     189  	goto bail9;
     190  
     191      config->maxObjects = 0;
     192      for (set = FcSetSystem; set <= FcSetApplication; set++)
     193  	config->fonts[set] = 0;
     194  
     195      config->rescanTime = time(0);
     196      config->rescanInterval = 30;
     197  
     198      config->expr_pool = NULL;
     199  
     200      config->sysRoot = FcStrRealPath ((const FcChar8 *) getenv("FONTCONFIG_SYSROOT"));
     201  
     202      config->rulesetList = FcPtrListCreate (FcDestroyAsRuleSet);
     203      if (!config->rulesetList)
     204  	goto bail9;
     205      config->availConfigFiles = FcStrSetCreate ();
     206      if (!config->availConfigFiles)
     207  	goto bail10;
     208  
     209      FcRefInit (&config->ref, 1);
     210  
     211      return config;
     212  
     213  bail10:
     214      FcPtrListDestroy (config->rulesetList);
     215  bail9:
     216      for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++)
     217  	if (config->subst[k])
     218  	    FcPtrListDestroy (config->subst[k]);
     219      FcStrSetDestroy (config->cacheDirs);
     220  bail8:
     221      FcFontSetDestroy (config->rejectPatterns);
     222  bail7:
     223      FcFontSetDestroy (config->acceptPatterns);
     224  bail6:
     225      FcStrSetDestroy (config->rejectGlobs);
     226  bail5:
     227      FcStrSetDestroy (config->acceptGlobs);
     228  bail4:
     229      FcStrSetDestroy (config->fontDirs);
     230  bail3:
     231      FcStrSetDestroy (config->configFiles);
     232  bail2:
     233      FcStrSetDestroy (config->configMapDirs);
     234  bail1_5:
     235      FcStrSetDestroy (config->configDirs);
     236  bail1:
     237      free (config);
     238  bail0:
     239      return 0;
     240  }
     241  
     242  static FcFileTime
     243  FcConfigNewestFile (FcStrSet *files)
     244  {
     245      FcStrList	    *list = FcStrListCreate (files);
     246      FcFileTime	    newest = { 0, FcFalse };
     247      FcChar8	    *file;
     248      struct  stat    statb;
     249  
     250      if (list)
     251      {
     252  	while ((file = FcStrListNext (list)))
     253  	    if (FcStat (file, &statb) == 0)
     254  		if (!newest.set || statb.st_mtime - newest.time > 0)
     255  		{
     256  		    newest.set = FcTrue;
     257  		    newest.time = statb.st_mtime;
     258  		}
     259  	FcStrListDone (list);
     260      }
     261      return newest;
     262  }
     263  
     264  FcBool
     265  FcConfigUptoDate (FcConfig *config)
     266  {
     267      FcFileTime	config_time, config_dir_time, font_time;
     268      time_t	now = time(0);
     269      FcBool	ret = FcTrue;
     270  
     271      config = FcConfigReference (config);
     272      if (!config)
     273  	return FcFalse;
     274  
     275      config_time = FcConfigNewestFile (config->configFiles);
     276      config_dir_time = FcConfigNewestFile (config->configDirs);
     277      font_time = FcConfigNewestFile (config->fontDirs);
     278      if ((config_time.set && config_time.time - config->rescanTime > 0) ||
     279  	(config_dir_time.set && (config_dir_time.time - config->rescanTime) > 0) ||
     280  	(font_time.set && (font_time.time - config->rescanTime) > 0))
     281      {
     282  	/* We need to check for potential clock problems here (OLPC ticket #6046) */
     283  	if ((config_time.set && (config_time.time - now) > 0) ||
     284      	(config_dir_time.set && (config_dir_time.time - now) > 0) ||
     285          (font_time.set && (font_time.time - now) > 0))
     286  	{
     287  	    fprintf (stderr,
     288                      "Fontconfig warning: Directory/file mtime in the future. New fonts may not be detected.\n");
     289  	    config->rescanTime = now;
     290  	    goto bail;
     291  	}
     292  	else
     293  	{
     294  	    ret = FcFalse;
     295  	    goto bail;
     296  	}
     297      }
     298      config->rescanTime = now;
     299  bail:
     300      FcConfigDestroy (config);
     301  
     302      return ret;
     303  }
     304  
     305  FcExpr *
     306  FcConfigAllocExpr (FcConfig *config)
     307  {
     308      if (!config->expr_pool || config->expr_pool->next == config->expr_pool->end)
     309      {
     310  	FcExprPage *new_page;
     311  
     312  	new_page = malloc (sizeof (FcExprPage));
     313  	if (!new_page)
     314  	    return 0;
     315  
     316  	new_page->next_page = config->expr_pool;
     317  	new_page->next = new_page->exprs;
     318  	config->expr_pool = new_page;
     319      }
     320  
     321      return config->expr_pool->next++;
     322  }
     323  
     324  FcConfig *
     325  FcConfigReference (FcConfig *config)
     326  {
     327      if (!config)
     328      {
     329  	/* lock during obtaining the value from _fcConfig and count up refcount there,
     330  	 * there are the race between them.
     331  	 */
     332  	lock_config ();
     333      retry:
     334  	config = fc_atomic_ptr_get (&_fcConfig);
     335  	if (!config)
     336  	{
     337  	    unlock_config ();
     338  
     339  	    config = FcInitLoadConfigAndFonts ();
     340  	    if (!config)
     341  		goto retry;
     342  	    lock_config ();
     343  	    if (!fc_atomic_ptr_cmpexch (&_fcConfig, NULL, config))
     344  	    {
     345  		FcConfigDestroy (config);
     346  		goto retry;
     347  	    }
     348  	}
     349  	FcRefInc (&config->ref);
     350  	unlock_config ();
     351      }
     352      else
     353  	FcRefInc (&config->ref);
     354  
     355      return config;
     356  }
     357  
     358  void
     359  FcConfigDestroy (FcConfig *config)
     360  {
     361      FcSetName	set;
     362      FcExprPage	*page;
     363      FcMatchKind	k;
     364  
     365      if (config)
     366      {
     367  	if (FcRefDec (&config->ref) != 1)
     368  	    return;
     369  
     370  	(void) fc_atomic_ptr_cmpexch (&_fcConfig, config, NULL);
     371  
     372  	FcStrSetDestroy (config->configDirs);
     373  	FcStrSetDestroy (config->configMapDirs);
     374  	FcStrSetDestroy (config->fontDirs);
     375  	FcStrSetDestroy (config->cacheDirs);
     376  	FcStrSetDestroy (config->configFiles);
     377  	FcStrSetDestroy (config->acceptGlobs);
     378  	FcStrSetDestroy (config->rejectGlobs);
     379  	FcFontSetDestroy (config->acceptPatterns);
     380  	FcFontSetDestroy (config->rejectPatterns);
     381  
     382  	for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++)
     383  	    FcPtrListDestroy (config->subst[k]);
     384  	FcPtrListDestroy (config->rulesetList);
     385  	FcStrSetDestroy (config->availConfigFiles);
     386  	for (set = FcSetSystem; set <= FcSetApplication; set++)
     387  	    if (config->fonts[set])
     388  		FcFontSetDestroy (config->fonts[set]);
     389  
     390  	page = config->expr_pool;
     391  	while (page)
     392  	{
     393  	    FcExprPage *next = page->next_page;
     394  	    free (page);
     395  	    page = next;
     396  	}
     397  	if (config->sysRoot)
     398  	FcStrFree (config->sysRoot);
     399  
     400  	free (config);
     401      }
     402  }
     403  
     404  /*
     405   * Add cache to configuration, adding fonts and directories
     406   */
     407  
     408  FcBool
     409  FcConfigAddCache (FcConfig *config, FcCache *cache,
     410  		  FcSetName set, FcStrSet *dirSet, FcChar8 *forDir)
     411  {
     412      FcFontSet	*fs;
     413      intptr_t	*dirs;
     414      int		i;
     415      FcBool      relocated = FcFalse;
     416  
     417      if (strcmp ((char *)FcCacheDir(cache), (char *)forDir) != 0)
     418        relocated = FcTrue;
     419  
     420      /*
     421       * Add fonts
     422       */
     423      fs = FcCacheSet (cache);
     424      if (fs)
     425      {
     426  	int	nref = 0;
     427  
     428  	for (i = 0; i < fs->nfont; i++)
     429  	{
     430  	    FcPattern	*font = FcFontSetFont (fs, i);
     431  	    FcChar8	*font_file;
     432  	    FcChar8	*relocated_font_file = NULL;
     433  
     434  	    if (FcPatternObjectGetString (font, FC_FILE_OBJECT,
     435  					  0, &font_file) == FcResultMatch)
     436  	    {
     437  		if (relocated)
     438  		  {
     439  		    FcChar8 *slash = FcStrLastSlash (font_file);
     440  		    relocated_font_file = FcStrBuildFilename (forDir, slash + 1, NULL);
     441  		    font_file = relocated_font_file;
     442  		  }
     443  
     444  		/*
     445  		 * Check to see if font is banned by filename
     446  		 */
     447  		if (!FcConfigAcceptFilename (config, font_file))
     448  		{
     449  		    free (relocated_font_file);
     450  		    continue;
     451  		}
     452  	    }
     453  
     454  	    /*
     455  	     * Check to see if font is banned by pattern
     456  	     */
     457  	    if (!FcConfigAcceptFont (config, font))
     458  	    {
     459  		free (relocated_font_file);
     460  		continue;
     461  	    }
     462  
     463  	    if (relocated_font_file)
     464  	    {
     465  	      font = FcPatternCacheRewriteFile (font, cache, relocated_font_file);
     466  	      free (relocated_font_file);
     467  	    }
     468  
     469  	    if (FcFontSetAdd (config->fonts[set], font))
     470  		nref++;
     471  	}
     472  	FcDirCacheReference (cache, nref);
     473      }
     474  
     475      /*
     476       * Add directories
     477       */
     478      dirs = FcCacheDirs (cache);
     479      if (dirs)
     480      {
     481  	for (i = 0; i < cache->dirs_count; i++)
     482  	{
     483  	    const FcChar8 *dir = FcCacheSubdir (cache, i);
     484  	    FcChar8 *s = NULL;
     485  
     486  	    if (relocated)
     487  	    {
     488  		FcChar8 *base = FcStrBasename (dir);
     489  		dir = s = FcStrBuildFilename (forDir, base, NULL);
     490  		FcStrFree (base);
     491  	    }
     492  	    if (FcConfigAcceptFilename (config, dir))
     493  		FcStrSetAddFilename (dirSet, dir);
     494  	    if (s)
     495  		FcStrFree (s);
     496  	}
     497      }
     498      return FcTrue;
     499  }
     500  
     501  static FcBool
     502  FcConfigAddDirList (FcConfig *config, FcSetName set, FcStrSet *dirSet)
     503  {
     504      FcStrList	    *dirlist;
     505      FcChar8	    *dir;
     506      FcCache	    *cache;
     507  
     508      dirlist = FcStrListCreate (dirSet);
     509      if (!dirlist)
     510          return FcFalse;
     511  
     512      while ((dir = FcStrListNext (dirlist)))
     513      {
     514  	if (FcDebug () & FC_DBG_FONTSET)
     515  	    printf ("adding fonts from %s\n", dir);
     516  	cache = FcDirCacheRead (dir, FcFalse, config);
     517  	if (!cache)
     518  	    continue;
     519  	FcConfigAddCache (config, cache, set, dirSet, dir);
     520  	FcDirCacheUnload (cache);
     521      }
     522      FcStrListDone (dirlist);
     523      return FcTrue;
     524  }
     525  
     526  /*
     527   * Scan the current list of directories in the configuration
     528   * and build the set of available fonts.
     529   */
     530  
     531  FcBool
     532  FcConfigBuildFonts (FcConfig *config)
     533  {
     534      FcFontSet	    *fonts;
     535      FcBool	    ret = FcTrue;
     536  
     537      config = FcConfigReference (config);
     538      if (!config)
     539  	return FcFalse;
     540  
     541      fonts = FcFontSetCreate ();
     542      if (!fonts)
     543      {
     544  	ret = FcFalse;
     545  	goto bail;
     546      }
     547  
     548      FcConfigSetFonts (config, fonts, FcSetSystem);
     549  
     550      if (!FcConfigAddDirList (config, FcSetSystem, config->fontDirs))
     551      {
     552  	ret = FcFalse;
     553  	goto bail;
     554      }
     555      if (FcDebug () & FC_DBG_FONTSET)
     556  	FcFontSetPrint (fonts);
     557  bail:
     558      FcConfigDestroy (config);
     559  
     560      return ret;
     561  }
     562  
     563  FcBool
     564  FcConfigSetCurrent (FcConfig *config)
     565  {
     566      FcConfig *cfg;
     567  
     568      if (config)
     569      {
     570  	if (!config->fonts[FcSetSystem])
     571  	    if (!FcConfigBuildFonts (config))
     572  		return FcFalse;
     573  	FcRefInc (&config->ref);
     574      }
     575  
     576      lock_config ();
     577  retry:
     578      cfg = fc_atomic_ptr_get (&_fcConfig);
     579  
     580      if (config == cfg)
     581      {
     582  	unlock_config ();
     583  	if (config)
     584  	    FcConfigDestroy (config);
     585  	return FcTrue;
     586      }
     587  
     588      if (!fc_atomic_ptr_cmpexch (&_fcConfig, cfg, config))
     589  	goto retry;
     590      unlock_config ();
     591      if (cfg)
     592  	FcConfigDestroy (cfg);
     593  
     594      return FcTrue;
     595  }
     596  
     597  FcConfig *
     598  FcConfigGetCurrent (void)
     599  {
     600      return FcConfigEnsure ();
     601  }
     602  
     603  FcBool
     604  FcConfigAddConfigDir (FcConfig	    *config,
     605  		      const FcChar8 *d)
     606  {
     607      return FcStrSetAddFilename (config->configDirs, d);
     608  }
     609  
     610  FcStrList *
     611  FcConfigGetConfigDirs (FcConfig   *config)
     612  {
     613      FcStrList *ret;
     614  
     615      config = FcConfigReference (config);
     616      if (!config)
     617  	return NULL;
     618      ret = FcStrListCreate (config->configDirs);
     619      FcConfigDestroy (config);
     620  
     621      return ret;
     622  }
     623  
     624  FcBool
     625  FcConfigAddFontDir (FcConfig	    *config,
     626  		    const FcChar8   *d,
     627  		    const FcChar8   *m,
     628  		    const FcChar8   *salt)
     629  {
     630      if (FcDebug() & FC_DBG_CACHE)
     631      {
     632  	if (m)
     633  	{
     634  	    printf ("%s -> %s%s%s%s\n", d, m, salt ? " (salt: " : "", salt ? (const char *)salt : "", salt ? ")" : "");
     635  	}
     636  	else if (salt)
     637  	{
     638  	    printf ("%s%s%s%s\n", d, salt ? " (salt: " : "", salt ? (const char *)salt : "", salt ? ")" : "");
     639  	}
     640      }
     641      return FcStrSetAddFilenamePairWithSalt (config->fontDirs, d, m, salt);
     642  }
     643  
     644  FcBool
     645  FcConfigResetFontDirs (FcConfig *config)
     646  {
     647      if (FcDebug() & FC_DBG_CACHE)
     648      {
     649  	printf ("Reset font directories!\n");
     650      }
     651      return FcStrSetDeleteAll (config->fontDirs);
     652  }
     653  
     654  FcStrList *
     655  FcConfigGetFontDirs (FcConfig	*config)
     656  {
     657      FcStrList *ret;
     658  
     659      config = FcConfigReference (config);
     660      if (!config)
     661  	return NULL;
     662      ret = FcStrListCreate (config->fontDirs);
     663      FcConfigDestroy (config);
     664  
     665      return ret;
     666  }
     667  
     668  static FcBool
     669  FcConfigPathStartsWith(const FcChar8	*path,
     670  		       const FcChar8	*start)
     671  {
     672      int len = strlen((char *) start);
     673  
     674      if (strncmp((char *) path, (char *) start, len) != 0)
     675  	return FcFalse;
     676  
     677      switch (path[len]) {
     678      case '\0':
     679      case FC_DIR_SEPARATOR:
     680  	return FcTrue;
     681      default:
     682  	return FcFalse;
     683      }
     684  }
     685  
     686  FcChar8 *
     687  FcConfigMapFontPath(FcConfig		*config,
     688  		    const FcChar8	*path)
     689  {
     690      FcStrList	*list;
     691      FcChar8	*dir;
     692      const FcChar8 *map, *rpath;
     693      FcChar8     *retval;
     694  
     695      list = FcConfigGetFontDirs(config);
     696      if (!list)
     697  	return 0;
     698      while ((dir = FcStrListNext(list)))
     699  	if (FcConfigPathStartsWith(path, dir))
     700  	    break;
     701      FcStrListDone(list);
     702      if (!dir)
     703  	return 0;
     704      map = FcStrTripleSecond(dir);
     705      if (!map)
     706  	return 0;
     707      rpath = path + strlen ((char *) dir);
     708      while (*rpath == '/')
     709  	rpath++;
     710      retval = FcStrBuildFilename(map, rpath, NULL);
     711      if (retval)
     712      {
     713  	size_t len = strlen ((const char *) retval);
     714  	while (len > 0 && retval[len-1] == '/')
     715  	    len--;
     716  	/* trim the last slash */
     717  	retval[len] = 0;
     718      }
     719      return retval;
     720  }
     721  
     722  const FcChar8 *
     723  FcConfigMapSalt (FcConfig      *config,
     724  		 const FcChar8 *path)
     725  {
     726      FcStrList *list;
     727      FcChar8 *dir;
     728  
     729      list = FcConfigGetFontDirs (config);
     730      if (!list)
     731  	return NULL;
     732      while ((dir = FcStrListNext (list)))
     733  	if (FcConfigPathStartsWith (path, dir))
     734  	    break;
     735      FcStrListDone (list);
     736      if (!dir)
     737  	return NULL;
     738  
     739      return FcStrTripleThird (dir);
     740  }
     741  
     742  FcBool
     743  FcConfigAddCacheDir (FcConfig	    *config,
     744  		     const FcChar8  *d)
     745  {
     746      return FcStrSetAddFilename (config->cacheDirs, d);
     747  }
     748  
     749  FcStrList *
     750  FcConfigGetCacheDirs (FcConfig *config)
     751  {
     752      FcStrList *ret;
     753  
     754      config = FcConfigReference (config);
     755      if (!config)
     756  	return NULL;
     757      ret = FcStrListCreate (config->cacheDirs);
     758      FcConfigDestroy (config);
     759  
     760      return ret;
     761  }
     762  
     763  FcBool
     764  FcConfigAddConfigFile (FcConfig	    *config,
     765  		       const FcChar8   *f)
     766  {
     767      FcBool	ret;
     768      FcChar8	*file = FcConfigGetFilename (config, f);
     769  
     770      if (!file)
     771  	return FcFalse;
     772  
     773      ret = FcStrSetAdd (config->configFiles, file);
     774      FcStrFree (file);
     775      return ret;
     776  }
     777  
     778  FcStrList *
     779  FcConfigGetConfigFiles (FcConfig    *config)
     780  {
     781      FcStrList *ret;
     782  
     783      config = FcConfigReference (config);
     784      if (!config)
     785  	return NULL;
     786      ret = FcStrListCreate (config->configFiles);
     787      FcConfigDestroy (config);
     788  
     789      return ret;
     790  }
     791  
     792  FcChar8 *
     793  FcConfigGetCache (FcConfig  *config FC_UNUSED)
     794  {
     795      return NULL;
     796  }
     797  
     798  FcFontSet *
     799  FcConfigGetFonts (FcConfig	*config,
     800  		  FcSetName	set)
     801  {
     802      if (!config)
     803      {
     804  	config = FcConfigGetCurrent ();
     805  	if (!config)
     806  	    return 0;
     807      }
     808      return config->fonts[set];
     809  }
     810  
     811  void
     812  FcConfigSetFonts (FcConfig	*config,
     813  		  FcFontSet	*fonts,
     814  		  FcSetName	set)
     815  {
     816      if (config->fonts[set])
     817  	FcFontSetDestroy (config->fonts[set]);
     818      config->fonts[set] = fonts;
     819  }
     820  
     821  
     822  FcBlanks *
     823  FcBlanksCreate (void)
     824  {
     825      /* Deprecated. */
     826      return NULL;
     827  }
     828  
     829  void
     830  FcBlanksDestroy (FcBlanks *b FC_UNUSED)
     831  {
     832      /* Deprecated. */
     833  }
     834  
     835  FcBool
     836  FcBlanksAdd (FcBlanks *b FC_UNUSED, FcChar32 ucs4 FC_UNUSED)
     837  {
     838      /* Deprecated. */
     839      return FcFalse;
     840  }
     841  
     842  FcBool
     843  FcBlanksIsMember (FcBlanks *b FC_UNUSED, FcChar32 ucs4 FC_UNUSED)
     844  {
     845      /* Deprecated. */
     846      return FcFalse;
     847  }
     848  
     849  FcBlanks *
     850  FcConfigGetBlanks (FcConfig	*config FC_UNUSED)
     851  {
     852      /* Deprecated. */
     853      return NULL;
     854  }
     855  
     856  FcBool
     857  FcConfigAddBlank (FcConfig	*config FC_UNUSED,
     858  		  FcChar32    	blank FC_UNUSED)
     859  {
     860      /* Deprecated. */
     861      return FcFalse;
     862  }
     863  
     864  
     865  int
     866  FcConfigGetRescanInterval (FcConfig *config)
     867  {
     868      int ret;
     869  
     870      config = FcConfigReference (config);
     871      if (!config)
     872  	return 0;
     873      ret = config->rescanInterval;
     874      FcConfigDestroy (config);
     875  
     876      return ret;
     877  }
     878  
     879  FcBool
     880  FcConfigSetRescanInterval (FcConfig *config, int rescanInterval)
     881  {
     882      config = FcConfigReference (config);
     883      if (!config)
     884  	return FcFalse;
     885      config->rescanInterval = rescanInterval;
     886      FcConfigDestroy (config);
     887  
     888      return FcTrue;
     889  }
     890  
     891  /*
     892   * A couple of typos escaped into the library
     893   */
     894  int
     895  FcConfigGetRescanInverval (FcConfig *config)
     896  {
     897      return FcConfigGetRescanInterval (config);
     898  }
     899  
     900  FcBool
     901  FcConfigSetRescanInverval (FcConfig *config, int rescanInterval)
     902  {
     903      return FcConfigSetRescanInterval (config, rescanInterval);
     904  }
     905  
     906  FcBool
     907  FcConfigAddRule (FcConfig	*config,
     908  		 FcRule		*rule,
     909  		 FcMatchKind	kind)
     910  {
     911      /* deprecated */
     912      return FcFalse;
     913  }
     914  
     915  static FcValue
     916  FcConfigPromote (FcValue v, FcValue u, FcValuePromotionBuffer *buf)
     917  {
     918      switch (v.type)
     919      {
     920      case FcTypeInteger:
     921          v.type = FcTypeDouble;
     922          v.u.d = (double) v.u.i;
     923          /* Fallthrough */
     924      case FcTypeDouble:
     925          if (u.type == FcTypeRange && buf)
     926          {
     927              v.u.r = FcRangePromote (v.u.d, buf);
     928              v.type = FcTypeRange;
     929          }
     930          break;
     931      case FcTypeVoid:
     932          if (u.type == FcTypeMatrix)
     933          {
     934              v.u.m = &FcIdentityMatrix;
     935              v.type = FcTypeMatrix;
     936          }
     937          else if (u.type == FcTypeLangSet && buf)
     938          {
     939              v.u.l = FcLangSetPromote (NULL, buf);
     940              v.type = FcTypeLangSet;
     941          }
     942          else if (u.type == FcTypeCharSet && buf)
     943          {
     944              v.u.c = FcCharSetPromote (buf);
     945              v.type = FcTypeCharSet;
     946          }
     947          break;
     948      case FcTypeString:
     949          if (u.type == FcTypeLangSet && buf)
     950          {
     951              v.u.l = FcLangSetPromote (v.u.s, buf);
     952              v.type = FcTypeLangSet;
     953          }
     954          break;
     955      default:
     956          break;
     957      }
     958      return v;
     959  }
     960  
     961  FcBool
     962  FcConfigCompareValue (const FcValue	*left_o,
     963  		      unsigned int      op_,
     964  		      const FcValue	*right_o)
     965  {
     966      FcValue     left;
     967      FcValue     right;
     968      FcBool	ret = FcFalse;
     969      FcOp	op = FC_OP_GET_OP (op_);
     970      int		flags = FC_OP_GET_FLAGS (op_);
     971      FcValuePromotionBuffer buf1, buf2;
     972  
     973      if (left_o->type != right_o->type)
     974      {
     975          left = FcValueCanonicalize(left_o);
     976          right = FcValueCanonicalize(right_o);
     977          left = FcConfigPromote (left, right, &buf1);
     978          right = FcConfigPromote (right, left, &buf2);
     979          left_o = &left;
     980          right_o = &right;
     981          if (left_o->type != right_o->type)
     982          {
     983  	    if (op == FcOpNotEqual || op == FcOpNotContains)
     984  	        ret = FcTrue;
     985              return ret;
     986          }
     987      }
     988      switch (left_o->type) {
     989      case FcTypeUnknown:
     990          break;	/* No way to guess how to compare for this object */
     991      case FcTypeInteger: {
     992          int l = left_o->u.i;
     993          int r = right_o->u.i;
     994          switch ((int) op) {
     995          case FcOpEqual:
     996          case FcOpContains:
     997          case FcOpListing:
     998              ret = l == r;
     999              break;
    1000          case FcOpNotEqual:
    1001          case FcOpNotContains:
    1002              ret = l != r;
    1003              break;
    1004          case FcOpLess:
    1005              ret = l < r;
    1006              break;
    1007          case FcOpLessEqual:
    1008              ret = l <= r;
    1009              break;
    1010          case FcOpMore:
    1011              ret = l > r;
    1012              break;
    1013          case FcOpMoreEqual:
    1014              ret = l >= r;
    1015              break;
    1016          default:
    1017              break;
    1018          }
    1019          break;
    1020      }
    1021      case FcTypeDouble: {
    1022          double l = left_o->u.d;
    1023          double r = right_o->u.d;
    1024          switch ((int) op) {
    1025          case FcOpEqual:
    1026          case FcOpContains:
    1027          case FcOpListing:
    1028              ret = l == r;
    1029              break;
    1030          case FcOpNotEqual:
    1031          case FcOpNotContains:
    1032              ret = l != r;
    1033              break;
    1034          case FcOpLess:
    1035              ret = l < r;
    1036              break;
    1037          case FcOpLessEqual:
    1038              ret = l <= r;
    1039              break;
    1040          case FcOpMore:
    1041              ret = l > r;
    1042              break;
    1043          case FcOpMoreEqual:
    1044              ret = l >= r;
    1045              break;
    1046          default:
    1047              break;
    1048          }
    1049          break;
    1050      }
    1051      case FcTypeBool: {
    1052          FcBool l = left_o->u.b;
    1053          FcBool r = right_o->u.b;
    1054          switch ((int) op) {
    1055          case FcOpEqual:
    1056              ret = l == r;
    1057              break;
    1058          case FcOpContains:
    1059          case FcOpListing:
    1060              ret = l == r || l >= FcDontCare;
    1061              break;
    1062          case FcOpNotEqual:
    1063              ret = l != r;
    1064              break;
    1065          case FcOpNotContains:
    1066              ret = !(l == r || l >= FcDontCare);
    1067              break;
    1068          case FcOpLess:
    1069              ret = l != r && r >= FcDontCare;
    1070              break;
    1071          case FcOpLessEqual:
    1072              ret = l == r || r >= FcDontCare;
    1073              break;
    1074          case FcOpMore:
    1075              ret = l != r && l >= FcDontCare;
    1076              break;
    1077          case FcOpMoreEqual:
    1078              ret = l == r || l >= FcDontCare;
    1079              break;
    1080          default:
    1081              break;
    1082          }
    1083          break;
    1084      }
    1085      case FcTypeString: {
    1086          const FcChar8 *l = FcValueString (left_o);
    1087          const FcChar8 *r = FcValueString (right_o);
    1088          switch ((int) op) {
    1089          case FcOpEqual:
    1090          case FcOpListing:
    1091              if (flags & FcOpFlagIgnoreBlanks)
    1092                  ret = FcStrCmpIgnoreBlanksAndCase (l, r) == 0;
    1093              else
    1094                  ret = FcStrCmpIgnoreCase (l, r) == 0;
    1095              break;
    1096          case FcOpContains:
    1097              ret = FcStrStrIgnoreCase (l, r) != 0;
    1098              break;
    1099          case FcOpNotEqual:
    1100              if (flags & FcOpFlagIgnoreBlanks)
    1101                  ret = FcStrCmpIgnoreBlanksAndCase (l, r) != 0;
    1102              else
    1103                  ret = FcStrCmpIgnoreCase (l, r) != 0;
    1104              break;
    1105          case FcOpNotContains:
    1106              ret = FcStrStrIgnoreCase (l, r) == 0;
    1107              break;
    1108          default:
    1109              break;
    1110          }
    1111          break;
    1112      }
    1113      case FcTypeMatrix: {
    1114          switch ((int) op) {
    1115          case FcOpEqual:
    1116          case FcOpContains:
    1117          case FcOpListing:
    1118              ret = FcMatrixEqual (left_o->u.m, right_o->u.m);
    1119              break;
    1120          case FcOpNotEqual:
    1121          case FcOpNotContains:
    1122              ret = !FcMatrixEqual (left_o->u.m, right_o->u.m);
    1123              break;
    1124          default:
    1125              break;
    1126          }
    1127          break;
    1128      }
    1129      case FcTypeCharSet: {
    1130          const FcCharSet *l = FcValueCharSet (left_o);
    1131          const FcCharSet *r = FcValueCharSet (right_o);
    1132          switch ((int) op) {
    1133          case FcOpContains:
    1134          case FcOpListing:
    1135              /* left contains right if right is a subset of left */
    1136              ret = FcCharSetIsSubset (r, l);
    1137              break;
    1138          case FcOpNotContains:
    1139              /* left contains right if right is a subset of left */
    1140              ret = !FcCharSetIsSubset (r, l);
    1141              break;
    1142          case FcOpEqual:
    1143              ret = FcCharSetEqual (l, r);
    1144              break;
    1145          case FcOpNotEqual:
    1146              ret = !FcCharSetEqual (l, r);
    1147              break;
    1148          default:
    1149              break;
    1150          }
    1151          break;
    1152      }
    1153      case FcTypeLangSet: {
    1154          const FcLangSet *l = FcValueLangSet (left_o);
    1155          const FcLangSet *r = FcValueLangSet (right_o);
    1156          switch ((int) op) {
    1157          case FcOpContains:
    1158          case FcOpListing:
    1159              ret = FcLangSetContains (l, r);
    1160              break;
    1161          case FcOpNotContains:
    1162              ret = !FcLangSetContains (l, r);
    1163              break;
    1164          case FcOpEqual:
    1165              ret = FcLangSetEqual (l, r);
    1166              break;
    1167          case FcOpNotEqual:
    1168              ret = !FcLangSetEqual (l, r);
    1169              break;
    1170          default:
    1171              break;
    1172          }
    1173          break;
    1174      }
    1175      case FcTypeVoid:
    1176          switch ((int) op) {
    1177          case FcOpEqual:
    1178          case FcOpContains:
    1179          case FcOpListing:
    1180              ret = FcTrue;
    1181              break;
    1182          default:
    1183              break;
    1184          }
    1185          break;
    1186      case FcTypeFTFace:
    1187          switch ((int) op) {
    1188          case FcOpEqual:
    1189          case FcOpContains:
    1190          case FcOpListing:
    1191              ret = left_o->u.f == right_o->u.f;
    1192              break;
    1193          case FcOpNotEqual:
    1194          case FcOpNotContains:
    1195              ret = left_o->u.f != right_o->u.f;
    1196              break;
    1197          default:
    1198              break;
    1199          }
    1200          break;
    1201      case FcTypeRange: {
    1202          const FcRange *l = FcValueRange (left_o);
    1203          const FcRange *r = FcValueRange (right_o);
    1204          ret = FcRangeCompare (op, l, r);
    1205          break;
    1206      }
    1207      }
    1208      return ret;
    1209  }
    1210  
    1211  
    1212  #define _FcDoubleFloor(d)	((int) (d))
    1213  #define _FcDoubleCeil(d)	((double) (int) (d) == (d) ? (int) (d) : (int) ((d) + 1))
    1214  #define FcDoubleFloor(d)	((d) >= 0 ? _FcDoubleFloor(d) : -_FcDoubleCeil(-(d)))
    1215  #define FcDoubleCeil(d)		((d) >= 0 ? _FcDoubleCeil(d) : -_FcDoubleFloor(-(d)))
    1216  #define FcDoubleRound(d)	FcDoubleFloor ((d) + 0.5)
    1217  #define FcDoubleTrunc(d)	((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d)))
    1218  
    1219  static FcValue
    1220  FcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e)
    1221  {
    1222      FcValue	v, vl, vr, vle, vre;
    1223      FcMatrix	*m;
    1224      FcChar8     *str;
    1225      FcOp	op = FC_OP_GET_OP (e->op);
    1226      FcValuePromotionBuffer buf1, buf2;
    1227  
    1228      switch ((int) op) {
    1229      case FcOpInteger:
    1230  	v.type = FcTypeInteger;
    1231  	v.u.i = e->u.ival;
    1232  	break;
    1233      case FcOpDouble:
    1234  	v.type = FcTypeDouble;
    1235  	v.u.d = e->u.dval;
    1236  	break;
    1237      case FcOpString:
    1238  	v.type = FcTypeString;
    1239  	v.u.s = e->u.sval;
    1240  	v = FcValueSave (v);
    1241  	break;
    1242      case FcOpMatrix:
    1243  	{
    1244  	  FcMatrix m;
    1245  	  FcValue xx, xy, yx, yy;
    1246  	  v.type = FcTypeMatrix;
    1247  	  xx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xx), v, NULL);
    1248  	  xy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xy), v, NULL);
    1249  	  yx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yx), v, NULL);
    1250  	  yy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yy), v, NULL);
    1251  	  if (xx.type == FcTypeDouble && xy.type == FcTypeDouble &&
    1252  	      yx.type == FcTypeDouble && yy.type == FcTypeDouble)
    1253  	  {
    1254  	    m.xx = xx.u.d;
    1255  	    m.xy = xy.u.d;
    1256  	    m.yx = yx.u.d;
    1257  	    m.yy = yy.u.d;
    1258  	    v.u.m = &m;
    1259  	  }
    1260  	  else
    1261  	    v.type = FcTypeVoid;
    1262  	  v = FcValueSave (v);
    1263  	}
    1264  	break;
    1265      case FcOpCharSet:
    1266  	v.type = FcTypeCharSet;
    1267  	v.u.c = e->u.cval;
    1268  	v = FcValueSave (v);
    1269  	break;
    1270      case FcOpLangSet:
    1271  	v.type = FcTypeLangSet;
    1272  	v.u.l = e->u.lval;
    1273  	v = FcValueSave (v);
    1274  	break;
    1275      case FcOpRange:
    1276  	v.type = FcTypeRange;
    1277  	v.u.r = e->u.rval;
    1278  	v = FcValueSave (v);
    1279  	break;
    1280      case FcOpBool:
    1281  	v.type = FcTypeBool;
    1282  	v.u.b = e->u.bval;
    1283  	break;
    1284      case FcOpField:
    1285  	if (kind == FcMatchFont && e->u.name.kind == FcMatchPattern)
    1286  	{
    1287  	    if (FcResultMatch != FcPatternObjectGet (p_pat, e->u.name.object, 0, &v))
    1288  		v.type = FcTypeVoid;
    1289  	}
    1290  	else if (kind == FcMatchPattern && e->u.name.kind == FcMatchFont)
    1291  	{
    1292  	    fprintf (stderr,
    1293                      "Fontconfig warning: <name> tag has target=\"font\" in a <match target=\"pattern\">.\n");
    1294  	    v.type = FcTypeVoid;
    1295  	}
    1296  	else
    1297  	{
    1298  	    if (FcResultMatch != FcPatternObjectGet (p, e->u.name.object, 0, &v))
    1299  		v.type = FcTypeVoid;
    1300  	}
    1301  	v = FcValueSave (v);
    1302  	break;
    1303      case FcOpConst:
    1304  	if (FcNameConstant (e->u.constant, &v.u.i))
    1305  	    v.type = FcTypeInteger;
    1306  	else
    1307  	    v.type = FcTypeVoid;
    1308  	break;
    1309      case FcOpQuest:
    1310  	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
    1311  	if (vl.type == FcTypeBool)
    1312  	{
    1313  	    if (vl.u.b)
    1314  		v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.left);
    1315  	    else
    1316  		v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.right);
    1317  	}
    1318  	else
    1319  	    v.type = FcTypeVoid;
    1320  	FcValueDestroy (vl);
    1321  	break;
    1322      case FcOpEqual:
    1323      case FcOpNotEqual:
    1324      case FcOpLess:
    1325      case FcOpLessEqual:
    1326      case FcOpMore:
    1327      case FcOpMoreEqual:
    1328      case FcOpContains:
    1329      case FcOpNotContains:
    1330      case FcOpListing:
    1331  	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
    1332  	vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right);
    1333  	v.type = FcTypeBool;
    1334  	v.u.b = FcConfigCompareValue (&vl, e->op, &vr);
    1335  	FcValueDestroy (vl);
    1336  	FcValueDestroy (vr);
    1337  	break;
    1338      case FcOpOr:
    1339      case FcOpAnd:
    1340      case FcOpPlus:
    1341      case FcOpMinus:
    1342      case FcOpTimes:
    1343      case FcOpDivide:
    1344  	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
    1345  	vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right);
    1346  	vle = FcConfigPromote (vl, vr, &buf1);
    1347  	vre = FcConfigPromote (vr, vle, &buf2);
    1348  	if (vle.type == vre.type)
    1349  	{
    1350  	    switch ((int) vle.type) {
    1351  	    case FcTypeDouble:
    1352  		switch ((int) op) {
    1353  		case FcOpPlus:
    1354  		    v.type = FcTypeDouble;
    1355  		    v.u.d = vle.u.d + vre.u.d;
    1356  		    break;
    1357  		case FcOpMinus:
    1358  		    v.type = FcTypeDouble;
    1359  		    v.u.d = vle.u.d - vre.u.d;
    1360  		    break;
    1361  		case FcOpTimes:
    1362  		    v.type = FcTypeDouble;
    1363  		    v.u.d = vle.u.d * vre.u.d;
    1364  		    break;
    1365  		case FcOpDivide:
    1366  		    v.type = FcTypeDouble;
    1367  		    v.u.d = vle.u.d / vre.u.d;
    1368  		    break;
    1369  		default:
    1370  		    v.type = FcTypeVoid;
    1371  		    break;
    1372  		}
    1373  		if (v.type == FcTypeDouble &&
    1374  		    v.u.d == (double) (int) v.u.d)
    1375  		{
    1376  		    v.type = FcTypeInteger;
    1377  		    v.u.i = (int) v.u.d;
    1378  		}
    1379  		break;
    1380  	    case FcTypeBool:
    1381  		switch ((int) op) {
    1382  		case FcOpOr:
    1383  		    v.type = FcTypeBool;
    1384  		    v.u.b = vle.u.b || vre.u.b;
    1385  		    break;
    1386  		case FcOpAnd:
    1387  		    v.type = FcTypeBool;
    1388  		    v.u.b = vle.u.b && vre.u.b;
    1389  		    break;
    1390  		default:
    1391  		    v.type = FcTypeVoid;
    1392  		    break;
    1393  		}
    1394  		break;
    1395  	    case FcTypeString:
    1396  		switch ((int) op) {
    1397  		case FcOpPlus:
    1398  		    v.type = FcTypeString;
    1399  		    str = FcStrPlus (vle.u.s, vre.u.s);
    1400  		    v.u.s = FcStrdup (str);
    1401  		    FcStrFree (str);
    1402  
    1403  		    if (!v.u.s)
    1404  			v.type = FcTypeVoid;
    1405  		    break;
    1406  		default:
    1407  		    v.type = FcTypeVoid;
    1408  		    break;
    1409  		}
    1410  		break;
    1411  	    case FcTypeMatrix:
    1412  		switch ((int) op) {
    1413  		case FcOpTimes:
    1414  		    v.type = FcTypeMatrix;
    1415  		    m = malloc (sizeof (FcMatrix));
    1416  		    if (m)
    1417  		    {
    1418  			FcMatrixMultiply (m, vle.u.m, vre.u.m);
    1419  			v.u.m = m;
    1420  		    }
    1421  		    else
    1422  		    {
    1423  			v.type = FcTypeVoid;
    1424  		    }
    1425  		    break;
    1426  		default:
    1427  		    v.type = FcTypeVoid;
    1428  		    break;
    1429  		}
    1430  		break;
    1431  	    case FcTypeCharSet:
    1432  		switch ((int) op) {
    1433  		case FcOpPlus:
    1434  		    v.type = FcTypeCharSet;
    1435  		    v.u.c = FcCharSetUnion (vle.u.c, vre.u.c);
    1436  		    if (!v.u.c)
    1437  			v.type = FcTypeVoid;
    1438  		    break;
    1439  		case FcOpMinus:
    1440  		    v.type = FcTypeCharSet;
    1441  		    v.u.c = FcCharSetSubtract (vle.u.c, vre.u.c);
    1442  		    if (!v.u.c)
    1443  			v.type = FcTypeVoid;
    1444  		    break;
    1445  		default:
    1446  		    v.type = FcTypeVoid;
    1447  		    break;
    1448  		}
    1449  		break;
    1450  	    case FcTypeLangSet:
    1451  		switch ((int) op) {
    1452  		case FcOpPlus:
    1453  		    v.type = FcTypeLangSet;
    1454  		    v.u.l = FcLangSetUnion (vle.u.l, vre.u.l);
    1455  		    if (!v.u.l)
    1456  			v.type = FcTypeVoid;
    1457  		    break;
    1458  		case FcOpMinus:
    1459  		    v.type = FcTypeLangSet;
    1460  		    v.u.l = FcLangSetSubtract (vle.u.l, vre.u.l);
    1461  		    if (!v.u.l)
    1462  			v.type = FcTypeVoid;
    1463  		    break;
    1464  		default:
    1465  		    v.type = FcTypeVoid;
    1466  		    break;
    1467  		}
    1468  		break;
    1469  	    default:
    1470  		v.type = FcTypeVoid;
    1471  		break;
    1472  	    }
    1473  	}
    1474  	else
    1475  	    v.type = FcTypeVoid;
    1476  	FcValueDestroy (vl);
    1477  	FcValueDestroy (vr);
    1478  	break;
    1479      case FcOpNot:
    1480  	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
    1481  	switch ((int) vl.type) {
    1482  	case FcTypeBool:
    1483  	    v.type = FcTypeBool;
    1484  	    v.u.b = !vl.u.b;
    1485  	    break;
    1486  	default:
    1487  	    v.type = FcTypeVoid;
    1488  	    break;
    1489  	}
    1490  	FcValueDestroy (vl);
    1491  	break;
    1492      case FcOpFloor:
    1493  	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
    1494  	switch ((int) vl.type) {
    1495  	case FcTypeInteger:
    1496  	    v = vl;
    1497  	    break;
    1498  	case FcTypeDouble:
    1499  	    v.type = FcTypeInteger;
    1500  	    v.u.i = FcDoubleFloor (vl.u.d);
    1501  	    break;
    1502  	default:
    1503  	    v.type = FcTypeVoid;
    1504  	    break;
    1505  	}
    1506  	FcValueDestroy (vl);
    1507  	break;
    1508      case FcOpCeil:
    1509  	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
    1510  	switch ((int) vl.type) {
    1511  	case FcTypeInteger:
    1512  	    v = vl;
    1513  	    break;
    1514  	case FcTypeDouble:
    1515  	    v.type = FcTypeInteger;
    1516  	    v.u.i = FcDoubleCeil (vl.u.d);
    1517  	    break;
    1518  	default:
    1519  	    v.type = FcTypeVoid;
    1520  	    break;
    1521  	}
    1522  	FcValueDestroy (vl);
    1523  	break;
    1524      case FcOpRound:
    1525  	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
    1526  	switch ((int) vl.type) {
    1527  	case FcTypeInteger:
    1528  	    v = vl;
    1529  	    break;
    1530  	case FcTypeDouble:
    1531  	    v.type = FcTypeInteger;
    1532  	    v.u.i = FcDoubleRound (vl.u.d);
    1533  	    break;
    1534  	default:
    1535  	    v.type = FcTypeVoid;
    1536  	    break;
    1537  	}
    1538  	FcValueDestroy (vl);
    1539  	break;
    1540      case FcOpTrunc:
    1541  	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
    1542  	switch ((int) vl.type) {
    1543  	case FcTypeInteger:
    1544  	    v = vl;
    1545  	    break;
    1546  	case FcTypeDouble:
    1547  	    v.type = FcTypeInteger;
    1548  	    v.u.i = FcDoubleTrunc (vl.u.d);
    1549  	    break;
    1550  	default:
    1551  	    v.type = FcTypeVoid;
    1552  	    break;
    1553  	}
    1554  	FcValueDestroy (vl);
    1555  	break;
    1556      default:
    1557  	v.type = FcTypeVoid;
    1558  	break;
    1559      }
    1560      return v;
    1561  }
    1562  
    1563  /* The bulk of the time in FcConfigSubstitute is spent walking
    1564   * lists of family names. We speed this up with a hash table.
    1565   * Since we need to take the ignore-blanks option into account,
    1566   * we use two separate hash tables.
    1567   */
    1568  typedef struct
    1569  {
    1570    int count;
    1571  } FamilyTableEntry;
    1572  
    1573  
    1574  typedef struct
    1575  {
    1576    FcHashTable *family_blank_hash;
    1577    FcHashTable *family_hash;
    1578  } FamilyTable;
    1579  
    1580  static FcBool
    1581  FamilyTableLookup (FamilyTable   *table,
    1582                     FcOp           _op,
    1583                     const FcChar8 *s)
    1584  {
    1585      FamilyTableEntry *fe;
    1586      int flags = FC_OP_GET_FLAGS (_op);
    1587      FcHashTable *hash;
    1588  
    1589      if (flags & FcOpFlagIgnoreBlanks)
    1590          hash = table->family_blank_hash;
    1591      else
    1592          hash = table->family_hash;
    1593  
    1594      return FcHashTableFind (hash, (const void *)s, (void **)&fe);
    1595  }
    1596  
    1597  static void
    1598  FamilyTableAdd (FamilyTable    *table,
    1599                  FcValueListPtr  values)
    1600  {
    1601      FcValueListPtr ll;
    1602      for (ll = values; ll; ll = FcValueListNext (ll))
    1603          {
    1604              const FcChar8 *s = FcValueString (&ll->value);
    1605              FamilyTableEntry *fe;
    1606  
    1607              if (!FcHashTableFind (table->family_hash, (const void *)s, (void **)&fe))
    1608              {
    1609                  fe = malloc (sizeof (FamilyTableEntry));
    1610                  fe->count = 0;
    1611                  FcHashTableAdd (table->family_hash, (void *)s, fe);
    1612              }
    1613              fe->count++;
    1614  
    1615              if (!FcHashTableFind (table->family_blank_hash, (const void *)s, (void **)&fe))
    1616              {
    1617                  fe = malloc (sizeof (FamilyTableEntry));
    1618                  fe->count = 0;
    1619                  FcHashTableAdd (table->family_blank_hash, (void *)s, fe);
    1620              }
    1621              fe->count++;
    1622         }
    1623  }
    1624  
    1625  static void
    1626  FamilyTableDel (FamilyTable   *table,
    1627                  const FcChar8 *s)
    1628  {
    1629      FamilyTableEntry *fe;
    1630  
    1631      if (FcHashTableFind (table->family_hash, (void *)s, (void **)&fe))
    1632      {
    1633          fe->count--;
    1634          if (fe->count == 0)
    1635              FcHashTableRemove (table->family_hash, (void *)s);
    1636      }
    1637  
    1638      if (FcHashTableFind (table->family_blank_hash, (void *)s, (void **)&fe))
    1639      {
    1640          fe->count--;
    1641          if (fe->count == 0)
    1642              FcHashTableRemove (table->family_blank_hash, (void *)s);
    1643      }
    1644  }
    1645  
    1646  static FcBool
    1647  copy_string (const void *src, void **dest)
    1648  {
    1649    *dest = strdup ((char *)src);
    1650    return FcTrue;
    1651  }
    1652  
    1653  static void
    1654  FamilyTableInit (FamilyTable *table,
    1655                   FcPattern *p)
    1656  {
    1657      FcPatternElt *e;
    1658  
    1659      table->family_blank_hash = FcHashTableCreate ((FcHashFunc)FcStrHashIgnoreBlanksAndCase,
    1660                                            (FcCompareFunc)FcStrCmpIgnoreBlanksAndCase,
    1661                                            (FcCopyFunc)copy_string,
    1662                                            NULL,
    1663                                            free,
    1664                                            free);
    1665      table->family_hash = FcHashTableCreate ((FcHashFunc)FcStrHashIgnoreCase,
    1666                                            (FcCompareFunc)FcStrCmpIgnoreCase,
    1667                                            (FcCopyFunc)copy_string,
    1668                                            NULL,
    1669                                            free,
    1670                                            free);
    1671      e = FcPatternObjectFindElt (p, FC_FAMILY_OBJECT);
    1672      if (e)
    1673          FamilyTableAdd (table, FcPatternEltValues (e));
    1674  }
    1675  
    1676  static void
    1677  FamilyTableClear (FamilyTable *table)
    1678  {
    1679      if (table->family_blank_hash)
    1680          FcHashTableDestroy (table->family_blank_hash);
    1681      if (table->family_hash)
    1682          FcHashTableDestroy (table->family_hash);
    1683  }
    1684  
    1685  static FcValueList *
    1686  FcConfigMatchValueList (FcPattern	*p,
    1687  			FcPattern	*p_pat,
    1688  			FcMatchKind      kind,
    1689  			FcTest		*t,
    1690  			FcValueList	*values,
    1691                          FamilyTable     *table)
    1692  {
    1693      FcValueList	    *ret = 0;
    1694      FcExpr	    *e = t->expr;
    1695      FcValue	    value;
    1696      FcValueList	    *v;
    1697      FcOp            op;
    1698  
    1699      while (e)
    1700      {
    1701  	/* Compute the value of the match expression */
    1702  	if (FC_OP_GET_OP (e->op) == FcOpComma)
    1703  	{
    1704  	    value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
    1705  	    e = e->u.tree.right;
    1706  	}
    1707  	else
    1708  	{
    1709  	    value = FcConfigEvaluate (p, p_pat, kind, e);
    1710  	    e = 0;
    1711  	}
    1712  
    1713          if (t->object == FC_FAMILY_OBJECT && table)
    1714          {
    1715              op = FC_OP_GET_OP (t->op);
    1716              if (op == FcOpEqual || op == FcOpListing)
    1717              {
    1718                  if (!FamilyTableLookup (table, t->op, FcValueString (&value)))
    1719                  {
    1720                      ret = 0;
    1721                      goto done;
    1722                  }
    1723              }
    1724              if (op == FcOpNotEqual && t->qual == FcQualAll)
    1725              {
    1726                  ret = 0;
    1727                  if (!FamilyTableLookup (table, t->op, FcValueString (&value)))
    1728                  {
    1729                      ret = values;
    1730                  }
    1731                  goto done;
    1732              }
    1733          }
    1734  	for (v = values; v; v = FcValueListNext(v))
    1735  	{
    1736  	    /* Compare the pattern value to the match expression value */
    1737  	    if (FcConfigCompareValue (&v->value, t->op, &value))
    1738  	    {
    1739  		if (!ret)
    1740  		    ret = v;
    1741                  if (t->qual != FcQualAll)
    1742                      break;
    1743  	    }
    1744  	    else
    1745  	    {
    1746  		if (t->qual == FcQualAll)
    1747  		{
    1748  		    ret = 0;
    1749  		    break;
    1750  		}
    1751  	    }
    1752  	}
    1753  done:
    1754  	FcValueDestroy (value);
    1755      }
    1756      return ret;
    1757  }
    1758  
    1759  static FcValueList *
    1760  FcConfigValues (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e, FcValueBinding binding)
    1761  {
    1762      FcValueList	*l;
    1763  
    1764      if (!e)
    1765  	return 0;
    1766      l = (FcValueList *) malloc (sizeof (FcValueList));
    1767      if (!l)
    1768  	return 0;
    1769      if (FC_OP_GET_OP (e->op) == FcOpComma)
    1770      {
    1771  	l->value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
    1772  	l->next = FcConfigValues (p, p_pat, kind, e->u.tree.right, binding);
    1773      }
    1774      else
    1775      {
    1776  	l->value = FcConfigEvaluate (p, p_pat, kind, e);
    1777  	l->next = NULL;
    1778      }
    1779      l->binding = binding;
    1780      if (l->value.type == FcTypeVoid)
    1781      {
    1782  	FcValueList  *next = FcValueListNext(l);
    1783  
    1784  	free (l);
    1785  	l = next;
    1786      }
    1787  
    1788      return l;
    1789  }
    1790  
    1791  static FcBool
    1792  FcConfigAdd (FcValueListPtr *head,
    1793  	     FcValueList    *position,
    1794  	     FcBool	    append,
    1795  	     FcValueList    *new,
    1796  	     FcObject        object,
    1797               FamilyTable    *table)
    1798  {
    1799      FcValueListPtr  *prev, l, last, v;
    1800      FcValueBinding  sameBinding;
    1801  
    1802      /*
    1803       * Make sure the stored type is valid for built-in objects
    1804       */
    1805      for (l = new; l != NULL; l = FcValueListNext (l))
    1806      {
    1807  	if (!FcObjectValidType (object, l->value.type))
    1808  	{
    1809  	    fprintf (stderr,
    1810  		     "Fontconfig warning: FcPattern object %s does not accept value", FcObjectName (object));
    1811  	    FcValuePrintFile (stderr, l->value);
    1812  	    fprintf (stderr, "\n");
    1813  
    1814  	    if (FcDebug () & FC_DBG_EDIT)
    1815  	    {
    1816  		printf ("Not adding\n");
    1817  	    }
    1818  
    1819  	    return FcFalse;
    1820  	}
    1821      }
    1822  
    1823      if (object == FC_FAMILY_OBJECT && table)
    1824      {
    1825          FamilyTableAdd (table, new);
    1826      }
    1827  
    1828      if (position)
    1829  	sameBinding = position->binding;
    1830      else
    1831  	sameBinding = FcValueBindingWeak;
    1832      for (v = new; v != NULL; v = FcValueListNext(v))
    1833  	if (v->binding == FcValueBindingSame)
    1834  	    v->binding = sameBinding;
    1835      if (append)
    1836      {
    1837  	if (position)
    1838  	    prev = &position->next;
    1839  	else
    1840  	    for (prev = head; *prev != NULL;
    1841  		 prev = &(*prev)->next)
    1842  		;
    1843      }
    1844      else
    1845      {
    1846  	if (position)
    1847  	{
    1848  	    for (prev = head; *prev != NULL;
    1849  		 prev = &(*prev)->next)
    1850  	    {
    1851  		if (*prev == position)
    1852  		    break;
    1853  	    }
    1854  	}
    1855  	else
    1856  	    prev = head;
    1857  
    1858  	if (FcDebug () & FC_DBG_EDIT)
    1859  	{
    1860  	    if (*prev == NULL)
    1861  		printf ("position not on list\n");
    1862  	}
    1863      }
    1864  
    1865      if (FcDebug () & FC_DBG_EDIT)
    1866      {
    1867  	printf ("%s list before ", append ? "Append" : "Prepend");
    1868  	FcValueListPrintWithPosition (*head, *prev);
    1869  	printf ("\n");
    1870      }
    1871  
    1872      if (new)
    1873      {
    1874  	last = new;
    1875  	while (last->next != NULL)
    1876  	    last = last->next;
    1877  
    1878  	last->next = *prev;
    1879  	*prev = new;
    1880      }
    1881  
    1882      if (FcDebug () & FC_DBG_EDIT)
    1883      {
    1884  	printf ("%s list after ", append ? "Append" : "Prepend");
    1885  	FcValueListPrint (*head);
    1886  	printf ("\n");
    1887      }
    1888  
    1889      return FcTrue;
    1890  }
    1891  
    1892  static void
    1893  FcConfigDel (FcValueListPtr *head,
    1894  	     FcValueList    *position,
    1895               FcObject        object,
    1896               FamilyTable    *table)
    1897  {
    1898      FcValueListPtr *prev;
    1899  
    1900      if (object == FC_FAMILY_OBJECT && table)
    1901      {
    1902          FamilyTableDel (table, FcValueString (&position->value));
    1903      }
    1904  
    1905      for (prev = head; *prev != NULL; prev = &(*prev)->next)
    1906      {
    1907  	if (*prev == position)
    1908  	{
    1909  	    *prev = position->next;
    1910  	    position->next = NULL;
    1911  	    FcValueListDestroy (position);
    1912  	    break;
    1913  	}
    1914      }
    1915  }
    1916  
    1917  static void
    1918  FcConfigPatternAdd (FcPattern	*p,
    1919  		    FcObject	 object,
    1920  		    FcValueList	*list,
    1921  		    FcBool	 append,
    1922                      FamilyTable *table)
    1923  {
    1924      if (list)
    1925      {
    1926  	FcPatternElt    *e = FcPatternObjectInsertElt (p, object);
    1927  
    1928  	if (!e)
    1929  	    return;
    1930  	FcConfigAdd (&e->values, 0, append, list, object, table);
    1931      }
    1932  }
    1933  
    1934  /*
    1935   * Delete all values associated with a field
    1936   */
    1937  static void
    1938  FcConfigPatternDel (FcPattern	*p,
    1939  		    FcObject	 object,
    1940                      FamilyTable *table)
    1941  {
    1942      FcPatternElt    *e = FcPatternObjectFindElt (p, object);
    1943      if (!e)
    1944  	return;
    1945      while (e->values != NULL)
    1946  	FcConfigDel (&e->values, e->values, object, table);
    1947  }
    1948  
    1949  static void
    1950  FcConfigPatternCanon (FcPattern	    *p,
    1951  		      FcObject	    object)
    1952  {
    1953      FcPatternElt    *e = FcPatternObjectFindElt (p, object);
    1954      if (!e)
    1955  	return;
    1956      if (e->values == NULL)
    1957  	FcPatternObjectDel (p, object);
    1958  }
    1959  
    1960  FcBool
    1961  FcConfigSubstituteWithPat (FcConfig    *config,
    1962  			   FcPattern   *p,
    1963  			   FcPattern   *p_pat,
    1964  			   FcMatchKind kind)
    1965  {
    1966      FcValue v;
    1967      FcPtrList	    *s;
    1968      FcPtrListIter    iter, iter2;
    1969      FcRule          *r;
    1970      FcRuleSet	    *rs;
    1971      FcValueList	    *l, **value = NULL, *vl;
    1972      FcPattern	    *m;
    1973      FcStrSet	    *strs;
    1974      FcObject	    object = FC_INVALID_OBJECT;
    1975      FcPatternElt    **elt = NULL, *e;
    1976      int		    i, nobjs;
    1977      FcBool	    retval = FcTrue;
    1978      FcTest	    **tst = NULL;
    1979      FamilyTable     data;
    1980      FamilyTable     *table = &data;
    1981  
    1982      if (kind < FcMatchKindBegin || kind >= FcMatchKindEnd)
    1983  	return FcFalse;
    1984  
    1985      config = FcConfigReference (config);
    1986      if (!config)
    1987  	return FcFalse;
    1988  
    1989      s = config->subst[kind];
    1990      if (kind == FcMatchPattern)
    1991      {
    1992  	strs = FcGetDefaultLangs ();
    1993  	if (strs)
    1994  	{
    1995  	    FcStrList *l = FcStrListCreate (strs);
    1996  	    FcChar8 *lang;
    1997  	    FcValue v;
    1998  	    FcLangSet *lsund = FcLangSetCreate ();
    1999  
    2000  	    FcLangSetAdd (lsund, (const FcChar8 *)"und");
    2001  	    FcStrSetDestroy (strs);
    2002  	    while (l && (lang = FcStrListNext (l)))
    2003  	    {
    2004  		FcPatternElt *e = FcPatternObjectFindElt (p, FC_LANG_OBJECT);
    2005  
    2006  		if (e)
    2007  		{
    2008  		    FcValueListPtr ll;
    2009  
    2010  		    for (ll = FcPatternEltValues (e); ll; ll = FcValueListNext (ll))
    2011  		    {
    2012  			FcValue vv = FcValueCanonicalize (&ll->value);
    2013  
    2014  			if (vv.type == FcTypeLangSet)
    2015  			{
    2016  			    FcLangSet *ls = FcLangSetCreate ();
    2017  			    FcBool b;
    2018  
    2019  			    FcLangSetAdd (ls, lang);
    2020  			    b = FcLangSetContains (vv.u.l, ls);
    2021  			    FcLangSetDestroy (ls);
    2022  			    if (b)
    2023  				goto bail_lang;
    2024  			    if (FcLangSetContains (vv.u.l, lsund))
    2025  				goto bail_lang;
    2026  			}
    2027  			else
    2028  			{
    2029  			    if (FcStrCmpIgnoreCase (vv.u.s, lang) == 0)
    2030  				goto bail_lang;
    2031  			    if (FcStrCmpIgnoreCase (vv.u.s, (const FcChar8 *)"und") == 0)
    2032  				goto bail_lang;
    2033  			}
    2034  		    }
    2035  		}
    2036  		v.type = FcTypeString;
    2037  		v.u.s = lang;
    2038  
    2039  		FcPatternObjectAddWithBinding (p, FC_LANG_OBJECT, v, FcValueBindingWeak, FcTrue);
    2040  	    }
    2041  	bail_lang:
    2042  	    FcStrListDone (l);
    2043  	    FcLangSetDestroy (lsund);
    2044  	}
    2045  	if (FcPatternObjectGet (p, FC_PRGNAME_OBJECT, 0, &v) == FcResultNoMatch)
    2046  	{
    2047  	    FcChar8 *prgname = FcGetPrgname ();
    2048  	    if (prgname)
    2049  		FcPatternObjectAddString (p, FC_PRGNAME_OBJECT, prgname);
    2050  	}
    2051      }
    2052  
    2053      nobjs = FC_MAX_BASE_OBJECT + config->maxObjects + 2;
    2054      value = (FcValueList **) malloc (SIZEOF_VOID_P * nobjs);
    2055      if (!value)
    2056      {
    2057  	retval = FcFalse;
    2058  	goto bail1;
    2059      }
    2060      elt = (FcPatternElt **) malloc (SIZEOF_VOID_P * nobjs);
    2061      if (!elt)
    2062      {
    2063  	retval = FcFalse;
    2064  	goto bail1;
    2065      }
    2066      tst = (FcTest **) malloc (SIZEOF_VOID_P * nobjs);
    2067      if (!tst)
    2068      {
    2069  	retval = FcFalse;
    2070  	goto bail1;
    2071      }
    2072  
    2073      if (FcDebug () & FC_DBG_EDIT)
    2074      {
    2075  	printf ("FcConfigSubstitute ");
    2076  	FcPatternPrint (p);
    2077      }
    2078  
    2079      FamilyTableInit (&data, p);
    2080  
    2081      FcPtrListIterInit (s, &iter);
    2082      for (; FcPtrListIterIsValid (s, &iter); FcPtrListIterNext (s, &iter))
    2083      {
    2084  	rs = (FcRuleSet *) FcPtrListIterGetValue (s, &iter);
    2085  	if (FcDebug () & FC_DBG_EDIT)
    2086  	{
    2087  	    printf ("\nRule Set: %s\n", rs->name);
    2088  	}
    2089  	FcPtrListIterInit (rs->subst[kind], &iter2);
    2090  	for (; FcPtrListIterIsValid (rs->subst[kind], &iter2); FcPtrListIterNext (rs->subst[kind], &iter2))
    2091  	{
    2092  	    r = (FcRule *) FcPtrListIterGetValue (rs->subst[kind], &iter2);
    2093  	    for (i = 0; i < nobjs; i++)
    2094  	    {
    2095  		elt[i] = NULL;
    2096  		value[i] = NULL;
    2097  		tst[i] = NULL;
    2098  	    }
    2099  	    for (; r; r = r->next)
    2100  	    {
    2101  		switch (r->type) {
    2102  		case FcRuleUnknown:
    2103  		    /* shouldn't be reached */
    2104  		    break;
    2105  		case FcRuleTest:
    2106  		    object = FC_OBJ_ID (r->u.test->object);
    2107  		    /*
    2108  		     * Check the tests to see if
    2109  		     * they all match the pattern
    2110  		     */
    2111  		    if (FcDebug () & FC_DBG_EDIT)
    2112  		    {
    2113  			printf ("FcConfigSubstitute test ");
    2114  			FcTestPrint (r->u.test);
    2115  		    }
    2116  		    if (kind == FcMatchFont && r->u.test->kind == FcMatchPattern)
    2117                      {
    2118  			m = p_pat;
    2119                          table = NULL;
    2120                      }
    2121  		    else
    2122                      {
    2123  			m = p;
    2124                          table = &data;
    2125                      }
    2126  		    if (m)
    2127  			e = FcPatternObjectFindElt (m, r->u.test->object);
    2128  		    else
    2129  			e = NULL;
    2130  		    /* different 'kind' won't be the target of edit */
    2131  		    if (!elt[object] && kind == r->u.test->kind)
    2132  		    {
    2133  			elt[object] = e;
    2134  			tst[object] = r->u.test;
    2135  		    }
    2136  		    /*
    2137  		     * If there's no such field in the font,
    2138  		     * then FcQualAll matches while FcQualAny does not
    2139  		     */
    2140  		    if (!e)
    2141  		    {
    2142  			if (r->u.test->qual == FcQualAll)
    2143  			{
    2144  			    value[object] = NULL;
    2145  			    continue;
    2146  			}
    2147  			else
    2148  			{
    2149  			    if (FcDebug () & FC_DBG_EDIT)
    2150  				printf ("No match\n");
    2151  			    goto bail;
    2152  			}
    2153  		    }
    2154  		    /*
    2155  		     * Check to see if there is a match, mark the location
    2156  		     * to apply match-relative edits
    2157  		     */
    2158  		    vl = FcConfigMatchValueList (m, p_pat, kind, r->u.test, e->values, table);
    2159  		    /* different 'kind' won't be the target of edit */
    2160  		    if (!value[object] && kind == r->u.test->kind)
    2161  			value[object] = vl;
    2162  		    if (!vl ||
    2163  			(r->u.test->qual == FcQualFirst && vl != e->values) ||
    2164  			(r->u.test->qual == FcQualNotFirst && vl == e->values))
    2165  		    {
    2166  			if (FcDebug () & FC_DBG_EDIT)
    2167  			    printf ("No match\n");
    2168  			goto bail;
    2169  		    }
    2170  		    break;
    2171  		case FcRuleEdit:
    2172  		    object = FC_OBJ_ID (r->u.edit->object);
    2173  		    if (FcDebug () & FC_DBG_EDIT)
    2174  		    {
    2175  			printf ("Substitute ");
    2176  			FcEditPrint (r->u.edit);
    2177  			printf ("\n\n");
    2178  		    }
    2179  		    /*
    2180  		     * Evaluate the list of expressions
    2181  		     */
    2182  		    l = FcConfigValues (p, p_pat, kind, r->u.edit->expr, r->u.edit->binding);
    2183  		    if (tst[object] && (tst[object]->kind == FcMatchFont || kind == FcMatchPattern))
    2184  			elt[object] = FcPatternObjectFindElt (p, tst[object]->object);
    2185  
    2186  		    switch (FC_OP_GET_OP (r->u.edit->op)) {
    2187  		    case FcOpAssign:
    2188  			/*
    2189  			 * If there was a test, then replace the matched
    2190  			 * value with the new list of values
    2191  			 */
    2192  			if (value[object])
    2193  			{
    2194  			    FcValueList	*thisValue = value[object];
    2195  			    FcValueList	*nextValue = l;
    2196  
    2197  			    /*
    2198  			     * Append the new list of values after the current value
    2199  			     */
    2200  			    FcConfigAdd (&elt[object]->values, thisValue, FcTrue, l, r->u.edit->object, table);
    2201  			    /*
    2202  			     * Delete the marked value
    2203  			     */
    2204  			    if (thisValue)
    2205  				FcConfigDel (&elt[object]->values, thisValue, object, table);
    2206  			    /*
    2207  			     * Adjust a pointer into the value list to ensure
    2208  			     * future edits occur at the same place
    2209  			     */
    2210  			    value[object] = nextValue;
    2211  			    break;
    2212  			}
    2213  			/* fall through ... */
    2214  		    case FcOpAssignReplace:
    2215  			/*
    2216  			 * Delete all of the values and insert
    2217  			 * the new set
    2218  			 */
    2219  			FcConfigPatternDel (p, r->u.edit->object, table);
    2220  			FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue, table);
    2221  			/*
    2222  			 * Adjust a pointer into the value list as they no
    2223  			 * longer point to anything valid
    2224  			 */
    2225  			value[object] = NULL;
    2226  			break;
    2227  		    case FcOpPrepend:
    2228  			if (value[object])
    2229  			{
    2230  			    FcConfigAdd (&elt[object]->values, value[object], FcFalse, l, r->u.edit->object, table);
    2231  			    break;
    2232  			}
    2233  			/* fall through ... */
    2234  		    case FcOpPrependFirst:
    2235  			FcConfigPatternAdd (p, r->u.edit->object, l, FcFalse, table);
    2236  			break;
    2237  		    case FcOpAppend:
    2238  			if (value[object])
    2239  			{
    2240  			    FcConfigAdd (&elt[object]->values, value[object], FcTrue, l, r->u.edit->object, table);
    2241  			    break;
    2242  			}
    2243  			/* fall through ... */
    2244  		    case FcOpAppendLast:
    2245  			FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue, table);
    2246  			break;
    2247  		    case FcOpDelete:
    2248  			if (value[object])
    2249  			{
    2250  			    FcConfigDel (&elt[object]->values, value[object], object, table);
    2251  			    FcValueListDestroy (l);
    2252  			    break;
    2253  			}
    2254  			/* fall through ... */
    2255  		    case FcOpDeleteAll:
    2256  			FcConfigPatternDel (p, r->u.edit->object, table);
    2257  			FcValueListDestroy (l);
    2258  			break;
    2259  		    default:
    2260  			FcValueListDestroy (l);
    2261  			break;
    2262  		    }
    2263  		    /*
    2264  		     * Now go through the pattern and eliminate
    2265  		     * any properties without data
    2266  		     */
    2267  		    FcConfigPatternCanon (p, r->u.edit->object);
    2268  
    2269  		    if (FcDebug () & FC_DBG_EDIT)
    2270  		    {
    2271  			printf ("FcConfigSubstitute edit");
    2272  			FcPatternPrint (p);
    2273  		    }
    2274  		    break;
    2275  		}
    2276  	    }
    2277  	bail:;
    2278  	}
    2279      }
    2280      if (FcDebug () & FC_DBG_EDIT)
    2281      {
    2282  	printf ("FcConfigSubstitute done");
    2283  	FcPatternPrint (p);
    2284      }
    2285  bail1:
    2286      FamilyTableClear (&data);
    2287      if (elt)
    2288  	free (elt);
    2289      if (value)
    2290  	free (value);
    2291      if (tst)
    2292  	free (tst);
    2293      FcConfigDestroy (config);
    2294  
    2295      return retval;
    2296  }
    2297  
    2298  FcBool
    2299  FcConfigSubstitute (FcConfig	*config,
    2300  		    FcPattern	*p,
    2301  		    FcMatchKind	kind)
    2302  {
    2303      return FcConfigSubstituteWithPat (config, p, 0, kind);
    2304  }
    2305  
    2306  #if defined (_WIN32)
    2307  
    2308  static FcChar8 fontconfig_path[1000] = ""; /* MT-dontcare */
    2309  FcChar8 fontconfig_instprefix[1000] = ""; /* MT-dontcare */
    2310  
    2311  #  if (defined (PIC) || defined (DLL_EXPORT))
    2312  
    2313  BOOL WINAPI
    2314  DllMain (HINSTANCE hinstDLL,
    2315  	 DWORD     fdwReason,
    2316  	 LPVOID    lpvReserved);
    2317  
    2318  BOOL WINAPI
    2319  DllMain (HINSTANCE hinstDLL,
    2320  	 DWORD     fdwReason,
    2321  	 LPVOID    lpvReserved)
    2322  {
    2323    FcChar8 *p;
    2324  
    2325    switch (fdwReason) {
    2326    case DLL_PROCESS_ATTACH:
    2327        if (!GetModuleFileName ((HMODULE) hinstDLL, (LPCH) fontconfig_path,
    2328  			      sizeof (fontconfig_path)))
    2329  	  break;
    2330  
    2331        /* If the fontconfig DLL is in a "bin" or "lib" subfolder,
    2332         * assume it's a Unix-style installation tree, and use
    2333         * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the
    2334         * folder where the DLL is as FONTCONFIG_PATH.
    2335         */
    2336        p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\');
    2337        if (p)
    2338        {
    2339  	  *p = '\0';
    2340  	  p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\');
    2341  	  if (p && (FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "bin") == 0 ||
    2342  		    FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "lib") == 0))
    2343  	      *p = '\0';
    2344  	  strcat ((char *) fontconfig_instprefix, (char *) fontconfig_path);
    2345  	  strcat ((char *) fontconfig_path, "\\etc\\fonts");
    2346        }
    2347        else
    2348            fontconfig_path[0] = '\0';
    2349  
    2350        break;
    2351    }
    2352  
    2353    return TRUE;
    2354  }
    2355  
    2356  #  endif /* !PIC */
    2357  
    2358  #undef FONTCONFIG_PATH
    2359  #define FONTCONFIG_PATH fontconfig_path
    2360  
    2361  #endif /* !_WIN32 */
    2362  
    2363  #ifndef FONTCONFIG_FILE
    2364  #define FONTCONFIG_FILE	"fonts.conf"
    2365  #endif
    2366  
    2367  static FcChar8 *
    2368  FcConfigFileExists (const FcChar8 *dir, const FcChar8 *file)
    2369  {
    2370      FcChar8    *path;
    2371      int         size, osize;
    2372  
    2373      if (!dir)
    2374  	dir = (FcChar8 *) "";
    2375  
    2376      osize = strlen ((char *) dir) + 1 + strlen ((char *) file) + 1;
    2377      /*
    2378       * workaround valgrind warning because glibc takes advantage of how it knows memory is
    2379       * allocated to implement strlen by reading in groups of 4
    2380       */
    2381      size = (osize + 3) & ~3;
    2382  
    2383      path = malloc (size);
    2384      if (!path)
    2385  	return 0;
    2386  
    2387      strcpy ((char *) path, (const char *) dir);
    2388      /* make sure there's a single separator */
    2389  #ifdef _WIN32
    2390      if ((!path[0] || (path[strlen((char *) path)-1] != '/' &&
    2391  		      path[strlen((char *) path)-1] != '\\')) &&
    2392  	!(file[0] == '/' ||
    2393  	  file[0] == '\\' ||
    2394  	  (isalpha (file[0]) && file[1] == ':' && (file[2] == '/' || file[2] == '\\'))))
    2395  	strcat ((char *) path, "\\");
    2396  #else
    2397      if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/')
    2398  	strcat ((char *) path, "/");
    2399      else
    2400  	osize--;
    2401  #endif
    2402      strcat ((char *) path, (char *) file);
    2403  
    2404      if (access ((char *) path, R_OK) == 0)
    2405  	return path;
    2406  
    2407      FcStrFree (path);
    2408  
    2409      return 0;
    2410  }
    2411  
    2412  static FcChar8 **
    2413  FcConfigGetPath (void)
    2414  {
    2415      FcChar8    **path;
    2416      FcChar8    *env, *e, *colon;
    2417      FcChar8    *dir;
    2418      int	    npath;
    2419      int	    i;
    2420  
    2421      npath = 2;	/* default dir + null */
    2422      env = (FcChar8 *) getenv ("FONTCONFIG_PATH");
    2423      if (env)
    2424      {
    2425  	e = env;
    2426  	npath++;
    2427  	while (*e)
    2428  	    if (*e++ == FC_SEARCH_PATH_SEPARATOR)
    2429  		npath++;
    2430      }
    2431      path = calloc (npath, sizeof (FcChar8 *));
    2432      if (!path)
    2433  	goto bail0;
    2434      i = 0;
    2435  
    2436      if (env)
    2437      {
    2438  	e = env;
    2439  	while (*e)
    2440  	{
    2441  	    colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR);
    2442  	    if (!colon)
    2443  		colon = e + strlen ((char *) e);
    2444  	    path[i] = malloc (colon - e + 1);
    2445  	    if (!path[i])
    2446  		goto bail1;
    2447  	    strncpy ((char *) path[i], (const char *) e, colon - e);
    2448  	    path[i][colon - e] = '\0';
    2449  	    if (*colon)
    2450  		e = colon + 1;
    2451  	    else
    2452  		e = colon;
    2453  	    i++;
    2454  	}
    2455      }
    2456  
    2457  #ifdef _WIN32
    2458  	if (fontconfig_path[0] == '\0')
    2459  	{
    2460  		char *p;
    2461  		if(!GetModuleFileName(NULL, (LPCH) fontconfig_path, sizeof(fontconfig_path)))
    2462  			goto bail1;
    2463  		p = strrchr ((const char *) fontconfig_path, '\\');
    2464  		if (p) *p = '\0';
    2465  		strcat ((char *) fontconfig_path, "\\fonts");
    2466  	}
    2467  #endif
    2468      dir = (FcChar8 *) FONTCONFIG_PATH;
    2469      path[i] = malloc (strlen ((char *) dir) + 1);
    2470      if (!path[i])
    2471  	goto bail1;
    2472      strcpy ((char *) path[i], (const char *) dir);
    2473      return path;
    2474  
    2475  bail1:
    2476      for (i = 0; path[i]; i++)
    2477  	free (path[i]);
    2478      free (path);
    2479  bail0:
    2480      return 0;
    2481  }
    2482  
    2483  static void
    2484  FcConfigFreePath (FcChar8 **path)
    2485  {
    2486      FcChar8    **p;
    2487  
    2488      for (p = path; *p; p++)
    2489  	free (*p);
    2490      free (path);
    2491  }
    2492  
    2493  static FcBool	_FcConfigHomeEnabled = FcTrue; /* MT-goodenough */
    2494  
    2495  FcChar8 *
    2496  FcConfigHome (void)
    2497  {
    2498      if (_FcConfigHomeEnabled)
    2499      {
    2500          char *home = getenv ("HOME");
    2501  
    2502  #ifdef _WIN32
    2503  	if (home == NULL)
    2504  	    home = getenv ("USERPROFILE");
    2505  #endif
    2506  
    2507  	return (FcChar8 *) home;
    2508      }
    2509      return 0;
    2510  }
    2511  
    2512  FcChar8 *
    2513  FcConfigXdgCacheHome (void)
    2514  {
    2515      const char *env = getenv ("XDG_CACHE_HOME");
    2516      FcChar8 *ret = NULL;
    2517  
    2518      if (!_FcConfigHomeEnabled)
    2519  	return NULL;
    2520      if (env && env[0])
    2521  	ret = FcStrCopy ((const FcChar8 *)env);
    2522      else
    2523      {
    2524  	const FcChar8 *home = FcConfigHome ();
    2525  	size_t len = home ? strlen ((const char *)home) : 0;
    2526  
    2527  	ret = malloc (len + 7 + 1);
    2528  	if (ret)
    2529  	{
    2530  	    if (home)
    2531  		memcpy (ret, home, len);
    2532  	    memcpy (&ret[len], FC_DIR_SEPARATOR_S ".cache", 7);
    2533  	    ret[len + 7] = 0;
    2534  	}
    2535      }
    2536  
    2537      return ret;
    2538  }
    2539  
    2540  FcChar8 *
    2541  FcConfigXdgConfigHome (void)
    2542  {
    2543      const char *env = getenv ("XDG_CONFIG_HOME");
    2544      FcChar8 *ret = NULL;
    2545  
    2546      if (!_FcConfigHomeEnabled)
    2547  	return NULL;
    2548      if (env)
    2549  	ret = FcStrCopy ((const FcChar8 *)env);
    2550      else
    2551      {
    2552  	const FcChar8 *home = FcConfigHome ();
    2553  	size_t len = home ? strlen ((const char *)home) : 0;
    2554  
    2555  	ret = malloc (len + 8 + 1);
    2556  	if (ret)
    2557  	{
    2558  	    if (home)
    2559  		memcpy (ret, home, len);
    2560  	    memcpy (&ret[len], FC_DIR_SEPARATOR_S ".config", 8);
    2561  	    ret[len + 8] = 0;
    2562  	}
    2563      }
    2564  
    2565      return ret;
    2566  }
    2567  
    2568  FcChar8 *
    2569  FcConfigXdgDataHome (void)
    2570  {
    2571      const char *env = getenv ("XDG_DATA_HOME");
    2572      FcChar8 *ret = NULL;
    2573  
    2574      if (!_FcConfigHomeEnabled)
    2575  	return NULL;
    2576      if (env)
    2577  	ret = FcStrCopy ((const FcChar8 *)env);
    2578      else
    2579      {
    2580  	const FcChar8 *home = FcConfigHome ();
    2581  	size_t len = home ? strlen ((const char *)home) : 0;
    2582  
    2583  	ret = malloc (len + 13 + 1);
    2584  	if (ret)
    2585  	{
    2586  	    if (home)
    2587  		memcpy (ret, home, len);
    2588  	    memcpy (&ret[len], FC_DIR_SEPARATOR_S ".local" FC_DIR_SEPARATOR_S "share", 13);
    2589  	    ret[len + 13] = 0;
    2590  	}
    2591      }
    2592  
    2593      return ret;
    2594  }
    2595  
    2596  FcStrSet *
    2597  FcConfigXdgDataDirs (void)
    2598  {
    2599      const char *env = getenv ("XDG_DATA_DIRS");
    2600      FcStrSet *ret = FcStrSetCreate ();
    2601  
    2602      if (env)
    2603      {
    2604  	FcChar8 *ee, *e = ee = FcStrCopy ((const FcChar8 *) env);
    2605  
    2606  	/* We don't intentionally use FC_SEARCH_PATH_SEPARATOR here because of:
    2607  	 *   The directories in $XDG_DATA_DIRS should be seperated with a colon ':'.
    2608  	 * in doc.
    2609  	 */
    2610  	while (e)
    2611  	{
    2612  	    FcChar8 *p = (FcChar8 *) strchr ((const char *) e, ':');
    2613  	    FcChar8 *s;
    2614  	    size_t len;
    2615  
    2616  	    if (!p)
    2617  	    {
    2618  		s = FcStrCopy (e);
    2619  		e = NULL;
    2620  	    }
    2621  	    else
    2622  	    {
    2623  		*p = 0;
    2624  		s = FcStrCopy (e);
    2625  		e = p + 1;
    2626  	    }
    2627  	    len = strlen ((const char *) s);
    2628  	    if (s[len - 1] == FC_DIR_SEPARATOR)
    2629  	    {
    2630  		do
    2631  		{
    2632  		    len--;
    2633  		}
    2634  		while (len > 1 && s[len - 1] == FC_DIR_SEPARATOR);
    2635  		s[len] = 0;
    2636  	    }
    2637  	    FcStrSetAdd (ret, s);
    2638  	    FcStrFree (s);
    2639  	}
    2640  	FcStrFree (ee);
    2641      }
    2642      else
    2643      {
    2644  	/* From spec doc at https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html#variables
    2645  	 *
    2646  	 * If $XDG_DATA_DIRS is either not set or empty, a value equal to /usr/local/share/:/usr/share/ should be used.
    2647  	 */
    2648  	FcStrSetAdd (ret, (const FcChar8 *) "/usr/local/share");
    2649  	FcStrSetAdd (ret, (const FcChar8 *) "/usr/share");
    2650      }
    2651  
    2652      return ret;
    2653  }
    2654  
    2655  FcBool
    2656  FcConfigEnableHome (FcBool enable)
    2657  {
    2658      FcBool  prev = _FcConfigHomeEnabled;
    2659      _FcConfigHomeEnabled = enable;
    2660      return prev;
    2661  }
    2662  
    2663  FcChar8 *
    2664  FcConfigGetFilename (FcConfig      *config,
    2665  		     const FcChar8 *url)
    2666  {
    2667      FcChar8    *file, *dir, **path, **p;
    2668      const FcChar8 *sysroot;
    2669  
    2670      config = FcConfigReference (config);
    2671      if (!config)
    2672  	return NULL;
    2673      sysroot = FcConfigGetSysRoot (config);
    2674      if (!url || !*url)
    2675      {
    2676  	url = (FcChar8 *) getenv ("FONTCONFIG_FILE");
    2677  	if (!url)
    2678  	    url = (FcChar8 *) FONTCONFIG_FILE;
    2679      }
    2680      file = 0;
    2681  
    2682      if (FcStrIsAbsoluteFilename(url))
    2683      {
    2684  	if (sysroot)
    2685  	{
    2686  	    size_t len = strlen ((const char *) sysroot);
    2687  
    2688  	    /* Workaround to avoid adding sysroot repeatedly */
    2689  	    if (strncmp ((const char *) url, (const char *) sysroot, len) == 0)
    2690  		sysroot = NULL;
    2691  	}
    2692  	file = FcConfigFileExists (sysroot, url);
    2693  	goto bail;
    2694      }
    2695  
    2696      if (*url == '~')
    2697      {
    2698  	dir = FcConfigHome ();
    2699  	if (dir)
    2700  	{
    2701  	    FcChar8 *s;
    2702  
    2703  	    if (sysroot)
    2704  		s = FcStrBuildFilename (sysroot, dir, NULL);
    2705  	    else
    2706  		s = dir;
    2707  	    file = FcConfigFileExists (s, url + 1);
    2708  	    if (sysroot)
    2709  		FcStrFree (s);
    2710  	}
    2711  	else
    2712  	    file = 0;
    2713      }
    2714      else
    2715      {
    2716  	path = FcConfigGetPath ();
    2717  	if (!path)
    2718  	{
    2719  	    file = NULL;
    2720  	    goto bail;
    2721  	}
    2722  	for (p = path; *p; p++)
    2723  	{
    2724  	    FcChar8 *s;
    2725  
    2726  	    if (sysroot)
    2727  		s = FcStrBuildFilename (sysroot, *p, NULL);
    2728  	    else
    2729  		s = *p;
    2730  	    file = FcConfigFileExists (s, url);
    2731  	    if (sysroot)
    2732  		FcStrFree (s);
    2733  	    if (file)
    2734  		break;
    2735  	}
    2736  	FcConfigFreePath (path);
    2737      }
    2738  bail:
    2739      FcConfigDestroy (config);
    2740  
    2741      return file;
    2742  }
    2743  
    2744  FcChar8 *
    2745  FcConfigFilename (const FcChar8 *url)
    2746  {
    2747      return FcConfigGetFilename (NULL, url);
    2748  }
    2749  
    2750  FcChar8 *
    2751  FcConfigRealFilename (FcConfig		*config,
    2752  		      const FcChar8	*url)
    2753  {
    2754      FcChar8 *n = FcConfigGetFilename (config, url);
    2755  
    2756      if (n)
    2757      {
    2758  	FcChar8 buf[FC_PATH_MAX];
    2759  	ssize_t len;
    2760  	struct stat sb;
    2761  
    2762  	if ((len = FcReadLink (n, buf, sizeof (buf) - 1)) != -1)
    2763  	{
    2764  	    buf[len] = 0;
    2765  
    2766  	    /* We try to pick up a config from FONTCONFIG_FILE
    2767  	     * when url is null. don't try to address the real filename
    2768  	     * if it is a named pipe.
    2769  	     */
    2770  	    if (!url && FcStat (n, &sb) == 0 && S_ISFIFO (sb.st_mode))
    2771  		return n;
    2772  	    else if (!FcStrIsAbsoluteFilename (buf))
    2773  	    {
    2774  		FcChar8 *dirname = FcStrDirname (n);
    2775  		FcStrFree (n);
    2776  		if (!dirname)
    2777  		    return NULL;
    2778  
    2779  		FcChar8 *path = FcStrBuildFilename (dirname, buf, NULL);
    2780  		FcStrFree (dirname);
    2781  		if (!path)
    2782  		    return NULL;
    2783  
    2784  		n = FcStrCanonFilename (path);
    2785  		FcStrFree (path);
    2786  	    }
    2787  	    else
    2788  	    {
    2789  		FcStrFree (n);
    2790  		n = FcStrdup (buf);
    2791  	    }
    2792  	}
    2793      }
    2794  
    2795      return n;
    2796  }
    2797  
    2798  /*
    2799   * Manage the application-specific fonts
    2800   */
    2801  
    2802  FcBool
    2803  FcConfigAppFontAddFile (FcConfig    *config,
    2804  			const FcChar8  *file)
    2805  {
    2806      FcFontSet	*set;
    2807      FcStrSet	*subdirs;
    2808      FcStrList	*sublist;
    2809      FcChar8	*subdir;
    2810      FcBool	ret = FcTrue;
    2811  
    2812      config = FcConfigReference (config);
    2813      if (!config)
    2814  	return FcFalse;
    2815  
    2816      subdirs = FcStrSetCreateEx (FCSS_GROW_BY_64);
    2817      if (!subdirs)
    2818      {
    2819  	ret = FcFalse;
    2820  	goto bail;
    2821      }
    2822  
    2823      set = FcConfigGetFonts (config, FcSetApplication);
    2824      if (!set)
    2825      {
    2826  	set = FcFontSetCreate ();
    2827  	if (!set)
    2828  	{
    2829  	    FcStrSetDestroy (subdirs);
    2830  	    ret = FcFalse;
    2831  	    goto bail;
    2832  	}
    2833  	FcConfigSetFonts (config, set, FcSetApplication);
    2834      }
    2835  
    2836      if (!FcFileScanConfig (set, subdirs, file, config))
    2837      {
    2838  	FcStrSetDestroy (subdirs);
    2839  	ret = FcFalse;
    2840  	goto bail;
    2841      }
    2842      if ((sublist = FcStrListCreate (subdirs)))
    2843      {
    2844  	while ((subdir = FcStrListNext (sublist)))
    2845  	{
    2846  	    FcConfigAppFontAddDir (config, subdir);
    2847  	}
    2848  	FcStrListDone (sublist);
    2849      }
    2850      FcStrSetDestroy (subdirs);
    2851  bail:
    2852      FcConfigDestroy (config);
    2853  
    2854      return ret;
    2855  }
    2856  
    2857  FcBool
    2858  FcConfigAppFontAddDir (FcConfig	    *config,
    2859  		       const FcChar8   *dir)
    2860  {
    2861      FcFontSet	*set;
    2862      FcStrSet	*dirs;
    2863      FcBool	ret = FcTrue;
    2864  
    2865      config = FcConfigReference (config);
    2866      if (!config)
    2867  	return FcFalse;
    2868  
    2869      dirs = FcStrSetCreateEx (FCSS_GROW_BY_64);
    2870      if (!dirs)
    2871      {
    2872  	ret = FcFalse;
    2873  	goto bail;
    2874      }
    2875  
    2876      set = FcConfigGetFonts (config, FcSetApplication);
    2877      if (!set)
    2878      {
    2879  	set = FcFontSetCreate ();
    2880  	if (!set)
    2881  	{
    2882  	    FcStrSetDestroy (dirs);
    2883  	    ret = FcFalse;
    2884  	    goto bail;
    2885  	}
    2886  	FcConfigSetFonts (config, set, FcSetApplication);
    2887      }
    2888  
    2889      FcStrSetAddFilename (dirs, dir);
    2890  
    2891      if (!FcConfigAddDirList (config, FcSetApplication, dirs))
    2892      {
    2893  	FcStrSetDestroy (dirs);
    2894  	ret = FcFalse;
    2895  	goto bail;
    2896      }
    2897      FcStrSetDestroy (dirs);
    2898  bail:
    2899      FcConfigDestroy (config);
    2900  
    2901      return ret;
    2902  }
    2903  
    2904  void
    2905  FcConfigAppFontClear (FcConfig	    *config)
    2906  {
    2907      config = FcConfigReference (config);
    2908      if (!config)
    2909  	return;
    2910  
    2911      FcConfigSetFonts (config, 0, FcSetApplication);
    2912  
    2913      FcConfigDestroy (config);
    2914  }
    2915  
    2916  /*
    2917   * Manage filename-based font source selectors
    2918   */
    2919  
    2920  FcBool
    2921  FcConfigGlobAdd (FcConfig	*config,
    2922  		 const FcChar8  *glob,
    2923  		 FcBool		accept)
    2924  {
    2925      FcStrSet	*set = accept ? config->acceptGlobs : config->rejectGlobs;
    2926  	FcChar8	*realglob = FcStrCopyFilename(glob);
    2927  	if (!realglob)
    2928  		return FcFalse;
    2929  
    2930      FcBool	 ret = FcStrSetAdd (set, realglob);
    2931      FcStrFree(realglob);
    2932      return ret;
    2933  }
    2934  
    2935  static FcBool
    2936  FcConfigGlobsMatch (const FcStrSet	*globs,
    2937  		    const FcChar8	*string)
    2938  {
    2939      int	i;
    2940  
    2941      for (i = 0; i < globs->num; i++)
    2942  	if (FcStrGlobMatch (globs->strs[i], string))
    2943  	    return FcTrue;
    2944      return FcFalse;
    2945  }
    2946  
    2947  FcBool
    2948  FcConfigAcceptFilename (FcConfig	*config,
    2949  			const FcChar8	*filename)
    2950  {
    2951      if (FcConfigGlobsMatch (config->acceptGlobs, filename))
    2952  	return FcTrue;
    2953      if (FcConfigGlobsMatch (config->rejectGlobs, filename))
    2954  	return FcFalse;
    2955      return FcTrue;
    2956  }
    2957  
    2958  /*
    2959   * Manage font-pattern based font source selectors
    2960   */
    2961  
    2962  FcBool
    2963  FcConfigPatternsAdd (FcConfig	*config,
    2964  		     FcPattern	*pattern,
    2965  		     FcBool	accept)
    2966  {
    2967      FcFontSet	*set = accept ? config->acceptPatterns : config->rejectPatterns;
    2968  
    2969      return FcFontSetAdd (set, pattern);
    2970  }
    2971  
    2972  static FcBool
    2973  FcConfigPatternsMatch (const FcFontSet	*patterns,
    2974  		       const FcPattern	*font)
    2975  {
    2976      int i;
    2977  
    2978      for (i = 0; i < patterns->nfont; i++)
    2979  	if (FcListPatternMatchAny (patterns->fonts[i], font))
    2980  	    return FcTrue;
    2981      return FcFalse;
    2982  }
    2983  
    2984  FcBool
    2985  FcConfigAcceptFont (FcConfig	    *config,
    2986  		    const FcPattern *font)
    2987  {
    2988      if (FcConfigPatternsMatch (config->acceptPatterns, font))
    2989  	return FcTrue;
    2990      if (FcConfigPatternsMatch (config->rejectPatterns, font))
    2991  	return FcFalse;
    2992      return FcTrue;
    2993  }
    2994  
    2995  const FcChar8 *
    2996  FcConfigGetSysRoot (const FcConfig *config)
    2997  {
    2998      if (!config)
    2999      {
    3000  	config = FcConfigGetCurrent ();
    3001  	if (!config)
    3002  	    return NULL;
    3003      }
    3004      return config->sysRoot;
    3005  }
    3006  
    3007  void
    3008  FcConfigSetSysRoot (FcConfig      *config,
    3009  		    const FcChar8 *sysroot)
    3010  {
    3011      FcChar8 *s = NULL;
    3012      FcBool init = FcFalse;
    3013      int nretry = 3;
    3014  
    3015  retry:
    3016      if (!config)
    3017      {
    3018  	/* We can't use FcConfigGetCurrent() here to ensure
    3019  	 * the sysroot is set prior to initialize FcConfig,
    3020  	 * to avoid loading caches from non-sysroot dirs.
    3021  	 * So postpone the initialization later.
    3022  	 */
    3023  	config = fc_atomic_ptr_get (&_fcConfig);
    3024  	if (!config)
    3025  	{
    3026  	    config = FcConfigCreate ();
    3027  	    if (!config)
    3028  		return;
    3029  	    init = FcTrue;
    3030  	}
    3031      }
    3032  
    3033      if (sysroot)
    3034      {
    3035  	s = FcStrRealPath (sysroot);
    3036  	if (!s)
    3037  	    return;
    3038      }
    3039  
    3040      if (config->sysRoot)
    3041  	FcStrFree (config->sysRoot);
    3042  
    3043      config->sysRoot = s;
    3044      if (init)
    3045      {
    3046  	config = FcInitLoadOwnConfigAndFonts (config);
    3047  	if (!config)
    3048  	{
    3049  	    /* Something failed. this is usually unlikely. so retrying */
    3050  	    init = FcFalse;
    3051  	    if (--nretry == 0)
    3052  	    {
    3053  		fprintf (stderr, "Fontconfig warning: Unable to initialize config and retry limit exceeded. sysroot functionality may not work as expected.\n");
    3054  		return;
    3055  	    }
    3056  	    goto retry;
    3057  	}
    3058  	FcConfigSetCurrent (config);
    3059  	/* FcConfigSetCurrent() increases the refcount.
    3060  	 * decrease it here to avoid the memory leak.
    3061  	 */
    3062  	FcConfigDestroy (config);
    3063      }
    3064  }
    3065  
    3066  FcRuleSet *
    3067  FcRuleSetCreate (const FcChar8 *name)
    3068  {
    3069      FcRuleSet *ret = (FcRuleSet *) malloc (sizeof (FcRuleSet));
    3070      FcMatchKind k;
    3071      const FcChar8 *p;
    3072  
    3073      if (!name)
    3074  	p = (const FcChar8 *)"";
    3075      else
    3076  	p = name;
    3077  
    3078      if (ret)
    3079      {
    3080  	ret->name = FcStrdup (p);
    3081  	ret->description = NULL;
    3082  	ret->domain = NULL;
    3083  	for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++)
    3084  	    ret->subst[k] = FcPtrListCreate (FcDestroyAsRule);
    3085  	FcRefInit (&ret->ref, 1);
    3086      }
    3087  
    3088      return ret;
    3089  }
    3090  
    3091  void
    3092  FcRuleSetDestroy (FcRuleSet *rs)
    3093  {
    3094      FcMatchKind k;
    3095  
    3096      if (!rs)
    3097  	return;
    3098      if (FcRefDec (&rs->ref) != 1)
    3099  	return;
    3100  
    3101      if (rs->name)
    3102  	FcStrFree (rs->name);
    3103      if (rs->description)
    3104  	FcStrFree (rs->description);
    3105      if (rs->domain)
    3106  	FcStrFree (rs->domain);
    3107      for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++)
    3108  	FcPtrListDestroy (rs->subst[k]);
    3109  
    3110      free (rs);
    3111  }
    3112  
    3113  void
    3114  FcRuleSetReference (FcRuleSet *rs)
    3115  {
    3116      if (!FcRefIsConst (&rs->ref))
    3117  	FcRefInc (&rs->ref);
    3118  }
    3119  
    3120  void
    3121  FcRuleSetEnable (FcRuleSet	*rs,
    3122  		 FcBool		flag)
    3123  {
    3124      if (rs)
    3125      {
    3126  	rs->enabled = flag;
    3127  	/* XXX: we may want to provide a feature
    3128  	 * to enable/disable rulesets through API
    3129  	 * in the future?
    3130  	 */
    3131      }
    3132  }
    3133  
    3134  void
    3135  FcRuleSetAddDescription (FcRuleSet	*rs,
    3136  			 const FcChar8	*domain,
    3137  			 const FcChar8	*description)
    3138  {
    3139      if (rs->domain)
    3140  	FcStrFree (rs->domain);
    3141      if (rs->description)
    3142  	FcStrFree (rs->description);
    3143  
    3144      rs->domain = domain ? FcStrdup (domain) : NULL;
    3145      rs->description = description ? FcStrdup (description) : NULL;
    3146  }
    3147  
    3148  int
    3149  FcRuleSetAdd (FcRuleSet		*rs,
    3150  	      FcRule		*rule,
    3151  	      FcMatchKind	kind)
    3152  {
    3153      FcPtrListIter iter;
    3154      FcRule *r;
    3155      int n = 0, ret;
    3156  
    3157      if (!rs ||
    3158         kind < FcMatchKindBegin || kind >= FcMatchKindEnd)
    3159  	return -1;
    3160      FcPtrListIterInitAtLast (rs->subst[kind], &iter);
    3161      if (!FcPtrListIterAdd (rs->subst[kind], &iter, rule))
    3162  	return -1;
    3163  
    3164      for (r = rule; r; r = r->next)
    3165      {
    3166  	switch (r->type)
    3167  	{
    3168  	case FcRuleTest:
    3169  	    if (r->u.test)
    3170  	    {
    3171  		if (r->u.test->kind == FcMatchDefault)
    3172  		    r->u.test->kind = kind;
    3173  		if (n < r->u.test->object)
    3174  		    n = r->u.test->object;
    3175  	    }
    3176  	    break;
    3177  	case FcRuleEdit:
    3178  	    if (n < r->u.edit->object)
    3179  		n = r->u.edit->object;
    3180  	    break;
    3181  	default:
    3182  	    break;
    3183  	}
    3184      }
    3185      if (FcDebug () & FC_DBG_EDIT)
    3186      {
    3187  	printf ("Add Rule(kind:%d, name: %s) ", kind, rs->name);
    3188  	FcRulePrint (rule);
    3189      }
    3190      ret = FC_OBJ_ID (n) - FC_MAX_BASE_OBJECT;
    3191  
    3192      return ret < 0 ? 0 : ret;
    3193  }
    3194  
    3195  void
    3196  FcConfigFileInfoIterInit (FcConfig		*config,
    3197  			  FcConfigFileInfoIter	*iter)
    3198  {
    3199      FcConfig *c;
    3200      FcPtrListIter *i = (FcPtrListIter *)iter;
    3201  
    3202      if (!config)
    3203  	c = FcConfigGetCurrent ();
    3204      else
    3205  	c = config;
    3206      FcPtrListIterInit (c->rulesetList, i);
    3207  }
    3208  
    3209  FcBool
    3210  FcConfigFileInfoIterNext (FcConfig		*config,
    3211  			  FcConfigFileInfoIter	*iter)
    3212  {
    3213      FcConfig *c;
    3214      FcPtrListIter *i = (FcPtrListIter *)iter;
    3215  
    3216      if (!config)
    3217  	c = FcConfigGetCurrent ();
    3218      else
    3219  	c = config;
    3220      if (FcPtrListIterIsValid (c->rulesetList, i))
    3221      {
    3222  	FcPtrListIterNext (c->rulesetList, i);
    3223      }
    3224      else
    3225  	return FcFalse;
    3226  
    3227      return FcTrue;
    3228  }
    3229  
    3230  FcBool
    3231  FcConfigFileInfoIterGet (FcConfig		*config,
    3232  			 FcConfigFileInfoIter	*iter,
    3233  			 FcChar8		**name,
    3234  			 FcChar8		**description,
    3235  			 FcBool			*enabled)
    3236  {
    3237      FcConfig *c;
    3238      FcRuleSet *r;
    3239      FcPtrListIter *i = (FcPtrListIter *)iter;
    3240  
    3241      if (!config)
    3242  	c = FcConfigGetCurrent ();
    3243      else
    3244  	c = config;
    3245      if (!FcPtrListIterIsValid (c->rulesetList, i))
    3246  	return FcFalse;
    3247      r = FcPtrListIterGetValue (c->rulesetList, i);
    3248      if (name)
    3249  	*name = FcStrdup (r->name && r->name[0] ? r->name : (const FcChar8 *) "fonts.conf");
    3250      if (description)
    3251  	*description = FcStrdup (!r->description ? _("No description") :
    3252  				 dgettext (r->domain ? (const char *) r->domain : GETTEXT_PACKAGE "-conf",
    3253  					   (const char *) r->description));
    3254      if (enabled)
    3255  	*enabled = r->enabled;
    3256  
    3257      return FcTrue;
    3258  }
    3259  
    3260  #define __fccfg__
    3261  #include "fcaliastail.h"
    3262  #undef __fccfg__