fcname.c 15.1 KB
Newer Older
Keith Packard's avatar
Keith Packard committed
1
/*
2
 * $RCSId: xc/lib/fontconfig/src/fcname.c,v 1.15 2002/09/26 00:17:28 keithp Exp $
Keith Packard's avatar
Keith Packard committed
3
 *
4
 * Copyright © 2000 Keith Packard
Keith Packard's avatar
Keith Packard committed
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of Keith Packard not be used in
 * advertising or publicity pertaining to distribution of the software without
 * specific, written prior permission.  Keith Packard makes no
 * representations about the suitability of this software for any purpose.  It
 * is provided "as is" without express or implied warranty.
 *
 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */

#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "fcint.h"

static const FcObjectType _FcBaseObjectTypes[] = {
    { FC_FAMILY,	FcTypeString, },
33
    { FC_FAMILYLANG,	FcTypeString, },
Keith Packard's avatar
Keith Packard committed
34
    { FC_STYLE,		FcTypeString, },
35 36 37
    { FC_STYLELANG,	FcTypeString, },
    { FC_FULLNAME,	FcTypeString, },
    { FC_FULLNAMELANG,	FcTypeString, },
Keith Packard's avatar
Keith Packard committed
38 39
    { FC_SLANT,		FcTypeInteger, },
    { FC_WEIGHT,	FcTypeInteger, },
40
    { FC_WIDTH,		FcTypeInteger, },
Keith Packard's avatar
Keith Packard committed
41
    { FC_SIZE,		FcTypeDouble, },
42
    { FC_ASPECT,	FcTypeDouble, },
Keith Packard's avatar
Keith Packard committed
43 44 45 46 47
    { FC_PIXEL_SIZE,	FcTypeDouble, },
    { FC_SPACING,	FcTypeInteger, },
    { FC_FOUNDRY,	FcTypeString, },
/*    { FC_CORE,		FcTypeBool, }, */
    { FC_ANTIALIAS,	FcTypeBool, },
48
    { FC_HINT_STYLE,    FcTypeInteger, },
49 50 51 52
    { FC_HINTING,	FcTypeBool, },
    { FC_VERTICAL_LAYOUT,   FcTypeBool, },
    { FC_AUTOHINT,	FcTypeBool, },
    { FC_GLOBAL_ADVANCE,    FcTypeBool, },
Keith Packard's avatar
Keith Packard committed
53 54 55 56 57 58
/*    { FC_XLFD,		FcTypeString, }, */
    { FC_FILE,		FcTypeString, },
    { FC_INDEX,		FcTypeInteger, },
    { FC_RASTERIZER,	FcTypeString, },
    { FC_OUTLINE,	FcTypeBool, },
    { FC_SCALABLE,	FcTypeBool, },
59
    { FC_DPI,		FcTypeDouble },
Keith Packard's avatar
Keith Packard committed
60 61 62 63 64 65 66 67
    { FC_RGBA,		FcTypeInteger, },
    { FC_SCALE,		FcTypeDouble, },
/*    { FC_RENDER,	FcTypeBool, },*/
    { FC_MINSPACE,	FcTypeBool, },
    { FC_CHAR_WIDTH,	FcTypeInteger },
    { FC_CHAR_HEIGHT,	FcTypeInteger },
    { FC_MATRIX,	FcTypeMatrix },
    { FC_CHARSET,	FcTypeCharSet },
68
    { FC_LANG,		FcTypeLangSet },
Keith Packard's avatar
Keith Packard committed
69
    { FC_FONTVERSION,	FcTypeInteger },
Keith Packard's avatar
Keith Packard committed
70
    { FC_CAPABILITY,	FcTypeString },
71
    { FC_FONTFORMAT,	FcTypeString },
Keith Packard's avatar
Keith Packard committed
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
};

#define NUM_OBJECT_TYPES    (sizeof _FcBaseObjectTypes / sizeof _FcBaseObjectTypes[0])

typedef struct _FcObjectTypeList    FcObjectTypeList;

struct _FcObjectTypeList {
    const FcObjectTypeList  *next;
    const FcObjectType	    *types;
    int			    ntypes;
};

static const FcObjectTypeList _FcBaseObjectTypesList = {
    0,
    _FcBaseObjectTypes,
    NUM_OBJECT_TYPES
};

