]> git.wh0rd.org - fontconfig.git/blob - src/fcstr.c
Include $(top_srcdir), $(top_srcdir)/src before anything else.
[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 "fcint.h"
26 #include <stdlib.h>
27 #include <ctype.h>
28 #include <string.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 /* never reached. */
453 }
454
455 int
456 FcUtf8ToUcs4 (const FcChar8 *src_orig,
457 FcChar32 *dst,
458 int len)
459 {
460 const FcChar8 *src = src_orig;
461 FcChar8 s;
462 int extra;
463 FcChar32 result;
464
465 if (len == 0)
466 return 0;
467
468 s = *src++;
469 len--;
470
471 if (!(s & 0x80))
472 {
473 result = s;
474 extra = 0;
475 }
476 else if (!(s & 0x40))
477 {
478 return -1;
479 }
480 else if (!(s & 0x20))
481 {
482 result = s & 0x1f;
483 extra = 1;
484 }
485 else if (!(s & 0x10))
486 {
487 result = s & 0xf;
488 extra = 2;
489 }
490 else if (!(s & 0x08))
491 {
492 result = s & 0x07;
493 extra = 3;
494 }
495 else if (!(s & 0x04))
496 {
497 result = s & 0x03;
498 extra = 4;
499 }
500 else if ( ! (s & 0x02))
501 {
502 result = s & 0x01;
503 extra = 5;
504 }
505 else
506 {
507 return -1;
508 }
509 if (extra > len)
510 return -1;
511
512 while (extra--)
513 {
514 result <<= 6;
515 s = *src++;
516
517 if ((s & 0xc0) != 0x80)
518 return -1;
519
520 result |= s & 0x3f;
521 }
522 *dst = result;
523 return src - src_orig;
524 }
525
526 FcBool
527 FcUtf8Len (const FcChar8 *string,
528 int len,
529 int *nchar,
530 int *wchar)
531 {
532 int n;
533 int clen;
534 FcChar32 c;
535 FcChar32 max;
536
537 n = 0;
538 max = 0;
539 while (len)
540 {
541 clen = FcUtf8ToUcs4 (string, &c, len);
542 if (clen <= 0) /* malformed UTF8 string */
543 return FcFalse;
544 if (c > max)
545 max = c;
546 string += clen;
547 len -= clen;
548 n++;
549 }
550 *nchar = n;
551 if (max >= 0x10000)
552 *wchar = 4;
553 else if (max > 0x100)
554 *wchar = 2;
555 else
556 *wchar = 1;
557 return FcTrue;
558 }
559
560 int
561 FcUcs4ToUtf8 (FcChar32 ucs4,
562 FcChar8 dest[FC_UTF8_MAX_LEN])
563 {
564 int bits;
565 FcChar8 *d = dest;
566
567 if (ucs4 < 0x80) { *d++= ucs4; bits= -6; }
568 else if (ucs4 < 0x800) { *d++= ((ucs4 >> 6) & 0x1F) | 0xC0; bits= 0; }
569 else if (ucs4 < 0x10000) { *d++= ((ucs4 >> 12) & 0x0F) | 0xE0; bits= 6; }
570 else if (ucs4 < 0x200000) { *d++= ((ucs4 >> 18) & 0x07) | 0xF0; bits= 12; }
571 else if (ucs4 < 0x4000000) { *d++= ((ucs4 >> 24) & 0x03) | 0xF8; bits= 18; }
572 else if (ucs4 < 0x80000000) { *d++= ((ucs4 >> 30) & 0x01) | 0xFC; bits= 24; }
573 else return 0;
574
575 for ( ; bits >= 0; bits-= 6) {
576 *d++= ((ucs4 >> bits) & 0x3F) | 0x80;
577 }
578 return d - dest;
579 }
580
581 #define GetUtf16(src,endian) \
582 ((FcChar16) ((src)[endian == FcEndianBig ? 0 : 1] << 8) | \
583 (FcChar16) ((src)[endian == FcEndianBig ? 1 : 0]))
584
585 int
586 FcUtf16ToUcs4 (const FcChar8 *src_orig,
587 FcEndian endian,
588 FcChar32 *dst,
589 int len) /* in bytes */
590 {
591 const FcChar8 *src = src_orig;
592 FcChar16 a, b;
593 FcChar32 result;
594
595 if (len < 2)
596 return 0;
597
598 a = GetUtf16 (src, endian); src += 2; len -= 2;
599
600 /*
601 * Check for surrogate
602 */
603 if ((a & 0xfc00) == 0xd800)
604 {
605 if (len < 2)
606 return 0;
607 b = GetUtf16 (src, endian); src += 2; len -= 2;
608 /*
609 * Check for invalid surrogate sequence
610 */
611 if ((b & 0xfc00) != 0xdc00)
612 return 0;
613 result = ((((FcChar32) a & 0x3ff) << 10) |
614 ((FcChar32) b & 0x3ff)) + 0x10000;
615 }
616 else
617 result = a;
618 *dst = result;
619 return src - src_orig;
620 }
621
622 FcBool
623 FcUtf16Len (const FcChar8 *string,
624 FcEndian endian,
625 int len, /* in bytes */
626 int *nchar,
627 int *wchar)
628 {
629 int n;
630 int clen;
631 FcChar32 c;
632 FcChar32 max;
633
634 n = 0;
635 max = 0;
636 while (len)
637 {
638 clen = FcUtf16ToUcs4 (string, endian, &c, len);
639 if (clen <= 0) /* malformed UTF8 string */
640 return FcFalse;
641 if (c > max)
642 max = c;
643 string += clen;
644 len -= clen;
645 n++;
646 }
647 *nchar = n;
648 if (max >= 0x10000)
649 *wchar = 4;
650 else if (max > 0x100)
651 *wchar = 2;
652 else
653 *wchar = 1;
654 return FcTrue;
655 }
656
657 void
658 FcStrBufInit (FcStrBuf *buf, FcChar8 *init, int size)
659 {
660 buf->buf = init;
661 buf->allocated = FcFalse;
662 buf->failed = FcFalse;
663 buf->len = 0;
664 buf->size = size;
665 }
666
667 void
668 FcStrBufDestroy (FcStrBuf *buf)
669 {
670 if (buf->allocated)
671 {
672 FcMemFree (FC_MEM_STRBUF, buf->size);
673 free (buf->buf);
674 FcStrBufInit (buf, 0, 0);
675 }
676 }
677
678 FcChar8 *
679 FcStrBufDone (FcStrBuf *buf)
680 {
681 FcChar8 *ret;
682
683 ret = malloc (buf->len + 1);
684 if (ret)
685 {
686 FcMemAlloc (FC_MEM_STRING, buf->len + 1);
687 memcpy (ret, buf->buf, buf->len);
688 ret[buf->len] = '\0';
689 }
690 FcStrBufDestroy (buf);
691 return ret;
692 }
693
694 FcBool
695 FcStrBufChar (FcStrBuf *buf, FcChar8 c)
696 {
697 if (buf->len == buf->size)
698 {
699 FcChar8 *new;
700 int size;
701
702 if (buf->allocated)
703 {
704 size = buf->size * 2;
705 new = realloc (buf->buf, size);
706 }
707 else
708 {
709 size = buf->size + 1024;
710 new = malloc (size);
711 if (new)
712 {
713 buf->allocated = FcTrue;
714 memcpy (new, buf->buf, buf->len);
715 }
716 }
717 if (!new)
718 {
719 buf->failed = FcTrue;
720 return FcFalse;
721 }
722 if (buf->size)
723 FcMemFree (FC_MEM_STRBUF, buf->size);
724 FcMemAlloc (FC_MEM_STRBUF, size);
725 buf->size = size;
726 buf->buf = new;
727 }
728 buf->buf[buf->len++] = c;
729 return FcTrue;
730 }
731
732 FcBool
733 FcStrBufString (FcStrBuf *buf, const FcChar8 *s)
734 {
735 FcChar8 c;
736 while ((c = *s++))
737 if (!FcStrBufChar (buf, c))
738 return FcFalse;
739 return FcTrue;
740 }
741
742 FcBool
743 FcStrBufData (FcStrBuf *buf, const FcChar8 *s, int len)
744 {
745 while (len-- > 0)
746 if (!FcStrBufChar (buf, *s++))
747 return FcFalse;
748 return FcTrue;
749 }
750
751 FcBool
752 FcStrUsesHome (const FcChar8 *s)
753 {
754 return *s == '~';
755 }
756
757 FcChar8 *
758 FcStrCopyFilename (const FcChar8 *s)
759 {
760 FcChar8 *new;
761
762 if (*s == '~')
763 {
764 FcChar8 *home = FcConfigHome ();
765 int size;
766 if (!home)
767 return 0;
768 size = strlen ((char *) home) + strlen ((char *) s);
769 new = (FcChar8 *) malloc (size);
770 if (!new)
771 return 0;
772 FcMemAlloc (FC_MEM_STRING, size);
773 strcpy ((char *) new, (char *) home);
774 strcat ((char *) new, (char *) s + 1);
775 }
776 else
777 {
778 int size = strlen ((char *) s) + 1;
779 new = (FcChar8 *) malloc (size);
780 if (!new)
781 return 0;
782 FcMemAlloc (FC_MEM_STRING, size);
783 strcpy ((char *) new, (const char *) s);
784 }
785 return new;
786 }
787
788 FcChar8 *
789 FcStrLastSlash (const FcChar8 *path)
790 {
791 FcChar8 *slash;
792
793 slash = (FcChar8 *) strrchr ((const char *) path, '/');
794 #ifdef _WIN32
795 {
796 FcChar8 *backslash;
797
798 backslash = (FcChar8 *) strrchr ((const char *) path, '\\');
799 if (!slash || (backslash && backslash > slash))
800 slash = backslash;
801 }
802 #endif
803
804 return slash;
805 }
806
807 FcChar8 *
808 FcStrDirname (const FcChar8 *file)
809 {
810 FcChar8 *slash;
811 FcChar8 *dir;
812
813 slash = FcStrLastSlash (file);
814 if (!slash)
815 return FcStrCopy ((FcChar8 *) ".");
816 dir = malloc ((slash - file) + 1);
817 if (!dir)
818 return 0;
819 FcMemAlloc (FC_MEM_STRING, (slash - file) + 1);
820 strncpy ((char *) dir, (const char *) file, slash - file);
821 dir[slash - file] = '\0';
822 return dir;
823 }
824
825 FcChar8 *
826 FcStrBasename (const FcChar8 *file)
827 {
828 FcChar8 *slash;
829
830 slash = FcStrLastSlash (file);
831 if (!slash)
832 return FcStrCopy (file);
833 return FcStrCopy (slash + 1);
834 }
835
836 FcStrSet *
837 FcStrSetCreate (void)
838 {
839 FcStrSet *set = malloc (sizeof (FcStrSet));
840 if (!set)
841 return 0;
842 FcMemAlloc (FC_MEM_STRSET, sizeof (FcStrSet));
843 set->ref = 1;
844 set->num = 0;
845 set->size = 0;
846 set->strs = 0;
847 return set;
848 }
849
850 static FcBool
851 _FcStrSetAppend (FcStrSet *set, FcChar8 *s)
852 {
853 if (FcStrSetMember (set, s))
854 {
855 FcStrFree (s);
856 return FcTrue;
857 }
858 if (set->num == set->size)
859 {
860 FcChar8 **strs = malloc ((set->size + 2) * sizeof (FcChar8 *));
861
862 if (!strs)
863 return FcFalse;
864 FcMemAlloc (FC_MEM_STRSET, (set->size + 2) * sizeof (FcChar8 *));
865 set->size = set->size + 1;
866 if (set->num)
867 memcpy (strs, set->strs, set->num * sizeof (FcChar8 *));
868 if (set->strs)
869 free (set->strs);
870 set->strs = strs;
871 }
872 set->strs[set->num++] = s;
873 set->strs[set->num] = 0;
874 return FcTrue;
875 }
876
877 FcBool
878 FcStrSetMember (FcStrSet *set, const FcChar8 *s)
879 {
880 int i;
881
882 for (i = 0; i < set->num; i++)
883 if (!FcStrCmp (set->strs[i], s))
884 return FcTrue;
885 return FcFalse;
886 }
887
888 FcBool
889 FcStrSetEqual (FcStrSet *sa, FcStrSet *sb)
890 {
891 int i;
892 if (sa->num != sb->num)
893 return FcFalse;
894 for (i = 0; i < sa->num; i++)
895 if (!FcStrSetMember (sb, sa->strs[i]))
896 return FcFalse;
897 return FcTrue;
898 }
899
900 FcBool
901 FcStrSetAdd (FcStrSet *set, const FcChar8 *s)
902 {
903 FcChar8 *new = FcStrCopy (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 FcStrSetAddFilename (FcStrSet *set, const FcChar8 *s)
916 {
917 FcChar8 *new = FcStrCopyFilename (s);
918 if (!new)
919 return FcFalse;
920 if (!_FcStrSetAppend (set, new))
921 {
922 FcStrFree (new);
923 return FcFalse;
924 }
925 return FcTrue;
926 }
927
928 FcBool
929 FcStrSetDel (FcStrSet *set, const FcChar8 *s)
930 {
931 int i;
932
933 for (i = 0; i < set->num; i++)
934 if (!FcStrCmp (set->strs[i], s))
935 {
936 FcStrFree (set->strs[i]);
937 /*
938 * copy remaining string pointers and trailing
939 * NULL
940 */
941 memmove (&set->strs[i], &set->strs[i+1],
942 (set->num - i) * sizeof (FcChar8 *));
943 set->num--;
944 return FcTrue;
945 }
946 return FcFalse;
947 }
948
949 void
950 FcStrSetDestroy (FcStrSet *set)
951 {
952 if (--set->ref == 0)
953 {
954 int i;
955
956 for (i = 0; i < set->num; i++)
957 FcStrFree (set->strs[i]);
958 FcMemFree (FC_MEM_STRSET, (set->size) * sizeof (FcChar8 *));
959 if (set->strs)
960 free (set->strs);
961 FcMemFree (FC_MEM_STRSET, sizeof (FcStrSet));
962 free (set);
963 }
964 }
965
966 FcStrList *
967 FcStrListCreate (FcStrSet *set)
968 {
969 FcStrList *list;
970
971 list = malloc (sizeof (FcStrList));
972 if (!list)
973 return 0;
974 FcMemAlloc (FC_MEM_STRLIST, sizeof (FcStrList));
975 list->set = set;
976 set->ref++;
977 list->n = 0;
978 return list;
979 }
980
981 FcChar8 *
982 FcStrListNext (FcStrList *list)
983 {
984 if (list->n >= list->set->num)
985 return 0;
986 return list->set->strs[list->n++];
987 }
988
989 void
990 FcStrListDone (FcStrList *list)
991 {
992 FcStrSetDestroy (list->set);
993 FcMemFree (FC_MEM_STRLIST, sizeof (FcStrList));
994 free (list);
995 }