fcstr.c revision a4e54154
12c393a42Smrg/* 2a6844aabSmrg * fontconfig/src/fcstr.c 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 10ca08ab68Smrg * documentation, and that the name of the author(s) not be used in 112c393a42Smrg * advertising or publicity pertaining to distribution of the software without 12ca08ab68Smrg * specific, written prior permission. The authors make no 132c393a42Smrg * representations about the suitability of this software for any purpose. It 142c393a42Smrg * is provided "as is" without express or implied warranty. 152c393a42Smrg * 16a6844aabSmrg * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 172c393a42Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 18a6844aabSmrg * EVENT SHALL THE AUTHOR(S) 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> 29c9710b42Smrg 30c9710b42Smrg 31c9710b42Smrg/* Objects MT-safe for readonly access. */ 322c393a42Smrg 332c393a42SmrgFcChar8 * 342c393a42SmrgFcStrCopy (const FcChar8 *s) 352c393a42Smrg{ 36c9710b42Smrg return FcStrdup (s); 372c393a42Smrg} 382c393a42Smrg 39a4e54154Smrgstatic FcChar8 * 40a4e54154SmrgFcStrMakeTriple (const FcChar8 *s1, const FcChar8 *s2, const FcChar8 *s3) 41a4e54154Smrg{ 42a4e54154Smrg int s1l = s1 ? strlen ((char *) s1) : 0; 43a4e54154Smrg int s2l = s2 ? strlen ((char *) s2) : 0; 44a4e54154Smrg int s3l = s3 ? strlen ((char *) s3) : 0; 45a4e54154Smrg int l = s1l + 1 + s2l + 1 + s3l + 1; 46a4e54154Smrg FcChar8 *s = malloc (l); 47a4e54154Smrg 48a4e54154Smrg if (!s) 49a4e54154Smrg return 0; 50a4e54154Smrg if (s1) 51a4e54154Smrg memcpy (s, s1, s1l + 1); 52a4e54154Smrg else 53a4e54154Smrg s[0] = '\0'; 54a4e54154Smrg if (s2) 55a4e54154Smrg memcpy (s + s1l + 1, s2, s2l + 1); 56a4e54154Smrg else 57a4e54154Smrg s[s1l + 1] = '\0'; 58a4e54154Smrg if (s3) 59a4e54154Smrg memcpy (s + s1l + 1 + s2l + 1, s3, s3l + 1); 60a4e54154Smrg else 61a4e54154Smrg s[s1l + 1 + s2l + 1] = '\0'; 62a4e54154Smrg return s; 63a4e54154Smrg} 64a4e54154Smrg 652c393a42SmrgFcChar8 * 662c393a42SmrgFcStrPlus (const FcChar8 *s1, const FcChar8 *s2) 672c393a42Smrg{ 68ca08ab68Smrg int s1l = strlen ((char *) s1); 69ca08ab68Smrg int s2l = strlen ((char *) s2); 70ca08ab68Smrg int l = s1l + s2l + 1; 712c393a42Smrg FcChar8 *s = malloc (l); 722c393a42Smrg 732c393a42Smrg if (!s) 742c393a42Smrg return 0; 75ca08ab68Smrg memcpy (s, s1, s1l); 76ca08ab68Smrg memcpy (s + s1l, s2, s2l + 1); 772c393a42Smrg return s; 782c393a42Smrg} 792c393a42Smrg 802c393a42Smrgvoid 812c393a42SmrgFcStrFree (FcChar8 *s) 822c393a42Smrg{ 832c393a42Smrg free (s); 842c393a42Smrg} 852c393a42Smrg 862c393a42Smrg 872c393a42Smrg#include "../fc-case/fccase.h" 882c393a42Smrg 892c393a42Smrg#define FcCaseFoldUpperCount(cf) \ 902c393a42Smrg ((cf)->method == FC_CASE_FOLD_FULL ? 1 : (cf)->count) 912c393a42Smrg 922c393a42Smrgtypedef struct _FcCaseWalker { 932c393a42Smrg const FcChar8 *read; 942c393a42Smrg const FcChar8 *src; 952c393a42Smrg FcChar8 utf8[FC_MAX_CASE_FOLD_CHARS + 1]; 962c393a42Smrg} FcCaseWalker; 972c393a42Smrg 982c393a42Smrgstatic void 992c393a42SmrgFcStrCaseWalkerInit (const FcChar8 *src, FcCaseWalker *w) 1002c393a42Smrg{ 1012c393a42Smrg w->src = src; 1022c393a42Smrg w->read = 0; 1032c393a42Smrg} 1042c393a42Smrg 1052c393a42Smrgstatic FcChar8 1062c393a42SmrgFcStrCaseWalkerLong (FcCaseWalker *w, FcChar8 r) 1072c393a42Smrg{ 1082c393a42Smrg FcChar32 ucs4; 1092c393a42Smrg int slen; 1102c393a42Smrg int len = strlen((char*)w->src); 1112c393a42Smrg 1122c393a42Smrg slen = FcUtf8ToUcs4 (w->src - 1, &ucs4, len + 1); 1132c393a42Smrg if (slen <= 0) 1142c393a42Smrg return r; 1152c393a42Smrg if (FC_MIN_FOLD_CHAR <= ucs4 && ucs4 <= FC_MAX_FOLD_CHAR) 1162c393a42Smrg { 1172c393a42Smrg int min = 0; 1182c393a42Smrg int max = FC_NUM_CASE_FOLD; 1192c393a42Smrg 1202c393a42Smrg while (min <= max) 1212c393a42Smrg { 1222c393a42Smrg int mid = (min + max) >> 1; 1232c393a42Smrg FcChar32 low = fcCaseFold[mid].upper; 1242c393a42Smrg FcChar32 high = low + FcCaseFoldUpperCount (&fcCaseFold[mid]); 125ca08ab68Smrg 1262c393a42Smrg if (high <= ucs4) 1272c393a42Smrg min = mid + 1; 1282c393a42Smrg else if (ucs4 < low) 1292c393a42Smrg max = mid - 1; 1302c393a42Smrg else 1312c393a42Smrg { 1322c393a42Smrg const FcCaseFold *fold = &fcCaseFold[mid]; 1332c393a42Smrg int dlen; 1342c393a42Smrg 1352c393a42Smrg switch (fold->method) { 1362c393a42Smrg case FC_CASE_FOLD_EVEN_ODD: 1372c393a42Smrg if ((ucs4 & 1) != (fold->upper & 1)) 1382c393a42Smrg return r; 1392c393a42Smrg /* fall through ... */ 1402c393a42Smrg default: 1412c393a42Smrg dlen = FcUcs4ToUtf8 (ucs4 + fold->offset, w->utf8); 1422c393a42Smrg break; 1432c393a42Smrg case FC_CASE_FOLD_FULL: 1442c393a42Smrg dlen = fold->count; 1452c393a42Smrg memcpy (w->utf8, fcCaseFoldChars + fold->offset, dlen); 1462c393a42Smrg break; 1472c393a42Smrg } 1482c393a42Smrg 1492c393a42Smrg /* consume rest of src utf-8 bytes */ 1502c393a42Smrg w->src += slen - 1; 1512c393a42Smrg 1522c393a42Smrg /* read from temp buffer */ 1532c393a42Smrg w->utf8[dlen] = '\0'; 1542c393a42Smrg w->read = w->utf8; 1552c393a42Smrg return *w->read++; 1562c393a42Smrg } 1572c393a42Smrg } 1582c393a42Smrg } 1592c393a42Smrg return r; 1602c393a42Smrg} 1612c393a42Smrg 1622c393a42Smrgstatic FcChar8 163a4e54154SmrgFcStrCaseWalkerNextNonDelim (FcCaseWalker *w, const char *delims) 1642c393a42Smrg{ 1652c393a42Smrg FcChar8 r; 1662c393a42Smrg 167a4e54154Smrg if (FC_UNLIKELY (w->read != NULL)) 1682c393a42Smrg { 1692c393a42Smrg if ((r = *w->read++)) 1702c393a42Smrg return r; 1712c393a42Smrg w->read = 0; 1722c393a42Smrg } 1732c393a42Smrg do 1742c393a42Smrg { 1752c393a42Smrg r = *w->src++; 176c9710b42Smrg } while (r != 0 && delims && strchr (delims, r)); 177ca08ab68Smrg 178a4e54154Smrg if (FC_UNLIKELY ((r & 0xc0) == 0xc0)) 179a4e54154Smrg return FcStrCaseWalkerLong (w, r); 180a4e54154Smrg if ('A' <= r && r <= 'Z') 181a4e54154Smrg r = r - 'A' + 'a'; 182a4e54154Smrg return r; 183a4e54154Smrg} 184a4e54154Smrg 185a4e54154Smrgstatic FcChar8 186a4e54154SmrgFcStrCaseWalkerNextNonBlank (FcCaseWalker *w) 187a4e54154Smrg{ 188a4e54154Smrg FcChar8 r; 189a4e54154Smrg 190a4e54154Smrg if (FC_UNLIKELY (w->read != NULL)) 191a4e54154Smrg { 192a4e54154Smrg if ((r = *w->read++)) 193a4e54154Smrg return r; 194a4e54154Smrg w->read = 0; 195a4e54154Smrg } 196a4e54154Smrg do 197a4e54154Smrg { 198a4e54154Smrg r = *w->src++; 199a4e54154Smrg } while (r == ' '); 200a4e54154Smrg 201a4e54154Smrg if (FC_UNLIKELY ((r & 0xc0) == 0xc0)) 202a4e54154Smrg return FcStrCaseWalkerLong (w, r); 203a4e54154Smrg if ('A' <= r && r <= 'Z') 204a4e54154Smrg r = r - 'A' + 'a'; 205a4e54154Smrg return r; 206a4e54154Smrg} 207a4e54154Smrg 208a4e54154Smrgstatic FcChar8 209a4e54154SmrgFcStrCaseWalkerNext (FcCaseWalker *w) 210a4e54154Smrg{ 211a4e54154Smrg FcChar8 r; 212a4e54154Smrg 213a4e54154Smrg if (FC_UNLIKELY (w->read != NULL)) 214a4e54154Smrg { 215a4e54154Smrg if ((r = *w->read++)) 216a4e54154Smrg return r; 217a4e54154Smrg w->read = 0; 218a4e54154Smrg } 219a4e54154Smrg 220a4e54154Smrg r = *w->src++; 221a4e54154Smrg 222a4e54154Smrg if (FC_UNLIKELY ((r & 0xc0) == 0xc0)) 2232c393a42Smrg return FcStrCaseWalkerLong (w, r); 2242c393a42Smrg if ('A' <= r && r <= 'Z') 2252c393a42Smrg r = r - 'A' + 'a'; 2262c393a42Smrg return r; 2272c393a42Smrg} 2282c393a42Smrg 2292c393a42SmrgFcChar8 * 2302c393a42SmrgFcStrDowncase (const FcChar8 *s) 2312c393a42Smrg{ 2322c393a42Smrg FcCaseWalker w; 2332c393a42Smrg int len = 0; 2342c393a42Smrg FcChar8 *dst, *d; 2352c393a42Smrg 2362c393a42Smrg FcStrCaseWalkerInit (s, &w); 237a4e54154Smrg while (FcStrCaseWalkerNext (&w)) 2382c393a42Smrg len++; 2392c393a42Smrg d = dst = malloc (len + 1); 2402c393a42Smrg if (!d) 2412c393a42Smrg return 0; 2422c393a42Smrg FcStrCaseWalkerInit (s, &w); 243a4e54154Smrg while ((*d++ = FcStrCaseWalkerNext (&w))); 2442c393a42Smrg return dst; 2452c393a42Smrg} 2462c393a42Smrg 2472c393a42Smrgint 2482c393a42SmrgFcStrCmpIgnoreCase (const FcChar8 *s1, const FcChar8 *s2) 2492c393a42Smrg{ 2502c393a42Smrg FcCaseWalker w1, w2; 2512c393a42Smrg FcChar8 c1, c2; 2522c393a42Smrg 2532c393a42Smrg if (s1 == s2) return 0; 254ca08ab68Smrg 2552c393a42Smrg FcStrCaseWalkerInit (s1, &w1); 2562c393a42Smrg FcStrCaseWalkerInit (s2, &w2); 257ca08ab68Smrg 258ca08ab68Smrg for (;;) 2592c393a42Smrg { 260a4e54154Smrg c1 = FcStrCaseWalkerNext (&w1); 261a4e54154Smrg c2 = FcStrCaseWalkerNext (&w2); 2622c393a42Smrg if (!c1 || (c1 != c2)) 2632c393a42Smrg break; 2642c393a42Smrg } 2652c393a42Smrg return (int) c1 - (int) c2; 2662c393a42Smrg} 2672c393a42Smrg 2682c393a42Smrgint 2692c393a42SmrgFcStrCmpIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2) 2702c393a42Smrg{ 2712c393a42Smrg FcCaseWalker w1, w2; 2722c393a42Smrg FcChar8 c1, c2; 2732c393a42Smrg 2742c393a42Smrg if (s1 == s2) return 0; 275ca08ab68Smrg 2762c393a42Smrg FcStrCaseWalkerInit (s1, &w1); 2772c393a42Smrg FcStrCaseWalkerInit (s2, &w2); 278ca08ab68Smrg 279ca08ab68Smrg for (;;) 2802c393a42Smrg { 281a4e54154Smrg c1 = FcStrCaseWalkerNextNonBlank (&w1); 282a4e54154Smrg c2 = FcStrCaseWalkerNextNonBlank (&w2); 2832c393a42Smrg if (!c1 || (c1 != c2)) 2842c393a42Smrg break; 2852c393a42Smrg } 2862c393a42Smrg return (int) c1 - (int) c2; 2872c393a42Smrg} 2882c393a42Smrg 2892c393a42Smrgint 2902c393a42SmrgFcStrCmp (const FcChar8 *s1, const FcChar8 *s2) 2912c393a42Smrg{ 2922c393a42Smrg FcChar8 c1, c2; 293ca08ab68Smrg 2942c393a42Smrg if (s1 == s2) 2952c393a42Smrg return 0; 296ca08ab68Smrg for (;;) 2972c393a42Smrg { 2982c393a42Smrg c1 = *s1++; 2992c393a42Smrg c2 = *s2++; 3002c393a42Smrg if (!c1 || c1 != c2) 3012c393a42Smrg break; 3022c393a42Smrg } 3032c393a42Smrg return (int) c1 - (int) c2; 3042c393a42Smrg} 3052c393a42Smrg 3062c393a42Smrg/* 3072c393a42Smrg * Return a hash value for a string 3082c393a42Smrg */ 3092c393a42Smrg 3102c393a42SmrgFcChar32 3112c393a42SmrgFcStrHashIgnoreCase (const FcChar8 *s) 3122c393a42Smrg{ 3132c393a42Smrg FcChar32 h = 0; 3142c393a42Smrg FcCaseWalker w; 3152c393a42Smrg FcChar8 c; 3162c393a42Smrg 3172c393a42Smrg FcStrCaseWalkerInit (s, &w); 318a4e54154Smrg while ((c = FcStrCaseWalkerNext (&w))) 319a4e54154Smrg h = ((h << 3) ^ (h >> 3)) ^ c; 320a4e54154Smrg return h; 321a4e54154Smrg} 322a4e54154Smrg 323a4e54154SmrgFcChar32 324a4e54154SmrgFcStrHashIgnoreBlanksAndCase (const FcChar8 *s) 325a4e54154Smrg{ 326a4e54154Smrg FcChar32 h = 0; 327a4e54154Smrg FcCaseWalker w; 328a4e54154Smrg FcChar8 c; 329a4e54154Smrg 330a4e54154Smrg FcStrCaseWalkerInit (s, &w); 331a4e54154Smrg while ((c = FcStrCaseWalkerNextNonBlank (&w))) 3322c393a42Smrg h = ((h << 3) ^ (h >> 3)) ^ c; 3332c393a42Smrg return h; 3342c393a42Smrg} 3352c393a42Smrg 3362c393a42Smrg/* 3372c393a42Smrg * Is the head of s1 equal to s2? 3382c393a42Smrg */ 3392c393a42Smrg 3402c393a42Smrgstatic FcBool 3412c393a42SmrgFcStrIsAtIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2) 3422c393a42Smrg{ 3432c393a42Smrg FcCaseWalker w1, w2; 3442c393a42Smrg FcChar8 c1, c2; 3452c393a42Smrg 3462c393a42Smrg FcStrCaseWalkerInit (s1, &w1); 3472c393a42Smrg FcStrCaseWalkerInit (s2, &w2); 348ca08ab68Smrg 349ca08ab68Smrg for (;;) 3502c393a42Smrg { 351a4e54154Smrg c1 = FcStrCaseWalkerNextNonBlank (&w1); 352a4e54154Smrg c2 = FcStrCaseWalkerNextNonBlank (&w2); 3532c393a42Smrg if (!c1 || (c1 != c2)) 3542c393a42Smrg break; 3552c393a42Smrg } 3562c393a42Smrg return c1 == c2 || !c2; 3572c393a42Smrg} 3582c393a42Smrg 3592c393a42Smrg/* 3602c393a42Smrg * Does s1 contain an instance of s2 (ignoring blanks and case)? 3612c393a42Smrg */ 3622c393a42Smrg 3632c393a42Smrgconst FcChar8 * 3642c393a42SmrgFcStrContainsIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2) 3652c393a42Smrg{ 3662c393a42Smrg while (*s1) 3672c393a42Smrg { 3682c393a42Smrg if (FcStrIsAtIgnoreBlanksAndCase (s1, s2)) 3692c393a42Smrg return s1; 3702c393a42Smrg s1++; 3712c393a42Smrg } 3722c393a42Smrg return 0; 3732c393a42Smrg} 3742c393a42Smrg 3752c393a42Smrgstatic FcBool 3762c393a42SmrgFcCharIsPunct (const FcChar8 c) 3772c393a42Smrg{ 3782c393a42Smrg if (c < '0') 3792c393a42Smrg return FcTrue; 3802c393a42Smrg if (c <= '9') 3812c393a42Smrg return FcFalse; 3822c393a42Smrg if (c < 'A') 3832c393a42Smrg return FcTrue; 3842c393a42Smrg if (c <= 'Z') 3852c393a42Smrg return FcFalse; 3862c393a42Smrg if (c < 'a') 3872c393a42Smrg return FcTrue; 3882c393a42Smrg if (c <= 'z') 3892c393a42Smrg return FcFalse; 3902c393a42Smrg if (c <= '~') 3912c393a42Smrg return FcTrue; 3922c393a42Smrg return FcFalse; 3932c393a42Smrg} 3942c393a42Smrg 3952c393a42Smrg/* 3962c393a42Smrg * Is the head of s1 equal to s2? 3972c393a42Smrg */ 3982c393a42Smrg 3992c393a42Smrgstatic FcBool 4002c393a42SmrgFcStrIsAtIgnoreCase (const FcChar8 *s1, const FcChar8 *s2) 4012c393a42Smrg{ 4022c393a42Smrg FcCaseWalker w1, w2; 4032c393a42Smrg FcChar8 c1, c2; 4042c393a42Smrg 4052c393a42Smrg FcStrCaseWalkerInit (s1, &w1); 4062c393a42Smrg FcStrCaseWalkerInit (s2, &w2); 407ca08ab68Smrg 408ca08ab68Smrg for (;;) 4092c393a42Smrg { 410a4e54154Smrg c1 = FcStrCaseWalkerNext (&w1); 411a4e54154Smrg c2 = FcStrCaseWalkerNext (&w2); 4122c393a42Smrg if (!c1 || (c1 != c2)) 4132c393a42Smrg break; 4142c393a42Smrg } 4152c393a42Smrg return c1 == c2 || !c2; 4162c393a42Smrg} 4172c393a42Smrg 4182c393a42Smrg/* 4192c393a42Smrg * Does s1 contain an instance of s2 (ignoring blanks and case)? 4202c393a42Smrg */ 4212c393a42Smrg 4222c393a42Smrgconst FcChar8 * 4232c393a42SmrgFcStrContainsIgnoreCase (const FcChar8 *s1, const FcChar8 *s2) 4242c393a42Smrg{ 4252c393a42Smrg while (*s1) 4262c393a42Smrg { 4272c393a42Smrg if (FcStrIsAtIgnoreCase (s1, s2)) 4282c393a42Smrg return s1; 4292c393a42Smrg s1++; 4302c393a42Smrg } 4312c393a42Smrg return 0; 4322c393a42Smrg} 4332c393a42Smrg 4342c393a42Smrg/* 4352c393a42Smrg * Does s1 contain an instance of s2 on a word boundary (ignoring case)? 4362c393a42Smrg */ 4372c393a42Smrg 4382c393a42Smrgconst FcChar8 * 4392c393a42SmrgFcStrContainsWord (const FcChar8 *s1, const FcChar8 *s2) 4402c393a42Smrg{ 4412c393a42Smrg FcBool wordStart = FcTrue; 4422c393a42Smrg int s1len = strlen ((char *) s1); 4432c393a42Smrg int s2len = strlen ((char *) s2); 4442c393a42Smrg 4452c393a42Smrg while (s1len >= s2len) 4462c393a42Smrg { 447ca08ab68Smrg if (wordStart && 4482c393a42Smrg FcStrIsAtIgnoreCase (s1, s2) && 4492c393a42Smrg (s1len == s2len || FcCharIsPunct (s1[s2len]))) 4502c393a42Smrg { 4512c393a42Smrg return s1; 4522c393a42Smrg } 4532c393a42Smrg wordStart = FcFalse; 4542c393a42Smrg if (FcCharIsPunct (*s1)) 4552c393a42Smrg wordStart = FcTrue; 4562c393a42Smrg s1++; 4572c393a42Smrg s1len--; 4582c393a42Smrg } 4592c393a42Smrg return 0; 4602c393a42Smrg} 4612c393a42Smrg 462c9710b42Smrg/* 463a4e54154Smrg * returns the number of strings (ignoring delimiters and case) being matched 464c9710b42Smrg */ 465c9710b42Smrg 466c9710b42Smrgint 467c9710b42SmrgFcStrMatchIgnoreCaseAndDelims (const FcChar8 *s1, const FcChar8 *s2, const FcChar8 *delims) 468c9710b42Smrg{ 469c9710b42Smrg FcCaseWalker w1, w2; 470c9710b42Smrg FcChar8 c1, c2; 471c9710b42Smrg 472c9710b42Smrg if (s1 == s2) return 0; 473c9710b42Smrg 474c9710b42Smrg FcStrCaseWalkerInit (s1, &w1); 475c9710b42Smrg FcStrCaseWalkerInit (s2, &w2); 476c9710b42Smrg 477c9710b42Smrg for (;;) 478c9710b42Smrg { 479a4e54154Smrg c1 = FcStrCaseWalkerNextNonDelim (&w1, (const char *)delims); 480a4e54154Smrg c2 = FcStrCaseWalkerNextNonDelim (&w2, (const char *)delims); 481c9710b42Smrg if (!c1 || (c1 != c2)) 482c9710b42Smrg break; 483c9710b42Smrg } 484c9710b42Smrg return w1.src - s1 - 1; 485c9710b42Smrg} 486c9710b42Smrg 487c9710b42SmrgFcBool 488c9710b42SmrgFcStrGlobMatch (const FcChar8 *glob, 489c9710b42Smrg const FcChar8 *string) 490c9710b42Smrg{ 491c9710b42Smrg FcChar8 c; 492c9710b42Smrg 493c9710b42Smrg while ((c = *glob++)) 494c9710b42Smrg { 495c9710b42Smrg switch (c) { 496c9710b42Smrg case '*': 497c9710b42Smrg /* short circuit common case */ 498c9710b42Smrg if (!*glob) 499c9710b42Smrg return FcTrue; 500c9710b42Smrg /* short circuit another common case */ 501c9710b42Smrg if (strchr ((char *) glob, '*') == 0) 502c9710b42Smrg { 503c9710b42Smrg size_t l1, l2; 504c9710b42Smrg 505c9710b42Smrg l1 = strlen ((char *) string); 506c9710b42Smrg l2 = strlen ((char *) glob); 507c9710b42Smrg if (l1 < l2) 508c9710b42Smrg return FcFalse; 509c9710b42Smrg string += (l1 - l2); 510c9710b42Smrg } 511c9710b42Smrg while (*string) 512c9710b42Smrg { 513c9710b42Smrg if (FcStrGlobMatch (glob, string)) 514c9710b42Smrg return FcTrue; 515c9710b42Smrg string++; 516c9710b42Smrg } 517c9710b42Smrg return FcFalse; 518c9710b42Smrg case '?': 519c9710b42Smrg if (*string++ == '\0') 520c9710b42Smrg return FcFalse; 521c9710b42Smrg break; 522c9710b42Smrg default: 523c9710b42Smrg if (*string++ != c) 524c9710b42Smrg return FcFalse; 525c9710b42Smrg break; 526c9710b42Smrg } 527c9710b42Smrg } 528c9710b42Smrg return *string == '\0'; 529c9710b42Smrg} 530c9710b42Smrg 5312c393a42Smrgconst FcChar8 * 5322c393a42SmrgFcStrStrIgnoreCase (const FcChar8 *s1, const FcChar8 *s2) 5332c393a42Smrg{ 5342c393a42Smrg FcCaseWalker w1, w2; 5352c393a42Smrg FcChar8 c1, c2; 5362c393a42Smrg const FcChar8 *cur; 5372c393a42Smrg 5382c393a42Smrg if (!s1 || !s2) 5392c393a42Smrg return 0; 5402c393a42Smrg 5412c393a42Smrg if (s1 == s2) 5422c393a42Smrg return s1; 543ca08ab68Smrg 5442c393a42Smrg FcStrCaseWalkerInit (s1, &w1); 5452c393a42Smrg FcStrCaseWalkerInit (s2, &w2); 546ca08ab68Smrg 547a4e54154Smrg c2 = FcStrCaseWalkerNext (&w2); 548ca08ab68Smrg 5492c393a42Smrg for (;;) 5502c393a42Smrg { 5512c393a42Smrg cur = w1.src; 552a4e54154Smrg c1 = FcStrCaseWalkerNext (&w1); 5532c393a42Smrg if (!c1) 5542c393a42Smrg break; 5552c393a42Smrg if (c1 == c2) 5562c393a42Smrg { 5572c393a42Smrg FcCaseWalker w1t = w1; 5582c393a42Smrg FcCaseWalker w2t = w2; 5592c393a42Smrg FcChar8 c1t, c2t; 5602c393a42Smrg 5612c393a42Smrg for (;;) 5622c393a42Smrg { 563a4e54154Smrg c1t = FcStrCaseWalkerNext (&w1t); 564a4e54154Smrg c2t = FcStrCaseWalkerNext (&w2t); 5652c393a42Smrg 5662c393a42Smrg if (!c2t) 5672c393a42Smrg return cur; 5682c393a42Smrg if (c2t != c1t) 5692c393a42Smrg break; 5702c393a42Smrg } 5712c393a42Smrg } 5722c393a42Smrg } 5732c393a42Smrg return 0; 5742c393a42Smrg} 5752c393a42Smrg 5762c393a42Smrgconst FcChar8 * 5772c393a42SmrgFcStrStr (const FcChar8 *s1, const FcChar8 *s2) 5782c393a42Smrg{ 5792c393a42Smrg FcChar8 c1, c2; 5802c393a42Smrg const FcChar8 * p = s1; 5812c393a42Smrg const FcChar8 * b = s2; 5822c393a42Smrg 5832c393a42Smrg if (!s1 || !s2) 5842c393a42Smrg return 0; 5852c393a42Smrg 5862c393a42Smrg if (s1 == s2) 5872c393a42Smrg return s1; 5882c393a42Smrg 5892c393a42Smrgagain: 5902c393a42Smrg c2 = *s2++; 5912c393a42Smrg 5922c393a42Smrg if (!c2) 5932c393a42Smrg return 0; 5942c393a42Smrg 595ca08ab68Smrg for (;;) 5962c393a42Smrg { 5972c393a42Smrg p = s1; 5982c393a42Smrg c1 = *s1++; 5992c393a42Smrg if (!c1 || c1 == c2) 6002c393a42Smrg break; 6012c393a42Smrg } 6022c393a42Smrg 6032c393a42Smrg if (c1 != c2) 6042c393a42Smrg return 0; 6052c393a42Smrg 6062c393a42Smrg for (;;) 6072c393a42Smrg { 6082c393a42Smrg c1 = *s1; 6092c393a42Smrg c2 = *s2; 6102c393a42Smrg if (c1 && c2 && c1 != c2) 6112c393a42Smrg { 6122c393a42Smrg s1 = p + 1; 6132c393a42Smrg s2 = b; 6142c393a42Smrg goto again; 6152c393a42Smrg } 6162c393a42Smrg if (!c2) 6172c393a42Smrg return p; 6182c393a42Smrg if (!c1) 6192c393a42Smrg return 0; 6202c393a42Smrg ++ s1; 6212c393a42Smrg ++ s2; 6222c393a42Smrg } 6232c393a42Smrg /* never reached. */ 6242c393a42Smrg} 6252c393a42Smrg 6262c393a42Smrgint 6272c393a42SmrgFcUtf8ToUcs4 (const FcChar8 *src_orig, 6282c393a42Smrg FcChar32 *dst, 6292c393a42Smrg int len) 6302c393a42Smrg{ 6312c393a42Smrg const FcChar8 *src = src_orig; 6322c393a42Smrg FcChar8 s; 6332c393a42Smrg int extra; 6342c393a42Smrg FcChar32 result; 6352c393a42Smrg 6362c393a42Smrg if (len == 0) 6372c393a42Smrg return 0; 638ca08ab68Smrg 6392c393a42Smrg s = *src++; 6402c393a42Smrg len--; 641ca08ab68Smrg 6422c393a42Smrg if (!(s & 0x80)) 6432c393a42Smrg { 6442c393a42Smrg result = s; 6452c393a42Smrg extra = 0; 646ca08ab68Smrg } 6472c393a42Smrg else if (!(s & 0x40)) 6482c393a42Smrg { 6492c393a42Smrg return -1; 6502c393a42Smrg } 6512c393a42Smrg else if (!(s & 0x20)) 6522c393a42Smrg { 6532c393a42Smrg result = s & 0x1f; 6542c393a42Smrg extra = 1; 6552c393a42Smrg } 6562c393a42Smrg else if (!(s & 0x10)) 6572c393a42Smrg { 6582c393a42Smrg result = s & 0xf; 6592c393a42Smrg extra = 2; 6602c393a42Smrg } 6612c393a42Smrg else if (!(s & 0x08)) 6622c393a42Smrg { 6632c393a42Smrg result = s & 0x07; 6642c393a42Smrg extra = 3; 6652c393a42Smrg } 6662c393a42Smrg else if (!(s & 0x04)) 6672c393a42Smrg { 6682c393a42Smrg result = s & 0x03; 6692c393a42Smrg extra = 4; 6702c393a42Smrg } 6712c393a42Smrg else if ( ! (s & 0x02)) 6722c393a42Smrg { 6732c393a42Smrg result = s & 0x01; 6742c393a42Smrg extra = 5; 6752c393a42Smrg } 6762c393a42Smrg else 6772c393a42Smrg { 6782c393a42Smrg return -1; 6792c393a42Smrg } 6802c393a42Smrg if (extra > len) 6812c393a42Smrg return -1; 682ca08ab68Smrg 6832c393a42Smrg while (extra--) 6842c393a42Smrg { 6852c393a42Smrg result <<= 6; 6862c393a42Smrg s = *src++; 6872c393a42Smrg 6882c393a42Smrg if ((s & 0xc0) != 0x80) 6892c393a42Smrg return -1; 6902c393a42Smrg 6912c393a42Smrg result |= s & 0x3f; 6922c393a42Smrg } 6932c393a42Smrg *dst = result; 6942c393a42Smrg return src - src_orig; 6952c393a42Smrg} 6962c393a42Smrg 6972c393a42SmrgFcBool 6982c393a42SmrgFcUtf8Len (const FcChar8 *string, 6992c393a42Smrg int len, 7002c393a42Smrg int *nchar, 7012c393a42Smrg int *wchar) 7022c393a42Smrg{ 7032c393a42Smrg int n; 7042c393a42Smrg int clen; 7052c393a42Smrg FcChar32 c; 7062c393a42Smrg FcChar32 max; 707ca08ab68Smrg 7082c393a42Smrg n = 0; 7092c393a42Smrg max = 0; 7102c393a42Smrg while (len) 7112c393a42Smrg { 7122c393a42Smrg clen = FcUtf8ToUcs4 (string, &c, len); 7132c393a42Smrg if (clen <= 0) /* malformed UTF8 string */ 7142c393a42Smrg return FcFalse; 7152c393a42Smrg if (c > max) 7162c393a42Smrg max = c; 7172c393a42Smrg string += clen; 7182c393a42Smrg len -= clen; 7192c393a42Smrg n++; 7202c393a42Smrg } 7212c393a42Smrg *nchar = n; 7222c393a42Smrg if (max >= 0x10000) 7232c393a42Smrg *wchar = 4; 7242c393a42Smrg else if (max > 0x100) 7252c393a42Smrg *wchar = 2; 7262c393a42Smrg else 7272c393a42Smrg *wchar = 1; 7282c393a42Smrg return FcTrue; 7292c393a42Smrg} 7302c393a42Smrg 7312c393a42Smrgint 7322c393a42SmrgFcUcs4ToUtf8 (FcChar32 ucs4, 7332c393a42Smrg FcChar8 dest[FC_UTF8_MAX_LEN]) 7342c393a42Smrg{ 7352c393a42Smrg int bits; 7362c393a42Smrg FcChar8 *d = dest; 737ca08ab68Smrg 7382c393a42Smrg if (ucs4 < 0x80) { *d++= ucs4; bits= -6; } 7392c393a42Smrg else if (ucs4 < 0x800) { *d++= ((ucs4 >> 6) & 0x1F) | 0xC0; bits= 0; } 7402c393a42Smrg else if (ucs4 < 0x10000) { *d++= ((ucs4 >> 12) & 0x0F) | 0xE0; bits= 6; } 7412c393a42Smrg else if (ucs4 < 0x200000) { *d++= ((ucs4 >> 18) & 0x07) | 0xF0; bits= 12; } 7422c393a42Smrg else if (ucs4 < 0x4000000) { *d++= ((ucs4 >> 24) & 0x03) | 0xF8; bits= 18; } 7432c393a42Smrg else if (ucs4 < 0x80000000) { *d++= ((ucs4 >> 30) & 0x01) | 0xFC; bits= 24; } 7442c393a42Smrg else return 0; 7452c393a42Smrg 7462c393a42Smrg for ( ; bits >= 0; bits-= 6) { 7472c393a42Smrg *d++= ((ucs4 >> bits) & 0x3F) | 0x80; 7482c393a42Smrg } 7492c393a42Smrg return d - dest; 7502c393a42Smrg} 7512c393a42Smrg 7522c393a42Smrg#define GetUtf16(src,endian) \ 7532c393a42Smrg ((FcChar16) ((src)[endian == FcEndianBig ? 0 : 1] << 8) | \ 7542c393a42Smrg (FcChar16) ((src)[endian == FcEndianBig ? 1 : 0])) 7552c393a42Smrg 7562c393a42Smrgint 7572c393a42SmrgFcUtf16ToUcs4 (const FcChar8 *src_orig, 7582c393a42Smrg FcEndian endian, 7592c393a42Smrg FcChar32 *dst, 7602c393a42Smrg int len) /* in bytes */ 7612c393a42Smrg{ 7622c393a42Smrg const FcChar8 *src = src_orig; 7632c393a42Smrg FcChar16 a, b; 7642c393a42Smrg FcChar32 result; 7652c393a42Smrg 7662c393a42Smrg if (len < 2) 7672c393a42Smrg return 0; 768ca08ab68Smrg 7692c393a42Smrg a = GetUtf16 (src, endian); src += 2; len -= 2; 770ca08ab68Smrg 771ca08ab68Smrg /* 772ca08ab68Smrg * Check for surrogate 7732c393a42Smrg */ 7742c393a42Smrg if ((a & 0xfc00) == 0xd800) 7752c393a42Smrg { 7762c393a42Smrg if (len < 2) 7772c393a42Smrg return 0; 7782c393a42Smrg b = GetUtf16 (src, endian); src += 2; len -= 2; 7792c393a42Smrg /* 7802c393a42Smrg * Check for invalid surrogate sequence 7812c393a42Smrg */ 7822c393a42Smrg if ((b & 0xfc00) != 0xdc00) 7832c393a42Smrg return 0; 7842c393a42Smrg result = ((((FcChar32) a & 0x3ff) << 10) | 7852c393a42Smrg ((FcChar32) b & 0x3ff)) + 0x10000; 7862c393a42Smrg } 7872c393a42Smrg else 7882c393a42Smrg result = a; 7892c393a42Smrg *dst = result; 7902c393a42Smrg return src - src_orig; 7912c393a42Smrg} 7922c393a42Smrg 7932c393a42SmrgFcBool 7942c393a42SmrgFcUtf16Len (const FcChar8 *string, 7952c393a42Smrg FcEndian endian, 7962c393a42Smrg int len, /* in bytes */ 7972c393a42Smrg int *nchar, 7982c393a42Smrg int *wchar) 7992c393a42Smrg{ 8002c393a42Smrg int n; 8012c393a42Smrg int clen; 8022c393a42Smrg FcChar32 c; 8032c393a42Smrg FcChar32 max; 804ca08ab68Smrg 8052c393a42Smrg n = 0; 8062c393a42Smrg max = 0; 8072c393a42Smrg while (len) 8082c393a42Smrg { 8092c393a42Smrg clen = FcUtf16ToUcs4 (string, endian, &c, len); 8102c393a42Smrg if (clen <= 0) /* malformed UTF8 string */ 8112c393a42Smrg return FcFalse; 8122c393a42Smrg if (c > max) 8132c393a42Smrg max = c; 8142c393a42Smrg string += clen; 8152c393a42Smrg len -= clen; 8162c393a42Smrg n++; 8172c393a42Smrg } 8182c393a42Smrg *nchar = n; 8192c393a42Smrg if (max >= 0x10000) 8202c393a42Smrg *wchar = 4; 8212c393a42Smrg else if (max > 0x100) 8222c393a42Smrg *wchar = 2; 8232c393a42Smrg else 8242c393a42Smrg *wchar = 1; 8252c393a42Smrg return FcTrue; 8262c393a42Smrg} 8272c393a42Smrg 8282c393a42Smrgvoid 8292c393a42SmrgFcStrBufInit (FcStrBuf *buf, FcChar8 *init, int size) 8302c393a42Smrg{ 831a6844aabSmrg if (init) 832a6844aabSmrg { 833a6844aabSmrg buf->buf = init; 834a6844aabSmrg buf->size = size; 835a6844aabSmrg } else 836a6844aabSmrg { 837a6844aabSmrg buf->buf = buf->buf_static; 838a6844aabSmrg buf->size = sizeof (buf->buf_static); 839a6844aabSmrg } 8402c393a42Smrg buf->allocated = FcFalse; 8412c393a42Smrg buf->failed = FcFalse; 8422c393a42Smrg buf->len = 0; 8432c393a42Smrg} 8442c393a42Smrg 8452c393a42Smrgvoid 8462c393a42SmrgFcStrBufDestroy (FcStrBuf *buf) 8472c393a42Smrg{ 8482c393a42Smrg if (buf->allocated) 8492c393a42Smrg { 8502c393a42Smrg free (buf->buf); 8512c393a42Smrg FcStrBufInit (buf, 0, 0); 8522c393a42Smrg } 8532c393a42Smrg} 8542c393a42Smrg 8552c393a42SmrgFcChar8 * 8562c393a42SmrgFcStrBufDone (FcStrBuf *buf) 8572c393a42Smrg{ 8582c393a42Smrg FcChar8 *ret; 8592c393a42Smrg 860a6844aabSmrg if (buf->failed) 861a6844aabSmrg ret = NULL; 862a6844aabSmrg else 863a6844aabSmrg ret = malloc (buf->len + 1); 8642c393a42Smrg if (ret) 8652c393a42Smrg { 8662c393a42Smrg memcpy (ret, buf->buf, buf->len); 8672c393a42Smrg ret[buf->len] = '\0'; 8682c393a42Smrg } 8692c393a42Smrg FcStrBufDestroy (buf); 8702c393a42Smrg return ret; 8712c393a42Smrg} 8722c393a42Smrg 873a6844aabSmrgFcChar8 * 874a6844aabSmrgFcStrBufDoneStatic (FcStrBuf *buf) 875a6844aabSmrg{ 876a6844aabSmrg FcStrBufChar (buf, '\0'); 877a6844aabSmrg 878a6844aabSmrg if (buf->failed) 879a6844aabSmrg return NULL; 880a6844aabSmrg 881a6844aabSmrg return buf->buf; 882a6844aabSmrg} 883a6844aabSmrg 8842c393a42SmrgFcBool 8852c393a42SmrgFcStrBufChar (FcStrBuf *buf, FcChar8 c) 8862c393a42Smrg{ 8872c393a42Smrg if (buf->len == buf->size) 8882c393a42Smrg { 8892c393a42Smrg FcChar8 *new; 8902c393a42Smrg int size; 8912c393a42Smrg 892a6844aabSmrg if (buf->failed) 893a6844aabSmrg return FcFalse; 894a6844aabSmrg 8952c393a42Smrg if (buf->allocated) 8962c393a42Smrg { 8972c393a42Smrg size = buf->size * 2; 8982c393a42Smrg new = realloc (buf->buf, size); 8992c393a42Smrg } 9002c393a42Smrg else 9012c393a42Smrg { 9022c393a42Smrg size = buf->size + 64; 9032c393a42Smrg new = malloc (size); 9042c393a42Smrg if (new) 9052c393a42Smrg { 9062c393a42Smrg buf->allocated = FcTrue; 9072c393a42Smrg memcpy (new, buf->buf, buf->len); 9082c393a42Smrg } 9092c393a42Smrg } 9102c393a42Smrg if (!new) 9112c393a42Smrg { 9122c393a42Smrg buf->failed = FcTrue; 9132c393a42Smrg return FcFalse; 9142c393a42Smrg } 9152c393a42Smrg buf->size = size; 9162c393a42Smrg buf->buf = new; 9172c393a42Smrg } 9182c393a42Smrg buf->buf[buf->len++] = c; 9192c393a42Smrg return FcTrue; 9202c393a42Smrg} 9212c393a42Smrg 9222c393a42SmrgFcBool 9232c393a42SmrgFcStrBufString (FcStrBuf *buf, const FcChar8 *s) 9242c393a42Smrg{ 9252c393a42Smrg FcChar8 c; 9262c393a42Smrg while ((c = *s++)) 9272c393a42Smrg if (!FcStrBufChar (buf, c)) 9282c393a42Smrg return FcFalse; 9292c393a42Smrg return FcTrue; 9302c393a42Smrg} 9312c393a42Smrg 9322c393a42SmrgFcBool 9332c393a42SmrgFcStrBufData (FcStrBuf *buf, const FcChar8 *s, int len) 9342c393a42Smrg{ 9352c393a42Smrg while (len-- > 0) 9362c393a42Smrg if (!FcStrBufChar (buf, *s++)) 9372c393a42Smrg return FcFalse; 9382c393a42Smrg return FcTrue; 9392c393a42Smrg} 9402c393a42Smrg 9412c393a42SmrgFcBool 9422c393a42SmrgFcStrUsesHome (const FcChar8 *s) 9432c393a42Smrg{ 9442c393a42Smrg return *s == '~'; 9452c393a42Smrg} 9462c393a42Smrg 947a32e9e42SmrgFcBool 948a32e9e42SmrgFcStrIsAbsoluteFilename (const FcChar8 *s) 949a32e9e42Smrg{ 950a32e9e42Smrg#ifdef _WIN32 951a32e9e42Smrg if (*s == '\\' || 952a32e9e42Smrg (isalpha (*s) && s[1] == ':' && (s[2] == '/' || s[2] == '\\'))) 953a32e9e42Smrg return FcTrue; 954a32e9e42Smrg#endif 955a32e9e42Smrg return *s == '/'; 956a32e9e42Smrg} 957a32e9e42Smrg 958c9710b42SmrgFcChar8 * 959c9710b42SmrgFcStrBuildFilename (const FcChar8 *path, 960c9710b42Smrg ...) 961c9710b42Smrg{ 962c9710b42Smrg va_list ap; 963b09479dcSmrg FcStrSet *sset; 964c9710b42Smrg FcStrList *list; 965c9710b42Smrg FcChar8 *s, *ret = NULL, *p; 966c9710b42Smrg size_t len = 0; 967c9710b42Smrg 968b09479dcSmrg if (!path) 969b09479dcSmrg return NULL; 970b09479dcSmrg 971953daebaSmrg sset = FcStrSetCreateEx (FCSS_ALLOW_DUPLICATES | FCSS_GROW_BY_64); 972b09479dcSmrg if (!sset) 973c9710b42Smrg return NULL; 974c9710b42Smrg 975c9710b42Smrg if (!FcStrSetAdd (sset, path)) 976c9710b42Smrg goto bail0; 977c9710b42Smrg 978c9710b42Smrg va_start (ap, path); 979c9710b42Smrg while (1) 980c9710b42Smrg { 981c9710b42Smrg s = (FcChar8 *)va_arg (ap, FcChar8 *); 982c9710b42Smrg if (!s) 983c9710b42Smrg break; 984c9710b42Smrg if (!FcStrSetAdd (sset, s)) 985c9710b42Smrg goto bail1; 986c9710b42Smrg } 987c9710b42Smrg list = FcStrListCreate (sset); 988c9710b42Smrg while ((s = FcStrListNext (list))) 989c9710b42Smrg { 990c9710b42Smrg len += strlen ((const char *)s) + 1; 991c9710b42Smrg } 992c9710b42Smrg list->n = 0; 993c9710b42Smrg ret = malloc (sizeof (FcChar8) * (len + 1)); 994c9710b42Smrg if (!ret) 995c9710b42Smrg goto bail2; 996c9710b42Smrg p = ret; 997c9710b42Smrg while ((s = FcStrListNext (list))) 998c9710b42Smrg { 999c9710b42Smrg if (p != ret) 1000c9710b42Smrg { 1001c9710b42Smrg p[0] = FC_DIR_SEPARATOR; 1002c9710b42Smrg p++; 1003c9710b42Smrg } 1004c9710b42Smrg len = strlen ((const char *)s); 1005c9710b42Smrg memcpy (p, s, len); 1006c9710b42Smrg p += len; 1007c9710b42Smrg } 1008c9710b42Smrg *p = 0; 1009c9710b42Smrg 1010c9710b42Smrgbail2: 1011c9710b42Smrg FcStrListDone (list); 1012c9710b42Smrgbail1: 1013c9710b42Smrg va_end (ap); 1014c9710b42Smrgbail0: 1015c9710b42Smrg FcStrSetDestroy (sset); 1016c9710b42Smrg 1017c9710b42Smrg return ret; 1018c9710b42Smrg} 1019c9710b42Smrg 10202c393a42SmrgFcChar8 * 10212c393a42SmrgFcStrCopyFilename (const FcChar8 *s) 10222c393a42Smrg{ 10232c393a42Smrg FcChar8 *new; 1024ca08ab68Smrg 10252c393a42Smrg if (*s == '~') 10262c393a42Smrg { 10272c393a42Smrg FcChar8 *home = FcConfigHome (); 10282c393a42Smrg FcChar8 *full; 10292c393a42Smrg int size; 10302c393a42Smrg if (!home) 1031ca08ab68Smrg return NULL; 10322c393a42Smrg size = strlen ((char *) home) + strlen ((char *) s); 1033a32e9e42Smrg full = (FcChar8 *) malloc (size + 1); 10342c393a42Smrg if (!full) 1035ca08ab68Smrg return NULL; 10362c393a42Smrg strcpy ((char *) full, (char *) home); 10372c393a42Smrg strcat ((char *) full, (char *) s + 1); 10382c393a42Smrg new = FcStrCanonFilename (full); 10392c393a42Smrg free (full); 10402c393a42Smrg } 10412c393a42Smrg else 10422c393a42Smrg new = FcStrCanonFilename (s); 1043ca08ab68Smrg 10442c393a42Smrg return new; 10452c393a42Smrg} 10462c393a42Smrg 10472c393a42SmrgFcChar8 * 10482c393a42SmrgFcStrLastSlash (const FcChar8 *path) 10492c393a42Smrg{ 10502c393a42Smrg FcChar8 *slash; 10512c393a42Smrg 10522c393a42Smrg slash = (FcChar8 *) strrchr ((const char *) path, '/'); 10532c393a42Smrg#ifdef _WIN32 10542c393a42Smrg { 10552c393a42Smrg FcChar8 *backslash; 10562c393a42Smrg 10572c393a42Smrg backslash = (FcChar8 *) strrchr ((const char *) path, '\\'); 10582c393a42Smrg if (!slash || (backslash && backslash > slash)) 10592c393a42Smrg slash = backslash; 10602c393a42Smrg } 10612c393a42Smrg#endif 10622c393a42Smrg 10632c393a42Smrg return slash; 10642c393a42Smrg} 1065ca08ab68Smrg 10662c393a42SmrgFcChar8 * 10672c393a42SmrgFcStrDirname (const FcChar8 *file) 10682c393a42Smrg{ 10692c393a42Smrg FcChar8 *slash; 10702c393a42Smrg FcChar8 *dir; 10712c393a42Smrg 10722c393a42Smrg slash = FcStrLastSlash (file); 10732c393a42Smrg if (!slash) 10742c393a42Smrg return FcStrCopy ((FcChar8 *) "."); 10752c393a42Smrg dir = malloc ((slash - file) + 1); 10762c393a42Smrg if (!dir) 10772c393a42Smrg return 0; 10782c393a42Smrg strncpy ((char *) dir, (const char *) file, slash - file); 10792c393a42Smrg dir[slash - file] = '\0'; 10802c393a42Smrg return dir; 10812c393a42Smrg} 10822c393a42Smrg 10832c393a42SmrgFcChar8 * 10842c393a42SmrgFcStrBasename (const FcChar8 *file) 10852c393a42Smrg{ 10862c393a42Smrg FcChar8 *slash; 10872c393a42Smrg 10882c393a42Smrg slash = FcStrLastSlash (file); 10892c393a42Smrg if (!slash) 10902c393a42Smrg return FcStrCopy (file); 10912c393a42Smrg return FcStrCopy (slash + 1); 10922c393a42Smrg} 10932c393a42Smrg 1094a4e54154SmrgFcChar8 * 1095a4e54154SmrgFcStrRealPath (const FcChar8 *path) 1096a4e54154Smrg{ 1097a4e54154Smrg char resolved_name[FC_PATH_MAX+1]; 1098a4e54154Smrg char *resolved_ret; 1099a4e54154Smrg 1100a4e54154Smrg if (!path) 1101a4e54154Smrg return NULL; 1102a4e54154Smrg 1103a4e54154Smrg#ifndef _WIN32 1104a4e54154Smrg resolved_ret = realpath((const char *) path, resolved_name); 1105a4e54154Smrg#else 1106a4e54154Smrg if (GetFullPathNameA ((LPCSTR) path, FC_PATH_MAX, resolved_name, NULL) == 0) 1107a4e54154Smrg { 1108a4e54154Smrg fprintf (stderr, "Fontconfig warning: GetFullPathNameA failed.\n"); 1109a4e54154Smrg return NULL; 1110a4e54154Smrg } 1111a4e54154Smrg resolved_ret = resolved_name; 1112a4e54154Smrg#endif 1113a4e54154Smrg if (resolved_ret) 1114a4e54154Smrg path = (FcChar8 *) resolved_ret; 1115a4e54154Smrg return FcStrCopyFilename(path); 1116a4e54154Smrg} 1117a4e54154Smrg 11182c393a42Smrgstatic FcChar8 * 11192c393a42SmrgFcStrCanonAbsoluteFilename (const FcChar8 *s) 11202c393a42Smrg{ 11212c393a42Smrg FcChar8 *file; 11222c393a42Smrg FcChar8 *f; 11232c393a42Smrg const FcChar8 *slash; 11242c393a42Smrg int size; 11252c393a42Smrg 11262c393a42Smrg size = strlen ((char *) s) + 1; 11272c393a42Smrg file = malloc (size); 11282c393a42Smrg if (!file) 11292c393a42Smrg return NULL; 11302c393a42Smrg slash = NULL; 11312c393a42Smrg f = file; 1132ca08ab68Smrg#ifdef _WIN32 1133ca08ab68Smrg if (*s == '/' && *(s+1) == '/') /* Network path, do not squash // */ 1134ca08ab68Smrg *f++ = *s++; 1135ca08ab68Smrg#endif 11362c393a42Smrg for (;;) { 11372c393a42Smrg if (*s == '/' || *s == '\0') 11382c393a42Smrg { 11392c393a42Smrg if (slash) 11402c393a42Smrg { 11412c393a42Smrg switch (s - slash) { 1142a6844aabSmrg case 1: 1143a6844aabSmrg f -= 1; /* squash // and trim final / from file */ 1144a6844aabSmrg break; 11452c393a42Smrg case 2: 11462c393a42Smrg if (!strncmp ((char *) slash, "/.", 2)) 11472c393a42Smrg { 11482c393a42Smrg f -= 2; /* trim /. from file */ 11492c393a42Smrg } 11502c393a42Smrg break; 11512c393a42Smrg case 3: 11522c393a42Smrg if (!strncmp ((char *) slash, "/..", 3)) 11532c393a42Smrg { 11542c393a42Smrg f -= 3; /* trim /.. from file */ 11552c393a42Smrg while (f > file) { 11562c393a42Smrg if (*--f == '/') 11572c393a42Smrg break; 11582c393a42Smrg } 11592c393a42Smrg } 11602c393a42Smrg break; 11612c393a42Smrg } 11622c393a42Smrg } 11632c393a42Smrg slash = s; 11642c393a42Smrg } 11652c393a42Smrg if (!(*f++ = *s++)) 11662c393a42Smrg break; 11672c393a42Smrg } 11682c393a42Smrg return file; 11692c393a42Smrg} 1170ca08ab68Smrg 11712c393a42Smrg#ifdef _WIN32 11722c393a42Smrg/* 1173ca08ab68Smrg * Convert '\\' to '/' , remove double '/' 11742c393a42Smrg */ 11752c393a42Smrgstatic void 11762c393a42SmrgFcConvertDosPath (char *str) 11772c393a42Smrg{ 11782c393a42Smrg size_t len = strlen (str); 11792c393a42Smrg char *p = str; 11802c393a42Smrg char *dest = str; 11812c393a42Smrg char *end = str + len; 11822c393a42Smrg char last = 0; 1183a6844aabSmrg 1184a6844aabSmrg if (*p == '\\') 1185a6844aabSmrg { 1186a6844aabSmrg *p = '/'; 1187a6844aabSmrg p++; 1188a6844aabSmrg dest++; 1189a6844aabSmrg } 11902c393a42Smrg while (p < end) 11912c393a42Smrg { 11922c393a42Smrg if (*p == '\\') 11932c393a42Smrg *p = '/'; 11942c393a42Smrg 11952c393a42Smrg if (*p != '/' 11962c393a42Smrg || last != '/') 11972c393a42Smrg { 11982c393a42Smrg *dest++ = *p; 11992c393a42Smrg } 12002c393a42Smrg 12012c393a42Smrg last = *p; 12022c393a42Smrg p++; 12032c393a42Smrg } 12042c393a42Smrg 12052c393a42Smrg *dest = 0; 12062c393a42Smrg} 12072c393a42Smrg#endif 12082c393a42Smrg 12092c393a42SmrgFcChar8 * 12102c393a42SmrgFcStrCanonFilename (const FcChar8 *s) 12112c393a42Smrg{ 12122c393a42Smrg#ifdef _WIN32 12132c393a42Smrg FcChar8 full[FC_MAX_FILE_LEN + 2]; 1214ca08ab68Smrg int size = GetFullPathName ((LPCSTR) s, sizeof (full) -1, 1215ca08ab68Smrg (LPSTR) full, NULL); 12162c393a42Smrg 12172c393a42Smrg if (size == 0) 12182c393a42Smrg perror ("GetFullPathName"); 12192c393a42Smrg 1220ca08ab68Smrg FcConvertDosPath ((char *) full); 12212c393a42Smrg return FcStrCanonAbsoluteFilename (full); 12222c393a42Smrg#else 12232c393a42Smrg if (s[0] == '/') 12242c393a42Smrg return FcStrCanonAbsoluteFilename (s); 12252c393a42Smrg else 12262c393a42Smrg { 12272c393a42Smrg FcChar8 *full; 12282c393a42Smrg FcChar8 *file; 12292c393a42Smrg 12302c393a42Smrg FcChar8 cwd[FC_MAX_FILE_LEN + 2]; 12312c393a42Smrg if (getcwd ((char *) cwd, FC_MAX_FILE_LEN) == NULL) 12322c393a42Smrg return NULL; 1233c9710b42Smrg full = FcStrBuildFilename (cwd, s, NULL); 12342c393a42Smrg file = FcStrCanonAbsoluteFilename (full); 12352c393a42Smrg FcStrFree (full); 12362c393a42Smrg return file; 12372c393a42Smrg } 12382c393a42Smrg#endif 12392c393a42Smrg} 12402c393a42Smrg 12412c393a42Smrg 12422c393a42SmrgFcStrSet * 12432c393a42SmrgFcStrSetCreate (void) 1244953daebaSmrg{ 1245953daebaSmrg return FcStrSetCreateEx (FCSS_DEFAULT); 1246953daebaSmrg} 1247953daebaSmrg 1248953daebaSmrgFcStrSet * 1249953daebaSmrgFcStrSetCreateEx (unsigned int control) 12502c393a42Smrg{ 12512c393a42Smrg FcStrSet *set = malloc (sizeof (FcStrSet)); 12522c393a42Smrg if (!set) 12532c393a42Smrg return 0; 1254c9710b42Smrg FcRefInit (&set->ref, 1); 12552c393a42Smrg set->num = 0; 12562c393a42Smrg set->size = 0; 12572c393a42Smrg set->strs = 0; 1258953daebaSmrg set->control = control; 12592c393a42Smrg return set; 12602c393a42Smrg} 12612c393a42Smrg 1262953daebaSmrgstatic FcBool 1263953daebaSmrg_FcStrSetGrow (FcStrSet *set, int growElements) 1264953daebaSmrg{ 1265953daebaSmrg /* accommodate an additional NULL entry at the end of the array */ 1266953daebaSmrg FcChar8 **strs = malloc ((set->size + growElements + 1) * sizeof (FcChar8 *)); 1267953daebaSmrg if (!strs) 1268953daebaSmrg return FcFalse; 1269953daebaSmrg if (set->num) 1270953daebaSmrg memcpy (strs, set->strs, set->num * sizeof (FcChar8 *)); 1271953daebaSmrg if (set->strs) 1272953daebaSmrg free (set->strs); 1273953daebaSmrg set->size = set->size + growElements; 1274953daebaSmrg set->strs = strs; 1275953daebaSmrg return FcTrue; 1276953daebaSmrg} 1277953daebaSmrg 12782c393a42Smrgstatic FcBool 1279a4e54154Smrg_FcStrSetInsert (FcStrSet *set, FcChar8 *s, int pos) 12802c393a42Smrg{ 1281953daebaSmrg if (!FcStrSetHasControlBit (set, FCSS_ALLOW_DUPLICATES)) 12822c393a42Smrg { 1283953daebaSmrg if (FcStrSetMember (set, s)) 1284953daebaSmrg { 1285953daebaSmrg FcStrFree (s); 1286953daebaSmrg return FcTrue; 1287953daebaSmrg } 12882c393a42Smrg } 12892c393a42Smrg if (set->num == set->size) 12902c393a42Smrg { 1291953daebaSmrg int growElements = FcStrSetHasControlBit (set, FCSS_GROW_BY_64) ? 64 : 1; 1292953daebaSmrg if (!_FcStrSetGrow(set, growElements)) 1293953daebaSmrg return FcFalse; 12942c393a42Smrg } 1295a4e54154Smrg if (pos >= set->num) 1296a4e54154Smrg { 1297a4e54154Smrg set->strs[set->num++] = s; 1298a4e54154Smrg set->strs[set->num] = 0; 1299a4e54154Smrg } 1300a4e54154Smrg else 1301a4e54154Smrg { 1302a4e54154Smrg int i; 1303a4e54154Smrg 1304a4e54154Smrg set->num++; 1305a4e54154Smrg set->strs[set->num] = 0; 1306a4e54154Smrg for (i = set->num - 1; i > pos; i--) 1307a4e54154Smrg set->strs[i] = set->strs[i - 1]; 1308a4e54154Smrg set->strs[pos] = s; 1309a4e54154Smrg } 13102c393a42Smrg return FcTrue; 13112c393a42Smrg} 13122c393a42Smrg 13132c393a42SmrgFcBool 13142c393a42SmrgFcStrSetMember (FcStrSet *set, const FcChar8 *s) 13152c393a42Smrg{ 13162c393a42Smrg int i; 13172c393a42Smrg 13182c393a42Smrg for (i = 0; i < set->num; i++) 13192c393a42Smrg if (!FcStrCmp (set->strs[i], s)) 13202c393a42Smrg return FcTrue; 13212c393a42Smrg return FcFalse; 13222c393a42Smrg} 13232c393a42Smrg 1324a4e54154Smrgstatic int 1325a4e54154Smrgfc_strcmp_r (const FcChar8 *s1, const FcChar8 *s2, const FcChar8 **ret) 1326a4e54154Smrg{ 1327a4e54154Smrg FcChar8 c1, c2; 1328a4e54154Smrg 1329a4e54154Smrg if (s1 == s2) 1330a4e54154Smrg { 1331a4e54154Smrg if (ret) 1332a4e54154Smrg *ret = NULL; 1333a4e54154Smrg return 0; 1334a4e54154Smrg } 1335a4e54154Smrg for (;;) 1336a4e54154Smrg { 1337a4e54154Smrg if (s1) 1338a4e54154Smrg c1 = *s1++; 1339a4e54154Smrg else 1340a4e54154Smrg c1 = 0; 1341a4e54154Smrg if (s2) 1342a4e54154Smrg c2 = *s2++; 1343a4e54154Smrg else 1344a4e54154Smrg c2 = 0; 1345a4e54154Smrg if (!c1 || c1 != c2) 1346a4e54154Smrg break; 1347a4e54154Smrg } 1348a4e54154Smrg if (ret) 1349a4e54154Smrg *ret = s1; 1350a4e54154Smrg return (int) c1 - (int) c2; 1351a4e54154Smrg} 1352a4e54154Smrg 1353a4e54154SmrgFcBool 1354a4e54154SmrgFcStrSetMemberAB (FcStrSet *set, const FcChar8 *a, FcChar8 *b, FcChar8 **ret) 1355a4e54154Smrg{ 1356a4e54154Smrg int i; 1357a4e54154Smrg const FcChar8 *s = NULL; 1358a4e54154Smrg 1359a4e54154Smrg for (i = 0; i < set->num; i++) 1360a4e54154Smrg { 1361a4e54154Smrg if (!fc_strcmp_r (set->strs[i], a, &s) && s) 1362a4e54154Smrg { 1363a4e54154Smrg if (!fc_strcmp_r (s, b, NULL)) 1364a4e54154Smrg { 1365a4e54154Smrg if (ret) 1366a4e54154Smrg *ret = set->strs[i]; 1367a4e54154Smrg return FcTrue; 1368a4e54154Smrg } 1369a4e54154Smrg } 1370a4e54154Smrg } 1371a4e54154Smrg if (ret) 1372a4e54154Smrg *ret = NULL; 1373a4e54154Smrg return FcFalse; 1374a4e54154Smrg} 1375a4e54154Smrg 13762c393a42SmrgFcBool 13772c393a42SmrgFcStrSetEqual (FcStrSet *sa, FcStrSet *sb) 13782c393a42Smrg{ 13792c393a42Smrg int i; 13802c393a42Smrg if (sa->num != sb->num) 13812c393a42Smrg return FcFalse; 13822c393a42Smrg for (i = 0; i < sa->num; i++) 13832c393a42Smrg if (!FcStrSetMember (sb, sa->strs[i])) 13842c393a42Smrg return FcFalse; 13852c393a42Smrg return FcTrue; 13862c393a42Smrg} 13872c393a42Smrg 13882c393a42SmrgFcBool 13892c393a42SmrgFcStrSetAdd (FcStrSet *set, const FcChar8 *s) 13902c393a42Smrg{ 13912c393a42Smrg FcChar8 *new = FcStrCopy (s); 13922c393a42Smrg if (!new) 13932c393a42Smrg return FcFalse; 1394a4e54154Smrg if (!_FcStrSetInsert (set, new, set->num)) 1395a4e54154Smrg { 1396a4e54154Smrg FcStrFree (new); 1397a4e54154Smrg return FcFalse; 1398a4e54154Smrg } 1399a4e54154Smrg return FcTrue; 1400a4e54154Smrg} 1401a4e54154Smrg 1402a4e54154SmrgFcBool 1403a4e54154SmrgFcStrSetInsert (FcStrSet *set, const FcChar8 *s, int pos) 1404a4e54154Smrg{ 1405a4e54154Smrg FcChar8 *new = FcStrCopy (s); 1406a4e54154Smrg if (!new) 1407a4e54154Smrg return FcFalse; 1408a4e54154Smrg if (!_FcStrSetInsert (set, new, pos)) 14092c393a42Smrg { 14102c393a42Smrg FcStrFree (new); 14112c393a42Smrg return FcFalse; 14122c393a42Smrg } 14132c393a42Smrg return FcTrue; 14142c393a42Smrg} 14152c393a42Smrg 1416a4e54154SmrgFcBool 1417a4e54154SmrgFcStrSetAddTriple (FcStrSet *set, const FcChar8 *a, const FcChar8 *b, const FcChar8 *c) 1418a4e54154Smrg{ 1419a4e54154Smrg FcChar8 *new = FcStrMakeTriple (a, b, c); 1420a4e54154Smrg if (!new) 1421a4e54154Smrg return FcFalse; 1422a4e54154Smrg if (!_FcStrSetInsert (set, new, set->num)) 1423a4e54154Smrg { 1424a4e54154Smrg FcStrFree (new); 1425a4e54154Smrg return FcFalse; 1426a4e54154Smrg } 1427a4e54154Smrg return FcTrue; 1428a4e54154Smrg} 1429a4e54154Smrg 1430a4e54154Smrgconst FcChar8 * 1431a4e54154SmrgFcStrTripleSecond (FcChar8 *str) 1432a4e54154Smrg{ 1433a4e54154Smrg FcChar8 *second = str + strlen((char *) str) + 1; 1434a4e54154Smrg 1435a4e54154Smrg if (*second == '\0') 1436a4e54154Smrg return 0; 1437a4e54154Smrg return second; 1438a4e54154Smrg} 1439a4e54154Smrg 1440a4e54154Smrgconst FcChar8 * 1441a4e54154SmrgFcStrTripleThird (FcChar8 *str) 1442a4e54154Smrg{ 1443a4e54154Smrg FcChar8 *second = str + strlen ((char *) str) + 1; 1444a4e54154Smrg FcChar8 *third = second + strlen ((char *) second) + 1; 1445a4e54154Smrg 1446a4e54154Smrg if (*third == '\0') 1447a4e54154Smrg return 0; 1448a4e54154Smrg return third; 1449a4e54154Smrg} 1450a4e54154Smrg 14512c393a42SmrgFcBool 14522c393a42SmrgFcStrSetAddFilename (FcStrSet *set, const FcChar8 *s) 14532c393a42Smrg{ 14542c393a42Smrg FcChar8 *new = FcStrCopyFilename (s); 14552c393a42Smrg if (!new) 14562c393a42Smrg return FcFalse; 1457a4e54154Smrg if (!_FcStrSetInsert (set, new, set->num)) 14582c393a42Smrg { 14592c393a42Smrg FcStrFree (new); 14602c393a42Smrg return FcFalse; 14612c393a42Smrg } 14622c393a42Smrg return FcTrue; 14632c393a42Smrg} 14642c393a42Smrg 1465a4e54154SmrgFcBool 1466a4e54154SmrgFcStrSetAddFilenamePairWithSalt (FcStrSet *set, const FcChar8 *a, const FcChar8 *b, const FcChar8 *salt) 1467a4e54154Smrg{ 1468a4e54154Smrg FcChar8 *new_a = NULL; 1469a4e54154Smrg FcChar8 *new_b = NULL; 1470a4e54154Smrg FcChar8 *rs = NULL; 1471a4e54154Smrg FcBool ret; 1472a4e54154Smrg 1473a4e54154Smrg if (a) 1474a4e54154Smrg { 1475a4e54154Smrg new_a = FcStrCopyFilename (a); 1476a4e54154Smrg if (!new_a) 1477a4e54154Smrg return FcFalse; 1478a4e54154Smrg } 1479a4e54154Smrg if (b) 1480a4e54154Smrg { 1481a4e54154Smrg new_b = FcStrCopyFilename(b); 1482a4e54154Smrg if (!new_b) 1483a4e54154Smrg { 1484a4e54154Smrg if (new_a) 1485a4e54154Smrg FcStrFree(new_a); 1486a4e54154Smrg return FcFalse; 1487a4e54154Smrg } 1488a4e54154Smrg } 1489a4e54154Smrg /* Override maps with new one if exists */ 1490a4e54154Smrg if (FcStrSetMemberAB (set, new_a, new_b, &rs)) 1491a4e54154Smrg { 1492a4e54154Smrg FcStrSetDel (set, rs); 1493a4e54154Smrg } 1494a4e54154Smrg ret = FcStrSetAddTriple (set, new_a, new_b, salt); 1495a4e54154Smrg if (new_a) 1496a4e54154Smrg FcStrFree (new_a); 1497a4e54154Smrg if (new_b) 1498a4e54154Smrg FcStrFree (new_b); 1499a4e54154Smrg return ret; 1500a4e54154Smrg} 1501a4e54154Smrg 1502ca08ab68SmrgFcBool 1503ca08ab68SmrgFcStrSetAddLangs (FcStrSet *strs, const char *languages) 1504ca08ab68Smrg{ 1505ca08ab68Smrg const char *p = languages, *next; 1506ca08ab68Smrg FcChar8 lang[128] = {0}, *normalized_lang; 1507ca08ab68Smrg size_t len; 1508ca08ab68Smrg FcBool ret = FcFalse; 1509ca08ab68Smrg 1510ca08ab68Smrg if (!languages) 1511ca08ab68Smrg return FcFalse; 1512ca08ab68Smrg 1513ca08ab68Smrg while ((next = strchr (p, ':'))) 1514ca08ab68Smrg { 1515ca08ab68Smrg len = next - p; 1516c9710b42Smrg len = FC_MIN (len, 127); 1517ca08ab68Smrg strncpy ((char *) lang, p, len); 1518ca08ab68Smrg lang[len] = 0; 1519ca08ab68Smrg /* ignore an empty item */ 1520ca08ab68Smrg if (*lang) 1521ca08ab68Smrg { 1522ca08ab68Smrg normalized_lang = FcLangNormalize ((const FcChar8 *) lang); 1523ca08ab68Smrg if (normalized_lang) 1524ca08ab68Smrg { 1525ca08ab68Smrg FcStrSetAdd (strs, normalized_lang); 1526c9710b42Smrg FcStrFree (normalized_lang); 1527ca08ab68Smrg ret = FcTrue; 1528ca08ab68Smrg } 1529ca08ab68Smrg } 1530ca08ab68Smrg p = next + 1; 1531ca08ab68Smrg } 1532ca08ab68Smrg if (*p) 1533ca08ab68Smrg { 1534ca08ab68Smrg normalized_lang = FcLangNormalize ((const FcChar8 *) p); 1535ca08ab68Smrg if (normalized_lang) 1536ca08ab68Smrg { 1537ca08ab68Smrg FcStrSetAdd (strs, normalized_lang); 1538c9710b42Smrg FcStrFree (normalized_lang); 1539ca08ab68Smrg ret = FcTrue; 1540ca08ab68Smrg } 1541ca08ab68Smrg } 1542ca08ab68Smrg 1543ca08ab68Smrg return ret; 1544ca08ab68Smrg} 1545ca08ab68Smrg 15462c393a42SmrgFcBool 15472c393a42SmrgFcStrSetDel (FcStrSet *set, const FcChar8 *s) 15482c393a42Smrg{ 15492c393a42Smrg int i; 15502c393a42Smrg 15512c393a42Smrg for (i = 0; i < set->num; i++) 15522c393a42Smrg if (!FcStrCmp (set->strs[i], s)) 15532c393a42Smrg { 15542c393a42Smrg FcStrFree (set->strs[i]); 15552c393a42Smrg /* 15562c393a42Smrg * copy remaining string pointers and trailing 15572c393a42Smrg * NULL 15582c393a42Smrg */ 1559ca08ab68Smrg memmove (&set->strs[i], &set->strs[i+1], 15602c393a42Smrg (set->num - i) * sizeof (FcChar8 *)); 15612c393a42Smrg set->num--; 15622c393a42Smrg return FcTrue; 15632c393a42Smrg } 15642c393a42Smrg return FcFalse; 15652c393a42Smrg} 15662c393a42Smrg 1567a4e54154SmrgFcBool 1568a4e54154SmrgFcStrSetDeleteAll (FcStrSet *set) 1569a4e54154Smrg{ 1570a4e54154Smrg int i; 1571a4e54154Smrg 1572a4e54154Smrg if (FcRefIsConst (&set->ref)) 1573a4e54154Smrg return FcFalse; 1574a4e54154Smrg 1575a4e54154Smrg for (i = set->num; i > 0; i--) 1576a4e54154Smrg { 1577a4e54154Smrg FcStrFree (set->strs[i - 1]); 1578a4e54154Smrg set->num--; 1579a4e54154Smrg } 1580a4e54154Smrg return FcTrue; 1581a4e54154Smrg} 1582a4e54154Smrg 1583c9710b42Smrg/* TODO Make public */ 1584c9710b42Smrgstatic FcStrSet * 1585c9710b42SmrgFcStrSetReference (FcStrSet *set) 1586c9710b42Smrg{ 1587c9710b42Smrg if (FcRefIsConst (&set->ref)) 1588c9710b42Smrg return set; 1589c9710b42Smrg 1590c9710b42Smrg FcRefInc (&set->ref); 1591c9710b42Smrg return set; 1592c9710b42Smrg} 1593c9710b42Smrg 15942c393a42Smrgvoid 15952c393a42SmrgFcStrSetDestroy (FcStrSet *set) 15962c393a42Smrg{ 1597c9710b42Smrg int i; 1598ca08ab68Smrg 1599c9710b42Smrg /* We rely on this in FcGetDefaultLangs for caching. */ 1600c9710b42Smrg if (FcRefIsConst (&set->ref)) 1601c9710b42Smrg return; 1602c9710b42Smrg 1603c9710b42Smrg if (FcRefDec (&set->ref) != 1) 1604c9710b42Smrg return; 1605c9710b42Smrg 1606c9710b42Smrg for (i = 0; i < set->num; i++) 1607c9710b42Smrg FcStrFree (set->strs[i]); 1608c9710b42Smrg if (set->strs) 1609c9710b42Smrg free (set->strs); 1610c9710b42Smrg free (set); 16112c393a42Smrg} 16122c393a42Smrg 16132c393a42SmrgFcStrList * 16142c393a42SmrgFcStrListCreate (FcStrSet *set) 16152c393a42Smrg{ 16162c393a42Smrg FcStrList *list; 16172c393a42Smrg 16182c393a42Smrg list = malloc (sizeof (FcStrList)); 16192c393a42Smrg if (!list) 16202c393a42Smrg return 0; 16212c393a42Smrg list->set = set; 1622c9710b42Smrg FcStrSetReference (set); 16232c393a42Smrg list->n = 0; 16242c393a42Smrg return list; 16252c393a42Smrg} 16262c393a42Smrg 16276fc018e4Smrgvoid 16286fc018e4SmrgFcStrListFirst (FcStrList *list) 16296fc018e4Smrg{ 16306fc018e4Smrg list->n = 0; 16316fc018e4Smrg} 16326fc018e4Smrg 16332c393a42SmrgFcChar8 * 16342c393a42SmrgFcStrListNext (FcStrList *list) 16352c393a42Smrg{ 16362c393a42Smrg if (list->n >= list->set->num) 16372c393a42Smrg return 0; 16382c393a42Smrg return list->set->strs[list->n++]; 16392c393a42Smrg} 16402c393a42Smrg 16412c393a42Smrgvoid 16422c393a42SmrgFcStrListDone (FcStrList *list) 16432c393a42Smrg{ 16442c393a42Smrg FcStrSetDestroy (list->set); 16452c393a42Smrg free (list); 16462c393a42Smrg} 16472c393a42Smrg 16482c393a42Smrg#define __fcstr__ 16492c393a42Smrg#include "fcaliastail.h" 16502c393a42Smrg#undef __fcstr__ 1651