blob: eb1ebd4ea2e89acb0dedc3b3c088fcf3a0eb020e [file] [log] [blame]
/*
* $RCSId: xc/lib/fontconfig/src/fcpat.c,v 1.18 2002/09/18 17:11:46 tsi Exp $
*
* 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.
*
* 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 <stdlib.h>
#include <string.h>
#include <assert.h>
#include "fcint.h"
FcPattern *
FcPatternCreate (void)
{
FcPattern *p;
p = (FcPattern *) malloc (sizeof (FcPattern));
if (!p)
return 0;
FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern));
p->num = 0;
p->size = 0;
p->elts = 0;
p->ref = 1;
return p;
}
void
FcValueDestroy (FcValue v)
{
switch (v.type) {
case FcTypeString:
FcStrFree ((FcChar8 *) v.u.s);
break;
case FcTypeMatrix:
FcMatrixFree ((FcMatrix *) v.u.m);
break;
case FcTypeCharSet:
FcCharSetDestroy ((FcCharSet *) v.u.c);
break;
case FcTypeLangSet:
FcLangSetDestroy ((FcLangSet *) v.u.l);
break;
default:
break;
}
}
FcValue
FcValueSave (FcValue v)
{
switch (v.type) {
case FcTypeString:
v.u.s = FcStrCopy (v.u.s);
if (!v.u.s)
v.type = FcTypeVoid;
break;
case FcTypeMatrix:
v.u.m = FcMatrixCopy (v.u.m);
if (!v.u.m)
v.type = FcTypeVoid;
break;
case FcTypeCharSet:
v.u.c = FcCharSetCopy ((FcCharSet *) v.u.c);
if (!v.u.c)
v.type = FcTypeVoid;
break;
case FcTypeLangSet:
v.u.l = FcLangSetCopy (v.u.l);
if (!v.u.l)
v.type = FcTypeVoid;
break;
default:
break;
}
return v;
}
void
FcValueListDestroy (FcValueList *l)
{
FcValueList *next;
for (; l; l = next)
{
switch (l->value.type) {
case FcTypeString:
FcStrFree ((FcChar8 *) l->value.u.s);
break;
case FcTypeMatrix:
FcMatrixFree ((FcMatrix *) l->value.u.m);
break;
case FcTypeCharSet:
FcCharSetDestroy ((FcCharSet *) l->value.u.c);
break;
case FcTypeLangSet:
FcLangSetDestroy ((FcLangSet *) l->value.u.l);
break;
default:
break;
}
next = l->next;
FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
free (l);
}
}
FcBool
FcValueEqual (FcValue va, FcValue vb)
{
if (va.type != vb.type)
{
if (va.type == FcTypeInteger)
{
va.type = FcTypeDouble;
va.u.d = va.u.i;
}
if (vb.type == FcTypeInteger)
{
vb.type = FcTypeDouble;
vb.u.d = vb.u.i;
}
if (va.type != vb.type)
return FcFalse;
}
switch (va.type) {
case FcTypeVoid:
return FcTrue;
case FcTypeInteger:
return va.u.i == vb.u.i;
case FcTypeDouble:
return va.u.d == vb.u.d;
case FcTypeString:
return FcStrCmpIgnoreCase (va.u.s, vb.u.s) == 0;
case FcTypeBool:
return va.u.b == vb.u.b;
case FcTypeMatrix:
return FcMatrixEqual (va.u.m, vb.u.m);
case FcTypeCharSet:
return FcCharSetEqual (va.u.c, vb.u.c);
case FcTypeFTFace:
return va.u.f == vb.u.f;
case FcTypeLangSet:
return FcLangSetEqual (va.u.l, vb.u.l);
}
return FcFalse;
}
static FcChar32
FcDoubleHash (double d)
{
if (d < 0)
d = -d;
if (d > 0xffffffff)
d = 0xffffffff;
return (FcChar32) d;
}
static FcChar32
FcStringHash (const FcChar8 *s)
{
FcChar8 c;
FcChar32 h = 0;
if (s)
while ((c = *s++))
h = ((h << 1) | (h >> 31)) ^ c;
return h;
}
static FcChar32
FcValueHash (FcValue v)
{
switch (v.type) {
case FcTypeVoid:
return 0;
case FcTypeInteger:
return (FcChar32) v.u.i;
case FcTypeDouble:
return FcDoubleHash (v.u.d);
case FcTypeString:
return FcStringHash (v.u.s);
case FcTypeBool:
return (FcChar32) v.u.b;
case FcTypeMatrix:
return (FcDoubleHash (v.u.m->xx) ^
FcDoubleHash (v.u.m->xy) ^
FcDoubleHash (v.u.m->yx) ^
FcDoubleHash (v.u.m->yy));
case FcTypeCharSet:
return (FcChar32) v.u.c->num;
case FcTypeFTFace:
return FcStringHash ((const FcChar8 *) ((FT_Face) v.u.f)->family_name) ^
FcStringHash ((const FcChar8 *) ((FT_Face) v.u.f)->style_name);
case FcTypeLangSet:
return FcLangSetHash (v.u.l);
}
return FcFalse;
}
static FcBool
FcValueListEqual (FcValueList *la, FcValueList *lb)
{
if (la == lb)
return FcTrue;
while (la && lb)
{
if (!FcValueEqual (la->value, lb->value))
return FcFalse;
la = la->next;
lb = lb->next;
}
if (la || lb)
return FcFalse;
return FcTrue;
}
static FcChar32
FcValueListHash (FcValueList *l)
{
FcChar32 hash = 0;
while (l)
{
hash = ((hash << 1) | (hash >> 31)) ^ FcValueHash (l->value);
l = l->next;
}
return hash;
}
void
FcPatternDestroy (FcPattern *p)
{
int i;
if (p->ref == FC_REF_CONSTANT || --p->ref > 0)
return;
for (i = 0; i < p->num; i++)
FcValueListDestroy (p->elts[i].values);
p->num = 0;
if (p->elts)
{
FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
free (p->elts);
p->elts = 0;
}
p->size = 0;
FcMemFree (FC_MEM_PATTERN, sizeof (FcPattern));
free (p);
}
#define FC_VALUE_LIST_HASH_SIZE 257
#define FC_PATTERN_HASH_SIZE 67
typedef struct _FcValueListEnt FcValueListEnt;
struct _FcValueListEnt {
FcValueListEnt *next;
FcValueList *list;
FcChar32 hash, pad;
};
typedef union _FcValueListAlign {
FcValueListEnt ent;
FcValueList list;
} FcValueListAlign;
static int FcValueListFrozenCount[FcTypeLangSet + 1];
static int FcValueListFrozenBytes[FcTypeLangSet + 1];
static char *FcValueListFrozenName[] = {
"Void",
"Integer",
"Double",
"String",
"Bool",
"Matrix",
"CharSet",
"FTFace",
"LangSet"
};
void
FcValueListReport (void);
void
FcValueListReport (void)
{
FcType t;
printf ("Fc Frozen Values:\n");
printf ("\t%8s %9s %9s\n", "Type", "Count", "Bytes");
for (t = FcTypeVoid; t <= FcTypeLangSet; t++)
printf ("\t%8s %9d %9d\n", FcValueListFrozenName[t],
FcValueListFrozenCount[t], FcValueListFrozenBytes[t]);
}
static FcValueListEnt *
FcValueListEntCreate (FcValueList *h)
{
FcValueListAlign *ea;
FcValueListEnt *e;
FcValueList *l, *new;
int n;
int string_size = 0;
FcChar8 *strs;
int size;
n = 0;
for (l = h; l; l = l->next)
{
if (l->value.type == FcTypeString)
string_size += strlen ((char *) l->value.u.s) + 1;
n++;
}
size = sizeof (FcValueListAlign) + n * sizeof (FcValueList) + string_size;
FcValueListFrozenCount[h->value.type]++;
FcValueListFrozenBytes[h->value.type] += size;
ea = malloc (size);
if (!ea)
return 0;
FcMemAlloc (FC_MEM_VALLIST, size);
e = &ea->ent;
e->list = (FcValueList *) (ea + 1);
strs = (FcChar8 *) (e->list + n);
new = e->list;
for (l = h; l; l = l->next, new++)
{
if (l->value.type == FcTypeString)
{
new->value.type = FcTypeString;
new->value.u.s = strs;
strcpy ((char *) strs, (char *) l->value.u.s);
strs += strlen ((char *) strs) + 1;
}
else
{
new->value = l->value;
new->value = FcValueSave (new->value);
}
new->binding = l->binding;
if (l->next)
new->next = new + 1;
else
new->next = 0;
}
return e;
}
static int FcValueListTotal;
static int FcValueListUsed;
static FcValueList *
FcValueListFreeze (FcValueList *l)
{
static FcValueListEnt *hashTable[FC_VALUE_LIST_HASH_SIZE];
FcChar32 hash = FcValueListHash (l);
FcValueListEnt **bucket = &hashTable[hash % FC_VALUE_LIST_HASH_SIZE];
FcValueListEnt *ent;
FcValueListTotal++;
for (ent = *bucket; ent; ent = ent->next)
{
if (ent->hash == hash && FcValueListEqual (ent->list, l))
return ent->list;
}
ent = FcValueListEntCreate (l);
if (!ent)
return 0;
FcValueListUsed++;
ent->hash = hash;
ent->next = *bucket;
*bucket = ent;
return ent->list;
}
static FcChar32
FcPatternBaseHash (FcPattern *b)
{
FcChar32 hash = b->num;
int i;
for (i = 0; i < b->num; i++)
hash = ((hash << 1) | (hash >> 31)) ^ ((long) b->elts[i].values);
return hash;
}
typedef struct _FcPatternEnt FcPatternEnt;
struct _FcPatternEnt {
FcPatternEnt *next;
FcChar32 hash;
FcPattern pattern;
};
static int FcPatternTotal;
static int FcPatternUsed;
static FcPattern *
FcPatternBaseFreeze (FcPattern *b)
{
static FcPatternEnt *hashTable[FC_VALUE_LIST_HASH_SIZE];
FcChar32 hash = FcPatternBaseHash (b);
FcPatternEnt **bucket = &hashTable[hash % FC_VALUE_LIST_HASH_SIZE];
FcPatternEnt *ent;
int i;
char *objects;
int size_objects;
int size;
FcPatternTotal++;
for (ent = *bucket; ent; ent = ent->next)
{
if (ent->hash == hash && b->num == ent->pattern.num)
{
for (i = 0; i < b->num; i++)
{
if (strcmp (b->elts[i].object, ent->pattern.elts[i].object))
break;
if (b->elts[i].values != ent->pattern.elts[i].values)
break;
}
if (i == b->num)
return &ent->pattern;
}
}
/*
* Compute size of pattern + elts + object names
*/
size_objects = 0;
for (i = 0; i < b->num; i++)
size_objects += strlen (b->elts[i].object) + 1;
size = sizeof (FcPatternEnt) + b->num*sizeof (FcPatternElt) + size_objects;
ent = malloc (size);
if (!ent)
return 0;
FcMemAlloc (FC_MEM_PATTERN, size);
FcPatternUsed++;
ent->pattern.elts = (FcPatternElt *) (ent + 1);
ent->pattern.num = b->num;
ent->pattern.size = b->num;
ent->pattern.ref = FC_REF_CONSTANT;
objects = (char *) (ent->pattern.elts + b->num);
for (i = 0; i < b->num; i++)
{
ent->pattern.elts[i].values = b->elts[i].values;
strcpy (objects, b->elts[i].object);
ent->pattern.elts[i].object = objects;
objects += strlen (objects) + 1;
}
ent->hash = hash;
ent->next = *bucket;
*bucket = ent;
return &ent->pattern;
}
FcPattern *
FcPatternFreeze (FcPattern *p)
{
FcPattern *b, *n = 0;
int size;
int i;
size = sizeof (FcPattern) + p->num * sizeof (FcPatternElt);
b = (FcPattern *) malloc (size);
if (!b)
return 0;
FcMemAlloc (FC_MEM_PATTERN, size);
b->num = p->num;
b->size = b->num;
b->ref = 1;
b->elts = (FcPatternElt *) (b + 1);
/*
* Freeze object lists
*/
for (i = 0; i < p->num; i++)
{
b->elts[i].object = p->elts[i].object;
b->elts[i].values = FcValueListFreeze (p->elts[i].values);
if (!b->elts[i].values)
goto bail;
}
/*
* Freeze base
*/
n = FcPatternBaseFreeze (b);
#ifdef CHATTY
if (FcDebug() & FC_DBG_MEMORY)
{
printf ("ValueLists: total %9d used %9d\n", FcValueListTotal, FcValueListUsed);
printf ("Patterns: total %9d used %9d\n", FcPatternTotal, FcPatternUsed);
}
#endif
bail:
free (b);
#ifdef DEBUG
assert (FcPatternEqual (n, p));
#endif
return n;
}
static int
FcPatternPosition (const FcPattern *p, const char *object)
{
int low, high, mid, c;
low = 0;
high = p->num - 1;
c = 1;
mid = 0;
while (low <= high)
{
mid = (low + high) >> 1;
c = strcmp (p->elts[mid].object, object);
if (c == 0)
return mid;
if (c < 0)
low = mid + 1;
else
high = mid - 1;
}
if (c < 0)
mid++;
return -(mid + 1);
}
FcPatternElt *
FcPatternFindElt (const FcPattern *p, const char *object)
{
int i = FcPatternPosition (p, object);
if (i < 0)
return 0;
return &p->elts[i];
}
FcPatternElt *
FcPatternInsertElt (FcPattern *p, const char *object)
{
int i;
FcPatternElt *e;
i = FcPatternPosition (p, object);
if (i < 0)
{
i = -i - 1;
/* grow array */
if (p->num + 1 >= p->size)
{
int s = p->size + 16;
if (p->elts)
e = (FcPatternElt *) realloc (p->elts, s * sizeof (FcPatternElt));
else
e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
if (!e)
return FcFalse;
p->elts = e;
if (p->size)
FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
FcMemAlloc (FC_MEM_PATELT, s * sizeof (FcPatternElt));
while (p->size < s)
{
p->elts[p->size].object = 0;
p->elts[p->size].values = 0;
p->size++;
}
}
/* move elts up */
memmove (p->elts + i + 1,
p->elts + i,
sizeof (FcPatternElt) *
(p->num - i));
/* bump count */
p->num++;
p->elts[i].object = object;
p->elts[i].values = 0;
}
return &p->elts[i];
}
FcBool
FcPatternEqual (const FcPattern *pa, const FcPattern *pb)
{
int i;
if (pa == pb)
return FcTrue;
if (pa->num != pb->num)
return FcFalse;
for (i = 0; i < pa->num; i++)
{
if (strcmp (pa->elts[i].object, pb->elts[i].object) != 0)
return FcFalse;
if (!FcValueListEqual (pa->elts[i].values, pb->elts[i].values))
return FcFalse;
}
return FcTrue;
}
FcChar32
FcPatternHash (const FcPattern *p)
{
int i;
FcChar32 h = 0;
for (i = 0; i < p->num; i++)
{
h = (((h << 1) | (h >> 31)) ^
FcStringHash ((const FcChar8 *) p->elts[i].object) ^
FcValueListHash (p->elts[i].values));
}
return h;
}
FcBool
FcPatternEqualSubset (const FcPattern *pa, const FcPattern *pb, const FcObjectSet *os)
{
FcPatternElt *ea, *eb;
int i;
for (i = 0; i < os->nobject; i++)
{
ea = FcPatternFindElt (pa, os->objects[i]);
eb = FcPatternFindElt (pb, os->objects[i]);
if (ea)
{
if (!eb)
return FcFalse;
if (!FcValueListEqual (ea->values, eb->values))
return FcFalse;
}
else
{
if (eb)
return FcFalse;
}
}
return FcTrue;
}
FcBool
FcPatternAddWithBinding (FcPattern *p,
const char *object,
FcValue value,
FcValueBinding binding,
FcBool append)
{
FcPatternElt *e;
FcValueList *new, **prev;
if (p->ref == FC_REF_CONSTANT)
goto bail0;
new = (FcValueList *) malloc (sizeof (FcValueList));
if (!new)
goto bail0;
FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
/* dup string */
value = FcValueSave (value);
if (value.type == FcTypeVoid)
goto bail1;
new->value = value;
new->binding = binding;
new->next = 0;
e = FcPatternInsertElt (p, object);
if (!e)
goto bail2;
if (append)
{
for (prev = &e->values; *prev; prev = &(*prev)->next);
*prev = new;
}
else
{
new->next = e->values;
e->values = new;
}
return FcTrue;
bail2:
switch (value.type) {
case FcTypeString:
FcStrFree ((FcChar8 *) value.u.s);
break;
case FcTypeMatrix:
FcMatrixFree ((FcMatrix *) value.u.m);
break;
case FcTypeCharSet:
FcCharSetDestroy ((FcCharSet *) value.u.c);
break;
case FcTypeLangSet:
FcLangSetDestroy ((FcLangSet *) value.u.l);
break;
default:
break;
}
bail1:
FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
free (new);
bail0:
return FcFalse;
}
FcBool
FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
{
return FcPatternAddWithBinding (p, object, value, FcValueBindingStrong, append);
}
FcBool
FcPatternAddWeak (FcPattern *p, const char *object, FcValue value, FcBool append)
{
return FcPatternAddWithBinding (p, object, value, FcValueBindingWeak, append);
}
FcBool
FcPatternDel (FcPattern *p, const char *object)
{
FcPatternElt *e;
int i;
e = FcPatternFindElt (p, object);
if (!e)
return FcFalse;
i = e - p->elts;
/* destroy value */
FcValueListDestroy (e->values);
/* shuffle existing ones down */
memmove (e, e+1, (p->elts + p->num - (e + 1)) * sizeof (FcPatternElt));
p->num--;
p->elts[p->num].object = 0;
p->elts[p->num].values = 0;
return FcTrue;
}
FcBool
FcPatternAddInteger (FcPattern *p, const char *object, int i)
{
FcValue v;
v.type = FcTypeInteger;
v.u.i = i;
return FcPatternAdd (p, object, v, FcTrue);
}
FcBool
FcPatternAddDouble (FcPattern *p, const char *object, double d)
{
FcValue v;
v.type = FcTypeDouble;
v.u.d = d;
return FcPatternAdd (p, object, v, FcTrue);
}
FcBool
FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
{
FcValue v;
v.type = FcTypeString;
v.u.s = s;
return FcPatternAdd (p, object, v, FcTrue);
}
FcBool
FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
{
FcValue v;
v.type = FcTypeMatrix;
v.u.m = (FcMatrix *) s;
return FcPatternAdd (p, object, v, FcTrue);
}
FcBool
FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
{
FcValue v;
v.type = FcTypeBool;
v.u.b = b;
return FcPatternAdd (p, object, v, FcTrue);
}
FcBool
FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
{
FcValue v;
v.type = FcTypeCharSet;
v.u.c = (FcCharSet *) c;
return FcPatternAdd (p, object, v, FcTrue);
}
FcBool
FcPatternAddFTFace (FcPattern *p, const char *object, const FT_Face f)
{
FcValue v;
v.type = FcTypeFTFace;
v.u.f = (void *) f;
return FcPatternAdd (p, object, v, FcTrue);
}
FcBool
FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls)
{
FcValue v;
v.type = FcTypeLangSet;
v.u.l = (FcLangSet *) ls;
return FcPatternAdd (p, object, v, FcTrue);
}
FcResult
FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v)
{
FcPatternElt *e;
FcValueList *l;
e = FcPatternFindElt (p, object);
if (!e)
return FcResultNoMatch;
for (l = e->values; l; l = l->next)
{
if (!id)
{
*v = l->value;
return FcResultMatch;
}
id--;
}
return FcResultNoId;
}
FcResult
FcPatternGetInteger (const FcPattern *p, const char *object, int id, int *i)
{
FcValue v;
FcResult r;
r = FcPatternGet (p, object, id, &v);
if (r != FcResultMatch)
return r;
switch (v.type) {
case FcTypeDouble:
*i = (int) v.u.d;
break;
case FcTypeInteger:
*i = v.u.i;
break;
default:
return FcResultTypeMismatch;
}
return FcResultMatch;
}
FcResult
FcPatternGetDouble (const FcPattern *p, const char *object, int id, double *d)
{
FcValue v;
FcResult r;
r = FcPatternGet (p, object, id, &v);
if (r != FcResultMatch)
return r;
switch (v.type) {
case FcTypeDouble:
*d = v.u.d;
break;
case FcTypeInteger:
*d = (double) v.u.i;
break;
default:
return FcResultTypeMismatch;
}
return FcResultMatch;
}
FcResult
FcPatternGetString (const FcPattern *p, const char *object, int id, FcChar8 ** s)
{
FcValue v;
FcResult r;
r = FcPatternGet (p, object, id, &v);
if (r != FcResultMatch)
return r;
if (v.type != FcTypeString)
return FcResultTypeMismatch;
*s = (FcChar8 *) v.u.s;
return FcResultMatch;
}
FcResult
FcPatternGetMatrix(const FcPattern *p, const char *object, int id, FcMatrix **m)
{
FcValue v;
FcResult r;
r = FcPatternGet (p, object, id, &v);
if (r != FcResultMatch)
return r;
if (v.type != FcTypeMatrix)
return FcResultTypeMismatch;
*m = (FcMatrix *) v.u.m;
return FcResultMatch;
}
FcResult
FcPatternGetBool(const FcPattern *p, const char *object, int id, FcBool *b)
{
FcValue v;
FcResult r;
r = FcPatternGet (p, object, id, &v);
if (r != FcResultMatch)
return r;
if (v.type != FcTypeBool)
return FcResultTypeMismatch;
*b = v.u.b;
return FcResultMatch;
}
FcResult
FcPatternGetCharSet(const FcPattern *p, const char *object, int id, FcCharSet **c)
{
FcValue v;
FcResult r;
r = FcPatternGet (p, object, id, &v);
if (r != FcResultMatch)
return r;
if (v.type != FcTypeCharSet)
return FcResultTypeMismatch;
*c = (FcCharSet *) v.u.c;
return FcResultMatch;
}
FcResult
FcPatternGetFTFace(const FcPattern *p, const char *object, int id, FT_Face *f)
{
FcValue v;
FcResult r;
r = FcPatternGet (p, object, id, &v);
if (r != FcResultMatch)
return r;
if (v.type != FcTypeFTFace)
return FcResultTypeMismatch;
*f = (FT_Face) v.u.f;
return FcResultMatch;
}
FcResult
FcPatternGetLangSet(const FcPattern *p, const char *object, int id, FcLangSet **ls)
{
FcValue v;
FcResult r;
r = FcPatternGet (p, object, id, &v);
if (r != FcResultMatch)
return r;
if (v.type != FcTypeLangSet)
return FcResultTypeMismatch;
*ls = (FcLangSet *) v.u.l;
return FcResultMatch;
}
FcPattern *
FcPatternDuplicate (const FcPattern *orig)
{
FcPattern *new;
int i;
FcValueList *l;
new = FcPatternCreate ();
if (!new)
goto bail0;
for (i = 0; i < orig->num; i++)
{
for (l = orig->elts[i].values; l; l = l->next)
if (!FcPatternAdd (new, orig->elts[i].object, l->value, FcTrue))
goto bail1;
}
return new;
bail1:
FcPatternDestroy (new);
bail0:
return 0;
}
void
FcPatternReference (FcPattern *p)
{
if (p->ref != FC_REF_CONSTANT)
p->ref++;
}
FcPattern *
FcPatternVaBuild (FcPattern *orig, va_list va)
{
FcPattern *ret;
FcPatternVapBuild (ret, orig, va);
return ret;
}
FcPattern *
FcPatternBuild (FcPattern *orig, ...)
{
va_list va;
va_start (va, orig);
FcPatternVapBuild (orig, orig, va);
va_end (va);
return orig;
}