static const FcObjectTypeList	*_FcObjectTypes = &_FcBaseObjectTypesList;

FcBool
FcNameRegisterObjectTypes (const FcObjectType *types, int ntypes)
{
    FcObjectTypeList	*l;

    l = (FcObjectTypeList *) malloc (sizeof (FcObjectTypeList));
    if (!l)
	return FcFalse;
100
    FcMemAlloc (FC_MEM_OBJECTTYPE, sizeof (FcObjectTypeList));
Keith Packard's avatar
Keith Packard committed
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
    l->types = types;
    l->ntypes = ntypes;
    l->next = _FcObjectTypes;
    _FcObjectTypes = l;
    return FcTrue;
}

FcBool
FcNameUnregisterObjectTypes (const FcObjectType *types, int ntypes)
{
    const FcObjectTypeList	*l, **prev;

    for (prev = &_FcObjectTypes; 
	 (l = *prev); 
	 prev = (const FcObjectTypeList **) &(l->next))
    {
	if (l->types == types && l->ntypes == ntypes)
	{
	    *prev = l->next;
120
	    FcMemFree (FC_MEM_OBJECTTYPE, sizeof (FcObjectTypeList));
Keith Packard's avatar
Keith Packard committed
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
	    free ((void *) l);
	    return FcTrue;
	}
    }
    return FcFalse;
}

const FcObjectType *
FcNameGetObjectType (const char *object)
{
    int			    i;
    const FcObjectTypeList  *l;
    const FcObjectType	    *t;
    
    for (l = _FcObjectTypes; l; l = l->next)
    {
	for (i = 0; i < l->ntypes; i++)
	{
	    t = &l->types[i];
140
	    if (!strcmp (object, t->object))
Keith Packard's avatar
Keith Packard committed
141 142 143 144 145 146 147
		return t;
	}
    }
    return 0;
}

static const FcConstant _FcBaseConstants[] = {
148 149 150
    { (FcChar8 *) "thin",	    "weight",   FC_WEIGHT_THIN, },
    { (FcChar8 *) "extralight",	    "weight",   FC_WEIGHT_EXTRALIGHT, },
    { (FcChar8 *) "ultralight",	    "weight",   FC_WEIGHT_EXTRALIGHT, },
151
    { (FcChar8 *) "light",	    "weight",   FC_WEIGHT_LIGHT, },
152
    { (FcChar8 *) "book",	    "weight",	FC_WEIGHT_BOOK, },
153
    { (FcChar8 *) "regular",	    "weight",   FC_WEIGHT_REGULAR, },
154 155
    { (FcChar8 *) "medium",	    "weight",   FC_WEIGHT_MEDIUM, },
    { (FcChar8 *) "demibold",	    "weight",   FC_WEIGHT_DEMIBOLD, },
156
    { (FcChar8 *) "semibold",	    "weight",   FC_WEIGHT_DEMIBOLD, },
157
    { (FcChar8 *) "bold",	    "weight",   FC_WEIGHT_BOLD, },
158 159
    { (FcChar8 *) "extrabold",	    "weight",   FC_WEIGHT_EXTRABOLD, },
    { (FcChar8 *) "ultrabold",	    "weight",   FC_WEIGHT_EXTRABOLD, },
160 161 162 163 164 165
    { (FcChar8 *) "black",	    "weight",   FC_WEIGHT_BLACK, },

    { (FcChar8 *) "roman",	    "slant",    FC_SLANT_ROMAN, },
    { (FcChar8 *) "italic",	    "slant",    FC_SLANT_ITALIC, },
    { (FcChar8 *) "oblique",	    "slant",    FC_SLANT_OBLIQUE, },

166 167 168 169 170 171 172 173 174 175
    { (FcChar8 *) "ultracondensed", "width",	FC_WIDTH_ULTRACONDENSED },
    { (FcChar8 *) "extracondensed", "width",	FC_WIDTH_EXTRACONDENSED },
    { (FcChar8 *) "condensed",	    "width",	FC_WIDTH_CONDENSED },
    { (FcChar8 *) "semicondensed", "width",	FC_WIDTH_SEMICONDENSED },
    { (FcChar8 *) "normal",	    "width",	FC_WIDTH_NORMAL },
    { (FcChar8 *) "semiexpanded",   "width",	FC_WIDTH_SEMIEXPANDED },
    { (FcChar8 *) "expanded",	    "width",	FC_WIDTH_EXPANDED },
    { (FcChar8 *) "extraexpanded",  "width",	FC_WIDTH_EXTRAEXPANDED },
    { (FcChar8 *) "ultraexpanded",  "width",	FC_WIDTH_ULTRAEXPANDED },
    
176
    { (FcChar8 *) "proportional",   "spacing",  FC_PROPORTIONAL, },
177
    { (FcChar8 *) "dual",	    "spacing",  FC_DUAL, },
178 179 180
    { (FcChar8 *) "mono",	    "spacing",  FC_MONO, },
    { (FcChar8 *) "charcell",	    "spacing",  FC_CHARCELL, },

Keith Packard's avatar
Keith Packard committed
181
    { (FcChar8 *) "unknown",	    "rgba",	    FC_RGBA_UNKNOWN },
182 183 184 185
    { (FcChar8 *) "rgb",	    "rgba",	    FC_RGBA_RGB, },
    { (FcChar8 *) "bgr",	    "rgba",	    FC_RGBA_BGR, },
    { (FcChar8 *) "vrgb",	    "rgba",	    FC_RGBA_VRGB },
    { (FcChar8 *) "vbgr",	    "rgba",	    FC_RGBA_VBGR },
Keith Packard's avatar
Keith Packard committed
186
    { (FcChar8 *) "none",	    "rgba",	    FC_RGBA_NONE },
187 188 189 190 191

    { (FcChar8 *) "hintnone",	    "hintstyle",   FC_HINT_NONE },
    { (FcChar8 *) "hintslight",	    "hintstyle",   FC_HINT_SLIGHT },
    { (FcChar8 *) "hintmedium",	    "hintstyle",   FC_HINT_MEDIUM },
    { (FcChar8 *) "hintfull",	    "hintstyle",   FC_HINT_FULL },
Keith Packard's avatar
Keith Packard committed
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
};

