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