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