Edit

IABSD.fr/xenocara/lib/fontconfig/src/fcname.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2010-03-25 21:45:57
    Hash : e248f656
    Message : Update to fontconfig 2.8.0. Tested on a full ports build by naddy@.

  • lib/fontconfig/src/fcname.c
  • /*
     * fontconfig/src/fcname.c
     *
     * Copyright © 2000 Keith Packard
     *
     * 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.
     *
     * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
     * EVENT SHALL THE AUTHOR(S) 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 "fcint.h"
    #include <ctype.h>
    #include <stdlib.h>
    #include <string.h>
    #include <stdio.h>
    
    /* 
     * Please do not change this list, it is used to initialize the object
     * list in this order to match the FC_foo_OBJECT constants. Those 
     * constants are written into cache files.
     */
    
    static const FcObjectType _FcBaseObjectTypes[] = {
        { FC_FAMILY,	FcTypeString, },    /* 1 */
        { FC_FAMILYLANG,	FcTypeString, },
        { FC_STYLE,		FcTypeString, },
        { FC_STYLELANG,	FcTypeString, },
        { FC_FULLNAME,	FcTypeString, },
        { FC_FULLNAMELANG,	FcTypeString, },
        { FC_SLANT,		FcTypeInteger, },
        { FC_WEIGHT,	FcTypeInteger, },
        { FC_WIDTH,		FcTypeInteger, },
        { FC_SIZE,		FcTypeDouble, },
        { FC_ASPECT,	FcTypeDouble, },
        { FC_PIXEL_SIZE,	FcTypeDouble, },
        { FC_SPACING,	FcTypeInteger, },
        { FC_FOUNDRY,	FcTypeString, },
        { FC_ANTIALIAS,	FcTypeBool, },
        { FC_HINT_STYLE,    FcTypeInteger, },
        { FC_HINTING,	FcTypeBool, },
        { FC_VERTICAL_LAYOUT,   FcTypeBool, },
        { FC_AUTOHINT,	FcTypeBool, },
        { FC_GLOBAL_ADVANCE,    FcTypeBool, },
        { FC_FILE,		FcTypeString, },
        { FC_INDEX,		FcTypeInteger, },
        { FC_RASTERIZER,	FcTypeString, },
        { FC_OUTLINE,	FcTypeBool, },
        { FC_SCALABLE,	FcTypeBool, },
        { FC_DPI,		FcTypeDouble },
        { FC_RGBA,		FcTypeInteger, },
        { FC_SCALE,		FcTypeDouble, },
        { FC_MINSPACE,	FcTypeBool, },
        { FC_CHAR_WIDTH,	FcTypeInteger },
        { FC_CHAR_HEIGHT,	FcTypeInteger },
        { FC_MATRIX,	FcTypeMatrix },
        { FC_CHARSET,	FcTypeCharSet },
        { FC_LANG,		FcTypeLangSet },
        { FC_FONTVERSION,	FcTypeInteger },
        { FC_CAPABILITY,	FcTypeString },
        { FC_FONTFORMAT,	FcTypeString },
        { FC_EMBOLDEN,	FcTypeBool },
        { FC_EMBEDDED_BITMAP,   FcTypeBool },
        { FC_DECORATIVE,	FcTypeBool },
        { FC_LCD_FILTER,	FcTypeInteger }, /* 41 */
    };
    
    #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;
    
    #define OBJECT_HASH_SIZE    31
    
    typedef struct _FcObjectBucket {
        struct _FcObjectBucket  *next;
        FcChar32		    hash;
        FcObject		    id;
    } FcObjectBucket;
    
    static FcObjectBucket	*FcObjectBuckets[OBJECT_HASH_SIZE];
    
    static FcObjectType	*FcObjects = (FcObjectType *) _FcBaseObjectTypes;
    static int		FcObjectsNumber = NUM_OBJECT_TYPES;
    static int		FcObjectsSize = 0;
    static FcBool		FcObjectsInited;
    
    static FcObjectType *
    FcObjectInsert (const char *name, FcType type)
    {
        FcObjectType    *o;
        if (FcObjectsNumber >= FcObjectsSize)
        {
    	int		newsize = FcObjectsNumber * 2;
    	FcObjectType	*newobjects;
    	
    	if (FcObjectsSize)
    	    newobjects = realloc (FcObjects, newsize * sizeof (FcObjectType));
    	else
    	{
    	    newobjects = malloc (newsize * sizeof (FcObjectType));
    	    if (newobjects)
    		memcpy (newobjects, FcObjects,
    			FcObjectsNumber * sizeof (FcObjectType));
    	}
    	if (!newobjects)
    	    return NULL;
    	FcObjects = newobjects;
    	FcObjectsSize = newsize;
        }
        o = &FcObjects[FcObjectsNumber];
        o->object = name;
        o->type = type;
        ++FcObjectsNumber;
        return o;
    }
    
    static FcObject
    FcObjectId (FcObjectType *o)
    {
        return o - FcObjects + 1;
    }
    
    static FcObjectType *
    FcObjectFindByName (const char *object, FcBool insert)
    {
        FcChar32	    hash = FcStringHash ((const FcChar8 *) object);
        FcObjectBucket  **p;
        FcObjectBucket  *b;
        FcObjectType    *o;
    
        if (!FcObjectsInited)
    	FcObjectInit ();
        for (p = &FcObjectBuckets[hash%OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
        {
    	o = FcObjects + b->id - 1;
            if (b->hash == hash && !strcmp (object, (o->object)))
                return o;
        }
        if (!insert)
    	return NULL;
        /*
         * Hook it into the hash chain
         */
        b = malloc (sizeof(FcObjectBucket));
        if (!b) 
    	return NULL;
        object = (const char *) FcStrCopy ((FcChar8 *) object);
        if (!object) {
    	free (b);
    	return NULL;
        }
        o = FcObjectInsert (object, -1);
        b->next = NULL;
        b->hash = hash;
        b->id = FcObjectId (o);
        *p = b;
        return o;
    }
    
    static FcObjectType *
    FcObjectFindById (FcObject object)
    {
        if (1 <= object && object <= FcObjectsNumber)
    	return FcObjects + object - 1;
        return NULL;
    }
    
    static FcBool
    FcObjectHashInsert (const FcObjectType *object, FcBool copy)
    {
        FcChar32	    hash = FcStringHash ((const FcChar8 *) object->object);
        FcObjectBucket  **p;
        FcObjectBucket  *b;
        FcObjectType    *o;
    
        if (!FcObjectsInited)
    	FcObjectInit ();
        for (p = &FcObjectBuckets[hash%OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
        {
    	o = FcObjects + b->id - 1;
            if (b->hash == hash && !strcmp (object->object, o->object))
                return FcFalse;
        }
        /*
         * Hook it into the hash chain
         */
        b = malloc (sizeof(FcObjectBucket));
        if (!b) 
    	return FcFalse;
        if (copy)
        {
    	o = FcObjectInsert (object->object, object->type);
    	if (!o)
    	{
    	    free (b);
    	    return FcFalse;
    	}
        }
        else
    	o = (FcObjectType *) object;
        b->next = NULL;
        b->hash = hash;
        b->id = FcObjectId (o);
        *p = b;
        return FcTrue;
    }
    
    static void
    FcObjectHashRemove (const FcObjectType *object, FcBool cleanobj)
    {
        FcChar32	    hash = FcStringHash ((const FcChar8 *) object->object);
        FcObjectBucket  **p;
        FcObjectBucket  *b;
        FcObjectType    *o;
    
        if (!FcObjectsInited)
    	FcObjectInit ();
        for (p = &FcObjectBuckets[hash%OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
        {
    	o = FcObjects + b->id - 1;
            if (b->hash == hash && !strcmp (object->object, o->object))
    	{
    	    *p = b->next;
    	    free (b);
    	    if (cleanobj)
    	    {
    		/* Clean up object array */
    		o->object = NULL;
    		o->type = -1;
    		while (FcObjects[FcObjectsNumber-1].object == NULL)
    		    --FcObjectsNumber;
    	    }
                break;
    	}
        }
    }
    
    FcBool
    FcNameRegisterObjectTypes (const FcObjectType *types, int ntypes)
    {
        int	i;
    
        for (i = 0; i < ntypes; i++)
    	if (!FcObjectHashInsert (&types[i], FcTrue))
    	    return FcFalse;
        return FcTrue;
    }
    
    FcBool
    FcNameUnregisterObjectTypes (const FcObjectType *types, int ntypes)
    {
        int	i;
    
        for (i = 0; i < ntypes; i++)
    	FcObjectHashRemove (&types[i], FcTrue);
        return FcTrue;
    }
    
    const FcObjectType *
    FcNameGetObjectType (const char *object)
    {
        return FcObjectFindByName (object, FcFalse);
    }
    
    FcBool
    FcObjectValidType (FcObject object, FcType type)
    {
        FcObjectType    *t = FcObjectFindById (object);
    
        if (t) {
    	switch (t->type) {
    	case -1:
    	    return FcTrue;
    	case FcTypeDouble:
    	case FcTypeInteger:
    	    if (type == FcTypeDouble || type == FcTypeInteger)
    		return FcTrue;
    	    break;
    	case FcTypeLangSet:
    	    if (type == FcTypeLangSet || type == FcTypeString)
    		return FcTrue;
    	    break;
    	default:
    	    if (type == t->type)
    		return FcTrue;
    	    break;
    	}
    	return FcFalse;
        }
        return FcTrue;
    }
    
    FcObject
    FcObjectFromName (const char * name)
    {
        FcObjectType    *o = FcObjectFindByName (name, FcTrue);
    
        if (o)
    	return FcObjectId (o);
        return 0;
    }
    
    FcObjectSet *
    FcObjectGetSet (void)
    {
        int		i;
        FcObjectSet	*os = NULL;
    
    
        os = FcObjectSetCreate ();
        for (i = 0; i < FcObjectsNumber; i++)
    	FcObjectSetAdd (os, FcObjects[i].object);
    
        return os;
    }
    
    FcBool
    FcObjectInit (void)
    {
        int	i;
    
        if (FcObjectsInited)
    	return FcTrue;
    
        FcObjectsInited = FcTrue;
        for (i = 0; i < NUM_OBJECT_TYPES; i++)
    	if (!FcObjectHashInsert (&_FcBaseObjectTypes[i], FcFalse))
    	    return FcFalse;
        return FcTrue;
    }
    
    void
    FcObjectFini (void)
    {
        int		    i;
        FcObjectBucket  *b, *next;
    
        for (i = 0; i < OBJECT_HASH_SIZE; i++)
        {
    	for (b = FcObjectBuckets[i]; b; b = next)
    	{
    	    next = b->next;
    	    free (b);
    	}
    	FcObjectBuckets[i] = 0;
        }
        for (i = 0; i < FcObjectsNumber; i++)
    	if (FcObjects[i].type == -1)
    	    free ((void*) FcObjects[i].object);
        if (FcObjects != _FcBaseObjectTypes)
    	free (FcObjects);
        FcObjects = (FcObjectType *) _FcBaseObjectTypes;
        FcObjectsNumber = NUM_OBJECT_TYPES;
        FcObjectsSize = 0;
        FcObjectsInited = FcFalse;
    }
    
    const char *
    FcObjectName (FcObject object)
    {
        FcObjectType    *o = FcObjectFindById (object);
    
        if (o)
    	return o->object;
        return NULL;
    }
    
    static const FcConstant _FcBaseConstants[] = {
        { (FcChar8 *) "thin",	    "weight",   FC_WEIGHT_THIN, },
        { (FcChar8 *) "extralight",	    "weight",   FC_WEIGHT_EXTRALIGHT, },
        { (FcChar8 *) "ultralight",	    "weight",   FC_WEIGHT_EXTRALIGHT, },
        { (FcChar8 *) "light",	    "weight",   FC_WEIGHT_LIGHT, },
        { (FcChar8 *) "book",	    "weight",	FC_WEIGHT_BOOK, },
        { (FcChar8 *) "regular",	    "weight",   FC_WEIGHT_REGULAR, },
        { (FcChar8 *) "medium",	    "weight",   FC_WEIGHT_MEDIUM, },
        { (FcChar8 *) "demibold",	    "weight",   FC_WEIGHT_DEMIBOLD, },
        { (FcChar8 *) "semibold",	    "weight",   FC_WEIGHT_DEMIBOLD, },
        { (FcChar8 *) "bold",	    "weight",   FC_WEIGHT_BOLD, },
        { (FcChar8 *) "extrabold",	    "weight",   FC_WEIGHT_EXTRABOLD, },
        { (FcChar8 *) "ultrabold",	    "weight",   FC_WEIGHT_EXTRABOLD, },
        { (FcChar8 *) "black",	    "weight",   FC_WEIGHT_BLACK, },
        { (FcChar8 *) "heavy",	    "weight",	FC_WEIGHT_HEAVY, },
    
        { (FcChar8 *) "roman",	    "slant",    FC_SLANT_ROMAN, },
        { (FcChar8 *) "italic",	    "slant",    FC_SLANT_ITALIC, },
        { (FcChar8 *) "oblique",	    "slant",    FC_SLANT_OBLIQUE, },
    
        { (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 },
        
        { (FcChar8 *) "proportional",   "spacing",  FC_PROPORTIONAL, },
        { (FcChar8 *) "dual",	    "spacing",  FC_DUAL, },
        { (FcChar8 *) "mono",	    "spacing",  FC_MONO, },
        { (FcChar8 *) "charcell",	    "spacing",  FC_CHARCELL, },
    
        { (FcChar8 *) "unknown",	    "rgba",	    FC_RGBA_UNKNOWN },
        { (FcChar8 *) "rgb",	    "rgba",	    FC_RGBA_RGB, },
        { (FcChar8 *) "bgr",	    "rgba",	    FC_RGBA_BGR, },
        { (FcChar8 *) "vrgb",	    "rgba",	    FC_RGBA_VRGB },
        { (FcChar8 *) "vbgr",	    "rgba",	    FC_RGBA_VBGR },
        { (FcChar8 *) "none",	    "rgba",	    FC_RGBA_NONE },
    
        { (FcChar8 *) "hintnone",	    "hintstyle",   FC_HINT_NONE },
        { (FcChar8 *) "hintslight",	    "hintstyle",   FC_HINT_SLIGHT },
        { (FcChar8 *) "hintmedium",	    "hintstyle",   FC_HINT_MEDIUM },
        { (FcChar8 *) "hintfull",	    "hintstyle",   FC_HINT_FULL },
    
        { (FcChar8 *) "antialias",	    "antialias",    FcTrue },
        { (FcChar8 *) "hinting",	    "hinting",	    FcTrue },
        { (FcChar8 *) "verticallayout", "verticallayout",	FcTrue },
        { (FcChar8 *) "autohint",	    "autohint",	    FcTrue },
        { (FcChar8 *) "globaladvance",  "globaladvance",	FcTrue },
        { (FcChar8 *) "outline",	    "outline",	    FcTrue },
        { (FcChar8 *) "scalable",	    "scalable",	    FcTrue },
        { (FcChar8 *) "minspace",	    "minspace",	    FcTrue },
        { (FcChar8 *) "embolden",	    "embolden",	    FcTrue },
        { (FcChar8 *) "embeddedbitmap", "embeddedbitmap",	FcTrue },
        { (FcChar8 *) "decorative",	    "decorative",   FcTrue },
        { (FcChar8 *) "lcdnone",	    "lcdfilter",    FC_LCD_NONE },
        { (FcChar8 *) "lcddefault",	    "lcdfilter",    FC_LCD_DEFAULT },
        { (FcChar8 *) "lcdlight",	    "lcdfilter",    FC_LCD_LIGHT },
        { (FcChar8 *) "lcdlegacy",	    "lcdfilter",    FC_LCD_LEGACY },
    };
    
    #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;
        FcMemAlloc (FC_MEM_CONSTANT, sizeof (FcConstantList));
        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;
    	    FcMemFree (FC_MEM_CONSTANT, sizeof (FcConstantList));
    	    free ((void *) l);
    	    return FcTrue;
    	}
        }
        return FcFalse;
    }
    
    const FcConstant *
    FcNameGetConstant (FcChar8 *string)
    {
        const FcConstantList    *l;
        int			    i;
    
        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
    FcNameConstant (FcChar8 *string, int *result)
    {
        const FcConstant	*c;
    
        if ((c = FcNameGetConstant(string)))
        {
    	*result = c->value;
    	return FcTrue;
        }
        return FcFalse;
    }
    
    FcBool
    FcNameBool (const FcChar8 *v, FcBool *result)
    {
        char    c0, c1;
    
        c0 = *v;
        c0 = FcToLower (c0);
        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];
    	c1 = FcToLower (c1);
    	if (c1 == 'n')
    	{
    	    *result = FcTrue;
    	    return FcTrue;
    	}
    	if (c1 == 'f')
    	{
    	    *result = FcFalse;
    	    return FcTrue;
    	}
        }
        return FcFalse;
    }
    
    static FcValue
    FcNameConvert (FcType type, FcChar8 *string, FcMatrix *m)
    {
        FcValue	v;
    
        v.type = type;
        switch (v.type) {
        case FcTypeInteger:
    	if (!FcNameConstant (string, &v.u.i))
    	    v.u.i = atoi ((char *) string);
    	break;
        case FcTypeString:
    	v.u.s = FcStrStaticName(string);
    	if (!v.u.s)
    	    v.type = FcTypeVoid;
    	break;
        case FcTypeBool:
    	if (!FcNameBool (string, &v.u.b))
    	    v.u.b = FcFalse;
    	break;
        case FcTypeDouble:
    	v.u.d = strtod ((char *) string, 0);
    	break;
        case FcTypeMatrix:
    	v.u.m = m;
    	sscanf ((char *) string, "%lg %lg %lg %lg", &m->xx, &m->xy, &m->yx, &m->yy);
    	break;
        case FcTypeCharSet:
    	v.u.c = FcNameParseCharSet (string);
    	if (!v.u.c)
    	    v.type = FcTypeVoid;
    	break;
        case FcTypeLangSet:
    	v.u.l = FcNameParseLangSet (string);
    	if (!v.u.l)
    	    v.type = FcTypeVoid;
    	break;
        default:
    	break;
        }
        return v;
    }
    
    static const FcChar8 *
    FcNameFindNext (const FcChar8 *cur, const char *delim, FcChar8 *save, FcChar8 *last)
    {
        FcChar8    c;
        
        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 *
    FcNameParse (const FcChar8 *name)
    {
        FcChar8		*save;
        FcPattern		*pat;
        double		d;
        FcChar8		*e;
        FcChar8		delim;
        FcValue		v;
        FcMatrix		m;
        const FcObjectType	*t;
        const FcConstant	*c;
    
        /* freed below */
        save = malloc (strlen ((char *) name) + 1);
        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);
    	    d = strtod ((char *) save, (char **) &e);
    	    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 == '_')
    	    {
    		t = FcNameGetObjectType ((char *) save);
    		for (;;)
    		{
    		    name = FcNameFindNext (name, ":,", save, &delim);
    		    if (t)
    		    {
    			v = FcNameConvert (t->type, save, &m);
    			if (!FcPatternAdd (pat, t->object, v, FcTrue))
    			{
    			    switch (v.type) {
    			    case FcTypeCharSet:
    				FcCharSetDestroy ((FcCharSet *) v.u.c);
    				break;
    			    case FcTypeLangSet:
    				FcLangSetDestroy ((FcLangSet *) v.u.l);
    				break;
    			    default:
    				break;
    			    }
    			    goto bail2;
    			}
    			switch (v.type) {
    			case FcTypeCharSet:
    			    FcCharSetDestroy ((FcCharSet *) v.u.c);
    			    break;
    			case FcTypeLangSet:
    			    FcLangSetDestroy ((FcLangSet *) v.u.l);
    			    break;
    			default:
    			    break;
    			}
    		    }
    		    if (delim != ',')
    			break;
    		}
    	    }
    	    else
    	    {
    		if ((c = FcNameGetConstant (save)))
    		{
    		    t = FcNameGetObjectType ((char *) c->object);
    		    switch (t->type) {
    		    case FcTypeInteger:
    		    case FcTypeDouble:
    			if (!FcPatternAddInteger (pat, c->object, c->value))
    			    goto bail2;
    			break;
    		    case FcTypeBool:
    			if (!FcPatternAddBool (pat, c->object, c->value))
    			    goto bail2;
    			break;
    		    default:
    			break;
    		    }
    		}
    	    }
    	}
        }
    
        free (save);
        return pat;
    
    bail2:
        FcPatternDestroy (pat);
    bail1:
        free (save);
    bail0:
        return 0;
    }
    static FcBool
    FcNameUnparseString (FcStrBuf	    *buf, 
    		     const FcChar8  *string,
    		     const FcChar8  *escape)
    {
        FcChar8 c;
        while ((c = *string++))
        {
    	if (escape && strchr ((char *) escape, (char) c))
    	{
    	    if (!FcStrBufChar (buf, escape[0]))
    		return FcFalse;
    	}
    	if (!FcStrBufChar (buf, c))
    	    return FcFalse;
        }
        return FcTrue;
    }
    
    FcBool
    FcNameUnparseValue (FcStrBuf	*buf,
    		    FcValue	*v0,
    		    FcChar8	*escape)
    {
        FcChar8	temp[1024];
        FcValue v = FcValueCanonicalize(v0);
        
        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:
    	return FcNameUnparseString (buf, v.u.b ? (FcChar8 *) "True" : (FcChar8 *) "False", 0);
        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);
        case FcTypeLangSet:
    	return FcNameUnparseLangSet (buf, v.u.l);
        case FcTypeFTFace:
    	return FcTrue;
        }
        return FcFalse;
    }
    
    FcBool
    FcNameUnparseValueList (FcStrBuf	*buf,
    			FcValueListPtr	v,
    			FcChar8		*escape)
    {
        while (v)
        {
    	if (!FcNameUnparseValue (buf, &v->value, escape))
    	    return FcFalse;
    	if ((v = FcValueListNext(v)) != NULL)
    	    if (!FcNameUnparseString (buf, (FcChar8 *) ",", 0))
    		return FcFalse;
        }
        return FcTrue;
    }
    
    #define FC_ESCAPE_FIXED    "\\-:,"
    #define FC_ESCAPE_VARIABLE "\\=_:,"
    
    FcChar8 *
    FcNameUnparse (FcPattern *pat)
    {
        return FcNameUnparseEscaped (pat, FcTrue);
    }
    
    FcChar8 *
    FcNameUnparseEscaped (FcPattern *pat, FcBool escape)
    {
        FcStrBuf		    buf;
        FcChar8		    buf_static[8192];
        int			    i;
        FcPatternElt	    *e;
        const FcObjectTypeList  *l;
        const FcObjectType	    *o;
    
        FcStrBufInit (&buf, buf_static, sizeof (buf_static));
        e = FcPatternObjectFindElt (pat, FC_FAMILY_OBJECT);
        if (e)
        {
            if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0))
    	    goto bail0;
        }
        e = FcPatternObjectFindElt (pat, FC_SIZE_OBJECT);
        if (e)
        {
    	if (!FcNameUnparseString (&buf, (FcChar8 *) "-", 0))
    	    goto bail0;
    	if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0))
    	    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;
    	    
    	    e = FcPatternObjectFindElt (pat, FcObjectFromName (o->object));
    	    if (e)
    	    {
    		if (!FcNameUnparseString (&buf, (FcChar8 *) ":", 0))
    		    goto bail0;
    		if (!FcNameUnparseString (&buf, (FcChar8 *) o->object, escape ? (FcChar8 *) FC_ESCAPE_VARIABLE : 0))
    		    goto bail0;
    		if (!FcNameUnparseString (&buf, (FcChar8 *) "=", 0))
    		    goto bail0;
    		if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ? 
    					     (FcChar8 *) FC_ESCAPE_VARIABLE : 0))
    		    goto bail0;
    	    }
    	}
        }
        return FcStrBufDone (&buf);
    bail0:
        FcStrBufDestroy (&buf);
        return 0;
    }
    #define __fcname__
    #include "fcaliastail.h"
    #undef __fcname__