]> git.wh0rd.org - fontconfig.git/blob - src/fcstr.c
Change files from ISO-Latin-1 to UTF-8
[fontconfig.git] / src / fcstr.c
1 /*
2 * $RCSId: xc/lib/fontconfig/src/fcstr.c,v 1.10 2002/08/31 22:17:32 keithp Exp $
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 Keith Packard not be used in
11 * advertising or publicity pertaining to distribution of the software without
12 * specific, written prior permission. Keith Packard makes 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 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL KEITH PACKARD 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 <stdlib.h>
26 #include <ctype.h>
27 #include <string.h>
28 #include "fcint.h"
29
30 FcChar8 *
31 FcStrCopy (const FcChar8 *s)
32 {
33 FcChar8 *r;
34
35 if (!s)
36 return 0;
37 r = (FcChar8 *) malloc (strlen ((char *) s) + 1);
38 if (!r)
39 return 0;
40 FcMemAlloc (FC_MEM_STRING, strlen ((char *) s) + 1);
41 strcpy ((char *) r, (char *) s);
42 return r;
43 }
44
45 FcChar8 *
46 FcStrPlus (const FcChar8 *s1, const FcChar8 *s2)
47 {
48 int l = strlen ((char *)s1) + strlen ((char *) s2) + 1;
49 FcChar8 *s = malloc (l);
50
51 if (!s)
52 return 0;
53 FcMemAlloc (FC_MEM_STRING, l);
54 strcpy ((char *) s, (char *) s1);
55 strcat ((char *) s, (char *) s2);
56 return s;
57 }
58
59 void
60 FcStrFree (FcChar8 *s)
61 {
62 FcMemFree (FC_MEM_STRING, strlen ((char *) s) + 1);
63 free (s);
64 }
65
66 int
67 FcStrCmpIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
68 {
69 FcChar8 c1, c2;
70
71 for (;;)
72 {
73 c1 = *s1++;
74 c2 = *s2++;
75 if (!c1 || (c1 != c2 && (c1 = FcToLower(c1)) != (c2 = FcToLower(c2))))
76 break;
77 }
78 return (int) c1 - (int) c2;
79 }
80
81 int
82 FcStrCmpIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2)
83 {
84 FcChar8 c1, c2;
85
86 for (;;)
87 {
88 do
89 c1 = *s1++;
90 while (c1 == ' ');
91 do
92 c2 = *s2++;
93 while (c2 == ' ');
94 if (!c1 || (c1 != c2 && (c1 = FcToLower(c1)) != (c2 = FcToLower(c2))))
95 break;
96 }
97 return (int) c1 - (int) c2;
98 }
99
100 int
101 FcStrCmp (const FcChar8 *s1, const FcChar8 *s2)
102 {
103 FcChar8 c1, c2;
104
105 if (s1 == s2)
106 return 0;
107 for (;;)
108 {
109 c1 = *s1++;
110 c2 = *s2++;
111 if (!c1 || c1 != c2)
112 break;
113 }
114 return (int) c1 - (int) c2;
115 }
116
117 /*
118 * Is the head of s1 equal to s2?
119 */
120
121 static FcBool
122 FcStrIsAtIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2)
123 {
124 FcChar8 c1, c2;
125
126 for (;;)
127 {
128 do
129 c1 = *s1++;
130 while (c1 == ' ');
131 do
132 c2 = *s2++;
133 while (c2 == ' ');
134 if (!c1 || (c1 != c2 && (c1 = FcToLower(c1)) != (c2 = FcToLower(c2))))
135 break;
136 }
137 return c1 == c2 || !c2;
138 }
139
140 /*
141 * Does s1 contain an instance of s2 (ignoring blanks and case)?
142 */
143
144 const FcChar8 *
145 FcStrContainsIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2)
146 {
147 while (*s1)
148 {
149 if (FcStrIsAtIgnoreBlanksAndCase (s1, s2))
150 return s1;
151 s1++;
152 }
153 return 0;
154 }
155
156 /*
157 * Is the head of s1 equal to s2?
158 */
159
160 static FcBool
161 FcStrIsAtIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
162 {
163 FcChar8 c1, c2;
164
165 for (;;)
166 {
167 c1 = *s1++;
168 c2 = *s2++;
169 if (!c1 || (c1 != c2 && (c1 = FcToLower(c1)) != (c2 = FcToLower(c2))))
170 break;
171 }
172 return c1 == c2 || !c2;
173 }
174
175 /*
176 * Does s1 contain an instance of s2 (ignoring blanks and case)?
177 */
178
179 const FcChar8 *
180 FcStrContainsIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
181 {
182 while (*s1)
183 {
184 if (FcStrIsAtIgnoreCase (s1, s2))
185 return s1;
186 s1++;
187 }
188 return 0;
189 }
190
191 const FcChar8 *
192 FcStrStrIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
193 {
194 FcChar8 c1, c2;
195 const FcChar8 * p = s1;
196 const FcChar8 * b = s2;
197
198 if (!s1 || !s2)
199 return 0;
200
201 if (s1 == s2)
202 return s1;
203
204 again:
205 c2 = *s2++;
206 c2 = FcToLower (c2);
207
208 if (!c2)
209 return 0;
210
211 for (;;)
212 {
213 p = s1;
214 c1 = *s1++;
215 if (!c1 || (c1 = FcToLower (c1)) == c2)
216 break;
217 }
218
219 if (c1 != c2)
220 return 0;
221
222 for (;;)
223 {
224 c1 = *s1;
225 c2 = *s2;
226 if (c1 && c2 && (c1 = FcToLower (c1)) != (c2 = FcToLower (c2)))
227 {
228 s1 = p + 1;
229 s2 = b;
230 goto again;
231 }
232 if (!c2)
233 return p;
234 if (!c1)
235 return 0;
236 ++ s1;
237 ++ s2;
238 }
239
240 return 0;
241 }
242
243 const FcChar8 *
244 FcStrStr (const FcChar8 *s1, const FcChar8 *s2)
245 {
246 FcChar8 c1, c2;
247 const FcChar8 * p = s1;
248 const FcChar8 * b = s2;
249
250 if (!s1 || !s2)
251 return 0;
252
253 if (s1 == s2)
254 return s1;
255
256 again:
257 c2 = *s2++;
258
259 if (!c2)
260 return 0;
261
262 for (;;)
263 {
264 p = s1;
265 c1 = *s1++;
266 if (!c1 || c1 == c2)
267 break;
268 }
269
270 if (c1 != c2)
271 return 0;
272
273 for (;;)
274 {
275 c1 = *s1;
276 c2 = *s2;
277 if (c1 && c2 && c1 != c2)
278 {
279 s1 = p + 1;
280 s2 = b;
281 goto again;
282 }
283 if (!c2)
284 return p;
285 if (!c1)
286 return 0;
287 ++ s1;
288 ++ s2;
289 }
290
291 return 0;
292 }
293
294 int
295 FcUtf8ToUcs4 (const FcChar8 *src_orig,
296 FcChar32 *dst,
297 int len)
298 {
299 const FcChar8 *src = src_orig;
300 FcChar8 s;
301 int extra;
302 FcChar32 result;
303
304 if (len == 0)
305 return 0;
306
307 s = *src++;
308 len--;
309
310 if (!(s & 0x80))
311 {
312 result = s;
313 extra = 0;
314 }
315 else if (!(s & 0x40))
316 {
317 return -1;
318 }
319 else if (!(s & 0x20))
320 {
321 result = s & 0x1f;
322 extra = 1;
323 }
324 else if (!(s & 0x10))
325 {
326 result = s & 0xf;
327 extra = 2;
328 }
329 else if (!(s & 0x08))
330 {
331 result = s & 0x07;
332 extra = 3;
333 }
334 else if (!(s & 0x04))
335 {
336 result = s & 0x03;
337 extra = 4;
338 }
339 else if ( ! (s & 0x02))
340 {
341 result = s & 0x01;
342 extra = 5;
343 }
344 else
345 {
346 return -1;
347 }
348 if (extra > len)
349 return -1;
350
351 while (extra--)
352 {
353 result <<= 6;
354 s = *src++;
355
356 if ((s & 0xc0) != 0x80)
357 return -1;
358
359 result |= s & 0x3f;
360 }
361 *dst = result;
362 return src - src_orig;
363 }
364
365 FcBool
366 FcUtf8Len (const FcChar8 *string,
367 int len,
368 int *nchar,
369 int *wchar)
370 {
371 int n;
372 int clen;
373 FcChar32 c;
374 FcChar32 max;
375
376 n = 0;
377 max = 0;
378 while (len)
379 {
380 clen = FcUtf8ToUcs4 (string, &c, len);
381 if (clen <= 0) /* malformed UTF8 string */
382 return FcFalse;
383 if (c > max)
384 max = c;
385 string += clen;
386 len -= clen;
387 n++;
388 }
389 *nchar = n;
390 if (max >= 0x10000)
391 *wchar = 4;
392 else if (max > 0x100)
393 *wchar = 2;
394 else
395 *wchar = 1;
396 return FcTrue;
397 }
398
399 int
400 FcUcs4ToUtf8 (FcChar32 ucs4,
401 FcChar8 dest[FC_UTF8_MAX_LEN])
402 {
403 int bits;
404 FcChar8 *d = dest;
405
406 if (ucs4 < 0x80) { *d++= ucs4; bits= -6; }
407 else if (ucs4 < 0x800) { *d++= ((ucs4 >> 6) & 0x1F) | 0xC0; bits= 0; }
408 else if (ucs4 < 0x10000) { *d++= ((ucs4 >> 12) & 0x0F) | 0xE0; bits= 6; }
409 else if (ucs4 < 0x200000) { *d++= ((ucs4 >> 18) & 0x07) | 0xF0; bits= 12; }
410 else if (ucs4 < 0x4000000) { *d++= ((ucs4 >> 24) & 0x03) | 0xF8; bits= 18; }
411 else if (ucs4 < 0x80000000) { *d++= ((ucs4 >> 30) & 0x01) | 0xFC; bits= 24; }
412 else return 0;
413
414 for ( ; bits >= 0; bits-= 6) {
415 *d++= ((ucs4 >> bits) & 0x3F) | 0x80;
416 }
417 return d - dest;
418 }
419
420 #define GetUtf16(src,endian) \
421 ((FcChar16) ((src)[endian == FcEndianBig ? 0 : 1] << 8) | \
422 (FcChar16) ((src)[endian == FcEndianBig ? 1 : 0]))
423
424 int
425 FcUtf16ToUcs4 (const FcChar8 *src_orig,
426 FcEndian endian,
427 FcChar32 *dst,
428 int len) /* in bytes */
429 {
430 const FcChar8 *src = src_orig;
431 FcChar16 a, b;
432 FcChar32 result;
433
434 if (len < 2)
435 return 0;
436
437 a = GetUtf16 (src, endian); src += 2; len -= 2;
438
439 /*
440 * Check for surrogate
441 */
442 if ((a & 0xfc00) == 0xd800)
443 {
444 if (len < 2)
445 return 0;
446 b = GetUtf16 (src, endian); src += 2; len -= 2;
447 /*
448 * Check for invalid surrogate sequence
449 */
450 if ((b & 0xfc00) != 0xdc00)
451 return 0;
452 result = ((((FcChar32) a & 0x3ff) << 10) |
453 ((FcChar32) b & 0x3ff)) + 0x10000;
454 }
455 else
456 result = a;
457 *dst = result;
458 return src - src_orig;
459 }
460
461 FcBool
462 FcUtf16Len (const FcChar8 *string,
463 FcEndian endian,
464 int len, /* in bytes */
465 int *nchar,
466 int *wchar)
467 {
468 int n;
469 int clen;
470 FcChar32 c;
471 FcChar32 max;
472
473 n = 0;
474 max = 0;
475 while (len)
476 {
477 clen = FcUtf16ToUcs4 (string, endian, &c, len);
478 if (clen <= 0) /* malformed UTF8 string */
479 return FcFalse;
480 if (c > max)
481 max = c;
482 string += clen;
483 len -= clen;
484 n++;
485 }
486 *nchar = n;
487 if (max >= 0x10000)
488 *wchar = 4;
489 else if (max > 0x100)
490 *wchar = 2;
491 else
492 *wchar = 1;
493 return FcTrue;
494 }
495
496 void
497 FcStrBufInit (FcStrBuf *buf, FcChar8 *init, int size)
498 {
499 buf->buf = init;
500 buf->allocated = FcFalse;
501 buf->failed = FcFalse;
502 buf->len = 0;
503 buf->size = size;
504 }
505
506 void
507 FcStrBufDestroy (FcStrBuf *buf)
508 {
509 if (buf->allocated)
510 {
511 FcMemFree (FC_MEM_STRBUF, buf->size);
512 free (buf->buf);
513 FcStrBufInit (buf, 0, 0);
514 }
515 }
516
517 FcChar8 *
518 FcStrBufDone (FcStrBuf *buf)
519 {
520 FcChar8 *ret;
521
522 ret = malloc (buf->len + 1);
523 if (ret)
524 {
525 FcMemAlloc (FC_MEM_STRING, buf->len + 1);
526 memcpy (ret, buf->buf, buf->len);
527 ret[buf->len] = '\0';
528 }
529 FcStrBufDestroy (buf);
530 return ret;
531 }
532
533 FcBool
534 FcStrBufChar (FcStrBuf *buf, FcChar8 c)
535 {
536 if (buf->len == buf->size)
537 {
538 FcChar8 *new;
539 int size;
540
541 if (buf->allocated)
542 {
543 size = buf->size * 2;
544 new = realloc (buf->buf, size);
545 }
546 else
547 {
548 size = buf->size + 1024;
549 new = malloc (size);
550 if (new)
551 {
552 buf->allocated = FcTrue;
553 memcpy (new, buf->buf, buf->len);
554 }
555 }
556 if (!new)
557 {
558 buf->failed = FcTrue;
559 return FcFalse;
560 }
561 if (buf->size)
562 FcMemFree (FC_MEM_STRBUF, buf->size);
563 FcMemAlloc (FC_MEM_STRBUF, size);
564 buf->size = size;
565 buf->buf = new;
566 }
567 buf->buf[buf->len++] = c;
568 return FcTrue;
569 }
570
571 FcBool
572 FcStrBufString (FcStrBuf *buf, const FcChar8 *s)
573 {
574 FcChar8 c;
575 while ((c = *s++))
576 if (!FcStrBufChar (buf, c))
577 return FcFalse;
578 return FcTrue;
579 }
580
581 FcBool
582 FcStrBufData (FcStrBuf *buf, const FcChar8 *s, int len)
583 {
584 while (len-- > 0)
585 if (!FcStrBufChar (buf, *s++))
586 return FcFalse;
587 return FcTrue;
588 }
589
590 FcBool
591 FcStrUsesHome (const FcChar8 *s)
592 {
593 return *s == '~';
594 }
595
596 FcChar8 *
597 FcStrCopyFilename (const FcChar8 *s)
598 {
599 FcChar8 *new;
600
601 if (*s == '~')
602 {
603 FcChar8 *home = FcConfigHome ();
604 int size;
605 if (!home)
606 return 0;
607 size = strlen ((char *) home) + strlen ((char *) s);
608 new = (FcChar8 *) malloc (size);
609 if (!new)
610 return 0;
611 FcMemAlloc (FC_MEM_STRING, size);
612 strcpy ((char *) new, (char *) home);
613 strcat ((char *) new, (char *) s + 1);
614 }
615 else
616 {
617 int size = strlen ((char *) s) + 1;
618 new = (FcChar8 *) malloc (size);
619 if (!new)
620 return 0;
621 FcMemAlloc (FC_MEM_STRING, size);
622 strcpy ((char *) new, (const char *) s);
623 }
624 return new;
625 }
626
627 FcChar8 *
628 FcStrLastSlash (const FcChar8 *path)
629 {
630 FcChar8 *slash;
631
632 slash = (FcChar8 *) strrchr ((const char *) path, '/');
633 #ifdef _WIN32
634 {
635 FcChar8 *backslash;
636
637 backslash = (FcChar8 *) strrchr ((const char *) path, '\\');
638 if (!slash || (backslash && backslash > slash))
639 slash = backslash;
640 }
641 #endif
642
643 return slash;
644 }
645
646 FcChar8 *
647 FcStrDirname (const FcChar8 *file)
648 {
649 FcChar8 *slash;
650 FcChar8 *dir;
651
652 slash = FcStrLastSlash (file);
653 if (!slash)
654 return FcStrCopy ((FcChar8 *) ".");
655 dir = malloc ((slash - file) + 1);
656 if (!dir)
657 return 0;
658 FcMemAlloc (FC_MEM_STRING, (slash - file) + 1);
659 strncpy ((char *) dir, (const char *) file, slash - file);
660 dir[slash - file] = '\0';
661 return dir;
662 }
663
664 FcChar8 *
665 FcStrBasename (const FcChar8 *file)
666 {
667 FcChar8 *slash;
668
669 slash = FcStrLastSlash (file);
670 if (!slash)
671 return FcStrCopy (file);
672 return FcStrCopy (slash + 1);
673 }
674
675 FcStrSet *
676 FcStrSetCreate (void)
677 {
678 FcStrSet *set = malloc (sizeof (FcStrSet));
679 if (!set)
680 return 0;
681 FcMemAlloc (FC_MEM_STRSET, sizeof (FcStrSet));
682 set->ref = 1;
683 set->num = 0;
684 set->size = 0;
685 set->strs = 0;
686 return set;
687 }
688
689 static FcBool
690 _FcStrSetAppend (FcStrSet *set, FcChar8 *s)
691 {
692 if (FcStrSetMember (set, s))
693 {
694 FcStrFree (s);
695 return FcTrue;
696 }
697 if (set->num == set->size)
698 {
699 FcChar8 **strs = malloc ((set->size + 2) * sizeof (FcChar8 *));
700
701 if (!strs)
702 return FcFalse;
703 FcMemAlloc (FC_MEM_STRSET, (set->size + 2) * sizeof (FcChar8 *));
704 set->size = set->size + 1;
705 if (set->num)
706 memcpy (strs, set->strs, set->num * sizeof (FcChar8 *));
707 if (set->strs)
708 free (set->strs);
709 set->strs = strs;
710 }
711 set->strs[set->num++] = s;
712 set->strs[set->num] = 0;
713 return FcTrue;
714 }
715
716 FcBool
717 FcStrSetMember (FcStrSet *set, const FcChar8 *s)
718 {
719 int i;
720
721 for (i = 0; i < set->num; i++)
722 if (!FcStrCmp (set->strs[i], s))
723 return FcTrue;
724 return FcFalse;
725 }
726
727 FcBool
728 FcStrSetEqual (FcStrSet *sa, FcStrSet *sb)
729 {
730 int i;
731 if (sa->num != sb->num)
732 return FcFalse;
733 for (i = 0; i < sa->num; i++)
734 if (!FcStrSetMember (sb, sa->strs[i]))
735 return FcFalse;
736 return FcTrue;
737 }
738
739 FcBool
740 FcStrSetAdd (FcStrSet *set, const FcChar8 *s)
741 {
742 FcChar8 *new = FcStrCopy (s);
743 if (!new)
744 return FcFalse;
745 if (!_FcStrSetAppend (set, new))
746 {
747 FcStrFree (new);
748 return FcFalse;
749 }
750 return FcTrue;
751 }
752
753 FcBool
754 FcStrSetAddFilename (FcStrSet *set, const FcChar8 *s)
755 {
756 FcChar8 *new = FcStrCopyFilename (s);
757 if (!new)
758 return FcFalse;
759 if (!_FcStrSetAppend (set, new))
760 {
761 FcStrFree (new);
762 return FcFalse;
763 }
764 return FcTrue;
765 }
766
767 FcBool
768 FcStrSetDel (FcStrSet *set, const FcChar8 *s)
769 {
770 int i;
771
772 for (i = 0; i < set->num; i++)
773 if (!FcStrCmp (set->strs[i], s))
774 {
775 FcStrFree (set->strs[i]);
776 /*
777 * copy remaining string pointers and trailing
778 * NULL
779 */
780 memmove (&set->strs[i], &set->strs[i+1],
781 (set->num - i) * sizeof (FcChar8 *));
782 set->num--;
783 return FcTrue;
784 }
785 return FcFalse;
786 }
787
788 void
789 FcStrSetDestroy (FcStrSet *set)
790 {
791 if (--set->ref == 0)
792 {
793 int i;
794
795 for (i = 0; i < set->num; i++)
796 FcStrFree (set->strs[i]);
797 FcMemFree (FC_MEM_STRSET, (set->size) * sizeof (FcChar8 *));
798 if (set->strs)
799 free (set->strs);
800 FcMemFree (FC_MEM_STRSET, sizeof (FcStrSet));
801 free (set);
802 }
803 }
804
805 FcStrList *
806 FcStrListCreate (FcStrSet *set)
807 {
808 FcStrList *list;
809
810 list = malloc (sizeof (FcStrList));
811 if (!list)
812 return 0;
813 FcMemAlloc (FC_MEM_STRLIST, sizeof (FcStrList));
814 list->set = set;
815 set->ref++;
816 list->n = 0;
817 return list;
818 }
819
820 FcChar8 *
821 FcStrListNext (FcStrList *list)
822 {
823 if (list->n >= list->set->num)
824 return 0;
825 return list->set->strs[list->n++];
826 }
827
828 void
829 FcStrListDone (FcStrList *list)
830 {
831 FcStrSetDestroy (list->set);
832 FcMemFree (FC_MEM_STRLIST, sizeof (FcStrList));
833 free (list);
834 }