#define NUM_FC_CONSTANTS   (sizeof _FcBaseConstants/sizeof _FcBaseConstants[0])

typedef struct _FcConstantList FcConstantList;

struct _FcConstantList {
    const FcConstantList    *next;
    const FcConstant	    *consts;
    int			    nconsts;
};

static const FcConstantList _FcBaseConstantList = {
    0,
    _FcBaseConstants,
    NUM_FC_CONSTANTS
};

static const FcConstantList	*_FcConstants = &_FcBaseConstantList;

FcBool
FcNameRegisterConstants (const FcConstant *consts, int nconsts)
{
    FcConstantList	*l;

    l = (FcConstantList *) malloc (sizeof (FcConstantList));
    if (!l)
	return FcFalse;
220
    FcMemAlloc (FC_MEM_CONSTANT, sizeof (FcConstantList));
Keith Packard's avatar
Keith Packard committed
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
    l->consts = consts;
    l->nconsts = nconsts;
    l->next = _FcConstants;
    _FcConstants = l;
    return FcTrue;
}

FcBool
FcNameUnregisterConstants (const FcConstant *consts, int nconsts)
{
    const FcConstantList	*l, **prev;

    for (prev = &_FcConstants; 
	 (l = *prev); 
	 prev = (const FcConstantList **) &(l->next))
    {
	if (l->consts == consts && l->nconsts == nconsts)
	{
	    *prev = l->next;
240
	    FcMemFree (FC_MEM_CONSTANT, sizeof (FcConstantList));
Keith Packard's avatar
Keith Packard committed
241 242 243 244 245 246 247 248
	    free ((void *) l);
	    return FcTrue;
	}
    }
    return FcFalse;
}

const FcConstant *
249
FcNameGetConstant (FcChar8 *string)
Keith Packard's avatar
Keith Packard committed
250 251 252
{
    const FcConstantList    *l;
    int			    i;
253

Keith Packard's avatar
Keith Packard committed
254 255 256 257 258 259 260 261 262 263
    for (l = _FcConstants; l; l = l->next)
    {
	for (i = 0; i < l->nconsts; i++)
	    if (!FcStrCmpIgnoreCase (string, l->consts[i].name))
		return &l->consts[i];
    }
    return 0;
}

