]> git.wh0rd.org - fontconfig.git/blame - src/fcstr.c
I changed FcFontSetSort to respect the generic aliases better in the face
[fontconfig.git] / src / fcstr.c
CommitLineData
24330d27 1/*
4bd4418a 2 * $RCSId: xc/lib/fontconfig/src/fcstr.c,v 1.10 2002/08/31 22:17:32 keithp Exp $
24330d27 3 *
46b51147 4 * Copyright © 2000 Keith Packard
24330d27
KP
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
ccb3e93b
KP
30FcChar8 *
31FcStrCopy (const FcChar8 *s)
24330d27 32{
ccb3e93b 33 FcChar8 *r;
24330d27
KP
34
35 if (!s)
36 return 0;
ccb3e93b 37 r = (FcChar8 *) malloc (strlen ((char *) s) + 1);
24330d27
KP
38 if (!r)
39 return 0;
ccb3e93b
KP
40 FcMemAlloc (FC_MEM_STRING, strlen ((char *) s) + 1);
41 strcpy ((char *) r, (char *) s);
24330d27
KP
42 return r;
43}
44
ccb3e93b
KP
45FcChar8 *
46FcStrPlus (const FcChar8 *s1, const FcChar8 *s2)
24330d27 47{
ccb3e93b
KP
48 int l = strlen ((char *)s1) + strlen ((char *) s2) + 1;
49 FcChar8 *s = malloc (l);
24330d27
KP
50
51 if (!s)
52 return 0;
53 FcMemAlloc (FC_MEM_STRING, l);
ccb3e93b
KP
54 strcpy ((char *) s, (char *) s1);
55 strcat ((char *) s, (char *) s2);
24330d27
KP
56 return s;
57}
58
59void
ccb3e93b 60FcStrFree (FcChar8 *s)
24330d27 61{
ccb3e93b 62 FcMemFree (FC_MEM_STRING, strlen ((char *) s) + 1);
24330d27
KP
63 free (s);
64}
65
66int
ccb3e93b 67FcStrCmpIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
24330d27 68{
ccb3e93b 69 FcChar8 c1, c2;
24330d27
KP
70
71 for (;;)
72 {
73 c1 = *s1++;
74 c2 = *s2++;
d93fb00e 75 if (!c1 || (c1 != c2 && (c1 = FcToLower(c1)) != (c2 = FcToLower(c2))))
24330d27 76 break;
82f4243f
KP
77 }
78 return (int) c1 - (int) c2;
79}
80
81int
82FcStrCmpIgnoreBlanksAndCase (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 == ' ');
d93fb00e 94 if (!c1 || (c1 != c2 && (c1 = FcToLower(c1)) != (c2 = FcToLower(c2))))
24330d27
KP
95 break;
96 }
bc9469ba 97 return (int) c1 - (int) c2;
24330d27
KP
98}
99
179c3995
KP
100int
101FcStrCmp (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++;
d93fb00e 111 if (!c1 || c1 != c2)
179c3995
KP
112 break;
113 }
bc9469ba 114 return (int) c1 - (int) c2;
179c3995
KP
115}
116
11fec41c
KP
117/*
118 * Is the head of s1 equal to s2?
119 */
120
121static FcBool
122FcStrIsAtIgnoreBlanksAndCase (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
144const FcChar8 *
145FcStrContainsIgnoreBlanksAndCase (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
160static FcBool
161FcStrIsAtIgnoreCase (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
179const FcChar8 *
180FcStrContainsIgnoreCase (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
d4d1e8bc
JS
191const FcChar8 *
192FcStrStrIgnoreCase (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
204again:
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
243const FcChar8 *
244FcStrStr (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
256again:
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
24330d27 294int
0f9a306e
KP
295FcUtf8ToUcs4 (const FcChar8 *src_orig,
296 FcChar32 *dst,
297 int len)
24330d27 298{
0f9a306e
KP
299 const FcChar8 *src = src_orig;
300 FcChar8 s;
301 int extra;
302 FcChar32 result;
24330d27
KP
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
365FcBool
0f9a306e
KP
366FcUtf8Len (const FcChar8 *string,
367 int len,
368 int *nchar,
369 int *wchar)
24330d27
KP
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}
c2e7c611 398
69937bd9
KP
399int
400FcUcs4ToUtf8 (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
424int
0f9a306e
KP
425FcUtf16ToUcs4 (const FcChar8 *src_orig,
426 FcEndian endian,
427 FcChar32 *dst,
428 int len) /* in bytes */
69937bd9 429{
0f9a306e
KP
430 const FcChar8 *src = src_orig;
431 FcChar16 a, b;
432 FcChar32 result;
69937bd9
KP
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) |
45fb31aa 453 ((FcChar32) b & 0x3ff)) + 0x10000;
69937bd9
KP
454 }
455 else
456 result = a;
457 *dst = result;
458 return src - src_orig;
459}
460
461FcBool
0f9a306e
KP
462FcUtf16Len (const FcChar8 *string,
463 FcEndian endian,
464 int len, /* in bytes */
465 int *nchar,
466 int *wchar)
69937bd9
KP
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
c2e7c611
KP
496void
497FcStrBufInit (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
506void
507FcStrBufDestroy (FcStrBuf *buf)
508{
509 if (buf->allocated)
510 {
9dac3c59 511 FcMemFree (FC_MEM_STRBUF, buf->size);
c2e7c611
KP
512 free (buf->buf);
513 FcStrBufInit (buf, 0, 0);
514 }
515}
516
517FcChar8 *
518FcStrBufDone (FcStrBuf *buf)
519{
520 FcChar8 *ret;
521
522 ret = malloc (buf->len + 1);
523 if (ret)
524 {
9dac3c59 525 FcMemAlloc (FC_MEM_STRING, buf->len + 1);
c2e7c611
KP
526 memcpy (ret, buf->buf, buf->len);
527 ret[buf->len] = '\0';
528 }
529 FcStrBufDestroy (buf);
530 return ret;
531}
532
533FcBool
534FcStrBufChar (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 }
9dac3c59
KP
561 if (buf->size)
562 FcMemFree (FC_MEM_STRBUF, buf->size);
563 FcMemAlloc (FC_MEM_STRBUF, size);
c2e7c611
KP
564 buf->size = size;
565 buf->buf = new;
566 }
567 buf->buf[buf->len++] = c;
568 return FcTrue;
569}
570
571FcBool
572FcStrBufString (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
581FcBool
582FcStrBufData (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
ff3f1f98
KP
590FcBool
591FcStrUsesHome (const FcChar8 *s)
592{
593 return *s == '~';
594}
595
179c3995
KP
596FcChar8 *
597FcStrCopyFilename (const FcChar8 *s)
598{
599 FcChar8 *new;
600
601 if (*s == '~')
602 {
ff3f1f98 603 FcChar8 *home = FcConfigHome ();
dda27aa9 604 int size;
179c3995
KP
605 if (!home)
606 return 0;
dda27aa9 607 size = strlen ((char *) home) + strlen ((char *) s);
179c3995
KP
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
daeed6e0
TL
627FcChar8 *
628FcStrLastSlash (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
179c3995
KP
646FcChar8 *
647FcStrDirname (const FcChar8 *file)
648{
649 FcChar8 *slash;
650 FcChar8 *dir;
651
daeed6e0 652 slash = FcStrLastSlash (file);
179c3995
KP
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
664FcChar8 *
665FcStrBasename (const FcChar8 *file)
666{
667 FcChar8 *slash;
668
daeed6e0 669 slash = FcStrLastSlash (file);
179c3995
KP
670 if (!slash)
671 return FcStrCopy (file);
672 return FcStrCopy (slash + 1);
673}
674
675FcStrSet *
676FcStrSetCreate (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
689static 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
716FcBool
717FcStrSetMember (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
d8d73958
KP
727FcBool
728FcStrSetEqual (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
179c3995
KP
739FcBool
740FcStrSetAdd (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
753FcBool
754FcStrSetAddFilename (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
767FcBool
768FcStrSetDel (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
788void
789FcStrSetDestroy (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
805FcStrList *
806FcStrListCreate (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
820FcChar8 *
821FcStrListNext (FcStrList *list)
822{
823 if (list->n >= list->set->num)
824 return 0;
825 return list->set->strs[list->n++];
826}
827
828void
829FcStrListDone (FcStrList *list)
830{
831 FcStrSetDestroy (list->set);
832 FcMemFree (FC_MEM_STRLIST, sizeof (FcStrList));
833 free (list);
834}