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 (&reg, (const char *)regex, cflags)) != 0)
253ca08ab68Smrg    {
254ca08ab68Smrg	if (FcDebug () & FC_DBG_MATCHV)
255ca08ab68Smrg	{
256ca08ab68Smrg	    char buf[512];
257ca08ab68Smrg
258ca08ab68Smrg	    regerror (ret, &reg, buf, 512);
259ca08ab68Smrg	    printf("Regexp compile error: %s\n", buf);
260ca08ab68Smrg	}
261ca08ab68Smrg	return FcFalse;
262ca08ab68Smrg    }
263ca08ab68Smrg    ret = regexec (&reg, (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, &reg, buf, 512);
271ca08ab68Smrg	    printf("Regexp exec error: %s\n", buf);
272ca08ab68Smrg	}
273ca08ab68Smrg    }
274ca08ab68Smrg    regfree (&reg);
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