(root)/
fontconfig-2.14.2/
src/
fcname.c
       1  /*
       2   * fontconfig/src/fcname.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  #include "fcint.h"
      26  #include <ctype.h>
      27  #include <stdlib.h>
      28  #include <string.h>
      29  #include <stdio.h>
      30  
      31  static const FcObjectType FcObjects[] = {
      32  #define FC_OBJECT(NAME, Type, Cmp) { FC_##NAME, Type },
      33  #include "fcobjs.h"
      34  #undef FC_OBJECT
      35  };
      36  
      37  #define NUM_OBJECT_TYPES ((int) (sizeof FcObjects / sizeof FcObjects[0]))
      38  
      39  static const FcObjectType *
      40  FcObjectFindById (FcObject object)
      41  {
      42      if (1 <= object && object <= NUM_OBJECT_TYPES)
      43  	return &FcObjects[object - 1];
      44      return FcObjectLookupOtherTypeById (object);
      45  }
      46  
      47  FcBool
      48  FcNameRegisterObjectTypes (const FcObjectType *types, int ntypes)
      49  {
      50      /* Deprecated. */
      51      return FcFalse;
      52  }
      53  
      54  FcBool
      55  FcNameUnregisterObjectTypes (const FcObjectType *types, int ntypes)
      56  {
      57      /* Deprecated. */
      58      return FcFalse;
      59  }
      60  
      61  const FcObjectType *
      62  FcNameGetObjectType (const char *object)
      63  {
      64      int id = FcObjectLookupBuiltinIdByName (object);
      65  
      66      if (!id)
      67  	return FcObjectLookupOtherTypeByName (object);
      68  
      69      return &FcObjects[id - 1];
      70  }
      71  
      72  FcBool
      73  FcObjectValidType (FcObject object, FcType type)
      74  {
      75      const FcObjectType    *t = FcObjectFindById (object);
      76  
      77      if (t) {
      78  	switch ((int) t->type) {
      79  	case FcTypeUnknown:
      80  	    return FcTrue;
      81  	case FcTypeDouble:
      82  	case FcTypeInteger:
      83  	    if (type == FcTypeDouble || type == FcTypeInteger)
      84  		return FcTrue;
      85  	    break;
      86  	case FcTypeLangSet:
      87  	    if (type == FcTypeLangSet || type == FcTypeString)
      88  		return FcTrue;
      89  	    break;
      90  	case FcTypeRange:
      91  	    if (type == FcTypeRange ||
      92  		type == FcTypeDouble ||
      93  		type == FcTypeInteger)
      94  		return FcTrue;
      95  	    break;
      96  	default:
      97  	    if (type == t->type)
      98  		return FcTrue;
      99  	    break;
     100  	}
     101  	return FcFalse;
     102      }
     103      return FcTrue;
     104  }
     105  
     106  FcObject
     107  FcObjectFromName (const char * name)
     108  {
     109      return FcObjectLookupIdByName (name);
     110  }
     111  
     112  FcObjectSet *
     113  FcObjectGetSet (void)
     114  {
     115      int		i;
     116      FcObjectSet	*os = NULL;
     117  
     118  
     119      os = FcObjectSetCreate ();
     120      for (i = 0; i < NUM_OBJECT_TYPES; i++)
     121  	FcObjectSetAdd (os, FcObjects[i].object);
     122  
     123      return os;
     124  }
     125  
     126  const char *
     127  FcObjectName (FcObject object)
     128  {
     129      const FcObjectType   *o = FcObjectFindById (object);
     130  
     131      if (o)
     132  	return o->object;
     133  
     134      return FcObjectLookupOtherNameById (object);
     135  }
     136  
     137  static const FcConstant _FcBaseConstants[] = {
     138      { (FcChar8 *) "thin",	    "weight",   FC_WEIGHT_THIN, },
     139      { (FcChar8 *) "extralight",	    "weight",   FC_WEIGHT_EXTRALIGHT, },
     140      { (FcChar8 *) "ultralight",	    "weight",   FC_WEIGHT_EXTRALIGHT, },
     141      { (FcChar8 *) "demilight",	    "weight",   FC_WEIGHT_DEMILIGHT, },
     142      { (FcChar8 *) "semilight",	    "weight",   FC_WEIGHT_DEMILIGHT, },
     143      { (FcChar8 *) "light",	    "weight",   FC_WEIGHT_LIGHT, },
     144      { (FcChar8 *) "book",	    "weight",	FC_WEIGHT_BOOK, },
     145      { (FcChar8 *) "regular",	    "weight",   FC_WEIGHT_REGULAR, },
     146      { (FcChar8 *) "normal",	    "weight",	FC_WEIGHT_NORMAL, },
     147      { (FcChar8 *) "medium",	    "weight",   FC_WEIGHT_MEDIUM, },
     148      { (FcChar8 *) "demibold",	    "weight",   FC_WEIGHT_DEMIBOLD, },
     149      { (FcChar8 *) "semibold",	    "weight",   FC_WEIGHT_DEMIBOLD, },
     150      { (FcChar8 *) "bold",	    "weight",   FC_WEIGHT_BOLD, },
     151      { (FcChar8 *) "extrabold",	    "weight",   FC_WEIGHT_EXTRABOLD, },
     152      { (FcChar8 *) "ultrabold",	    "weight",   FC_WEIGHT_EXTRABOLD, },
     153      { (FcChar8 *) "black",	    "weight",   FC_WEIGHT_BLACK, },
     154      { (FcChar8 *) "heavy",	    "weight",	FC_WEIGHT_HEAVY, },
     155      { (FcChar8 *) "extrablack",     "weight",	FC_WEIGHT_EXTRABLACK, },
     156      { (FcChar8 *) "ultrablack",     "weight",	FC_WEIGHT_ULTRABLACK, },
     157  
     158      { (FcChar8 *) "roman",	    "slant",    FC_SLANT_ROMAN, },
     159      { (FcChar8 *) "italic",	    "slant",    FC_SLANT_ITALIC, },
     160      { (FcChar8 *) "oblique",	    "slant",    FC_SLANT_OBLIQUE, },
     161  
     162      { (FcChar8 *) "ultracondensed", "width",	FC_WIDTH_ULTRACONDENSED },
     163      { (FcChar8 *) "extracondensed", "width",	FC_WIDTH_EXTRACONDENSED },
     164      { (FcChar8 *) "condensed",	    "width",	FC_WIDTH_CONDENSED },
     165      { (FcChar8 *) "semicondensed",  "width",	FC_WIDTH_SEMICONDENSED },
     166      { (FcChar8 *) "normal",	    "width",	FC_WIDTH_NORMAL },
     167      { (FcChar8 *) "semiexpanded",   "width",	FC_WIDTH_SEMIEXPANDED },
     168      { (FcChar8 *) "expanded",	    "width",	FC_WIDTH_EXPANDED },
     169      { (FcChar8 *) "extraexpanded",  "width",	FC_WIDTH_EXTRAEXPANDED },
     170      { (FcChar8 *) "ultraexpanded",  "width",	FC_WIDTH_ULTRAEXPANDED },
     171  
     172      { (FcChar8 *) "proportional",   "spacing",  FC_PROPORTIONAL, },
     173      { (FcChar8 *) "dual",	    "spacing",  FC_DUAL, },
     174      { (FcChar8 *) "mono",	    "spacing",  FC_MONO, },
     175      { (FcChar8 *) "charcell",	    "spacing",  FC_CHARCELL, },
     176  
     177      { (FcChar8 *) "unknown",	    "rgba",	    FC_RGBA_UNKNOWN },
     178      { (FcChar8 *) "rgb",	    "rgba",	    FC_RGBA_RGB, },
     179      { (FcChar8 *) "bgr",	    "rgba",	    FC_RGBA_BGR, },
     180      { (FcChar8 *) "vrgb",	    "rgba",	    FC_RGBA_VRGB },
     181      { (FcChar8 *) "vbgr",	    "rgba",	    FC_RGBA_VBGR },
     182      { (FcChar8 *) "none",	    "rgba",	    FC_RGBA_NONE },
     183  
     184      { (FcChar8 *) "hintnone",	    "hintstyle",   FC_HINT_NONE },
     185      { (FcChar8 *) "hintslight",	    "hintstyle",   FC_HINT_SLIGHT },
     186      { (FcChar8 *) "hintmedium",	    "hintstyle",   FC_HINT_MEDIUM },
     187      { (FcChar8 *) "hintfull",	    "hintstyle",   FC_HINT_FULL },
     188  
     189      { (FcChar8 *) "antialias",	    "antialias",    FcTrue },
     190      { (FcChar8 *) "hinting",	    "hinting",	    FcTrue },
     191      { (FcChar8 *) "verticallayout", "verticallayout",	FcTrue },
     192      { (FcChar8 *) "autohint",	    "autohint",	    FcTrue },
     193      { (FcChar8 *) "globaladvance",  "globaladvance",	FcTrue }, /* deprecated */
     194      { (FcChar8 *) "outline",	    "outline",	    FcTrue },
     195      { (FcChar8 *) "scalable",	    "scalable",	    FcTrue },
     196      { (FcChar8 *) "minspace",	    "minspace",	    FcTrue },
     197      { (FcChar8 *) "embolden",	    "embolden",	    FcTrue },
     198      { (FcChar8 *) "embeddedbitmap", "embeddedbitmap",	FcTrue },
     199      { (FcChar8 *) "decorative",	    "decorative",   FcTrue },
     200      { (FcChar8 *) "lcdnone",	    "lcdfilter",    FC_LCD_NONE },
     201      { (FcChar8 *) "lcddefault",	    "lcdfilter",    FC_LCD_DEFAULT },
     202      { (FcChar8 *) "lcdlight",	    "lcdfilter",    FC_LCD_LIGHT },
     203      { (FcChar8 *) "lcdlegacy",	    "lcdfilter",    FC_LCD_LEGACY },
     204  };
     205  
     206  #define NUM_FC_CONSTANTS   (sizeof _FcBaseConstants/sizeof _FcBaseConstants[0])
     207  
     208  FcBool
     209  FcNameRegisterConstants (const FcConstant *consts, int nconsts)
     210  {
     211      /* Deprecated. */
     212      return FcFalse;
     213  }
     214  
     215  FcBool
     216  FcNameUnregisterConstants (const FcConstant *consts, int nconsts)
     217  {
     218      /* Deprecated. */
     219      return FcFalse;
     220  }
     221  
     222  const FcConstant *
     223  FcNameGetConstant (const FcChar8 *string)
     224  {
     225      unsigned int	    i;
     226  
     227      for (i = 0; i < NUM_FC_CONSTANTS; i++)
     228  	if (!FcStrCmpIgnoreCase (string, _FcBaseConstants[i].name))
     229  	    return &_FcBaseConstants[i];
     230  
     231      return 0;
     232  }
     233  
     234  const FcConstant *
     235  FcNameGetConstantFor (const FcChar8 *string, const char *object)
     236  {
     237      unsigned int	    i;
     238  
     239      for (i = 0; i < NUM_FC_CONSTANTS; i++)
     240  	if (!FcStrCmpIgnoreCase (string, _FcBaseConstants[i].name) &&
     241  	    !FcStrCmpIgnoreCase ((const FcChar8 *)object, (const FcChar8 *)_FcBaseConstants[i].object))
     242  	    return &_FcBaseConstants[i];
     243  
     244      return 0;
     245  }
     246  
     247  FcBool
     248  FcNameConstant (const FcChar8 *string, int *result)
     249  {
     250      const FcConstant	*c;
     251  
     252      if ((c = FcNameGetConstant(string)))
     253      {
     254  	*result = c->value;
     255  	return FcTrue;
     256      }
     257      return FcFalse;
     258  }
     259  
     260  FcBool
     261  FcNameConstantWithObjectCheck (const FcChar8 *string, const char *object, int *result)
     262  {
     263      const FcConstant	*c;
     264  
     265      if ((c = FcNameGetConstantFor(string, object)))
     266      {
     267  	*result = c->value;
     268  	return FcTrue;
     269      }
     270      else if ((c = FcNameGetConstant(string)))
     271      {
     272  	if (strcmp (c->object, object) != 0)
     273  	{
     274  	    fprintf (stderr, "Fontconfig error: Unexpected constant name `%s' used for object `%s': should be `%s'\n", string, object, c->object);
     275  	    return FcFalse;
     276  	}
     277  	/* Unlikely to reach out */
     278  	*result = c->value;
     279  	return FcTrue;
     280      }
     281      return FcFalse;
     282  }
     283  
     284  FcBool
     285  FcNameBool (const FcChar8 *v, FcBool *result)
     286  {
     287      char    c0, c1;
     288  
     289      c0 = *v;
     290      c0 = FcToLower (c0);
     291      if (c0 == 't' || c0 == 'y' || c0 == '1')
     292      {
     293  	*result = FcTrue;
     294  	return FcTrue;
     295      }
     296      if (c0 == 'f' || c0 == 'n' || c0 == '0')
     297      {
     298  	*result = FcFalse;
     299  	return FcTrue;
     300      }
     301      if (c0 == 'd' || c0 == 'x' || c0 == '2')
     302      {
     303  	*result = FcDontCare;
     304  	return FcTrue;
     305      }
     306      if (c0 == 'o')
     307      {
     308  	c1 = v[1];
     309  	c1 = FcToLower (c1);
     310  	if (c1 == 'n')
     311  	{
     312  	    *result = FcTrue;
     313  	    return FcTrue;
     314  	}
     315  	if (c1 == 'f')
     316  	{
     317  	    *result = FcFalse;
     318  	    return FcTrue;
     319  	}
     320  	if (c1 == 'r')
     321  	{
     322  	    *result = FcDontCare;
     323  	    return FcTrue;
     324  	}
     325      }
     326      return FcFalse;
     327  }
     328  
     329  static FcValue
     330  FcNameConvert (FcType type, const char *object, FcChar8 *string)
     331  {
     332      FcValue	v;
     333      FcMatrix	m;
     334      double	b, e;
     335      char	*p;
     336  
     337      v.type = type;
     338      switch ((int) v.type) {
     339      case FcTypeInteger:
     340  	if (!FcNameConstantWithObjectCheck (string, object, &v.u.i))
     341  	    v.u.i = atoi ((char *) string);
     342  	break;
     343      case FcTypeString:
     344  	v.u.s = FcStrdup (string);
     345  	if (!v.u.s)
     346  	    v.type = FcTypeVoid;
     347  	break;
     348      case FcTypeBool:
     349  	if (!FcNameBool (string, &v.u.b))
     350  	    v.u.b = FcFalse;
     351  	break;
     352      case FcTypeDouble:
     353  	v.u.d = strtod ((char *) string, 0);
     354  	break;
     355      case FcTypeMatrix:
     356  	FcMatrixInit (&m);
     357  	sscanf ((char *) string, "%lg %lg %lg %lg", &m.xx, &m.xy, &m.yx, &m.yy);
     358  	v.u.m = FcMatrixCopy (&m);
     359  	break;
     360      case FcTypeCharSet:
     361  	v.u.c = FcNameParseCharSet (string);
     362  	if (!v.u.c)
     363  	    v.type = FcTypeVoid;
     364  	break;
     365      case FcTypeLangSet:
     366  	v.u.l = FcNameParseLangSet (string);
     367  	if (!v.u.l)
     368  	    v.type = FcTypeVoid;
     369  	break;
     370      case FcTypeRange:
     371  	if (sscanf ((char *) string, "[%lg %lg]", &b, &e) != 2)
     372  	{
     373  	    char *sc, *ec;
     374  	    size_t len = strlen ((const char *) string);
     375  	    int si, ei;
     376  
     377  	    sc = malloc (len + 1);
     378  	    ec = malloc (len + 1);
     379  	    if (sc && ec && sscanf ((char *) string, "[%s %[^]]]", sc, ec) == 2)
     380  	    {
     381  		if (FcNameConstantWithObjectCheck ((const FcChar8 *) sc, object, &si) &&
     382  		    FcNameConstantWithObjectCheck ((const FcChar8 *) ec, object, &ei))
     383  		    v.u.r =  FcRangeCreateDouble (si, ei);
     384  		else
     385  		    goto bail1;
     386  	    }
     387  	    else
     388  	    {
     389  	    bail1:
     390  		v.type = FcTypeDouble;
     391  		if (FcNameConstantWithObjectCheck (string, object, &si))
     392  		{
     393  		    v.u.d = (double) si;
     394  		} else {
     395  		    v.u.d = strtod ((char *) string, &p);
     396  		    if (p != NULL && p[0] != 0)
     397  			v.type = FcTypeVoid;
     398  		}
     399  	    }
     400  	    if (sc)
     401  		free (sc);
     402  	    if (ec)
     403  		free (ec);
     404  	}
     405  	else
     406  	    v.u.r = FcRangeCreateDouble (b, e);
     407  	break;
     408      default:
     409  	break;
     410      }
     411      return v;
     412  }
     413  
     414  static const FcChar8 *
     415  FcNameFindNext (const FcChar8 *cur, const char *delim, FcChar8 *save, FcChar8 *last)
     416  {
     417      FcChar8    c;
     418  
     419      while ((c = *cur))
     420      {
     421  	if (!isspace (c))
     422  	    break;
     423  	++cur;
     424      }
     425      while ((c = *cur))
     426      {
     427  	if (c == '\\')
     428  	{
     429  	    ++cur;
     430  	    if (!(c = *cur))
     431  		break;
     432  	}
     433  	else if (strchr (delim, c))
     434  	    break;
     435  	++cur;
     436  	*save++ = c;
     437      }
     438      *save = 0;
     439      *last = *cur;
     440      if (*cur)
     441  	cur++;
     442      return cur;
     443  }
     444  
     445  FcPattern *
     446  FcNameParse (const FcChar8 *name)
     447  {
     448      FcChar8		*save;
     449      FcPattern		*pat;
     450      double		d;
     451      FcChar8		*e;
     452      FcChar8		delim;
     453      FcValue		v;
     454      const FcObjectType	*t;
     455      const FcConstant	*c;
     456  
     457      /* freed below */
     458      save = malloc (strlen ((char *) name) + 1);
     459      if (!save)
     460  	goto bail0;
     461      pat = FcPatternCreate ();
     462      if (!pat)
     463  	goto bail1;
     464  
     465      for (;;)
     466      {
     467  	name = FcNameFindNext (name, "-,:", save, &delim);
     468  	if (save[0])
     469  	{
     470  	    if (!FcPatternObjectAddString (pat, FC_FAMILY_OBJECT, save))
     471  		goto bail2;
     472  	}
     473  	if (delim != ',')
     474  	    break;
     475      }
     476      if (delim == '-')
     477      {
     478  	for (;;)
     479  	{
     480  	    name = FcNameFindNext (name, "-,:", save, &delim);
     481  	    d = strtod ((char *) save, (char **) &e);
     482  	    if (e != save)
     483  	    {
     484  		if (!FcPatternObjectAddDouble (pat, FC_SIZE_OBJECT, d))
     485  		    goto bail2;
     486  	    }
     487  	    if (delim != ',')
     488  		break;
     489  	}
     490      }
     491      while (delim == ':')
     492      {
     493  	name = FcNameFindNext (name, "=_:", save, &delim);
     494  	if (save[0])
     495  	{
     496  	    if (delim == '=' || delim == '_')
     497  	    {
     498  		t = FcNameGetObjectType ((char *) save);
     499  		for (;;)
     500  		{
     501  		    name = FcNameFindNext (name, ":,", save, &delim);
     502  		    if (t)
     503  		    {
     504  			v = FcNameConvert (t->type, t->object, save);
     505  			if (!FcPatternAdd (pat, t->object, v, FcTrue))
     506  			{
     507  			    FcValueDestroy (v);
     508  			    goto bail2;
     509  			}
     510  			FcValueDestroy (v);
     511  		    }
     512  		    if (delim != ',')
     513  			break;
     514  		}
     515  	    }
     516  	    else
     517  	    {
     518  		if ((c = FcNameGetConstant (save)))
     519  		{
     520  		    t = FcNameGetObjectType ((char *) c->object);
     521  		    if (t == NULL)
     522  			goto bail2;
     523  		    switch ((int) t->type) {
     524  		    case FcTypeInteger:
     525  		    case FcTypeDouble:
     526  			if (!FcPatternAddInteger (pat, c->object, c->value))
     527  			    goto bail2;
     528  			break;
     529  		    case FcTypeBool:
     530  			if (!FcPatternAddBool (pat, c->object, c->value))
     531  			    goto bail2;
     532  			break;
     533  		    case FcTypeRange:
     534  			if (!FcPatternAddInteger (pat, c->object, c->value))
     535  			    goto bail2;
     536  			break;
     537  		    default:
     538  			break;
     539  		    }
     540  		}
     541  	    }
     542  	}
     543      }
     544  
     545      free (save);
     546      return pat;
     547  
     548  bail2:
     549      FcPatternDestroy (pat);
     550  bail1:
     551      free (save);
     552  bail0:
     553      return 0;
     554  }
     555  static FcBool
     556  FcNameUnparseString (FcStrBuf	    *buf,
     557  		     const FcChar8  *string,
     558  		     const FcChar8  *escape)
     559  {
     560      FcChar8 c;
     561      while ((c = *string++))
     562      {
     563  	if (escape && strchr ((char *) escape, (char) c))
     564  	{
     565  	    if (!FcStrBufChar (buf, escape[0]))
     566  		return FcFalse;
     567  	}
     568  	if (!FcStrBufChar (buf, c))
     569  	    return FcFalse;
     570      }
     571      return FcTrue;
     572  }
     573  
     574  FcBool
     575  FcNameUnparseValue (FcStrBuf	*buf,
     576  		    FcValue	*v0,
     577  		    FcChar8	*escape)
     578  {
     579      FcChar8	temp[1024];
     580      FcValue v = FcValueCanonicalize(v0);
     581  
     582      switch (v.type) {
     583      case FcTypeUnknown:
     584      case FcTypeVoid:
     585  	return FcTrue;
     586      case FcTypeInteger:
     587  	sprintf ((char *) temp, "%d", v.u.i);
     588  	return FcNameUnparseString (buf, temp, 0);
     589      case FcTypeDouble:
     590  	sprintf ((char *) temp, "%g", v.u.d);
     591  	return FcNameUnparseString (buf, temp, 0);
     592      case FcTypeString:
     593  	return FcNameUnparseString (buf, v.u.s, escape);
     594      case FcTypeBool:
     595  	return FcNameUnparseString (buf,
     596  				    v.u.b == FcTrue  ? (FcChar8 *) "True" :
     597  				    v.u.b == FcFalse ? (FcChar8 *) "False" :
     598  				                       (FcChar8 *) "DontCare", 0);
     599      case FcTypeMatrix:
     600  	sprintf ((char *) temp, "%g %g %g %g",
     601  		 v.u.m->xx, v.u.m->xy, v.u.m->yx, v.u.m->yy);
     602  	return FcNameUnparseString (buf, temp, 0);
     603      case FcTypeCharSet:
     604  	return FcNameUnparseCharSet (buf, v.u.c);
     605      case FcTypeLangSet:
     606  	return FcNameUnparseLangSet (buf, v.u.l);
     607      case FcTypeFTFace:
     608  	return FcTrue;
     609      case FcTypeRange:
     610  	sprintf ((char *) temp, "[%g %g]", v.u.r->begin, v.u.r->end);
     611  	return FcNameUnparseString (buf, temp, 0);
     612      }
     613      return FcFalse;
     614  }
     615  
     616  FcBool
     617  FcNameUnparseValueList (FcStrBuf	*buf,
     618  			FcValueListPtr	v,
     619  			FcChar8		*escape)
     620  {
     621      while (v)
     622      {
     623  	if (!FcNameUnparseValue (buf, &v->value, escape))
     624  	    return FcFalse;
     625  	if ((v = FcValueListNext(v)) != NULL)
     626  	    if (!FcNameUnparseString (buf, (FcChar8 *) ",", 0))
     627  		return FcFalse;
     628      }
     629      return FcTrue;
     630  }
     631  
     632  #define FC_ESCAPE_FIXED    "\\-:,"
     633  #define FC_ESCAPE_VARIABLE "\\=_:,"
     634  
     635  FcChar8 *
     636  FcNameUnparse (FcPattern *pat)
     637  {
     638      return FcNameUnparseEscaped (pat, FcTrue);
     639  }
     640  
     641  FcChar8 *
     642  FcNameUnparseEscaped (FcPattern *pat, FcBool escape)
     643  {
     644      FcStrBuf		    buf, buf2;
     645      FcChar8		    buf_static[8192], buf2_static[256];
     646      int			    i;
     647      FcPatternElt	    *e;
     648  
     649      FcStrBufInit (&buf, buf_static, sizeof (buf_static));
     650      FcStrBufInit (&buf2, buf2_static, sizeof (buf2_static));
     651      e = FcPatternObjectFindElt (pat, FC_FAMILY_OBJECT);
     652      if (e)
     653      {
     654          if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0))
     655  	    goto bail0;
     656      }
     657      e = FcPatternObjectFindElt (pat, FC_SIZE_OBJECT);
     658      if (e)
     659      {
     660  	FcChar8 *p;
     661  
     662  	if (!FcNameUnparseString (&buf2, (FcChar8 *) "-", 0))
     663  	    goto bail0;
     664  	if (!FcNameUnparseValueList (&buf2, FcPatternEltValues(e), escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0))
     665  	    goto bail0;
     666  	p = FcStrBufDoneStatic (&buf2);
     667  	FcStrBufDestroy (&buf2);
     668  	if (strlen ((const char *)p) > 1)
     669  	    if (!FcStrBufString (&buf, p))
     670  		goto bail0;
     671      }
     672      for (i = 0; i < NUM_OBJECT_TYPES; i++)
     673      {
     674  	FcObject id = i + 1;
     675  	const FcObjectType	    *o;
     676  	o = &FcObjects[i];
     677  	if (!strcmp (o->object, FC_FAMILY) ||
     678  	    !strcmp (o->object, FC_SIZE))
     679  	    continue;
     680  
     681  	e = FcPatternObjectFindElt (pat, id);
     682  	if (e)
     683  	{
     684  	    if (!FcNameUnparseString (&buf, (FcChar8 *) ":", 0))
     685  		goto bail0;
     686  	    if (!FcNameUnparseString (&buf, (FcChar8 *) o->object, escape ? (FcChar8 *) FC_ESCAPE_VARIABLE : 0))
     687  		goto bail0;
     688  	    if (!FcNameUnparseString (&buf, (FcChar8 *) "=", 0))
     689  		goto bail0;
     690  	    if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ?
     691  					 (FcChar8 *) FC_ESCAPE_VARIABLE : 0))
     692  		goto bail0;
     693  	}
     694      }
     695      return FcStrBufDone (&buf);
     696  bail0:
     697      FcStrBufDestroy (&buf);
     698      return 0;
     699  }
     700  #define __fcname__
     701  #include "fcaliastail.h"
     702  #undef __fcname__