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