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