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