FcBool
264
FcNameConstant (FcChar8 *string, int *result)
Keith Packard's avatar
Keith Packard committed
265 266 267 268 269 270 271 272 273 274 275 276
{
    const FcConstant	*c;

    if ((c = FcNameGetConstant(string)))
    {
	*result = c->value;
	return FcTrue;
    }
    return FcFalse;
}

FcBool
277
FcNameBool (const FcChar8 *v, FcBool *result)
Keith Packard's avatar
Keith Packard committed
278 279 280 281
{
    char    c0, c1;

    c0 = *v;
282
    c0 = FcToLower (c0);
Keith Packard's avatar
Keith Packard committed
283 284 285 286 287 288 289 290 291 292 293 294 295
    if (c0 == 't' || c0 == 'y' || c0 == '1')
    {
	*result = FcTrue;
	return FcTrue;
    }
    if (c0 == 'f' || c0 == 'n' || c0 == '0')
    {
	*result = FcFalse;
	return FcTrue;
    }
    if (c0 == 'o')
    {
	c1 = v[1];
296
	c1 = FcToLower (c1);
Keith Packard's avatar
Keith Packard committed
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
	if (c1 == 'n')
	{
	    *result = FcTrue;
	    return FcTrue;
	}
	if (c1 == 'f')
	{
	    *result = FcFalse;
	    return FcTrue;
	}
    }
    return FcFalse;
}

static FcValue
312
FcNameConvert (FcType type, FcChar8 *string, FcMatrix *m)
Keith Packard's avatar
Keith Packard committed
313 314 315 316 317 318 319
{
    FcValue	v;

    v.type = type;
    switch (v.type) {
    case FcTypeInteger:
	if (!FcNameConstant (string, &v.u.i))
320
	    v.u.i = atoi ((char *) string);
Keith Packard's avatar
Keith Packard committed
321 322 323 324 325 326 327 328 329
	break;
    case FcTypeString:
	v.u.s = string;
	break;
    case FcTypeBool:
	if (!FcNameBool (string, &v.u.b))
	    v.u.b = FcFalse;
	break;
    case FcTypeDouble:
330
	v.u.d = strtod ((char *) string, 0);
Keith Packard's avatar
Keith Packard committed
331 332 333
	break;
    case FcTypeMatrix:
	v.u.m = m;
334
	sscanf ((char *) string, "%lg %lg %lg %lg", &m->xx, &m->xy, &m->yx, &m->yy);
Keith Packard's avatar
Keith Packard committed
335 336 337 338
	break;
    case FcTypeCharSet:
	v.u.c = FcNameParseCharSet (string);
	break;
339 340 341
    case FcTypeLangSet:
	v.u.l = FcNameParseLangSet (string);
	break;
Keith Packard's avatar
Keith Packard committed
342 343 344 345 346 347
    default:
	break;
    }
    return v;
}

348 349
static const FcChar8 *
FcNameFindNext (const FcChar8 *cur, const char *delim, FcChar8 *save, FcChar8 *last)
Keith Packard's avatar
Keith Packard committed
350
{
351
    FcChar8    c;
Keith Packard's avatar
Keith Packard committed
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
    
    while ((c = *cur))
    {
	if (c == '\\')
	{
	    ++cur;
	    if (!(c = *cur))
		break;
	}
	else if (strchr (delim, c))
	    break;
	++cur;
	*save++ = c;
    }
    *save = 0;
    *last = *cur;
    if (*cur)
	cur++;
    return cur;
}

