]> git.wh0rd.org - fontconfig.git/blob - src/fcstr.c
Grub through style to find weight/slant/width values when other techniques
[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 int
192 FcUtf8ToUcs4 (const FcChar8 *src_orig,
193 FcChar32 *dst,
194 int len)
195 {
196 const FcChar8 *src = src_orig;
197 FcChar8 s;
198 int extra;
199 FcChar32 result;
200
201 if (len == 0)
202 return 0;
203
204 s = *src++;
205 len--;
206
207 if (!(s & 0x80))
208 {
209 result = s;
210 extra = 0;
211 }
212 else if (!(s & 0x40))
213 {
214 return -1;
215 }
216 else if (!(s & 0x20))
217 {
218 result = s & 0x1f;
219 extra = 1;
220 }
221 else if (!(s & 0x10))
222 {
223 result = s & 0xf;
224 extra = 2;
225 }
226 else if (!(s & 0x08))
227 {
228 result = s & 0x07;
229 extra = 3;
230 }
231 else if (!(s & 0x04))
232 {
233 result = s & 0x03;
234 extra = 4;
235 }
236 else if ( ! (s & 0x02))
237 {
238 result = s & 0x01;
239 extra = 5;
240 }
241 else
242 {
243 return -1;
244 }
245 if (extra > len)
246 return -1;
247
248 while (extra--)
249 {
250 result <<= 6;
251 s = *src++;
252
253 if ((s & 0xc0) != 0x80)
254 return -1;
255
256 result |= s & 0x3f;
257 }
258 *dst = result;
259 return src - src_orig;
260 }
261
262 FcBool
263 FcUtf8Len (const FcChar8 *string,
264 int len,
265 int *nchar,
266 int *wchar)
267 {
268 int n;
269 int clen;
270 FcChar32 c;
271 FcChar32 max;
272
273 n = 0;
274 max = 0;
275 while (len)
276 {
277 clen = FcUtf8ToUcs4 (string, &c, len);
278 if (clen <= 0) /* malformed UTF8 string */
279 return FcFalse;
280 if (c > max)
281 max = c;
282 string += clen;
283 len -= clen;
284 n++;
285 }
286 *nchar = n;
287 if (max >= 0x10000)
288 *wchar = 4;
289 else if (max > 0x100)
290 *wchar = 2;
291 else
292 *wchar = 1;
293 return FcTrue;
294 }
295
296 int
297 FcUcs4ToUtf8 (FcChar32 ucs4,
298 FcChar8 dest[FC_UTF8_MAX_LEN])
299 {
300 int bits;
301 FcChar8 *d = dest;
302
303 if (ucs4 < 0x80) { *d++= ucs4; bits= -6; }
304 else if (ucs4 < 0x800) { *d++= ((ucs4 >> 6) & 0x1F) | 0xC0; bits= 0; }
305 else if (ucs4 < 0x10000) { *d++= ((ucs4 >> 12) & 0x0F) | 0xE0; bits= 6; }
306 else if (ucs4 < 0x200000) { *d++= ((ucs4 >> 18) & 0x07) | 0xF0; bits= 12; }
307 else if (ucs4 < 0x4000000) { *d++= ((ucs4 >> 24) & 0x03) | 0xF8; bits= 18; }
308 else if (ucs4 < 0x80000000) { *d++= ((ucs4 >> 30) & 0x01) | 0xFC; bits= 24; }
309 else return 0;
310
311 for ( ; bits >= 0; bits-= 6) {
312 *d++= ((ucs4 >> bits) & 0x3F) | 0x80;
313 }
314 return d - dest;
315 }
316
317 #define GetUtf16(src,endian) \
318 ((FcChar16) ((src)[endian == FcEndianBig ? 0 : 1] << 8) | \
319 (FcChar16) ((src)[endian == FcEndianBig ? 1 : 0]))
320
321 int
322 FcUtf16ToUcs4 (const FcChar8 *src_orig,
323 FcEndian endian,
324 FcChar32 *dst,
325 int len) /* in bytes */
326 {
327 const FcChar8 *src = src_orig;
328 FcChar16 a, b;
329 FcChar32 result;
330
331 if (len < 2)
332 return 0;
333
334 a = GetUtf16 (src, endian); src += 2; len -= 2;
335
336 /*
337 * Check for surrogate
338 */
339 if ((a & 0xfc00) == 0xd800)
340 {
341 if (len < 2)
342 return 0;
343 b = GetUtf16 (src, endian); src += 2; len -= 2;
344 /*
345 * Check for invalid surrogate sequence
346 */
347 if ((b & 0xfc00) != 0xdc00)
348 return 0;
349 result = ((((FcChar32) a & 0x3ff) << 10) |
350 ((FcChar32) b & 0x3ff)) + 0x10000;
351 }
352 else
353 result = a;
354 *dst = result;
355 return src - src_orig;
356 }
357
358 FcBool
359 FcUtf16Len (const FcChar8 *string,
360 FcEndian endian,
361 int len, /* in bytes */
362 int *nchar,
363 int *wchar)
364 {
365 int n;
366 int clen;
367 FcChar32 c;
368 FcChar32 max;
369
370 n = 0;
371 max = 0;
372 while (len)
373 {
374 clen = FcUtf16ToUcs4 (string, endian, &c, len);
375 if (clen <= 0) /* malformed UTF8 string */
376 return FcFalse;
377 if (c > max)
378 max = c;
379 string += clen;
380 len -= clen;
381 n++;
382 }
383 *nchar = n;
384 if (max >= 0x10000)
385 *wchar = 4;
386 else if (max > 0x100)
387 *wchar = 2;
388 else
389 *wchar = 1;
390 return FcTrue;
391 }
392
393 void
394 FcStrBufInit (FcStrBuf *buf, FcChar8 *init, int size)
395 {
396 buf->buf = init;
397 buf->allocated = FcFalse;
398 buf->failed = FcFalse;
399 buf->len = 0;
400 buf->size = size;
401 }
402
403 void
404 FcStrBufDestroy (FcStrBuf *buf)
405 {
406 if (buf->allocated)
407 {
408 FcMemFree (FC_MEM_STRBUF, buf->size);
409 free (buf->buf);
410 FcStrBufInit (buf, 0, 0);
411 }
412 }
413
414 FcChar8 *
415 FcStrBufDone (FcStrBuf *buf)
416 {
417 FcChar8 *ret;
418
419 ret = malloc (buf->len + 1);
420 if (ret)
421 {
422 FcMemAlloc (FC_MEM_STRING, buf->len + 1);
423 memcpy (ret, buf->buf, buf->len);
424 ret[buf->len] = '\0';
425 }
426 FcStrBufDestroy (buf);
427 return ret;
428 }
429
430 FcBool
431 FcStrBufChar (FcStrBuf *buf, FcChar8 c)
432 {
433 if (buf->len == buf->size)
434 {
435 FcChar8 *new;
436 int size;
437
438 if (buf->allocated)
439 {
440 size = buf->size * 2;
441 new = realloc (buf->buf, size);
442 }
443 else
444 {
445 size = buf->size + 1024;
446 new = malloc (size);
447 if (new)
448 {
449 buf->allocated = FcTrue;
450 memcpy (new, buf->buf, buf->len);
451 }
452 }
453 if (!new)
454 {
455 buf->failed = FcTrue;
456 return FcFalse;
457 }
458 if (buf->size)
459 FcMemFree (FC_MEM_STRBUF, buf->size);
460 FcMemAlloc (FC_MEM_STRBUF, size);
461 buf->size = size;
462 buf->buf = new;
463 }
464 buf->buf[buf->len++] = c;
465 return FcTrue;
466 }
467
468 FcBool
469 FcStrBufString (FcStrBuf *buf, const FcChar8 *s)
470 {
471 FcChar8 c;
472 while ((c = *s++))
473 if (!FcStrBufChar (buf, c))
474 return FcFalse;
475 return FcTrue;
476 }
477
478 FcBool
479 FcStrBufData (FcStrBuf *buf, const FcChar8 *s, int len)
480 {
481 while (len-- > 0)
482 if (!FcStrBufChar (buf, *s++))
483 return FcFalse;
484 return FcTrue;
485 }
486
487 FcBool
488 FcStrUsesHome (const FcChar8 *s)
489 {
490 return *s == '~';
491 }
492
493 FcChar8 *
494 FcStrCopyFilename (const FcChar8 *s)
495 {
496 FcChar8 *new;
497
498 if (*s == '~')
499 {
500 FcChar8 *home = FcConfigHome ();
501 int size;
502 if (!home)
503 return 0;
504 size = strlen ((char *) home) + strlen ((char *) s);
505 new = (FcChar8 *) malloc (size);
506 if (!new)
507 return 0;
508 FcMemAlloc (FC_MEM_STRING, size);
509 strcpy ((char *) new, (char *) home);
510 strcat ((char *) new, (char *) s + 1);
511 }
512 else
513 {
514 int size = strlen ((char *) s) + 1;
515 new = (FcChar8 *) malloc (size);
516 if (!new)
517 return 0;
518 FcMemAlloc (FC_MEM_STRING, size);
519 strcpy ((char *) new, (const char *) s);
520 }
521 return new;
522 }
523
524 FcChar8 *
525 FcStrLastSlash (const FcChar8 *path)
526 {
527 FcChar8 *slash;
528
529 slash = (FcChar8 *) strrchr ((const char *) path, '/');
530 #ifdef _WIN32
531 {
532 FcChar8 *backslash;
533
534 backslash = (FcChar8 *) strrchr ((const char *) path, '\\');
535 if (!slash || (backslash && backslash > slash))
536 slash = backslash;
537 }
538 #endif
539
540 return slash;
541 }
542
543 FcChar8 *
544 FcStrDirname (const FcChar8 *file)
545 {
546 FcChar8 *slash;
547 FcChar8 *dir;
548
549 slash = FcStrLastSlash (file);
550 if (!slash)
551 return FcStrCopy ((FcChar8 *) ".");
552 dir = malloc ((slash - file) + 1);
553 if (!dir)
554 return 0;
555 FcMemAlloc (FC_MEM_STRING, (slash - file) + 1);
556 strncpy ((char *) dir, (const char *) file, slash - file);
557 dir[slash - file] = '\0';
558 return dir;
559 }
560
561 FcChar8 *
562 FcStrBasename (const FcChar8 *file)
563 {
564 FcChar8 *slash;
565
566 slash = FcStrLastSlash (file);
567 if (!slash)
568 return FcStrCopy (file);
569 return FcStrCopy (slash + 1);
570 }
571
572 FcStrSet *
573 FcStrSetCreate (void)
574 {
575 FcStrSet *set = malloc (sizeof (FcStrSet));
576 if (!set)
577 return 0;
578 FcMemAlloc (FC_MEM_STRSET, sizeof (FcStrSet));
579 set->ref = 1;
580 set->num = 0;
581 set->size = 0;
582 set->strs = 0;
583 return set;
584 }
585
586 static FcBool
587 _FcStrSetAppend (FcStrSet *set, FcChar8 *s)
588 {
589 if (FcStrSetMember (set, s))
590 {
591 FcStrFree (s);
592 return FcTrue;
593 }
594 if (set->num == set->size)
595 {
596 FcChar8 **strs = malloc ((set->size + 2) * sizeof (FcChar8 *));
597
598 if (!strs)
599 return FcFalse;
600 FcMemAlloc (FC_MEM_STRSET, (set->size + 2) * sizeof (FcChar8 *));
601 set->size = set->size + 1;
602 if (set->num)
603 memcpy (strs, set->strs, set->num * sizeof (FcChar8 *));
604 if (set->strs)
605 free (set->strs);
606 set->strs = strs;
607 }
608 set->strs[set->num++] = s;
609 set->strs[set->num] = 0;
610 return FcTrue;
611 }
612
613 FcBool
614 FcStrSetMember (FcStrSet *set, const FcChar8 *s)
615 {
616 int i;
617
618 for (i = 0; i < set->num; i++)
619 if (!FcStrCmp (set->strs[i], s))
620 return FcTrue;
621 return FcFalse;
622 }
623
624 FcBool
625 FcStrSetEqual (FcStrSet *sa, FcStrSet *sb)
626 {
627 int i;
628 if (sa->num != sb->num)
629 return FcFalse;
630 for (i = 0; i < sa->num; i++)
631 if (!FcStrSetMember (sb, sa->strs[i]))
632 return FcFalse;
633 return FcTrue;
634 }
635
636 FcBool
637 FcStrSetAdd (FcStrSet *set, const FcChar8 *s)
638 {
639 FcChar8 *new = FcStrCopy (s);
640 if (!new)
641 return FcFalse;
642 if (!_FcStrSetAppend (set, new))
643 {
644 FcStrFree (new);
645 return FcFalse;
646 }
647 return FcTrue;
648 }
649
650 FcBool
651 FcStrSetAddFilename (FcStrSet *set, const FcChar8 *s)
652 {
653 FcChar8 *new = FcStrCopyFilename (s);
654 if (!new)
655 return FcFalse;
656 if (!_FcStrSetAppend (set, new))
657 {
658 FcStrFree (new);
659 return FcFalse;
660 }
661 return FcTrue;
662 }
663
664 FcBool
665 FcStrSetDel (FcStrSet *set, const FcChar8 *s)
666 {
667 int i;
668
669 for (i = 0; i < set->num; i++)
670 if (!FcStrCmp (set->strs[i], s))
671 {
672 FcStrFree (set->strs[i]);
673 /*
674 * copy remaining string pointers and trailing
675 * NULL
676 */
677 memmove (&set->strs[i], &set->strs[i+1],
678 (set->num - i) * sizeof (FcChar8 *));
679 set->num--;
680 return FcTrue;
681 }
682 return FcFalse;
683 }
684
685 void
686 FcStrSetDestroy (FcStrSet *set)
687 {
688 if (--set->ref == 0)
689 {
690 int i;
691
692 for (i = 0; i < set->num; i++)
693 FcStrFree (set->strs[i]);
694 FcMemFree (FC_MEM_STRSET, (set->size) * sizeof (FcChar8 *));
695 if (set->strs)
696 free (set->strs);
697 FcMemFree (FC_MEM_STRSET, sizeof (FcStrSet));
698 free (set);
699 }
700 }
701
702 FcStrList *
703 FcStrListCreate (FcStrSet *set)
704 {
705 FcStrList *list;
706
707 list = malloc (sizeof (FcStrList));
708 if (!list)
709 return 0;
710 FcMemAlloc (FC_MEM_STRLIST, sizeof (FcStrList));
711 list->set = set;
712 set->ref++;
713 list->n = 0;
714 return list;
715 }
716
717 FcChar8 *
718 FcStrListNext (FcStrList *list)
719 {
720 if (list->n >= list->set->num)
721 return 0;
722 return list->set->strs[list->n++];
723 }
724
725 void
726 FcStrListDone (FcStrList *list)
727 {
728 FcStrSetDestroy (list->set);
729 FcMemFree (FC_MEM_STRLIST, sizeof (FcStrList));
730 free (list);
731 }