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