FcPattern *
374
FcNameParse (const FcChar8 *name)
Keith Packard's avatar
Keith Packard committed
375
{
376
    FcChar8		*save;
Keith Packard's avatar
Keith Packard committed
377 378
    FcPattern		*pat;
    double		d;
379 380
    FcChar8		*e;
    FcChar8		delim;
Keith Packard's avatar
Keith Packard committed
381 382 383 384 385
    FcValue		v;
    FcMatrix		m;
    const FcObjectType	*t;
    const FcConstant	*c;

386
    /* freed below */
387
    save = malloc (strlen ((char *) name) + 1);
Keith Packard's avatar
Keith Packard committed
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
    if (!save)
	goto bail0;
    pat = FcPatternCreate ();
    if (!pat)
	goto bail1;

    for (;;)
    {
	name = FcNameFindNext (name, "-,:", save, &delim);
	if (save[0])
	{
	    if (!FcPatternAddString (pat, FC_FAMILY, save))
		goto bail2;
	}
	if (delim != ',')
	    break;
    }
    if (delim == '-')
    {
	for (;;)
	{
	    name = FcNameFindNext (name, "-,:", save, &delim);
410
	    d = strtod ((char *) save, (char **) &e);
Keith Packard's avatar
Keith Packard committed
411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
	    if (e != save)
	    {
		if (!FcPatternAddDouble (pat, FC_SIZE, d))
		    goto bail2;
	    }
	    if (delim != ',')
		break;
	}
    }
    while (delim == ':')
    {
	name = FcNameFindNext (name, "=_:", save, &delim);
	if (save[0])
	{
	    if (delim == '=' || delim == '_')
	    {
427
		t = FcNameGetObjectType ((char *) save);
Keith Packard's avatar
Keith Packard committed
428 429 430
		for (;;)
		{
		    name = FcNameFindNext (name, ":,", save, &delim);
431
		    if (t)
Keith Packard's avatar
Keith Packard committed
432 433 434 435
		    {
			v = FcNameConvert (t->type, save, &m);
			if (!FcPatternAdd (pat, t->object, v, FcTrue))
			{
436 437
			    switch (v.type) {
			    case FcTypeCharSet:
Keith Packard's avatar
Keith Packard committed
438
				FcCharSetDestroy ((FcCharSet *) v.u.c);
439 440 441 442 443 444 445
				break;
			    case FcTypeLangSet:
				FcLangSetDestroy ((FcLangSet *) v.u.l);
				break;
			    default:
				break;
			    }
Keith Packard's avatar
Keith Packard committed
446 447
			    goto bail2;
			}
448 449
			switch (v.type) {
			case FcTypeCharSet:
Keith Packard's avatar
Keith Packard committed
450
			    FcCharSetDestroy ((FcCharSet *) v.u.c);
451 452 453 454 455 456 457
			    break;
			case FcTypeLangSet:
			    FcLangSetDestroy ((FcLangSet *) v.u.l);
			    break;
			default:
			    break;
			}
Keith Packard's avatar
Keith Packard committed
458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484
		    }
		    if (delim != ',')
			break;
		}
	    }
	    else
	    {
		if ((c = FcNameGetConstant (save)))
		{
		    if (!FcPatternAddInteger (pat, c->object, c->value))
			goto bail2;
		}
	    }
	}
    }

    free (save);
    return pat;

bail2:
    FcPatternDestroy (pat);
bail1:
    free (save);
bail0:
    return 0;
}
static FcBool
485
FcNameUnparseString (FcStrBuf	    *buf, 
Keith Packard's avatar
Keith Packard committed
486 487 488 489 490 491 492 493
		     const FcChar8  *string,
		     const FcChar8  *escape)
{
    FcChar8 c;
    while ((c = *string++))
    {
	if (escape && strchr ((char *) escape, (char) c))
	{
494
	    if (!FcStrBufChar (buf, escape[0]))
Keith Packard's avatar
Keith Packard committed
495 496
		return FcFalse;
	}
497
	if (!FcStrBufChar (buf, c))
Keith Packard's avatar
Keith Packard committed
498 499 500 501 502 503
	    return FcFalse;
    }
    return FcTrue;
}

static FcBool
504
FcNameUnparseValue (FcStrBuf	*buf,
Keith Packard's avatar
Keith Packard committed
505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521
		    FcValue	v,
		    FcChar8	*escape)
{
    FcChar8	temp[1024];
    
    switch (v.type) {
    case FcTypeVoid:
	return FcTrue;
    case FcTypeInteger:
	sprintf ((char *) temp, "%d", v.u.i);
	return FcNameUnparseString (buf, temp, 0);
    case FcTypeDouble:
	sprintf ((char *) temp, "%g", v.u.d);
	return FcNameUnparseString (buf, temp, 0);
    case FcTypeString:
	return FcNameUnparseString (buf, v.u.s, escape);
    case FcTypeBool:
522
	return FcNameUnparseString (buf, v.u.b ? (FcChar8 *) "True" : (FcChar8 *) "False", 0);
Keith Packard's avatar
Keith Packard committed
523 524 525 526 527 528
    case FcTypeMatrix:
	sprintf ((char *) temp, "%g %g %g %g", 
		 v.u.m->xx, v.u.m->xy, v.u.m->yx, v.u.m->yy);
	return FcNameUnparseString (buf, temp, 0);
    case FcTypeCharSet:
	return FcNameUnparseCharSet (buf, v.u.c);
529 530
    case FcTypeLangSet:
	return FcNameUnparseLangSet (buf, v.u.l);
531 532
    case FcTypeFTFace:
	return FcTrue;
Keith Packard's avatar
Keith Packard committed
533 534 535 536 537
    }
    return FcFalse;
}

