fcstr.c revision 6fc018e4
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> 29ca08ab68Smrg#ifdef HAVE_REGEX_H 30ca08ab68Smrg#include <regex.h> 31ca08ab68Smrg#endif 32c9710b42Smrg 33c9710b42Smrg 34c9710b42Smrg/* Objects MT-safe for readonly access. */ 352c393a42Smrg 362c393a42SmrgFcChar8 * 372c393a42SmrgFcStrCopy (const FcChar8 *s) 382c393a42Smrg{ 39c9710b42Smrg return FcStrdup (s); 402c393a42Smrg} 412c393a42Smrg 422c393a42SmrgFcChar8 * 432c393a42SmrgFcStrPlus (const FcChar8 *s1, const FcChar8 *s2) 442c393a42Smrg{ 45ca08ab68Smrg int s1l = strlen ((char *) s1); 46ca08ab68Smrg int s2l = strlen ((char *) s2); 47ca08ab68Smrg int l = s1l + s2l + 1; 482c393a42Smrg FcChar8 *s = malloc (l); 492c393a42Smrg 502c393a42Smrg if (!s) 512c393a42Smrg return 0; 52ca08ab68Smrg memcpy (s, s1, s1l); 53ca08ab68Smrg memcpy (s + s1l, s2, s2l + 1); 542c393a42Smrg return s; 552c393a42Smrg} 562c393a42Smrg 572c393a42Smrgvoid 582c393a42SmrgFcStrFree (FcChar8 *s) 592c393a42Smrg{ 602c393a42Smrg free (s); 612c393a42Smrg} 622c393a42Smrg 632c393a42Smrg 642c393a42Smrg#include "../fc-case/fccase.h" 652c393a42Smrg 662c393a42Smrg#define FcCaseFoldUpperCount(cf) \ 672c393a42Smrg ((cf)->method == FC_CASE_FOLD_FULL ? 1 : (cf)->count) 682c393a42Smrg 692c393a42Smrgtypedef struct _FcCaseWalker { 702c393a42Smrg const FcChar8 *read; 712c393a42Smrg const FcChar8 *src; 722c393a42Smrg FcChar8 utf8[FC_MAX_CASE_FOLD_CHARS + 1]; 732c393a42Smrg} FcCaseWalker; 742c393a42Smrg 752c393a42Smrgstatic void 762c393a42SmrgFcStrCaseWalkerInit (const FcChar8 *src, FcCaseWalker *w) 772c393a42Smrg{ 782c393a42Smrg w->src = src; 792c393a42Smrg w->read = 0; 802c393a42Smrg} 812c393a42Smrg 822c393a42Smrgstatic FcChar8 832c393a42SmrgFcStrCaseWalkerLong (FcCaseWalker *w, FcChar8 r) 842c393a42Smrg{ 852c393a42Smrg FcChar32 ucs4; 862c393a42Smrg int slen; 872c393a42Smrg int len = strlen((char*)w->src); 882c393a42Smrg 892c393a42Smrg slen = FcUtf8ToUcs4 (w->src - 1, &ucs4, len + 1); 902c393a42Smrg if (slen <= 0) 912c393a42Smrg return r; 922c393a42Smrg if (FC_MIN_FOLD_CHAR <= ucs4 && ucs4 <= FC_MAX_FOLD_CHAR) 932c393a42Smrg { 942c393a42Smrg int min = 0; 952c393a42Smrg int max = FC_NUM_CASE_FOLD; 962c393a42Smrg 972c393a42Smrg while (min <= max) 982c393a42Smrg { 992c393a42Smrg int mid = (min + max) >> 1; 1002c393a42Smrg FcChar32 low = fcCaseFold[mid].upper; 1012c393a42Smrg FcChar32 high = low + FcCaseFoldUpperCount (&fcCaseFold[mid]); 102ca08ab68Smrg 1032c393a42Smrg if (high <= ucs4) 1042c393a42Smrg min = mid + 1; 1052c393a42Smrg else if (ucs4 < low) 1062c393a42Smrg max = mid - 1; 1072c393a42Smrg else 1082c393a42Smrg { 1092c393a42Smrg const FcCaseFold *fold = &fcCaseFold[mid]; 1102c393a42Smrg int dlen; 1112c393a42Smrg 1122c393a42Smrg switch (fold->method) { 1132c393a42Smrg case FC_CASE_FOLD_EVEN_ODD: 1142c393a42Smrg if ((ucs4 & 1) != (fold->upper & 1)) 1152c393a42Smrg return r; 1162c393a42Smrg /* fall through ... */ 1172c393a42Smrg default: 1182c393a42Smrg dlen = FcUcs4ToUtf8 (ucs4 + fold->offset, w->utf8); 1192c393a42Smrg break; 1202c393a42Smrg case FC_CASE_FOLD_FULL: 1212c393a42Smrg dlen = fold->count; 1222c393a42Smrg memcpy (w->utf8, fcCaseFoldChars + fold->offset, dlen); 1232c393a42Smrg break; 1242c393a42Smrg } 1252c393a42Smrg 1262c393a42Smrg /* consume rest of src utf-8 bytes */ 1272c393a42Smrg w->src += slen - 1; 1282c393a42Smrg 1292c393a42Smrg /* read from temp buffer */ 1302c393a42Smrg w->utf8[dlen] = '\0'; 1312c393a42Smrg w->read = w->utf8; 1322c393a42Smrg return *w->read++; 1332c393a42Smrg } 1342c393a42Smrg } 1352c393a42Smrg } 1362c393a42Smrg return r; 1372c393a42Smrg} 1382c393a42Smrg 1392c393a42Smrgstatic FcChar8 140c9710b42SmrgFcStrCaseWalkerNext (FcCaseWalker *w, const char *delims) 1412c393a42Smrg{ 1422c393a42Smrg FcChar8 r; 1432c393a42Smrg 1442c393a42Smrg if (w->read) 1452c393a42Smrg { 1462c393a42Smrg if ((r = *w->read++)) 1472c393a42Smrg return r; 1482c393a42Smrg w->read = 0; 1492c393a42Smrg } 1502c393a42Smrg do 1512c393a42Smrg { 1522c393a42Smrg r = *w->src++; 153c9710b42Smrg } while (r != 0 && delims && strchr (delims, r)); 154ca08ab68Smrg 1552c393a42Smrg if ((r & 0xc0) == 0xc0) 1562c393a42Smrg return FcStrCaseWalkerLong (w, r); 1572c393a42Smrg if ('A' <= r && r <= 'Z') 1582c393a42Smrg r = r - 'A' + 'a'; 1592c393a42Smrg return r; 1602c393a42Smrg} 1612c393a42Smrg 1622c393a42SmrgFcChar8 * 1632c393a42SmrgFcStrDowncase (const FcChar8 *s) 1642c393a42Smrg{ 1652c393a42Smrg FcCaseWalker w; 1662c393a42Smrg int len = 0; 1672c393a42Smrg FcChar8 *dst, *d; 1682c393a42Smrg 1692c393a42Smrg FcStrCaseWalkerInit (s, &w); 170c9710b42Smrg while (FcStrCaseWalkerNext (&w, NULL)) 1712c393a42Smrg len++; 1722c393a42Smrg d = dst = malloc (len + 1); 1732c393a42Smrg if (!d) 1742c393a42Smrg return 0; 1752c393a42Smrg FcStrCaseWalkerInit (s, &w); 176c9710b42Smrg while ((*d++ = FcStrCaseWalkerNext (&w, NULL))); 1772c393a42Smrg return dst; 1782c393a42Smrg} 1792c393a42Smrg 1802c393a42Smrgint 1812c393a42SmrgFcStrCmpIgnoreCase (const FcChar8 *s1, const FcChar8 *s2) 1822c393a42Smrg{ 1832c393a42Smrg FcCaseWalker w1, w2; 1842c393a42Smrg FcChar8 c1, c2; 1852c393a42Smrg 1862c393a42Smrg if (s1 == s2) return 0; 187ca08ab68Smrg 1882c393a42Smrg FcStrCaseWalkerInit (s1, &w1); 1892c393a42Smrg FcStrCaseWalkerInit (s2, &w2); 190ca08ab68Smrg 191ca08ab68Smrg for (;;) 1922c393a42Smrg { 193c9710b42Smrg c1 = FcStrCaseWalkerNext (&w1, NULL); 194c9710b42Smrg c2 = FcStrCaseWalkerNext (&w2, NULL); 1952c393a42Smrg if (!c1 || (c1 != c2)) 1962c393a42Smrg break; 1972c393a42Smrg } 1982c393a42Smrg return (int) c1 - (int) c2; 1992c393a42Smrg} 2002c393a42Smrg 2012c393a42Smrgint 2022c393a42SmrgFcStrCmpIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2) 203c9710b42Smrg{ 204c9710b42Smrg return FcStrCmpIgnoreCaseAndDelims (s1, s2, (const FcChar8 *)" "); 205c9710b42Smrg} 206c9710b42Smrg 207c9710b42Smrgint 208c9710b42SmrgFcStrCmpIgnoreCaseAndDelims (const FcChar8 *s1, const FcChar8 *s2, const FcChar8 *delims) 2092c393a42Smrg{ 2102c393a42Smrg FcCaseWalker w1, w2; 2112c393a42Smrg FcChar8 c1, c2; 2122c393a42Smrg 2132c393a42Smrg if (s1 == s2) return 0; 214ca08ab68Smrg 2152c393a42Smrg FcStrCaseWalkerInit (s1, &w1); 2162c393a42Smrg FcStrCaseWalkerInit (s2, &w2); 217ca08ab68Smrg 218ca08ab68Smrg for (;;) 2192c393a42Smrg { 220c9710b42Smrg c1 = FcStrCaseWalkerNext (&w1, (const char *)delims); 221c9710b42Smrg c2 = FcStrCaseWalkerNext (&w2, (const char *)delims); 2222c393a42Smrg if (!c1 || (c1 != c2)) 2232c393a42Smrg break; 2242c393a42Smrg } 2252c393a42Smrg return (int) c1 - (int) c2; 2262c393a42Smrg} 2272c393a42Smrg 2282c393a42Smrgint 2292c393a42SmrgFcStrCmp (const FcChar8 *s1, const FcChar8 *s2) 2302c393a42Smrg{ 2312c393a42Smrg FcChar8 c1, c2; 232ca08ab68Smrg 2332c393a42Smrg if (s1 == s2) 2342c393a42Smrg return 0; 235ca08ab68Smrg for (;;) 2362c393a42Smrg { 2372c393a42Smrg c1 = *s1++; 2382c393a42Smrg c2 = *s2++; 2392c393a42Smrg if (!c1 || c1 != c2) 2402c393a42Smrg break; 2412c393a42Smrg } 2422c393a42Smrg return (int) c1 - (int) c2; 2432c393a42Smrg} 2442c393a42Smrg 245ca08ab68Smrg#ifdef USE_REGEX 246ca08ab68Smrgstatic FcBool 247ca08ab68Smrg_FcStrRegexCmp (const FcChar8 *s, const FcChar8 *regex, int cflags, int eflags) 248ca08ab68Smrg{ 249ca08ab68Smrg int ret = -1; 250ca08ab68Smrg regex_t reg; 251ca08ab68Smrg 252ca08ab68Smrg if ((ret = regcomp (®, (const char *)regex, cflags)) != 0) 253ca08ab68Smrg { 254ca08ab68Smrg if (FcDebug () & FC_DBG_MATCHV) 255ca08ab68Smrg { 256ca08ab68Smrg char buf[512]; 257ca08ab68Smrg 258ca08ab68Smrg regerror (ret, ®, buf, 512); 259ca08ab68Smrg printf("Regexp compile error: %s\n", buf); 260ca08ab68Smrg } 261ca08ab68Smrg return FcFalse; 262ca08ab68Smrg } 263ca08ab68Smrg ret = regexec (®, (const char *)s, 0, NULL, eflags); 264ca08ab68Smrg if (ret != 0) 265ca08ab68Smrg { 266ca08ab68Smrg if (FcDebug () & FC_DBG_MATCHV) 267ca08ab68Smrg { 268ca08ab68Smrg char buf[512]; 269ca08ab68Smrg 270ca08ab68Smrg regerror (ret, ®, buf, 512); 271ca08ab68Smrg printf("Regexp exec error: %s\n", buf); 272ca08ab68Smrg } 273ca08ab68Smrg } 274ca08ab68Smrg regfree (®); 275ca08ab68Smrg 276ca08ab68Smrg return ret == 0 ? FcTrue : FcFalse; 277ca08ab68Smrg} 278ca08ab68Smrg#else 279ca08ab68Smrg# define _FcStrRegexCmp(_s_, _regex_, _cflags_, _eflags_) (FcFalse) 280ca08ab68Smrg#endif 281ca08ab68Smrg 282ca08ab68SmrgFcBool 283ca08ab68SmrgFcStrRegexCmp (const FcChar8 *s, const FcChar8 *regex) 284ca08ab68Smrg{ 285ca08ab68Smrg return _FcStrRegexCmp (s, regex, REG_EXTENDED | REG_NOSUB, 0); 286ca08ab68Smrg} 287ca08ab68Smrg 288ca08ab68SmrgFcBool 289ca08ab68SmrgFcStrRegexCmpIgnoreCase (const FcChar8 *s, const FcChar8 *regex) 290ca08ab68Smrg{ 291ca08ab68Smrg return _FcStrRegexCmp (s, regex, REG_EXTENDED | REG_NOSUB | REG_ICASE, 0); 292ca08ab68Smrg} 293ca08ab68Smrg 2942c393a42Smrg/* 2952c393a42Smrg * Return a hash value for a string 2962c393a42Smrg */ 2972c393a42Smrg 2982c393a42SmrgFcChar32 2992c393a42SmrgFcStrHashIgnoreCase (const FcChar8 *s) 3002c393a42Smrg{ 3012c393a42Smrg FcChar32 h = 0; 3022c393a42Smrg FcCaseWalker w; 3032c393a42Smrg FcChar8 c; 3042c393a42Smrg 3052c393a42Smrg FcStrCaseWalkerInit (s, &w); 306c9710b42Smrg while ((c = FcStrCaseWalkerNext (&w, NULL))) 3072c393a42Smrg h = ((h << 3) ^ (h >> 3)) ^ c; 3082c393a42Smrg return h; 3092c393a42Smrg} 3102c393a42Smrg 3112c393a42Smrg/* 3122c393a42Smrg * Is the head of s1 equal to s2? 3132c393a42Smrg */ 3142c393a42Smrg 3152c393a42Smrgstatic FcBool 3162c393a42SmrgFcStrIsAtIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2) 3172c393a42Smrg{ 3182c393a42Smrg FcCaseWalker w1, w2; 3192c393a42Smrg FcChar8 c1, c2; 3202c393a42Smrg 3212c393a42Smrg FcStrCaseWalkerInit (s1, &w1); 3222c393a42Smrg FcStrCaseWalkerInit (s2, &w2); 323ca08ab68Smrg 324ca08ab68Smrg for (;;) 3252c393a42Smrg { 326c9710b42Smrg c1 = FcStrCaseWalkerNext (&w1, " "); 327c9710b42Smrg c2 = FcStrCaseWalkerNext (&w2, " "); 3282c393a42Smrg if (!c1 || (c1 != c2)) 3292c393a42Smrg break; 3302c393a42Smrg } 3312c393a42Smrg return c1 == c2 || !c2; 3322c393a42Smrg} 3332c393a42Smrg 3342c393a42Smrg/* 3352c393a42Smrg * Does s1 contain an instance of s2 (ignoring blanks and case)? 3362c393a42Smrg */ 3372c393a42Smrg 3382c393a42Smrgconst FcChar8 * 3392c393a42SmrgFcStrContainsIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2) 3402c393a42Smrg{ 3412c393a42Smrg while (*s1) 3422c393a42Smrg { 3432c393a42Smrg if (FcStrIsAtIgnoreBlanksAndCase (s1, s2)) 3442c393a42Smrg return s1; 3452c393a42Smrg s1++; 3462c393a42Smrg } 3472c393a42Smrg return 0; 3482c393a42Smrg} 3492c393a42Smrg 3502c393a42Smrgstatic FcBool 3512c393a42SmrgFcCharIsPunct (const FcChar8 c) 3522c393a42Smrg{ 3532c393a42Smrg if (c < '0') 3542c393a42Smrg return FcTrue; 3552c393a42Smrg if (c <= '9') 3562c393a42Smrg return FcFalse; 3572c393a42Smrg if (c < 'A') 3582c393a42Smrg return FcTrue; 3592c393a42Smrg if (c <= 'Z') 3602c393a42Smrg return FcFalse; 3612c393a42Smrg if (c < 'a') 3622c393a42Smrg return FcTrue; 3632c393a42Smrg if (c <= 'z') 3642c393a42Smrg return FcFalse; 3652c393a42Smrg if (c <= '~') 3662c393a42Smrg return FcTrue; 3672c393a42Smrg return FcFalse; 3682c393a42Smrg} 3692c393a42Smrg 3702c393a42Smrg/* 3712c393a42Smrg * Is the head of s1 equal to s2? 3722c393a42Smrg */ 3732c393a42Smrg 3742c393a42Smrgstatic FcBool 3752c393a42SmrgFcStrIsAtIgnoreCase (const FcChar8 *s1, const FcChar8 *s2) 3762c393a42Smrg{ 3772c393a42Smrg FcCaseWalker w1, w2; 3782c393a42Smrg FcChar8 c1, c2; 3792c393a42Smrg 3802c393a42Smrg FcStrCaseWalkerInit (s1, &w1); 3812c393a42Smrg FcStrCaseWalkerInit (s2, &w2); 382ca08ab68Smrg 383ca08ab68Smrg for (;;) 3842c393a42Smrg { 385c9710b42Smrg c1 = FcStrCaseWalkerNext (&w1, NULL); 386c9710b42Smrg c2 = FcStrCaseWalkerNext (&w2, NULL); 3872c393a42Smrg if (!c1 || (c1 != c2)) 3882c393a42Smrg break; 3892c393a42Smrg } 3902c393a42Smrg return c1 == c2 || !c2; 3912c393a42Smrg} 3922c393a42Smrg 3932c393a42Smrg/* 3942c393a42Smrg * Does s1 contain an instance of s2 (ignoring blanks and case)? 3952c393a42Smrg */ 3962c393a42Smrg 3972c393a42Smrgconst FcChar8 * 3982c393a42SmrgFcStrContainsIgnoreCase (const FcChar8 *s1, const FcChar8 *s2) 3992c393a42Smrg{ 4002c393a42Smrg while (*s1) 4012c393a42Smrg { 4022c393a42Smrg if (FcStrIsAtIgnoreCase (s1, s2)) 4032c393a42Smrg return s1; 4042c393a42Smrg s1++; 4052c393a42Smrg } 4062c393a42Smrg return 0; 4072c393a42Smrg} 4082c393a42Smrg 4092c393a42Smrg/* 4102c393a42Smrg * Does s1 contain an instance of s2 on a word boundary (ignoring case)? 4112c393a42Smrg */ 4122c393a42Smrg 4132c393a42Smrgconst FcChar8 * 4142c393a42SmrgFcStrContainsWord (const FcChar8 *s1, const FcChar8 *s2) 4152c393a42Smrg{ 4162c393a42Smrg FcBool wordStart = FcTrue; 4172c393a42Smrg int s1len = strlen ((char *) s1); 4182c393a42Smrg int s2len = strlen ((char *) s2); 4192c393a42Smrg 4202c393a42Smrg while (s1len >= s2len) 4212c393a42Smrg { 422ca08ab68Smrg if (wordStart && 4232c393a42Smrg FcStrIsAtIgnoreCase (s1, s2) && 4242c393a42Smrg (s1len == s2len || FcCharIsPunct (s1[s2len]))) 4252c393a42Smrg { 4262c393a42Smrg return s1; 4272c393a42Smrg } 4282c393a42Smrg wordStart = FcFalse; 4292c393a42Smrg if (FcCharIsPunct (*s1)) 4302c393a42Smrg wordStart = FcTrue; 4312c393a42Smrg s1++; 4322c393a42Smrg s1len--; 4332c393a42Smrg } 4342c393a42Smrg return 0; 4352c393a42Smrg} 4362c393a42Smrg 437c9710b42Smrg/* 438c9710b42Smrg * returns the number of strings (ignoring delimitors and case) being matched 439c9710b42Smrg */ 440c9710b42Smrg 441c9710b42Smrgint 442c9710b42SmrgFcStrMatchIgnoreCaseAndDelims (const FcChar8 *s1, const FcChar8 *s2, const FcChar8 *delims) 443c9710b42Smrg{ 444c9710b42Smrg FcCaseWalker w1, w2; 445c9710b42Smrg FcChar8 c1, c2; 446c9710b42Smrg 447c9710b42Smrg if (s1 == s2) return 0; 448c9710b42Smrg 449c9710b42Smrg FcStrCaseWalkerInit (s1, &w1); 450c9710b42Smrg FcStrCaseWalkerInit (s2, &w2); 451c9710b42Smrg 452c9710b42Smrg for (;;) 453c9710b42Smrg { 454c9710b42Smrg c1 = FcStrCaseWalkerNext (&w1, (const char *)delims); 455c9710b42Smrg c2 = FcStrCaseWalkerNext (&w2, (const char *)delims); 456c9710b42Smrg if (!c1 || (c1 != c2)) 457c9710b42Smrg break; 458c9710b42Smrg } 459c9710b42Smrg return w1.src - s1 - 1; 460c9710b42Smrg} 461c9710b42Smrg 462c9710b42SmrgFcBool 463c9710b42SmrgFcStrGlobMatch (const FcChar8 *glob, 464c9710b42Smrg const FcChar8 *string) 465c9710b42Smrg{ 466c9710b42Smrg FcChar8 c; 467c9710b42Smrg 468c9710b42Smrg while ((c = *glob++)) 469c9710b42Smrg { 470c9710b42Smrg switch (c) { 471c9710b42Smrg case '*': 472c9710b42Smrg /* short circuit common case */ 473c9710b42Smrg if (!*glob) 474c9710b42Smrg return FcTrue; 475c9710b42Smrg /* short circuit another common case */ 476c9710b42Smrg if (strchr ((char *) glob, '*') == 0) 477c9710b42Smrg { 478c9710b42Smrg size_t l1, l2; 479c9710b42Smrg 480c9710b42Smrg l1 = strlen ((char *) string); 481c9710b42Smrg l2 = strlen ((char *) glob); 482c9710b42Smrg if (l1 < l2) 483c9710b42Smrg return FcFalse; 484c9710b42Smrg string += (l1 - l2); 485c9710b42Smrg } 486c9710b42Smrg while (*string) 487c9710b42Smrg { 488c9710b42Smrg if (FcStrGlobMatch (glob, string)) 489c9710b42Smrg return FcTrue; 490c9710b42Smrg string++; 491c9710b42Smrg } 492c9710b42Smrg return FcFalse; 493c9710b42Smrg case '?': 494c9710b42Smrg if (*string++ == '\0') 495c9710b42Smrg return FcFalse; 496c9710b42Smrg break; 497c9710b42Smrg default: 498c9710b42Smrg if (*string++ != c) 499c9710b42Smrg return FcFalse; 500c9710b42Smrg break; 501c9710b42Smrg } 502c9710b42Smrg } 503c9710b42Smrg return *string == '\0'; 504c9710b42Smrg} 505c9710b42Smrg 5062c393a42Smrgconst FcChar8 * 5072c393a42SmrgFcStrStrIgnoreCase (const FcChar8 *s1, const FcChar8 *s2) 5082c393a42Smrg{ 5092c393a42Smrg FcCaseWalker w1, w2; 5102c393a42Smrg FcChar8 c1, c2; 5112c393a42Smrg const FcChar8 *cur; 5122c393a42Smrg 5132c393a42Smrg if (!s1 || !s2) 5142c393a42Smrg return 0; 5152c393a42Smrg 5162c393a42Smrg if (s1 == s2) 5172c393a42Smrg return s1; 518ca08ab68Smrg 5192c393a42Smrg FcStrCaseWalkerInit (s1, &w1); 5202c393a42Smrg FcStrCaseWalkerInit (s2, &w2); 521ca08ab68Smrg 522c9710b42Smrg c2 = FcStrCaseWalkerNext (&w2, NULL); 523ca08ab68Smrg 5242c393a42Smrg for (;;) 5252c393a42Smrg { 5262c393a42Smrg cur = w1.src; 527c9710b42Smrg c1 = FcStrCaseWalkerNext (&w1, NULL); 5282c393a42Smrg if (!c1) 5292c393a42Smrg break; 5302c393a42Smrg if (c1 == c2) 5312c393a42Smrg { 5322c393a42Smrg FcCaseWalker w1t = w1; 5332c393a42Smrg FcCaseWalker w2t = w2; 5342c393a42Smrg FcChar8 c1t, c2t; 5352c393a42Smrg 5362c393a42Smrg for (;;) 5372c393a42Smrg { 538c9710b42Smrg c1t = FcStrCaseWalkerNext (&w1t, NULL); 539c9710b42Smrg c2t = FcStrCaseWalkerNext (&w2t, NULL); 5402c393a42Smrg 5412c393a42Smrg if (!c2t) 5422c393a42Smrg return cur; 5432c393a42Smrg if (c2t != c1t) 5442c393a42Smrg break; 5452c393a42Smrg } 5462c393a42Smrg } 5472c393a42Smrg } 5482c393a42Smrg return 0; 5492c393a42Smrg} 5502c393a42Smrg 5512c393a42Smrgconst FcChar8 * 5522c393a42SmrgFcStrStr (const FcChar8 *s1, const FcChar8 *s2) 5532c393a42Smrg{ 5542c393a42Smrg FcChar8 c1, c2; 5552c393a42Smrg const FcChar8 * p = s1; 5562c393a42Smrg const FcChar8 * b = s2; 5572c393a42Smrg 5582c393a42Smrg if (!s1 || !s2) 5592c393a42Smrg return 0; 5602c393a42Smrg 5612c393a42Smrg if (s1 == s2) 5622c393a42Smrg return s1; 5632c393a42Smrg 5642c393a42Smrgagain: 5652c393a42Smrg c2 = *s2++; 5662c393a42Smrg 5672c393a42Smrg if (!c2) 5682c393a42Smrg return 0; 5692c393a42Smrg 570ca08ab68Smrg for (;;) 5712c393a42Smrg { 5722c393a42Smrg p = s1; 5732c393a42Smrg c1 = *s1++; 5742c393a42Smrg if (!c1 || c1 == c2) 5752c393a42Smrg break; 5762c393a42Smrg } 5772c393a42Smrg 5782c393a42Smrg if (c1 != c2) 5792c393a42Smrg return 0; 5802c393a42Smrg 5812c393a42Smrg for (;;) 5822c393a42Smrg { 5832c393a42Smrg c1 = *s1; 5842c393a42Smrg c2 = *s2; 5852c393a42Smrg if (c1 && c2 && c1 != c2) 5862c393a42Smrg { 5872c393a42Smrg s1 = p + 1; 5882c393a42Smrg s2 = b; 5892c393a42Smrg goto again; 5902c393a42Smrg } 5912c393a42Smrg if (!c2) 5922c393a42Smrg return p; 5932c393a42Smrg if (!c1) 5942c393a42Smrg return 0; 5952c393a42Smrg ++ s1; 5962c393a42Smrg ++ s2; 5972c393a42Smrg } 5982c393a42Smrg /* never reached. */ 5992c393a42Smrg} 6002c393a42Smrg 6012c393a42Smrgint 6022c393a42SmrgFcUtf8ToUcs4 (const FcChar8 *src_orig, 6032c393a42Smrg FcChar32 *dst, 6042c393a42Smrg int len) 6052c393a42Smrg{ 6062c393a42Smrg const FcChar8 *src = src_orig; 6072c393a42Smrg FcChar8 s; 6082c393a42Smrg int extra; 6092c393a42Smrg FcChar32 result; 6102c393a42Smrg 6112c393a42Smrg if (len == 0) 6122c393a42Smrg return 0; 613ca08ab68Smrg 6142c393a42Smrg s = *src++; 6152c393a42Smrg len--; 616ca08ab68Smrg 6172c393a42Smrg if (!(s & 0x80)) 6182c393a42Smrg { 6192c393a42Smrg result = s; 6202c393a42Smrg extra = 0; 621ca08ab68Smrg } 6222c393a42Smrg else if (!(s & 0x40)) 6232c393a42Smrg { 6242c393a42Smrg return -1; 6252c393a42Smrg } 6262c393a42Smrg else if (!(s & 0x20)) 6272c393a42Smrg { 6282c393a42Smrg result = s & 0x1f; 6292c393a42Smrg extra = 1; 6302c393a42Smrg } 6312c393a42Smrg else if (!(s & 0x10)) 6322c393a42Smrg { 6332c393a42Smrg result = s & 0xf; 6342c393a42Smrg extra = 2; 6352c393a42Smrg } 6362c393a42Smrg else if (!(s & 0x08)) 6372c393a42Smrg { 6382c393a42Smrg result = s & 0x07; 6392c393a42Smrg extra = 3; 6402c393a42Smrg } 6412c393a42Smrg else if (!(s & 0x04)) 6422c393a42Smrg { 6432c393a42Smrg result = s & 0x03; 6442c393a42Smrg extra = 4; 6452c393a42Smrg } 6462c393a42Smrg else if ( ! (s & 0x02)) 6472c393a42Smrg { 6482c393a42Smrg result = s & 0x01; 6492c393a42Smrg extra = 5; 6502c393a42Smrg } 6512c393a42Smrg else 6522c393a42Smrg { 6532c393a42Smrg return -1; 6542c393a42Smrg } 6552c393a42Smrg if (extra > len) 6562c393a42Smrg return -1; 657ca08ab68Smrg 6582c393a42Smrg while (extra--) 6592c393a42Smrg { 6602c393a42Smrg result <<= 6; 6612c393a42Smrg s = *src++; 6622c393a42Smrg 6632c393a42Smrg if ((s & 0xc0) != 0x80) 6642c393a42Smrg return -1; 6652c393a42Smrg 6662c393a42Smrg result |= s & 0x3f; 6672c393a42Smrg } 6682c393a42Smrg *dst = result; 6692c393a42Smrg return src - src_orig; 6702c393a42Smrg} 6712c393a42Smrg 6722c393a42SmrgFcBool 6732c393a42SmrgFcUtf8Len (const FcChar8 *string, 6742c393a42Smrg int len, 6752c393a42Smrg int *nchar, 6762c393a42Smrg int *wchar) 6772c393a42Smrg{ 6782c393a42Smrg int n; 6792c393a42Smrg int clen; 6802c393a42Smrg FcChar32 c; 6812c393a42Smrg FcChar32 max; 682ca08ab68Smrg 6832c393a42Smrg n = 0; 6842c393a42Smrg max = 0; 6852c393a42Smrg while (len) 6862c393a42Smrg { 6872c393a42Smrg clen = FcUtf8ToUcs4 (string, &c, len); 6882c393a42Smrg if (clen <= 0) /* malformed UTF8 string */ 6892c393a42Smrg return FcFalse; 6902c393a42Smrg if (c > max) 6912c393a42Smrg max = c; 6922c393a42Smrg string += clen; 6932c393a42Smrg len -= clen; 6942c393a42Smrg n++; 6952c393a42Smrg } 6962c393a42Smrg *nchar = n; 6972c393a42Smrg if (max >= 0x10000) 6982c393a42Smrg *wchar = 4; 6992c393a42Smrg else if (max > 0x100) 7002c393a42Smrg *wchar = 2; 7012c393a42Smrg else 7022c393a42Smrg *wchar = 1; 7032c393a42Smrg return FcTrue; 7042c393a42Smrg} 7052c393a42Smrg 7062c393a42Smrgint 7072c393a42SmrgFcUcs4ToUtf8 (FcChar32 ucs4, 7082c393a42Smrg FcChar8 dest[FC_UTF8_MAX_LEN]) 7092c393a42Smrg{ 7102c393a42Smrg int bits; 7112c393a42Smrg FcChar8 *d = dest; 712ca08ab68Smrg 7132c393a42Smrg if (ucs4 < 0x80) { *d++= ucs4; bits= -6; } 7142c393a42Smrg else if (ucs4 < 0x800) { *d++= ((ucs4 >> 6) & 0x1F) | 0xC0; bits= 0; } 7152c393a42Smrg else if (ucs4 < 0x10000) { *d++= ((ucs4 >> 12) & 0x0F) | 0xE0; bits= 6; } 7162c393a42Smrg else if (ucs4 < 0x200000) { *d++= ((ucs4 >> 18) & 0x07) | 0xF0; bits= 12; } 7172c393a42Smrg else if (ucs4 < 0x4000000) { *d++= ((ucs4 >> 24) & 0x03) | 0xF8; bits= 18; } 7182c393a42Smrg else if (ucs4 < 0x80000000) { *d++= ((ucs4 >> 30) & 0x01) | 0xFC; bits= 24; } 7192c393a42Smrg else return 0; 7202c393a42Smrg 7212c393a42Smrg for ( ; bits >= 0; bits-= 6) { 7222c393a42Smrg *d++= ((ucs4 >> bits) & 0x3F) | 0x80; 7232c393a42Smrg } 7242c393a42Smrg return d - dest; 7252c393a42Smrg} 7262c393a42Smrg 7272c393a42Smrg#define GetUtf16(src,endian) \ 7282c393a42Smrg ((FcChar16) ((src)[endian == FcEndianBig ? 0 : 1] << 8) | \ 7292c393a42Smrg (FcChar16) ((src)[endian == FcEndianBig ? 1 : 0])) 7302c393a42Smrg 7312c393a42Smrgint 7322c393a42SmrgFcUtf16ToUcs4 (const FcChar8 *src_orig, 7332c393a42Smrg FcEndian endian, 7342c393a42Smrg FcChar32 *dst, 7352c393a42Smrg int len) /* in bytes */ 7362c393a42Smrg{ 7372c393a42Smrg const FcChar8 *src = src_orig; 7382c393a42Smrg FcChar16 a, b; 7392c393a42Smrg FcChar32 result; 7402c393a42Smrg 7412c393a42Smrg if (len < 2) 7422c393a42Smrg return 0; 743ca08ab68Smrg 7442c393a42Smrg a = GetUtf16 (src, endian); src += 2; len -= 2; 745ca08ab68Smrg 746ca08ab68Smrg /* 747ca08ab68Smrg * Check for surrogate 7482c393a42Smrg */ 7492c393a42Smrg if ((a & 0xfc00) == 0xd800) 7502c393a42Smrg { 7512c393a42Smrg if (len < 2) 7522c393a42Smrg return 0; 7532c393a42Smrg b = GetUtf16 (src, endian); src += 2; len -= 2; 7542c393a42Smrg /* 7552c393a42Smrg * Check for invalid surrogate sequence 7562c393a42Smrg */ 7572c393a42Smrg if ((b & 0xfc00) != 0xdc00) 7582c393a42Smrg return 0; 7592c393a42Smrg result = ((((FcChar32) a & 0x3ff) << 10) | 7602c393a42Smrg ((FcChar32) b & 0x3ff)) + 0x10000; 7612c393a42Smrg } 7622c393a42Smrg else 7632c393a42Smrg result = a; 7642c393a42Smrg *dst = result; 7652c393a42Smrg return src - src_orig; 7662c393a42Smrg} 7672c393a42Smrg 7682c393a42SmrgFcBool 7692c393a42SmrgFcUtf16Len (const FcChar8 *string, 7702c393a42Smrg FcEndian endian, 7712c393a42Smrg int len, /* in bytes */ 7722c393a42Smrg int *nchar, 7732c393a42Smrg int *wchar) 7742c393a42Smrg{ 7752c393a42Smrg int n; 7762c393a42Smrg int clen; 7772c393a42Smrg FcChar32 c; 7782c393a42Smrg FcChar32 max; 779ca08ab68Smrg 7802c393a42Smrg n = 0; 7812c393a42Smrg max = 0; 7822c393a42Smrg while (len) 7832c393a42Smrg { 7842c393a42Smrg clen = FcUtf16ToUcs4 (string, endian, &c, len); 7852c393a42Smrg if (clen <= 0) /* malformed UTF8 string */ 7862c393a42Smrg return FcFalse; 7872c393a42Smrg if (c > max) 7882c393a42Smrg max = c; 7892c393a42Smrg string += clen; 7902c393a42Smrg len -= clen; 7912c393a42Smrg n++; 7922c393a42Smrg } 7932c393a42Smrg *nchar = n; 7942c393a42Smrg if (max >= 0x10000) 7952c393a42Smrg *wchar = 4; 7962c393a42Smrg else if (max > 0x100) 7972c393a42Smrg *wchar = 2; 7982c393a42Smrg else 7992c393a42Smrg *wchar = 1; 8002c393a42Smrg return FcTrue; 8012c393a42Smrg} 8022c393a42Smrg 8032c393a42Smrgvoid 8042c393a42SmrgFcStrBufInit (FcStrBuf *buf, FcChar8 *init, int size) 8052c393a42Smrg{ 806a6844aabSmrg if (init) 807a6844aabSmrg { 808a6844aabSmrg buf->buf = init; 809a6844aabSmrg buf->size = size; 810a6844aabSmrg } else 811a6844aabSmrg { 812a6844aabSmrg buf->buf = buf->buf_static; 813a6844aabSmrg buf->size = sizeof (buf->buf_static); 814a6844aabSmrg } 8152c393a42Smrg buf->allocated = FcFalse; 8162c393a42Smrg buf->failed = FcFalse; 8172c393a42Smrg buf->len = 0; 8182c393a42Smrg} 8192c393a42Smrg 8202c393a42Smrgvoid 8212c393a42SmrgFcStrBufDestroy (FcStrBuf *buf) 8222c393a42Smrg{ 8232c393a42Smrg if (buf->allocated) 8242c393a42Smrg { 8252c393a42Smrg free (buf->buf); 8262c393a42Smrg FcStrBufInit (buf, 0, 0); 8272c393a42Smrg } 8282c393a42Smrg} 8292c393a42Smrg 8302c393a42SmrgFcChar8 * 8312c393a42SmrgFcStrBufDone (FcStrBuf *buf) 8322c393a42Smrg{ 8332c393a42Smrg FcChar8 *ret; 8342c393a42Smrg 835a6844aabSmrg if (buf->failed) 836a6844aabSmrg ret = NULL; 837a6844aabSmrg else 838a6844aabSmrg ret = malloc (buf->len + 1); 8392c393a42Smrg if (ret) 8402c393a42Smrg { 8412c393a42Smrg memcpy (ret, buf->buf, buf->len); 8422c393a42Smrg ret[buf->len] = '\0'; 8432c393a42Smrg } 8442c393a42Smrg FcStrBufDestroy (buf); 8452c393a42Smrg return ret; 8462c393a42Smrg} 8472c393a42Smrg 848a6844aabSmrgFcChar8 * 849a6844aabSmrgFcStrBufDoneStatic (FcStrBuf *buf) 850a6844aabSmrg{ 851a6844aabSmrg FcStrBufChar (buf, '\0'); 852a6844aabSmrg 853a6844aabSmrg if (buf->failed) 854a6844aabSmrg return NULL; 855a6844aabSmrg 856a6844aabSmrg return buf->buf; 857a6844aabSmrg} 858a6844aabSmrg 8592c393a42SmrgFcBool 8602c393a42SmrgFcStrBufChar (FcStrBuf *buf, FcChar8 c) 8612c393a42Smrg{ 8622c393a42Smrg if (buf->len == buf->size) 8632c393a42Smrg { 8642c393a42Smrg FcChar8 *new; 8652c393a42Smrg int size; 8662c393a42Smrg 867a6844aabSmrg if (buf->failed) 868a6844aabSmrg return FcFalse; 869a6844aabSmrg 8702c393a42Smrg if (buf->allocated) 8712c393a42Smrg { 8722c393a42Smrg size = buf->size * 2; 8732c393a42Smrg new = realloc (buf->buf, size); 8742c393a42Smrg } 8752c393a42Smrg else 8762c393a42Smrg { 8772c393a42Smrg size = buf->size + 64; 8782c393a42Smrg new = malloc (size); 8792c393a42Smrg if (new) 8802c393a42Smrg { 8812c393a42Smrg buf->allocated = FcTrue; 8822c393a42Smrg memcpy (new, buf->buf, buf->len); 8832c393a42Smrg } 8842c393a42Smrg } 8852c393a42Smrg if (!new) 8862c393a42Smrg { 8872c393a42Smrg buf->failed = FcTrue; 8882c393a42Smrg return FcFalse; 8892c393a42Smrg } 8902c393a42Smrg buf->size = size; 8912c393a42Smrg buf->buf = new; 8922c393a42Smrg } 8932c393a42Smrg buf->buf[buf->len++] = c; 8942c393a42Smrg return FcTrue; 8952c393a42Smrg} 8962c393a42Smrg 8972c393a42SmrgFcBool 8982c393a42SmrgFcStrBufString (FcStrBuf *buf, const FcChar8 *s) 8992c393a42Smrg{ 9002c393a42Smrg FcChar8 c; 9012c393a42Smrg while ((c = *s++)) 9022c393a42Smrg if (!FcStrBufChar (buf, c)) 9032c393a42Smrg return FcFalse; 9042c393a42Smrg return FcTrue; 9052c393a42Smrg} 9062c393a42Smrg 9072c393a42SmrgFcBool 9082c393a42SmrgFcStrBufData (FcStrBuf *buf, const FcChar8 *s, int len) 9092c393a42Smrg{ 9102c393a42Smrg while (len-- > 0) 9112c393a42Smrg if (!FcStrBufChar (buf, *s++)) 9122c393a42Smrg return FcFalse; 9132c393a42Smrg return FcTrue; 9142c393a42Smrg} 9152c393a42Smrg 9162c393a42SmrgFcBool 9172c393a42SmrgFcStrUsesHome (const FcChar8 *s) 9182c393a42Smrg{ 9192c393a42Smrg return *s == '~'; 9202c393a42Smrg} 9212c393a42Smrg 922c9710b42SmrgFcChar8 * 923c9710b42SmrgFcStrBuildFilename (const FcChar8 *path, 924c9710b42Smrg ...) 925c9710b42Smrg{ 926c9710b42Smrg va_list ap; 927c9710b42Smrg FcStrSet *sset = FcStrSetCreate (); 928c9710b42Smrg FcStrList *list; 929c9710b42Smrg FcChar8 *s, *ret = NULL, *p; 930c9710b42Smrg size_t len = 0; 931c9710b42Smrg 932c9710b42Smrg if (!sset || !path) 933c9710b42Smrg return NULL; 934c9710b42Smrg 935c9710b42Smrg if (!FcStrSetAdd (sset, path)) 936c9710b42Smrg goto bail0; 937c9710b42Smrg 938c9710b42Smrg va_start (ap, path); 939c9710b42Smrg while (1) 940c9710b42Smrg { 941c9710b42Smrg s = (FcChar8 *)va_arg (ap, FcChar8 *); 942c9710b42Smrg if (!s) 943c9710b42Smrg break; 944c9710b42Smrg if (!FcStrSetAdd (sset, s)) 945c9710b42Smrg goto bail1; 946c9710b42Smrg } 947c9710b42Smrg list = FcStrListCreate (sset); 948c9710b42Smrg while ((s = FcStrListNext (list))) 949c9710b42Smrg { 950c9710b42Smrg len += strlen ((const char *)s) + 1; 951c9710b42Smrg } 952c9710b42Smrg list->n = 0; 953c9710b42Smrg ret = malloc (sizeof (FcChar8) * (len + 1)); 954c9710b42Smrg if (!ret) 955c9710b42Smrg goto bail2; 956c9710b42Smrg p = ret; 957c9710b42Smrg while ((s = FcStrListNext (list))) 958c9710b42Smrg { 959c9710b42Smrg if (p != ret) 960c9710b42Smrg { 961c9710b42Smrg p[0] = FC_DIR_SEPARATOR; 962c9710b42Smrg p++; 963c9710b42Smrg } 964c9710b42Smrg len = strlen ((const char *)s); 965c9710b42Smrg memcpy (p, s, len); 966c9710b42Smrg p += len; 967c9710b42Smrg } 968c9710b42Smrg *p = 0; 969c9710b42Smrg 970c9710b42Smrgbail2: 971c9710b42Smrg FcStrListDone (list); 972c9710b42Smrgbail1: 973c9710b42Smrg va_end (ap); 974c9710b42Smrgbail0: 975c9710b42Smrg FcStrSetDestroy (sset); 976c9710b42Smrg 977c9710b42Smrg return ret; 978c9710b42Smrg} 979c9710b42Smrg 9802c393a42SmrgFcChar8 * 9812c393a42SmrgFcStrCopyFilename (const FcChar8 *s) 9822c393a42Smrg{ 9832c393a42Smrg FcChar8 *new; 984ca08ab68Smrg 9852c393a42Smrg if (*s == '~') 9862c393a42Smrg { 9872c393a42Smrg FcChar8 *home = FcConfigHome (); 9882c393a42Smrg FcChar8 *full; 9892c393a42Smrg int size; 9902c393a42Smrg if (!home) 991ca08ab68Smrg return NULL; 9922c393a42Smrg size = strlen ((char *) home) + strlen ((char *) s); 9932c393a42Smrg full = (FcChar8 *) malloc (size); 9942c393a42Smrg if (!full) 995ca08ab68Smrg return NULL; 9962c393a42Smrg strcpy ((char *) full, (char *) home); 9972c393a42Smrg strcat ((char *) full, (char *) s + 1); 9982c393a42Smrg new = FcStrCanonFilename (full); 9992c393a42Smrg free (full); 10002c393a42Smrg } 10012c393a42Smrg else 10022c393a42Smrg new = FcStrCanonFilename (s); 1003ca08ab68Smrg 10042c393a42Smrg return new; 10052c393a42Smrg} 10062c393a42Smrg 10072c393a42SmrgFcChar8 * 10082c393a42SmrgFcStrLastSlash (const FcChar8 *path) 10092c393a42Smrg{ 10102c393a42Smrg FcChar8 *slash; 10112c393a42Smrg 10122c393a42Smrg slash = (FcChar8 *) strrchr ((const char *) path, '/'); 10132c393a42Smrg#ifdef _WIN32 10142c393a42Smrg { 10152c393a42Smrg FcChar8 *backslash; 10162c393a42Smrg 10172c393a42Smrg backslash = (FcChar8 *) strrchr ((const char *) path, '\\'); 10182c393a42Smrg if (!slash || (backslash && backslash > slash)) 10192c393a42Smrg slash = backslash; 10202c393a42Smrg } 10212c393a42Smrg#endif 10222c393a42Smrg 10232c393a42Smrg return slash; 10242c393a42Smrg} 1025ca08ab68Smrg 10262c393a42SmrgFcChar8 * 10272c393a42SmrgFcStrDirname (const FcChar8 *file) 10282c393a42Smrg{ 10292c393a42Smrg FcChar8 *slash; 10302c393a42Smrg FcChar8 *dir; 10312c393a42Smrg 10322c393a42Smrg slash = FcStrLastSlash (file); 10332c393a42Smrg if (!slash) 10342c393a42Smrg return FcStrCopy ((FcChar8 *) "."); 10352c393a42Smrg dir = malloc ((slash - file) + 1); 10362c393a42Smrg if (!dir) 10372c393a42Smrg return 0; 10382c393a42Smrg strncpy ((char *) dir, (const char *) file, slash - file); 10392c393a42Smrg dir[slash - file] = '\0'; 10402c393a42Smrg return dir; 10412c393a42Smrg} 10422c393a42Smrg 10432c393a42SmrgFcChar8 * 10442c393a42SmrgFcStrBasename (const FcChar8 *file) 10452c393a42Smrg{ 10462c393a42Smrg FcChar8 *slash; 10472c393a42Smrg 10482c393a42Smrg slash = FcStrLastSlash (file); 10492c393a42Smrg if (!slash) 10502c393a42Smrg return FcStrCopy (file); 10512c393a42Smrg return FcStrCopy (slash + 1); 10522c393a42Smrg} 10532c393a42Smrg 10542c393a42Smrgstatic FcChar8 * 10552c393a42SmrgFcStrCanonAbsoluteFilename (const FcChar8 *s) 10562c393a42Smrg{ 10572c393a42Smrg FcChar8 *file; 10582c393a42Smrg FcChar8 *f; 10592c393a42Smrg const FcChar8 *slash; 10602c393a42Smrg int size; 10612c393a42Smrg 10622c393a42Smrg size = strlen ((char *) s) + 1; 10632c393a42Smrg file = malloc (size); 10642c393a42Smrg if (!file) 10652c393a42Smrg return NULL; 10662c393a42Smrg slash = NULL; 10672c393a42Smrg f = file; 1068ca08ab68Smrg#ifdef _WIN32 1069ca08ab68Smrg if (*s == '/' && *(s+1) == '/') /* Network path, do not squash // */ 1070ca08ab68Smrg *f++ = *s++; 1071ca08ab68Smrg#endif 10722c393a42Smrg for (;;) { 10732c393a42Smrg if (*s == '/' || *s == '\0') 10742c393a42Smrg { 10752c393a42Smrg if (slash) 10762c393a42Smrg { 10772c393a42Smrg switch (s - slash) { 1078a6844aabSmrg case 1: 1079a6844aabSmrg f -= 1; /* squash // and trim final / from file */ 1080a6844aabSmrg break; 10812c393a42Smrg case 2: 10822c393a42Smrg if (!strncmp ((char *) slash, "/.", 2)) 10832c393a42Smrg { 10842c393a42Smrg f -= 2; /* trim /. from file */ 10852c393a42Smrg } 10862c393a42Smrg break; 10872c393a42Smrg case 3: 10882c393a42Smrg if (!strncmp ((char *) slash, "/..", 3)) 10892c393a42Smrg { 10902c393a42Smrg f -= 3; /* trim /.. from file */ 10912c393a42Smrg while (f > file) { 10922c393a42Smrg if (*--f == '/') 10932c393a42Smrg break; 10942c393a42Smrg } 10952c393a42Smrg } 10962c393a42Smrg break; 10972c393a42Smrg } 10982c393a42Smrg } 10992c393a42Smrg slash = s; 11002c393a42Smrg } 11012c393a42Smrg if (!(*f++ = *s++)) 11022c393a42Smrg break; 11032c393a42Smrg } 11042c393a42Smrg return file; 11052c393a42Smrg} 1106ca08ab68Smrg 11072c393a42Smrg#ifdef _WIN32 11082c393a42Smrg/* 1109ca08ab68Smrg * Convert '\\' to '/' , remove double '/' 11102c393a42Smrg */ 11112c393a42Smrgstatic void 11122c393a42SmrgFcConvertDosPath (char *str) 11132c393a42Smrg{ 11142c393a42Smrg size_t len = strlen (str); 11152c393a42Smrg char *p = str; 11162c393a42Smrg char *dest = str; 11172c393a42Smrg char *end = str + len; 11182c393a42Smrg char last = 0; 1119a6844aabSmrg 1120a6844aabSmrg if (*p == '\\') 1121a6844aabSmrg { 1122a6844aabSmrg *p = '/'; 1123a6844aabSmrg p++; 1124a6844aabSmrg dest++; 1125a6844aabSmrg } 11262c393a42Smrg while (p < end) 11272c393a42Smrg { 11282c393a42Smrg if (*p == '\\') 11292c393a42Smrg *p = '/'; 11302c393a42Smrg 11312c393a42Smrg if (*p != '/' 11322c393a42Smrg || last != '/') 11332c393a42Smrg { 11342c393a42Smrg *dest++ = *p; 11352c393a42Smrg } 11362c393a42Smrg 11372c393a42Smrg last = *p; 11382c393a42Smrg p++; 11392c393a42Smrg } 11402c393a42Smrg 11412c393a42Smrg *dest = 0; 11422c393a42Smrg} 11432c393a42Smrg#endif 11442c393a42Smrg 11452c393a42SmrgFcChar8 * 11462c393a42SmrgFcStrCanonFilename (const FcChar8 *s) 11472c393a42Smrg{ 11482c393a42Smrg#ifdef _WIN32 11492c393a42Smrg FcChar8 full[FC_MAX_FILE_LEN + 2]; 1150ca08ab68Smrg int size = GetFullPathName ((LPCSTR) s, sizeof (full) -1, 1151ca08ab68Smrg (LPSTR) full, NULL); 11522c393a42Smrg 11532c393a42Smrg if (size == 0) 11542c393a42Smrg perror ("GetFullPathName"); 11552c393a42Smrg 1156ca08ab68Smrg FcConvertDosPath ((char *) full); 11572c393a42Smrg return FcStrCanonAbsoluteFilename (full); 11582c393a42Smrg#else 11592c393a42Smrg if (s[0] == '/') 11602c393a42Smrg return FcStrCanonAbsoluteFilename (s); 11612c393a42Smrg else 11622c393a42Smrg { 11632c393a42Smrg FcChar8 *full; 11642c393a42Smrg FcChar8 *file; 11652c393a42Smrg 11662c393a42Smrg FcChar8 cwd[FC_MAX_FILE_LEN + 2]; 11672c393a42Smrg if (getcwd ((char *) cwd, FC_MAX_FILE_LEN) == NULL) 11682c393a42Smrg return NULL; 1169c9710b42Smrg full = FcStrBuildFilename (cwd, s, NULL); 11702c393a42Smrg file = FcStrCanonAbsoluteFilename (full); 11712c393a42Smrg FcStrFree (full); 11722c393a42Smrg return file; 11732c393a42Smrg } 11742c393a42Smrg#endif 11752c393a42Smrg} 11762c393a42Smrg 11772c393a42Smrg 11782c393a42SmrgFcStrSet * 11792c393a42SmrgFcStrSetCreate (void) 11802c393a42Smrg{ 11812c393a42Smrg FcStrSet *set = malloc (sizeof (FcStrSet)); 11822c393a42Smrg if (!set) 11832c393a42Smrg return 0; 1184c9710b42Smrg FcRefInit (&set->ref, 1); 11852c393a42Smrg set->num = 0; 11862c393a42Smrg set->size = 0; 11872c393a42Smrg set->strs = 0; 11882c393a42Smrg return set; 11892c393a42Smrg} 11902c393a42Smrg 11912c393a42Smrgstatic FcBool 11922c393a42Smrg_FcStrSetAppend (FcStrSet *set, FcChar8 *s) 11932c393a42Smrg{ 11942c393a42Smrg if (FcStrSetMember (set, s)) 11952c393a42Smrg { 11962c393a42Smrg FcStrFree (s); 11972c393a42Smrg return FcTrue; 11982c393a42Smrg } 11992c393a42Smrg if (set->num == set->size) 12002c393a42Smrg { 12012c393a42Smrg FcChar8 **strs = malloc ((set->size + 2) * sizeof (FcChar8 *)); 12022c393a42Smrg 12032c393a42Smrg if (!strs) 12042c393a42Smrg return FcFalse; 12052c393a42Smrg if (set->num) 12062c393a42Smrg memcpy (strs, set->strs, set->num * sizeof (FcChar8 *)); 12072c393a42Smrg if (set->strs) 12082c393a42Smrg free (set->strs); 12092c393a42Smrg set->size = set->size + 1; 12102c393a42Smrg set->strs = strs; 12112c393a42Smrg } 12122c393a42Smrg set->strs[set->num++] = s; 12132c393a42Smrg set->strs[set->num] = 0; 12142c393a42Smrg return FcTrue; 12152c393a42Smrg} 12162c393a42Smrg 12172c393a42SmrgFcBool 12182c393a42SmrgFcStrSetMember (FcStrSet *set, const FcChar8 *s) 12192c393a42Smrg{ 12202c393a42Smrg int i; 12212c393a42Smrg 12222c393a42Smrg for (i = 0; i < set->num; i++) 12232c393a42Smrg if (!FcStrCmp (set->strs[i], s)) 12242c393a42Smrg return FcTrue; 12252c393a42Smrg return FcFalse; 12262c393a42Smrg} 12272c393a42Smrg 12282c393a42SmrgFcBool 12292c393a42SmrgFcStrSetEqual (FcStrSet *sa, FcStrSet *sb) 12302c393a42Smrg{ 12312c393a42Smrg int i; 12322c393a42Smrg if (sa->num != sb->num) 12332c393a42Smrg return FcFalse; 12342c393a42Smrg for (i = 0; i < sa->num; i++) 12352c393a42Smrg if (!FcStrSetMember (sb, sa->strs[i])) 12362c393a42Smrg return FcFalse; 12372c393a42Smrg return FcTrue; 12382c393a42Smrg} 12392c393a42Smrg 12402c393a42SmrgFcBool 12412c393a42SmrgFcStrSetAdd (FcStrSet *set, const FcChar8 *s) 12422c393a42Smrg{ 12432c393a42Smrg FcChar8 *new = FcStrCopy (s); 12442c393a42Smrg if (!new) 12452c393a42Smrg return FcFalse; 12462c393a42Smrg if (!_FcStrSetAppend (set, new)) 12472c393a42Smrg { 12482c393a42Smrg FcStrFree (new); 12492c393a42Smrg return FcFalse; 12502c393a42Smrg } 12512c393a42Smrg return FcTrue; 12522c393a42Smrg} 12532c393a42Smrg 12542c393a42SmrgFcBool 12552c393a42SmrgFcStrSetAddFilename (FcStrSet *set, const FcChar8 *s) 12562c393a42Smrg{ 12572c393a42Smrg FcChar8 *new = FcStrCopyFilename (s); 12582c393a42Smrg if (!new) 12592c393a42Smrg return FcFalse; 12602c393a42Smrg if (!_FcStrSetAppend (set, new)) 12612c393a42Smrg { 12622c393a42Smrg FcStrFree (new); 12632c393a42Smrg return FcFalse; 12642c393a42Smrg } 12652c393a42Smrg return FcTrue; 12662c393a42Smrg} 12672c393a42Smrg 1268ca08ab68SmrgFcBool 1269ca08ab68SmrgFcStrSetAddLangs (FcStrSet *strs, const char *languages) 1270ca08ab68Smrg{ 1271ca08ab68Smrg const char *p = languages, *next; 1272ca08ab68Smrg FcChar8 lang[128] = {0}, *normalized_lang; 1273ca08ab68Smrg size_t len; 1274ca08ab68Smrg FcBool ret = FcFalse; 1275ca08ab68Smrg 1276ca08ab68Smrg if (!languages) 1277ca08ab68Smrg return FcFalse; 1278ca08ab68Smrg 1279ca08ab68Smrg while ((next = strchr (p, ':'))) 1280ca08ab68Smrg { 1281ca08ab68Smrg len = next - p; 1282c9710b42Smrg len = FC_MIN (len, 127); 1283ca08ab68Smrg strncpy ((char *) lang, p, len); 1284ca08ab68Smrg lang[len] = 0; 1285ca08ab68Smrg /* ignore an empty item */ 1286ca08ab68Smrg if (*lang) 1287ca08ab68Smrg { 1288ca08ab68Smrg normalized_lang = FcLangNormalize ((const FcChar8 *) lang); 1289ca08ab68Smrg if (normalized_lang) 1290ca08ab68Smrg { 1291ca08ab68Smrg FcStrSetAdd (strs, normalized_lang); 1292c9710b42Smrg FcStrFree (normalized_lang); 1293ca08ab68Smrg ret = FcTrue; 1294ca08ab68Smrg } 1295ca08ab68Smrg } 1296ca08ab68Smrg p = next + 1; 1297ca08ab68Smrg } 1298ca08ab68Smrg if (*p) 1299ca08ab68Smrg { 1300ca08ab68Smrg normalized_lang = FcLangNormalize ((const FcChar8 *) p); 1301ca08ab68Smrg if (normalized_lang) 1302ca08ab68Smrg { 1303ca08ab68Smrg FcStrSetAdd (strs, normalized_lang); 1304c9710b42Smrg FcStrFree (normalized_lang); 1305ca08ab68Smrg ret = FcTrue; 1306ca08ab68Smrg } 1307ca08ab68Smrg } 1308ca08ab68Smrg 1309ca08ab68Smrg return ret; 1310ca08ab68Smrg} 1311ca08ab68Smrg 13122c393a42SmrgFcBool 13132c393a42SmrgFcStrSetDel (FcStrSet *set, const FcChar8 *s) 13142c393a42Smrg{ 13152c393a42Smrg int i; 13162c393a42Smrg 13172c393a42Smrg for (i = 0; i < set->num; i++) 13182c393a42Smrg if (!FcStrCmp (set->strs[i], s)) 13192c393a42Smrg { 13202c393a42Smrg FcStrFree (set->strs[i]); 13212c393a42Smrg /* 13222c393a42Smrg * copy remaining string pointers and trailing 13232c393a42Smrg * NULL 13242c393a42Smrg */ 1325ca08ab68Smrg memmove (&set->strs[i], &set->strs[i+1], 13262c393a42Smrg (set->num - i) * sizeof (FcChar8 *)); 13272c393a42Smrg set->num--; 13282c393a42Smrg return FcTrue; 13292c393a42Smrg } 13302c393a42Smrg return FcFalse; 13312c393a42Smrg} 13322c393a42Smrg 1333c9710b42Smrg/* TODO Make public */ 1334c9710b42Smrgstatic FcStrSet * 1335c9710b42SmrgFcStrSetReference (FcStrSet *set) 1336c9710b42Smrg{ 1337c9710b42Smrg if (FcRefIsConst (&set->ref)) 1338c9710b42Smrg return set; 1339c9710b42Smrg 1340c9710b42Smrg FcRefInc (&set->ref); 1341c9710b42Smrg return set; 1342c9710b42Smrg} 1343c9710b42Smrg 13442c393a42Smrgvoid 13452c393a42SmrgFcStrSetDestroy (FcStrSet *set) 13462c393a42Smrg{ 1347c9710b42Smrg int i; 1348ca08ab68Smrg 1349c9710b42Smrg /* We rely on this in FcGetDefaultLangs for caching. */ 1350c9710b42Smrg if (FcRefIsConst (&set->ref)) 1351c9710b42Smrg return; 1352c9710b42Smrg 1353c9710b42Smrg if (FcRefDec (&set->ref) != 1) 1354c9710b42Smrg return; 1355c9710b42Smrg 1356c9710b42Smrg for (i = 0; i < set->num; i++) 1357c9710b42Smrg FcStrFree (set->strs[i]); 1358c9710b42Smrg if (set->strs) 1359c9710b42Smrg free (set->strs); 1360c9710b42Smrg free (set); 13612c393a42Smrg} 13622c393a42Smrg 13632c393a42SmrgFcStrList * 13642c393a42SmrgFcStrListCreate (FcStrSet *set) 13652c393a42Smrg{ 13662c393a42Smrg FcStrList *list; 13672c393a42Smrg 13682c393a42Smrg list = malloc (sizeof (FcStrList)); 13692c393a42Smrg if (!list) 13702c393a42Smrg return 0; 13712c393a42Smrg list->set = set; 1372c9710b42Smrg FcStrSetReference (set); 13732c393a42Smrg list->n = 0; 13742c393a42Smrg return list; 13752c393a42Smrg} 13762c393a42Smrg 13776fc018e4Smrgvoid 13786fc018e4SmrgFcStrListFirst (FcStrList *list) 13796fc018e4Smrg{ 13806fc018e4Smrg list->n = 0; 13816fc018e4Smrg} 13826fc018e4Smrg 13832c393a42SmrgFcChar8 * 13842c393a42SmrgFcStrListNext (FcStrList *list) 13852c393a42Smrg{ 13862c393a42Smrg if (list->n >= list->set->num) 13872c393a42Smrg return 0; 13882c393a42Smrg return list->set->strs[list->n++]; 13892c393a42Smrg} 13902c393a42Smrg 13912c393a42Smrgvoid 13922c393a42SmrgFcStrListDone (FcStrList *list) 13932c393a42Smrg{ 13942c393a42Smrg FcStrSetDestroy (list->set); 13952c393a42Smrg free (list); 13962c393a42Smrg} 13972c393a42Smrg 13982c393a42Smrg#define __fcstr__ 13992c393a42Smrg#include "fcaliastail.h" 14002c393a42Smrg#undef __fcstr__ 1401