Home | History | Annotate | Line # | Download | only in src
      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__
    703