static FcBool
538
FcNameUnparseValueList (FcStrBuf	*buf,
Keith Packard's avatar
Keith Packard committed
539
			FcValueList	*v,
540
			FcChar8		*escape)
Keith Packard's avatar
Keith Packard committed
541 542 543 544 545 546
{
    while (v)
    {
	if (!FcNameUnparseValue (buf, v->value, escape))
	    return FcFalse;
	if ((v = v->next))
547
	    if (!FcNameUnparseString (buf, (FcChar8 *) ",", 0))
Keith Packard's avatar
Keith Packard committed
548 549 550 551 552 553 554 555 556 557 558
		return FcFalse;
    }
    return FcTrue;
}

#define FC_ESCAPE_FIXED    "\\-:,"
#define FC_ESCAPE_VARIABLE "\\=_:,"

FcChar8 *
FcNameUnparse (FcPattern *pat)
{
559
    FcStrBuf		    buf;
Keith Packard's avatar
Keith Packard committed
560 561 562 563 564 565
    FcChar8		    buf_static[8192];
    int			    i;
    FcPatternElt	    *e;
    const FcObjectTypeList  *l;
    const FcObjectType	    *o;

566
    FcStrBufInit (&buf, buf_static, sizeof (buf_static));
567
    e = FcPatternFindElt (pat, FC_FAMILY);
Keith Packard's avatar
Keith Packard committed
568 569
    if (e)
    {
570
	if (!FcNameUnparseValueList (&buf, e->values, (FcChar8 *) FC_ESCAPE_FIXED))
Keith Packard's avatar
Keith Packard committed
571 572
	    goto bail0;
    }
573
    e = FcPatternFindElt (pat, FC_SIZE);
Keith Packard's avatar
Keith Packard committed
574 575
    if (e)
    {
576
	if (!FcNameUnparseString (&buf, (FcChar8 *) "-", 0))
Keith Packard's avatar
Keith Packard committed
577
	    goto bail0;
578
	if (!FcNameUnparseValueList (&buf, e->values, (FcChar8 *) FC_ESCAPE_FIXED))
Keith Packard's avatar
Keith Packard committed
579 580 581 582 583 584 585 586 587 588 589 590
	    goto bail0;
    }
    for (l = _FcObjectTypes; l; l = l->next)
    {
	for (i = 0; i < l->ntypes; i++)
	{
	    o = &l->types[i];
	    if (!strcmp (o->object, FC_FAMILY) || 
		!strcmp (o->object, FC_SIZE) ||
		!strcmp (o->object, FC_FILE))
		continue;
	    
591
	    e = FcPatternFindElt (pat, o->object);
Keith Packard's avatar
Keith Packard committed
592 593
	    if (e)
	    {
594
		if (!FcNameUnparseString (&buf, (FcChar8 *) ":", 0))
Keith Packard's avatar
Keith Packard committed
595
		    goto bail0;
596
		if (!FcNameUnparseString (&buf, (FcChar8 *) o->object, (FcChar8 *) FC_ESCAPE_VARIABLE))
Keith Packard's avatar
Keith Packard committed
597
		    goto bail0;
598
		if (!FcNameUnparseString (&buf, (FcChar8 *) "=", 0))
Keith Packard's avatar
Keith Packard committed
599 600
		    goto bail0;
		if (!FcNameUnparseValueList (&buf, e->values, 
601
					     (FcChar8 *) FC_ESCAPE_VARIABLE))
Keith Packard's avatar
Keith Packard committed
602 603 604 605
		    goto bail0;
	    }
	}
    }
606
    return FcStrBufDone (&buf);
Keith Packard's avatar
Keith Packard committed
607
bail0:
608
    FcStrBufDestroy (&buf);
Keith Packard's avatar
Keith Packard committed
609 610
    return 0;
}