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