]> git.wh0rd.org - fontconfig.git/blob - src/fcstr.c
Make FcStrCmpIgnoreCase a bit faster
[fontconfig.git] / src / fcstr.c
1 /*
2 * $XFree86: xc/lib/fontconfig/src/fcstr.c,v 1.10 2002/08/31 22:17:32 keithp Exp $
3 *
4 * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
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)
76 break;
77 if (c1 != c2)
78 {
79 c1 = FcToLower (c1);
80 c2 = FcToLower (c2);
81 if (c1 != c2)
82 break;
83 }
84 }
85 return (int) c1 - (int) c2;
86 }
87
88 int
89 FcStrCmpIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2)
90 {
91 FcChar8 c1, c2;
92
93 for (;;)
94 {
95 do
96 c1 = *s1++;
97 while (c1 == ' ');
98 do
99 c2 = *s2++;
100 while (c2 == ' ');
101 if (!c1 || !c2)
102 break;
103 c1 = FcToLower (c1);
104 c2 = FcToLower (c2);
105 if (c1 != c2)
106 break;
107 }
108 return (int) c1 - (int) c2;
109 }
110
111 int
112 FcStrCmp (const FcChar8 *s1, const FcChar8 *s2)
113 {
114 FcChar8 c1, c2;
115
116 if (s1 == s2)
117 return 0;
118 for (;;)
119 {
120 c1 = *s1++;
121 c2 = *s2++;
122 if (!c1 || !c2)
123 break;
124 if (c1 != c2)
125 break;
126 }
127 return (int) c1 - (int) c2;
128 }
129
130 int
131 FcUtf8ToUcs4 (const FcChar8 *src_orig,
132 FcChar32 *dst,
133 int len)
134 {
135 const FcChar8 *src = src_orig;
136 FcChar8 s;
137 int extra;
138 FcChar32 result;
139
140 if (len == 0)
141 return 0;
142
143 s = *src++;
144 len--;
145
146 if (!(s & 0x80))
147 {
148 result = s;
149 extra = 0;
150 }
151 else if (!(s & 0x40))
152 {
153 return -1;
154 }
155 else if (!(s & 0x20))
156 {
157 result = s & 0x1f;
158 extra = 1;
159 }
160 else if (!(s & 0x10))
161 {
162 result = s & 0xf;
163 extra = 2;
164 }
165 else if (!(s & 0x08))
166 {
167 result = s & 0x07;
168 extra = 3;
169 }
170 else if (!(s & 0x04))
171 {
172 result = s & 0x03;
173 extra = 4;
174 }
175 else if ( ! (s & 0x02))
176 {
177 result = s & 0x01;
178 extra = 5;
179 }
180 else
181 {
182 return -1;
183 }
184 if (extra > len)
185 return -1;
186
187 while (extra--)
188 {
189 result <<= 6;
190 s = *src++;
191
192 if ((s & 0xc0) != 0x80)
193 return -1;
194
195 result |= s & 0x3f;
196 }
197 *dst = result;
198 return src - src_orig;
199 }
200
201 FcBool
202 FcUtf8Len (const FcChar8 *string,
203 int len,
204 int *nchar,
205 int *wchar)
206 {
207 int n;
208 int clen;
209 FcChar32 c;
210 FcChar32 max;
211
212 n = 0;
213 max = 0;
214 while (len)
215 {
216 clen = FcUtf8ToUcs4 (string, &c, len);
217 if (clen <= 0) /* malformed UTF8 string */
218 return FcFalse;
219 if (c > max)
220 max = c;
221 string += clen;
222 len -= clen;
223 n++;
224 }
225 *nchar = n;
226 if (max >= 0x10000)
227 *wchar = 4;
228 else if (max > 0x100)
229 *wchar = 2;
230 else
231 *wchar = 1;
232 return FcTrue;
233 }
234
235 int
236 FcUcs4ToUtf8 (FcChar32 ucs4,
237 FcChar8 dest[FC_UTF8_MAX_LEN])
238 {
239 int bits;
240 FcChar8 *d = dest;
241
242 if (ucs4 < 0x80) { *d++= ucs4; bits= -6; }
243 else if (ucs4 < 0x800) { *d++= ((ucs4 >> 6) & 0x1F) | 0xC0; bits= 0; }
244 else if (ucs4 < 0x10000) { *d++= ((ucs4 >> 12) & 0x0F) | 0xE0; bits= 6; }
245 else if (ucs4 < 0x200000) { *d++= ((ucs4 >> 18) & 0x07) | 0xF0; bits= 12; }
246 else if (ucs4 < 0x4000000) { *d++= ((ucs4 >> 24) & 0x03) | 0xF8; bits= 18; }
247 else if (ucs4 < 0x80000000) { *d++= ((ucs4 >> 30) & 0x01) | 0xFC; bits= 24; }
248 else return 0;
249
250 for ( ; bits >= 0; bits-= 6) {
251 *d++= ((ucs4 >> bits) & 0x3F) | 0x80;
252 }
253 return d - dest;
254 }
255
256 #define GetUtf16(src,endian) \
257 ((FcChar16) ((src)[endian == FcEndianBig ? 0 : 1] << 8) | \
258 (FcChar16) ((src)[endian == FcEndianBig ? 1 : 0]))
259
260 int
261 FcUtf16ToUcs4 (const FcChar8 *src_orig,
262 FcEndian endian,
263 FcChar32 *dst,
264 int len) /* in bytes */
265 {
266 const FcChar8 *src = src_orig;
267 FcChar16 a, b;
268 FcChar32 result;
269
270 if (len < 2)
271 return 0;
272
273 a = GetUtf16 (src, endian); src += 2; len -= 2;
274
275 /*
276 * Check for surrogate
277 */
278 if ((a & 0xfc00) == 0xd800)
279 {
280 if (len < 2)
281 return 0;
282 b = GetUtf16 (src, endian); src += 2; len -= 2;
283 /*
284 * Check for invalid surrogate sequence
285 */
286 if ((b & 0xfc00) != 0xdc00)
287 return 0;
288 result = ((((FcChar32) a & 0x3ff) << 10) |
289 ((FcChar32) b & 0x3ff)) + 0x10000;
290 }
291 else
292 result = a;
293 *dst = result;
294 return src - src_orig;
295 }
296
297 FcBool
298 FcUtf16Len (const FcChar8 *string,
299 FcEndian endian,
300 int len, /* in bytes */
301 int *nchar,
302 int *wchar)
303 {
304 int n;
305 int clen;
306 FcChar32 c;
307 FcChar32 max;
308
309 n = 0;
310 max = 0;
311 while (len)
312 {
313 clen = FcUtf16ToUcs4 (string, endian, &c, len);
314 if (clen <= 0) /* malformed UTF8 string */
315 return FcFalse;
316 if (c > max)
317 max = c;
318 string += clen;
319 len -= clen;
320 n++;
321 }
322 *nchar = n;
323 if (max >= 0x10000)
324 *wchar = 4;
325 else if (max > 0x100)
326 *wchar = 2;
327 else
328 *wchar = 1;
329 return FcTrue;
330 }
331
332 void
333 FcStrBufInit (FcStrBuf *buf, FcChar8 *init, int size)
334 {
335 buf->buf = init;
336 buf->allocated = FcFalse;
337 buf->failed = FcFalse;
338 buf->len = 0;
339 buf->size = size;
340 }
341
342 void
343 FcStrBufDestroy (FcStrBuf *buf)
344 {
345 if (buf->allocated)
346 {
347 FcMemFree (FC_MEM_STRBUF, buf->size);
348 free (buf->buf);
349 FcStrBufInit (buf, 0, 0);
350 }
351 }
352
353 FcChar8 *
354 FcStrBufDone (FcStrBuf *buf)
355 {
356 FcChar8 *ret;
357
358 ret = malloc (buf->len + 1);
359 if (ret)
360 {
361 FcMemAlloc (FC_MEM_STRING, buf->len + 1);
362 memcpy (ret, buf->buf, buf->len);
363 ret[buf->len] = '\0';
364 }
365 FcStrBufDestroy (buf);
366 return ret;
367 }
368
369 FcBool
370 FcStrBufChar (FcStrBuf *buf, FcChar8 c)
371 {
372 if (buf->len == buf->size)
373 {
374 FcChar8 *new;
375 int size;
376
377 if (buf->allocated)
378 {
379 size = buf->size * 2;
380 new = realloc (buf->buf, size);
381 }
382 else
383 {
384 size = buf->size + 1024;
385 new = malloc (size);
386 if (new)
387 {
388 buf->allocated = FcTrue;
389 memcpy (new, buf->buf, buf->len);
390 }
391 }
392 if (!new)
393 {
394 buf->failed = FcTrue;
395 return FcFalse;
396 }
397 if (buf->size)
398 FcMemFree (FC_MEM_STRBUF, buf->size);
399 FcMemAlloc (FC_MEM_STRBUF, size);
400 buf->size = size;
401 buf->buf = new;
402 }
403 buf->buf[buf->len++] = c;
404 return FcTrue;
405 }
406
407 FcBool
408 FcStrBufString (FcStrBuf *buf, const FcChar8 *s)
409 {
410 FcChar8 c;
411 while ((c = *s++))
412 if (!FcStrBufChar (buf, c))
413 return FcFalse;
414 return FcTrue;
415 }
416
417 FcBool
418 FcStrBufData (FcStrBuf *buf, const FcChar8 *s, int len)
419 {
420 while (len-- > 0)
421 if (!FcStrBufChar (buf, *s++))
422 return FcFalse;
423 return FcTrue;
424 }
425
426 FcChar8 *
427 FcStrCopyFilename (const FcChar8 *s)
428 {
429 FcChar8 *new;
430
431 if (*s == '~')
432 {
433 FcChar8 *home = (FcChar8 *) getenv ("HOME");
434 int size;
435 if (!home)
436 return 0;
437 size = strlen ((char *) home) + strlen ((char *) s);
438 new = (FcChar8 *) malloc (size);
439 if (!new)
440 return 0;
441 FcMemAlloc (FC_MEM_STRING, size);
442 strcpy ((char *) new, (char *) home);
443 strcat ((char *) new, (char *) s + 1);
444 }
445 else
446 {
447 int size = strlen ((char *) s) + 1;
448 new = (FcChar8 *) malloc (size);
449 if (!new)
450 return 0;
451 FcMemAlloc (FC_MEM_STRING, size);
452 strcpy ((char *) new, (const char *) s);
453 }
454 return new;
455 }
456
457 FcChar8 *
458 FcStrDirname (const FcChar8 *file)
459 {
460 FcChar8 *slash;
461 FcChar8 *dir;
462
463 slash = (FcChar8 *) strrchr ((char *) file, '/');
464 if (!slash)
465 return FcStrCopy ((FcChar8 *) ".");
466 dir = malloc ((slash - file) + 1);
467 if (!dir)
468 return 0;
469 FcMemAlloc (FC_MEM_STRING, (slash - file) + 1);
470 strncpy ((char *) dir, (const char *) file, slash - file);
471 dir[slash - file] = '\0';
472 return dir;
473 }
474
475 FcChar8 *
476 FcStrBasename (const FcChar8 *file)
477 {
478 FcChar8 *slash;
479
480 slash = (FcChar8 *) strrchr ((char *) file, '/');
481 if (!slash)
482 return FcStrCopy (file);
483 return FcStrCopy (slash + 1);
484 }
485
486 FcStrSet *
487 FcStrSetCreate (void)
488 {
489 FcStrSet *set = malloc (sizeof (FcStrSet));
490 if (!set)
491 return 0;
492 FcMemAlloc (FC_MEM_STRSET, sizeof (FcStrSet));
493 set->ref = 1;
494 set->num = 0;
495 set->size = 0;
496 set->strs = 0;
497 return set;
498 }
499
500 static FcBool
501 _FcStrSetAppend (FcStrSet *set, FcChar8 *s)
502 {
503 if (FcStrSetMember (set, s))
504 {
505 FcStrFree (s);
506 return FcTrue;
507 }
508 if (set->num == set->size)
509 {
510 FcChar8 **strs = malloc ((set->size + 2) * sizeof (FcChar8 *));
511
512 if (!strs)
513 return FcFalse;
514 FcMemAlloc (FC_MEM_STRSET, (set->size + 2) * sizeof (FcChar8 *));
515 set->size = set->size + 1;
516 if (set->num)
517 memcpy (strs, set->strs, set->num * sizeof (FcChar8 *));
518 if (set->strs)
519 free (set->strs);
520 set->strs = strs;
521 }
522 set->strs[set->num++] = s;
523 set->strs[set->num] = 0;
524 return FcTrue;
525 }
526
527 FcBool
528 FcStrSetMember (FcStrSet *set, const FcChar8 *s)
529 {
530 int i;
531
532 for (i = 0; i < set->num; i++)
533 if (!FcStrCmp (set->strs[i], s))
534 return FcTrue;
535 return FcFalse;
536 }
537
538 FcBool
539 FcStrSetEqual (FcStrSet *sa, FcStrSet *sb)
540 {
541 int i;
542 if (sa->num != sb->num)
543 return FcFalse;
544 for (i = 0; i < sa->num; i++)
545 if (!FcStrSetMember (sb, sa->strs[i]))
546 return FcFalse;
547 return FcTrue;
548 }
549
550 FcBool
551 FcStrSetAdd (FcStrSet *set, const FcChar8 *s)
552 {
553 FcChar8 *new = FcStrCopy (s);
554 if (!new)
555 return FcFalse;
556 if (!_FcStrSetAppend (set, new))
557 {
558 FcStrFree (new);
559 return FcFalse;
560 }
561 return FcTrue;
562 }
563
564 FcBool
565 FcStrSetAddFilename (FcStrSet *set, const FcChar8 *s)
566 {
567 FcChar8 *new = FcStrCopyFilename (s);
568 if (!new)
569 return FcFalse;
570 if (!_FcStrSetAppend (set, new))
571 {
572 FcStrFree (new);
573 return FcFalse;
574 }
575 return FcTrue;
576 }
577
578 FcBool
579 FcStrSetDel (FcStrSet *set, const FcChar8 *s)
580 {
581 int i;
582
583 for (i = 0; i < set->num; i++)
584 if (!FcStrCmp (set->strs[i], s))
585 {
586 FcStrFree (set->strs[i]);
587 /*
588 * copy remaining string pointers and trailing
589 * NULL
590 */
591 memmove (&set->strs[i], &set->strs[i+1],
592 (set->num - i) * sizeof (FcChar8 *));
593 set->num--;
594 return FcTrue;
595 }
596 return FcFalse;
597 }
598
599 void
600 FcStrSetDestroy (FcStrSet *set)
601 {
602 if (--set->ref == 0)
603 {
604 int i;
605
606 for (i = 0; i < set->num; i++)
607 FcStrFree (set->strs[i]);
608 FcMemFree (FC_MEM_STRSET, (set->size) * sizeof (FcChar8 *));
609 if (set->strs)
610 free (set->strs);
611 FcMemFree (FC_MEM_STRSET, sizeof (FcStrSet));
612 free (set);
613 }
614 }
615
616 FcStrList *
617 FcStrListCreate (FcStrSet *set)
618 {
619 FcStrList *list;
620
621 list = malloc (sizeof (FcStrList));
622 if (!list)
623 return 0;
624 FcMemAlloc (FC_MEM_STRLIST, sizeof (FcStrList));
625 list->set = set;
626 set->ref++;
627 list->n = 0;
628 return list;
629 }
630
631 FcChar8 *
632 FcStrListNext (FcStrList *list)
633 {
634 if (list->n >= list->set->num)
635 return 0;
636 return list->set->strs[list->n++];
637 }
638
639 void
640 FcStrListDone (FcStrList *list)
641 {
642 FcStrSetDestroy (list->set);
643 FcMemFree (FC_MEM_STRLIST, sizeof (FcStrList));
644 free (list);
645 }