fcstr.c revision 2c393a42
12c393a42Smrg/* 22c393a42Smrg * $RCSId: xc/lib/fontconfig/src/fcstr.c,v 1.10 2002/08/31 22:17:32 keithp Exp $ 32c393a42Smrg * 42c393a42Smrg * Copyright © 2000 Keith Packard 52c393a42Smrg * 62c393a42Smrg * Permission to use, copy, modify, distribute, and sell this software and its 72c393a42Smrg * documentation for any purpose is hereby granted without fee, provided that 82c393a42Smrg * the above copyright notice appear in all copies and that both that 92c393a42Smrg * copyright notice and this permission notice appear in supporting 102c393a42Smrg * documentation, and that the name of Keith Packard not be used in 112c393a42Smrg * advertising or publicity pertaining to distribution of the software without 122c393a42Smrg * specific, written prior permission. Keith Packard makes no 132c393a42Smrg * representations about the suitability of this software for any purpose. It 142c393a42Smrg * is provided "as is" without express or implied warranty. 152c393a42Smrg * 162c393a42Smrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 172c393a42Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 182c393a42Smrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 192c393a42Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 202c393a42Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 212c393a42Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 222c393a42Smrg * PERFORMANCE OF THIS SOFTWARE. 232c393a42Smrg */ 242c393a42Smrg 252c393a42Smrg#include "fcint.h" 262c393a42Smrg#include <stdlib.h> 272c393a42Smrg#include <ctype.h> 282c393a42Smrg#include <string.h> 292c393a42Smrg#ifdef _WIN32 302c393a42Smrg#include <windows.h> 312c393a42Smrg#endif 322c393a42Smrg 332c393a42SmrgFcChar8 * 342c393a42SmrgFcStrCopy (const FcChar8 *s) 352c393a42Smrg{ 362c393a42Smrg int len; 372c393a42Smrg FcChar8 *r; 382c393a42Smrg 392c393a42Smrg if (!s) 402c393a42Smrg return 0; 412c393a42Smrg len = strlen ((char *) s) + 1; 422c393a42Smrg r = (FcChar8 *) malloc (len); 432c393a42Smrg if (!r) 442c393a42Smrg return 0; 452c393a42Smrg FcMemAlloc (FC_MEM_STRING, len); 462c393a42Smrg memcpy (r, s, len); 472c393a42Smrg return r; 482c393a42Smrg} 492c393a42Smrg 502c393a42SmrgFcChar8 * 512c393a42SmrgFcStrPlus (const FcChar8 *s1, const FcChar8 *s2) 522c393a42Smrg{ 532c393a42Smrg int l = strlen ((char *)s1) + strlen ((char *) s2) + 1; 542c393a42Smrg FcChar8 *s = malloc (l); 552c393a42Smrg 562c393a42Smrg if (!s) 572c393a42Smrg return 0; 582c393a42Smrg FcMemAlloc (FC_MEM_STRING, l); 592c393a42Smrg strcpy ((char *) s, (char *) s1); 602c393a42Smrg strcat ((char *) s, (char *) s2); 612c393a42Smrg return s; 622c393a42Smrg} 632c393a42Smrg 642c393a42Smrgvoid 652c393a42SmrgFcStrFree (FcChar8 *s) 662c393a42Smrg{ 672c393a42Smrg FcMemFree (FC_MEM_STRING, strlen ((char *) s) + 1); 682c393a42Smrg free (s); 692c393a42Smrg} 702c393a42Smrg 712c393a42Smrg 722c393a42Smrg#include "../fc-case/fccase.h" 732c393a42Smrg 742c393a42Smrg#define FcCaseFoldUpperCount(cf) \ 752c393a42Smrg ((cf)->method == FC_CASE_FOLD_FULL ? 1 : (cf)->count) 762c393a42Smrg 772c393a42Smrg#define FC_STR_CANON_BUF_LEN 1024 782c393a42Smrg 792c393a42Smrgtypedef struct _FcCaseWalker { 802c393a42Smrg const FcChar8 *read; 812c393a42Smrg const FcChar8 *src; 822c393a42Smrg FcChar8 utf8[FC_MAX_CASE_FOLD_CHARS + 1]; 832c393a42Smrg} FcCaseWalker; 842c393a42Smrg 852c393a42Smrgstatic void 862c393a42SmrgFcStrCaseWalkerInit (const FcChar8 *src, FcCaseWalker *w) 872c393a42Smrg{ 882c393a42Smrg w->src = src; 892c393a42Smrg w->read = 0; 902c393a42Smrg} 912c393a42Smrg 922c393a42Smrgstatic FcChar8 932c393a42SmrgFcStrCaseWalkerLong (FcCaseWalker *w, FcChar8 r) 942c393a42Smrg{ 952c393a42Smrg FcChar32 ucs4; 962c393a42Smrg int slen; 972c393a42Smrg int len = strlen((char*)w->src); 982c393a42Smrg 992c393a42Smrg slen = FcUtf8ToUcs4 (w->src - 1, &ucs4, len + 1); 1002c393a42Smrg if (slen <= 0) 1012c393a42Smrg return r; 1022c393a42Smrg if (FC_MIN_FOLD_CHAR <= ucs4 && ucs4 <= FC_MAX_FOLD_CHAR) 1032c393a42Smrg { 1042c393a42Smrg int min = 0; 1052c393a42Smrg int max = FC_NUM_CASE_FOLD; 1062c393a42Smrg 1072c393a42Smrg while (min <= max) 1082c393a42Smrg { 1092c393a42Smrg int mid = (min + max) >> 1; 1102c393a42Smrg FcChar32 low = fcCaseFold[mid].upper; 1112c393a42Smrg FcChar32 high = low + FcCaseFoldUpperCount (&fcCaseFold[mid]); 1122c393a42Smrg 1132c393a42Smrg if (high <= ucs4) 1142c393a42Smrg min = mid + 1; 1152c393a42Smrg else if (ucs4 < low) 1162c393a42Smrg max = mid - 1; 1172c393a42Smrg else 1182c393a42Smrg { 1192c393a42Smrg const FcCaseFold *fold = &fcCaseFold[mid]; 1202c393a42Smrg int dlen; 1212c393a42Smrg 1222c393a42Smrg switch (fold->method) { 1232c393a42Smrg case FC_CASE_FOLD_EVEN_ODD: 1242c393a42Smrg if ((ucs4 & 1) != (fold->upper & 1)) 1252c393a42Smrg return r; 1262c393a42Smrg /* fall through ... */ 1272c393a42Smrg default: 1282c393a42Smrg dlen = FcUcs4ToUtf8 (ucs4 + fold->offset, w->utf8); 1292c393a42Smrg break; 1302c393a42Smrg case FC_CASE_FOLD_FULL: 1312c393a42Smrg dlen = fold->count; 1322c393a42Smrg memcpy (w->utf8, fcCaseFoldChars + fold->offset, dlen); 1332c393a42Smrg break; 1342c393a42Smrg } 1352c393a42Smrg 1362c393a42Smrg /* consume rest of src utf-8 bytes */ 1372c393a42Smrg w->src += slen - 1; 1382c393a42Smrg 1392c393a42Smrg /* read from temp buffer */ 1402c393a42Smrg w->utf8[dlen] = '\0'; 1412c393a42Smrg w->read = w->utf8; 1422c393a42Smrg return *w->read++; 1432c393a42Smrg } 1442c393a42Smrg } 1452c393a42Smrg } 1462c393a42Smrg return r; 1472c393a42Smrg} 1482c393a42Smrg 1492c393a42Smrgstatic FcChar8 1502c393a42SmrgFcStrCaseWalkerNext (FcCaseWalker *w) 1512c393a42Smrg{ 1522c393a42Smrg FcChar8 r; 1532c393a42Smrg 1542c393a42Smrg if (w->read) 1552c393a42Smrg { 1562c393a42Smrg if ((r = *w->read++)) 1572c393a42Smrg return r; 1582c393a42Smrg w->read = 0; 1592c393a42Smrg } 1602c393a42Smrg r = *w->src++; 1612c393a42Smrg 1622c393a42Smrg if ((r & 0xc0) == 0xc0) 1632c393a42Smrg return FcStrCaseWalkerLong (w, r); 1642c393a42Smrg if ('A' <= r && r <= 'Z') 1652c393a42Smrg r = r - 'A' + 'a'; 1662c393a42Smrg return r; 1672c393a42Smrg} 1682c393a42Smrg 1692c393a42Smrgstatic FcChar8 1702c393a42SmrgFcStrCaseWalkerNextIgnoreBlanks (FcCaseWalker *w) 1712c393a42Smrg{ 1722c393a42Smrg FcChar8 r; 1732c393a42Smrg 1742c393a42Smrg if (w->read) 1752c393a42Smrg { 1762c393a42Smrg if ((r = *w->read++)) 1772c393a42Smrg return r; 1782c393a42Smrg w->read = 0; 1792c393a42Smrg } 1802c393a42Smrg do 1812c393a42Smrg { 1822c393a42Smrg r = *w->src++; 1832c393a42Smrg } while (r == ' '); 1842c393a42Smrg 1852c393a42Smrg if ((r & 0xc0) == 0xc0) 1862c393a42Smrg return FcStrCaseWalkerLong (w, r); 1872c393a42Smrg if ('A' <= r && r <= 'Z') 1882c393a42Smrg r = r - 'A' + 'a'; 1892c393a42Smrg return r; 1902c393a42Smrg} 1912c393a42Smrg 1922c393a42SmrgFcChar8 * 1932c393a42SmrgFcStrDowncase (const FcChar8 *s) 1942c393a42Smrg{ 1952c393a42Smrg FcCaseWalker w; 1962c393a42Smrg int len = 0; 1972c393a42Smrg FcChar8 *dst, *d; 1982c393a42Smrg 1992c393a42Smrg FcStrCaseWalkerInit (s, &w); 2002c393a42Smrg while (FcStrCaseWalkerNext (&w)) 2012c393a42Smrg len++; 2022c393a42Smrg d = dst = malloc (len + 1); 2032c393a42Smrg if (!d) 2042c393a42Smrg return 0; 2052c393a42Smrg FcMemAlloc (FC_MEM_STRING, len + 1); 2062c393a42Smrg FcStrCaseWalkerInit (s, &w); 2072c393a42Smrg while ((*d++ = FcStrCaseWalkerNext (&w))); 2082c393a42Smrg return dst; 2092c393a42Smrg} 2102c393a42Smrg 2112c393a42Smrgint 2122c393a42SmrgFcStrCmpIgnoreCase (const FcChar8 *s1, const FcChar8 *s2) 2132c393a42Smrg{ 2142c393a42Smrg FcCaseWalker w1, w2; 2152c393a42Smrg FcChar8 c1, c2; 2162c393a42Smrg 2172c393a42Smrg if (s1 == s2) return 0; 2182c393a42Smrg 2192c393a42Smrg FcStrCaseWalkerInit (s1, &w1); 2202c393a42Smrg FcStrCaseWalkerInit (s2, &w2); 2212c393a42Smrg 2222c393a42Smrg for (;;) 2232c393a42Smrg { 2242c393a42Smrg c1 = FcStrCaseWalkerNext (&w1); 2252c393a42Smrg c2 = FcStrCaseWalkerNext (&w2); 2262c393a42Smrg if (!c1 || (c1 != c2)) 2272c393a42Smrg break; 2282c393a42Smrg } 2292c393a42Smrg return (int) c1 - (int) c2; 2302c393a42Smrg} 2312c393a42Smrg 2322c393a42Smrgint 2332c393a42SmrgFcStrCmpIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2) 2342c393a42Smrg{ 2352c393a42Smrg FcCaseWalker w1, w2; 2362c393a42Smrg FcChar8 c1, c2; 2372c393a42Smrg 2382c393a42Smrg if (s1 == s2) return 0; 2392c393a42Smrg 2402c393a42Smrg FcStrCaseWalkerInit (s1, &w1); 2412c393a42Smrg FcStrCaseWalkerInit (s2, &w2); 2422c393a42Smrg 2432c393a42Smrg for (;;) 2442c393a42Smrg { 2452c393a42Smrg c1 = FcStrCaseWalkerNextIgnoreBlanks (&w1); 2462c393a42Smrg c2 = FcStrCaseWalkerNextIgnoreBlanks (&w2); 2472c393a42Smrg if (!c1 || (c1 != c2)) 2482c393a42Smrg break; 2492c393a42Smrg } 2502c393a42Smrg return (int) c1 - (int) c2; 2512c393a42Smrg} 2522c393a42Smrg 2532c393a42Smrgint 2542c393a42SmrgFcStrCmp (const FcChar8 *s1, const FcChar8 *s2) 2552c393a42Smrg{ 2562c393a42Smrg FcChar8 c1, c2; 2572c393a42Smrg 2582c393a42Smrg if (s1 == s2) 2592c393a42Smrg return 0; 2602c393a42Smrg for (;;) 2612c393a42Smrg { 2622c393a42Smrg c1 = *s1++; 2632c393a42Smrg c2 = *s2++; 2642c393a42Smrg if (!c1 || c1 != c2) 2652c393a42Smrg break; 2662c393a42Smrg } 2672c393a42Smrg return (int) c1 - (int) c2; 2682c393a42Smrg} 2692c393a42Smrg 2702c393a42Smrg/* 2712c393a42Smrg * Return a hash value for a string 2722c393a42Smrg */ 2732c393a42Smrg 2742c393a42SmrgFcChar32 2752c393a42SmrgFcStrHashIgnoreCase (const FcChar8 *s) 2762c393a42Smrg{ 2772c393a42Smrg FcChar32 h = 0; 2782c393a42Smrg FcCaseWalker w; 2792c393a42Smrg FcChar8 c; 2802c393a42Smrg 2812c393a42Smrg FcStrCaseWalkerInit (s, &w); 2822c393a42Smrg while ((c = FcStrCaseWalkerNext (&w))) 2832c393a42Smrg h = ((h << 3) ^ (h >> 3)) ^ c; 2842c393a42Smrg return h; 2852c393a42Smrg} 2862c393a42Smrg 2872c393a42Smrg/* 2882c393a42Smrg * Is the head of s1 equal to s2? 2892c393a42Smrg */ 2902c393a42Smrg 2912c393a42Smrgstatic FcBool 2922c393a42SmrgFcStrIsAtIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2) 2932c393a42Smrg{ 2942c393a42Smrg FcCaseWalker w1, w2; 2952c393a42Smrg FcChar8 c1, c2; 2962c393a42Smrg 2972c393a42Smrg FcStrCaseWalkerInit (s1, &w1); 2982c393a42Smrg FcStrCaseWalkerInit (s2, &w2); 2992c393a42Smrg 3002c393a42Smrg for (;;) 3012c393a42Smrg { 3022c393a42Smrg c1 = FcStrCaseWalkerNextIgnoreBlanks (&w1); 3032c393a42Smrg c2 = FcStrCaseWalkerNextIgnoreBlanks (&w2); 3042c393a42Smrg if (!c1 || (c1 != c2)) 3052c393a42Smrg break; 3062c393a42Smrg } 3072c393a42Smrg return c1 == c2 || !c2; 3082c393a42Smrg} 3092c393a42Smrg 3102c393a42Smrg/* 3112c393a42Smrg * Does s1 contain an instance of s2 (ignoring blanks and case)? 3122c393a42Smrg */ 3132c393a42Smrg 3142c393a42Smrgconst FcChar8 * 3152c393a42SmrgFcStrContainsIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2) 3162c393a42Smrg{ 3172c393a42Smrg while (*s1) 3182c393a42Smrg { 3192c393a42Smrg if (FcStrIsAtIgnoreBlanksAndCase (s1, s2)) 3202c393a42Smrg return s1; 3212c393a42Smrg s1++; 3222c393a42Smrg } 3232c393a42Smrg return 0; 3242c393a42Smrg} 3252c393a42Smrg 3262c393a42Smrgstatic FcBool 3272c393a42SmrgFcCharIsPunct (const FcChar8 c) 3282c393a42Smrg{ 3292c393a42Smrg if (c < '0') 3302c393a42Smrg return FcTrue; 3312c393a42Smrg if (c <= '9') 3322c393a42Smrg return FcFalse; 3332c393a42Smrg if (c < 'A') 3342c393a42Smrg return FcTrue; 3352c393a42Smrg if (c <= 'Z') 3362c393a42Smrg return FcFalse; 3372c393a42Smrg if (c < 'a') 3382c393a42Smrg return FcTrue; 3392c393a42Smrg if (c <= 'z') 3402c393a42Smrg return FcFalse; 3412c393a42Smrg if (c <= '~') 3422c393a42Smrg return FcTrue; 3432c393a42Smrg return FcFalse; 3442c393a42Smrg} 3452c393a42Smrg 3462c393a42Smrg/* 3472c393a42Smrg * Is the head of s1 equal to s2? 3482c393a42Smrg */ 3492c393a42Smrg 3502c393a42Smrgstatic FcBool 3512c393a42SmrgFcStrIsAtIgnoreCase (const FcChar8 *s1, const FcChar8 *s2) 3522c393a42Smrg{ 3532c393a42Smrg FcCaseWalker w1, w2; 3542c393a42Smrg FcChar8 c1, c2; 3552c393a42Smrg 3562c393a42Smrg FcStrCaseWalkerInit (s1, &w1); 3572c393a42Smrg FcStrCaseWalkerInit (s2, &w2); 3582c393a42Smrg 3592c393a42Smrg for (;;) 3602c393a42Smrg { 3612c393a42Smrg c1 = FcStrCaseWalkerNext (&w1); 3622c393a42Smrg c2 = FcStrCaseWalkerNext (&w2); 3632c393a42Smrg if (!c1 || (c1 != c2)) 3642c393a42Smrg break; 3652c393a42Smrg } 3662c393a42Smrg return c1 == c2 || !c2; 3672c393a42Smrg} 3682c393a42Smrg 3692c393a42Smrg/* 3702c393a42Smrg * Does s1 contain an instance of s2 (ignoring blanks and case)? 3712c393a42Smrg */ 3722c393a42Smrg 3732c393a42Smrgconst FcChar8 * 3742c393a42SmrgFcStrContainsIgnoreCase (const FcChar8 *s1, const FcChar8 *s2) 3752c393a42Smrg{ 3762c393a42Smrg while (*s1) 3772c393a42Smrg { 3782c393a42Smrg if (FcStrIsAtIgnoreCase (s1, s2)) 3792c393a42Smrg return s1; 3802c393a42Smrg s1++; 3812c393a42Smrg } 3822c393a42Smrg return 0; 3832c393a42Smrg} 3842c393a42Smrg 3852c393a42Smrg/* 3862c393a42Smrg * Does s1 contain an instance of s2 on a word boundary (ignoring case)? 3872c393a42Smrg */ 3882c393a42Smrg 3892c393a42Smrgconst FcChar8 * 3902c393a42SmrgFcStrContainsWord (const FcChar8 *s1, const FcChar8 *s2) 3912c393a42Smrg{ 3922c393a42Smrg FcBool wordStart = FcTrue; 3932c393a42Smrg int s1len = strlen ((char *) s1); 3942c393a42Smrg int s2len = strlen ((char *) s2); 3952c393a42Smrg 3962c393a42Smrg while (s1len >= s2len) 3972c393a42Smrg { 3982c393a42Smrg if (wordStart && 3992c393a42Smrg FcStrIsAtIgnoreCase (s1, s2) && 4002c393a42Smrg (s1len == s2len || FcCharIsPunct (s1[s2len]))) 4012c393a42Smrg { 4022c393a42Smrg return s1; 4032c393a42Smrg } 4042c393a42Smrg wordStart = FcFalse; 4052c393a42Smrg if (FcCharIsPunct (*s1)) 4062c393a42Smrg wordStart = FcTrue; 4072c393a42Smrg s1++; 4082c393a42Smrg s1len--; 4092c393a42Smrg } 4102c393a42Smrg return 0; 4112c393a42Smrg} 4122c393a42Smrg 4132c393a42Smrgconst FcChar8 * 4142c393a42SmrgFcStrStrIgnoreCase (const FcChar8 *s1, const FcChar8 *s2) 4152c393a42Smrg{ 4162c393a42Smrg FcCaseWalker w1, w2; 4172c393a42Smrg FcChar8 c1, c2; 4182c393a42Smrg const FcChar8 *cur; 4192c393a42Smrg 4202c393a42Smrg if (!s1 || !s2) 4212c393a42Smrg return 0; 4222c393a42Smrg 4232c393a42Smrg if (s1 == s2) 4242c393a42Smrg return s1; 4252c393a42Smrg 4262c393a42Smrg FcStrCaseWalkerInit (s1, &w1); 4272c393a42Smrg FcStrCaseWalkerInit (s2, &w2); 4282c393a42Smrg 4292c393a42Smrg c2 = FcStrCaseWalkerNext (&w2); 4302c393a42Smrg 4312c393a42Smrg for (;;) 4322c393a42Smrg { 4332c393a42Smrg cur = w1.src; 4342c393a42Smrg c1 = FcStrCaseWalkerNext (&w1); 4352c393a42Smrg if (!c1) 4362c393a42Smrg break; 4372c393a42Smrg if (c1 == c2) 4382c393a42Smrg { 4392c393a42Smrg FcCaseWalker w1t = w1; 4402c393a42Smrg FcCaseWalker w2t = w2; 4412c393a42Smrg FcChar8 c1t, c2t; 4422c393a42Smrg 4432c393a42Smrg for (;;) 4442c393a42Smrg { 4452c393a42Smrg c1t = FcStrCaseWalkerNext (&w1t); 4462c393a42Smrg c2t = FcStrCaseWalkerNext (&w2t); 4472c393a42Smrg 4482c393a42Smrg if (!c2t) 4492c393a42Smrg return cur; 4502c393a42Smrg if (c2t != c1t) 4512c393a42Smrg break; 4522c393a42Smrg } 4532c393a42Smrg } 4542c393a42Smrg } 4552c393a42Smrg return 0; 4562c393a42Smrg} 4572c393a42Smrg 4582c393a42Smrgconst FcChar8 * 4592c393a42SmrgFcStrStr (const FcChar8 *s1, const FcChar8 *s2) 4602c393a42Smrg{ 4612c393a42Smrg FcChar8 c1, c2; 4622c393a42Smrg const FcChar8 * p = s1; 4632c393a42Smrg const FcChar8 * b = s2; 4642c393a42Smrg 4652c393a42Smrg if (!s1 || !s2) 4662c393a42Smrg return 0; 4672c393a42Smrg 4682c393a42Smrg if (s1 == s2) 4692c393a42Smrg return s1; 4702c393a42Smrg 4712c393a42Smrgagain: 4722c393a42Smrg c2 = *s2++; 4732c393a42Smrg 4742c393a42Smrg if (!c2) 4752c393a42Smrg return 0; 4762c393a42Smrg 4772c393a42Smrg for (;;) 4782c393a42Smrg { 4792c393a42Smrg p = s1; 4802c393a42Smrg c1 = *s1++; 4812c393a42Smrg if (!c1 || c1 == c2) 4822c393a42Smrg break; 4832c393a42Smrg } 4842c393a42Smrg 4852c393a42Smrg if (c1 != c2) 4862c393a42Smrg return 0; 4872c393a42Smrg 4882c393a42Smrg for (;;) 4892c393a42Smrg { 4902c393a42Smrg c1 = *s1; 4912c393a42Smrg c2 = *s2; 4922c393a42Smrg if (c1 && c2 && c1 != c2) 4932c393a42Smrg { 4942c393a42Smrg s1 = p + 1; 4952c393a42Smrg s2 = b; 4962c393a42Smrg goto again; 4972c393a42Smrg } 4982c393a42Smrg if (!c2) 4992c393a42Smrg return p; 5002c393a42Smrg if (!c1) 5012c393a42Smrg return 0; 5022c393a42Smrg ++ s1; 5032c393a42Smrg ++ s2; 5042c393a42Smrg } 5052c393a42Smrg /* never reached. */ 5062c393a42Smrg} 5072c393a42Smrg 5082c393a42Smrgint 5092c393a42SmrgFcUtf8ToUcs4 (const FcChar8 *src_orig, 5102c393a42Smrg FcChar32 *dst, 5112c393a42Smrg int len) 5122c393a42Smrg{ 5132c393a42Smrg const FcChar8 *src = src_orig; 5142c393a42Smrg FcChar8 s; 5152c393a42Smrg int extra; 5162c393a42Smrg FcChar32 result; 5172c393a42Smrg 5182c393a42Smrg if (len == 0) 5192c393a42Smrg return 0; 5202c393a42Smrg 5212c393a42Smrg s = *src++; 5222c393a42Smrg len--; 5232c393a42Smrg 5242c393a42Smrg if (!(s & 0x80)) 5252c393a42Smrg { 5262c393a42Smrg result = s; 5272c393a42Smrg extra = 0; 5282c393a42Smrg } 5292c393a42Smrg else if (!(s & 0x40)) 5302c393a42Smrg { 5312c393a42Smrg return -1; 5322c393a42Smrg } 5332c393a42Smrg else if (!(s & 0x20)) 5342c393a42Smrg { 5352c393a42Smrg result = s & 0x1f; 5362c393a42Smrg extra = 1; 5372c393a42Smrg } 5382c393a42Smrg else if (!(s & 0x10)) 5392c393a42Smrg { 5402c393a42Smrg result = s & 0xf; 5412c393a42Smrg extra = 2; 5422c393a42Smrg } 5432c393a42Smrg else if (!(s & 0x08)) 5442c393a42Smrg { 5452c393a42Smrg result = s & 0x07; 5462c393a42Smrg extra = 3; 5472c393a42Smrg } 5482c393a42Smrg else if (!(s & 0x04)) 5492c393a42Smrg { 5502c393a42Smrg result = s & 0x03; 5512c393a42Smrg extra = 4; 5522c393a42Smrg } 5532c393a42Smrg else if ( ! (s & 0x02)) 5542c393a42Smrg { 5552c393a42Smrg result = s & 0x01; 5562c393a42Smrg extra = 5; 5572c393a42Smrg } 5582c393a42Smrg else 5592c393a42Smrg { 5602c393a42Smrg return -1; 5612c393a42Smrg } 5622c393a42Smrg if (extra > len) 5632c393a42Smrg return -1; 5642c393a42Smrg 5652c393a42Smrg while (extra--) 5662c393a42Smrg { 5672c393a42Smrg result <<= 6; 5682c393a42Smrg s = *src++; 5692c393a42Smrg 5702c393a42Smrg if ((s & 0xc0) != 0x80) 5712c393a42Smrg return -1; 5722c393a42Smrg 5732c393a42Smrg result |= s & 0x3f; 5742c393a42Smrg } 5752c393a42Smrg *dst = result; 5762c393a42Smrg return src - src_orig; 5772c393a42Smrg} 5782c393a42Smrg 5792c393a42SmrgFcBool 5802c393a42SmrgFcUtf8Len (const FcChar8 *string, 5812c393a42Smrg int len, 5822c393a42Smrg int *nchar, 5832c393a42Smrg int *wchar) 5842c393a42Smrg{ 5852c393a42Smrg int n; 5862c393a42Smrg int clen; 5872c393a42Smrg FcChar32 c; 5882c393a42Smrg FcChar32 max; 5892c393a42Smrg 5902c393a42Smrg n = 0; 5912c393a42Smrg max = 0; 5922c393a42Smrg while (len) 5932c393a42Smrg { 5942c393a42Smrg clen = FcUtf8ToUcs4 (string, &c, len); 5952c393a42Smrg if (clen <= 0) /* malformed UTF8 string */ 5962c393a42Smrg return FcFalse; 5972c393a42Smrg if (c > max) 5982c393a42Smrg max = c; 5992c393a42Smrg string += clen; 6002c393a42Smrg len -= clen; 6012c393a42Smrg n++; 6022c393a42Smrg } 6032c393a42Smrg *nchar = n; 6042c393a42Smrg if (max >= 0x10000) 6052c393a42Smrg *wchar = 4; 6062c393a42Smrg else if (max > 0x100) 6072c393a42Smrg *wchar = 2; 6082c393a42Smrg else 6092c393a42Smrg *wchar = 1; 6102c393a42Smrg return FcTrue; 6112c393a42Smrg} 6122c393a42Smrg 6132c393a42Smrgint 6142c393a42SmrgFcUcs4ToUtf8 (FcChar32 ucs4, 6152c393a42Smrg FcChar8 dest[FC_UTF8_MAX_LEN]) 6162c393a42Smrg{ 6172c393a42Smrg int bits; 6182c393a42Smrg FcChar8 *d = dest; 6192c393a42Smrg 6202c393a42Smrg if (ucs4 < 0x80) { *d++= ucs4; bits= -6; } 6212c393a42Smrg else if (ucs4 < 0x800) { *d++= ((ucs4 >> 6) & 0x1F) | 0xC0; bits= 0; } 6222c393a42Smrg else if (ucs4 < 0x10000) { *d++= ((ucs4 >> 12) & 0x0F) | 0xE0; bits= 6; } 6232c393a42Smrg else if (ucs4 < 0x200000) { *d++= ((ucs4 >> 18) & 0x07) | 0xF0; bits= 12; } 6242c393a42Smrg else if (ucs4 < 0x4000000) { *d++= ((ucs4 >> 24) & 0x03) | 0xF8; bits= 18; } 6252c393a42Smrg else if (ucs4 < 0x80000000) { *d++= ((ucs4 >> 30) & 0x01) | 0xFC; bits= 24; } 6262c393a42Smrg else return 0; 6272c393a42Smrg 6282c393a42Smrg for ( ; bits >= 0; bits-= 6) { 6292c393a42Smrg *d++= ((ucs4 >> bits) & 0x3F) | 0x80; 6302c393a42Smrg } 6312c393a42Smrg return d - dest; 6322c393a42Smrg} 6332c393a42Smrg 6342c393a42Smrg#define GetUtf16(src,endian) \ 6352c393a42Smrg ((FcChar16) ((src)[endian == FcEndianBig ? 0 : 1] << 8) | \ 6362c393a42Smrg (FcChar16) ((src)[endian == FcEndianBig ? 1 : 0])) 6372c393a42Smrg 6382c393a42Smrgint 6392c393a42SmrgFcUtf16ToUcs4 (const FcChar8 *src_orig, 6402c393a42Smrg FcEndian endian, 6412c393a42Smrg FcChar32 *dst, 6422c393a42Smrg int len) /* in bytes */ 6432c393a42Smrg{ 6442c393a42Smrg const FcChar8 *src = src_orig; 6452c393a42Smrg FcChar16 a, b; 6462c393a42Smrg FcChar32 result; 6472c393a42Smrg 6482c393a42Smrg if (len < 2) 6492c393a42Smrg return 0; 6502c393a42Smrg 6512c393a42Smrg a = GetUtf16 (src, endian); src += 2; len -= 2; 6522c393a42Smrg 6532c393a42Smrg /* 6542c393a42Smrg * Check for surrogate 6552c393a42Smrg */ 6562c393a42Smrg if ((a & 0xfc00) == 0xd800) 6572c393a42Smrg { 6582c393a42Smrg if (len < 2) 6592c393a42Smrg return 0; 6602c393a42Smrg b = GetUtf16 (src, endian); src += 2; len -= 2; 6612c393a42Smrg /* 6622c393a42Smrg * Check for invalid surrogate sequence 6632c393a42Smrg */ 6642c393a42Smrg if ((b & 0xfc00) != 0xdc00) 6652c393a42Smrg return 0; 6662c393a42Smrg result = ((((FcChar32) a & 0x3ff) << 10) | 6672c393a42Smrg ((FcChar32) b & 0x3ff)) + 0x10000; 6682c393a42Smrg } 6692c393a42Smrg else 6702c393a42Smrg result = a; 6712c393a42Smrg *dst = result; 6722c393a42Smrg return src - src_orig; 6732c393a42Smrg} 6742c393a42Smrg 6752c393a42SmrgFcBool 6762c393a42SmrgFcUtf16Len (const FcChar8 *string, 6772c393a42Smrg FcEndian endian, 6782c393a42Smrg int len, /* in bytes */ 6792c393a42Smrg int *nchar, 6802c393a42Smrg int *wchar) 6812c393a42Smrg{ 6822c393a42Smrg int n; 6832c393a42Smrg int clen; 6842c393a42Smrg FcChar32 c; 6852c393a42Smrg FcChar32 max; 6862c393a42Smrg 6872c393a42Smrg n = 0; 6882c393a42Smrg max = 0; 6892c393a42Smrg while (len) 6902c393a42Smrg { 6912c393a42Smrg clen = FcUtf16ToUcs4 (string, endian, &c, len); 6922c393a42Smrg if (clen <= 0) /* malformed UTF8 string */ 6932c393a42Smrg return FcFalse; 6942c393a42Smrg if (c > max) 6952c393a42Smrg max = c; 6962c393a42Smrg string += clen; 6972c393a42Smrg len -= clen; 6982c393a42Smrg n++; 6992c393a42Smrg } 7002c393a42Smrg *nchar = n; 7012c393a42Smrg if (max >= 0x10000) 7022c393a42Smrg *wchar = 4; 7032c393a42Smrg else if (max > 0x100) 7042c393a42Smrg *wchar = 2; 7052c393a42Smrg else 7062c393a42Smrg *wchar = 1; 7072c393a42Smrg return FcTrue; 7082c393a42Smrg} 7092c393a42Smrg 7102c393a42Smrgvoid 7112c393a42SmrgFcStrBufInit (FcStrBuf *buf, FcChar8 *init, int size) 7122c393a42Smrg{ 7132c393a42Smrg buf->buf = init; 7142c393a42Smrg buf->allocated = FcFalse; 7152c393a42Smrg buf->failed = FcFalse; 7162c393a42Smrg buf->len = 0; 7172c393a42Smrg buf->size = size; 7182c393a42Smrg} 7192c393a42Smrg 7202c393a42Smrgvoid 7212c393a42SmrgFcStrBufDestroy (FcStrBuf *buf) 7222c393a42Smrg{ 7232c393a42Smrg if (buf->allocated) 7242c393a42Smrg { 7252c393a42Smrg FcMemFree (FC_MEM_STRBUF, buf->size); 7262c393a42Smrg free (buf->buf); 7272c393a42Smrg FcStrBufInit (buf, 0, 0); 7282c393a42Smrg } 7292c393a42Smrg} 7302c393a42Smrg 7312c393a42SmrgFcChar8 * 7322c393a42SmrgFcStrBufDone (FcStrBuf *buf) 7332c393a42Smrg{ 7342c393a42Smrg FcChar8 *ret; 7352c393a42Smrg 7362c393a42Smrg ret = malloc (buf->len + 1); 7372c393a42Smrg if (ret) 7382c393a42Smrg { 7392c393a42Smrg FcMemAlloc (FC_MEM_STRING, buf->len + 1); 7402c393a42Smrg memcpy (ret, buf->buf, buf->len); 7412c393a42Smrg ret[buf->len] = '\0'; 7422c393a42Smrg } 7432c393a42Smrg FcStrBufDestroy (buf); 7442c393a42Smrg return ret; 7452c393a42Smrg} 7462c393a42Smrg 7472c393a42SmrgFcBool 7482c393a42SmrgFcStrBufChar (FcStrBuf *buf, FcChar8 c) 7492c393a42Smrg{ 7502c393a42Smrg if (buf->len == buf->size) 7512c393a42Smrg { 7522c393a42Smrg FcChar8 *new; 7532c393a42Smrg int size; 7542c393a42Smrg 7552c393a42Smrg if (buf->allocated) 7562c393a42Smrg { 7572c393a42Smrg size = buf->size * 2; 7582c393a42Smrg new = realloc (buf->buf, size); 7592c393a42Smrg } 7602c393a42Smrg else 7612c393a42Smrg { 7622c393a42Smrg size = buf->size + 64; 7632c393a42Smrg new = malloc (size); 7642c393a42Smrg if (new) 7652c393a42Smrg { 7662c393a42Smrg buf->allocated = FcTrue; 7672c393a42Smrg memcpy (new, buf->buf, buf->len); 7682c393a42Smrg } 7692c393a42Smrg } 7702c393a42Smrg if (!new) 7712c393a42Smrg { 7722c393a42Smrg buf->failed = FcTrue; 7732c393a42Smrg return FcFalse; 7742c393a42Smrg } 7752c393a42Smrg if (buf->size) 7762c393a42Smrg FcMemFree (FC_MEM_STRBUF, buf->size); 7772c393a42Smrg FcMemAlloc (FC_MEM_STRBUF, size); 7782c393a42Smrg buf->size = size; 7792c393a42Smrg buf->buf = new; 7802c393a42Smrg } 7812c393a42Smrg buf->buf[buf->len++] = c; 7822c393a42Smrg return FcTrue; 7832c393a42Smrg} 7842c393a42Smrg 7852c393a42SmrgFcBool 7862c393a42SmrgFcStrBufString (FcStrBuf *buf, const FcChar8 *s) 7872c393a42Smrg{ 7882c393a42Smrg FcChar8 c; 7892c393a42Smrg while ((c = *s++)) 7902c393a42Smrg if (!FcStrBufChar (buf, c)) 7912c393a42Smrg return FcFalse; 7922c393a42Smrg return FcTrue; 7932c393a42Smrg} 7942c393a42Smrg 7952c393a42SmrgFcBool 7962c393a42SmrgFcStrBufData (FcStrBuf *buf, const FcChar8 *s, int len) 7972c393a42Smrg{ 7982c393a42Smrg while (len-- > 0) 7992c393a42Smrg if (!FcStrBufChar (buf, *s++)) 8002c393a42Smrg return FcFalse; 8012c393a42Smrg return FcTrue; 8022c393a42Smrg} 8032c393a42Smrg 8042c393a42SmrgFcBool 8052c393a42SmrgFcStrUsesHome (const FcChar8 *s) 8062c393a42Smrg{ 8072c393a42Smrg return *s == '~'; 8082c393a42Smrg} 8092c393a42Smrg 8102c393a42SmrgFcChar8 * 8112c393a42SmrgFcStrCopyFilename (const FcChar8 *s) 8122c393a42Smrg{ 8132c393a42Smrg FcChar8 *new; 8142c393a42Smrg 8152c393a42Smrg if (*s == '~') 8162c393a42Smrg { 8172c393a42Smrg FcChar8 *home = FcConfigHome (); 8182c393a42Smrg FcChar8 *full; 8192c393a42Smrg int size; 8202c393a42Smrg if (!home) 8212c393a42Smrg return 0; 8222c393a42Smrg size = strlen ((char *) home) + strlen ((char *) s); 8232c393a42Smrg full = (FcChar8 *) malloc (size); 8242c393a42Smrg if (!full) 8252c393a42Smrg return 0; 8262c393a42Smrg strcpy ((char *) full, (char *) home); 8272c393a42Smrg strcat ((char *) full, (char *) s + 1); 8282c393a42Smrg new = FcStrCanonFilename (full); 8292c393a42Smrg free (full); 8302c393a42Smrg } 8312c393a42Smrg else 8322c393a42Smrg new = FcStrCanonFilename (s); 8332c393a42Smrg return new; 8342c393a42Smrg} 8352c393a42Smrg 8362c393a42SmrgFcChar8 * 8372c393a42SmrgFcStrLastSlash (const FcChar8 *path) 8382c393a42Smrg{ 8392c393a42Smrg FcChar8 *slash; 8402c393a42Smrg 8412c393a42Smrg slash = (FcChar8 *) strrchr ((const char *) path, '/'); 8422c393a42Smrg#ifdef _WIN32 8432c393a42Smrg { 8442c393a42Smrg FcChar8 *backslash; 8452c393a42Smrg 8462c393a42Smrg backslash = (FcChar8 *) strrchr ((const char *) path, '\\'); 8472c393a42Smrg if (!slash || (backslash && backslash > slash)) 8482c393a42Smrg slash = backslash; 8492c393a42Smrg } 8502c393a42Smrg#endif 8512c393a42Smrg 8522c393a42Smrg return slash; 8532c393a42Smrg} 8542c393a42Smrg 8552c393a42SmrgFcChar8 * 8562c393a42SmrgFcStrDirname (const FcChar8 *file) 8572c393a42Smrg{ 8582c393a42Smrg FcChar8 *slash; 8592c393a42Smrg FcChar8 *dir; 8602c393a42Smrg 8612c393a42Smrg slash = FcStrLastSlash (file); 8622c393a42Smrg if (!slash) 8632c393a42Smrg return FcStrCopy ((FcChar8 *) "."); 8642c393a42Smrg dir = malloc ((slash - file) + 1); 8652c393a42Smrg if (!dir) 8662c393a42Smrg return 0; 8672c393a42Smrg FcMemAlloc (FC_MEM_STRING, (slash - file) + 1); 8682c393a42Smrg strncpy ((char *) dir, (const char *) file, slash - file); 8692c393a42Smrg dir[slash - file] = '\0'; 8702c393a42Smrg return dir; 8712c393a42Smrg} 8722c393a42Smrg 8732c393a42SmrgFcChar8 * 8742c393a42SmrgFcStrBasename (const FcChar8 *file) 8752c393a42Smrg{ 8762c393a42Smrg FcChar8 *slash; 8772c393a42Smrg 8782c393a42Smrg slash = FcStrLastSlash (file); 8792c393a42Smrg if (!slash) 8802c393a42Smrg return FcStrCopy (file); 8812c393a42Smrg return FcStrCopy (slash + 1); 8822c393a42Smrg} 8832c393a42Smrg 8842c393a42Smrgstatic FcChar8 * 8852c393a42SmrgFcStrCanonAbsoluteFilename (const FcChar8 *s) 8862c393a42Smrg{ 8872c393a42Smrg FcChar8 *file; 8882c393a42Smrg FcChar8 *f; 8892c393a42Smrg const FcChar8 *slash; 8902c393a42Smrg int size; 8912c393a42Smrg 8922c393a42Smrg size = strlen ((char *) s) + 1; 8932c393a42Smrg file = malloc (size); 8942c393a42Smrg if (!file) 8952c393a42Smrg return NULL; 8962c393a42Smrg FcMemAlloc (FC_MEM_STRING, size); 8972c393a42Smrg slash = NULL; 8982c393a42Smrg f = file; 8992c393a42Smrg for (;;) { 9002c393a42Smrg if (*s == '/' || *s == '\0') 9012c393a42Smrg { 9022c393a42Smrg if (slash) 9032c393a42Smrg { 9042c393a42Smrg switch (s - slash) { 9052c393a42Smrg case 2: 9062c393a42Smrg if (!strncmp ((char *) slash, "/.", 2)) 9072c393a42Smrg { 9082c393a42Smrg f -= 2; /* trim /. from file */ 9092c393a42Smrg } 9102c393a42Smrg break; 9112c393a42Smrg case 3: 9122c393a42Smrg if (!strncmp ((char *) slash, "/..", 3)) 9132c393a42Smrg { 9142c393a42Smrg f -= 3; /* trim /.. from file */ 9152c393a42Smrg while (f > file) { 9162c393a42Smrg if (*--f == '/') 9172c393a42Smrg break; 9182c393a42Smrg } 9192c393a42Smrg } 9202c393a42Smrg break; 9212c393a42Smrg } 9222c393a42Smrg } 9232c393a42Smrg slash = s; 9242c393a42Smrg } 9252c393a42Smrg if (!(*f++ = *s++)) 9262c393a42Smrg break; 9272c393a42Smrg } 9282c393a42Smrg return file; 9292c393a42Smrg} 9302c393a42Smrg 9312c393a42Smrg#ifdef _WIN32 9322c393a42Smrg/* 9332c393a42Smrg * Convert '\\' to '/' , remove double '/' 9342c393a42Smrg */ 9352c393a42Smrgstatic void 9362c393a42SmrgFcConvertDosPath (char *str) 9372c393a42Smrg{ 9382c393a42Smrg size_t len = strlen (str); 9392c393a42Smrg char *p = str; 9402c393a42Smrg char *dest = str; 9412c393a42Smrg char *end = str + len; 9422c393a42Smrg char last = 0; 9432c393a42Smrg 9442c393a42Smrg while (p < end) 9452c393a42Smrg { 9462c393a42Smrg if (*p == '\\') 9472c393a42Smrg *p = '/'; 9482c393a42Smrg 9492c393a42Smrg if (*p != '/' 9502c393a42Smrg || last != '/') 9512c393a42Smrg { 9522c393a42Smrg *dest++ = *p; 9532c393a42Smrg } 9542c393a42Smrg 9552c393a42Smrg last = *p; 9562c393a42Smrg p++; 9572c393a42Smrg } 9582c393a42Smrg 9592c393a42Smrg *dest = 0; 9602c393a42Smrg} 9612c393a42Smrg#endif 9622c393a42Smrg 9632c393a42SmrgFcChar8 * 9642c393a42SmrgFcStrCanonFilename (const FcChar8 *s) 9652c393a42Smrg{ 9662c393a42Smrg#ifdef _WIN32 9672c393a42Smrg FcChar8 full[FC_MAX_FILE_LEN + 2]; 9682c393a42Smrg FcChar8 basename[FC_MAX_FILE_LEN + 2]; 9692c393a42Smrg int size = GetFullPathName (s, sizeof (full) -1, 9702c393a42Smrg full, 9712c393a42Smrg basename); 9722c393a42Smrg 9732c393a42Smrg if (size == 0) 9742c393a42Smrg perror ("GetFullPathName"); 9752c393a42Smrg 9762c393a42Smrg FcConvertDosPath (full); 9772c393a42Smrg return FcStrCanonAbsoluteFilename (full); 9782c393a42Smrg#else 9792c393a42Smrg if (s[0] == '/') 9802c393a42Smrg return FcStrCanonAbsoluteFilename (s); 9812c393a42Smrg else 9822c393a42Smrg { 9832c393a42Smrg FcChar8 *full; 9842c393a42Smrg FcChar8 *file; 9852c393a42Smrg 9862c393a42Smrg FcChar8 cwd[FC_MAX_FILE_LEN + 2]; 9872c393a42Smrg if (getcwd ((char *) cwd, FC_MAX_FILE_LEN) == NULL) 9882c393a42Smrg return NULL; 9892c393a42Smrg strcat ((char *) cwd, "/"); 9902c393a42Smrg full = FcStrPlus (cwd, s); 9912c393a42Smrg file = FcStrCanonAbsoluteFilename (full); 9922c393a42Smrg FcStrFree (full); 9932c393a42Smrg return file; 9942c393a42Smrg } 9952c393a42Smrg#endif 9962c393a42Smrg} 9972c393a42Smrg 9982c393a42Smrg 9992c393a42SmrgFcStrSet * 10002c393a42SmrgFcStrSetCreate (void) 10012c393a42Smrg{ 10022c393a42Smrg FcStrSet *set = malloc (sizeof (FcStrSet)); 10032c393a42Smrg if (!set) 10042c393a42Smrg return 0; 10052c393a42Smrg FcMemAlloc (FC_MEM_STRSET, sizeof (FcStrSet)); 10062c393a42Smrg set->ref = 1; 10072c393a42Smrg set->num = 0; 10082c393a42Smrg set->size = 0; 10092c393a42Smrg set->strs = 0; 10102c393a42Smrg return set; 10112c393a42Smrg} 10122c393a42Smrg 10132c393a42Smrgstatic FcBool 10142c393a42Smrg_FcStrSetAppend (FcStrSet *set, FcChar8 *s) 10152c393a42Smrg{ 10162c393a42Smrg if (FcStrSetMember (set, s)) 10172c393a42Smrg { 10182c393a42Smrg FcStrFree (s); 10192c393a42Smrg return FcTrue; 10202c393a42Smrg } 10212c393a42Smrg if (set->num == set->size) 10222c393a42Smrg { 10232c393a42Smrg FcChar8 **strs = malloc ((set->size + 2) * sizeof (FcChar8 *)); 10242c393a42Smrg 10252c393a42Smrg if (!strs) 10262c393a42Smrg return FcFalse; 10272c393a42Smrg FcMemAlloc (FC_MEM_STRSET, (set->size + 2) * sizeof (FcChar8 *)); 10282c393a42Smrg if (set->num) 10292c393a42Smrg memcpy (strs, set->strs, set->num * sizeof (FcChar8 *)); 10302c393a42Smrg if (set->strs) 10312c393a42Smrg { 10322c393a42Smrg FcMemFree (FC_MEM_STRSET, (set->size + 1) * sizeof (FcChar8 *)); 10332c393a42Smrg free (set->strs); 10342c393a42Smrg } 10352c393a42Smrg set->size = set->size + 1; 10362c393a42Smrg set->strs = strs; 10372c393a42Smrg } 10382c393a42Smrg set->strs[set->num++] = s; 10392c393a42Smrg set->strs[set->num] = 0; 10402c393a42Smrg return FcTrue; 10412c393a42Smrg} 10422c393a42Smrg 10432c393a42SmrgFcBool 10442c393a42SmrgFcStrSetMember (FcStrSet *set, const FcChar8 *s) 10452c393a42Smrg{ 10462c393a42Smrg int i; 10472c393a42Smrg 10482c393a42Smrg for (i = 0; i < set->num; i++) 10492c393a42Smrg if (!FcStrCmp (set->strs[i], s)) 10502c393a42Smrg return FcTrue; 10512c393a42Smrg return FcFalse; 10522c393a42Smrg} 10532c393a42Smrg 10542c393a42SmrgFcBool 10552c393a42SmrgFcStrSetEqual (FcStrSet *sa, FcStrSet *sb) 10562c393a42Smrg{ 10572c393a42Smrg int i; 10582c393a42Smrg if (sa->num != sb->num) 10592c393a42Smrg return FcFalse; 10602c393a42Smrg for (i = 0; i < sa->num; i++) 10612c393a42Smrg if (!FcStrSetMember (sb, sa->strs[i])) 10622c393a42Smrg return FcFalse; 10632c393a42Smrg return FcTrue; 10642c393a42Smrg} 10652c393a42Smrg 10662c393a42SmrgFcBool 10672c393a42SmrgFcStrSetAdd (FcStrSet *set, const FcChar8 *s) 10682c393a42Smrg{ 10692c393a42Smrg FcChar8 *new = FcStrCopy (s); 10702c393a42Smrg if (!new) 10712c393a42Smrg return FcFalse; 10722c393a42Smrg if (!_FcStrSetAppend (set, new)) 10732c393a42Smrg { 10742c393a42Smrg FcStrFree (new); 10752c393a42Smrg return FcFalse; 10762c393a42Smrg } 10772c393a42Smrg return FcTrue; 10782c393a42Smrg} 10792c393a42Smrg 10802c393a42SmrgFcBool 10812c393a42SmrgFcStrSetAddFilename (FcStrSet *set, const FcChar8 *s) 10822c393a42Smrg{ 10832c393a42Smrg FcChar8 *new = FcStrCopyFilename (s); 10842c393a42Smrg if (!new) 10852c393a42Smrg return FcFalse; 10862c393a42Smrg if (!_FcStrSetAppend (set, new)) 10872c393a42Smrg { 10882c393a42Smrg FcStrFree (new); 10892c393a42Smrg return FcFalse; 10902c393a42Smrg } 10912c393a42Smrg return FcTrue; 10922c393a42Smrg} 10932c393a42Smrg 10942c393a42SmrgFcBool 10952c393a42SmrgFcStrSetDel (FcStrSet *set, const FcChar8 *s) 10962c393a42Smrg{ 10972c393a42Smrg int i; 10982c393a42Smrg 10992c393a42Smrg for (i = 0; i < set->num; i++) 11002c393a42Smrg if (!FcStrCmp (set->strs[i], s)) 11012c393a42Smrg { 11022c393a42Smrg FcStrFree (set->strs[i]); 11032c393a42Smrg /* 11042c393a42Smrg * copy remaining string pointers and trailing 11052c393a42Smrg * NULL 11062c393a42Smrg */ 11072c393a42Smrg memmove (&set->strs[i], &set->strs[i+1], 11082c393a42Smrg (set->num - i) * sizeof (FcChar8 *)); 11092c393a42Smrg set->num--; 11102c393a42Smrg return FcTrue; 11112c393a42Smrg } 11122c393a42Smrg return FcFalse; 11132c393a42Smrg} 11142c393a42Smrg 11152c393a42Smrgvoid 11162c393a42SmrgFcStrSetDestroy (FcStrSet *set) 11172c393a42Smrg{ 11182c393a42Smrg if (--set->ref == 0) 11192c393a42Smrg { 11202c393a42Smrg int i; 11212c393a42Smrg 11222c393a42Smrg for (i = 0; i < set->num; i++) 11232c393a42Smrg FcStrFree (set->strs[i]); 11242c393a42Smrg if (set->strs) 11252c393a42Smrg { 11262c393a42Smrg FcMemFree (FC_MEM_STRSET, (set->size + 1) * sizeof (FcChar8 *)); 11272c393a42Smrg free (set->strs); 11282c393a42Smrg } 11292c393a42Smrg FcMemFree (FC_MEM_STRSET, sizeof (FcStrSet)); 11302c393a42Smrg free (set); 11312c393a42Smrg } 11322c393a42Smrg} 11332c393a42Smrg 11342c393a42SmrgFcStrList * 11352c393a42SmrgFcStrListCreate (FcStrSet *set) 11362c393a42Smrg{ 11372c393a42Smrg FcStrList *list; 11382c393a42Smrg 11392c393a42Smrg list = malloc (sizeof (FcStrList)); 11402c393a42Smrg if (!list) 11412c393a42Smrg return 0; 11422c393a42Smrg FcMemAlloc (FC_MEM_STRLIST, sizeof (FcStrList)); 11432c393a42Smrg list->set = set; 11442c393a42Smrg set->ref++; 11452c393a42Smrg list->n = 0; 11462c393a42Smrg return list; 11472c393a42Smrg} 11482c393a42Smrg 11492c393a42SmrgFcChar8 * 11502c393a42SmrgFcStrListNext (FcStrList *list) 11512c393a42Smrg{ 11522c393a42Smrg if (list->n >= list->set->num) 11532c393a42Smrg return 0; 11542c393a42Smrg return list->set->strs[list->n++]; 11552c393a42Smrg} 11562c393a42Smrg 11572c393a42Smrgvoid 11582c393a42SmrgFcStrListDone (FcStrList *list) 11592c393a42Smrg{ 11602c393a42Smrg FcStrSetDestroy (list->set); 11612c393a42Smrg FcMemFree (FC_MEM_STRLIST, sizeof (FcStrList)); 11622c393a42Smrg free (list); 11632c393a42Smrg} 11642c393a42Smrg 11652c393a42Smrg#define __fcstr__ 11662c393a42Smrg#include "fcaliastail.h" 11672c393a42Smrg#undef __fcstr__ 1168