1 /*
2 * Copyright © 2000 Keith Packard
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of the author(s) not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission. The authors make no
11 * representations about the suitability of this software for any purpose. It
12 * is provided "as is" without express or implied warranty.
13 *
14 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 */
22
23 #include "fcint.h"
24 #include "fcftint.h"
25
26 /* Objects MT-safe for readonly access. */
27
28 FcPattern *
29 FcPatternCreate (void)
30 {
31 FcPattern *p;
32
33 p = (FcPattern *) malloc (sizeof (FcPattern));
34 if (!p)
35 return 0;
36 memset (p, 0, sizeof (FcPattern));
37 p->num = 0;
38 p->size = 0;
39 p->elts_offset = FcPtrToOffset (p, NULL);
40 FcRefInit (&p->ref, 1);
41 return p;
42 }
43
44 void
45 FcValueDestroy (FcValue v)
46 {
47 switch ((int) v.type) {
48 case FcTypeString:
49 FcFree (v.u.s);
50 break;
51 case FcTypeMatrix:
52 FcMatrixFree ((FcMatrix *) v.u.m);
53 break;
54 case FcTypeCharSet:
55 FcCharSetDestroy ((FcCharSet *) v.u.c);
56 break;
57 case FcTypeLangSet:
58 FcLangSetDestroy ((FcLangSet *) v.u.l);
59 break;
60 case FcTypeRange:
61 FcRangeDestroy ((FcRange *) v.u.r);
62 break;
63 default:
64 break;
65 }
66 }
67
68 FcValue
69 FcValueCanonicalize (const FcValue *v)
70 {
71 FcValue new;
72
73 switch ((int) v->type)
74 {
75 case FcTypeString:
76 new.u.s = FcValueString(v);
77 new.type = FcTypeString;
78 break;
79 case FcTypeCharSet:
80 new.u.c = FcValueCharSet(v);
81 new.type = FcTypeCharSet;
82 break;
83 case FcTypeLangSet:
84 new.u.l = FcValueLangSet(v);
85 new.type = FcTypeLangSet;
86 break;
87 case FcTypeRange:
88 new.u.r = FcValueRange(v);
89 new.type = FcTypeRange;
90 break;
91 default:
92 new = *v;
93 break;
94 }
95 return new;
96 }
97
98 FcValue
99 FcValueSave (FcValue v)
100 {
101 switch ((int) v.type) {
102 case FcTypeString:
103 v.u.s = FcStrdup (v.u.s);
104 if (!v.u.s)
105 v.type = FcTypeVoid;
106 break;
107 case FcTypeMatrix:
108 v.u.m = FcMatrixCopy (v.u.m);
109 if (!v.u.m)
110 v.type = FcTypeVoid;
111 break;
112 case FcTypeCharSet:
113 v.u.c = FcCharSetCopy ((FcCharSet *) v.u.c);
114 if (!v.u.c)
115 v.type = FcTypeVoid;
116 break;
117 case FcTypeLangSet:
118 v.u.l = FcLangSetCopy (v.u.l);
119 if (!v.u.l)
120 v.type = FcTypeVoid;
121 break;
122 case FcTypeRange:
123 v.u.r = FcRangeCopy (v.u.r);
124 if (!v.u.r)
125 v.type = FcTypeVoid;
126 break;
127 default:
128 break;
129 }
130 return v;
131 }
132
133 FcValueListPtr
134 FcValueListCreate (void)
135 {
136 return calloc (1, sizeof (FcValueList));
137 }
138
139 void
140 FcValueListDestroy (FcValueListPtr l)
141 {
142 FcValueListPtr next;
143 for (; l; l = next)
144 {
145 FcValueDestroy (l->value);
146 next = FcValueListNext(l);
147 free(l);
148 }
149 }
150
151 FcValueListPtr
152 FcValueListPrepend (FcValueListPtr vallist,
153 FcValue value,
154 FcValueBinding binding)
155 {
156 FcValueListPtr new;
157
158 if (value.type == FcTypeVoid)
159 return vallist;
160 new = FcValueListCreate ();
161 if (!new)
162 return vallist;
163
164 new->value = FcValueSave (value);
165 new->binding = binding;
166 new->next = vallist;
167
168 return new;
169 }
170
171 FcValueListPtr
172 FcValueListAppend (FcValueListPtr vallist,
173 FcValue value,
174 FcValueBinding binding)
175 {
176 FcValueListPtr new, last;
177
178 if (value.type == FcTypeVoid)
179 return vallist;
180 new = FcValueListCreate ();
181 if (!new)
182 return vallist;
183
184 new->value = FcValueSave (value);
185 new->binding = binding;
186 new->next = NULL;
187
188 if (vallist)
189 {
190 for (last = vallist; FcValueListNext (last); last = FcValueListNext (last));
191
192 last->next = new;
193 }
194 else
195 vallist = new;
196
197 return vallist;
198 }
199
200 FcValueListPtr
201 FcValueListDuplicate(FcValueListPtr orig)
202 {
203 FcValueListPtr new = NULL, l, t = NULL;
204 FcValue v;
205
206 for (l = orig; l != NULL; l = FcValueListNext (l))
207 {
208 if (!new)
209 {
210 t = new = FcValueListCreate();
211 }
212 else
213 {
214 t->next = FcValueListCreate();
215 t = FcValueListNext (t);
216 }
217 v = FcValueCanonicalize (&l->value);
218 t->value = FcValueSave (v);
219 t->binding = l->binding;
220 t->next = NULL;
221 }
222
223 return new;
224 }
225
226 FcBool
227 FcValueEqual (FcValue va, FcValue vb)
228 {
229 if (va.type != vb.type)
230 {
231 if (va.type == FcTypeInteger)
232 {
233 va.type = FcTypeDouble;
234 va.u.d = va.u.i;
235 }
236 if (vb.type == FcTypeInteger)
237 {
238 vb.type = FcTypeDouble;
239 vb.u.d = vb.u.i;
240 }
241 if (va.type != vb.type)
242 return FcFalse;
243 }
244 switch (va.type) {
245 case FcTypeUnknown:
246 return FcFalse; /* don't know how to compare this object */
247 case FcTypeVoid:
248 return FcTrue;
249 case FcTypeInteger:
250 return va.u.i == vb.u.i;
251 case FcTypeDouble:
252 return va.u.d == vb.u.d;
253 case FcTypeString:
254 return FcStrCmpIgnoreCase (va.u.s, vb.u.s) == 0;
255 case FcTypeBool:
256 return va.u.b == vb.u.b;
257 case FcTypeMatrix:
258 return FcMatrixEqual (va.u.m, vb.u.m);
259 case FcTypeCharSet:
260 return FcCharSetEqual (va.u.c, vb.u.c);
261 case FcTypeFTFace:
262 return va.u.f == vb.u.f;
263 case FcTypeLangSet:
264 return FcLangSetEqual (va.u.l, vb.u.l);
265 case FcTypeRange:
266 return FcRangeIsInRange (va.u.r, vb.u.r);
267 }
268 return FcFalse;
269 }
270
271 static FcChar32
272 FcDoubleHash (double d)
273 {
274 if (d < 0)
275 d = -d;
276 if (d > 0xffffffff)
277 d = 0xffffffff;
278 return (FcChar32) d;
279 }
280
281 FcChar32
282 FcStringHash (const FcChar8 *s)
283 {
284 FcChar8 c;
285 FcChar32 h = 0;
286
287 if (s)
288 while ((c = *s++))
289 h = ((h << 1) | (h >> 31)) ^ c;
290 return h;
291 }
292
293 static FcChar32
294 FcValueHash (const FcValue *v)
295 {
296 switch (v->type) {
297 case FcTypeUnknown:
298 case FcTypeVoid:
299 return 0;
300 case FcTypeInteger:
301 return (FcChar32) v->u.i;
302 case FcTypeDouble:
303 return FcDoubleHash (v->u.d);
304 case FcTypeString:
305 return FcStringHash (FcValueString(v));
306 case FcTypeBool:
307 return (FcChar32) v->u.b;
308 case FcTypeMatrix:
309 return (FcDoubleHash (v->u.m->xx) ^
310 FcDoubleHash (v->u.m->xy) ^
311 FcDoubleHash (v->u.m->yx) ^
312 FcDoubleHash (v->u.m->yy));
313 case FcTypeCharSet:
314 return (FcChar32) FcValueCharSet(v)->num;
315 case FcTypeFTFace:
316 return FcStringHash ((const FcChar8 *) ((FT_Face) v->u.f)->family_name) ^
317 FcStringHash ((const FcChar8 *) ((FT_Face) v->u.f)->style_name);
318 case FcTypeLangSet:
319 return FcLangSetHash (FcValueLangSet(v));
320 case FcTypeRange:
321 return FcRangeHash (FcValueRange (v));
322 }
323 return 0;
324 }
325
326 static FcBool
327 FcValueListEqual (FcValueListPtr la, FcValueListPtr lb)
328 {
329 if (la == lb)
330 return FcTrue;
331
332 while (la && lb)
333 {
334 if (!FcValueEqual (la->value, lb->value))
335 return FcFalse;
336 la = FcValueListNext(la);
337 lb = FcValueListNext(lb);
338 }
339 if (la || lb)
340 return FcFalse;
341 return FcTrue;
342 }
343
344 static FcChar32
345 FcValueListHash (FcValueListPtr l)
346 {
347 FcChar32 hash = 0;
348
349 for (; l; l = FcValueListNext(l))
350 {
351 hash = ((hash << 1) | (hash >> 31)) ^ FcValueHash (&l->value);
352 }
353 return hash;
354 }
355
356 static void *
357 FcPatternGetCacheObject (FcPattern *p)
358 {
359 /* We use a value to find the cache, instead of the FcPattern object
360 * because the pattern itself may be a cache allocation if we rewrote the path,
361 * so the p may not be in the cached region. */
362 return FcPatternEltValues(&FcPatternElts (p)[0]);
363 }
364
365 FcPattern *
366 FcPatternCacheRewriteFile (const FcPattern *p,
367 FcCache *cache,
368 const FcChar8 *relocated_font_file)
369 {
370 FcPatternElt *elts = FcPatternElts (p);
371 size_t i,j;
372 FcChar8 *data;
373 FcPattern *new_p;
374 FcPatternElt *new_elts;
375 FcValueList *new_value_list;
376 size_t new_path_len = strlen ((char *)relocated_font_file);
377 FcChar8 *new_path;
378
379 /* Allocate space for the patter, the PatternElt headers and
380 * the FC_FILE FcValueList and path that will be freed with the
381 * cache */
382 data = FcCacheAllocate (cache,
383 sizeof (FcPattern) +
384 p->num * sizeof (FcPatternElt) +
385 sizeof (FcValueList) +
386 new_path_len + 1);
387
388 new_p = (FcPattern *)data;
389 data += sizeof (FcPattern);
390 new_elts = (FcPatternElt *)(data);
391 data += p->num * sizeof (FcPatternElt);
392 new_value_list = (FcValueList *)data;
393 data += sizeof (FcValueList);
394 new_path = data;
395
396 *new_p = *p;
397 new_p->elts_offset = FcPtrToOffset (new_p, new_elts);
398
399 /* Copy all but the FILE values from the cache */
400 for (i = 0, j = 0; i < p->num; i++)
401 {
402 FcPatternElt *elt = &elts[i];
403 new_elts[j].object = elt->object;
404 if (elt->object != FC_FILE_OBJECT)
405 new_elts[j++].values = FcPatternEltValues(elt);
406 else
407 new_elts[j++].values = new_value_list;
408 }
409
410 new_value_list->next = NULL;
411 new_value_list->value.type = FcTypeString;
412 new_value_list->value.u.s = new_path;
413 new_value_list->binding = FcValueBindingWeak;
414
415 /* Add rewritten path at the end */
416 strcpy ((char *)new_path, (char *)relocated_font_file);
417
418 return new_p;
419 }
420
421 void
422 FcPatternDestroy (FcPattern *p)
423 {
424 int i;
425 FcPatternElt *elts;
426
427 if (!p)
428 return;
429
430 if (FcRefIsConst (&p->ref))
431 {
432 FcCacheObjectDereference (FcPatternGetCacheObject(p));
433 return;
434 }
435
436 if (FcRefDec (&p->ref) != 1)
437 return;
438
439 elts = FcPatternElts (p);
440 for (i = 0; i < FcPatternObjectCount (p); i++)
441 FcValueListDestroy (FcPatternEltValues(&elts[i]));
442
443 free (elts);
444 free (p);
445 }
446
447 int
448 FcPatternObjectCount (const FcPattern *pat)
449 {
450 if (pat)
451 return pat->num;
452
453 return 0;
454 }
455
456
457 static int
458 FcPatternObjectPosition (const FcPattern *p, FcObject object)
459 {
460 int low, high, mid, c;
461 FcPatternElt *elts = FcPatternElts(p);
462
463 low = 0;
464 high = FcPatternObjectCount (p) - 1;
465 c = 1;
466 mid = 0;
467 while (low <= high)
468 {
469 mid = (low + high) >> 1;
470 c = elts[mid].object - object;
471 if (c == 0)
472 return mid;
473 if (c < 0)
474 low = mid + 1;
475 else
476 high = mid - 1;
477 }
478 if (c < 0)
479 mid++;
480 return -(mid + 1);
481 }
482
483 int
484 FcPatternPosition (const FcPattern *p, const char *object)
485 {
486 return FcPatternObjectPosition (p, FcObjectFromName (object));
487 }
488
489 FcPatternElt *
490 FcPatternObjectFindElt (const FcPattern *p, FcObject object)
491 {
492 int i = FcPatternObjectPosition (p, object);
493 if (i < 0)
494 return 0;
495 return &FcPatternElts(p)[i];
496 }
497
498 FcPatternElt *
499 FcPatternObjectInsertElt (FcPattern *p, FcObject object)
500 {
501 int i;
502 FcPatternElt *e;
503
504 i = FcPatternObjectPosition (p, object);
505 if (i < 0)
506 {
507 i = -i - 1;
508
509 /* reallocate array */
510 if (FcPatternObjectCount (p) + 1 >= p->size)
511 {
512 int s = p->size + 16;
513 if (p->size)
514 {
515 FcPatternElt *e0 = FcPatternElts(p);
516 e = (FcPatternElt *) realloc (e0, s * sizeof (FcPatternElt));
517 if (!e) /* maybe it was mmapped */
518 {
519 e = malloc(s * sizeof (FcPatternElt));
520 if (e)
521 memcpy(e, e0, FcPatternObjectCount (p) * sizeof (FcPatternElt));
522 }
523 }
524 else
525 e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
526 if (!e)
527 return FcFalse;
528 p->elts_offset = FcPtrToOffset (p, e);
529 while (p->size < s)
530 {
531 e[p->size].object = 0;
532 e[p->size].values = NULL;
533 p->size++;
534 }
535 }
536
537 e = FcPatternElts(p);
538 /* move elts up */
539 memmove (e + i + 1,
540 e + i,
541 sizeof (FcPatternElt) *
542 (FcPatternObjectCount (p) - i));
543
544 /* bump count */
545 p->num++;
546
547 e[i].object = object;
548 e[i].values = NULL;
549 }
550
551 return FcPatternElts(p) + i;
552 }
553
554 FcBool
555 FcPatternEqual (const FcPattern *pa, const FcPattern *pb)
556 {
557 FcPatternIter ia, ib;
558
559 if (pa == pb)
560 return FcTrue;
561
562 if (FcPatternObjectCount (pa) != FcPatternObjectCount (pb))
563 return FcFalse;
564 FcPatternIterStart (pa, &ia);
565 FcPatternIterStart (pb, &ib);
566 do {
567 FcBool ra, rb;
568
569 if (!FcPatternIterEqual (pa, &ia, pb, &ib))
570 return FcFalse;
571 ra = FcPatternIterNext (pa, &ia);
572 rb = FcPatternIterNext (pb, &ib);
573 if (!ra && !rb)
574 break;
575 } while (1);
576
577 return FcTrue;
578 }
579
580 FcChar32
581 FcPatternHash (const FcPattern *p)
582 {
583 int i;
584 FcChar32 h = 0;
585 FcPatternElt *pe = FcPatternElts(p);
586
587 for (i = 0; i < FcPatternObjectCount (p); i++)
588 {
589 h = (((h << 1) | (h >> 31)) ^
590 pe[i].object ^
591 FcValueListHash (FcPatternEltValues(&pe[i])));
592 }
593 return h;
594 }
595
596 FcBool
597 FcPatternEqualSubset (const FcPattern *pai, const FcPattern *pbi, const FcObjectSet *os)
598 {
599 FcPatternElt *ea, *eb;
600 int i;
601
602 for (i = 0; i < os->nobject; i++)
603 {
604 FcObject object = FcObjectFromName (os->objects[i]);
605 ea = FcPatternObjectFindElt (pai, object);
606 eb = FcPatternObjectFindElt (pbi, object);
607 if (ea)
608 {
609 if (!eb)
610 return FcFalse;
611 if (!FcValueListEqual (FcPatternEltValues(ea), FcPatternEltValues(eb)))
612 return FcFalse;
613 }
614 else
615 {
616 if (eb)
617 return FcFalse;
618 }
619 }
620 return FcTrue;
621 }
622
623 FcBool
624 FcPatternObjectListAdd (FcPattern *p,
625 FcObject object,
626 FcValueListPtr list,
627 FcBool append)
628 {
629 FcPatternElt *e;
630 FcValueListPtr l, *prev;
631
632 if (FcRefIsConst (&p->ref))
633 goto bail0;
634
635 /*
636 * Make sure the stored type is valid for built-in objects
637 */
638 for (l = list; l != NULL; l = FcValueListNext (l))
639 {
640 if (!FcObjectValidType (object, l->value.type))
641 {
642 fprintf (stderr,
643 "Fontconfig warning: FcPattern object %s does not accept value", FcObjectName (object));
644 FcValuePrintFile (stderr, l->value);
645 fprintf (stderr, "\n");
646 goto bail0;
647 }
648 }
649
650 e = FcPatternObjectInsertElt (p, object);
651 if (!e)
652 goto bail0;
653
654 if (append)
655 {
656 for (prev = &e->values; *prev; prev = &(*prev)->next)
657 ;
658 *prev = list;
659 }
660 else
661 {
662 for (prev = &list; *prev; prev = &(*prev)->next)
663 ;
664 *prev = e->values;
665 e->values = list;
666 }
667
668 return FcTrue;
669
670 bail0:
671 return FcFalse;
672 }
673
674 FcBool
675 FcPatternObjectAddWithBinding (FcPattern *p,
676 FcObject object,
677 FcValue value,
678 FcValueBinding binding,
679 FcBool append)
680 {
681 FcPatternElt *e;
682 FcValueListPtr new, *prev;
683
684 if (FcRefIsConst (&p->ref))
685 goto bail0;
686
687 new = FcValueListCreate ();
688 if (!new)
689 goto bail0;
690
691 new->value = FcValueSave (value);
692 new->binding = binding;
693 new->next = NULL;
694
695 if (new->value.type == FcTypeVoid)
696 goto bail1;
697
698 /*
699 * Make sure the stored type is valid for built-in objects
700 */
701 if (!FcObjectValidType (object, new->value.type))
702 {
703 fprintf (stderr,
704 "Fontconfig warning: FcPattern object %s does not accept value",
705 FcObjectName (object));
706 FcValuePrintFile (stderr, new->value);
707 fprintf (stderr, "\n");
708 goto bail1;
709 }
710
711 e = FcPatternObjectInsertElt (p, object);
712 if (!e)
713 goto bail1;
714
715 if (append)
716 {
717 for (prev = &e->values; *prev; prev = &(*prev)->next)
718 ;
719 *prev = new;
720 }
721 else
722 {
723 new->next = e->values;
724 e->values = new;
725 }
726
727 return FcTrue;
728
729 bail1:
730 FcValueListDestroy (new);
731 bail0:
732 return FcFalse;
733 }
734
735 FcBool
736 FcPatternObjectAdd (FcPattern *p, FcObject object, FcValue value, FcBool append)
737 {
738 return FcPatternObjectAddWithBinding (p, object,
739 value, FcValueBindingStrong, append);
740 }
741
742 FcBool
743 FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
744 {
745 return FcPatternObjectAddWithBinding (p, FcObjectFromName (object),
746 value, FcValueBindingStrong, append);
747 }
748
749 FcBool
750 FcPatternAddWeak (FcPattern *p, const char *object, FcValue value, FcBool append)
751 {
752 return FcPatternObjectAddWithBinding (p, FcObjectFromName (object),
753 value, FcValueBindingWeak, append);
754 }
755
756 FcBool
757 FcPatternObjectDel (FcPattern *p, FcObject object)
758 {
759 FcPatternElt *e;
760
761 e = FcPatternObjectFindElt (p, object);
762 if (!e)
763 return FcFalse;
764
765 /* destroy value */
766 FcValueListDestroy (e->values);
767
768 /* shuffle existing ones down */
769 memmove (e, e+1,
770 (FcPatternElts(p) + FcPatternObjectCount (p) - (e + 1)) *
771 sizeof (FcPatternElt));
772 p->num--;
773 e = FcPatternElts(p) + FcPatternObjectCount (p);
774 e->object = 0;
775 e->values = NULL;
776 return FcTrue;
777 }
778
779 FcBool
780 FcPatternDel (FcPattern *p, const char *object)
781 {
782 return FcPatternObjectDel (p, FcObjectFromName (object));
783 }
784
785 FcBool
786 FcPatternRemove (FcPattern *p, const char *object, int id)
787 {
788 FcPatternElt *e;
789 FcValueListPtr *prev, l;
790
791 e = FcPatternObjectFindElt (p, FcObjectFromName (object));
792 if (!e)
793 return FcFalse;
794 for (prev = &e->values; (l = *prev); prev = &l->next)
795 {
796 if (!id)
797 {
798 *prev = l->next;
799 l->next = NULL;
800 FcValueListDestroy (l);
801 if (!e->values)
802 FcPatternDel (p, object);
803 return FcTrue;
804 }
805 id--;
806 }
807 return FcFalse;
808 }
809
810 FcBool
811 FcPatternObjectAddInteger (FcPattern *p, FcObject object, int i)
812 {
813 FcValue v;
814
815 v.type = FcTypeInteger;
816 v.u.i = i;
817 return FcPatternObjectAdd (p, object, v, FcTrue);
818 }
819
820 FcBool
821 FcPatternAddInteger (FcPattern *p, const char *object, int i)
822 {
823 return FcPatternObjectAddInteger (p, FcObjectFromName (object), i);
824 }
825
826 FcBool
827 FcPatternObjectAddDouble (FcPattern *p, FcObject object, double d)
828 {
829 FcValue v;
830
831 v.type = FcTypeDouble;
832 v.u.d = d;
833 return FcPatternObjectAdd (p, object, v, FcTrue);
834 }
835
836
837 FcBool
838 FcPatternAddDouble (FcPattern *p, const char *object, double d)
839 {
840 return FcPatternObjectAddDouble (p, FcObjectFromName (object), d);
841 }
842
843 FcBool
844 FcPatternObjectAddString (FcPattern *p, FcObject object, const FcChar8 *s)
845 {
846 FcValue v;
847
848 if (!s)
849 {
850 v.type = FcTypeVoid;
851 v.u.s = 0;
852 return FcPatternObjectAdd (p, object, v, FcTrue);
853 }
854
855 v.type = FcTypeString;
856 v.u.s = s;
857 return FcPatternObjectAdd (p, object, v, FcTrue);
858 }
859
860 FcBool
861 FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
862 {
863 return FcPatternObjectAddString (p, FcObjectFromName (object), s);
864 }
865
866 FcBool
867 FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
868 {
869 FcValue v;
870
871 v.type = FcTypeMatrix;
872 v.u.m = s;
873 return FcPatternAdd (p, object, v, FcTrue);
874 }
875
876
877 FcBool
878 FcPatternObjectAddBool (FcPattern *p, FcObject object, FcBool b)
879 {
880 FcValue v;
881
882 v.type = FcTypeBool;
883 v.u.b = b;
884 return FcPatternObjectAdd (p, object, v, FcTrue);
885 }
886
887 FcBool
888 FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
889 {
890 return FcPatternObjectAddBool (p, FcObjectFromName (object), b);
891 }
892
893 FcBool
894 FcPatternObjectAddCharSet (FcPattern *p, FcObject object, const FcCharSet *c)
895 {
896 FcValue v;
897
898 v.type = FcTypeCharSet;
899 v.u.c = (FcCharSet *)c;
900 return FcPatternObjectAdd (p, object, v, FcTrue);
901 }
902
903 FcBool
904 FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
905 {
906 return FcPatternObjectAddCharSet (p, FcObjectFromName (object), c);
907 }
908
909 FcBool
910 FcPatternAddFTFace (FcPattern *p, const char *object, const FT_Face f)
911 {
912 FcValue v;
913
914 v.type = FcTypeFTFace;
915 v.u.f = (void *) f;
916 return FcPatternAdd (p, object, v, FcTrue);
917 }
918
919 FcBool
920 FcPatternObjectAddLangSet (FcPattern *p, FcObject object, const FcLangSet *ls)
921 {
922 FcValue v;
923
924 v.type = FcTypeLangSet;
925 v.u.l = (FcLangSet *)ls;
926 return FcPatternObjectAdd (p, object, v, FcTrue);
927 }
928
929 FcBool
930 FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls)
931 {
932 return FcPatternObjectAddLangSet (p, FcObjectFromName (object), ls);
933 }
934
935 FcBool
936 FcPatternObjectAddRange (FcPattern *p, FcObject object, const FcRange *r)
937 {
938 FcValue v;
939
940 v.type = FcTypeRange;
941 v.u.r = (FcRange *)r;
942 return FcPatternObjectAdd (p, object, v, FcTrue);
943 }
944
945 FcBool
946 FcPatternAddRange (FcPattern *p, const char *object, const FcRange *r)
947 {
948 return FcPatternObjectAddRange (p, FcObjectFromName (object), r);
949 }
950
951 FcResult
952 FcPatternObjectGetWithBinding (const FcPattern *p, FcObject object, int id, FcValue *v, FcValueBinding *b)
953 {
954 FcPatternElt *e;
955 FcValueListPtr l;
956
957 if (!p)
958 return FcResultNoMatch;
959 e = FcPatternObjectFindElt (p, object);
960 if (!e)
961 return FcResultNoMatch;
962 for (l = FcPatternEltValues(e); l; l = FcValueListNext(l))
963 {
964 if (!id)
965 {
966 *v = FcValueCanonicalize(&l->value);
967 if (b)
968 *b = l->binding;
969 return FcResultMatch;
970 }
971 id--;
972 }
973 return FcResultNoId;
974 }
975
976 FcResult
977 FcPatternObjectGet (const FcPattern *p, FcObject object, int id, FcValue *v)
978 {
979 return FcPatternObjectGetWithBinding (p, object, id, v, NULL);
980 }
981
982 FcResult
983 FcPatternGetWithBinding (const FcPattern *p, const char *object, int id, FcValue *v, FcValueBinding *b)
984 {
985 return FcPatternObjectGetWithBinding (p, FcObjectFromName (object), id, v, b);
986 }
987
988 FcResult
989 FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v)
990 {
991 return FcPatternObjectGetWithBinding (p, FcObjectFromName (object), id, v, NULL);
992 }
993
994 FcResult
995 FcPatternObjectGetInteger (const FcPattern *p, FcObject object, int id, int *i)
996 {
997 FcValue v;
998 FcResult r;
999
1000 r = FcPatternObjectGet (p, object, id, &v);
1001 if (r != FcResultMatch)
1002 return r;
1003 switch ((int) v.type) {
1004 case FcTypeDouble:
1005 *i = (int) v.u.d;
1006 break;
1007 case FcTypeInteger:
1008 *i = v.u.i;
1009 break;
1010 default:
1011 return FcResultTypeMismatch;
1012 }
1013 return FcResultMatch;
1014 }
1015
1016 FcResult
1017 FcPatternGetInteger (const FcPattern *p, const char *object, int id, int *i)
1018 {
1019 return FcPatternObjectGetInteger (p, FcObjectFromName (object), id, i);
1020 }
1021
1022
1023 FcResult
1024 FcPatternObjectGetDouble (const FcPattern *p, FcObject object, int id, double *d)
1025 {
1026 FcValue v;
1027 FcResult r;
1028
1029 r = FcPatternObjectGet (p, object, id, &v);
1030 if (r != FcResultMatch)
1031 return r;
1032 switch ((int) v.type) {
1033 case FcTypeDouble:
1034 *d = v.u.d;
1035 break;
1036 case FcTypeInteger:
1037 *d = (double) v.u.i;
1038 break;
1039 default:
1040 return FcResultTypeMismatch;
1041 }
1042 return FcResultMatch;
1043 }
1044
1045 FcResult
1046 FcPatternGetDouble (const FcPattern *p, const char *object, int id, double *d)
1047 {
1048 return FcPatternObjectGetDouble (p, FcObjectFromName (object), id, d);
1049 }
1050
1051 FcResult
1052 FcPatternObjectGetString (const FcPattern *p, FcObject object, int id, FcChar8 ** s)
1053 {
1054 FcValue v;
1055 FcResult r;
1056
1057 r = FcPatternObjectGet (p, object, id, &v);
1058 if (r != FcResultMatch)
1059 return r;
1060 if (v.type != FcTypeString)
1061 return FcResultTypeMismatch;
1062
1063 *s = (FcChar8 *) v.u.s;
1064 return FcResultMatch;
1065 }
1066
1067 FcResult
1068 FcPatternGetString (const FcPattern *p, const char *object, int id, FcChar8 ** s)
1069 {
1070 return FcPatternObjectGetString (p, FcObjectFromName (object), id, s);
1071 }
1072
1073 FcResult
1074 FcPatternGetMatrix(const FcPattern *p, const char *object, int id, FcMatrix **m)
1075 {
1076 FcValue v;
1077 FcResult r;
1078
1079 r = FcPatternGet (p, object, id, &v);
1080 if (r != FcResultMatch)
1081 return r;
1082 if (v.type != FcTypeMatrix)
1083 return FcResultTypeMismatch;
1084 *m = (FcMatrix *)v.u.m;
1085 return FcResultMatch;
1086 }
1087
1088
1089 FcResult
1090 FcPatternObjectGetBool (const FcPattern *p, FcObject object, int id, FcBool *b)
1091 {
1092 FcValue v;
1093 FcResult r;
1094
1095 r = FcPatternObjectGet (p, object, id, &v);
1096 if (r != FcResultMatch)
1097 return r;
1098 if (v.type != FcTypeBool)
1099 return FcResultTypeMismatch;
1100 *b = v.u.b;
1101 return FcResultMatch;
1102 }
1103
1104 FcResult
1105 FcPatternGetBool(const FcPattern *p, const char *object, int id, FcBool *b)
1106 {
1107 return FcPatternObjectGetBool (p, FcObjectFromName (object), id, b);
1108 }
1109
1110 FcResult
1111 FcPatternGetCharSet(const FcPattern *p, const char *object, int id, FcCharSet **c)
1112 {
1113 FcValue v;
1114 FcResult r;
1115
1116 r = FcPatternGet (p, object, id, &v);
1117 if (r != FcResultMatch)
1118 return r;
1119 if (v.type != FcTypeCharSet)
1120 return FcResultTypeMismatch;
1121 *c = (FcCharSet *)v.u.c;
1122 return FcResultMatch;
1123 }
1124
1125 FcResult
1126 FcPatternGetFTFace(const FcPattern *p, const char *object, int id, FT_Face *f)
1127 {
1128 FcValue v;
1129 FcResult r;
1130
1131 r = FcPatternGet (p, object, id, &v);
1132 if (r != FcResultMatch)
1133 return r;
1134 if (v.type != FcTypeFTFace)
1135 return FcResultTypeMismatch;
1136 *f = (FT_Face) v.u.f;
1137 return FcResultMatch;
1138 }
1139
1140 FcResult
1141 FcPatternGetLangSet(const FcPattern *p, const char *object, int id, FcLangSet **ls)
1142 {
1143 FcValue v;
1144 FcResult r;
1145
1146 r = FcPatternGet (p, object, id, &v);
1147 if (r != FcResultMatch)
1148 return r;
1149 if (v.type != FcTypeLangSet)
1150 return FcResultTypeMismatch;
1151 *ls = (FcLangSet *)v.u.l;
1152 return FcResultMatch;
1153 }
1154
1155 FcResult
1156 FcPatternObjectGetRange (const FcPattern *p, FcObject object, int id, FcRange **r)
1157 {
1158 FcValue v;
1159 FcResult res;
1160
1161 res = FcPatternObjectGet (p, object, id, &v);
1162 if (res != FcResultMatch)
1163 return res;
1164 switch ((int)v.type) {
1165 case FcTypeRange:
1166 *r = (FcRange *)v.u.r;
1167 break;
1168 default:
1169 return FcResultTypeMismatch;
1170 }
1171 return FcResultMatch;
1172 }
1173
1174 FcResult
1175 FcPatternGetRange (const FcPattern *p, const char *object, int id, FcRange **r)
1176 {
1177 return FcPatternObjectGetRange (p, FcObjectFromName (object), id, r);
1178 }
1179
1180 FcPattern *
1181 FcPatternDuplicate (const FcPattern *orig)
1182 {
1183 FcPattern *new;
1184 FcPatternIter iter;
1185 FcValueListPtr l;
1186
1187 if (!orig)
1188 return NULL;
1189
1190 new = FcPatternCreate ();
1191 if (!new)
1192 goto bail0;
1193
1194 FcPatternIterStart (orig, &iter);
1195 do
1196 {
1197 for (l = FcPatternIterGetValues (orig, &iter); l; l = FcValueListNext (l))
1198 {
1199 if (!FcPatternObjectAddWithBinding (new, FcPatternIterGetObjectId (orig, &iter),
1200 FcValueCanonicalize(&l->value),
1201 l->binding,
1202 FcTrue))
1203 goto bail1;
1204 }
1205 } while (FcPatternIterNext (orig, &iter));
1206
1207 return new;
1208
1209 bail1:
1210 FcPatternDestroy (new);
1211 bail0:
1212 return 0;
1213 }
1214
1215 void
1216 FcPatternReference (FcPattern *p)
1217 {
1218 if (!FcRefIsConst (&p->ref))
1219 FcRefInc (&p->ref);
1220 else
1221 FcCacheObjectReference (FcPatternGetCacheObject(p));
1222 }
1223
1224 FcPattern *
1225 FcPatternVaBuild (FcPattern *p, va_list va)
1226 {
1227 FcPattern *ret;
1228
1229 FcPatternVapBuild (ret, p, va);
1230 return ret;
1231 }
1232
1233 FcPattern *
1234 FcPatternBuild (FcPattern *p, ...)
1235 {
1236 va_list va;
1237
1238 va_start (va, p);
1239 FcPatternVapBuild (p, p, va);
1240 va_end (va);
1241 return p;
1242 }
1243
1244 /*
1245 * Add all of the elements in 's' to 'p'
1246 */
1247 FcBool
1248 FcPatternAppend (FcPattern *p, FcPattern *s)
1249 {
1250 FcPatternIter iter;
1251 FcValueListPtr v;
1252
1253 FcPatternIterStart (s, &iter);
1254 do
1255 {
1256 for (v = FcPatternIterGetValues (s, &iter); v; v = FcValueListNext (v))
1257 {
1258 if (!FcPatternObjectAddWithBinding (p, FcPatternIterGetObjectId (s, &iter),
1259 FcValueCanonicalize(&v->value),
1260 v->binding, FcTrue))
1261 return FcFalse;
1262 }
1263 } while (FcPatternIterNext (s, &iter));
1264
1265 return FcTrue;
1266 }
1267
1268 FcPattern *
1269 FcPatternFilter (FcPattern *p, const FcObjectSet *os)
1270 {
1271 int i;
1272 FcPattern *ret;
1273 FcPatternElt *e;
1274 FcValueListPtr v;
1275
1276 if (!os)
1277 return FcPatternDuplicate (p);
1278
1279 ret = FcPatternCreate ();
1280 if (!ret)
1281 return NULL;
1282
1283 for (i = 0; i < os->nobject; i++)
1284 {
1285 FcObject object = FcObjectFromName (os->objects[i]);
1286 e = FcPatternObjectFindElt (p, object);
1287 if (e)
1288 {
1289 for (v = FcPatternEltValues(e); v; v = FcValueListNext(v))
1290 {
1291 if (!FcPatternObjectAddWithBinding (ret, e->object,
1292 FcValueCanonicalize(&v->value),
1293 v->binding, FcTrue))
1294 goto bail0;
1295 }
1296 }
1297 }
1298 return ret;
1299
1300 bail0:
1301 FcPatternDestroy (ret);
1302 return NULL;
1303 }
1304
1305 typedef struct _FcPatternPrivateIter {
1306 FcPatternElt *elt;
1307 int pos;
1308 } FcPatternPrivateIter;
1309
1310 static void
1311 FcPatternIterSet (const FcPattern *pat, FcPatternPrivateIter *iter)
1312 {
1313 iter->elt = FcPatternObjectCount (pat) > 0 && iter->pos < FcPatternObjectCount (pat) ? &FcPatternElts (pat)[iter->pos] : NULL;
1314 }
1315
1316 void
1317 FcPatternIterStart (const FcPattern *pat, FcPatternIter *iter)
1318 {
1319 FcPatternPrivateIter *priv = (FcPatternPrivateIter *) iter;
1320
1321 priv->pos = 0;
1322 FcPatternIterSet (pat, priv);
1323 }
1324
1325 FcBool
1326 FcPatternIterNext (const FcPattern *pat, FcPatternIter *iter)
1327 {
1328 FcPatternPrivateIter *priv = (FcPatternPrivateIter *) iter;
1329
1330 priv->pos++;
1331 if (priv->pos >= FcPatternObjectCount (pat))
1332 return FcFalse;
1333 FcPatternIterSet (pat, priv);
1334
1335 return FcTrue;
1336 }
1337
1338 FcBool
1339 FcPatternIterEqual (const FcPattern *p1, FcPatternIter *i1,
1340 const FcPattern *p2, FcPatternIter *i2)
1341 {
1342 FcBool b1 = FcPatternIterIsValid (p1, i1);
1343 FcBool b2 = FcPatternIterIsValid (p2, i2);
1344
1345 if (!i1 && !i2)
1346 return FcTrue;
1347 if (!b1 || !b2)
1348 return FcFalse;
1349 if (FcPatternIterGetObjectId (p1, i1) != FcPatternIterGetObjectId (p2, i2))
1350 return FcFalse;
1351
1352 return FcValueListEqual (FcPatternIterGetValues (p1, i1),
1353 FcPatternIterGetValues (p2, i2));
1354 }
1355
1356 FcBool
1357 FcPatternFindObjectIter (const FcPattern *pat, FcPatternIter *iter, FcObject object)
1358 {
1359 FcPatternPrivateIter *priv = (FcPatternPrivateIter *) iter;
1360 int i = FcPatternObjectPosition (pat, object);
1361
1362 priv->elt = NULL;
1363 if (i < 0)
1364 return FcFalse;
1365
1366 priv->pos = i;
1367 FcPatternIterSet (pat, priv);
1368
1369 return FcTrue;
1370 }
1371
1372 FcBool
1373 FcPatternFindIter (const FcPattern *pat, FcPatternIter *iter, const char *object)
1374 {
1375 return FcPatternFindObjectIter (pat, iter, FcObjectFromName (object));
1376 }
1377
1378 FcBool
1379 FcPatternIterIsValid (const FcPattern *pat, FcPatternIter *iter)
1380 {
1381 FcPatternPrivateIter *priv = (FcPatternPrivateIter *)iter;
1382
1383 if (priv && priv->elt)
1384 return FcTrue;
1385
1386 return FcFalse;
1387 }
1388
1389 FcObject
1390 FcPatternIterGetObjectId (const FcPattern *pat, FcPatternIter *iter)
1391 {
1392 FcPatternPrivateIter *priv = (FcPatternPrivateIter *) iter;
1393
1394 if (priv && priv->elt)
1395 return priv->elt->object;
1396
1397 return 0;
1398 }
1399
1400 const char *
1401 FcPatternIterGetObject (const FcPattern *pat, FcPatternIter *iter)
1402 {
1403 return FcObjectName (FcPatternIterGetObjectId (pat, iter));
1404 }
1405
1406 FcValueListPtr
1407 FcPatternIterGetValues (const FcPattern *pat, FcPatternIter *iter)
1408 {
1409 FcPatternPrivateIter *priv = (FcPatternPrivateIter *) iter;
1410
1411 if (priv && priv->elt)
1412 return FcPatternEltValues (priv->elt);
1413
1414 return NULL;
1415 }
1416
1417 int
1418 FcPatternIterValueCount (const FcPattern *pat, FcPatternIter *iter)
1419 {
1420 int count = 0;
1421 FcValueListPtr l;
1422
1423 for (l = FcPatternIterGetValues (pat, iter); l; l = FcValueListNext (l))
1424 count++;
1425
1426 return count;
1427 }
1428
1429 FcResult
1430 FcPatternIterGetValue (const FcPattern *pat, FcPatternIter *iter, int id, FcValue *v, FcValueBinding *b)
1431 {
1432 FcValueListPtr l;
1433
1434 for (l = FcPatternIterGetValues (pat, iter); l; l = FcValueListNext (l))
1435 {
1436 if (id == 0)
1437 {
1438 *v = FcValueCanonicalize (&l->value);
1439 if (b)
1440 *b = l->binding;
1441 return FcResultMatch;
1442 }
1443 id--;
1444 }
1445 return FcResultNoId;
1446 }
1447
1448 FcBool
1449 FcPatternSerializeAlloc (FcSerialize *serialize, const FcPattern *pat)
1450 {
1451 int i;
1452 FcPatternElt *elts = FcPatternElts(pat);
1453
1454 if (!FcSerializeAlloc (serialize, pat, sizeof (FcPattern)))
1455 return FcFalse;
1456 if (!FcSerializeAlloc (serialize, elts, FcPatternObjectCount (pat) * sizeof (FcPatternElt)))
1457 return FcFalse;
1458 for (i = 0; i < FcPatternObjectCount (pat); i++)
1459 if (!FcValueListSerializeAlloc (serialize, FcPatternEltValues(elts+i)))
1460 return FcFalse;
1461 return FcTrue;
1462 }
1463
1464 FcPattern *
1465 FcPatternSerialize (FcSerialize *serialize, const FcPattern *pat)
1466 {
1467 FcPattern *pat_serialized;
1468 FcPatternElt *elts = FcPatternElts (pat);
1469 FcPatternElt *elts_serialized;
1470 FcValueList *values_serialized;
1471 int i;
1472
1473 pat_serialized = FcSerializePtr (serialize, pat);
1474 if (!pat_serialized)
1475 return NULL;
1476 *pat_serialized = *pat;
1477 pat_serialized->size = FcPatternObjectCount (pat);
1478 FcRefSetConst (&pat_serialized->ref);
1479
1480 elts_serialized = FcSerializePtr (serialize, elts);
1481 if (!elts_serialized)
1482 return NULL;
1483
1484 pat_serialized->elts_offset = FcPtrToOffset (pat_serialized,
1485 elts_serialized);
1486
1487 for (i = 0; i < FcPatternObjectCount (pat); i++)
1488 {
1489 values_serialized = FcValueListSerialize (serialize, FcPatternEltValues (elts+i));
1490 if (!values_serialized)
1491 return NULL;
1492 elts_serialized[i].object = elts[i].object;
1493 elts_serialized[i].values = FcPtrToEncodedOffset (&elts_serialized[i],
1494 values_serialized,
1495 FcValueList);
1496 }
1497 if (FcDebug() & FC_DBG_CACHEV) {
1498 printf ("Raw pattern:\n");
1499 FcPatternPrint (pat);
1500 printf ("Serialized pattern:\n");
1501 FcPatternPrint (pat_serialized);
1502 printf ("\n");
1503 }
1504 return pat_serialized;
1505 }
1506
1507 FcBool
1508 FcValueListSerializeAlloc (FcSerialize *serialize, const FcValueList *vl)
1509 {
1510 while (vl)
1511 {
1512 if (!FcSerializeAlloc (serialize, vl, sizeof (FcValueList)))
1513 return FcFalse;
1514 switch ((int) vl->value.type) {
1515 case FcTypeString:
1516 if (!FcStrSerializeAlloc (serialize, vl->value.u.s))
1517 return FcFalse;
1518 break;
1519 case FcTypeCharSet:
1520 if (!FcCharSetSerializeAlloc (serialize, vl->value.u.c))
1521 return FcFalse;
1522 break;
1523 case FcTypeLangSet:
1524 if (!FcLangSetSerializeAlloc (serialize, vl->value.u.l))
1525 return FcFalse;
1526 break;
1527 case FcTypeRange:
1528 if (!FcRangeSerializeAlloc (serialize, vl->value.u.r))
1529 return FcFalse;
1530 break;
1531 default:
1532 break;
1533 }
1534 vl = vl->next;
1535 }
1536 return FcTrue;
1537 }
1538
1539 FcValueList *
1540 FcValueListSerialize (FcSerialize *serialize, const FcValueList *vl)
1541 {
1542 FcValueList *vl_serialized;
1543 FcChar8 *s_serialized;
1544 FcCharSet *c_serialized;
1545 FcLangSet *l_serialized;
1546 FcRange *r_serialized;
1547 FcValueList *head_serialized = NULL;
1548 FcValueList *prev_serialized = NULL;
1549
1550 while (vl)
1551 {
1552 vl_serialized = FcSerializePtr (serialize, vl);
1553 if (!vl_serialized)
1554 return NULL;
1555
1556 if (prev_serialized)
1557 prev_serialized->next = FcPtrToEncodedOffset (prev_serialized,
1558 vl_serialized,
1559 FcValueList);
1560 else
1561 head_serialized = vl_serialized;
1562
1563 vl_serialized->next = NULL;
1564 vl_serialized->value.type = vl->value.type;
1565 switch ((int) vl->value.type) {
1566 case FcTypeInteger:
1567 vl_serialized->value.u.i = vl->value.u.i;
1568 break;
1569 case FcTypeDouble:
1570 vl_serialized->value.u.d = vl->value.u.d;
1571 break;
1572 case FcTypeString:
1573 s_serialized = FcStrSerialize (serialize, vl->value.u.s);
1574 if (!s_serialized)
1575 return NULL;
1576 vl_serialized->value.u.s = FcPtrToEncodedOffset (&vl_serialized->value,
1577 s_serialized,
1578 FcChar8);
1579 break;
1580 case FcTypeBool:
1581 vl_serialized->value.u.b = vl->value.u.b;
1582 break;
1583 case FcTypeMatrix:
1584 /* can't happen */
1585 break;
1586 case FcTypeCharSet:
1587 c_serialized = FcCharSetSerialize (serialize, vl->value.u.c);
1588 if (!c_serialized)
1589 return NULL;
1590 vl_serialized->value.u.c = FcPtrToEncodedOffset (&vl_serialized->value,
1591 c_serialized,
1592 FcCharSet);
1593 break;
1594 case FcTypeFTFace:
1595 /* can't happen */
1596 break;
1597 case FcTypeLangSet:
1598 l_serialized = FcLangSetSerialize (serialize, vl->value.u.l);
1599 if (!l_serialized)
1600 return NULL;
1601 vl_serialized->value.u.l = FcPtrToEncodedOffset (&vl_serialized->value,
1602 l_serialized,
1603 FcLangSet);
1604 break;
1605 case FcTypeRange:
1606 r_serialized = FcRangeSerialize (serialize, vl->value.u.r);
1607 if (!r_serialized)
1608 return NULL;
1609 vl_serialized->value.u.r = FcPtrToEncodedOffset (&vl_serialized->value,
1610 r_serialized,
1611 FcRange);
1612 break;
1613 default:
1614 break;
1615 }
1616 prev_serialized = vl_serialized;
1617 vl = vl->next;
1618 }
1619 return head_serialized;
1620 }
1621
1622 #define __fcpat__
1623 #include "fcaliastail.h"
1624 #include "fcftaliastail.h"
1625 #undef __fcpat__