]> git.wh0rd.org Git - fontconfig.git/blob - src/fcstr.c
Reimplement FC_LANG as FcTypeLang, freeze patterns, other cleanup
[fontconfig.git] / src / fcstr.c
1 /*
2  * $XFree86: xc/lib/fontconfig/src/fcstr.c,v 1.7 2002/07/13 05:43:25 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 (FcChar8   *src_orig,
129               FcChar32  *dst,
130               int       len)
131 {
132     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 (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 (FcChar8  *src_orig,
259                FcEndian endian,
260                FcChar32 *dst,
261                int      len)    /* in bytes */
262 {
263     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 (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         free (buf->buf);
345         FcStrBufInit (buf, 0, 0);
346     }
347 }
348
349 FcChar8 *
350 FcStrBufDone (FcStrBuf *buf)
351 {
352     FcChar8 *ret;
353
354     ret = malloc (buf->len + 1);
355     if (ret)
356     {
357         memcpy (ret, buf->buf, buf->len);
358         ret[buf->len] = '\0';
359     }
360     FcStrBufDestroy (buf);
361     return ret;
362 }
363
364 FcBool
365 FcStrBufChar (FcStrBuf *buf, FcChar8 c)
366 {
367     if (buf->len == buf->size)
368     {
369         FcChar8     *new;
370         int         size;
371
372         if (buf->allocated)
373         {
374             size = buf->size * 2;
375             new = realloc (buf->buf, size);
376         }
377         else
378         {
379             size = buf->size + 1024;
380             new = malloc (size);
381             if (new)
382             {
383                 buf->allocated = FcTrue;
384                 memcpy (new, buf->buf, buf->len);
385             }
386         }
387         if (!new)
388         {
389             buf->failed = FcTrue;
390             return FcFalse;
391         }
392         buf->size = size;
393         buf->buf = new;
394     }
395     buf->buf[buf->len++] = c;
396     return FcTrue;
397 }
398
399 FcBool
400 FcStrBufString (FcStrBuf *buf, const FcChar8 *s)
401 {
402     FcChar8 c;
403     while ((c = *s++))
404         if (!FcStrBufChar (buf, c))
405             return FcFalse;
406     return FcTrue;
407 }
408
409 FcBool
410 FcStrBufData (FcStrBuf *buf, const FcChar8 *s, int len)
411 {
412     while (len-- > 0)
413         if (!FcStrBufChar (buf, *s++))
414             return FcFalse;
415     return FcTrue;
416 }
417
418 FcChar8 *
419 FcStrCopyFilename (const FcChar8 *s)
420 {
421     FcChar8 *new;
422     
423     if (*s == '~')
424     {
425         FcChar8 *home = (FcChar8 *) getenv ("HOME");
426         int     size = strlen ((char *) home) + strlen ((char *) s);
427         if (!home)
428             return 0;
429         new = (FcChar8 *) malloc (size);
430         if (!new)
431             return 0;
432         FcMemAlloc (FC_MEM_STRING, size);
433         strcpy ((char *) new, (char *) home);
434         strcat ((char *) new, (char *) s + 1);
435     }
436     else
437     {
438         int     size = strlen ((char *) s) + 1;
439         new = (FcChar8 *) malloc (size);
440         if (!new)
441             return 0;
442         FcMemAlloc (FC_MEM_STRING, size);
443         strcpy ((char *) new, (const char *) s);
444     }
445     return new;
446 }
447
448 FcChar8 *
449 FcStrDirname (const FcChar8 *file)
450 {
451     FcChar8 *slash;
452     FcChar8 *dir;
453
454     slash = (FcChar8 *) strrchr ((char *) file, '/');
455     if (!slash)
456         return FcStrCopy ((FcChar8 *) ".");
457     dir = malloc ((slash - file) + 1);
458     if (!dir)
459         return 0;
460     FcMemAlloc (FC_MEM_STRING, (slash - file) + 1);
461     strncpy ((char *) dir, (const char *) file, slash - file);
462     dir[slash - file] = '\0';
463     return dir;
464 }
465
466 FcChar8 *
467 FcStrBasename (const FcChar8 *file)
468 {
469     FcChar8 *slash;
470
471     slash = (FcChar8 *) strrchr ((char *) file, '/');
472     if (!slash)
473         return FcStrCopy (file);
474     return FcStrCopy (slash + 1);
475 }
476
477 FcStrSet *
478 FcStrSetCreate (void)
479 {
480     FcStrSet    *set = malloc (sizeof (FcStrSet));
481     if (!set)
482         return 0;
483     FcMemAlloc (FC_MEM_STRSET, sizeof (FcStrSet));
484     set->ref = 1;
485     set->num = 0;
486     set->size = 0;
487     set->strs = 0;
488     return set;
489 }
490
491 static FcBool
492 _FcStrSetAppend (FcStrSet *set, FcChar8 *s)
493 {
494     if (FcStrSetMember (set, s))
495     {
496         FcStrFree (s);
497         return FcTrue;
498     }
499     if (set->num == set->size)
500     {
501         FcChar8 **strs = malloc ((set->size + 2) * sizeof (FcChar8 *));
502
503         if (!strs)
504             return FcFalse;
505         FcMemAlloc (FC_MEM_STRSET, (set->size + 2) * sizeof (FcChar8 *));
506         set->size = set->size + 1;
507         if (set->num)
508             memcpy (strs, set->strs, set->num * sizeof (FcChar8 *));
509         if (set->strs)
510             free (set->strs);
511         set->strs = strs;
512     }
513     set->strs[set->num++] = s;
514     set->strs[set->num] = 0;
515     return FcTrue;
516 }
517
518 FcBool
519 FcStrSetMember (FcStrSet *set, const FcChar8 *s)
520 {
521     int i;
522
523     for (i = 0; i < set->num; i++)
524         if (!FcStrCmp (set->strs[i], s))
525             return FcTrue;
526     return FcFalse;
527 }
528
529 FcBool
530 FcStrSetEqual (FcStrSet *sa, FcStrSet *sb)
531 {
532     int i;
533     if (sa->num != sb->num)
534         return FcFalse;
535     for (i = 0; i < sa->num; i++)
536         if (!FcStrSetMember (sb, sa->strs[i]))
537             return FcFalse;
538     return FcTrue;
539 }
540
541 FcBool
542 FcStrSetAdd (FcStrSet *set, const FcChar8 *s)
543 {
544     FcChar8 *new = FcStrCopy (s);
545     if (!new)
546         return FcFalse;
547     if (!_FcStrSetAppend (set, new))
548     {
549         FcStrFree (new);
550         return FcFalse;
551     }
552     return FcTrue;
553 }
554
555 FcBool
556 FcStrSetAddFilename (FcStrSet *set, const FcChar8 *s)
557 {
558     FcChar8 *new = FcStrCopyFilename (s);
559     if (!new)
560         return FcFalse;
561     if (!_FcStrSetAppend (set, new))
562     {
563         FcStrFree (new);
564         return FcFalse;
565     }
566     return FcTrue;
567 }
568
569 FcBool
570 FcStrSetDel (FcStrSet *set, const FcChar8 *s)
571 {
572     int i;
573
574     for (i = 0; i < set->num; i++)
575         if (!FcStrCmp (set->strs[i], s))
576         {
577             FcStrFree (set->strs[i]);
578             /*
579              * copy remaining string pointers and trailing
580              * NULL
581              */
582             memmove (&set->strs[i], &set->strs[i+1], 
583                      (set->num - i) * sizeof (FcChar8 *));
584             set->num--;
585             return FcTrue;
586         }
587     return FcFalse;
588 }
589
590 void
591 FcStrSetDestroy (FcStrSet *set)
592 {
593     if (--set->ref == 0)
594     {
595         int     i;
596     
597         for (i = 0; i < set->num; i++)
598             FcStrFree (set->strs[i]);
599         FcMemFree (FC_MEM_STRSET, (set->size) * sizeof (FcChar8 *));
600         if (set->strs)
601             free (set->strs);
602         FcMemFree (FC_MEM_STRSET, sizeof (FcStrSet));
603         free (set);
604     }
605 }
606
607 FcStrList *
608 FcStrListCreate (FcStrSet *set)
609 {
610     FcStrList   *list;
611
612     list = malloc (sizeof (FcStrList));
613     if (!list)
614         return 0;
615     FcMemAlloc (FC_MEM_STRLIST, sizeof (FcStrList));
616     list->set = set;
617     set->ref++;
618     list->n = 0;
619     return list;
620 }
621
622 FcChar8 *
623 FcStrListNext (FcStrList *list)
624 {
625     if (list->n >= list->set->num)
626         return 0;
627     return list->set->strs[list->n++];
628 }
629
630 void
631 FcStrListDone (FcStrList *list)
632 {
633     FcStrSetDestroy (list->set);
634     FcMemFree (FC_MEM_STRLIST, sizeof (FcStrList));
635     free (list);
636 }