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