1 /*
2 * fontconfig/src/fcstr.c
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 the author(s) not be used in
11 * advertising or publicity pertaining to distribution of the software without
12 * specific, written prior permission. The authors make 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 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL THE AUTHOR(S) 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
31 /* Objects MT-safe for readonly access. */
32
33 FcChar8 *
34 FcStrCopy (const FcChar8 *s)
35 {
36 return FcStrdup (s);
37 }
38
39 static FcChar8 *
40 FcStrMakeTriple (const FcChar8 *s1, const FcChar8 *s2, const FcChar8 *s3)
41 {
42 int s1l = s1 ? strlen ((char *) s1) : 0;
43 int s2l = s2 ? strlen ((char *) s2) : 0;
44 int s3l = s3 ? strlen ((char *) s3) : 0;
45 int l = s1l + 1 + s2l + 1 + s3l + 1;
46 FcChar8 *s = malloc (l);
47
48 if (!s)
49 return 0;
50 if (s1)
51 memcpy (s, s1, s1l + 1);
52 else
53 s[0] = '\0';
54 if (s2)
55 memcpy (s + s1l + 1, s2, s2l + 1);
56 else
57 s[s1l + 1] = '\0';
58 if (s3)
59 memcpy (s + s1l + 1 + s2l + 1, s3, s3l + 1);
60 else
61 s[s1l + 1 + s2l + 1] = '\0';
62 return s;
63 }
64
65 FcChar8 *
66 FcStrPlus (const FcChar8 *s1, const FcChar8 *s2)
67 {
68 int s1l = strlen ((char *) s1);
69 int s2l = strlen ((char *) s2);
70 int l = s1l + s2l + 1;
71 FcChar8 *s = malloc (l);
72
73 if (!s)
74 return 0;
75 memcpy (s, s1, s1l);
76 memcpy (s + s1l, s2, s2l + 1);
77 return s;
78 }
79
80 void
81 FcStrFree (FcChar8 *s)
82 {
83 free (s);
84 }
85
86
87 #include "../fc-case/fccase.h"
88
89 #define FcCaseFoldUpperCount(cf) \
90 ((cf)->method == FC_CASE_FOLD_FULL ? 1 : (cf)->count)
91
92 typedef struct _FcCaseWalker {
93 const FcChar8 *read;
94 const FcChar8 *src;
95 FcChar8 utf8[FC_MAX_CASE_FOLD_CHARS + 1];
96 } FcCaseWalker;
97
98 static void
99 FcStrCaseWalkerInit (const FcChar8 *src, FcCaseWalker *w)
100 {
101 w->src = src;
102 w->read = 0;
103 }
104
105 static FcChar8
106 FcStrCaseWalkerLong (FcCaseWalker *w, FcChar8 r)
107 {
108 FcChar32 ucs4;
109 int slen;
110 int len = strlen((char*)w->src);
111
112 slen = FcUtf8ToUcs4 (w->src - 1, &ucs4, len + 1);
113 if (slen <= 0)
114 return r;
115 if (FC_MIN_FOLD_CHAR <= ucs4 && ucs4 <= FC_MAX_FOLD_CHAR)
116 {
117 int min = 0;
118 int max = FC_NUM_CASE_FOLD;
119
120 while (min <= max)
121 {
122 int mid = (min + max) >> 1;
123 FcChar32 low = fcCaseFold[mid].upper;
124 FcChar32 high = low + FcCaseFoldUpperCount (&fcCaseFold[mid]);
125
126 if (high <= ucs4)
127 min = mid + 1;
128 else if (ucs4 < low)
129 max = mid - 1;
130 else
131 {
132 const FcCaseFold *fold = &fcCaseFold[mid];
133 int dlen;
134
135 switch (fold->method) {
136 case FC_CASE_FOLD_EVEN_ODD:
137 if ((ucs4 & 1) != (fold->upper & 1))
138 return r;
139 /* fall through ... */
140 default:
141 dlen = FcUcs4ToUtf8 (ucs4 + fold->offset, w->utf8);
142 break;
143 case FC_CASE_FOLD_FULL:
144 dlen = fold->count;
145 memcpy (w->utf8, fcCaseFoldChars + fold->offset, dlen);
146 break;
147 }
148
149 /* consume rest of src utf-8 bytes */
150 w->src += slen - 1;
151
152 /* read from temp buffer */
153 w->utf8[dlen] = '\0';
154 w->read = w->utf8;
155 return *w->read++;
156 }
157 }
158 }
159 return r;
160 }
161
162 static FcChar8
163 FcStrCaseWalkerNextNonDelim (FcCaseWalker *w, const char *delims)
164 {
165 FcChar8 r;
166
167 if (FC_UNLIKELY (w->read != NULL))
168 {
169 if ((r = *w->read++))
170 return r;
171 w->read = 0;
172 }
173 do
174 {
175 r = *w->src++;
176 } while (r != 0 && delims && strchr (delims, r));
177
178 if (FC_UNLIKELY ((r & 0xc0) == 0xc0))
179 return FcStrCaseWalkerLong (w, r);
180 if ('A' <= r && r <= 'Z')
181 r = r - 'A' + 'a';
182 return r;
183 }
184
185 static FcChar8
186 FcStrCaseWalkerNextNonBlank (FcCaseWalker *w)
187 {
188 FcChar8 r;
189
190 if (FC_UNLIKELY (w->read != NULL))
191 {
192 if ((r = *w->read++))
193 return r;
194 w->read = 0;
195 }
196 do
197 {
198 r = *w->src++;
199 } while (r == ' ');
200
201 if (FC_UNLIKELY ((r & 0xc0) == 0xc0))
202 return FcStrCaseWalkerLong (w, r);
203 if ('A' <= r && r <= 'Z')
204 r = r - 'A' + 'a';
205 return r;
206 }
207
208 static FcChar8
209 FcStrCaseWalkerNext (FcCaseWalker *w)
210 {
211 FcChar8 r;
212
213 if (FC_UNLIKELY (w->read != NULL))
214 {
215 if ((r = *w->read++))
216 return r;
217 w->read = 0;
218 }
219
220 r = *w->src++;
221
222 if (FC_UNLIKELY ((r & 0xc0) == 0xc0))
223 return FcStrCaseWalkerLong (w, r);
224 if ('A' <= r && r <= 'Z')
225 r = r - 'A' + 'a';
226 return r;
227 }
228
229 FcChar8 *
230 FcStrDowncase (const FcChar8 *s)
231 {
232 FcCaseWalker w;
233 int len = 0;
234 FcChar8 *dst, *d;
235
236 FcStrCaseWalkerInit (s, &w);
237 while (FcStrCaseWalkerNext (&w))
238 len++;
239 d = dst = malloc (len + 1);
240 if (!d)
241 return 0;
242 FcStrCaseWalkerInit (s, &w);
243 while ((*d++ = FcStrCaseWalkerNext (&w)));
244 return dst;
245 }
246
247 int
248 FcStrCmpIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
249 {
250 FcCaseWalker w1, w2;
251 FcChar8 c1, c2;
252
253 if (s1 == s2) return 0;
254
255 FcStrCaseWalkerInit (s1, &w1);
256 FcStrCaseWalkerInit (s2, &w2);
257
258 for (;;)
259 {
260 c1 = FcStrCaseWalkerNext (&w1);
261 c2 = FcStrCaseWalkerNext (&w2);
262 if (!c1 || (c1 != c2))
263 break;
264 }
265 return (int) c1 - (int) c2;
266 }
267
268 int
269 FcStrCmpIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2)
270 {
271 FcCaseWalker w1, w2;
272 FcChar8 c1, c2;
273
274 if (s1 == s2) return 0;
275
276 FcStrCaseWalkerInit (s1, &w1);
277 FcStrCaseWalkerInit (s2, &w2);
278
279 for (;;)
280 {
281 c1 = FcStrCaseWalkerNextNonBlank (&w1);
282 c2 = FcStrCaseWalkerNextNonBlank (&w2);
283 if (!c1 || (c1 != c2))
284 break;
285 }
286 return (int) c1 - (int) c2;
287 }
288
289 int
290 FcStrCmp (const FcChar8 *s1, const FcChar8 *s2)
291 {
292 FcChar8 c1, c2;
293
294 if (s1 == s2)
295 return 0;
296 for (;;)
297 {
298 c1 = *s1++;
299 c2 = *s2++;
300 if (!c1 || c1 != c2)
301 break;
302 }
303 return (int) c1 - (int) c2;
304 }
305
306 /*
307 * Return a hash value for a string
308 */
309
310 FcChar32
311 FcStrHashIgnoreCase (const FcChar8 *s)
312 {
313 FcChar32 h = 0;
314 FcCaseWalker w;
315 FcChar8 c;
316
317 FcStrCaseWalkerInit (s, &w);
318 while ((c = FcStrCaseWalkerNext (&w)))
319 h = ((h << 3) ^ (h >> 3)) ^ c;
320 return h;
321 }
322
323 FcChar32
324 FcStrHashIgnoreBlanksAndCase (const FcChar8 *s)
325 {
326 FcChar32 h = 0;
327 FcCaseWalker w;
328 FcChar8 c;
329
330 FcStrCaseWalkerInit (s, &w);
331 while ((c = FcStrCaseWalkerNextNonBlank (&w)))
332 h = ((h << 3) ^ (h >> 3)) ^ c;
333 return h;
334 }
335
336 /*
337 * Is the head of s1 equal to s2?
338 */
339
340 static FcBool
341 FcStrIsAtIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2)
342 {
343 FcCaseWalker w1, w2;
344 FcChar8 c1, c2;
345
346 FcStrCaseWalkerInit (s1, &w1);
347 FcStrCaseWalkerInit (s2, &w2);
348
349 for (;;)
350 {
351 c1 = FcStrCaseWalkerNextNonBlank (&w1);
352 c2 = FcStrCaseWalkerNextNonBlank (&w2);
353 if (!c1 || (c1 != c2))
354 break;
355 }
356 return c1 == c2 || !c2;
357 }
358
359 /*
360 * Does s1 contain an instance of s2 (ignoring blanks and case)?
361 */
362
363 const FcChar8 *
364 FcStrContainsIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2)
365 {
366 while (*s1)
367 {
368 if (FcStrIsAtIgnoreBlanksAndCase (s1, s2))
369 return s1;
370 s1++;
371 }
372 return 0;
373 }
374
375 static FcBool
376 FcCharIsPunct (const FcChar8 c)
377 {
378 if (c < '0')
379 return FcTrue;
380 if (c <= '9')
381 return FcFalse;
382 if (c < 'A')
383 return FcTrue;
384 if (c <= 'Z')
385 return FcFalse;
386 if (c < 'a')
387 return FcTrue;
388 if (c <= 'z')
389 return FcFalse;
390 if (c <= '~')
391 return FcTrue;
392 return FcFalse;
393 }
394
395 /*
396 * Is the head of s1 equal to s2?
397 */
398
399 static FcBool
400 FcStrIsAtIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
401 {
402 FcCaseWalker w1, w2;
403 FcChar8 c1, c2;
404
405 FcStrCaseWalkerInit (s1, &w1);
406 FcStrCaseWalkerInit (s2, &w2);
407
408 for (;;)
409 {
410 c1 = FcStrCaseWalkerNext (&w1);
411 c2 = FcStrCaseWalkerNext (&w2);
412 if (!c1 || (c1 != c2))
413 break;
414 }
415 return c1 == c2 || !c2;
416 }
417
418 /*
419 * Does s1 contain an instance of s2 (ignoring blanks and case)?
420 */
421
422 const FcChar8 *
423 FcStrContainsIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
424 {
425 while (*s1)
426 {
427 if (FcStrIsAtIgnoreCase (s1, s2))
428 return s1;
429 s1++;
430 }
431 return 0;
432 }
433
434 /*
435 * Does s1 contain an instance of s2 on a word boundary (ignoring case)?
436 */
437
438 const FcChar8 *
439 FcStrContainsWord (const FcChar8 *s1, const FcChar8 *s2)
440 {
441 FcBool wordStart = FcTrue;
442 int s1len = strlen ((char *) s1);
443 int s2len = strlen ((char *) s2);
444
445 while (s1len >= s2len)
446 {
447 if (wordStart &&
448 FcStrIsAtIgnoreCase (s1, s2) &&
449 (s1len == s2len || FcCharIsPunct (s1[s2len])))
450 {
451 return s1;
452 }
453 wordStart = FcFalse;
454 if (FcCharIsPunct (*s1))
455 wordStart = FcTrue;
456 s1++;
457 s1len--;
458 }
459 return 0;
460 }
461
462 /*
463 * returns the number of strings (ignoring delimiters and case) being matched
464 */
465
466 int
467 FcStrMatchIgnoreCaseAndDelims (const FcChar8 *s1, const FcChar8 *s2, const FcChar8 *delims)
468 {
469 FcCaseWalker w1, w2;
470 FcChar8 c1, c2;
471
472 if (s1 == s2) return 0;
473
474 FcStrCaseWalkerInit (s1, &w1);
475 FcStrCaseWalkerInit (s2, &w2);
476
477 for (;;)
478 {
479 c1 = FcStrCaseWalkerNextNonDelim (&w1, (const char *)delims);
480 c2 = FcStrCaseWalkerNextNonDelim (&w2, (const char *)delims);
481 if (!c1 || (c1 != c2))
482 break;
483 }
484 return w1.src - s1 - 1;
485 }
486
487 FcBool
488 FcStrGlobMatch (const FcChar8 *glob,
489 const FcChar8 *string)
490 {
491 FcChar8 c;
492
493 while ((c = *glob++))
494 {
495 switch (c) {
496 case '*':
497 /* short circuit common case */
498 if (!*glob)
499 return FcTrue;
500 /* short circuit another common case */
501 if (strchr ((char *) glob, '*') == 0)
502 {
503 size_t l1, l2;
504
505 l1 = strlen ((char *) string);
506 l2 = strlen ((char *) glob);
507 if (l1 < l2)
508 return FcFalse;
509 string += (l1 - l2);
510 }
511 while (*string)
512 {
513 if (FcStrGlobMatch (glob, string))
514 return FcTrue;
515 string++;
516 }
517 return FcFalse;
518 case '?':
519 if (*string++ == '\0')
520 return FcFalse;
521 break;
522 default:
523 if (*string++ != c)
524 return FcFalse;
525 break;
526 }
527 }
528 return *string == '\0';
529 }
530
531 const FcChar8 *
532 FcStrStrIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
533 {
534 FcCaseWalker w1, w2;
535 FcChar8 c1, c2;
536 const FcChar8 *cur;
537
538 if (!s1 || !s2)
539 return 0;
540
541 if (s1 == s2)
542 return s1;
543
544 FcStrCaseWalkerInit (s1, &w1);
545 FcStrCaseWalkerInit (s2, &w2);
546
547 c2 = FcStrCaseWalkerNext (&w2);
548
549 for (;;)
550 {
551 cur = w1.src;
552 c1 = FcStrCaseWalkerNext (&w1);
553 if (!c1)
554 break;
555 if (c1 == c2)
556 {
557 FcCaseWalker w1t = w1;
558 FcCaseWalker w2t = w2;
559 FcChar8 c1t, c2t;
560
561 for (;;)
562 {
563 c1t = FcStrCaseWalkerNext (&w1t);
564 c2t = FcStrCaseWalkerNext (&w2t);
565
566 if (!c2t)
567 return cur;
568 if (c2t != c1t)
569 break;
570 }
571 }
572 }
573 return 0;
574 }
575
576 const FcChar8 *
577 FcStrStr (const FcChar8 *s1, const FcChar8 *s2)
578 {
579 FcChar8 c1, c2;
580 const FcChar8 * p = s1;
581 const FcChar8 * b = s2;
582
583 if (!s1 || !s2)
584 return 0;
585
586 if (s1 == s2)
587 return s1;
588
589 again:
590 c2 = *s2++;
591
592 if (!c2)
593 return 0;
594
595 for (;;)
596 {
597 p = s1;
598 c1 = *s1++;
599 if (!c1 || c1 == c2)
600 break;
601 }
602
603 if (c1 != c2)
604 return 0;
605
606 for (;;)
607 {
608 c1 = *s1;
609 c2 = *s2;
610 if (c1 && c2 && c1 != c2)
611 {
612 s1 = p + 1;
613 s2 = b;
614 goto again;
615 }
616 if (!c2)
617 return p;
618 if (!c1)
619 return 0;
620 ++ s1;
621 ++ s2;
622 }
623 /* never reached. */
624 }
625
626 int
627 FcUtf8ToUcs4 (const FcChar8 *src_orig,
628 FcChar32 *dst,
629 int len)
630 {
631 const FcChar8 *src = src_orig;
632 FcChar8 s;
633 int extra;
634 FcChar32 result;
635
636 if (len == 0)
637 return 0;
638
639 s = *src++;
640 len--;
641
642 if (!(s & 0x80))
643 {
644 result = s;
645 extra = 0;
646 }
647 else if (!(s & 0x40))
648 {
649 return -1;
650 }
651 else if (!(s & 0x20))
652 {
653 result = s & 0x1f;
654 extra = 1;
655 }
656 else if (!(s & 0x10))
657 {
658 result = s & 0xf;
659 extra = 2;
660 }
661 else if (!(s & 0x08))
662 {
663 result = s & 0x07;
664 extra = 3;
665 }
666 else if (!(s & 0x04))
667 {
668 result = s & 0x03;
669 extra = 4;
670 }
671 else if ( ! (s & 0x02))
672 {
673 result = s & 0x01;
674 extra = 5;
675 }
676 else
677 {
678 return -1;
679 }
680 if (extra > len)
681 return -1;
682
683 while (extra--)
684 {
685 result <<= 6;
686 s = *src++;
687
688 if ((s & 0xc0) != 0x80)
689 return -1;
690
691 result |= s & 0x3f;
692 }
693 *dst = result;
694 return src - src_orig;
695 }
696
697 FcBool
698 FcUtf8Len (const FcChar8 *string,
699 int len,
700 int *nchar,
701 int *wchar)
702 {
703 int n;
704 int clen;
705 FcChar32 c;
706 FcChar32 max;
707
708 n = 0;
709 max = 0;
710 while (len)
711 {
712 clen = FcUtf8ToUcs4 (string, &c, len);
713 if (clen <= 0) /* malformed UTF8 string */
714 return FcFalse;
715 if (c > max)
716 max = c;
717 string += clen;
718 len -= clen;
719 n++;
720 }
721 *nchar = n;
722 if (max >= 0x10000)
723 *wchar = 4;
724 else if (max > 0x100)
725 *wchar = 2;
726 else
727 *wchar = 1;
728 return FcTrue;
729 }
730
731 int
732 FcUcs4ToUtf8 (FcChar32 ucs4,
733 FcChar8 dest[FC_UTF8_MAX_LEN])
734 {
735 int bits;
736 FcChar8 *d = dest;
737
738 if (ucs4 < 0x80) { *d++= ucs4; bits= -6; }
739 else if (ucs4 < 0x800) { *d++= ((ucs4 >> 6) & 0x1F) | 0xC0; bits= 0; }
740 else if (ucs4 < 0x10000) { *d++= ((ucs4 >> 12) & 0x0F) | 0xE0; bits= 6; }
741 else if (ucs4 < 0x200000) { *d++= ((ucs4 >> 18) & 0x07) | 0xF0; bits= 12; }
742 else if (ucs4 < 0x4000000) { *d++= ((ucs4 >> 24) & 0x03) | 0xF8; bits= 18; }
743 else if (ucs4 < 0x80000000) { *d++= ((ucs4 >> 30) & 0x01) | 0xFC; bits= 24; }
744 else return 0;
745
746 for ( ; bits >= 0; bits-= 6) {
747 *d++= ((ucs4 >> bits) & 0x3F) | 0x80;
748 }
749 return d - dest;
750 }
751
752 #define GetUtf16(src,endian) \
753 ((FcChar16) ((src)[endian == FcEndianBig ? 0 : 1] << 8) | \
754 (FcChar16) ((src)[endian == FcEndianBig ? 1 : 0]))
755
756 int
757 FcUtf16ToUcs4 (const FcChar8 *src_orig,
758 FcEndian endian,
759 FcChar32 *dst,
760 int len) /* in bytes */
761 {
762 const FcChar8 *src = src_orig;
763 FcChar16 a, b;
764 FcChar32 result;
765
766 if (len < 2)
767 return 0;
768
769 a = GetUtf16 (src, endian); src += 2; len -= 2;
770
771 /*
772 * Check for surrogate
773 */
774 if ((a & 0xfc00) == 0xd800)
775 {
776 if (len < 2)
777 return 0;
778 b = GetUtf16 (src, endian); src += 2; len -= 2;
779 /*
780 * Check for invalid surrogate sequence
781 */
782 if ((b & 0xfc00) != 0xdc00)
783 return 0;
784 result = ((((FcChar32) a & 0x3ff) << 10) |
785 ((FcChar32) b & 0x3ff)) + 0x10000;
786 }
787 else
788 result = a;
789 *dst = result;
790 return src - src_orig;
791 }
792
793 FcBool
794 FcUtf16Len (const FcChar8 *string,
795 FcEndian endian,
796 int len, /* in bytes */
797 int *nchar,
798 int *wchar)
799 {
800 int n;
801 int clen;
802 FcChar32 c;
803 FcChar32 max;
804
805 n = 0;
806 max = 0;
807 while (len)
808 {
809 clen = FcUtf16ToUcs4 (string, endian, &c, len);
810 if (clen <= 0) /* malformed UTF8 string */
811 return FcFalse;
812 if (c > max)
813 max = c;
814 string += clen;
815 len -= clen;
816 n++;
817 }
818 *nchar = n;
819 if (max >= 0x10000)
820 *wchar = 4;
821 else if (max > 0x100)
822 *wchar = 2;
823 else
824 *wchar = 1;
825 return FcTrue;
826 }
827
828 void
829 FcStrBufInit (FcStrBuf *buf, FcChar8 *init, int size)
830 {
831 if (init)
832 {
833 buf->buf = init;
834 buf->size = size;
835 } else
836 {
837 buf->buf = buf->buf_static;
838 buf->size = sizeof (buf->buf_static);
839 }
840 buf->allocated = FcFalse;
841 buf->failed = FcFalse;
842 buf->len = 0;
843 }
844
845 void
846 FcStrBufDestroy (FcStrBuf *buf)
847 {
848 if (buf->allocated)
849 {
850 free (buf->buf);
851 FcStrBufInit (buf, 0, 0);
852 }
853 }
854
855 FcChar8 *
856 FcStrBufDone (FcStrBuf *buf)
857 {
858 FcChar8 *ret;
859
860 if (buf->failed)
861 ret = NULL;
862 else
863 ret = malloc (buf->len + 1);
864 if (ret)
865 {
866 memcpy (ret, buf->buf, buf->len);
867 ret[buf->len] = '\0';
868 }
869 FcStrBufDestroy (buf);
870 return ret;
871 }
872
873 FcChar8 *
874 FcStrBufDoneStatic (FcStrBuf *buf)
875 {
876 FcStrBufChar (buf, '\0');
877
878 if (buf->failed)
879 return NULL;
880
881 return buf->buf;
882 }
883
884 FcBool
885 FcStrBufChar (FcStrBuf *buf, FcChar8 c)
886 {
887 if (buf->len == buf->size)
888 {
889 FcChar8 *new;
890 int size;
891
892 if (buf->failed)
893 return FcFalse;
894
895 if (buf->allocated)
896 {
897 size = buf->size * 2;
898 new = realloc (buf->buf, size);
899 }
900 else
901 {
902 size = buf->size + 64;
903 new = malloc (size);
904 if (new)
905 {
906 buf->allocated = FcTrue;
907 memcpy (new, buf->buf, buf->len);
908 }
909 }
910 if (!new)
911 {
912 buf->failed = FcTrue;
913 return FcFalse;
914 }
915 buf->size = size;
916 buf->buf = new;
917 }
918 buf->buf[buf->len++] = c;
919 return FcTrue;
920 }
921
922 FcBool
923 FcStrBufString (FcStrBuf *buf, const FcChar8 *s)
924 {
925 FcChar8 c;
926 while ((c = *s++))
927 if (!FcStrBufChar (buf, c))
928 return FcFalse;
929 return FcTrue;
930 }
931
932 FcBool
933 FcStrBufData (FcStrBuf *buf, const FcChar8 *s, int len)
934 {
935 while (len-- > 0)
936 if (!FcStrBufChar (buf, *s++))
937 return FcFalse;
938 return FcTrue;
939 }
940
941 FcBool
942 FcStrUsesHome (const FcChar8 *s)
943 {
944 return *s == '~';
945 }
946
947 FcBool
948 FcStrIsAbsoluteFilename (const FcChar8 *s)
949 {
950 #ifdef _WIN32
951 if (*s == '\\' ||
952 (isalpha (*s) && s[1] == ':' && (s[2] == '/' || s[2] == '\\')))
953 return FcTrue;
954 #endif
955 return *s == '/';
956 }
957
958 FcChar8 *
959 FcStrBuildFilename (const FcChar8 *path,
960 ...)
961 {
962 va_list ap;
963 FcStrSet *sset;
964 FcStrList *list;
965 FcChar8 *s, *ret = NULL, *p;
966 size_t len = 0;
967
968 if (!path)
969 return NULL;
970
971 sset = FcStrSetCreateEx (FCSS_ALLOW_DUPLICATES | FCSS_GROW_BY_64);
972 if (!sset)
973 return NULL;
974
975 if (!FcStrSetAdd (sset, path))
976 goto bail0;
977
978 va_start (ap, path);
979 while (1)
980 {
981 s = (FcChar8 *)va_arg (ap, FcChar8 *);
982 if (!s)
983 break;
984 if (!FcStrSetAdd (sset, s))
985 goto bail1;
986 }
987 list = FcStrListCreate (sset);
988 while ((s = FcStrListNext (list)))
989 {
990 len += strlen ((const char *)s) + 1;
991 }
992 list->n = 0;
993 ret = malloc (sizeof (FcChar8) * (len + 1));
994 if (!ret)
995 goto bail2;
996 p = ret;
997 while ((s = FcStrListNext (list)))
998 {
999 if (p != ret)
1000 {
1001 p[0] = FC_DIR_SEPARATOR;
1002 p++;
1003 }
1004 len = strlen ((const char *)s);
1005 memcpy (p, s, len);
1006 p += len;
1007 }
1008 *p = 0;
1009
1010 bail2:
1011 FcStrListDone (list);
1012 bail1:
1013 va_end (ap);
1014 bail0:
1015 FcStrSetDestroy (sset);
1016
1017 return ret;
1018 }
1019
1020 FcChar8 *
1021 FcStrCopyFilename (const FcChar8 *s)
1022 {
1023 FcChar8 *new;
1024
1025 if (*s == '~')
1026 {
1027 FcChar8 *home = FcConfigHome ();
1028 FcChar8 *full;
1029 int size;
1030 if (!home)
1031 return NULL;
1032 size = strlen ((char *) home) + strlen ((char *) s);
1033 full = (FcChar8 *) malloc (size + 1);
1034 if (!full)
1035 return NULL;
1036 strcpy ((char *) full, (char *) home);
1037 strcat ((char *) full, (char *) s + 1);
1038 new = FcStrCanonFilename (full);
1039 free (full);
1040 }
1041 else
1042 new = FcStrCanonFilename (s);
1043
1044 return new;
1045 }
1046
1047 FcChar8 *
1048 FcStrLastSlash (const FcChar8 *path)
1049 {
1050 FcChar8 *slash;
1051
1052 slash = (FcChar8 *) strrchr ((const char *) path, '/');
1053 #ifdef _WIN32
1054 {
1055 FcChar8 *backslash;
1056
1057 backslash = (FcChar8 *) strrchr ((const char *) path, '\\');
1058 if (!slash || (backslash && backslash > slash))
1059 slash = backslash;
1060 }
1061 #endif
1062
1063 return slash;
1064 }
1065
1066 FcChar8 *
1067 FcStrDirname (const FcChar8 *file)
1068 {
1069 FcChar8 *slash;
1070 FcChar8 *dir;
1071
1072 slash = FcStrLastSlash (file);
1073 if (!slash)
1074 return FcStrCopy ((FcChar8 *) ".");
1075 dir = malloc ((slash - file) + 1);
1076 if (!dir)
1077 return 0;
1078 strncpy ((char *) dir, (const char *) file, slash - file);
1079 dir[slash - file] = '\0';
1080 return dir;
1081 }
1082
1083 FcChar8 *
1084 FcStrBasename (const FcChar8 *file)
1085 {
1086 FcChar8 *slash;
1087
1088 slash = FcStrLastSlash (file);
1089 if (!slash)
1090 return FcStrCopy (file);
1091 return FcStrCopy (slash + 1);
1092 }
1093
1094 FcChar8 *
1095 FcStrRealPath (const FcChar8 *path)
1096 {
1097 char resolved_name[FC_PATH_MAX+1];
1098 char *resolved_ret;
1099
1100 if (!path)
1101 return NULL;
1102
1103 #ifndef _WIN32
1104 resolved_ret = realpath((const char *) path, resolved_name);
1105 #else
1106 if (GetFullPathNameA ((LPCSTR) path, FC_PATH_MAX, resolved_name, NULL) == 0)
1107 {
1108 fprintf (stderr, "Fontconfig warning: GetFullPathNameA failed.\n");
1109 return NULL;
1110 }
1111 resolved_ret = resolved_name;
1112 #endif
1113 if (resolved_ret)
1114 path = (FcChar8 *) resolved_ret;
1115 return FcStrCopyFilename(path);
1116 }
1117
1118 static FcChar8 *
1119 FcStrCanonAbsoluteFilename (const FcChar8 *s)
1120 {
1121 FcChar8 *file;
1122 FcChar8 *f;
1123 const FcChar8 *slash;
1124 int size;
1125
1126 size = strlen ((char *) s) + 1;
1127 file = malloc (size);
1128 if (!file)
1129 return NULL;
1130 slash = NULL;
1131 f = file;
1132 #ifdef _WIN32
1133 if (*s == '/' && *(s+1) == '/') /* Network path, do not squash // */
1134 *f++ = *s++;
1135 #endif
1136 for (;;) {
1137 if (*s == '/' || *s == '\0')
1138 {
1139 if (slash)
1140 {
1141 switch (s - slash) {
1142 case 1:
1143 f -= 1; /* squash // and trim final / from file */
1144 break;
1145 case 2:
1146 if (!strncmp ((char *) slash, "/.", 2))
1147 {
1148 f -= 2; /* trim /. from file */
1149 }
1150 break;
1151 case 3:
1152 if (!strncmp ((char *) slash, "/..", 3))
1153 {
1154 f -= 3; /* trim /.. from file */
1155 while (f > file) {
1156 if (*--f == '/')
1157 break;
1158 }
1159 }
1160 break;
1161 }
1162 }
1163 slash = s;
1164 }
1165 if (!(*f++ = *s++))
1166 break;
1167 }
1168 return file;
1169 }
1170
1171 #ifdef _WIN32
1172 /*
1173 * Convert '\\' to '/' , remove double '/'
1174 */
1175 static void
1176 FcConvertDosPath (char *str)
1177 {
1178 size_t len = strlen (str);
1179 char *p = str;
1180 char *dest = str;
1181 char *end = str + len;
1182 char last = 0;
1183
1184 if (*p == '\\')
1185 {
1186 *p = '/';
1187 p++;
1188 dest++;
1189 }
1190 while (p < end)
1191 {
1192 if (*p == '\\')
1193 *p = '/';
1194
1195 if (*p != '/'
1196 || last != '/')
1197 {
1198 *dest++ = *p;
1199 }
1200
1201 last = *p;
1202 p++;
1203 }
1204
1205 *dest = 0;
1206 }
1207 #endif
1208
1209 FcChar8 *
1210 FcStrCanonFilename (const FcChar8 *s)
1211 {
1212 #ifdef _WIN32
1213 FcChar8 full[FC_MAX_FILE_LEN + 2];
1214 int size = GetFullPathName ((LPCSTR) s, sizeof (full) -1,
1215 (LPSTR) full, NULL);
1216
1217 if (size == 0)
1218 perror ("GetFullPathName");
1219
1220 FcConvertDosPath ((char *) full);
1221 return FcStrCanonAbsoluteFilename (full);
1222 #else
1223 if (s[0] == '/')
1224 return FcStrCanonAbsoluteFilename (s);
1225 else
1226 {
1227 FcChar8 *full;
1228 FcChar8 *file;
1229
1230 FcChar8 cwd[FC_MAX_FILE_LEN + 2];
1231 if (getcwd ((char *) cwd, FC_MAX_FILE_LEN) == NULL)
1232 return NULL;
1233 full = FcStrBuildFilename (cwd, s, NULL);
1234 file = FcStrCanonAbsoluteFilename (full);
1235 FcStrFree (full);
1236 return file;
1237 }
1238 #endif
1239 }
1240
1241
1242 FcStrSet *
1243 FcStrSetCreate (void)
1244 {
1245 return FcStrSetCreateEx (FCSS_DEFAULT);
1246 }
1247
1248 FcStrSet *
1249 FcStrSetCreateEx (unsigned int control)
1250 {
1251 FcStrSet *set = malloc (sizeof (FcStrSet));
1252 if (!set)
1253 return 0;
1254 FcRefInit (&set->ref, 1);
1255 set->num = 0;
1256 set->size = 0;
1257 set->strs = 0;
1258 set->control = control;
1259 return set;
1260 }
1261
1262 static FcBool
1263 _FcStrSetGrow (FcStrSet *set, int growElements)
1264 {
1265 /* accommodate an additional NULL entry at the end of the array */
1266 FcChar8 **strs = malloc ((set->size + growElements + 1) * sizeof (FcChar8 *));
1267 if (!strs)
1268 return FcFalse;
1269 if (set->num)
1270 memcpy (strs, set->strs, set->num * sizeof (FcChar8 *));
1271 if (set->strs)
1272 free (set->strs);
1273 set->size = set->size + growElements;
1274 set->strs = strs;
1275 return FcTrue;
1276 }
1277
1278 static FcBool
1279 _FcStrSetInsert (FcStrSet *set, FcChar8 *s, int pos)
1280 {
1281 if (!FcStrSetHasControlBit (set, FCSS_ALLOW_DUPLICATES))
1282 {
1283 if (FcStrSetMember (set, s))
1284 {
1285 FcStrFree (s);
1286 return FcTrue;
1287 }
1288 }
1289 if (set->num == set->size)
1290 {
1291 int growElements = FcStrSetHasControlBit (set, FCSS_GROW_BY_64) ? 64 : 1;
1292 if (!_FcStrSetGrow(set, growElements))
1293 return FcFalse;
1294 }
1295 if (pos >= set->num)
1296 {
1297 set->strs[set->num++] = s;
1298 set->strs[set->num] = 0;
1299 }
1300 else
1301 {
1302 int i;
1303
1304 set->num++;
1305 set->strs[set->num] = 0;
1306 for (i = set->num - 1; i > pos; i--)
1307 set->strs[i] = set->strs[i - 1];
1308 set->strs[pos] = s;
1309 }
1310 return FcTrue;
1311 }
1312
1313 FcBool
1314 FcStrSetMember (FcStrSet *set, const FcChar8 *s)
1315 {
1316 int i;
1317
1318 for (i = 0; i < set->num; i++)
1319 if (!FcStrCmp (set->strs[i], s))
1320 return FcTrue;
1321 return FcFalse;
1322 }
1323
1324 static int
1325 fc_strcmp_r (const FcChar8 *s1, const FcChar8 *s2, const FcChar8 **ret)
1326 {
1327 FcChar8 c1, c2;
1328
1329 if (s1 == s2)
1330 {
1331 if (ret)
1332 *ret = NULL;
1333 return 0;
1334 }
1335 for (;;)
1336 {
1337 if (s1)
1338 c1 = *s1++;
1339 else
1340 c1 = 0;
1341 if (s2)
1342 c2 = *s2++;
1343 else
1344 c2 = 0;
1345 if (!c1 || c1 != c2)
1346 break;
1347 }
1348 if (ret)
1349 *ret = s1;
1350 return (int) c1 - (int) c2;
1351 }
1352
1353 FcBool
1354 FcStrSetMemberAB (FcStrSet *set, const FcChar8 *a, FcChar8 *b, FcChar8 **ret)
1355 {
1356 int i;
1357 const FcChar8 *s = NULL;
1358
1359 for (i = 0; i < set->num; i++)
1360 {
1361 if (!fc_strcmp_r (set->strs[i], a, &s) && s)
1362 {
1363 if (!fc_strcmp_r (s, b, NULL))
1364 {
1365 if (ret)
1366 *ret = set->strs[i];
1367 return FcTrue;
1368 }
1369 }
1370 }
1371 if (ret)
1372 *ret = NULL;
1373 return FcFalse;
1374 }
1375
1376 FcBool
1377 FcStrSetEqual (FcStrSet *sa, FcStrSet *sb)
1378 {
1379 int i;
1380 if (sa->num != sb->num)
1381 return FcFalse;
1382 for (i = 0; i < sa->num; i++)
1383 if (!FcStrSetMember (sb, sa->strs[i]))
1384 return FcFalse;
1385 return FcTrue;
1386 }
1387
1388 FcBool
1389 FcStrSetAdd (FcStrSet *set, const FcChar8 *s)
1390 {
1391 FcChar8 *new = FcStrCopy (s);
1392 if (!new)
1393 return FcFalse;
1394 if (!_FcStrSetInsert (set, new, set->num))
1395 {
1396 FcStrFree (new);
1397 return FcFalse;
1398 }
1399 return FcTrue;
1400 }
1401
1402 FcBool
1403 FcStrSetInsert (FcStrSet *set, const FcChar8 *s, int pos)
1404 {
1405 FcChar8 *new = FcStrCopy (s);
1406 if (!new)
1407 return FcFalse;
1408 if (!_FcStrSetInsert (set, new, pos))
1409 {
1410 FcStrFree (new);
1411 return FcFalse;
1412 }
1413 return FcTrue;
1414 }
1415
1416 FcBool
1417 FcStrSetAddTriple (FcStrSet *set, const FcChar8 *a, const FcChar8 *b, const FcChar8 *c)
1418 {
1419 FcChar8 *new = FcStrMakeTriple (a, b, c);
1420 if (!new)
1421 return FcFalse;
1422 if (!_FcStrSetInsert (set, new, set->num))
1423 {
1424 FcStrFree (new);
1425 return FcFalse;
1426 }
1427 return FcTrue;
1428 }
1429
1430 const FcChar8 *
1431 FcStrTripleSecond (FcChar8 *str)
1432 {
1433 FcChar8 *second = str + strlen((char *) str) + 1;
1434
1435 if (*second == '\0')
1436 return 0;
1437 return second;
1438 }
1439
1440 const FcChar8 *
1441 FcStrTripleThird (FcChar8 *str)
1442 {
1443 FcChar8 *second = str + strlen ((char *) str) + 1;
1444 FcChar8 *third = second + strlen ((char *) second) + 1;
1445
1446 if (*third == '\0')
1447 return 0;
1448 return third;
1449 }
1450
1451 FcBool
1452 FcStrSetAddFilename (FcStrSet *set, const FcChar8 *s)
1453 {
1454 FcChar8 *new = FcStrCopyFilename (s);
1455 if (!new)
1456 return FcFalse;
1457 if (!_FcStrSetInsert (set, new, set->num))
1458 {
1459 FcStrFree (new);
1460 return FcFalse;
1461 }
1462 return FcTrue;
1463 }
1464
1465 FcBool
1466 FcStrSetAddFilenamePairWithSalt (FcStrSet *set, const FcChar8 *a, const FcChar8 *b, const FcChar8 *salt)
1467 {
1468 FcChar8 *new_a = NULL;
1469 FcChar8 *new_b = NULL;
1470 FcBool ret;
1471
1472 if (a)
1473 {
1474 new_a = FcStrCopyFilename (a);
1475 if (!new_a)
1476 return FcFalse;
1477 }
1478 if (b)
1479 {
1480 new_b = FcStrCopyFilename(b);
1481 if (!new_b)
1482 {
1483 if (new_a)
1484 FcStrFree(new_a);
1485 return FcFalse;
1486 }
1487 }
1488 /* Override maps with new one if exists */
1489 FcStrSetDel (set, new_a);
1490 ret = FcStrSetAddTriple (set, new_a, new_b, salt);
1491 if (new_a)
1492 FcStrFree (new_a);
1493 if (new_b)
1494 FcStrFree (new_b);
1495 return ret;
1496 }
1497
1498 FcBool
1499 FcStrSetAddLangs (FcStrSet *strs, const char *languages)
1500 {
1501 const char *p = languages, *next;
1502 FcChar8 lang[128] = {0}, *normalized_lang;
1503 size_t len;
1504 FcBool ret = FcFalse;
1505
1506 if (!languages)
1507 return FcFalse;
1508
1509 while ((next = strchr (p, ':')))
1510 {
1511 len = next - p;
1512 len = FC_MIN (len, 127);
1513 strncpy ((char *) lang, p, len);
1514 lang[len] = 0;
1515 /* ignore an empty item */
1516 if (*lang)
1517 {
1518 normalized_lang = FcLangNormalize ((const FcChar8 *) lang);
1519 if (normalized_lang)
1520 {
1521 FcStrSetAdd (strs, normalized_lang);
1522 FcStrFree (normalized_lang);
1523 ret = FcTrue;
1524 }
1525 }
1526 p = next + 1;
1527 }
1528 if (*p)
1529 {
1530 normalized_lang = FcLangNormalize ((const FcChar8 *) p);
1531 if (normalized_lang)
1532 {
1533 FcStrSetAdd (strs, normalized_lang);
1534 FcStrFree (normalized_lang);
1535 ret = FcTrue;
1536 }
1537 }
1538
1539 return ret;
1540 }
1541
1542 FcBool
1543 FcStrSetDel (FcStrSet *set, const FcChar8 *s)
1544 {
1545 int i;
1546
1547 for (i = 0; i < set->num; i++)
1548 if (!FcStrCmp (set->strs[i], s))
1549 {
1550 FcStrFree (set->strs[i]);
1551 /*
1552 * copy remaining string pointers and trailing
1553 * NULL
1554 */
1555 memmove (&set->strs[i], &set->strs[i+1],
1556 (set->num - i) * sizeof (FcChar8 *));
1557 set->num--;
1558 return FcTrue;
1559 }
1560 return FcFalse;
1561 }
1562
1563 FcBool
1564 FcStrSetDeleteAll (FcStrSet *set)
1565 {
1566 int i;
1567
1568 if (FcRefIsConst (&set->ref))
1569 return FcFalse;
1570
1571 for (i = set->num; i > 0; i--)
1572 {
1573 FcStrFree (set->strs[i - 1]);
1574 set->num--;
1575 }
1576 return FcTrue;
1577 }
1578
1579 /* TODO Make public */
1580 static FcStrSet *
1581 FcStrSetReference (FcStrSet *set)
1582 {
1583 if (FcRefIsConst (&set->ref))
1584 return set;
1585
1586 FcRefInc (&set->ref);
1587 return set;
1588 }
1589
1590 void
1591 FcStrSetDestroy (FcStrSet *set)
1592 {
1593 if (set)
1594 {
1595 int i;
1596
1597 /* We rely on this in FcGetDefaultLangs for caching. */
1598 if (FcRefIsConst (&set->ref))
1599 return;
1600
1601 if (FcRefDec (&set->ref) != 1)
1602 return;
1603
1604 for (i = 0; i < set->num; i++)
1605 FcStrFree (set->strs[i]);
1606 if (set->strs)
1607 free (set->strs);
1608 free (set);
1609 }
1610 }
1611
1612 FcStrList *
1613 FcStrListCreate (FcStrSet *set)
1614 {
1615 FcStrList *list;
1616
1617 list = malloc (sizeof (FcStrList));
1618 if (!list)
1619 return 0;
1620 list->set = set;
1621 FcStrSetReference (set);
1622 list->n = 0;
1623 return list;
1624 }
1625
1626 void
1627 FcStrListFirst (FcStrList *list)
1628 {
1629 list->n = 0;
1630 }
1631
1632 FcChar8 *
1633 FcStrListNext (FcStrList *list)
1634 {
1635 if (list->n >= list->set->num)
1636 return 0;
1637 return list->set->strs[list->n++];
1638 }
1639
1640 void
1641 FcStrListDone (FcStrList *list)
1642 {
1643 FcStrSetDestroy (list->set);
1644 free (list);
1645 }
1646
1647 #define __fcstr__
1648 #include "fcaliastail.h"
1649 #undef __fcstr__