]> git.wh0rd.org Git - fontconfig.git/blob - src/fcpat.c
#ifdef out old cache stuff, replace with first version of new mmapping
[fontconfig.git] / src / fcpat.c
1 /*
2  * $RCSId: xc/lib/fontconfig/src/fcpat.c,v 1.18 2002/09/18 17:11:46 tsi Exp $
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 Keith Packard not be used in
11  * advertising or publicity pertaining to distribution of the software without
12  * specific, written prior permission.  Keith Packard makes 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  * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18  * EVENT SHALL KEITH PACKARD 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 <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
28 #include <sys/mman.h>
29 #include "fcint.h"
30
31 static FcPattern * fcpatterns = NULL;
32 static int fcpattern_ptr, fcpattern_count;
33 static FcPatternElt * fcpatternelts = NULL;
34 static int fcpatternelt_ptr, fcpatternelt_count;
35 static FcValueList * fcvaluelists = NULL;
36 static int fcvaluelist_ptr, fcvaluelist_count;
37
38 static FcBool
39 FcPatternEltIsDynamic (FcPatternEltPtr pei);
40
41 static FcPatternEltPtr
42 FcPatternEltPtrCreateDynamic (FcPatternElt * e);
43
44 FcPattern *
45 FcPatternCreate (void)
46 {
47     FcPattern   *p;
48
49     p = (FcPattern *) malloc (sizeof (FcPattern));
50     if (!p)
51         return 0;
52     FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern));
53     p->num = 0;
54     p->size = 0;
55     p->elts = FcPatternEltPtrCreateDynamic(0);
56     p->ref = 1;
57     return p;
58 }
59
60 void
61 FcValueDestroy (FcValue v)
62 {
63     switch (v.type) {
64     case FcTypeString:
65         FcObjectPtrDestroy (v.u.si);
66         break;
67     case FcTypeMatrix:
68         FcMatrixPtrDestroy (v.u.mi);
69         break;
70     case FcTypeCharSet:
71         FcCharSetPtrDestroy (v.u.ci);
72         break;
73     case FcTypeLangSet:
74         FcLangSetPtrDestroy (v.u.li);
75         break;
76     default:
77         break;
78     }
79 }
80
81 FcValue
82 FcValueSave (FcValue v)
83 {
84     switch (v.type) {
85     case FcTypeString:
86         v.u.si = FcObjectStaticName(FcObjectPtrU(v.u.si));
87         if (!FcObjectPtrU(v.u.si))
88             v.type = FcTypeVoid;
89         break;
90     case FcTypeMatrix:
91         v.u.mi = FcMatrixPtrCreateDynamic
92             (FcMatrixCopy (FcMatrixPtrU(v.u.mi)));
93         if (!FcMatrixPtrU(v.u.mi))
94             v.type = FcTypeVoid;
95         break;
96     case FcTypeCharSet:
97         v.u.ci = FcCharSetCopyPtr (v.u.ci);
98         if (!FcCharSetPtrU(v.u.ci))
99             v.type = FcTypeVoid;
100         break;
101     case FcTypeLangSet:
102         v.u.li = FcLangSetPtrCreateDynamic
103             (FcLangSetCopy (FcLangSetPtrU(v.u.li)));
104         if (!FcLangSetPtrU(v.u.li))
105             v.type = FcTypeVoid;
106         break;
107     default:
108         break;
109     }
110     return v;
111 }
112
113 void
114 FcValueListDestroy (FcValueListPtr l)
115 {
116     FcValueListPtr next;
117     for (; FcValueListPtrU(l); l = next)
118     {
119         switch (FcValueListPtrU(l)->value.type) {
120         case FcTypeString:
121             FcObjectPtrDestroy (FcValueListPtrU(l)->value.u.si);
122             break;
123         case FcTypeMatrix:
124             FcMatrixPtrDestroy (FcValueListPtrU(l)->value.u.mi);
125             break;
126         case FcTypeCharSet:
127             FcCharSetDestroy 
128                 (FcCharSetPtrU (FcValueListPtrU(l)->value.u.ci));
129             break;
130         case FcTypeLangSet:
131             FcLangSetDestroy 
132                 (FcLangSetPtrU (FcValueListPtrU(l)->value.u.li));
133             break;
134         default:
135             break;
136         }
137         next = FcValueListPtrU(l)->next;
138
139         FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
140         if (l.storage == FcStorageDynamic)
141             free(l.u.dyn);
142     }
143 }
144
145 FcBool
146 FcValueEqual (FcValue va, FcValue vb)
147 {
148     if (va.type != vb.type)
149     {
150         if (va.type == FcTypeInteger)
151         {
152             va.type = FcTypeDouble;
153             va.u.d = va.u.i;
154         }
155         if (vb.type == FcTypeInteger)
156         {
157             vb.type = FcTypeDouble;
158             vb.u.d = vb.u.i;
159         }
160         if (va.type != vb.type)
161             return FcFalse;
162     }
163     switch (va.type) {
164     case FcTypeVoid:
165         return FcTrue;
166     case FcTypeInteger:
167         return va.u.i == vb.u.i;
168     case FcTypeDouble:
169         return va.u.d == vb.u.d;
170     case FcTypeString:
171         return FcStrCmpIgnoreCase (FcObjectPtrU(va.u.si), 
172                                    FcObjectPtrU(vb.u.si)) == 0;
173     case FcTypeBool:
174         return va.u.b == vb.u.b;
175     case FcTypeMatrix:
176         return FcMatrixEqual (FcMatrixPtrU(va.u.mi), 
177                               FcMatrixPtrU(vb.u.mi));
178     case FcTypeCharSet:
179         return FcCharSetEqual (FcCharSetPtrU(va.u.ci), 
180                                FcCharSetPtrU(vb.u.ci));
181     case FcTypeFTFace:
182         return va.u.f == vb.u.f;
183     case FcTypeLangSet:
184         return FcLangSetEqual (FcLangSetPtrU(va.u.li), 
185                                FcLangSetPtrU(vb.u.li));
186     }
187     return FcFalse;
188 }
189
190 static FcChar32
191 FcDoubleHash (double d)
192 {
193     if (d < 0)
194         d = -d;
195     if (d > 0xffffffff)
196         d = 0xffffffff;
197     return (FcChar32) d;
198 }
199
200 static FcChar32
201 FcStringHash (const FcChar8 *s)
202 {
203     FcChar8     c;
204     FcChar32    h = 0;
205     
206     if (s)
207         while ((c = *s++))
208             h = ((h << 1) | (h >> 31)) ^ c;
209     return h;
210 }
211
212 static FcChar32
213 FcValueHash (FcValue v)
214 {
215     switch (v.type) {
216     case FcTypeVoid:
217         return 0;
218     case FcTypeInteger:
219         return (FcChar32) v.u.i;
220     case FcTypeDouble:
221         return FcDoubleHash (v.u.d);
222     case FcTypeString:
223         return FcStringHash (FcObjectPtrU(v.u.si));
224     case FcTypeBool:
225         return (FcChar32) v.u.b;
226     case FcTypeMatrix:
227     {
228         FcMatrix * m = FcMatrixPtrU(v.u.mi);
229         return (FcDoubleHash (m->xx) ^ 
230                 FcDoubleHash (m->xy) ^ 
231                 FcDoubleHash (m->yx) ^ 
232                 FcDoubleHash (m->yy));
233     }
234     case FcTypeCharSet:
235         return (FcChar32) (FcCharSetPtrU(v.u.ci))->num;
236     case FcTypeFTFace:
237         return FcStringHash ((const FcChar8 *) ((FT_Face) v.u.f)->family_name) ^
238                FcStringHash ((const FcChar8 *) ((FT_Face) v.u.f)->style_name);
239     case FcTypeLangSet:
240         return FcLangSetHash (FcLangSetPtrU(v.u.li));
241     }
242     return FcFalse;
243 }
244
245 static FcBool
246 FcValueListEqual (FcValueListPtr la, FcValueListPtr lb)
247 {
248     if (FcValueListPtrU(la) == FcValueListPtrU(lb))
249         return FcTrue;
250
251     while (FcValueListPtrU(la) && FcValueListPtrU(lb))
252     {
253         if (!FcValueEqual (FcValueListPtrU(la)->value, 
254                            FcValueListPtrU(lb)->value))
255             return FcFalse;
256         la = FcValueListPtrU(la)->next;
257         lb = FcValueListPtrU(lb)->next;
258     }
259     if (FcValueListPtrU(la) || FcValueListPtrU(lb))
260         return FcFalse;
261     return FcTrue;
262 }
263
264 static FcChar32
265 FcValueListHash (FcValueListPtr l)
266 {
267     FcChar32    hash = 0;
268     
269     while (FcValueListPtrU(l))
270     {
271         hash = ((hash << 1) | (hash >> 31)) ^ 
272             FcValueHash (FcValueListPtrU(l)->value);
273         l = FcValueListPtrU(l)->next;
274     }
275     return hash;
276 }
277
278 void
279 FcPatternDestroy (FcPattern *p)
280 {
281     int             i;
282     
283     if (p->ref == FC_REF_CONSTANT || --p->ref > 0)
284         return;
285
286     for (i = 0; i < p->num; i++)
287         FcValueListDestroy ((FcPatternEltU(p->elts)+i)->values);
288
289     p->num = 0;
290     if (FcPatternEltU(p->elts) && FcPatternEltIsDynamic(p->elts))
291     {
292         FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
293         free (FcPatternEltU(p->elts));
294         p->elts = FcPatternEltPtrCreateDynamic(0);
295     }
296     p->size = 0;
297     FcMemFree (FC_MEM_PATTERN, sizeof (FcPattern));
298     free (p);
299 }
300
301 #define FC_VALUE_LIST_HASH_SIZE     257
302 #define FC_PATTERN_HASH_SIZE        67
303
304 typedef struct _FcValueListEnt FcValueListEnt;
305
306 struct _FcValueListEnt {
307     FcValueListEnt  *next;
308     FcValueListPtr  list;
309     FcChar32        hash, pad;
310 };
311
312 typedef union _FcValueListAlign {
313     FcValueListEnt  ent;
314     FcValueList     list;
315 } FcValueListAlign;
316
317 static int          FcValueListFrozenCount[FcTypeLangSet + 1];
318 static int          FcValueListFrozenBytes[FcTypeLangSet + 1];
319 static char         *FcValueListFrozenName[] = {
320     "Void", 
321     "Integer", 
322     "Double", 
323     "String", 
324     "Bool",
325     "Matrix",
326     "CharSet",
327     "FTFace",
328     "LangSet"
329 };
330
331 void
332 FcValueListReport (void);
333     
334 void
335 FcValueListReport (void)
336 {
337     FcType  t;
338
339     printf ("Fc Frozen Values:\n");
340     printf ("\t%8s %9s %9s\n", "Type", "Count", "Bytes");
341     for (t = FcTypeVoid; t <= FcTypeLangSet; t++)
342         printf ("\t%8s %9d %9d\n", FcValueListFrozenName[t],
343                 FcValueListFrozenCount[t], FcValueListFrozenBytes[t]);
344 }
345
346 static FcValueListEnt *
347 FcValueListEntCreate (FcValueListPtr h)
348 {
349     FcValueListAlign    *ea;
350     FcValueListEnt  *e;
351     FcValueListPtr  l;
352     FcValueList     *new;
353     int             n;
354     int             size;
355
356     n = 0;
357     for (l = h; FcValueListPtrU(l); l = FcValueListPtrU(l)->next)
358         n++;
359     size = sizeof (FcValueListAlign) + n * sizeof (FcValueList);
360     FcValueListFrozenCount[FcValueListPtrU(h)->value.type]++;
361     FcValueListFrozenBytes[FcValueListPtrU(h)->value.type] += size;
362     // this leaks for some reason
363     ea = malloc (sizeof (FcValueListAlign));
364     if (!ea)
365         return 0;
366     new = malloc (n * sizeof (FcValueList));
367     if (!new)
368         return 0;
369     memset(new, 0, n * sizeof (FcValueList));
370     FcMemAlloc (FC_MEM_VALLIST, size);
371     e = &ea->ent;
372     e->list = (FcValueListPtr) FcValueListPtrCreateDynamic(new);
373     for (l = h; FcValueListPtrU(l); 
374          l = FcValueListPtrU(l)->next, new++)
375     {
376         if (FcValueListPtrU(l)->value.type == FcTypeString)
377         {
378             new->value.type = FcTypeString;
379             new->value.u.si = FcObjectStaticName
380                 (FcObjectPtrU(FcValueListPtrU(l)->value.u.si));
381         }
382         else
383         {
384             new->value = FcValueSave (FcValueListPtrU(l)->value);
385         }
386         new->binding = FcValueListPtrU(l)->binding;
387         if (FcValueListPtrU(FcValueListPtrU(l)->next))
388         {
389             new->next = FcValueListPtrCreateDynamic(new + 1);
390         }
391         else
392         {
393             new->next = FcValueListPtrCreateDynamic(0);
394         }
395     }
396     return e;
397 }
398
399 static void
400 FcValueListEntDestroy (FcValueListEnt *e)
401 {
402     FcValueListPtr      l;
403
404     FcValueListFrozenCount[FcValueListPtrU(e->list)->value.type]--;
405
406     /* XXX: We should perform these two operations with "size" as
407        computed in FcValueListEntCreate, but we don't have access to
408        that value here. Without this, the FcValueListFrozenBytes
409        values will be wrong as will the FcMemFree counts.
410
411        FcValueListFrozenBytes[e->list->value.type] -= size;
412        FcMemFree (FC_MEM_VALLIST, size);
413     */
414
415     for (l = e->list; FcValueListPtrU(l); 
416          l = FcValueListPtrU(l)->next)
417     {
418         if (FcValueListPtrU(l)->value.type != FcTypeString)
419             FcValueDestroy (FcValueListPtrU(l)->value);
420     }
421     /* XXX: Are we being too chummy with the implementation here to
422        free(e) when it was actually the enclosing FcValueListAlign
423        that was allocated? */
424     free (e);
425 }
426
427 static int      FcValueListTotal;
428 static int      FcValueListUsed;
429
430 static FcValueListEnt   *FcValueListHashTable[FC_VALUE_LIST_HASH_SIZE];
431
432 static FcValueListPtr
433 FcValueListFreeze (FcValueListPtr l)
434 {
435     FcChar32                hash = FcValueListHash (l);
436     FcValueListEnt          **bucket = &FcValueListHashTable[hash % FC_VALUE_LIST_HASH_SIZE];
437     FcValueListEnt          *ent;
438
439     FcValueListTotal++;
440     for (ent = *bucket; ent; ent = ent->next)
441     {
442         if (ent->hash == hash && FcValueListEqual (ent->list, l))
443             return ent->list;
444     }
445
446     ent = FcValueListEntCreate (l);
447     if (!ent)
448         return FcValueListPtrCreateDynamic(0);
449
450     FcValueListUsed++;
451     ent->hash = hash;
452     ent->next = *bucket;
453     *bucket = ent;
454     return ent->list;
455 }
456
457 static void
458 FcValueListThawAll (void)
459 {
460     int i;
461     FcValueListEnt      *ent, *next;
462
463     for (i = 0; i < FC_VALUE_LIST_HASH_SIZE; i++)
464     {
465         for (ent = FcValueListHashTable[i]; ent; ent = next)
466         {
467             next = ent->next;
468             FcValueListEntDestroy (ent);
469         }
470         FcValueListHashTable[i] = 0;
471     }
472
473     FcValueListTotal = 0;
474     FcValueListUsed = 0;
475 }
476
477 static FcChar32
478 FcPatternBaseHash (FcPattern *b)
479 {
480     FcChar32    hash = b->num;
481     int         i;
482
483     for (i = 0; i < b->num; i++)
484         hash = ((hash << 1) | (hash >> 31)) ^ 
485             (long) (FcValueListPtrU((FcPatternEltU(b->elts)+i)->values));
486     return hash;
487 }
488
489 typedef struct _FcPatternEnt FcPatternEnt;
490
491 struct _FcPatternEnt {
492     FcPatternEnt    *next;
493     FcChar32        hash;
494     FcPattern       *pattern;
495 };
496
497 static int      FcPatternTotal;
498 static int      FcPatternUsed;
499
500 static FcPatternEnt     *FcPatternHashTable[FC_VALUE_LIST_HASH_SIZE];
501
502 static FcPattern *
503 FcPatternBaseFreeze (FcPattern *b)
504 {
505     FcPattern           *ep;
506     FcPatternElt        *epp;
507     FcChar32            hash = FcPatternBaseHash (b);
508     FcPatternEnt        **bucket = &FcPatternHashTable[hash % FC_VALUE_LIST_HASH_SIZE];
509     FcPatternEnt        *ent;
510     int                 i;
511
512     FcPatternTotal++;
513     for (ent = *bucket; ent; ent = ent->next)
514     {
515         if (ent->hash == hash && b->num == ent->pattern->num)
516         {
517             for (i = 0; i < b->num; i++)
518             {
519                 if (FcObjectPtrCompare((FcPatternEltU(b->elts)+i)->object,
520                                        (FcPatternEltU(ent->pattern->elts)+i)->object) != 0)
521                     break;
522                 if (FcValueListPtrU((FcPatternEltU(b->elts)+i)->values) != 
523                     FcValueListPtrU((FcPatternEltU(ent->pattern->elts)+i)->values))
524                     break;
525             }
526             if (i == b->num)
527                 return ent->pattern;
528         }
529     }
530
531     /*
532      * Compute size of pattern + elts
533      */
534     ent = malloc (sizeof (FcPatternEnt));
535     if (!ent)
536         return 0;
537
538     FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPatternEnt));
539     FcPatternUsed++;
540
541     ep = FcPatternCreate();
542     if (!ep)
543         return 0;
544     ent->pattern = ep;
545     epp = malloc(b->num * sizeof (FcPatternElt));
546     if (!epp)
547         goto bail;
548     ep->elts = FcPatternEltPtrCreateDynamic(epp);
549
550     FcMemAlloc (FC_MEM_PATELT, sizeof (FcPatternElt)*(b->num));
551
552     ep->num = b->num;
553     ep->size = b->num;
554     ep->ref = FC_REF_CONSTANT;
555
556     for (i = 0; i < b->num; i++)
557     {
558         (FcPatternEltU(ep->elts)+i)->values = 
559             (FcPatternEltU(b->elts)+i)->values;
560         (FcPatternEltU(ep->elts)+i)->object = 
561             (FcPatternEltU(b->elts)+i)->object;
562     }
563
564     ent->hash = hash;
565     ent->next = *bucket;
566     *bucket = ent;
567     return ent->pattern;
568  bail:
569     free(ent);
570     FcMemFree (FC_MEM_PATTERN, sizeof (FcPatternEnt));
571     FcPatternUsed--;
572     return 0;
573 }
574
575 static void
576 FcPatternBaseThawAll (void)
577 {
578     int i;
579     FcPatternEnt        *ent, *next;
580
581     for (i = 0; i < FC_VALUE_LIST_HASH_SIZE; i++)
582     {
583         for (ent = FcPatternHashTable[i]; ent; ent = next)
584         {
585             next = ent->next;
586             free (ent);
587         }
588         FcPatternHashTable[i] = 0;
589     }
590
591     FcPatternTotal = 0;
592     FcPatternUsed = 0;
593 }
594
595 FcPattern *
596 FcPatternFreeze (FcPattern *p)
597 {
598     FcPattern   *b, *n = 0;
599     FcPatternElt *e;
600     int         i;
601     
602     if (p->ref == FC_REF_CONSTANT)
603        return p;
604
605     b = FcPatternCreate();
606     if (!b)
607         return 0;
608
609     b->num = p->num;
610     b->size = b->num;
611     b->ref = 1;
612
613     e = malloc(b->num * sizeof (FcPatternElt));
614     if (!e)
615         return 0;
616     b->elts = FcPatternEltPtrCreateDynamic(e);
617     FcMemAlloc (FC_MEM_PATELT, sizeof (FcPatternElt)*(b->num));
618
619     /*
620      * Freeze object lists
621      */
622     for (i = 0; i < p->num; i++)
623     {
624         (FcPatternEltU(b->elts)+i)->object = 
625             (FcPatternEltU(p->elts)+i)->object;
626         (FcPatternEltU(b->elts)+i)->values = 
627             FcValueListFreeze((FcPatternEltU(p->elts)+i)->values);
628         if (!FcValueListPtrU((FcPatternEltU(p->elts)+i)->values))
629             goto bail;
630     }
631     /*
632      * Freeze base
633      */
634     n = FcPatternBaseFreeze (b);
635 #ifdef CHATTY
636     if (FcDebug() & FC_DBG_MEMORY)
637     {
638         printf ("ValueLists: total %9d used %9d\n", FcValueListTotal, FcValueListUsed);
639         printf ("Patterns:   total %9d used %9d\n", FcPatternTotal, FcPatternUsed);
640     }
641 #endif
642  bail:
643     free(FcPatternEltU(b->elts));
644     b->elts = FcPatternEltPtrCreateDynamic(0);
645     FcMemFree (FC_MEM_PATELT, sizeof (FcPatternElt)*(b->num));
646     b->num = -1;
647 #ifdef DEBUG
648     assert (FcPatternEqual (n, p));
649 #endif
650     return n;
651 }
652
653 static int
654 FcPatternPosition (const FcPattern *p, const char *object)
655 {
656     int     low, high, mid, c;
657     FcObjectPtr obj;
658
659     obj = FcObjectStaticName(object);
660     low = 0;
661     high = p->num - 1;
662     c = 1;
663     mid = 0;
664     while (low <= high)
665     {
666         mid = (low + high) >> 1;
667         c = FcObjectPtrCompare((FcPatternEltU(p->elts)+mid)->object, obj);
668         if (c == 0)
669             return mid;
670         if (c < 0)
671             low = mid + 1;
672         else
673             high = mid - 1;
674     }
675     if (c < 0)
676         mid++;
677     return -(mid + 1);
678 }
679
680 FcPatternElt *
681 FcPatternFindElt (const FcPattern *p, const char *object)
682 {
683     int     i = FcPatternPosition (p, object);
684     if (i < 0)
685         return 0;
686     return FcPatternEltU(p->elts)+i;
687 }
688
689 FcPatternElt *
690 FcPatternInsertElt (FcPattern *p, const char *object)
691 {
692     int             i;
693     FcPatternElt   *e;
694     
695     i = FcPatternPosition (p, object);
696     if (i < 0)
697     {
698         i = -i - 1;
699     
700         /* reallocate array */
701         if (p->num + 1 >= p->size)
702         {
703             int s = p->size + 16;
704             if (FcPatternEltU(p->elts))
705             {
706                 FcPatternElt *e0 = FcPatternEltU(p->elts);
707                 e = (FcPatternElt *) realloc (e0, s * sizeof (FcPatternElt));
708                 if (!e) /* maybe it was mmapped */
709                 {
710                     e = malloc(s * sizeof (FcPatternElt));
711                     if (e)
712                         memcpy(e, e0, p->num * sizeof (FcPatternElt));
713                 }
714             }
715             else
716                 e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
717             if (!e)
718                 return FcFalse;
719             p->elts = FcPatternEltPtrCreateDynamic(e);
720             if (p->size)
721                 FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
722             FcMemAlloc (FC_MEM_PATELT, s * sizeof (FcPatternElt));
723             while (p->size < s)
724             {
725                 (FcPatternEltU(p->elts)+p->size)->object = 0;
726                 (FcPatternEltU(p->elts)+p->size)->values = 
727                     FcValueListPtrCreateDynamic(0);
728                 p->size++;
729             }
730         }
731         
732         /* move elts up */
733         memmove (FcPatternEltU(p->elts) + i + 1,
734                  FcPatternEltU(p->elts) + i,
735                  sizeof (FcPatternElt) *
736                  (p->num - i));
737                  
738         /* bump count */
739         p->num++;
740         
741         (FcPatternEltU(p->elts)+i)->object = FcObjectStaticName (object);
742         (FcPatternEltU(p->elts)+i)->values = FcValueListPtrCreateDynamic(0);
743     }
744     
745     return FcPatternEltU(p->elts)+i;
746 }
747
748 FcBool
749 FcPatternEqual (const FcPattern *pa, const FcPattern *pb)
750 {
751     int i;
752
753     if (pa == pb)
754         return FcTrue;
755
756     if (pa->num != pb->num)
757         return FcFalse;
758     for (i = 0; i < pa->num; i++)
759     {
760         if (FcObjectPtrCompare((FcPatternEltU(pa->elts)+i)->object,
761                                (FcPatternEltU(pb->elts)+i)->object) != 0)
762             return FcFalse;
763         if (!FcValueListEqual ((FcPatternEltU(pa->elts)+i)->values, 
764                                (FcPatternEltU(pb->elts)+i)->values))
765             return FcFalse;
766     }
767     return FcTrue;
768 }
769
770 FcChar32
771 FcPatternHash (const FcPattern *p)
772 {
773     int         i;
774     FcChar32    h = 0;
775
776     for (i = 0; i < p->num; i++)
777     {
778         h = (((h << 1) | (h >> 31)) ^ 
779              FcStringHash ((const FcChar8 *) FcObjectPtrU(((FcPatternEltU(p->elts)+i)->object))) ^
780              FcValueListHash ((FcPatternEltU(p->elts)+i)->values));
781     }
782     return h;
783 }
784
785 FcBool
786 FcPatternEqualSubset (const FcPattern *pai, const FcPattern *pbi, const FcObjectSet *os)
787 {
788     FcPatternElt    *ea, *eb;
789     int             i;
790     
791     for (i = 0; i < os->nobject; i++)
792     {
793         ea = FcPatternFindElt (pai, FcObjectPtrU(os->objects[i]));
794         eb = FcPatternFindElt (pbi, FcObjectPtrU(os->objects[i]));
795         if (ea)
796         {
797             if (!eb)
798                 return FcFalse;
799             if (!FcValueListEqual (ea->values, eb->values))
800                 return FcFalse;
801         }
802         else
803         {
804             if (eb)
805                 return FcFalse;
806         }
807     }
808     return FcTrue;
809 }
810
811 FcBool
812 FcPatternAddWithBinding  (FcPattern         *p,
813                           const char        *object,
814                           FcValue           value,
815                           FcValueBinding    binding,
816                           FcBool            append)
817 {
818     FcPatternElt   *e;
819     FcValueListPtr new, *prev;
820     FcValueList *  newp;
821
822     if (p->ref == FC_REF_CONSTANT)
823         goto bail0;
824
825     newp = malloc (sizeof (FcValueList));
826     if (!newp)
827         goto bail0;
828
829     memset(newp, 0, sizeof (FcValueList));
830     new = FcValueListPtrCreateDynamic(newp);
831     FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
832     /* dup string */
833     value = FcValueSave (value);
834     if (value.type == FcTypeVoid)
835         goto bail1;
836
837     FcValueListPtrU(new)->value = value;
838     FcValueListPtrU(new)->binding = binding;
839     FcValueListPtrU(new)->next = FcValueListPtrCreateDynamic(0);
840     
841     e = FcPatternInsertElt (p, object);
842     if (!e)
843         goto bail2;
844     
845     if (append)
846     {
847         for (prev = &e->values; FcValueListPtrU(*prev); prev = &FcValueListPtrU(*prev)->next)
848             ;
849         *prev = new;
850     }
851     else
852     {
853         FcValueListPtrU(new)->next = e->values;
854         e->values = new;
855     }
856     
857     return FcTrue;
858
859 bail2:    
860     switch (value.type) {
861     case FcTypeString:
862         FcStrFree ((FcChar8 *) FcObjectPtrU(value.u.si));
863         break;
864     case FcTypeMatrix:
865         FcMatrixFree (FcMatrixPtrU(value.u.mi));
866         break;
867     case FcTypeCharSet:
868         FcCharSetDestroy (FcCharSetPtrU(value.u.ci));
869         break;
870     case FcTypeLangSet:
871         FcLangSetDestroy (FcLangSetPtrU(value.u.li));
872         break;
873     default:
874         break;
875     }
876 bail1:
877     FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
878     free (FcValueListPtrU(new));
879 bail0:
880     return FcFalse;
881 }
882
883 FcBool
884 FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
885 {
886     return FcPatternAddWithBinding (p, object, value, FcValueBindingStrong, append);
887 }
888
889 FcBool
890 FcPatternAddWeak  (FcPattern *p, const char *object, FcValue value, FcBool append)
891 {
892     return FcPatternAddWithBinding (p, object, value, FcValueBindingWeak, append);
893 }
894
895 FcBool
896 FcPatternDel (FcPattern *p, const char *object)
897 {
898     FcPatternElt   *e;
899
900     e = FcPatternFindElt (p, object);
901     if (!e)
902         return FcFalse;
903
904     /* destroy value */
905     FcValueListDestroy (e->values);
906     
907     /* shuffle existing ones down */
908     memmove (e, e+1, 
909              (FcPatternEltU(p->elts) + p->num - (e + 1)) * 
910              sizeof (FcPatternElt));
911     p->num--;
912     (FcPatternEltU(p->elts)+p->num)->object = 0;
913     (FcPatternEltU(p->elts)+p->num)->values = FcValueListPtrCreateDynamic(0);
914     return FcTrue;
915 }
916
917 FcBool
918 FcPatternRemove (FcPattern *p, const char *object, int id)
919 {
920     FcPatternElt    *e;
921     FcValueListPtr  *prev, l;
922
923     e = FcPatternFindElt (p, object);
924     if (!e)
925         return FcFalse;
926     for (prev = &e->values; 
927          FcValueListPtrU(l = *prev); 
928          prev = &FcValueListPtrU(l)->next)
929     {
930         if (!id)
931         {
932             *prev = FcValueListPtrU(l)->next;
933             FcValueListPtrU(l)->next = FcValueListPtrCreateDynamic(0);
934             FcValueListDestroy (l);
935             if (!FcValueListPtrU(e->values))
936                 FcPatternDel (p, object);
937             return FcTrue;
938         }
939         id--;
940     }
941     return FcFalse;
942 }
943
944 FcBool
945 FcPatternAddInteger (FcPattern *p, const char *object, int i)
946 {
947     FcValue     v;
948
949     v.type = FcTypeInteger;
950     v.u.i = i;
951     return FcPatternAdd (p, object, v, FcTrue);
952 }
953
954 FcBool
955 FcPatternAddDouble (FcPattern *p, const char *object, double d)
956 {
957     FcValue     v;
958
959     v.type = FcTypeDouble;
960     v.u.d = d;
961     return FcPatternAdd (p, object, v, FcTrue);
962 }
963
964
965 FcBool
966 FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
967 {
968     FcValue     v;
969
970     v.type = FcTypeString;
971     v.u.si = FcObjectStaticName(s);
972     return FcPatternAdd (p, object, v, FcTrue);
973 }
974
975 FcBool
976 FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
977 {
978     FcValue     v;
979
980     v.type = FcTypeMatrix;
981     v.u.mi = FcMatrixPtrCreateDynamic((FcMatrix *) s);
982     return FcPatternAdd (p, object, v, FcTrue);
983 }
984
985
986 FcBool
987 FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
988 {
989     FcValue     v;
990
991     v.type = FcTypeBool;
992     v.u.b = b;
993     return FcPatternAdd (p, object, v, FcTrue);
994 }
995
996 FcBool
997 FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
998 {
999     FcValue     v;
1000
1001     v.type = FcTypeCharSet;
1002     v.u.ci = FcCharSetPtrCreateDynamic((FcCharSet *)c);
1003     return FcPatternAdd (p, object, v, FcTrue);
1004 }
1005
1006 FcBool
1007 FcPatternAddFTFace (FcPattern *p, const char *object, const FT_Face f)
1008 {
1009     FcValue     v;
1010
1011     v.type = FcTypeFTFace;
1012     v.u.f = (void *) f;
1013     return FcPatternAdd (p, object, v, FcTrue);
1014 }
1015
1016 FcBool
1017 FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls)
1018 {
1019     FcValue     v;
1020
1021     v.type = FcTypeLangSet;
1022     v.u.li = FcLangSetPtrCreateDynamic((FcLangSet *)ls);
1023     return FcPatternAdd (p, object, v, FcTrue);
1024 }
1025
1026 FcResult
1027 FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v)
1028 {
1029     FcPatternElt   *e;
1030     FcValueListPtr l;
1031
1032     e = FcPatternFindElt (p, object);
1033     if (!e)
1034         return FcResultNoMatch;
1035     for (l = e->values; FcValueListPtrU(l); l = FcValueListPtrU(l)->next)
1036     {
1037         if (!id)
1038         {
1039             *v = FcValueListPtrU(l)->value;
1040             return FcResultMatch;
1041         }
1042         id--;
1043     }
1044     return FcResultNoId;
1045 }
1046
1047 FcResult
1048 FcPatternGetInteger (const FcPattern *p, const char *object, int id, int *i)
1049 {
1050     FcValue     v;
1051     FcResult    r;
1052
1053     r = FcPatternGet (p, object, id, &v);
1054     if (r != FcResultMatch)
1055         return r;
1056     switch (v.type) {
1057     case FcTypeDouble:
1058         *i = (int) v.u.d;
1059         break;
1060     case FcTypeInteger:
1061         *i = v.u.i;
1062         break;
1063     default:
1064         return FcResultTypeMismatch;
1065     }
1066     return FcResultMatch;
1067 }
1068
1069 FcResult
1070 FcPatternGetDouble (const FcPattern *p, const char *object, int id, double *d)
1071 {
1072     FcValue     v;
1073     FcResult    r;
1074
1075     r = FcPatternGet (p, object, id, &v);
1076     if (r != FcResultMatch)
1077         return r;
1078     switch (v.type) {
1079     case FcTypeDouble:
1080         *d = v.u.d;
1081         break;
1082     case FcTypeInteger:
1083         *d = (double) v.u.i;
1084         break;
1085     default:
1086         return FcResultTypeMismatch;
1087     }
1088     return FcResultMatch;
1089 }
1090
1091 FcResult
1092 FcPatternGetString (const FcPattern *p, const char *object, int id, FcChar8 ** s)
1093 {
1094     FcValue     v;
1095     FcResult    r;
1096
1097     r = FcPatternGet (p, object, id, &v);
1098     if (r != FcResultMatch)
1099         return r;
1100     if (v.type != FcTypeString)
1101         return FcResultTypeMismatch;
1102     *s = (FcChar8 *) FcObjectPtrU(v.u.si);
1103     return FcResultMatch;
1104 }
1105
1106 FcResult
1107 FcPatternGetMatrix(const FcPattern *p, const char *object, int id, FcMatrix **m)
1108 {
1109     FcValue     v;
1110     FcResult    r;
1111
1112     r = FcPatternGet (p, object, id, &v);
1113     if (r != FcResultMatch)
1114         return r;
1115     if (v.type != FcTypeMatrix)
1116         return FcResultTypeMismatch;
1117     *m = FcMatrixPtrU(v.u.mi);
1118     return FcResultMatch;
1119 }
1120
1121
1122 FcResult
1123 FcPatternGetBool(const FcPattern *p, const char *object, int id, FcBool *b)
1124 {
1125     FcValue     v;
1126     FcResult    r;
1127
1128     r = FcPatternGet (p, object, id, &v);
1129     if (r != FcResultMatch)
1130         return r;
1131     if (v.type != FcTypeBool)
1132         return FcResultTypeMismatch;
1133     *b = v.u.b;
1134     return FcResultMatch;
1135 }
1136
1137 FcResult
1138 FcPatternGetCharSet(const FcPattern *p, const char *object, int id, FcCharSet **c)
1139 {
1140     FcValue     v;
1141     FcResult    r;
1142
1143     r = FcPatternGet (p, object, id, &v);
1144     if (r != FcResultMatch)
1145         return r;
1146     if (v.type != FcTypeCharSet)
1147         return FcResultTypeMismatch;
1148     *c = FcCharSetPtrU(v.u.ci);
1149     return FcResultMatch;
1150 }
1151
1152 FcResult
1153 FcPatternGetFTFace(const FcPattern *p, const char *object, int id, FT_Face *f)
1154 {
1155     FcValue     v;
1156     FcResult    r;
1157
1158     r = FcPatternGet (p, object, id, &v);
1159     if (r != FcResultMatch)
1160         return r;
1161     if (v.type != FcTypeFTFace)
1162         return FcResultTypeMismatch;
1163     *f = (FT_Face) v.u.f;
1164     return FcResultMatch;
1165 }
1166
1167 FcResult
1168 FcPatternGetLangSet(const FcPattern *p, const char *object, int id, FcLangSet **ls)
1169 {
1170     FcValue     v;
1171     FcResult    r;
1172
1173     r = FcPatternGet (p, object, id, &v);
1174     if (r != FcResultMatch)
1175         return r;
1176     if (v.type != FcTypeLangSet)
1177         return FcResultTypeMismatch;
1178     *ls = FcLangSetPtrU(v.u.li);
1179     return FcResultMatch;
1180 }
1181
1182 FcPattern *
1183 FcPatternDuplicate (const FcPattern *orig)
1184 {
1185     FcPattern       *new;
1186     FcPatternElt    *e;
1187     int             i;
1188     FcValueListPtr  l;
1189
1190     new = FcPatternCreate ();
1191     if (!new)
1192         goto bail0;
1193
1194     e = FcPatternEltU(orig->elts);
1195
1196     for (i = 0; i < orig->num; i++)
1197     {
1198         for (l = (e + i)->values; 
1199              FcValueListPtrU(l); 
1200              l = FcValueListPtrU(l)->next)
1201             if (!FcPatternAdd (new, FcObjectPtrU((e + i)->object), 
1202                                FcValueListPtrU(l)->value, FcTrue))
1203                 goto bail1;
1204     }
1205
1206     return new;
1207
1208 bail1:
1209     FcPatternDestroy (new);
1210 bail0:
1211     return 0;
1212 }
1213
1214 void
1215 FcPatternReference (FcPattern *p)
1216 {
1217     if (p->ref != FC_REF_CONSTANT)
1218         p->ref++;
1219 }
1220
1221 FcPattern *
1222 FcPatternVaBuild (FcPattern *orig, va_list va)
1223 {
1224     FcPattern   *ret;
1225     
1226     FcPatternVapBuild (ret, orig, va);
1227     return ret;
1228 }
1229
1230 FcPattern *
1231 FcPatternBuild (FcPattern *orig, ...)
1232 {
1233     va_list     va;
1234     
1235     va_start (va, orig);
1236     FcPatternVapBuild (orig, orig, va);
1237     va_end (va);
1238     return orig;
1239 }
1240
1241 /*
1242  * Add all of the elements in 's' to 'p'
1243  */
1244 FcBool
1245 FcPatternAppend (FcPattern *p, FcPattern *s)
1246 {
1247     int             i;
1248     FcPatternElt    *e;
1249     FcValueListPtr  v;
1250     
1251     for (i = 0; i < s->num; i++)
1252     {
1253         e = FcPatternEltU(s->elts)+i;
1254         for (v = e->values; FcValueListPtrU(v); 
1255              v = FcValueListPtrU(v)->next)
1256         {
1257             if (!FcPatternAddWithBinding (p, FcObjectPtrU(e->object),
1258                                           FcValueListPtrU(v)->value, 
1259                                           FcValueListPtrU(v)->binding, FcTrue))
1260                 return FcFalse;
1261         }
1262     }
1263     return FcTrue;
1264 }
1265
1266 FcPatternElt *
1267 FcPatternEltU (FcPatternEltPtr pei)
1268 {
1269     switch (pei.storage)
1270     {
1271     case FcStorageStatic:
1272         return &fcpatternelts[pei.u.stat];
1273     case FcStorageDynamic:
1274         return pei.u.dyn;
1275     default:
1276         return 0;
1277     }
1278 }
1279
1280 static FcPatternEltPtr
1281 FcPatternEltPtrCreateDynamic (FcPatternElt * e)
1282 {
1283     FcPatternEltPtr new;
1284     new.storage = FcStorageDynamic;
1285     new.u.dyn = e;
1286     return new;
1287 }
1288
1289 static FcPatternEltPtr
1290 FcPatternEltPtrCreateStatic (int i)
1291 {
1292     FcPatternEltPtr new;
1293     new.storage = FcStorageStatic;
1294     new.u.stat = i;
1295     return new;
1296 }
1297
1298 static FcBool
1299 FcPatternEltIsDynamic (FcPatternEltPtr pei)
1300 {
1301     return pei.storage == FcStorageDynamic;
1302 }
1303
1304
1305 void
1306 FcPatternClearStatic (void)
1307 {
1308     fcpatterns = 0;
1309     fcpattern_ptr = 0;
1310     fcpattern_count = 0;
1311
1312     fcpatternelts = 0;
1313     fcpatternelt_ptr = 0;
1314     fcpatternelt_count = 0;
1315 }
1316
1317 void
1318 FcValueListClearStatic (void)
1319 {
1320     fcvaluelists = 0;
1321     fcvaluelist_ptr = 0;
1322     fcvaluelist_count = 0;
1323 }
1324
1325 static FcBool
1326 FcObjectPrepareSerialize (FcObjectPtr si);
1327 static FcObjectPtr
1328 FcObjectSerialize (FcObjectPtr si);
1329
1330 FcBool
1331 FcPatternPrepareSerialize (FcPattern * p)
1332 {
1333     int i;
1334
1335     fcpattern_count++;
1336     fcpatternelt_count += p->num;
1337
1338     for (i = 0; i < p->num; i++)
1339     {
1340         FcObjectPrepareSerialize 
1341             ((FcPatternEltU(p->elts)+i)->object);
1342         if (!FcValueListPrepareSerialize 
1343             (FcValueListPtrU(((FcPatternEltU(p->elts)+i)->values))))
1344             return FcFalse;
1345     }
1346
1347     return FcTrue;
1348 }
1349
1350 FcBool
1351 FcValueListPrepareSerialize (FcValueList *p)
1352 {
1353     FcValueList *vl;
1354
1355     for (vl = p;
1356          vl; 
1357          vl = FcValueListPtrU(vl->next))
1358     {
1359         FcValue v = vl->value;
1360
1361         switch (v.type)
1362         {
1363         case FcTypeMatrix:
1364             FcMatrixPrepareSerialize(FcMatrixPtrU(v.u.mi));
1365             break;
1366         case FcTypeCharSet:
1367             FcCharSetPrepareSerialize(FcCharSetPtrU(v.u.ci));
1368             break;
1369         case FcTypeLangSet:
1370             FcLangSetPrepareSerialize(FcLangSetPtrU(v.u.li));
1371             break;
1372         case FcTypeString:
1373             FcObjectPrepareSerialize(v.u.si);
1374         default:
1375             break;
1376         }
1377         fcvaluelist_count++;
1378     }
1379     
1380     return FcTrue;
1381 }
1382
1383 FcPattern *
1384 FcPatternSerialize (FcPattern *old)
1385 {
1386     FcPattern *p;
1387     FcPatternElt *e, *nep;
1388     FcValueList * nv;
1389     FcValueListPtr v, nv_head, nvp;
1390     int i, elts;
1391
1392     if (!fcpatterns)
1393     {
1394         p = malloc (sizeof (FcPattern) * fcpattern_count);
1395         if (!p)
1396             goto bail;
1397
1398         FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern) * fcpattern_count);
1399         fcpatterns = p;
1400         fcpattern_ptr = 0;
1401
1402         e = malloc (sizeof (FcPatternElt) * fcpatternelt_count);
1403         if (!e)
1404             goto bail1;
1405
1406         FcMemAlloc (FC_MEM_PATELT, sizeof (FcPatternElt) * fcpatternelt_count);
1407         fcpatternelts = e;
1408         fcpatternelt_ptr = 0;
1409     }
1410
1411     p = &fcpatterns[fcpattern_ptr++];
1412     elts = fcpatternelt_ptr;
1413     nep = &fcpatternelts[elts];
1414     if (!nep)
1415         return FcFalse;
1416
1417     fcpatternelt_ptr += old->num;
1418
1419     for (e = FcPatternEltU(old->elts), i=0; i < old->num; i++, e++) 
1420     {
1421         v = e->values;
1422         nvp = nv_head = FcValueListSerialize(FcValueListPtrU(v));
1423         if (!FcValueListPtrU(nv_head))
1424             goto bail2;
1425         nv = FcValueListPtrU(nvp);
1426         
1427         for (;
1428              FcValueListPtrU(v);
1429              v = FcValueListPtrU(v)->next, 
1430                  nv = FcValueListPtrU(nv->next))
1431         {
1432             
1433             if (FcValueListPtrU(FcValueListPtrU(v)->next))
1434             {
1435                 nvp = FcValueListSerialize
1436                     (FcValueListPtrU(FcValueListPtrU(v)->next));
1437                 nv->next = nvp;
1438             }
1439         }
1440         
1441         nep[i].values = nv_head;
1442         nep[i].object = FcObjectSerialize (e->object);
1443     }
1444
1445     p->elts = old->elts;
1446     p->elts = FcPatternEltPtrCreateStatic(elts);
1447     p->size = old->num;
1448     p->num = old->num;
1449     p->ref = FC_REF_CONSTANT;
1450     return p;
1451     
1452  bail2:
1453     free (fcpatternelts);
1454  bail1:
1455     free (fcpatterns);
1456  bail:
1457     return 0;
1458 }
1459
1460 FcBool
1461 FcPatternRead (int fd, FcCache metadata)
1462 {
1463     fcpatterns = mmap(NULL, 
1464                       metadata.pattern_length * sizeof (FcPattern),
1465                       PROT_READ,
1466                       MAP_SHARED, fd, metadata.pattern_offset);
1467     if (fcpatterns == MAP_FAILED)
1468         return FcFalse;
1469     fcpattern_count = fcpattern_ptr = metadata.pattern_length;
1470
1471     return FcTrue;
1472 }
1473
1474 FcBool
1475 FcPatternWrite (int fd, FcCache *metadata)
1476 {
1477     int c = fcpattern_ptr;
1478     off_t w = FcCacheNextOffset(fd);
1479
1480     metadata->pattern_offset = w;
1481     metadata->pattern_length = c;
1482
1483     if (c > 0)
1484     {
1485         lseek(fd, w, SEEK_SET);
1486         return write(fd, fcpatterns, c*sizeof(FcPattern)) != -1;
1487     }
1488     return FcTrue;
1489 }
1490
1491 FcBool
1492 FcPatternEltRead (int fd, FcCache metadata)
1493 {
1494     fcpatternelts = mmap(NULL, 
1495                          metadata.patternelt_length * sizeof (FcPatternElt),
1496                          PROT_READ,
1497                          MAP_SHARED, fd, metadata.patternelt_offset);
1498     if (fcpatternelts == MAP_FAILED)
1499         return FcFalse;
1500     fcpatternelt_count = fcpatternelt_ptr = metadata.patternelt_length;
1501
1502     return FcTrue;
1503 }
1504
1505 FcBool
1506 FcPatternEltWrite (int fd, FcCache *metadata)
1507 {
1508     int c = fcpatternelt_ptr;
1509     off_t w = FcCacheNextOffset(fd);
1510
1511     metadata->patternelt_offset = w;
1512     metadata->patternelt_length = c;
1513
1514     if (c > 0)
1515     {
1516         lseek(fd, w, SEEK_SET);
1517         return write(fd, fcpatternelts, c*sizeof(FcPatternElt)) != -1;
1518     }
1519     return FcTrue;
1520 }
1521
1522 FcValueListPtr
1523 FcValueListSerialize(FcValueList *pi)
1524 {
1525     FcValueListPtr new; 
1526     FcValue * v;
1527     FcValueList * vl;
1528
1529     if (!fcvaluelists)
1530     {
1531         vl = malloc (sizeof (FcValueList) * fcvaluelist_count);
1532         if (!vl)
1533             return FcValueListPtrCreateDynamic(0);
1534
1535         FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList) * fcvaluelist_count);
1536         fcvaluelists = vl;
1537         fcvaluelist_ptr = 0;
1538     }
1539
1540     fcvaluelists[fcvaluelist_ptr] = *pi;
1541     new.storage = FcStorageStatic;
1542     new.u.stat = fcvaluelist_ptr++;
1543     v = &fcvaluelists[new.u.stat].value;
1544     switch (v->type)
1545     {
1546     case FcTypeString:
1547         /* this departs from the usual convention of dereferencing
1548          * foo before serialization; FcObjectSerialize does the
1549          * translation itself. */
1550         /* also, v->u.si is 0 iff the string is null. */
1551         /* also, have to update the old pi */
1552         if (v->u.si)
1553         {
1554             FcObjectPtr si = FcObjectSerialize(v->u.si);
1555             if (!FcObjectPtrU(si))
1556                 return FcValueListPtrCreateDynamic(pi);
1557             v->u.si = si;
1558             pi->value.u.si = si;
1559         }
1560         break;
1561     case FcTypeMatrix:
1562         if (FcMatrixPtrU(v->u.mi))
1563         {
1564             FcMatrixPtr mi = FcMatrixSerialize(FcMatrixPtrU(v->u.mi));
1565
1566             if (!FcMatrixPtrU(mi))
1567                 return FcValueListPtrCreateDynamic(pi);
1568             v->u.mi = mi;
1569         }
1570         break;
1571     case FcTypeCharSet:
1572         if (FcCharSetPtrU(v->u.ci))
1573         {
1574             FcCharSetPtr ci = FcCharSetSerialize(FcCharSetPtrU(v->u.ci));
1575             if (!FcCharSetPtrU(ci))
1576                 return FcValueListPtrCreateDynamic(pi);
1577             v->u.ci = ci;
1578         }
1579         break;
1580     case FcTypeLangSet:
1581         if (FcLangSetPtrU(v->u.li))
1582         {
1583             FcLangSetPtr li = FcLangSetSerialize(FcLangSetPtrU(v->u.li));
1584             if (!FcLangSetPtrU(li))
1585                 return FcValueListPtrCreateDynamic(pi);
1586             v->u.li = li;
1587         }
1588         break;
1589     default:
1590         break;
1591     }
1592     return new;
1593 }
1594
1595 FcBool
1596 FcValueListRead (int fd, FcCache metadata)
1597 {
1598     fcvaluelists = mmap(NULL, 
1599                         metadata.valuelist_length * sizeof (FcValueList),
1600                         PROT_READ,
1601                         MAP_SHARED, fd, metadata.valuelist_offset);
1602     if (fcvaluelists == MAP_FAILED)
1603         return FcFalse;
1604     fcvaluelist_count = fcvaluelist_ptr = metadata.valuelist_length;
1605
1606     return FcTrue;
1607 }
1608
1609 FcBool
1610 FcValueListWrite (int fd, FcCache *metadata)
1611 {
1612     metadata->valuelist_offset = FcCacheNextOffset(fd);
1613     metadata->valuelist_length = fcvaluelist_ptr;
1614
1615     if (fcvaluelist_ptr > 0)
1616     {
1617         lseek(fd, metadata->valuelist_offset, SEEK_SET);
1618         return write(fd, fcvaluelists, 
1619                      fcvaluelist_ptr * sizeof(FcValueList)) != -1;
1620     }
1621     return FcTrue;
1622 }
1623
1624 FcValueList * 
1625 FcValueListPtrU (FcValueListPtr pi)
1626 {
1627     switch (pi.storage)
1628     {
1629     case FcStorageStatic:
1630         return &fcvaluelists[pi.u.stat];
1631     case FcStorageDynamic:
1632         return pi.u.dyn;
1633     default:
1634         return 0;
1635     }
1636 }
1637
1638 FcValueListPtr
1639 FcValueListPtrCreateDynamic(FcValueList * p)
1640 {
1641     FcValueListPtr r; 
1642
1643     r.storage = FcStorageDynamic; 
1644     r.u.dyn = p;
1645     return r;
1646 }
1647
1648 /* Indices allow us to convert dynamic strings into static
1649  * strings without having to reassign IDs.  We do reassign IDs
1650  * when serializing, which effectively performs mark-and-sweep 
1651  * garbage collection. */
1652
1653 /* objectptr_count maps FcObjectPtr to:
1654      + offsets in objectcontent_static_buf (if positive)
1655      - entries in objectcontent_dynamic (if negative)
1656 */
1657 static int objectptr_count = 1;
1658 static int objectptr_alloc = 0;
1659 static int * objectptr_indices = 0;
1660
1661 /* invariant: objectcontent_static_buf must be sorted. */
1662 /* e.g. objectptr_static_buf = "name\0style\0weight\0" */
1663 static int objectcontent_static_bytes = 0;
1664 static char * objectcontent_static_buf;
1665
1666 /* just a bunch of strings. */
1667 static int objectcontent_dynamic_count = 1;
1668 static int objectcontent_dynamic_alloc = 0;
1669 static const char ** objectcontent_dynamic = 0;
1670 static int * objectcontent_dynamic_refcount = 0;
1671
1672 #define OBJECT_HASH_SIZE    31
1673 struct objectBucket {
1674     struct objectBucket *next;
1675     FcChar32            hash;
1676 };
1677 static struct objectBucket **FcObjectBuckets = 0;
1678
1679 FcObjectPtr
1680 FcObjectStaticName (const char *name)
1681 {
1682     FcChar32            hash = FcStringHash ((const FcChar8 *) name);
1683     struct objectBucket **p;
1684     struct objectBucket *b;
1685     const char *        nn;
1686     int                 size;
1687     FcObjectPtr         new;
1688
1689     if (!FcObjectBuckets)
1690     {
1691         FcObjectBuckets = malloc(sizeof (struct objectBucket *)*OBJECT_HASH_SIZE);
1692         memset (FcObjectBuckets, 0, sizeof (struct objectBucket *)*OBJECT_HASH_SIZE);
1693     }
1694
1695     for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
1696     {
1697         FcObjectPtr bp = *((FcObjectPtr *) (b + 1));
1698         if (b->hash == hash && FcObjectPtrU(bp) && !strcmp (name, FcObjectPtrU(bp)))
1699         {
1700             if (objectptr_indices[bp] < 0)
1701                 objectcontent_dynamic_refcount[-objectptr_indices[bp]]++;
1702             return bp;
1703         }
1704     }
1705
1706     /* didn't find it, so add a new dynamic string */
1707     if (objectcontent_dynamic_count >= objectcontent_dynamic_alloc)
1708     {
1709         int s = objectcontent_dynamic_alloc + 4;
1710
1711         const char ** d = realloc (objectcontent_dynamic, 
1712                                    s*sizeof(char *));
1713         if (!d)
1714             return 0;
1715         FcMemFree(FC_MEM_STATICSTR, 
1716                   objectcontent_dynamic_alloc * sizeof(char *));
1717         FcMemAlloc(FC_MEM_STATICSTR, s*sizeof(char *));
1718         objectcontent_dynamic = d;
1719         objectcontent_dynamic_alloc = s;
1720
1721         int * rc = realloc (objectcontent_dynamic_refcount, s*sizeof(int));
1722         if (!rc)
1723             return 0;
1724         FcMemFree(FC_MEM_STATICSTR, 
1725                   objectcontent_dynamic_alloc * sizeof(int));
1726         FcMemAlloc(FC_MEM_STATICSTR, s * sizeof(int));
1727         objectcontent_dynamic_refcount = rc;
1728     }
1729     if (objectptr_count >= objectptr_alloc)
1730     {
1731         int s = objectptr_alloc + 4;
1732         int * d = realloc (objectptr_indices, s*sizeof(int));
1733         if (!d)
1734             return 0;
1735         FcMemFree(FC_MEM_STATICSTR, objectptr_alloc * sizeof(int));
1736         FcMemAlloc(FC_MEM_STATICSTR, s);
1737         objectptr_indices = d;
1738         objectptr_indices[0] = 0;
1739         objectptr_alloc = s;
1740     }
1741
1742     size = sizeof (struct objectBucket) + sizeof (char *);
1743     b = malloc (size);
1744     if (!b)
1745         return 0;
1746     FcMemAlloc (FC_MEM_STATICSTR, size);
1747     b->next = 0;
1748     b->hash = hash;
1749     nn = malloc(strlen(name)+1);
1750     if (!nn)
1751         goto bail;
1752     strcpy ((char *)nn, name);
1753     objectptr_indices[objectptr_count] = -objectcontent_dynamic_count;
1754     objectcontent_dynamic_refcount[objectcontent_dynamic_count] = 1;
1755     objectcontent_dynamic[objectcontent_dynamic_count++] = nn;
1756     new = objectptr_count++;
1757     *((FcObjectPtr *)(b+1)) = new;
1758     *p = b;
1759     return new;
1760
1761  bail:
1762     free(b);
1763     return 0;
1764 }
1765
1766 void
1767 FcObjectPtrDestroy (FcObjectPtr p)
1768 {
1769     if (objectptr_indices[p] < 0)
1770     {
1771         objectcontent_dynamic_refcount[-objectptr_indices[p]]--;
1772         if (objectcontent_dynamic_refcount[-objectptr_indices[p]] == 0)
1773         {
1774             /* this code doesn't seem to be reached terribly often. */
1775             /* (note that objectcontent_dynamic overapproximates 
1776              * the use count, because not every result from
1777              * StaticName is stored. */
1778             FcStrFree((char *)objectcontent_dynamic[-objectptr_indices[p]]);
1779             objectcontent_dynamic[-objectptr_indices[p]] = 0;
1780         }
1781     }
1782 }
1783
1784 const char *
1785 FcObjectPtrU (FcObjectPtr si)
1786 {
1787     if (si == 0)
1788         return 0;
1789
1790     if (objectptr_indices[si] > 0)
1791         return &objectcontent_static_buf[objectptr_indices[si]];
1792     else
1793         return objectcontent_dynamic[-objectptr_indices[si]];
1794 }
1795
1796 static FcBool objectptr_first_serialization = FcFalse;
1797 static int * object_old_id_to_new = 0;
1798
1799 static void 
1800 FcObjectRebuildStaticNameHashtable (void)
1801 {
1802     int i;
1803     struct objectBucket *b, *bn;
1804
1805     if (FcObjectBuckets)
1806     {
1807         for (i = 0; i < OBJECT_HASH_SIZE; i++)
1808         {
1809             b = FcObjectBuckets[i];
1810             while (b)
1811             {
1812                 bn = b->next;
1813                 free(b);
1814                 FcMemFree (FC_MEM_STATICSTR,
1815                            sizeof (struct objectBucket)+sizeof (FcObjectPtr));
1816                 b = bn;
1817             }
1818         }
1819         free (FcObjectBuckets);
1820     }
1821
1822     FcObjectBuckets = malloc(sizeof (struct objectBucket *)*OBJECT_HASH_SIZE);
1823     memset (FcObjectBuckets, 0, sizeof (struct objectBucket *)*OBJECT_HASH_SIZE);
1824
1825     for (i = 1; i < objectptr_count; i++)
1826     {
1827         if (FcObjectPtrU(i))
1828         {
1829             const char * name = FcObjectPtrU(i);
1830             FcChar32     hash = FcStringHash ((const FcChar8 *) name);
1831             struct objectBucket **p;
1832             int size;
1833
1834             for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); 
1835                  p = &(b->next))
1836                 ;
1837             size = sizeof (struct objectBucket) + sizeof (FcObjectPtr);
1838             b = malloc (size);
1839             if (!b)
1840                 return;
1841             FcMemAlloc (FC_MEM_STATICSTR, size);
1842             b->next = 0;
1843             b->hash = hash;
1844             *((FcObjectPtr *)(b+1)) = i;
1845             *p = b;
1846         }
1847     }
1848 }
1849
1850 /* Hmm.  This will have a terrible effect on the memory size,
1851  * because the mmapped strings now get reallocated on the heap. 
1852  * Is it all worth it? (Of course, the Serialization codepath is
1853  * not problematic, because the program quits just afterwards.) */
1854 static FcBool
1855 FcObjectPtrConvertToStatic(FcBool renumber)
1856 {
1857     int active_count, i, j, longest_string = 0, 
1858         new_static_bytes = 1;
1859     char * fixed_length_buf, * new_static_buf, * p;
1860     int * new_indices;
1861
1862     if (renumber)
1863         objectptr_first_serialization = FcFalse;
1864
1865     /* collect statistics */
1866     for (i = 1, active_count = 1; i < objectptr_count; i++)
1867         if (!renumber || object_old_id_to_new[i] == -1)
1868         {
1869             int sl = strlen(FcObjectPtrU(i));
1870             active_count++;
1871             if (sl > longest_string)
1872                 longest_string = sl;
1873             new_static_bytes += sl + 1;
1874         } 
1875
1876     /* allocate storage */
1877     fixed_length_buf = malloc 
1878         ((longest_string+1) * active_count * sizeof(char));
1879     if (!fixed_length_buf)
1880         goto bail;
1881     new_static_buf = malloc (new_static_bytes * sizeof(char));
1882     if (!new_static_buf)
1883         goto bail1;
1884     new_indices = malloc (active_count * sizeof(int));
1885     if (!new_indices)
1886         goto bail2;
1887     new_indices[0] = 0;
1888     new_static_buf[0] = 0;
1889     
1890     FcMemAlloc (FC_MEM_STATICSTR, new_static_bytes);
1891     FcMemFree (FC_MEM_STATICSTR, objectptr_count * sizeof (int));
1892     FcMemAlloc (FC_MEM_STATICSTR, active_count * sizeof (int));
1893     
1894     /* copy strings to temporary buffers */
1895     for (j = 0, i = 1; i < objectptr_count; i++)
1896         if (!renumber || object_old_id_to_new[i] == -1)
1897         {
1898             strcpy (fixed_length_buf+(j*(longest_string+1)), FcObjectPtrU(i));
1899             j++;
1900         }
1901     
1902     /* sort the new statics */
1903     qsort (fixed_length_buf, active_count-1, longest_string+1, 
1904            (int (*)(const void *, const void *)) FcStrCmp);
1905     
1906     /* now we create the new static buffer in sorted order. */
1907     p = new_static_buf+1;
1908     for (i = 0; i < active_count-1; i++)
1909     {
1910         strcpy(p, fixed_length_buf + i * (longest_string+1));
1911         p += strlen(p)+1;
1912     }
1913
1914     /* create translation table by iterating over sorted strings
1915      * and getting their old values */
1916     p = new_static_buf+1;
1917     for (i = 0; i < active_count-1; i++)
1918     {
1919         int n = FcObjectStaticName(fixed_length_buf+i*(longest_string+1));
1920         if (renumber)
1921         {
1922             object_old_id_to_new[n] = i+1;
1923             new_indices[i+1] = p-new_static_buf;
1924         }
1925         else
1926             new_indices[n] = p-new_static_buf;
1927         p += strlen(p)+1;
1928     }
1929
1930     free (objectptr_indices);
1931     objectptr_indices = new_indices;
1932     objectptr_count = active_count;
1933     objectptr_alloc = active_count;
1934
1935     /* free old storage */
1936     for (i = 1; i < objectcontent_dynamic_count; i++)
1937     {
1938         if (objectcontent_dynamic[i])
1939         {
1940             FcMemFree (FC_MEM_STATICSTR, strlen(objectcontent_dynamic[i])+1);
1941             free ((char *)objectcontent_dynamic[i]);
1942         }       
1943     }
1944     free (objectcontent_dynamic);
1945     free (objectcontent_dynamic_refcount);
1946     FcMemFree (FC_MEM_STATICSTR, objectcontent_dynamic_count*sizeof (int));
1947     objectcontent_dynamic = 0;
1948     objectcontent_dynamic_refcount = 0;
1949     objectcontent_dynamic_count = 1;
1950     objectcontent_dynamic_alloc = 0;
1951     free (objectcontent_static_buf);
1952     FcMemFree (FC_MEM_STATICSTR, objectcontent_static_bytes);
1953     objectcontent_static_buf = new_static_buf;
1954     objectcontent_static_bytes = new_static_bytes;
1955
1956     /* fix up hash table */
1957     FcObjectRebuildStaticNameHashtable();
1958
1959     free (fixed_length_buf);
1960     return FcTrue;
1961
1962  bail2: 
1963     free (new_static_buf);
1964  bail1: 
1965     free (fixed_length_buf);
1966  bail:
1967     return FcFalse;
1968 }
1969
1970 #define OBJECT_PTR_CONVERSION_TRIGGER 100000
1971
1972 int
1973 FcObjectPtrCompare (const FcObjectPtr a, const FcObjectPtr b)
1974 {
1975     /* This is the dynamic count.  We could also use a static
1976      * count, i.e. the number of slow strings being created.
1977      * I think dyncount gives us a better estimate of inefficiency. -PL */
1978     static int compare_count = OBJECT_PTR_CONVERSION_TRIGGER;
1979
1980     /* count on sortedness for fast objectptrs. */
1981     if ((a == b) || (objectptr_indices[a] > 0 && objectptr_indices[b] > 0))
1982         return objectptr_indices[a] - objectptr_indices[b];
1983
1984     compare_count--;
1985     if (!compare_count)
1986     {
1987         FcObjectPtrConvertToStatic(FcFalse);
1988         compare_count = OBJECT_PTR_CONVERSION_TRIGGER;
1989     }
1990
1991     return strcmp (FcObjectPtrU(a), FcObjectPtrU(b));
1992 }
1993
1994 void
1995 FcObjectClearStatic(void)
1996 {
1997     objectptr_count = 1;
1998     objectptr_alloc = 0;
1999     objectptr_indices = 0;
2000
2001     objectcontent_static_bytes = 0;
2002     objectcontent_static_buf = 0;
2003
2004     objectcontent_dynamic_count = 1;
2005     objectcontent_dynamic_alloc = 0;
2006     objectcontent_dynamic = 0;
2007     objectcontent_dynamic_refcount = 0;
2008
2009     object_old_id_to_new = 0;
2010 }
2011
2012 /* In the pre-serialization phase, mark the used strings with
2013  * -1 in the mapping array. */
2014 /* The first call to the serialization phase assigns actual 
2015  * static indices to the strings (sweep). */
2016 static FcBool
2017 FcObjectPrepareSerialize (FcObjectPtr si)
2018 {
2019     if (object_old_id_to_new == 0)
2020     {
2021         object_old_id_to_new = malloc(objectptr_count * sizeof(int));
2022         if (!object_old_id_to_new)
2023             goto bail;
2024         memset (object_old_id_to_new, 0, 
2025                 objectptr_count * sizeof(int));
2026     }
2027
2028     object_old_id_to_new[si] = -1;
2029     objectptr_first_serialization = FcTrue;
2030
2031     return FcTrue;
2032
2033  bail:
2034     return FcFalse;
2035 }
2036
2037 static FcObjectPtr
2038 FcObjectSerialize (FcObjectPtr si)
2039 {
2040     if (objectptr_first_serialization)
2041         if (!FcObjectPtrConvertToStatic(FcTrue))
2042             return 0;
2043
2044     return object_old_id_to_new[si];
2045 }
2046
2047 FcBool
2048 FcObjectRead (int fd, FcCache metadata)
2049 {
2050     /* do we have to merge strings? 
2051      * it's possible to merge dynamic strings, as long as we only store
2052      * static strings to disk and as long as all static strings have lower
2053      * ids than any dynamic strings. */
2054
2055     objectcontent_dynamic_count = 1;
2056     objectcontent_dynamic_alloc = 0;
2057     objectcontent_dynamic = 0;
2058     objectcontent_dynamic_refcount = 0;
2059
2060     /* well, we do need to allocate dynamic strings all the time,
2061      * so this would just have to be converted.  It takes 1.4k on
2062      * my system. - PL */
2063 /*     objectptr_indices = mmap(NULL,  */
2064 /*                           metadata.object_length * sizeof (int), */
2065 /*                           PROT_READ, */
2066 /*                           MAP_SHARED, fd, metadata.object_offset); */
2067 /*     if (objectptr_indices == MAP_FAILED) */
2068 /*         goto bail; */
2069
2070     objectptr_count = metadata.object_length;
2071     objectptr_alloc = metadata.object_length;
2072     objectptr_indices = malloc (metadata.object_length * sizeof (int));
2073     if (!objectptr_indices) 
2074         goto bail;
2075     FcMemAlloc (FC_MEM_STATICSTR, metadata.object_length * sizeof (int));
2076     lseek (fd, metadata.object_offset, SEEK_SET);
2077     read (fd, objectptr_indices, metadata.object_length * sizeof (int));
2078
2079     objectcontent_static_buf = 
2080         mmap(NULL,
2081              metadata.objectcontent_length * sizeof (char),
2082              PROT_READ,
2083              MAP_SHARED, fd, metadata.objectcontent_offset);
2084     if (objectptr_indices == MAP_FAILED)
2085         goto bail1;
2086     objectcontent_static_bytes = metadata.objectcontent_length;
2087
2088     FcObjectRebuildStaticNameHashtable ();
2089
2090     return FcTrue;
2091
2092  bail1:
2093     /*munmap(objectptr_indices, metadata.object_length * sizeof(int));*/
2094     free (objectptr_indices);
2095  bail:
2096     return FcFalse;
2097 }
2098
2099 FcBool
2100 FcObjectWrite (int fd, FcCache * metadata)
2101 {
2102     /* there should be no dynamic strings: 
2103      * serialize ought to have zapped 'em. */
2104     if (objectcontent_dynamic_alloc)
2105         return FcFalse;
2106
2107     metadata->object_length = objectptr_count;
2108     metadata->object_offset = FcCacheNextOffset(fd);    
2109     lseek(fd, metadata->object_offset, SEEK_SET);
2110     if (write (fd, objectptr_indices, 
2111                metadata->object_length * sizeof (int)) == -1)
2112         return FcFalse;
2113
2114     metadata->objectcontent_length = objectcontent_static_bytes;
2115     metadata->objectcontent_offset = FcCacheNextOffset(fd);
2116     lseek(fd, metadata->objectcontent_offset, SEEK_SET);
2117     if (write (fd, objectcontent_static_buf, 
2118                metadata->objectcontent_length * sizeof (char)) == -1)
2119         return FcFalse;
2120
2121     return FcTrue;
2122 }
2123
2124 static void
2125 FcObjectStaticNameFini (void)
2126 {
2127     int i, size;
2128     struct objectBucket *b, *next;
2129     char *name;
2130
2131     for (i = 0; i < OBJECT_HASH_SIZE; i++)
2132     {
2133         for (b = FcObjectBuckets[i]; b; b = next)
2134         {
2135             next = b->next;
2136             name = (char *) (b + 1);
2137             size = sizeof (struct objectBucket) + strlen (name) + 1;
2138             FcMemFree (FC_MEM_STATICSTR, size);
2139             free (b);
2140         }
2141         FcObjectBuckets[i] = 0;
2142     }
2143 }
2144
2145 void
2146 FcPatternFini (void)
2147 {
2148     FcPatternBaseThawAll ();
2149     FcValueListThawAll ();
2150     FcObjectStaticNameFini ();
2151 }