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