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