fcstr.c revision 953daeba
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 392c393a42SmrgFcChar8 * 402c393a42SmrgFcStrPlus (const FcChar8 *s1, const FcChar8 *s2) 412c393a42Smrg{ 42ca08ab68Smrg int s1l = strlen ((char *) s1); 43ca08ab68Smrg int s2l = strlen ((char *) s2); 44ca08ab68Smrg int l = s1l + s2l + 1; 452c393a42Smrg FcChar8 *s = malloc (l); 462c393a42Smrg 472c393a42Smrg if (!s) 482c393a42Smrg return 0; 49ca08ab68Smrg memcpy (s, s1, s1l); 50ca08ab68Smrg memcpy (s + s1l, s2, s2l + 1); 512c393a42Smrg return s; 522c393a42Smrg} 532c393a42Smrg 542c393a42Smrgvoid 552c393a42SmrgFcStrFree (FcChar8 *s) 562c393a42Smrg{ 572c393a42Smrg free (s); 582c393a42Smrg} 592c393a42Smrg 602c393a42Smrg 612c393a42Smrg#include "../fc-case/fccase.h" 622c393a42Smrg 632c393a42Smrg#define FcCaseFoldUpperCount(cf) \ 642c393a42Smrg ((cf)->method == FC_CASE_FOLD_FULL ? 1 : (cf)->count) 652c393a42Smrg 662c393a42Smrgtypedef struct _FcCaseWalker { 672c393a42Smrg const FcChar8 *read; 682c393a42Smrg const FcChar8 *src; 692c393a42Smrg FcChar8 utf8[FC_MAX_CASE_FOLD_CHARS + 1]; 702c393a42Smrg} FcCaseWalker; 712c393a42Smrg 722c393a42Smrgstatic void 732c393a42SmrgFcStrCaseWalkerInit (const FcChar8 *src, FcCaseWalker *w) 742c393a42Smrg{ 752c393a42Smrg w->src = src; 762c393a42Smrg w->read = 0; 772c393a42Smrg} 782c393a42Smrg 792c393a42Smrgstatic FcChar8 802c393a42SmrgFcStrCaseWalkerLong (FcCaseWalker *w, FcChar8 r) 812c393a42Smrg{ 822c393a42Smrg FcChar32 ucs4; 832c393a42Smrg int slen; 842c393a42Smrg int len = strlen((char*)w->src); 852c393a42Smrg 862c393a42Smrg slen = FcUtf8ToUcs4 (w->src - 1, &ucs4, len + 1); 872c393a42Smrg if (slen <= 0) 882c393a42Smrg return r; 892c393a42Smrg if (FC_MIN_FOLD_CHAR <= ucs4 && ucs4 <= FC_MAX_FOLD_CHAR) 902c393a42Smrg { 912c393a42Smrg int min = 0; 922c393a42Smrg int max = FC_NUM_CASE_FOLD; 932c393a42Smrg 942c393a42Smrg while (min <= max) 952c393a42Smrg { 962c393a42Smrg int mid = (min + max) >> 1; 972c393a42Smrg FcChar32 low = fcCaseFold[mid].upper; 982c393a42Smrg FcChar32 high = low + FcCaseFoldUpperCount (&fcCaseFold[mid]); 99ca08ab68Smrg 1002c393a42Smrg if (high <= ucs4) 1012c393a42Smrg min = mid + 1; 1022c393a42Smrg else if (ucs4 < low) 1032c393a42Smrg max = mid - 1; 1042c393a42Smrg else 1052c393a42Smrg { 1062c393a42Smrg const FcCaseFold *fold = &fcCaseFold[mid]; 1072c393a42Smrg int dlen; 1082c393a42Smrg 1092c393a42Smrg switch (fold->method) { 1102c393a42Smrg case FC_CASE_FOLD_EVEN_ODD: 1112c393a42Smrg if ((ucs4 & 1) != (fold->upper & 1)) 1122c393a42Smrg return r; 1132c393a42Smrg /* fall through ... */ 1142c393a42Smrg default: 1152c393a42Smrg dlen = FcUcs4ToUtf8 (ucs4 + fold->offset, w->utf8); 1162c393a42Smrg break; 1172c393a42Smrg case FC_CASE_FOLD_FULL: 1182c393a42Smrg dlen = fold->count; 1192c393a42Smrg memcpy (w->utf8, fcCaseFoldChars + fold->offset, dlen); 1202c393a42Smrg break; 1212c393a42Smrg } 1222c393a42Smrg 1232c393a42Smrg /* consume rest of src utf-8 bytes */ 1242c393a42Smrg w->src += slen - 1; 1252c393a42Smrg 1262c393a42Smrg /* read from temp buffer */ 1272c393a42Smrg w->utf8[dlen] = '\0'; 1282c393a42Smrg w->read = w->utf8; 1292c393a42Smrg return *w->read++; 1302c393a42Smrg } 1312c393a42Smrg } 1322c393a42Smrg } 1332c393a42Smrg return r; 1342c393a42Smrg} 1352c393a42Smrg 1362c393a42Smrgstatic FcChar8 137c9710b42SmrgFcStrCaseWalkerNext (FcCaseWalker *w, const char *delims) 1382c393a42Smrg{ 1392c393a42Smrg FcChar8 r; 1402c393a42Smrg 1412c393a42Smrg if (w->read) 1422c393a42Smrg { 1432c393a42Smrg if ((r = *w->read++)) 1442c393a42Smrg return r; 1452c393a42Smrg w->read = 0; 1462c393a42Smrg } 1472c393a42Smrg do 1482c393a42Smrg { 1492c393a42Smrg r = *w->src++; 150c9710b42Smrg } while (r != 0 && delims && strchr (delims, r)); 151ca08ab68Smrg 1522c393a42Smrg if ((r & 0xc0) == 0xc0) 1532c393a42Smrg return FcStrCaseWalkerLong (w, r); 1542c393a42Smrg if ('A' <= r && r <= 'Z') 1552c393a42Smrg r = r - 'A' + 'a'; 1562c393a42Smrg return r; 1572c393a42Smrg} 1582c393a42Smrg 1592c393a42SmrgFcChar8 * 1602c393a42SmrgFcStrDowncase (const FcChar8 *s) 1612c393a42Smrg{ 1622c393a42Smrg FcCaseWalker w; 1632c393a42Smrg int len = 0; 1642c393a42Smrg FcChar8 *dst, *d; 1652c393a42Smrg 1662c393a42Smrg FcStrCaseWalkerInit (s, &w); 167c9710b42Smrg while (FcStrCaseWalkerNext (&w, NULL)) 1682c393a42Smrg len++; 1692c393a42Smrg d = dst = malloc (len + 1); 1702c393a42Smrg if (!d) 1712c393a42Smrg return 0; 1722c393a42Smrg FcStrCaseWalkerInit (s, &w); 173c9710b42Smrg while ((*d++ = FcStrCaseWalkerNext (&w, NULL))); 1742c393a42Smrg return dst; 1752c393a42Smrg} 1762c393a42Smrg 1772c393a42Smrgint 1782c393a42SmrgFcStrCmpIgnoreCase (const FcChar8 *s1, const FcChar8 *s2) 1792c393a42Smrg{ 1802c393a42Smrg FcCaseWalker w1, w2; 1812c393a42Smrg FcChar8 c1, c2; 1822c393a42Smrg 1832c393a42Smrg if (s1 == s2) return 0; 184ca08ab68Smrg 1852c393a42Smrg FcStrCaseWalkerInit (s1, &w1); 1862c393a42Smrg FcStrCaseWalkerInit (s2, &w2); 187ca08ab68Smrg 188ca08ab68Smrg for (;;) 1892c393a42Smrg { 190c9710b42Smrg c1 = FcStrCaseWalkerNext (&w1, NULL); 191c9710b42Smrg c2 = FcStrCaseWalkerNext (&w2, NULL); 1922c393a42Smrg if (!c1 || (c1 != c2)) 1932c393a42Smrg break; 1942c393a42Smrg } 1952c393a42Smrg return (int) c1 - (int) c2; 1962c393a42Smrg} 1972c393a42Smrg 1982c393a42Smrgint 1992c393a42SmrgFcStrCmpIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2) 200c9710b42Smrg{ 201c9710b42Smrg return FcStrCmpIgnoreCaseAndDelims (s1, s2, (const FcChar8 *)" "); 202c9710b42Smrg} 203c9710b42Smrg 204c9710b42Smrgint 205c9710b42SmrgFcStrCmpIgnoreCaseAndDelims (const FcChar8 *s1, const FcChar8 *s2, const FcChar8 *delims) 2062c393a42Smrg{ 2072c393a42Smrg FcCaseWalker w1, w2; 2082c393a42Smrg FcChar8 c1, c2; 2092c393a42Smrg 2102c393a42Smrg if (s1 == s2) return 0; 211ca08ab68Smrg 2122c393a42Smrg FcStrCaseWalkerInit (s1, &w1); 2132c393a42Smrg FcStrCaseWalkerInit (s2, &w2); 214ca08ab68Smrg 215ca08ab68Smrg for (;;) 2162c393a42Smrg { 217c9710b42Smrg c1 = FcStrCaseWalkerNext (&w1, (const char *)delims); 218c9710b42Smrg c2 = FcStrCaseWalkerNext (&w2, (const char *)delims); 2192c393a42Smrg if (!c1 || (c1 != c2)) 2202c393a42Smrg break; 2212c393a42Smrg } 2222c393a42Smrg return (int) c1 - (int) c2; 2232c393a42Smrg} 2242c393a42Smrg 2252c393a42Smrgint 2262c393a42SmrgFcStrCmp (const FcChar8 *s1, const FcChar8 *s2) 2272c393a42Smrg{ 2282c393a42Smrg FcChar8 c1, c2; 229ca08ab68Smrg 2302c393a42Smrg if (s1 == s2) 2312c393a42Smrg return 0; 232ca08ab68Smrg for (;;) 2332c393a42Smrg { 2342c393a42Smrg c1 = *s1++; 2352c393a42Smrg c2 = *s2++; 2362c393a42Smrg if (!c1 || c1 != c2) 2372c393a42Smrg break; 2382c393a42Smrg } 2392c393a42Smrg return (int) c1 - (int) c2; 2402c393a42Smrg} 2412c393a42Smrg 2422c393a42Smrg/* 2432c393a42Smrg * Return a hash value for a string 2442c393a42Smrg */ 2452c393a42Smrg 2462c393a42SmrgFcChar32 2472c393a42SmrgFcStrHashIgnoreCase (const FcChar8 *s) 2482c393a42Smrg{ 2492c393a42Smrg FcChar32 h = 0; 2502c393a42Smrg FcCaseWalker w; 2512c393a42Smrg FcChar8 c; 2522c393a42Smrg 2532c393a42Smrg FcStrCaseWalkerInit (s, &w); 254c9710b42Smrg while ((c = FcStrCaseWalkerNext (&w, NULL))) 2552c393a42Smrg h = ((h << 3) ^ (h >> 3)) ^ c; 2562c393a42Smrg return h; 2572c393a42Smrg} 2582c393a42Smrg 2592c393a42Smrg/* 2602c393a42Smrg * Is the head of s1 equal to s2? 2612c393a42Smrg */ 2622c393a42Smrg 2632c393a42Smrgstatic FcBool 2642c393a42SmrgFcStrIsAtIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2) 2652c393a42Smrg{ 2662c393a42Smrg FcCaseWalker w1, w2; 2672c393a42Smrg FcChar8 c1, c2; 2682c393a42Smrg 2692c393a42Smrg FcStrCaseWalkerInit (s1, &w1); 2702c393a42Smrg FcStrCaseWalkerInit (s2, &w2); 271ca08ab68Smrg 272ca08ab68Smrg for (;;) 2732c393a42Smrg { 274c9710b42Smrg c1 = FcStrCaseWalkerNext (&w1, " "); 275c9710b42Smrg c2 = FcStrCaseWalkerNext (&w2, " "); 2762c393a42Smrg if (!c1 || (c1 != c2)) 2772c393a42Smrg break; 2782c393a42Smrg } 2792c393a42Smrg return c1 == c2 || !c2; 2802c393a42Smrg} 2812c393a42Smrg 2822c393a42Smrg/* 2832c393a42Smrg * Does s1 contain an instance of s2 (ignoring blanks and case)? 2842c393a42Smrg */ 2852c393a42Smrg 2862c393a42Smrgconst FcChar8 * 2872c393a42SmrgFcStrContainsIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2) 2882c393a42Smrg{ 2892c393a42Smrg while (*s1) 2902c393a42Smrg { 2912c393a42Smrg if (FcStrIsAtIgnoreBlanksAndCase (s1, s2)) 2922c393a42Smrg return s1; 2932c393a42Smrg s1++; 2942c393a42Smrg } 2952c393a42Smrg return 0; 2962c393a42Smrg} 2972c393a42Smrg 2982c393a42Smrgstatic FcBool 2992c393a42SmrgFcCharIsPunct (const FcChar8 c) 3002c393a42Smrg{ 3012c393a42Smrg if (c < '0') 3022c393a42Smrg return FcTrue; 3032c393a42Smrg if (c <= '9') 3042c393a42Smrg return FcFalse; 3052c393a42Smrg if (c < 'A') 3062c393a42Smrg return FcTrue; 3072c393a42Smrg if (c <= 'Z') 3082c393a42Smrg return FcFalse; 3092c393a42Smrg if (c < 'a') 3102c393a42Smrg return FcTrue; 3112c393a42Smrg if (c <= 'z') 3122c393a42Smrg return FcFalse; 3132c393a42Smrg if (c <= '~') 3142c393a42Smrg return FcTrue; 3152c393a42Smrg return FcFalse; 3162c393a42Smrg} 3172c393a42Smrg 3182c393a42Smrg/* 3192c393a42Smrg * Is the head of s1 equal to s2? 3202c393a42Smrg */ 3212c393a42Smrg 3222c393a42Smrgstatic FcBool 3232c393a42SmrgFcStrIsAtIgnoreCase (const FcChar8 *s1, const FcChar8 *s2) 3242c393a42Smrg{ 3252c393a42Smrg FcCaseWalker w1, w2; 3262c393a42Smrg FcChar8 c1, c2; 3272c393a42Smrg 3282c393a42Smrg FcStrCaseWalkerInit (s1, &w1); 3292c393a42Smrg FcStrCaseWalkerInit (s2, &w2); 330ca08ab68Smrg 331ca08ab68Smrg for (;;) 3322c393a42Smrg { 333c9710b42Smrg c1 = FcStrCaseWalkerNext (&w1, NULL); 334c9710b42Smrg c2 = FcStrCaseWalkerNext (&w2, NULL); 3352c393a42Smrg if (!c1 || (c1 != c2)) 3362c393a42Smrg break; 3372c393a42Smrg } 3382c393a42Smrg return c1 == c2 || !c2; 3392c393a42Smrg} 3402c393a42Smrg 3412c393a42Smrg/* 3422c393a42Smrg * Does s1 contain an instance of s2 (ignoring blanks and case)? 3432c393a42Smrg */ 3442c393a42Smrg 3452c393a42Smrgconst FcChar8 * 3462c393a42SmrgFcStrContainsIgnoreCase (const FcChar8 *s1, const FcChar8 *s2) 3472c393a42Smrg{ 3482c393a42Smrg while (*s1) 3492c393a42Smrg { 3502c393a42Smrg if (FcStrIsAtIgnoreCase (s1, s2)) 3512c393a42Smrg return s1; 3522c393a42Smrg s1++; 3532c393a42Smrg } 3542c393a42Smrg return 0; 3552c393a42Smrg} 3562c393a42Smrg 3572c393a42Smrg/* 3582c393a42Smrg * Does s1 contain an instance of s2 on a word boundary (ignoring case)? 3592c393a42Smrg */ 3602c393a42Smrg 3612c393a42Smrgconst FcChar8 * 3622c393a42SmrgFcStrContainsWord (const FcChar8 *s1, const FcChar8 *s2) 3632c393a42Smrg{ 3642c393a42Smrg FcBool wordStart = FcTrue; 3652c393a42Smrg int s1len = strlen ((char *) s1); 3662c393a42Smrg int s2len = strlen ((char *) s2); 3672c393a42Smrg 3682c393a42Smrg while (s1len >= s2len) 3692c393a42Smrg { 370ca08ab68Smrg if (wordStart && 3712c393a42Smrg FcStrIsAtIgnoreCase (s1, s2) && 3722c393a42Smrg (s1len == s2len || FcCharIsPunct (s1[s2len]))) 3732c393a42Smrg { 3742c393a42Smrg return s1; 3752c393a42Smrg } 3762c393a42Smrg wordStart = FcFalse; 3772c393a42Smrg if (FcCharIsPunct (*s1)) 3782c393a42Smrg wordStart = FcTrue; 3792c393a42Smrg s1++; 3802c393a42Smrg s1len--; 3812c393a42Smrg } 3822c393a42Smrg return 0; 3832c393a42Smrg} 3842c393a42Smrg 385c9710b42Smrg/* 386c9710b42Smrg * returns the number of strings (ignoring delimitors and case) being matched 387c9710b42Smrg */ 388c9710b42Smrg 389c9710b42Smrgint 390c9710b42SmrgFcStrMatchIgnoreCaseAndDelims (const FcChar8 *s1, const FcChar8 *s2, const FcChar8 *delims) 391c9710b42Smrg{ 392c9710b42Smrg FcCaseWalker w1, w2; 393c9710b42Smrg FcChar8 c1, c2; 394c9710b42Smrg 395c9710b42Smrg if (s1 == s2) return 0; 396c9710b42Smrg 397c9710b42Smrg FcStrCaseWalkerInit (s1, &w1); 398c9710b42Smrg FcStrCaseWalkerInit (s2, &w2); 399c9710b42Smrg 400c9710b42Smrg for (;;) 401c9710b42Smrg { 402c9710b42Smrg c1 = FcStrCaseWalkerNext (&w1, (const char *)delims); 403c9710b42Smrg c2 = FcStrCaseWalkerNext (&w2, (const char *)delims); 404c9710b42Smrg if (!c1 || (c1 != c2)) 405c9710b42Smrg break; 406c9710b42Smrg } 407c9710b42Smrg return w1.src - s1 - 1; 408c9710b42Smrg} 409c9710b42Smrg 410c9710b42SmrgFcBool 411c9710b42SmrgFcStrGlobMatch (const FcChar8 *glob, 412c9710b42Smrg const FcChar8 *string) 413c9710b42Smrg{ 414c9710b42Smrg FcChar8 c; 415c9710b42Smrg 416c9710b42Smrg while ((c = *glob++)) 417c9710b42Smrg { 418c9710b42Smrg switch (c) { 419c9710b42Smrg case '*': 420c9710b42Smrg /* short circuit common case */ 421c9710b42Smrg if (!*glob) 422c9710b42Smrg return FcTrue; 423c9710b42Smrg /* short circuit another common case */ 424c9710b42Smrg if (strchr ((char *) glob, '*') == 0) 425c9710b42Smrg { 426c9710b42Smrg size_t l1, l2; 427c9710b42Smrg 428c9710b42Smrg l1 = strlen ((char *) string); 429c9710b42Smrg l2 = strlen ((char *) glob); 430c9710b42Smrg if (l1 < l2) 431c9710b42Smrg return FcFalse; 432c9710b42Smrg string += (l1 - l2); 433c9710b42Smrg } 434c9710b42Smrg while (*string) 435c9710b42Smrg { 436c9710b42Smrg if (FcStrGlobMatch (glob, string)) 437c9710b42Smrg return FcTrue; 438c9710b42Smrg string++; 439c9710b42Smrg } 440c9710b42Smrg return FcFalse; 441c9710b42Smrg case '?': 442c9710b42Smrg if (*string++ == '\0') 443c9710b42Smrg return FcFalse; 444c9710b42Smrg break; 445c9710b42Smrg default: 446c9710b42Smrg if (*string++ != c) 447c9710b42Smrg return FcFalse; 448c9710b42Smrg break; 449c9710b42Smrg } 450c9710b42Smrg } 451c9710b42Smrg return *string == '\0'; 452c9710b42Smrg} 453c9710b42Smrg 4542c393a42Smrgconst FcChar8 * 4552c393a42SmrgFcStrStrIgnoreCase (const FcChar8 *s1, const FcChar8 *s2) 4562c393a42Smrg{ 4572c393a42Smrg FcCaseWalker w1, w2; 4582c393a42Smrg FcChar8 c1, c2; 4592c393a42Smrg const FcChar8 *cur; 4602c393a42Smrg 4612c393a42Smrg if (!s1 || !s2) 4622c393a42Smrg return 0; 4632c393a42Smrg 4642c393a42Smrg if (s1 == s2) 4652c393a42Smrg return s1; 466ca08ab68Smrg 4672c393a42Smrg FcStrCaseWalkerInit (s1, &w1); 4682c393a42Smrg FcStrCaseWalkerInit (s2, &w2); 469ca08ab68Smrg 470c9710b42Smrg c2 = FcStrCaseWalkerNext (&w2, NULL); 471ca08ab68Smrg 4722c393a42Smrg for (;;) 4732c393a42Smrg { 4742c393a42Smrg cur = w1.src; 475c9710b42Smrg c1 = FcStrCaseWalkerNext (&w1, NULL); 4762c393a42Smrg if (!c1) 4772c393a42Smrg break; 4782c393a42Smrg if (c1 == c2) 4792c393a42Smrg { 4802c393a42Smrg FcCaseWalker w1t = w1; 4812c393a42Smrg FcCaseWalker w2t = w2; 4822c393a42Smrg FcChar8 c1t, c2t; 4832c393a42Smrg 4842c393a42Smrg for (;;) 4852c393a42Smrg { 486c9710b42Smrg c1t = FcStrCaseWalkerNext (&w1t, NULL); 487c9710b42Smrg c2t = FcStrCaseWalkerNext (&w2t, NULL); 4882c393a42Smrg 4892c393a42Smrg if (!c2t) 4902c393a42Smrg return cur; 4912c393a42Smrg if (c2t != c1t) 4922c393a42Smrg break; 4932c393a42Smrg } 4942c393a42Smrg } 4952c393a42Smrg } 4962c393a42Smrg return 0; 4972c393a42Smrg} 4982c393a42Smrg 4992c393a42Smrgconst FcChar8 * 5002c393a42SmrgFcStrStr (const FcChar8 *s1, const FcChar8 *s2) 5012c393a42Smrg{ 5022c393a42Smrg FcChar8 c1, c2; 5032c393a42Smrg const FcChar8 * p = s1; 5042c393a42Smrg const FcChar8 * b = s2; 5052c393a42Smrg 5062c393a42Smrg if (!s1 || !s2) 5072c393a42Smrg return 0; 5082c393a42Smrg 5092c393a42Smrg if (s1 == s2) 5102c393a42Smrg return s1; 5112c393a42Smrg 5122c393a42Smrgagain: 5132c393a42Smrg c2 = *s2++; 5142c393a42Smrg 5152c393a42Smrg if (!c2) 5162c393a42Smrg return 0; 5172c393a42Smrg 518ca08ab68Smrg for (;;) 5192c393a42Smrg { 5202c393a42Smrg p = s1; 5212c393a42Smrg c1 = *s1++; 5222c393a42Smrg if (!c1 || c1 == c2) 5232c393a42Smrg break; 5242c393a42Smrg } 5252c393a42Smrg 5262c393a42Smrg if (c1 != c2) 5272c393a42Smrg return 0; 5282c393a42Smrg 5292c393a42Smrg for (;;) 5302c393a42Smrg { 5312c393a42Smrg c1 = *s1; 5322c393a42Smrg c2 = *s2; 5332c393a42Smrg if (c1 && c2 && c1 != c2) 5342c393a42Smrg { 5352c393a42Smrg s1 = p + 1; 5362c393a42Smrg s2 = b; 5372c393a42Smrg goto again; 5382c393a42Smrg } 5392c393a42Smrg if (!c2) 5402c393a42Smrg return p; 5412c393a42Smrg if (!c1) 5422c393a42Smrg return 0; 5432c393a42Smrg ++ s1; 5442c393a42Smrg ++ s2; 5452c393a42Smrg } 5462c393a42Smrg /* never reached. */ 5472c393a42Smrg} 5482c393a42Smrg 5492c393a42Smrgint 5502c393a42SmrgFcUtf8ToUcs4 (const FcChar8 *src_orig, 5512c393a42Smrg FcChar32 *dst, 5522c393a42Smrg int len) 5532c393a42Smrg{ 5542c393a42Smrg const FcChar8 *src = src_orig; 5552c393a42Smrg FcChar8 s; 5562c393a42Smrg int extra; 5572c393a42Smrg FcChar32 result; 5582c393a42Smrg 5592c393a42Smrg if (len == 0) 5602c393a42Smrg return 0; 561ca08ab68Smrg 5622c393a42Smrg s = *src++; 5632c393a42Smrg len--; 564ca08ab68Smrg 5652c393a42Smrg if (!(s & 0x80)) 5662c393a42Smrg { 5672c393a42Smrg result = s; 5682c393a42Smrg extra = 0; 569ca08ab68Smrg } 5702c393a42Smrg else if (!(s & 0x40)) 5712c393a42Smrg { 5722c393a42Smrg return -1; 5732c393a42Smrg } 5742c393a42Smrg else if (!(s & 0x20)) 5752c393a42Smrg { 5762c393a42Smrg result = s & 0x1f; 5772c393a42Smrg extra = 1; 5782c393a42Smrg } 5792c393a42Smrg else if (!(s & 0x10)) 5802c393a42Smrg { 5812c393a42Smrg result = s & 0xf; 5822c393a42Smrg extra = 2; 5832c393a42Smrg } 5842c393a42Smrg else if (!(s & 0x08)) 5852c393a42Smrg { 5862c393a42Smrg result = s & 0x07; 5872c393a42Smrg extra = 3; 5882c393a42Smrg } 5892c393a42Smrg else if (!(s & 0x04)) 5902c393a42Smrg { 5912c393a42Smrg result = s & 0x03; 5922c393a42Smrg extra = 4; 5932c393a42Smrg } 5942c393a42Smrg else if ( ! (s & 0x02)) 5952c393a42Smrg { 5962c393a42Smrg result = s & 0x01; 5972c393a42Smrg extra = 5; 5982c393a42Smrg } 5992c393a42Smrg else 6002c393a42Smrg { 6012c393a42Smrg return -1; 6022c393a42Smrg } 6032c393a42Smrg if (extra > len) 6042c393a42Smrg return -1; 605ca08ab68Smrg 6062c393a42Smrg while (extra--) 6072c393a42Smrg { 6082c393a42Smrg result <<= 6; 6092c393a42Smrg s = *src++; 6102c393a42Smrg 6112c393a42Smrg if ((s & 0xc0) != 0x80) 6122c393a42Smrg return -1; 6132c393a42Smrg 6142c393a42Smrg result |= s & 0x3f; 6152c393a42Smrg } 6162c393a42Smrg *dst = result; 6172c393a42Smrg return src - src_orig; 6182c393a42Smrg} 6192c393a42Smrg 6202c393a42SmrgFcBool 6212c393a42SmrgFcUtf8Len (const FcChar8 *string, 6222c393a42Smrg int len, 6232c393a42Smrg int *nchar, 6242c393a42Smrg int *wchar) 6252c393a42Smrg{ 6262c393a42Smrg int n; 6272c393a42Smrg int clen; 6282c393a42Smrg FcChar32 c; 6292c393a42Smrg FcChar32 max; 630ca08ab68Smrg 6312c393a42Smrg n = 0; 6322c393a42Smrg max = 0; 6332c393a42Smrg while (len) 6342c393a42Smrg { 6352c393a42Smrg clen = FcUtf8ToUcs4 (string, &c, len); 6362c393a42Smrg if (clen <= 0) /* malformed UTF8 string */ 6372c393a42Smrg return FcFalse; 6382c393a42Smrg if (c > max) 6392c393a42Smrg max = c; 6402c393a42Smrg string += clen; 6412c393a42Smrg len -= clen; 6422c393a42Smrg n++; 6432c393a42Smrg } 6442c393a42Smrg *nchar = n; 6452c393a42Smrg if (max >= 0x10000) 6462c393a42Smrg *wchar = 4; 6472c393a42Smrg else if (max > 0x100) 6482c393a42Smrg *wchar = 2; 6492c393a42Smrg else 6502c393a42Smrg *wchar = 1; 6512c393a42Smrg return FcTrue; 6522c393a42Smrg} 6532c393a42Smrg 6542c393a42Smrgint 6552c393a42SmrgFcUcs4ToUtf8 (FcChar32 ucs4, 6562c393a42Smrg FcChar8 dest[FC_UTF8_MAX_LEN]) 6572c393a42Smrg{ 6582c393a42Smrg int bits; 6592c393a42Smrg FcChar8 *d = dest; 660ca08ab68Smrg 6612c393a42Smrg if (ucs4 < 0x80) { *d++= ucs4; bits= -6; } 6622c393a42Smrg else if (ucs4 < 0x800) { *d++= ((ucs4 >> 6) & 0x1F) | 0xC0; bits= 0; } 6632c393a42Smrg else if (ucs4 < 0x10000) { *d++= ((ucs4 >> 12) & 0x0F) | 0xE0; bits= 6; } 6642c393a42Smrg else if (ucs4 < 0x200000) { *d++= ((ucs4 >> 18) & 0x07) | 0xF0; bits= 12; } 6652c393a42Smrg else if (ucs4 < 0x4000000) { *d++= ((ucs4 >> 24) & 0x03) | 0xF8; bits= 18; } 6662c393a42Smrg else if (ucs4 < 0x80000000) { *d++= ((ucs4 >> 30) & 0x01) | 0xFC; bits= 24; } 6672c393a42Smrg else return 0; 6682c393a42Smrg 6692c393a42Smrg for ( ; bits >= 0; bits-= 6) { 6702c393a42Smrg *d++= ((ucs4 >> bits) & 0x3F) | 0x80; 6712c393a42Smrg } 6722c393a42Smrg return d - dest; 6732c393a42Smrg} 6742c393a42Smrg 6752c393a42Smrg#define GetUtf16(src,endian) \ 6762c393a42Smrg ((FcChar16) ((src)[endian == FcEndianBig ? 0 : 1] << 8) | \ 6772c393a42Smrg (FcChar16) ((src)[endian == FcEndianBig ? 1 : 0])) 6782c393a42Smrg 6792c393a42Smrgint 6802c393a42SmrgFcUtf16ToUcs4 (const FcChar8 *src_orig, 6812c393a42Smrg FcEndian endian, 6822c393a42Smrg FcChar32 *dst, 6832c393a42Smrg int len) /* in bytes */ 6842c393a42Smrg{ 6852c393a42Smrg const FcChar8 *src = src_orig; 6862c393a42Smrg FcChar16 a, b; 6872c393a42Smrg FcChar32 result; 6882c393a42Smrg 6892c393a42Smrg if (len < 2) 6902c393a42Smrg return 0; 691ca08ab68Smrg 6922c393a42Smrg a = GetUtf16 (src, endian); src += 2; len -= 2; 693ca08ab68Smrg 694ca08ab68Smrg /* 695ca08ab68Smrg * Check for surrogate 6962c393a42Smrg */ 6972c393a42Smrg if ((a & 0xfc00) == 0xd800) 6982c393a42Smrg { 6992c393a42Smrg if (len < 2) 7002c393a42Smrg return 0; 7012c393a42Smrg b = GetUtf16 (src, endian); src += 2; len -= 2; 7022c393a42Smrg /* 7032c393a42Smrg * Check for invalid surrogate sequence 7042c393a42Smrg */ 7052c393a42Smrg if ((b & 0xfc00) != 0xdc00) 7062c393a42Smrg return 0; 7072c393a42Smrg result = ((((FcChar32) a & 0x3ff) << 10) | 7082c393a42Smrg ((FcChar32) b & 0x3ff)) + 0x10000; 7092c393a42Smrg } 7102c393a42Smrg else 7112c393a42Smrg result = a; 7122c393a42Smrg *dst = result; 7132c393a42Smrg return src - src_orig; 7142c393a42Smrg} 7152c393a42Smrg 7162c393a42SmrgFcBool 7172c393a42SmrgFcUtf16Len (const FcChar8 *string, 7182c393a42Smrg FcEndian endian, 7192c393a42Smrg int len, /* in bytes */ 7202c393a42Smrg int *nchar, 7212c393a42Smrg int *wchar) 7222c393a42Smrg{ 7232c393a42Smrg int n; 7242c393a42Smrg int clen; 7252c393a42Smrg FcChar32 c; 7262c393a42Smrg FcChar32 max; 727ca08ab68Smrg 7282c393a42Smrg n = 0; 7292c393a42Smrg max = 0; 7302c393a42Smrg while (len) 7312c393a42Smrg { 7322c393a42Smrg clen = FcUtf16ToUcs4 (string, endian, &c, len); 7332c393a42Smrg if (clen <= 0) /* malformed UTF8 string */ 7342c393a42Smrg return FcFalse; 7352c393a42Smrg if (c > max) 7362c393a42Smrg max = c; 7372c393a42Smrg string += clen; 7382c393a42Smrg len -= clen; 7392c393a42Smrg n++; 7402c393a42Smrg } 7412c393a42Smrg *nchar = n; 7422c393a42Smrg if (max >= 0x10000) 7432c393a42Smrg *wchar = 4; 7442c393a42Smrg else if (max > 0x100) 7452c393a42Smrg *wchar = 2; 7462c393a42Smrg else 7472c393a42Smrg *wchar = 1; 7482c393a42Smrg return FcTrue; 7492c393a42Smrg} 7502c393a42Smrg 7512c393a42Smrgvoid 7522c393a42SmrgFcStrBufInit (FcStrBuf *buf, FcChar8 *init, int size) 7532c393a42Smrg{ 754a6844aabSmrg if (init) 755a6844aabSmrg { 756a6844aabSmrg buf->buf = init; 757a6844aabSmrg buf->size = size; 758a6844aabSmrg } else 759a6844aabSmrg { 760a6844aabSmrg buf->buf = buf->buf_static; 761a6844aabSmrg buf->size = sizeof (buf->buf_static); 762a6844aabSmrg } 7632c393a42Smrg buf->allocated = FcFalse; 7642c393a42Smrg buf->failed = FcFalse; 7652c393a42Smrg buf->len = 0; 7662c393a42Smrg} 7672c393a42Smrg 7682c393a42Smrgvoid 7692c393a42SmrgFcStrBufDestroy (FcStrBuf *buf) 7702c393a42Smrg{ 7712c393a42Smrg if (buf->allocated) 7722c393a42Smrg { 7732c393a42Smrg free (buf->buf); 7742c393a42Smrg FcStrBufInit (buf, 0, 0); 7752c393a42Smrg } 7762c393a42Smrg} 7772c393a42Smrg 7782c393a42SmrgFcChar8 * 7792c393a42SmrgFcStrBufDone (FcStrBuf *buf) 7802c393a42Smrg{ 7812c393a42Smrg FcChar8 *ret; 7822c393a42Smrg 783a6844aabSmrg if (buf->failed) 784a6844aabSmrg ret = NULL; 785a6844aabSmrg else 786a6844aabSmrg ret = malloc (buf->len + 1); 7872c393a42Smrg if (ret) 7882c393a42Smrg { 7892c393a42Smrg memcpy (ret, buf->buf, buf->len); 7902c393a42Smrg ret[buf->len] = '\0'; 7912c393a42Smrg } 7922c393a42Smrg FcStrBufDestroy (buf); 7932c393a42Smrg return ret; 7942c393a42Smrg} 7952c393a42Smrg 796a6844aabSmrgFcChar8 * 797a6844aabSmrgFcStrBufDoneStatic (FcStrBuf *buf) 798a6844aabSmrg{ 799a6844aabSmrg FcStrBufChar (buf, '\0'); 800a6844aabSmrg 801a6844aabSmrg if (buf->failed) 802a6844aabSmrg return NULL; 803a6844aabSmrg 804a6844aabSmrg return buf->buf; 805a6844aabSmrg} 806a6844aabSmrg 8072c393a42SmrgFcBool 8082c393a42SmrgFcStrBufChar (FcStrBuf *buf, FcChar8 c) 8092c393a42Smrg{ 8102c393a42Smrg if (buf->len == buf->size) 8112c393a42Smrg { 8122c393a42Smrg FcChar8 *new; 8132c393a42Smrg int size; 8142c393a42Smrg 815a6844aabSmrg if (buf->failed) 816a6844aabSmrg return FcFalse; 817a6844aabSmrg 8182c393a42Smrg if (buf->allocated) 8192c393a42Smrg { 8202c393a42Smrg size = buf->size * 2; 8212c393a42Smrg new = realloc (buf->buf, size); 8222c393a42Smrg } 8232c393a42Smrg else 8242c393a42Smrg { 8252c393a42Smrg size = buf->size + 64; 8262c393a42Smrg new = malloc (size); 8272c393a42Smrg if (new) 8282c393a42Smrg { 8292c393a42Smrg buf->allocated = FcTrue; 8302c393a42Smrg memcpy (new, buf->buf, buf->len); 8312c393a42Smrg } 8322c393a42Smrg } 8332c393a42Smrg if (!new) 8342c393a42Smrg { 8352c393a42Smrg buf->failed = FcTrue; 8362c393a42Smrg return FcFalse; 8372c393a42Smrg } 8382c393a42Smrg buf->size = size; 8392c393a42Smrg buf->buf = new; 8402c393a42Smrg } 8412c393a42Smrg buf->buf[buf->len++] = c; 8422c393a42Smrg return FcTrue; 8432c393a42Smrg} 8442c393a42Smrg 8452c393a42SmrgFcBool 8462c393a42SmrgFcStrBufString (FcStrBuf *buf, const FcChar8 *s) 8472c393a42Smrg{ 8482c393a42Smrg FcChar8 c; 8492c393a42Smrg while ((c = *s++)) 8502c393a42Smrg if (!FcStrBufChar (buf, c)) 8512c393a42Smrg return FcFalse; 8522c393a42Smrg return FcTrue; 8532c393a42Smrg} 8542c393a42Smrg 8552c393a42SmrgFcBool 8562c393a42SmrgFcStrBufData (FcStrBuf *buf, const FcChar8 *s, int len) 8572c393a42Smrg{ 8582c393a42Smrg while (len-- > 0) 8592c393a42Smrg if (!FcStrBufChar (buf, *s++)) 8602c393a42Smrg return FcFalse; 8612c393a42Smrg return FcTrue; 8622c393a42Smrg} 8632c393a42Smrg 8642c393a42SmrgFcBool 8652c393a42SmrgFcStrUsesHome (const FcChar8 *s) 8662c393a42Smrg{ 8672c393a42Smrg return *s == '~'; 8682c393a42Smrg} 8692c393a42Smrg 870c9710b42SmrgFcChar8 * 871c9710b42SmrgFcStrBuildFilename (const FcChar8 *path, 872c9710b42Smrg ...) 873c9710b42Smrg{ 874c9710b42Smrg va_list ap; 875b09479dcSmrg FcStrSet *sset; 876c9710b42Smrg FcStrList *list; 877c9710b42Smrg FcChar8 *s, *ret = NULL, *p; 878c9710b42Smrg size_t len = 0; 879c9710b42Smrg 880b09479dcSmrg if (!path) 881b09479dcSmrg return NULL; 882b09479dcSmrg 883953daebaSmrg sset = FcStrSetCreateEx (FCSS_ALLOW_DUPLICATES | FCSS_GROW_BY_64); 884b09479dcSmrg if (!sset) 885c9710b42Smrg return NULL; 886c9710b42Smrg 887c9710b42Smrg if (!FcStrSetAdd (sset, path)) 888c9710b42Smrg goto bail0; 889c9710b42Smrg 890c9710b42Smrg va_start (ap, path); 891c9710b42Smrg while (1) 892c9710b42Smrg { 893c9710b42Smrg s = (FcChar8 *)va_arg (ap, FcChar8 *); 894c9710b42Smrg if (!s) 895c9710b42Smrg break; 896c9710b42Smrg if (!FcStrSetAdd (sset, s)) 897c9710b42Smrg goto bail1; 898c9710b42Smrg } 899c9710b42Smrg list = FcStrListCreate (sset); 900c9710b42Smrg while ((s = FcStrListNext (list))) 901c9710b42Smrg { 902c9710b42Smrg len += strlen ((const char *)s) + 1; 903c9710b42Smrg } 904c9710b42Smrg list->n = 0; 905c9710b42Smrg ret = malloc (sizeof (FcChar8) * (len + 1)); 906c9710b42Smrg if (!ret) 907c9710b42Smrg goto bail2; 908c9710b42Smrg p = ret; 909c9710b42Smrg while ((s = FcStrListNext (list))) 910c9710b42Smrg { 911c9710b42Smrg if (p != ret) 912c9710b42Smrg { 913c9710b42Smrg p[0] = FC_DIR_SEPARATOR; 914c9710b42Smrg p++; 915c9710b42Smrg } 916c9710b42Smrg len = strlen ((const char *)s); 917c9710b42Smrg memcpy (p, s, len); 918c9710b42Smrg p += len; 919c9710b42Smrg } 920c9710b42Smrg *p = 0; 921c9710b42Smrg 922c9710b42Smrgbail2: 923c9710b42Smrg FcStrListDone (list); 924c9710b42Smrgbail1: 925c9710b42Smrg va_end (ap); 926c9710b42Smrgbail0: 927c9710b42Smrg FcStrSetDestroy (sset); 928c9710b42Smrg 929c9710b42Smrg return ret; 930c9710b42Smrg} 931c9710b42Smrg 9322c393a42SmrgFcChar8 * 9332c393a42SmrgFcStrCopyFilename (const FcChar8 *s) 9342c393a42Smrg{ 9352c393a42Smrg FcChar8 *new; 936ca08ab68Smrg 9372c393a42Smrg if (*s == '~') 9382c393a42Smrg { 9392c393a42Smrg FcChar8 *home = FcConfigHome (); 9402c393a42Smrg FcChar8 *full; 9412c393a42Smrg int size; 9422c393a42Smrg if (!home) 943ca08ab68Smrg return NULL; 9442c393a42Smrg size = strlen ((char *) home) + strlen ((char *) s); 9452c393a42Smrg full = (FcChar8 *) malloc (size); 9462c393a42Smrg if (!full) 947ca08ab68Smrg return NULL; 9482c393a42Smrg strcpy ((char *) full, (char *) home); 9492c393a42Smrg strcat ((char *) full, (char *) s + 1); 9502c393a42Smrg new = FcStrCanonFilename (full); 9512c393a42Smrg free (full); 9522c393a42Smrg } 9532c393a42Smrg else 9542c393a42Smrg new = FcStrCanonFilename (s); 955ca08ab68Smrg 9562c393a42Smrg return new; 9572c393a42Smrg} 9582c393a42Smrg 9592c393a42SmrgFcChar8 * 9602c393a42SmrgFcStrLastSlash (const FcChar8 *path) 9612c393a42Smrg{ 9622c393a42Smrg FcChar8 *slash; 9632c393a42Smrg 9642c393a42Smrg slash = (FcChar8 *) strrchr ((const char *) path, '/'); 9652c393a42Smrg#ifdef _WIN32 9662c393a42Smrg { 9672c393a42Smrg FcChar8 *backslash; 9682c393a42Smrg 9692c393a42Smrg backslash = (FcChar8 *) strrchr ((const char *) path, '\\'); 9702c393a42Smrg if (!slash || (backslash && backslash > slash)) 9712c393a42Smrg slash = backslash; 9722c393a42Smrg } 9732c393a42Smrg#endif 9742c393a42Smrg 9752c393a42Smrg return slash; 9762c393a42Smrg} 977ca08ab68Smrg 9782c393a42SmrgFcChar8 * 9792c393a42SmrgFcStrDirname (const FcChar8 *file) 9802c393a42Smrg{ 9812c393a42Smrg FcChar8 *slash; 9822c393a42Smrg FcChar8 *dir; 9832c393a42Smrg 9842c393a42Smrg slash = FcStrLastSlash (file); 9852c393a42Smrg if (!slash) 9862c393a42Smrg return FcStrCopy ((FcChar8 *) "."); 9872c393a42Smrg dir = malloc ((slash - file) + 1); 9882c393a42Smrg if (!dir) 9892c393a42Smrg return 0; 9902c393a42Smrg strncpy ((char *) dir, (const char *) file, slash - file); 9912c393a42Smrg dir[slash - file] = '\0'; 9922c393a42Smrg return dir; 9932c393a42Smrg} 9942c393a42Smrg 9952c393a42SmrgFcChar8 * 9962c393a42SmrgFcStrBasename (const FcChar8 *file) 9972c393a42Smrg{ 9982c393a42Smrg FcChar8 *slash; 9992c393a42Smrg 10002c393a42Smrg slash = FcStrLastSlash (file); 10012c393a42Smrg if (!slash) 10022c393a42Smrg return FcStrCopy (file); 10032c393a42Smrg return FcStrCopy (slash + 1); 10042c393a42Smrg} 10052c393a42Smrg 10062c393a42Smrgstatic FcChar8 * 10072c393a42SmrgFcStrCanonAbsoluteFilename (const FcChar8 *s) 10082c393a42Smrg{ 10092c393a42Smrg FcChar8 *file; 10102c393a42Smrg FcChar8 *f; 10112c393a42Smrg const FcChar8 *slash; 10122c393a42Smrg int size; 10132c393a42Smrg 10142c393a42Smrg size = strlen ((char *) s) + 1; 10152c393a42Smrg file = malloc (size); 10162c393a42Smrg if (!file) 10172c393a42Smrg return NULL; 10182c393a42Smrg slash = NULL; 10192c393a42Smrg f = file; 1020ca08ab68Smrg#ifdef _WIN32 1021ca08ab68Smrg if (*s == '/' && *(s+1) == '/') /* Network path, do not squash // */ 1022ca08ab68Smrg *f++ = *s++; 1023ca08ab68Smrg#endif 10242c393a42Smrg for (;;) { 10252c393a42Smrg if (*s == '/' || *s == '\0') 10262c393a42Smrg { 10272c393a42Smrg if (slash) 10282c393a42Smrg { 10292c393a42Smrg switch (s - slash) { 1030a6844aabSmrg case 1: 1031a6844aabSmrg f -= 1; /* squash // and trim final / from file */ 1032a6844aabSmrg break; 10332c393a42Smrg case 2: 10342c393a42Smrg if (!strncmp ((char *) slash, "/.", 2)) 10352c393a42Smrg { 10362c393a42Smrg f -= 2; /* trim /. from file */ 10372c393a42Smrg } 10382c393a42Smrg break; 10392c393a42Smrg case 3: 10402c393a42Smrg if (!strncmp ((char *) slash, "/..", 3)) 10412c393a42Smrg { 10422c393a42Smrg f -= 3; /* trim /.. from file */ 10432c393a42Smrg while (f > file) { 10442c393a42Smrg if (*--f == '/') 10452c393a42Smrg break; 10462c393a42Smrg } 10472c393a42Smrg } 10482c393a42Smrg break; 10492c393a42Smrg } 10502c393a42Smrg } 10512c393a42Smrg slash = s; 10522c393a42Smrg } 10532c393a42Smrg if (!(*f++ = *s++)) 10542c393a42Smrg break; 10552c393a42Smrg } 10562c393a42Smrg return file; 10572c393a42Smrg} 1058ca08ab68Smrg 10592c393a42Smrg#ifdef _WIN32 10602c393a42Smrg/* 1061ca08ab68Smrg * Convert '\\' to '/' , remove double '/' 10622c393a42Smrg */ 10632c393a42Smrgstatic void 10642c393a42SmrgFcConvertDosPath (char *str) 10652c393a42Smrg{ 10662c393a42Smrg size_t len = strlen (str); 10672c393a42Smrg char *p = str; 10682c393a42Smrg char *dest = str; 10692c393a42Smrg char *end = str + len; 10702c393a42Smrg char last = 0; 1071a6844aabSmrg 1072a6844aabSmrg if (*p == '\\') 1073a6844aabSmrg { 1074a6844aabSmrg *p = '/'; 1075a6844aabSmrg p++; 1076a6844aabSmrg dest++; 1077a6844aabSmrg } 10782c393a42Smrg while (p < end) 10792c393a42Smrg { 10802c393a42Smrg if (*p == '\\') 10812c393a42Smrg *p = '/'; 10822c393a42Smrg 10832c393a42Smrg if (*p != '/' 10842c393a42Smrg || last != '/') 10852c393a42Smrg { 10862c393a42Smrg *dest++ = *p; 10872c393a42Smrg } 10882c393a42Smrg 10892c393a42Smrg last = *p; 10902c393a42Smrg p++; 10912c393a42Smrg } 10922c393a42Smrg 10932c393a42Smrg *dest = 0; 10942c393a42Smrg} 10952c393a42Smrg#endif 10962c393a42Smrg 10972c393a42SmrgFcChar8 * 10982c393a42SmrgFcStrCanonFilename (const FcChar8 *s) 10992c393a42Smrg{ 11002c393a42Smrg#ifdef _WIN32 11012c393a42Smrg FcChar8 full[FC_MAX_FILE_LEN + 2]; 1102ca08ab68Smrg int size = GetFullPathName ((LPCSTR) s, sizeof (full) -1, 1103ca08ab68Smrg (LPSTR) full, NULL); 11042c393a42Smrg 11052c393a42Smrg if (size == 0) 11062c393a42Smrg perror ("GetFullPathName"); 11072c393a42Smrg 1108ca08ab68Smrg FcConvertDosPath ((char *) full); 11092c393a42Smrg return FcStrCanonAbsoluteFilename (full); 11102c393a42Smrg#else 11112c393a42Smrg if (s[0] == '/') 11122c393a42Smrg return FcStrCanonAbsoluteFilename (s); 11132c393a42Smrg else 11142c393a42Smrg { 11152c393a42Smrg FcChar8 *full; 11162c393a42Smrg FcChar8 *file; 11172c393a42Smrg 11182c393a42Smrg FcChar8 cwd[FC_MAX_FILE_LEN + 2]; 11192c393a42Smrg if (getcwd ((char *) cwd, FC_MAX_FILE_LEN) == NULL) 11202c393a42Smrg return NULL; 1121c9710b42Smrg full = FcStrBuildFilename (cwd, s, NULL); 11222c393a42Smrg file = FcStrCanonAbsoluteFilename (full); 11232c393a42Smrg FcStrFree (full); 11242c393a42Smrg return file; 11252c393a42Smrg } 11262c393a42Smrg#endif 11272c393a42Smrg} 11282c393a42Smrg 11292c393a42Smrg 11302c393a42SmrgFcStrSet * 11312c393a42SmrgFcStrSetCreate (void) 1132953daebaSmrg{ 1133953daebaSmrg return FcStrSetCreateEx (FCSS_DEFAULT); 1134953daebaSmrg} 1135953daebaSmrg 1136953daebaSmrgFcStrSet * 1137953daebaSmrgFcStrSetCreateEx (unsigned int control) 11382c393a42Smrg{ 11392c393a42Smrg FcStrSet *set = malloc (sizeof (FcStrSet)); 11402c393a42Smrg if (!set) 11412c393a42Smrg return 0; 1142c9710b42Smrg FcRefInit (&set->ref, 1); 11432c393a42Smrg set->num = 0; 11442c393a42Smrg set->size = 0; 11452c393a42Smrg set->strs = 0; 1146953daebaSmrg set->control = control; 11472c393a42Smrg return set; 11482c393a42Smrg} 11492c393a42Smrg 1150953daebaSmrgstatic FcBool 1151953daebaSmrg_FcStrSetGrow (FcStrSet *set, int growElements) 1152953daebaSmrg{ 1153953daebaSmrg /* accommodate an additional NULL entry at the end of the array */ 1154953daebaSmrg FcChar8 **strs = malloc ((set->size + growElements + 1) * sizeof (FcChar8 *)); 1155953daebaSmrg if (!strs) 1156953daebaSmrg return FcFalse; 1157953daebaSmrg if (set->num) 1158953daebaSmrg memcpy (strs, set->strs, set->num * sizeof (FcChar8 *)); 1159953daebaSmrg if (set->strs) 1160953daebaSmrg free (set->strs); 1161953daebaSmrg set->size = set->size + growElements; 1162953daebaSmrg set->strs = strs; 1163953daebaSmrg return FcTrue; 1164953daebaSmrg} 1165953daebaSmrg 11662c393a42Smrgstatic FcBool 11672c393a42Smrg_FcStrSetAppend (FcStrSet *set, FcChar8 *s) 11682c393a42Smrg{ 1169953daebaSmrg if (!FcStrSetHasControlBit (set, FCSS_ALLOW_DUPLICATES)) 11702c393a42Smrg { 1171953daebaSmrg if (FcStrSetMember (set, s)) 1172953daebaSmrg { 1173953daebaSmrg FcStrFree (s); 1174953daebaSmrg return FcTrue; 1175953daebaSmrg } 11762c393a42Smrg } 11772c393a42Smrg if (set->num == set->size) 11782c393a42Smrg { 1179953daebaSmrg int growElements = FcStrSetHasControlBit (set, FCSS_GROW_BY_64) ? 64 : 1; 1180953daebaSmrg if (!_FcStrSetGrow(set, growElements)) 1181953daebaSmrg return FcFalse; 11822c393a42Smrg } 11832c393a42Smrg set->strs[set->num++] = s; 11842c393a42Smrg set->strs[set->num] = 0; 11852c393a42Smrg return FcTrue; 11862c393a42Smrg} 11872c393a42Smrg 11882c393a42SmrgFcBool 11892c393a42SmrgFcStrSetMember (FcStrSet *set, const FcChar8 *s) 11902c393a42Smrg{ 11912c393a42Smrg int i; 11922c393a42Smrg 11932c393a42Smrg for (i = 0; i < set->num; i++) 11942c393a42Smrg if (!FcStrCmp (set->strs[i], s)) 11952c393a42Smrg return FcTrue; 11962c393a42Smrg return FcFalse; 11972c393a42Smrg} 11982c393a42Smrg 11992c393a42SmrgFcBool 12002c393a42SmrgFcStrSetEqual (FcStrSet *sa, FcStrSet *sb) 12012c393a42Smrg{ 12022c393a42Smrg int i; 12032c393a42Smrg if (sa->num != sb->num) 12042c393a42Smrg return FcFalse; 12052c393a42Smrg for (i = 0; i < sa->num; i++) 12062c393a42Smrg if (!FcStrSetMember (sb, sa->strs[i])) 12072c393a42Smrg return FcFalse; 12082c393a42Smrg return FcTrue; 12092c393a42Smrg} 12102c393a42Smrg 12112c393a42SmrgFcBool 12122c393a42SmrgFcStrSetAdd (FcStrSet *set, const FcChar8 *s) 12132c393a42Smrg{ 12142c393a42Smrg FcChar8 *new = FcStrCopy (s); 12152c393a42Smrg if (!new) 12162c393a42Smrg return FcFalse; 12172c393a42Smrg if (!_FcStrSetAppend (set, new)) 12182c393a42Smrg { 12192c393a42Smrg FcStrFree (new); 12202c393a42Smrg return FcFalse; 12212c393a42Smrg } 12222c393a42Smrg return FcTrue; 12232c393a42Smrg} 12242c393a42Smrg 12252c393a42SmrgFcBool 12262c393a42SmrgFcStrSetAddFilename (FcStrSet *set, const FcChar8 *s) 12272c393a42Smrg{ 12282c393a42Smrg FcChar8 *new = FcStrCopyFilename (s); 12292c393a42Smrg if (!new) 12302c393a42Smrg return FcFalse; 12312c393a42Smrg if (!_FcStrSetAppend (set, new)) 12322c393a42Smrg { 12332c393a42Smrg FcStrFree (new); 12342c393a42Smrg return FcFalse; 12352c393a42Smrg } 12362c393a42Smrg return FcTrue; 12372c393a42Smrg} 12382c393a42Smrg 1239ca08ab68SmrgFcBool 1240ca08ab68SmrgFcStrSetAddLangs (FcStrSet *strs, const char *languages) 1241ca08ab68Smrg{ 1242ca08ab68Smrg const char *p = languages, *next; 1243ca08ab68Smrg FcChar8 lang[128] = {0}, *normalized_lang; 1244ca08ab68Smrg size_t len; 1245ca08ab68Smrg FcBool ret = FcFalse; 1246ca08ab68Smrg 1247ca08ab68Smrg if (!languages) 1248ca08ab68Smrg return FcFalse; 1249ca08ab68Smrg 1250ca08ab68Smrg while ((next = strchr (p, ':'))) 1251ca08ab68Smrg { 1252ca08ab68Smrg len = next - p; 1253c9710b42Smrg len = FC_MIN (len, 127); 1254ca08ab68Smrg strncpy ((char *) lang, p, len); 1255ca08ab68Smrg lang[len] = 0; 1256ca08ab68Smrg /* ignore an empty item */ 1257ca08ab68Smrg if (*lang) 1258ca08ab68Smrg { 1259ca08ab68Smrg normalized_lang = FcLangNormalize ((const FcChar8 *) lang); 1260ca08ab68Smrg if (normalized_lang) 1261ca08ab68Smrg { 1262ca08ab68Smrg FcStrSetAdd (strs, normalized_lang); 1263c9710b42Smrg FcStrFree (normalized_lang); 1264ca08ab68Smrg ret = FcTrue; 1265ca08ab68Smrg } 1266ca08ab68Smrg } 1267ca08ab68Smrg p = next + 1; 1268ca08ab68Smrg } 1269ca08ab68Smrg if (*p) 1270ca08ab68Smrg { 1271ca08ab68Smrg normalized_lang = FcLangNormalize ((const FcChar8 *) p); 1272ca08ab68Smrg if (normalized_lang) 1273ca08ab68Smrg { 1274ca08ab68Smrg FcStrSetAdd (strs, normalized_lang); 1275c9710b42Smrg FcStrFree (normalized_lang); 1276ca08ab68Smrg ret = FcTrue; 1277ca08ab68Smrg } 1278ca08ab68Smrg } 1279ca08ab68Smrg 1280ca08ab68Smrg return ret; 1281ca08ab68Smrg} 1282ca08ab68Smrg 12832c393a42SmrgFcBool 12842c393a42SmrgFcStrSetDel (FcStrSet *set, const FcChar8 *s) 12852c393a42Smrg{ 12862c393a42Smrg int i; 12872c393a42Smrg 12882c393a42Smrg for (i = 0; i < set->num; i++) 12892c393a42Smrg if (!FcStrCmp (set->strs[i], s)) 12902c393a42Smrg { 12912c393a42Smrg FcStrFree (set->strs[i]); 12922c393a42Smrg /* 12932c393a42Smrg * copy remaining string pointers and trailing 12942c393a42Smrg * NULL 12952c393a42Smrg */ 1296ca08ab68Smrg memmove (&set->strs[i], &set->strs[i+1], 12972c393a42Smrg (set->num - i) * sizeof (FcChar8 *)); 12982c393a42Smrg set->num--; 12992c393a42Smrg return FcTrue; 13002c393a42Smrg } 13012c393a42Smrg return FcFalse; 13022c393a42Smrg} 13032c393a42Smrg 1304c9710b42Smrg/* TODO Make public */ 1305c9710b42Smrgstatic FcStrSet * 1306c9710b42SmrgFcStrSetReference (FcStrSet *set) 1307c9710b42Smrg{ 1308c9710b42Smrg if (FcRefIsConst (&set->ref)) 1309c9710b42Smrg return set; 1310c9710b42Smrg 1311c9710b42Smrg FcRefInc (&set->ref); 1312c9710b42Smrg return set; 1313c9710b42Smrg} 1314c9710b42Smrg 13152c393a42Smrgvoid 13162c393a42SmrgFcStrSetDestroy (FcStrSet *set) 13172c393a42Smrg{ 1318c9710b42Smrg int i; 1319ca08ab68Smrg 1320c9710b42Smrg /* We rely on this in FcGetDefaultLangs for caching. */ 1321c9710b42Smrg if (FcRefIsConst (&set->ref)) 1322c9710b42Smrg return; 1323c9710b42Smrg 1324c9710b42Smrg if (FcRefDec (&set->ref) != 1) 1325c9710b42Smrg return; 1326c9710b42Smrg 1327c9710b42Smrg for (i = 0; i < set->num; i++) 1328c9710b42Smrg FcStrFree (set->strs[i]); 1329c9710b42Smrg if (set->strs) 1330c9710b42Smrg free (set->strs); 1331c9710b42Smrg free (set); 13322c393a42Smrg} 13332c393a42Smrg 13342c393a42SmrgFcStrList * 13352c393a42SmrgFcStrListCreate (FcStrSet *set) 13362c393a42Smrg{ 13372c393a42Smrg FcStrList *list; 13382c393a42Smrg 13392c393a42Smrg list = malloc (sizeof (FcStrList)); 13402c393a42Smrg if (!list) 13412c393a42Smrg return 0; 13422c393a42Smrg list->set = set; 1343c9710b42Smrg FcStrSetReference (set); 13442c393a42Smrg list->n = 0; 13452c393a42Smrg return list; 13462c393a42Smrg} 13472c393a42Smrg 13486fc018e4Smrgvoid 13496fc018e4SmrgFcStrListFirst (FcStrList *list) 13506fc018e4Smrg{ 13516fc018e4Smrg list->n = 0; 13526fc018e4Smrg} 13536fc018e4Smrg 13542c393a42SmrgFcChar8 * 13552c393a42SmrgFcStrListNext (FcStrList *list) 13562c393a42Smrg{ 13572c393a42Smrg if (list->n >= list->set->num) 13582c393a42Smrg return 0; 13592c393a42Smrg return list->set->strs[list->n++]; 13602c393a42Smrg} 13612c393a42Smrg 13622c393a42Smrgvoid 13632c393a42SmrgFcStrListDone (FcStrList *list) 13642c393a42Smrg{ 13652c393a42Smrg FcStrSetDestroy (list->set); 13662c393a42Smrg free (list); 13672c393a42Smrg} 13682c393a42Smrg 13692c393a42Smrg#define __fcstr__ 13702c393a42Smrg#include "fcaliastail.h" 13712c393a42Smrg#undef __fcstr__ 1372