]> git.wh0rd.org - fontconfig.git/blob - src/fcstr.c
FcStrPathPlus: new helper function
[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__