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