]> git.wh0rd.org Git - 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 }