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