]> git.wh0rd.org Git - fontconfig.git/blob - src/fcstr.c
Manually perform inlining & partial redundancy elimination to reduce calls
[fontconfig.git] / src / fcstr.c
1 /*
2  * $RCSId: xc/lib/fontconfig/src/fcstr.c,v 1.10 2002/08/31 22:17:32 keithp 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 <ctype.h>
27 #include <string.h>
28 #include "fcint.h"
29
30 FcChar8 *
31 FcStrCopy (const FcChar8 *s)
32 {
33     FcChar8     *r;
34
35     if (!s)
36         return 0;
37     r = (FcChar8 *) malloc (strlen ((char *) s) + 1);
38     if (!r)
39         return 0;
40     FcMemAlloc (FC_MEM_STRING, strlen ((char *) s) + 1);
41     strcpy ((char *) r, (char *) s);
42     return r;
43 }
44
45 FcChar8 *
46 FcStrPlus (const FcChar8 *s1, const FcChar8 *s2)
47 {
48     int     l = strlen ((char *)s1) + strlen ((char *) s2) + 1;
49     FcChar8 *s = malloc (l);
50
51     if (!s)
52         return 0;
53     FcMemAlloc (FC_MEM_STRING, l);
54     strcpy ((char *) s, (char *) s1);
55     strcat ((char *) s, (char *) s2);
56     return s;
57 }
58
59 void
60 FcStrFree (FcChar8 *s)
61 {
62     FcMemFree (FC_MEM_STRING, strlen ((char *) s) + 1);
63     free (s);
64 }
65
66
67 #include "../fc-case/fccase.h"
68
69 #define FcCaseFoldUpperCount(cf) \
70     ((cf)->method == FC_CASE_FOLD_FULL ? 1 : (cf)->count)
71
72 #define FC_STR_CANON_BUF_LEN    1024
73
74 typedef struct _FcCaseWalker {
75     const FcChar8   *read;
76     const FcChar8   *src;
77     FcChar8         utf8[FC_MAX_CASE_FOLD_CHARS + 1];
78 } FcCaseWalker;
79
80 static void
81 FcStrCaseWalkerInit (const FcChar8 *src, FcCaseWalker *w)
82 {
83     w->src = src;
84     w->read = 0;
85 }
86
87 static FcChar8
88 FcStrCaseWalkerLong (FcCaseWalker *w, FcChar8 r)
89 {
90     FcChar32    ucs4;
91     int         slen;
92     int         len = strlen((char*)w->src);
93
94     slen = FcUtf8ToUcs4 (w->src - 1, &ucs4, len + 1);
95     if (slen <= 0)
96         return r;
97     if (FC_MIN_FOLD_CHAR <= ucs4 && ucs4 <= FC_MAX_FOLD_CHAR)
98     {
99         int min = 0;
100         int max = FC_NUM_CASE_FOLD;
101
102         while (min <= max)
103         {
104             int         mid = (min + max) >> 1;
105             FcChar32    low = fcCaseFold[mid].upper;
106             FcChar32    high = low + FcCaseFoldUpperCount (&fcCaseFold[mid]);
107             
108             if (high <= ucs4)
109                 min = mid + 1;
110             else if (ucs4 < low)
111                 max = mid - 1;
112             else
113             {
114                 const FcCaseFold    *fold = &fcCaseFold[mid];
115                 int                 dlen;
116                 
117                 switch (fold->method) {
118                 case  FC_CASE_FOLD_EVEN_ODD:
119                     if ((ucs4 & 1) != (fold->upper & 1))
120                         return r;
121                     /* fall through ... */
122                 default:
123                     dlen = FcUcs4ToUtf8 (ucs4 + fold->offset, w->utf8);
124                     break;
125                 case FC_CASE_FOLD_FULL:
126                     dlen = fold->count;
127                     memcpy (w->utf8, fcCaseFoldChars + fold->offset, dlen);
128                     break;
129                 }
130                 
131                 /* consume rest of src utf-8 bytes */
132                 w->src += slen - 1;
133                 
134                 /* read from temp buffer */
135                 w->utf8[dlen] = '\0';
136                 w->read = w->utf8;
137                 return *w->read++;
138             }
139         }
140     }
141     return r;
142 }
143
144 static FcChar8
145 FcStrCaseWalkerNext (FcCaseWalker *w)
146 {
147     FcChar8     r;
148
149     if (w->read)
150     {
151         if ((r = *w->read++))
152             return r;
153         w->read = 0;
154     }
155     r = *w->src++;
156     
157     if ((r & 0xc0) == 0xc0)
158         return FcStrCaseWalkerLong (w, r);
159     if ('A' <= r && r <= 'Z')
160         r = r - 'A' + 'a';
161     return r;
162 }
163
164 static FcChar8
165 FcStrCaseWalkerNextIgnoreBlanks (FcCaseWalker *w)
166 {
167     FcChar8     r;
168
169     if (w->read)
170     {
171         if ((r = *w->read++))
172             return r;
173         w->read = 0;
174     }
175     do
176     {
177         r = *w->src++;
178     } while (r == ' ');
179     
180     if ((r & 0xc0) == 0xc0)
181         return FcStrCaseWalkerLong (w, r);
182     if ('A' <= r && r <= 'Z')
183         r = r - 'A' + 'a';
184     return r;
185 }
186
187 FcChar8 *
188 FcStrDowncase (const FcChar8 *s)
189 {
190     FcCaseWalker    w;
191     int             len = 0;
192     FcChar8         *dst, *d;
193
194     FcStrCaseWalkerInit (s, &w);
195     while (FcStrCaseWalkerNext (&w))
196         len++;
197     d = dst = malloc (len + 1);
198     if (!d)
199         return 0;
200     FcMemAlloc (FC_MEM_STRING, len + 1);
201     FcStrCaseWalkerInit (s, &w);
202     while ((*d++ = FcStrCaseWalkerNext (&w)));
203     return dst;
204 }
205
206 int
207 FcStrCmpIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
208 {
209     FcCaseWalker    w1, w2;
210     FcChar8         c1, c2;
211
212     if (s1 == s2) return 0;
213     
214     FcStrCaseWalkerInit (s1, &w1);
215     FcStrCaseWalkerInit (s2, &w2);
216     
217     for (;;) 
218     {
219         c1 = FcStrCaseWalkerNext (&w1);
220         c2 = FcStrCaseWalkerNext (&w2);
221         if (!c1 || (c1 != c2))
222             break;
223     }
224     return (int) c1 - (int) c2;
225 }
226
227 int
228 FcStrCmpIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2)
229 {
230     FcCaseWalker    w1, w2;
231     FcChar8         c1, c2;
232
233     if (s1 == s2) return 0;
234     
235     FcStrCaseWalkerInit (s1, &w1);
236     FcStrCaseWalkerInit (s2, &w2);
237     
238     for (;;) 
239     {
240         c1 = FcStrCaseWalkerNextIgnoreBlanks (&w1);
241         c2 = FcStrCaseWalkerNextIgnoreBlanks (&w2);
242         if (!c1 || (c1 != c2))
243             break;
244     }
245     return (int) c1 - (int) c2;
246 }
247
248 int
249 FcStrCmp (const FcChar8 *s1, const FcChar8 *s2)
250 {
251     FcChar8 c1, c2;
252     
253     if (s1 == s2)
254         return 0;
255     for (;;) 
256     {
257         c1 = *s1++;
258         c2 = *s2++;
259         if (!c1 || c1 != c2)
260             break;
261     }
262     return (int) c1 - (int) c2;
263 }
264
265 /*
266  * Return a hash value for a string
267  */
268
269 FcChar32
270 FcStrHashIgnoreCase (const FcChar8 *s)
271 {
272     FcChar32        h = 0;
273     FcCaseWalker    w;
274     FcChar8         c;
275
276     FcStrCaseWalkerInit (s, &w);
277     while ((c = FcStrCaseWalkerNext (&w)))
278         h = ((h << 3) ^ (h >> 3)) ^ c;
279     return h;
280 }
281
282 /*
283  * Is the head of s1 equal to s2?
284  */
285
286 static FcBool
287 FcStrIsAtIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2)
288 {
289     FcCaseWalker    w1, w2;
290     FcChar8         c1, c2;
291
292     FcStrCaseWalkerInit (s1, &w1);
293     FcStrCaseWalkerInit (s2, &w2);
294     
295     for (;;) 
296     {
297         c1 = FcStrCaseWalkerNextIgnoreBlanks (&w1);
298         c2 = FcStrCaseWalkerNextIgnoreBlanks (&w2);
299         if (!c1 || (c1 != c2))
300             break;
301     }
302     return c1 == c2 || !c2;
303 }
304
305 /*
306  * Does s1 contain an instance of s2 (ignoring blanks and case)?
307  */
308
309 const FcChar8 *
310 FcStrContainsIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2)
311 {
312     while (*s1)
313     {
314         if (FcStrIsAtIgnoreBlanksAndCase (s1, s2))
315             return s1;
316         s1++;
317     }
318     return 0;
319 }
320
321 /*
322  * Is the head of s1 equal to s2?
323  */
324
325 static FcBool
326 FcStrIsAtIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
327 {
328     FcCaseWalker    w1, w2;
329     FcChar8         c1, c2;
330
331     FcStrCaseWalkerInit (s1, &w1);
332     FcStrCaseWalkerInit (s2, &w2);
333     
334     for (;;) 
335     {
336         c1 = FcStrCaseWalkerNext (&w1);
337         c2 = FcStrCaseWalkerNext (&w2);
338         if (!c1 || (c1 != c2))
339             break;
340     }
341     return c1 == c2 || !c2;
342 }
343
344 /*
345  * Does s1 contain an instance of s2 (ignoring blanks and case)?
346  */
347
348 const FcChar8 *
349 FcStrContainsIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
350 {
351     while (*s1)
352     {
353         if (FcStrIsAtIgnoreCase (s1, s2))
354             return s1;
355         s1++;
356     }
357     return 0;
358 }
359
360 const FcChar8 *
361 FcStrStrIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
362 {
363     FcCaseWalker    w1, w2;
364     FcChar8         c1, c2;
365     const FcChar8   *cur;
366
367     if (!s1 || !s2)
368         return 0;
369
370     if (s1 == s2)
371         return s1;
372     
373     FcStrCaseWalkerInit (s1, &w1);
374     FcStrCaseWalkerInit (s2, &w2);
375     
376     c2 = FcStrCaseWalkerNext (&w2);
377     
378     for (;;)
379     {
380         cur = w1.src;
381         c1 = FcStrCaseWalkerNext (&w1);
382         if (!c1)
383             break;
384         if (c1 == c2)
385         {
386             FcCaseWalker    w1t = w1;
387             FcCaseWalker    w2t = w2;
388             FcChar8         c1t, c2t;
389
390             for (;;)
391             {
392                 c1t = FcStrCaseWalkerNext (&w1t);
393                 c2t = FcStrCaseWalkerNext (&w2t);
394
395                 if (!c2t)
396                     return cur;
397                 if (c2t != c1t)
398                     break;
399             }
400         }
401     }
402     return 0;
403 }
404
405 const FcChar8 *
406 FcStrStr (const FcChar8 *s1, const FcChar8 *s2)
407 {
408     FcChar8 c1, c2;
409     const FcChar8 * p = s1;
410     const FcChar8 * b = s2;
411
412     if (!s1 || !s2)
413         return 0;
414
415     if (s1 == s2)
416         return s1;
417
418 again:
419     c2 = *s2++;
420
421     if (!c2)
422         return 0;
423
424     for (;;) 
425     {
426         p = s1;
427         c1 = *s1++;
428         if (!c1 || c1 == c2)
429             break;
430     }
431
432     if (c1 != c2)
433         return 0;
434
435     for (;;)
436     {
437         c1 = *s1;
438         c2 = *s2;
439         if (c1 && c2 && c1 != c2)
440         {
441             s1 = p + 1;
442             s2 = b;
443             goto again;
444         }
445         if (!c2)
446             return p;
447         if (!c1)
448             return 0;
449         ++ s1;
450         ++ s2;
451     }
452
453     return 0;
454 }
455
456 int
457 FcUtf8ToUcs4 (const FcChar8 *src_orig,
458               FcChar32      *dst,
459               int           len)
460 {
461     const FcChar8   *src = src_orig;
462     FcChar8         s;
463     int             extra;
464     FcChar32        result;
465
466     if (len == 0)
467         return 0;
468     
469     s = *src++;
470     len--;
471     
472     if (!(s & 0x80))
473     {
474         result = s;
475         extra = 0;
476     } 
477     else if (!(s & 0x40))
478     {
479         return -1;
480     }
481     else if (!(s & 0x20))
482     {
483         result = s & 0x1f;
484         extra = 1;
485     }
486     else if (!(s & 0x10))
487     {
488         result = s & 0xf;
489         extra = 2;
490     }
491     else if (!(s & 0x08))
492     {
493         result = s & 0x07;
494         extra = 3;
495     }
496     else if (!(s & 0x04))
497     {
498         result = s & 0x03;
499         extra = 4;
500     }
501     else if ( ! (s & 0x02))
502     {
503         result = s & 0x01;
504         extra = 5;
505     }
506     else
507     {
508         return -1;
509     }
510     if (extra > len)
511         return -1;
512     
513     while (extra--)
514     {
515         result <<= 6;
516         s = *src++;
517         
518         if ((s & 0xc0) != 0x80)
519             return -1;
520         
521         result |= s & 0x3f;
522     }
523     *dst = result;
524     return src - src_orig;
525 }
526
527 FcBool
528 FcUtf8Len (const FcChar8    *string,
529            int              len,
530            int              *nchar,
531            int              *wchar)
532 {
533     int         n;
534     int         clen;
535     FcChar32    c;
536     FcChar32    max;
537     
538     n = 0;
539     max = 0;
540     while (len)
541     {
542         clen = FcUtf8ToUcs4 (string, &c, len);
543         if (clen <= 0)  /* malformed UTF8 string */
544             return FcFalse;
545         if (c > max)
546             max = c;
547         string += clen;
548         len -= clen;
549         n++;
550     }
551     *nchar = n;
552     if (max >= 0x10000)
553         *wchar = 4;
554     else if (max > 0x100)
555         *wchar = 2;
556     else
557         *wchar = 1;
558     return FcTrue;
559 }
560
561 int
562 FcUcs4ToUtf8 (FcChar32  ucs4,
563               FcChar8   dest[FC_UTF8_MAX_LEN])
564 {
565     int bits;
566     FcChar8 *d = dest;
567     
568     if      (ucs4 <       0x80) {  *d++=  ucs4;                         bits= -6; }
569     else if (ucs4 <      0x800) {  *d++= ((ucs4 >>  6) & 0x1F) | 0xC0;  bits=  0; }
570     else if (ucs4 <    0x10000) {  *d++= ((ucs4 >> 12) & 0x0F) | 0xE0;  bits=  6; }
571     else if (ucs4 <   0x200000) {  *d++= ((ucs4 >> 18) & 0x07) | 0xF0;  bits= 12; }
572     else if (ucs4 <  0x4000000) {  *d++= ((ucs4 >> 24) & 0x03) | 0xF8;  bits= 18; }
573     else if (ucs4 < 0x80000000) {  *d++= ((ucs4 >> 30) & 0x01) | 0xFC;  bits= 24; }
574     else return 0;
575
576     for ( ; bits >= 0; bits-= 6) {
577         *d++= ((ucs4 >> bits) & 0x3F) | 0x80;
578     }
579     return d - dest;
580 }
581
582 #define GetUtf16(src,endian) \
583     ((FcChar16) ((src)[endian == FcEndianBig ? 0 : 1] << 8) | \
584      (FcChar16) ((src)[endian == FcEndianBig ? 1 : 0]))
585
586 int
587 FcUtf16ToUcs4 (const FcChar8    *src_orig,
588                FcEndian         endian,
589                FcChar32         *dst,
590                int              len)    /* in bytes */
591 {
592     const FcChar8   *src = src_orig;
593     FcChar16        a, b;
594     FcChar32        result;
595
596     if (len < 2)
597         return 0;
598     
599     a = GetUtf16 (src, endian); src += 2; len -= 2;
600     
601     /* 
602      * Check for surrogate 
603      */
604     if ((a & 0xfc00) == 0xd800)
605     {
606         if (len < 2)
607             return 0;
608         b = GetUtf16 (src, endian); src += 2; len -= 2;
609         /*
610          * Check for invalid surrogate sequence
611          */
612         if ((b & 0xfc00) != 0xdc00)
613             return 0;
614         result = ((((FcChar32) a & 0x3ff) << 10) |
615                   ((FcChar32) b & 0x3ff)) + 0x10000;
616     }
617     else
618         result = a;
619     *dst = result;
620     return src - src_orig;
621 }
622
623 FcBool
624 FcUtf16Len (const FcChar8   *string,
625             FcEndian        endian,
626             int             len,        /* in bytes */
627             int             *nchar,
628             int             *wchar)
629 {
630     int         n;
631     int         clen;
632     FcChar32    c;
633     FcChar32    max;
634     
635     n = 0;
636     max = 0;
637     while (len)
638     {
639         clen = FcUtf16ToUcs4 (string, endian, &c, len);
640         if (clen <= 0)  /* malformed UTF8 string */
641             return FcFalse;
642         if (c > max)
643             max = c;
644         string += clen;
645         len -= clen;
646         n++;
647     }
648     *nchar = n;
649     if (max >= 0x10000)
650         *wchar = 4;
651     else if (max > 0x100)
652         *wchar = 2;
653     else
654         *wchar = 1;
655     return FcTrue;
656 }
657
658 void
659 FcStrBufInit (FcStrBuf *buf, FcChar8 *init, int size)
660 {
661     buf->buf = init;
662     buf->allocated = FcFalse;
663     buf->failed = FcFalse;
664     buf->len = 0;
665     buf->size = size;
666 }
667
668 void
669 FcStrBufDestroy (FcStrBuf *buf)
670 {
671     if (buf->allocated)
672     {
673         FcMemFree (FC_MEM_STRBUF, buf->size);
674         free (buf->buf);
675         FcStrBufInit (buf, 0, 0);
676     }
677 }
678
679 FcChar8 *
680 FcStrBufDone (FcStrBuf *buf)
681 {
682     FcChar8 *ret;
683
684     ret = malloc (buf->len + 1);
685     if (ret)
686     {
687         FcMemAlloc (FC_MEM_STRING, buf->len + 1);
688         memcpy (ret, buf->buf, buf->len);
689         ret[buf->len] = '\0';
690     }
691     FcStrBufDestroy (buf);
692     return ret;
693 }
694
695 FcBool
696 FcStrBufChar (FcStrBuf *buf, FcChar8 c)
697 {
698     if (buf->len == buf->size)
699     {
700         FcChar8     *new;
701         int         size;
702
703         if (buf->allocated)
704         {
705             size = buf->size * 2;
706             new = realloc (buf->buf, size);
707         }
708         else
709         {
710             size = buf->size + 1024;
711             new = malloc (size);
712             if (new)
713             {
714                 buf->allocated = FcTrue;
715                 memcpy (new, buf->buf, buf->len);
716             }
717         }
718         if (!new)
719         {
720             buf->failed = FcTrue;
721             return FcFalse;
722         }
723         if (buf->size)
724             FcMemFree (FC_MEM_STRBUF, buf->size);
725         FcMemAlloc (FC_MEM_STRBUF, size);
726         buf->size = size;
727         buf->buf = new;
728     }
729     buf->buf[buf->len++] = c;
730     return FcTrue;
731 }
732
733 FcBool
734 FcStrBufString (FcStrBuf *buf, const FcChar8 *s)
735 {
736     FcChar8 c;
737     while ((c = *s++))
738         if (!FcStrBufChar (buf, c))
739             return FcFalse;
740     return FcTrue;
741 }
742
743 FcBool
744 FcStrBufData (FcStrBuf *buf, const FcChar8 *s, int len)
745 {
746     while (len-- > 0)
747         if (!FcStrBufChar (buf, *s++))
748             return FcFalse;
749     return FcTrue;
750 }
751
752 FcBool
753 FcStrUsesHome (const FcChar8 *s)
754 {
755     return *s == '~';
756 }
757
758 FcChar8 *
759 FcStrCopyFilename (const FcChar8 *s)
760 {
761     FcChar8 *new;
762     
763     if (*s == '~')
764     {
765         FcChar8 *home = FcConfigHome ();
766         int     size;
767         if (!home)
768             return 0;
769         size = strlen ((char *) home) + strlen ((char *) s);
770         new = (FcChar8 *) malloc (size);
771         if (!new)
772             return 0;
773         FcMemAlloc (FC_MEM_STRING, size);
774         strcpy ((char *) new, (char *) home);
775         strcat ((char *) new, (char *) s + 1);
776     }
777     else
778     {
779         int     size = strlen ((char *) s) + 1;
780         new = (FcChar8 *) malloc (size);
781         if (!new)
782             return 0;
783         FcMemAlloc (FC_MEM_STRING, size);
784         strcpy ((char *) new, (const char *) s);
785     }
786     return new;
787 }
788
789 FcChar8 *
790 FcStrLastSlash (const FcChar8  *path)
791 {
792     FcChar8         *slash;
793
794     slash = (FcChar8 *) strrchr ((const char *) path, '/');
795 #ifdef _WIN32
796     {
797         FcChar8     *backslash;
798
799         backslash = (FcChar8 *) strrchr ((const char *) path, '\\');
800         if (!slash || (backslash && backslash > slash))
801             slash = backslash;
802     }
803 #endif
804
805     return slash;
806 }
807   
808 FcChar8 *
809 FcStrDirname (const FcChar8 *file)
810 {
811     FcChar8 *slash;
812     FcChar8 *dir;
813
814     slash = FcStrLastSlash (file);
815     if (!slash)
816         return FcStrCopy ((FcChar8 *) ".");
817     dir = malloc ((slash - file) + 1);
818     if (!dir)
819         return 0;
820     FcMemAlloc (FC_MEM_STRING, (slash - file) + 1);
821     strncpy ((char *) dir, (const char *) file, slash - file);
822     dir[slash - file] = '\0';
823     return dir;
824 }
825
826 FcChar8 *
827 FcStrBasename (const FcChar8 *file)
828 {
829     FcChar8 *slash;
830
831     slash = FcStrLastSlash (file);
832     if (!slash)
833         return FcStrCopy (file);
834     return FcStrCopy (slash + 1);
835 }
836
837 FcStrSet *
838 FcStrSetCreate (void)
839 {
840     FcStrSet    *set = malloc (sizeof (FcStrSet));
841     if (!set)
842         return 0;
843     FcMemAlloc (FC_MEM_STRSET, sizeof (FcStrSet));
844     set->ref = 1;
845     set->num = 0;
846     set->size = 0;
847     set->strs = 0;
848     return set;
849 }
850
851 static FcBool
852 _FcStrSetAppend (FcStrSet *set, FcChar8 *s)
853 {
854     if (FcStrSetMember (set, s))
855     {
856         FcStrFree (s);
857         return FcTrue;
858     }
859     if (set->num == set->size)
860     {
861         FcChar8 **strs = malloc ((set->size + 2) * sizeof (FcChar8 *));
862
863         if (!strs)
864             return FcFalse;
865         FcMemAlloc (FC_MEM_STRSET, (set->size + 2) * sizeof (FcChar8 *));
866         set->size = set->size + 1;
867         if (set->num)
868             memcpy (strs, set->strs, set->num * sizeof (FcChar8 *));
869         if (set->strs)
870             free (set->strs);
871         set->strs = strs;
872     }
873     set->strs[set->num++] = s;
874     set->strs[set->num] = 0;
875     return FcTrue;
876 }
877
878 FcBool
879 FcStrSetMember (FcStrSet *set, const FcChar8 *s)
880 {
881     int i;
882
883     for (i = 0; i < set->num; i++)
884         if (!FcStrCmp (set->strs[i], s))
885             return FcTrue;
886     return FcFalse;
887 }
888
889 FcBool
890 FcStrSetEqual (FcStrSet *sa, FcStrSet *sb)
891 {
892     int i;
893     if (sa->num != sb->num)
894         return FcFalse;
895     for (i = 0; i < sa->num; i++)
896         if (!FcStrSetMember (sb, sa->strs[i]))
897             return FcFalse;
898     return FcTrue;
899 }
900
901 FcBool
902 FcStrSetAdd (FcStrSet *set, const FcChar8 *s)
903 {
904     FcChar8 *new = FcStrCopy (s);
905     if (!new)
906         return FcFalse;
907     if (!_FcStrSetAppend (set, new))
908     {
909         FcStrFree (new);
910         return FcFalse;
911     }
912     return FcTrue;
913 }
914
915 FcBool
916 FcStrSetAddFilename (FcStrSet *set, const FcChar8 *s)
917 {
918     FcChar8 *new = FcStrCopyFilename (s);
919     if (!new)
920         return FcFalse;
921     if (!_FcStrSetAppend (set, new))
922     {
923         FcStrFree (new);
924         return FcFalse;
925     }
926     return FcTrue;
927 }
928
929 FcBool
930 FcStrSetDel (FcStrSet *set, const FcChar8 *s)
931 {
932     int i;
933
934     for (i = 0; i < set->num; i++)
935         if (!FcStrCmp (set->strs[i], s))
936         {
937             FcStrFree (set->strs[i]);
938             /*
939              * copy remaining string pointers and trailing
940              * NULL
941              */
942             memmove (&set->strs[i], &set->strs[i+1], 
943                      (set->num - i) * sizeof (FcChar8 *));
944             set->num--;
945             return FcTrue;
946         }
947     return FcFalse;
948 }
949
950 void
951 FcStrSetDestroy (FcStrSet *set)
952 {
953     if (--set->ref == 0)
954     {
955         int     i;
956     
957         for (i = 0; i < set->num; i++)
958             FcStrFree (set->strs[i]);
959         FcMemFree (FC_MEM_STRSET, (set->size) * sizeof (FcChar8 *));
960         if (set->strs)
961             free (set->strs);
962         FcMemFree (FC_MEM_STRSET, sizeof (FcStrSet));
963         free (set);
964     }
965 }
966
967 FcStrList *
968 FcStrListCreate (FcStrSet *set)
969 {
970     FcStrList   *list;
971
972     list = malloc (sizeof (FcStrList));
973     if (!list)
974         return 0;
975     FcMemAlloc (FC_MEM_STRLIST, sizeof (FcStrList));
976     list->set = set;
977     set->ref++;
978     list->n = 0;
979     return list;
980 }
981
982 FcChar8 *
983 FcStrListNext (FcStrList *list)
984 {
985     if (list->n >= list->set->num)
986         return 0;
987     return list->set->strs[list->n++];
988 }
989
990 void
991 FcStrListDone (FcStrList *list)
992 {
993     FcStrSetDestroy (list->set);
994     FcMemFree (FC_MEM_STRLIST, sizeof (FcStrList));
995     free (list);
996 }