Home | History | Annotate | Line # | Download | only in src
      1 /*
      2  * fontconfig/src/fcstr.c
      3  *
      4  * Copyright  2000 Keith Packard
      5  *
      6  * Permission to use, copy, modify, distribute, and sell this software and its
      7  * documentation for any purpose is hereby granted without fee, provided that
      8  * the above copyright notice appear in all copies and that both that
      9  * copyright notice and this permission notice appear in supporting
     10  * documentation, and that the name of the author(s) not be used in
     11  * advertising or publicity pertaining to distribution of the software without
     12  * specific, written prior permission.  The authors make no
     13  * representations about the suitability of this software for any purpose.  It
     14  * is provided "as is" without express or implied warranty.
     15  *
     16  * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
     18  * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     19  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
     20  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
     21  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
     22  * PERFORMANCE OF THIS SOFTWARE.
     23  */
     24 
     25 #include "fcint.h"
     26 #include <stdlib.h>
     27 #include <ctype.h>
     28 #include <string.h>
     29 
     30 
     31 /* Objects MT-safe for readonly access. */
     32 
     33 FcChar8 *
     34 FcStrCopy (const FcChar8 *s)
     35 {
     36     return FcStrdup (s);
     37 }
     38 
     39 static FcChar8 *
     40 FcStrMakeTriple (const FcChar8 *s1, const FcChar8 *s2, const FcChar8 *s3)
     41 {
     42     int	    s1l = s1 ? strlen ((char *) s1) : 0;
     43     int	    s2l = s2 ? strlen ((char *) s2) : 0;
     44     int     s3l = s3 ? strlen ((char *) s3) : 0;
     45     int	    l = s1l + 1 + s2l + 1 + s3l + 1;
     46     FcChar8 *s = malloc (l);
     47 
     48     if (!s)
     49 	return 0;
     50     if (s1)
     51 	memcpy (s, s1, s1l + 1);
     52     else
     53 	s[0] = '\0';
     54     if (s2)
     55 	memcpy (s + s1l + 1, s2, s2l + 1);
     56     else
     57 	s[s1l + 1] = '\0';
     58     if (s3)
     59 	memcpy (s + s1l + 1 + s2l + 1, s3, s3l + 1);
     60     else
     61 	s[s1l + 1 + s2l + 1] = '\0';
     62     return s;
     63 }
     64 
     65 FcChar8 *
     66 FcStrPlus (const FcChar8 *s1, const FcChar8 *s2)
     67 {
     68     int	    s1l = strlen ((char *) s1);
     69     int	    s2l = strlen ((char *) s2);
     70     int	    l = s1l + s2l + 1;
     71     FcChar8 *s = malloc (l);
     72 
     73     if (!s)
     74 	return 0;
     75     memcpy (s, s1, s1l);
     76     memcpy (s + s1l, s2, s2l + 1);
     77     return s;
     78 }
     79 
     80 void
     81 FcStrFree (FcChar8 *s)
     82 {
     83     free (s);
     84 }
     85 
     86 
     87 #include "../fc-case/fccase.h"
     88 
     89 #define FcCaseFoldUpperCount(cf) \
     90     ((cf)->method == FC_CASE_FOLD_FULL ? 1 : (cf)->count)
     91 
     92 typedef struct _FcCaseWalker {
     93     const FcChar8   *read;
     94     const FcChar8   *src;
     95     FcChar8	    utf8[FC_MAX_CASE_FOLD_CHARS + 1];
     96 } FcCaseWalker;
     97 
     98 static void
     99 FcStrCaseWalkerInit (const FcChar8 *src, FcCaseWalker *w)
    100 {
    101     w->src = src;
    102     w->read = 0;
    103 }
    104 
    105 static FcChar8
    106 FcStrCaseWalkerLong (FcCaseWalker *w, FcChar8 r)
    107 {
    108     FcChar32	ucs4;
    109     int		slen;
    110     int		len = strlen((char*)w->src);
    111 
    112     slen = FcUtf8ToUcs4 (w->src - 1, &ucs4, len + 1);
    113     if (slen <= 0)
    114 	return r;
    115     if (FC_MIN_FOLD_CHAR <= ucs4 && ucs4 <= FC_MAX_FOLD_CHAR)
    116     {
    117 	int min = 0;
    118 	int max = FC_NUM_CASE_FOLD;
    119 
    120 	while (min <= max)
    121 	{
    122 	    int		mid = (min + max) >> 1;
    123 	    FcChar32    low = fcCaseFold[mid].upper;
    124 	    FcChar32    high = low + FcCaseFoldUpperCount (&fcCaseFold[mid]);
    125 
    126 	    if (high <= ucs4)
    127 		min = mid + 1;
    128 	    else if (ucs4 < low)
    129 		max = mid - 1;
    130 	    else
    131 	    {
    132 		const FcCaseFold    *fold = &fcCaseFold[mid];
    133 		int		    dlen;
    134 
    135 		switch (fold->method) {
    136 		case  FC_CASE_FOLD_EVEN_ODD:
    137 		    if ((ucs4 & 1) != (fold->upper & 1))
    138 			return r;
    139 		    /* fall through ... */
    140 		default:
    141 		    dlen = FcUcs4ToUtf8 (ucs4 + fold->offset, w->utf8);
    142 		    break;
    143 		case FC_CASE_FOLD_FULL:
    144 		    dlen = fold->count;
    145 		    memcpy (w->utf8, fcCaseFoldChars + fold->offset, dlen);
    146 		    break;
    147 		}
    148 
    149 		/* consume rest of src utf-8 bytes */
    150 		w->src += slen - 1;
    151 
    152 		/* read from temp buffer */
    153 		w->utf8[dlen] = '\0';
    154 		w->read = w->utf8;
    155 		return *w->read++;
    156 	    }
    157 	}
    158     }
    159     return r;
    160 }
    161 
    162 static FcChar8
    163 FcStrCaseWalkerNextNonDelim (FcCaseWalker *w, const char *delims)
    164 {
    165     FcChar8	r;
    166 
    167     if (FC_UNLIKELY (w->read != NULL))
    168     {
    169 	if ((r = *w->read++))
    170 	    return r;
    171 	w->read = 0;
    172     }
    173     do
    174     {
    175 	r = *w->src++;
    176     } while (r != 0 && delims && strchr (delims, r));
    177 
    178     if (FC_UNLIKELY ((r & 0xc0) == 0xc0))
    179 	return FcStrCaseWalkerLong (w, r);
    180     if ('A' <= r && r <= 'Z')
    181         r = r - 'A' + 'a';
    182     return r;
    183 }
    184 
    185 static FcChar8
    186 FcStrCaseWalkerNextNonBlank (FcCaseWalker *w)
    187 {
    188     FcChar8	r;
    189 
    190     if (FC_UNLIKELY (w->read != NULL))
    191     {
    192 	if ((r = *w->read++))
    193 	    return r;
    194 	w->read = 0;
    195     }
    196     do
    197     {
    198 	r = *w->src++;
    199     } while (r == ' ');
    200 
    201     if (FC_UNLIKELY ((r & 0xc0) == 0xc0))
    202 	return FcStrCaseWalkerLong (w, r);
    203     if ('A' <= r && r <= 'Z')
    204         r = r - 'A' + 'a';
    205     return r;
    206 }
    207 
    208 static FcChar8
    209 FcStrCaseWalkerNext (FcCaseWalker *w)
    210 {
    211     FcChar8	r;
    212 
    213     if (FC_UNLIKELY (w->read != NULL))
    214     {
    215 	if ((r = *w->read++))
    216 	    return r;
    217 	w->read = 0;
    218     }
    219 
    220     r = *w->src++;
    221 
    222     if (FC_UNLIKELY ((r & 0xc0) == 0xc0))
    223 	return FcStrCaseWalkerLong (w, r);
    224     if ('A' <= r && r <= 'Z')
    225         r = r - 'A' + 'a';
    226     return r;
    227 }
    228 
    229 FcChar8 *
    230 FcStrDowncase (const FcChar8 *s)
    231 {
    232     FcCaseWalker    w;
    233     int		    len = 0;
    234     FcChar8	    *dst, *d;
    235 
    236     FcStrCaseWalkerInit (s, &w);
    237     while (FcStrCaseWalkerNext (&w))
    238 	len++;
    239     d = dst = malloc (len + 1);
    240     if (!d)
    241 	return 0;
    242     FcStrCaseWalkerInit (s, &w);
    243     while ((*d++ = FcStrCaseWalkerNext (&w)));
    244     return dst;
    245 }
    246 
    247 int
    248 FcStrCmpIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
    249 {
    250     FcCaseWalker    w1, w2;
    251     FcChar8	    c1, c2;
    252 
    253     if (s1 == s2) return 0;
    254 
    255     FcStrCaseWalkerInit (s1, &w1);
    256     FcStrCaseWalkerInit (s2, &w2);
    257 
    258     for (;;)
    259     {
    260 	c1 = FcStrCaseWalkerNext (&w1);
    261 	c2 = FcStrCaseWalkerNext (&w2);
    262 	if (!c1 || (c1 != c2))
    263 	    break;
    264     }
    265     return (int) c1 - (int) c2;
    266 }
    267 
    268 int
    269 FcStrCmpIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2)
    270 {
    271     FcCaseWalker    w1, w2;
    272     FcChar8	    c1, c2;
    273 
    274     if (s1 == s2) return 0;
    275 
    276     FcStrCaseWalkerInit (s1, &w1);
    277     FcStrCaseWalkerInit (s2, &w2);
    278 
    279     for (;;)
    280     {
    281 	c1 = FcStrCaseWalkerNextNonBlank (&w1);
    282 	c2 = FcStrCaseWalkerNextNonBlank (&w2);
    283 	if (!c1 || (c1 != c2))
    284 	    break;
    285     }
    286     return (int) c1 - (int) c2;
    287 }
    288 
    289 int
    290 FcStrCmp (const FcChar8 *s1, const FcChar8 *s2)
    291 {
    292     FcChar8 c1, c2;
    293 
    294     if (s1 == s2)
    295 	return 0;
    296     for (;;)
    297     {
    298 	c1 = *s1++;
    299 	c2 = *s2++;
    300 	if (!c1 || c1 != c2)
    301 	    break;
    302     }
    303     return (int) c1 - (int) c2;
    304 }
    305 
    306 /*
    307  * Return a hash value for a string
    308  */
    309 
    310 FcChar32
    311 FcStrHashIgnoreCase (const FcChar8 *s)
    312 {
    313     FcChar32	    h = 0;
    314     FcCaseWalker    w;
    315     FcChar8	    c;
    316 
    317     FcStrCaseWalkerInit (s, &w);
    318     while ((c = FcStrCaseWalkerNext (&w)))
    319 	h = ((h << 3) ^ (h >> 3)) ^ c;
    320     return h;
    321 }
    322 
    323 FcChar32
    324 FcStrHashIgnoreBlanksAndCase (const FcChar8 *s)
    325 {
    326     FcChar32	    h = 0;
    327     FcCaseWalker    w;
    328     FcChar8	    c;
    329 
    330     FcStrCaseWalkerInit (s, &w);
    331     while ((c = FcStrCaseWalkerNextNonBlank (&w)))
    332 	h = ((h << 3) ^ (h >> 3)) ^ c;
    333     return h;
    334 }
    335 
    336 /*
    337  * Is the head of s1 equal to s2?
    338  */
    339 
    340 static FcBool
    341 FcStrIsAtIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2)
    342 {
    343     FcCaseWalker    w1, w2;
    344     FcChar8	    c1, c2;
    345 
    346     FcStrCaseWalkerInit (s1, &w1);
    347     FcStrCaseWalkerInit (s2, &w2);
    348 
    349     for (;;)
    350     {
    351 	c1 = FcStrCaseWalkerNextNonBlank (&w1);
    352 	c2 = FcStrCaseWalkerNextNonBlank (&w2);
    353 	if (!c1 || (c1 != c2))
    354 	    break;
    355     }
    356     return c1 == c2 || !c2;
    357 }
    358 
    359 /*
    360  * Does s1 contain an instance of s2 (ignoring blanks and case)?
    361  */
    362 
    363 const FcChar8 *
    364 FcStrContainsIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2)
    365 {
    366     while (*s1)
    367     {
    368 	if (FcStrIsAtIgnoreBlanksAndCase (s1, s2))
    369 	    return s1;
    370 	s1++;
    371     }
    372     return 0;
    373 }
    374 
    375 static FcBool
    376 FcCharIsPunct (const FcChar8 c)
    377 {
    378     if (c < '0')
    379 	return FcTrue;
    380     if (c <= '9')
    381 	return FcFalse;
    382     if (c < 'A')
    383 	return FcTrue;
    384     if (c <= 'Z')
    385 	return FcFalse;
    386     if (c < 'a')
    387 	return FcTrue;
    388     if (c <= 'z')
    389 	return FcFalse;
    390     if (c <= '~')
    391 	return FcTrue;
    392     return FcFalse;
    393 }
    394 
    395 /*
    396  * Is the head of s1 equal to s2?
    397  */
    398 
    399 static FcBool
    400 FcStrIsAtIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
    401 {
    402     FcCaseWalker    w1, w2;
    403     FcChar8	    c1, c2;
    404 
    405     FcStrCaseWalkerInit (s1, &w1);
    406     FcStrCaseWalkerInit (s2, &w2);
    407 
    408     for (;;)
    409     {
    410 	c1 = FcStrCaseWalkerNext (&w1);
    411 	c2 = FcStrCaseWalkerNext (&w2);
    412 	if (!c1 || (c1 != c2))
    413 	    break;
    414     }
    415     return c1 == c2 || !c2;
    416 }
    417 
    418 /*
    419  * Does s1 contain an instance of s2 (ignoring blanks and case)?
    420  */
    421 
    422 const FcChar8 *
    423 FcStrContainsIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
    424 {
    425     while (*s1)
    426     {
    427 	if (FcStrIsAtIgnoreCase (s1, s2))
    428 	    return s1;
    429 	s1++;
    430     }
    431     return 0;
    432 }
    433 
    434 /*
    435  * Does s1 contain an instance of s2 on a word boundary (ignoring case)?
    436  */
    437 
    438 const FcChar8 *
    439 FcStrContainsWord (const FcChar8 *s1, const FcChar8 *s2)
    440 {
    441     FcBool  wordStart = FcTrue;
    442     int	    s1len = strlen ((char *) s1);
    443     int	    s2len = strlen ((char *) s2);
    444 
    445     while (s1len >= s2len)
    446     {
    447 	if (wordStart &&
    448 	    FcStrIsAtIgnoreCase (s1, s2) &&
    449 	    (s1len == s2len || FcCharIsPunct (s1[s2len])))
    450 	{
    451 	    return s1;
    452 	}
    453 	wordStart = FcFalse;
    454 	if (FcCharIsPunct (*s1))
    455 	    wordStart = FcTrue;
    456 	s1++;
    457 	s1len--;
    458     }
    459     return 0;
    460 }
    461 
    462 /*
    463  * returns the number of strings (ignoring delimiters and case) being matched
    464  */
    465 
    466 int
    467 FcStrMatchIgnoreCaseAndDelims (const FcChar8 *s1, const FcChar8 *s2, const FcChar8 *delims)
    468 {
    469     FcCaseWalker    w1, w2;
    470     FcChar8	    c1, c2;
    471 
    472     if (s1 == s2) return 0;
    473 
    474     FcStrCaseWalkerInit (s1, &w1);
    475     FcStrCaseWalkerInit (s2, &w2);
    476 
    477     for (;;)
    478     {
    479 	c1 = FcStrCaseWalkerNextNonDelim (&w1, (const char *)delims);
    480 	c2 = FcStrCaseWalkerNextNonDelim (&w2, (const char *)delims);
    481 	if (!c1 || (c1 != c2))
    482 	    break;
    483     }
    484     return w1.src - s1 - 1;
    485 }
    486 
    487 FcBool
    488 FcStrGlobMatch (const FcChar8 *glob,
    489 		const FcChar8 *string)
    490 {
    491     FcChar8	c;
    492 
    493     while ((c = *glob++))
    494     {
    495 	switch (c) {
    496 	case '*':
    497 	    /* short circuit common case */
    498 	    if (!*glob)
    499 		return FcTrue;
    500 	    /* short circuit another common case */
    501 	    if (strchr ((char *) glob, '*') == 0)
    502 	    {
    503 		size_t l1, l2;
    504 
    505 		l1 = strlen ((char *) string);
    506 		l2 = strlen ((char *) glob);
    507 		if (l1 < l2)
    508 		    return FcFalse;
    509 		string += (l1 - l2);
    510 	    }
    511 	    while (*string)
    512 	    {
    513 		if (FcStrGlobMatch (glob, string))
    514 		    return FcTrue;
    515 		string++;
    516 	    }
    517 	    return FcFalse;
    518 	case '?':
    519 	    if (*string++ == '\0')
    520 		return FcFalse;
    521 	    break;
    522 	default:
    523 	    if (*string++ != c)
    524 		return FcFalse;
    525 	    break;
    526 	}
    527     }
    528     return *string == '\0';
    529 }
    530 
    531 const FcChar8 *
    532 FcStrStrIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
    533 {
    534     FcCaseWalker    w1, w2;
    535     FcChar8	    c1, c2;
    536     const FcChar8   *cur;
    537 
    538     if (!s1 || !s2)
    539 	return 0;
    540 
    541     if (s1 == s2)
    542 	return s1;
    543 
    544     FcStrCaseWalkerInit (s1, &w1);
    545     FcStrCaseWalkerInit (s2, &w2);
    546 
    547     c2 = FcStrCaseWalkerNext (&w2);
    548 
    549     for (;;)
    550     {
    551 	cur = w1.src;
    552 	c1 = FcStrCaseWalkerNext (&w1);
    553 	if (!c1)
    554 	    break;
    555 	if (c1 == c2)
    556 	{
    557 	    FcCaseWalker    w1t = w1;
    558 	    FcCaseWalker    w2t = w2;
    559 	    FcChar8	    c1t, c2t;
    560 
    561 	    for (;;)
    562 	    {
    563 		c1t = FcStrCaseWalkerNext (&w1t);
    564 		c2t = FcStrCaseWalkerNext (&w2t);
    565 
    566 		if (!c2t)
    567 		    return cur;
    568 		if (c2t != c1t)
    569 		    break;
    570 	    }
    571 	}
    572     }
    573     return 0;
    574 }
    575 
    576 const FcChar8 *
    577 FcStrStr (const FcChar8 *s1, const FcChar8 *s2)
    578 {
    579     FcChar8 c1, c2;
    580     const FcChar8 * p = s1;
    581     const FcChar8 * b = s2;
    582 
    583     if (!s1 || !s2)
    584 	return 0;
    585 
    586     if (s1 == s2)
    587 	return s1;
    588 
    589 again:
    590     c2 = *s2++;
    591 
    592     if (!c2)
    593 	return 0;
    594 
    595     for (;;)
    596     {
    597 	p = s1;
    598 	c1 = *s1++;
    599 	if (!c1 || c1 == c2)
    600 	    break;
    601     }
    602 
    603     if (c1 != c2)
    604 	return 0;
    605 
    606     for (;;)
    607     {
    608 	c1 = *s1;
    609 	c2 = *s2;
    610 	if (c1 && c2 && c1 != c2)
    611 	{
    612 	    s1 = p + 1;
    613 	    s2 = b;
    614 	    goto again;
    615 	}
    616 	if (!c2)
    617 	    return p;
    618 	if (!c1)
    619 	    return 0;
    620 	++ s1;
    621 	++ s2;
    622     }
    623     /* never reached. */
    624 }
    625 
    626 int
    627 FcUtf8ToUcs4 (const FcChar8 *src_orig,
    628 	      FcChar32	    *dst,
    629 	      int	    len)
    630 {
    631     const FcChar8   *src = src_orig;
    632     FcChar8	    s;
    633     int		    extra;
    634     FcChar32	    result;
    635 
    636     if (len == 0)
    637 	return 0;
    638 
    639     s = *src++;
    640     len--;
    641 
    642     if (!(s & 0x80))
    643     {
    644 	result = s;
    645 	extra = 0;
    646     }
    647     else if (!(s & 0x40))
    648     {
    649 	return -1;
    650     }
    651     else if (!(s & 0x20))
    652     {
    653 	result = s & 0x1f;
    654 	extra = 1;
    655     }
    656     else if (!(s & 0x10))
    657     {
    658 	result = s & 0xf;
    659 	extra = 2;
    660     }
    661     else if (!(s & 0x08))
    662     {
    663 	result = s & 0x07;
    664 	extra = 3;
    665     }
    666     else if (!(s & 0x04))
    667     {
    668 	result = s & 0x03;
    669 	extra = 4;
    670     }
    671     else if ( ! (s & 0x02))
    672     {
    673 	result = s & 0x01;
    674 	extra = 5;
    675     }
    676     else
    677     {
    678 	return -1;
    679     }
    680     if (extra > len)
    681 	return -1;
    682 
    683     while (extra--)
    684     {
    685 	result <<= 6;
    686 	s = *src++;
    687 
    688 	if ((s & 0xc0) != 0x80)
    689 	    return -1;
    690 
    691 	result |= s & 0x3f;
    692     }
    693     *dst = result;
    694     return src - src_orig;
    695 }
    696 
    697 FcBool
    698 FcUtf8Len (const FcChar8    *string,
    699 	   int		    len,
    700 	   int		    *nchar,
    701 	   int		    *wchar)
    702 {
    703     int		n;
    704     int		clen;
    705     FcChar32	c;
    706     FcChar32	max;
    707 
    708     n = 0;
    709     max = 0;
    710     while (len)
    711     {
    712 	clen = FcUtf8ToUcs4 (string, &c, len);
    713 	if (clen <= 0)	/* malformed UTF8 string */
    714 	    return FcFalse;
    715 	if (c > max)
    716 	    max = c;
    717 	string += clen;
    718 	len -= clen;
    719 	n++;
    720     }
    721     *nchar = n;
    722     if (max >= 0x10000)
    723 	*wchar = 4;
    724     else if (max > 0x100)
    725 	*wchar = 2;
    726     else
    727 	*wchar = 1;
    728     return FcTrue;
    729 }
    730 
    731 int
    732 FcUcs4ToUtf8 (FcChar32	ucs4,
    733 	      FcChar8	dest[FC_UTF8_MAX_LEN])
    734 {
    735     int	bits;
    736     FcChar8 *d = dest;
    737 
    738     if      (ucs4 <       0x80) {  *d++=  ucs4;                         bits= -6; }
    739     else if (ucs4 <      0x800) {  *d++= ((ucs4 >>  6) & 0x1F) | 0xC0;  bits=  0; }
    740     else if (ucs4 <    0x10000) {  *d++= ((ucs4 >> 12) & 0x0F) | 0xE0;  bits=  6; }
    741     else if (ucs4 <   0x200000) {  *d++= ((ucs4 >> 18) & 0x07) | 0xF0;  bits= 12; }
    742     else if (ucs4 <  0x4000000) {  *d++= ((ucs4 >> 24) & 0x03) | 0xF8;  bits= 18; }
    743     else if (ucs4 < 0x80000000) {  *d++= ((ucs4 >> 30) & 0x01) | 0xFC;  bits= 24; }
    744     else return 0;
    745 
    746     for ( ; bits >= 0; bits-= 6) {
    747 	*d++= ((ucs4 >> bits) & 0x3F) | 0x80;
    748     }
    749     return d - dest;
    750 }
    751 
    752 #define GetUtf16(src,endian) \
    753     ((FcChar16) ((src)[endian == FcEndianBig ? 0 : 1] << 8) | \
    754      (FcChar16) ((src)[endian == FcEndianBig ? 1 : 0]))
    755 
    756 int
    757 FcUtf16ToUcs4 (const FcChar8	*src_orig,
    758 	       FcEndian		endian,
    759 	       FcChar32		*dst,
    760 	       int		len)	/* in bytes */
    761 {
    762     const FcChar8   *src = src_orig;
    763     FcChar16	    a, b;
    764     FcChar32	    result;
    765 
    766     if (len < 2)
    767 	return 0;
    768 
    769     a = GetUtf16 (src, endian); src += 2; len -= 2;
    770 
    771     /*
    772      * Check for surrogate
    773      */
    774     if ((a & 0xfc00) == 0xd800)
    775     {
    776 	if (len < 2)
    777 	    return 0;
    778 	b = GetUtf16 (src, endian); src += 2; len -= 2;
    779 	/*
    780 	 * Check for invalid surrogate sequence
    781 	 */
    782 	if ((b & 0xfc00) != 0xdc00)
    783 	    return 0;
    784 	result = ((((FcChar32) a & 0x3ff) << 10) |
    785 		  ((FcChar32) b & 0x3ff)) + 0x10000;
    786     }
    787     else
    788 	result = a;
    789     *dst = result;
    790     return src - src_orig;
    791 }
    792 
    793 FcBool
    794 FcUtf16Len (const FcChar8   *string,
    795 	    FcEndian	    endian,
    796 	    int		    len,	/* in bytes */
    797 	    int		    *nchar,
    798 	    int		    *wchar)
    799 {
    800     int		n;
    801     int		clen;
    802     FcChar32	c;
    803     FcChar32	max;
    804 
    805     n = 0;
    806     max = 0;
    807     while (len)
    808     {
    809 	clen = FcUtf16ToUcs4 (string, endian, &c, len);
    810 	if (clen <= 0)	/* malformed UTF8 string */
    811 	    return FcFalse;
    812 	if (c > max)
    813 	    max = c;
    814 	string += clen;
    815 	len -= clen;
    816 	n++;
    817     }
    818     *nchar = n;
    819     if (max >= 0x10000)
    820 	*wchar = 4;
    821     else if (max > 0x100)
    822 	*wchar = 2;
    823     else
    824 	*wchar = 1;
    825     return FcTrue;
    826 }
    827 
    828 void
    829 FcStrBufInit (FcStrBuf *buf, FcChar8 *init, int size)
    830 {
    831     if (init)
    832     {
    833 	buf->buf = init;
    834 	buf->size = size;
    835     } else
    836     {
    837 	buf->buf = buf->buf_static;
    838 	buf->size = sizeof (buf->buf_static);
    839     }
    840     buf->allocated = FcFalse;
    841     buf->failed = FcFalse;
    842     buf->len = 0;
    843 }
    844 
    845 void
    846 FcStrBufDestroy (FcStrBuf *buf)
    847 {
    848     if (buf->allocated)
    849     {
    850 	free (buf->buf);
    851 	FcStrBufInit (buf, 0, 0);
    852     }
    853 }
    854 
    855 FcChar8 *
    856 FcStrBufDone (FcStrBuf *buf)
    857 {
    858     FcChar8 *ret;
    859 
    860     if (buf->failed)
    861 	ret = NULL;
    862     else
    863 	ret = malloc (buf->len + 1);
    864     if (ret)
    865     {
    866 	memcpy (ret, buf->buf, buf->len);
    867 	ret[buf->len] = '\0';
    868     }
    869     FcStrBufDestroy (buf);
    870     return ret;
    871 }
    872 
    873 FcChar8 *
    874 FcStrBufDoneStatic (FcStrBuf *buf)
    875 {
    876     FcStrBufChar (buf, '\0');
    877 
    878     if (buf->failed)
    879 	return NULL;
    880 
    881     return buf->buf;
    882 }
    883 
    884 FcBool
    885 FcStrBufChar (FcStrBuf *buf, FcChar8 c)
    886 {
    887     if (buf->len == buf->size)
    888     {
    889 	FcChar8	    *new;
    890 	int	    size;
    891 
    892 	if (buf->failed)
    893 	    return FcFalse;
    894 
    895 	if (buf->allocated)
    896 	{
    897 	    size = buf->size * 2;
    898 	    new = realloc (buf->buf, size);
    899 	}
    900 	else
    901 	{
    902 	    size = buf->size + 64;
    903 	    new = malloc (size);
    904 	    if (new)
    905 	    {
    906 		buf->allocated = FcTrue;
    907 		memcpy (new, buf->buf, buf->len);
    908 	    }
    909 	}
    910 	if (!new)
    911 	{
    912 	    buf->failed = FcTrue;
    913 	    return FcFalse;
    914 	}
    915 	buf->size = size;
    916 	buf->buf = new;
    917     }
    918     buf->buf[buf->len++] = c;
    919     return FcTrue;
    920 }
    921 
    922 FcBool
    923 FcStrBufString (FcStrBuf *buf, const FcChar8 *s)
    924 {
    925     FcChar8 c;
    926     while ((c = *s++))
    927 	if (!FcStrBufChar (buf, c))
    928 	    return FcFalse;
    929     return FcTrue;
    930 }
    931 
    932 FcBool
    933 FcStrBufData (FcStrBuf *buf, const FcChar8 *s, int len)
    934 {
    935     while (len-- > 0)
    936 	if (!FcStrBufChar (buf, *s++))
    937 	    return FcFalse;
    938     return FcTrue;
    939 }
    940 
    941 FcBool
    942 FcStrUsesHome (const FcChar8 *s)
    943 {
    944     return *s == '~';
    945 }
    946 
    947 FcBool
    948 FcStrIsAbsoluteFilename (const FcChar8 *s)
    949 {
    950 #ifdef _WIN32
    951     if (*s == '\\' ||
    952 	(isalpha (*s) && s[1] == ':' && (s[2] == '/' || s[2] == '\\')))
    953 	return FcTrue;
    954 #endif
    955     return *s == '/';
    956 }
    957 
    958 FcChar8 *
    959 FcStrBuildFilename (const FcChar8 *path,
    960 		    ...)
    961 {
    962     va_list ap;
    963     FcStrSet *sset;
    964     FcStrList *list;
    965     FcChar8 *s, *ret = NULL, *p;
    966     size_t len = 0;
    967 
    968     if (!path)
    969 	return NULL;
    970 
    971     sset = FcStrSetCreateEx (FCSS_ALLOW_DUPLICATES | FCSS_GROW_BY_64);
    972     if (!sset)
    973 	return NULL;
    974 
    975     if (!FcStrSetAdd (sset, path))
    976 	goto bail0;
    977 
    978     va_start (ap, path);
    979     while (1)
    980     {
    981 	s = (FcChar8 *)va_arg (ap, FcChar8 *);
    982 	if (!s)
    983 	    break;
    984 	if (!FcStrSetAdd (sset, s))
    985 	    goto bail1;
    986     }
    987     list = FcStrListCreate (sset);
    988     while ((s = FcStrListNext (list)))
    989     {
    990 	len += strlen ((const char *)s) + 1;
    991     }
    992     list->n = 0;
    993     ret = malloc (sizeof (FcChar8) * (len + 1));
    994     if (!ret)
    995 	goto bail2;
    996     p = ret;
    997     while ((s = FcStrListNext (list)))
    998     {
    999 	if (p != ret)
   1000 	{
   1001 	    p[0] = FC_DIR_SEPARATOR;
   1002 	    p++;
   1003 	}
   1004 	len = strlen ((const char *)s);
   1005 	memcpy (p, s, len);
   1006 	p += len;
   1007     }
   1008     *p = 0;
   1009 
   1010 bail2:
   1011     FcStrListDone (list);
   1012 bail1:
   1013     va_end (ap);
   1014 bail0:
   1015     FcStrSetDestroy (sset);
   1016 
   1017     return ret;
   1018 }
   1019 
   1020 FcChar8 *
   1021 FcStrCopyFilename (const FcChar8 *s)
   1022 {
   1023     FcChar8 *new;
   1024 
   1025     if (*s == '~')
   1026     {
   1027 	FcChar8	*home = FcConfigHome ();
   1028 	FcChar8	*full;
   1029 	int	size;
   1030 	if (!home)
   1031 	    return NULL;
   1032 	size = strlen ((char *) home) + strlen ((char *) s);
   1033 	full = (FcChar8 *) malloc (size + 1);
   1034 	if (!full)
   1035 	    return NULL;
   1036 	strcpy ((char *) full, (char *) home);
   1037 	strcat ((char *) full, (char *) s + 1);
   1038 	new = FcStrCanonFilename (full);
   1039 	free (full);
   1040     }
   1041     else
   1042 	new = FcStrCanonFilename (s);
   1043 
   1044     return new;
   1045 }
   1046 
   1047 FcChar8 *
   1048 FcStrLastSlash (const FcChar8  *path)
   1049 {
   1050     FcChar8	    *slash;
   1051 
   1052     slash = (FcChar8 *) strrchr ((const char *) path, '/');
   1053 #ifdef _WIN32
   1054     {
   1055         FcChar8     *backslash;
   1056 
   1057 	backslash = (FcChar8 *) strrchr ((const char *) path, '\\');
   1058 	if (!slash || (backslash && backslash > slash))
   1059 	    slash = backslash;
   1060     }
   1061 #endif
   1062 
   1063     return slash;
   1064 }
   1065 
   1066 FcChar8 *
   1067 FcStrDirname (const FcChar8 *file)
   1068 {
   1069     FcChar8 *slash;
   1070     FcChar8 *dir;
   1071 
   1072     slash = FcStrLastSlash (file);
   1073     if (!slash)
   1074 	return FcStrCopy ((FcChar8 *) ".");
   1075     dir = malloc ((slash - file) + 1);
   1076     if (!dir)
   1077 	return 0;
   1078     strncpy ((char *) dir, (const char *) file, slash - file);
   1079     dir[slash - file] = '\0';
   1080     return dir;
   1081 }
   1082 
   1083 FcChar8 *
   1084 FcStrBasename (const FcChar8 *file)
   1085 {
   1086     FcChar8 *slash;
   1087 
   1088     slash = FcStrLastSlash (file);
   1089     if (!slash)
   1090 	return FcStrCopy (file);
   1091     return FcStrCopy (slash + 1);
   1092 }
   1093 
   1094 FcChar8 *
   1095 FcStrRealPath (const FcChar8 *path)
   1096 {
   1097     char	resolved_name[FC_PATH_MAX+1];
   1098     char	*resolved_ret;
   1099 
   1100     if (!path)
   1101 	return NULL;
   1102 
   1103 #ifndef _WIN32
   1104     resolved_ret = realpath((const char *) path, resolved_name);
   1105 #else
   1106     if (GetFullPathNameA ((LPCSTR) path, FC_PATH_MAX, resolved_name, NULL) == 0)
   1107     {
   1108         fprintf (stderr, "Fontconfig warning: GetFullPathNameA failed.\n");
   1109         return NULL;
   1110     }
   1111     resolved_ret = resolved_name;
   1112 #endif
   1113     if (resolved_ret)
   1114 	path = (FcChar8 *) resolved_ret;
   1115     return FcStrCopyFilename(path);
   1116 }
   1117 
   1118 static FcChar8 *
   1119 FcStrCanonAbsoluteFilename (const FcChar8 *s)
   1120 {
   1121     FcChar8 *file;
   1122     FcChar8 *f;
   1123     const FcChar8 *slash;
   1124     int size;
   1125 
   1126     size = strlen ((char *) s) + 1;
   1127     file = malloc (size);
   1128     if (!file)
   1129 	return NULL;
   1130     slash = NULL;
   1131     f = file;
   1132 #ifdef _WIN32
   1133     if (*s == '/' && *(s+1) == '/') /* Network path, do not squash // */
   1134 	*f++ = *s++;
   1135 #endif
   1136     for (;;) {
   1137 	if (*s == '/' || *s == '\0')
   1138 	{
   1139 	    if (slash)
   1140 	    {
   1141 		switch (s - slash) {
   1142 		case 1:
   1143 		    f -= 1;	/* squash // and trim final / from file */
   1144 		    break;
   1145 		case 2:
   1146 		    if (!strncmp ((char *) slash, "/.", 2))
   1147 		    {
   1148 			f -= 2;	/* trim /. from file */
   1149 		    }
   1150 		    break;
   1151 		case 3:
   1152 		    if (!strncmp ((char *) slash, "/..", 3))
   1153 		    {
   1154 			f -= 3;	/* trim /.. from file */
   1155 			while (f > file) {
   1156 			    if (*--f == '/')
   1157 				break;
   1158 			}
   1159 		    }
   1160 		    break;
   1161 		}
   1162 	    }
   1163 	    slash = s;
   1164 	}
   1165 	if (!(*f++ = *s++))
   1166 	    break;
   1167     }
   1168     return file;
   1169 }
   1170 
   1171 #ifdef _WIN32
   1172 /*
   1173  * Convert '\\' to '/' , remove double '/'
   1174  */
   1175 static void
   1176 FcConvertDosPath (char *str)
   1177 {
   1178   size_t len = strlen (str);
   1179   char *p = str;
   1180   char *dest = str;
   1181   char *end = str + len;
   1182   char last = 0;
   1183 
   1184   if (*p == '\\')
   1185     {
   1186       *p = '/';
   1187       p++;
   1188       dest++;
   1189     }
   1190   while (p < end)
   1191     {
   1192       if (*p == '\\')
   1193 	*p = '/';
   1194 
   1195       if (*p != '/'
   1196 	  || last != '/')
   1197 	{
   1198 	  *dest++ = *p;
   1199 	}
   1200 
   1201       last = *p;
   1202       p++;
   1203     }
   1204 
   1205   *dest = 0;
   1206 }
   1207 #endif
   1208 
   1209 FcChar8 *
   1210 FcStrCanonFilename (const FcChar8 *s)
   1211 {
   1212 #ifdef _WIN32
   1213     FcChar8 full[FC_MAX_FILE_LEN + 2];
   1214     int size = GetFullPathName ((LPCSTR) s, sizeof (full) -1,
   1215 				(LPSTR) full, NULL);
   1216 
   1217     if (size == 0)
   1218 	perror ("GetFullPathName");
   1219 
   1220     FcConvertDosPath ((char *) full);
   1221     return FcStrCanonAbsoluteFilename (full);
   1222 #else
   1223     if (s[0] == '/')
   1224 	return FcStrCanonAbsoluteFilename (s);
   1225     else
   1226     {
   1227 	FcChar8	*full;
   1228 	FcChar8 *file;
   1229 
   1230 	FcChar8	cwd[FC_MAX_FILE_LEN + 2];
   1231 	if (getcwd ((char *) cwd, FC_MAX_FILE_LEN) == NULL)
   1232 	    return NULL;
   1233 	full = FcStrBuildFilename (cwd, s, NULL);
   1234 	file = FcStrCanonAbsoluteFilename (full);
   1235 	FcStrFree (full);
   1236 	return file;
   1237     }
   1238 #endif
   1239 }
   1240 
   1241 
   1242 FcStrSet *
   1243 FcStrSetCreate (void)
   1244 {
   1245     return FcStrSetCreateEx (FCSS_DEFAULT);
   1246 }
   1247 
   1248 FcStrSet *
   1249 FcStrSetCreateEx (unsigned int control)
   1250 {
   1251     FcStrSet	*set = malloc (sizeof (FcStrSet));
   1252     if (!set)
   1253 	return 0;
   1254     FcRefInit (&set->ref, 1);
   1255     set->num = 0;
   1256     set->size = 0;
   1257     set->strs = 0;
   1258     set->control = control;
   1259     return set;
   1260 }
   1261 
   1262 static FcBool
   1263 _FcStrSetGrow (FcStrSet *set, int growElements)
   1264 {
   1265     /* accommodate an additional NULL entry at the end of the array */
   1266     FcChar8 **strs = malloc ((set->size + growElements + 1) * sizeof (FcChar8 *));
   1267     if (!strs)
   1268         return FcFalse;
   1269     if (set->num)
   1270         memcpy (strs, set->strs, set->num * sizeof (FcChar8 *));
   1271     if (set->strs)
   1272         free (set->strs);
   1273     set->size = set->size + growElements;
   1274     set->strs = strs;
   1275     return FcTrue;
   1276 }
   1277 
   1278 static FcBool
   1279 _FcStrSetInsert (FcStrSet *set, FcChar8 *s, int pos)
   1280 {
   1281     if (!FcStrSetHasControlBit (set, FCSS_ALLOW_DUPLICATES))
   1282     {
   1283         if (FcStrSetMember (set, s))
   1284         {
   1285             FcStrFree (s);
   1286             return FcTrue;
   1287         }
   1288     }
   1289     if (set->num == set->size)
   1290     {
   1291         int growElements = FcStrSetHasControlBit (set, FCSS_GROW_BY_64) ? 64 : 1;
   1292         if (!_FcStrSetGrow(set, growElements))
   1293             return FcFalse;
   1294     }
   1295     if (pos >= set->num)
   1296     {
   1297 	set->strs[set->num++] = s;
   1298 	set->strs[set->num] = 0;
   1299     }
   1300     else
   1301     {
   1302 	int i;
   1303 
   1304 	set->num++;
   1305 	set->strs[set->num] = 0;
   1306 	for (i = set->num - 1; i > pos; i--)
   1307 	    set->strs[i] = set->strs[i - 1];
   1308 	set->strs[pos] = s;
   1309     }
   1310     return FcTrue;
   1311 }
   1312 
   1313 FcBool
   1314 FcStrSetMember (FcStrSet *set, const FcChar8 *s)
   1315 {
   1316     int	i;
   1317 
   1318     for (i = 0; i < set->num; i++)
   1319 	if (!FcStrCmp (set->strs[i], s))
   1320 	    return FcTrue;
   1321     return FcFalse;
   1322 }
   1323 
   1324 static int
   1325 fc_strcmp_r (const FcChar8 *s1, const FcChar8 *s2, const FcChar8 **ret)
   1326 {
   1327     FcChar8 c1, c2;
   1328 
   1329     if (s1 == s2)
   1330     {
   1331 	if (ret)
   1332 	    *ret = NULL;
   1333 	return 0;
   1334     }
   1335     for (;;)
   1336     {
   1337 	if (s1)
   1338 	    c1 = *s1++;
   1339 	else
   1340 	    c1 = 0;
   1341 	if (s2)
   1342 	    c2 = *s2++;
   1343 	else
   1344 	    c2 = 0;
   1345 	if (!c1 || c1 != c2)
   1346 	    break;
   1347     }
   1348     if (ret)
   1349 	*ret = s1;
   1350     return (int) c1  - (int) c2;
   1351 }
   1352 
   1353 FcBool
   1354 FcStrSetMemberAB (FcStrSet *set, const FcChar8 *a, FcChar8 *b, FcChar8 **ret)
   1355 {
   1356     int i;
   1357     const FcChar8 *s = NULL;
   1358 
   1359     for (i = 0; i < set->num; i++)
   1360     {
   1361 	if (!fc_strcmp_r (set->strs[i], a, &s) && s)
   1362 	{
   1363 	    if (!fc_strcmp_r (s, b, NULL))
   1364 	    {
   1365 		if (ret)
   1366 		    *ret = set->strs[i];
   1367 		return FcTrue;
   1368 	    }
   1369 	}
   1370     }
   1371     if (ret)
   1372 	*ret = NULL;
   1373     return FcFalse;
   1374 }
   1375 
   1376 FcBool
   1377 FcStrSetEqual (FcStrSet *sa, FcStrSet *sb)
   1378 {
   1379     int	i;
   1380     if (sa->num != sb->num)
   1381 	return FcFalse;
   1382     for (i = 0; i < sa->num; i++)
   1383 	if (!FcStrSetMember (sb, sa->strs[i]))
   1384 	    return FcFalse;
   1385     return FcTrue;
   1386 }
   1387 
   1388 FcBool
   1389 FcStrSetAdd (FcStrSet *set, const FcChar8 *s)
   1390 {
   1391     FcChar8 *new = FcStrCopy (s);
   1392     if (!new)
   1393 	return FcFalse;
   1394     if (!_FcStrSetInsert (set, new, set->num))
   1395     {
   1396 	FcStrFree (new);
   1397 	return FcFalse;
   1398     }
   1399     return FcTrue;
   1400 }
   1401 
   1402 FcBool
   1403 FcStrSetInsert (FcStrSet *set, const FcChar8 *s, int pos)
   1404 {
   1405     FcChar8 *new = FcStrCopy (s);
   1406     if (!new)
   1407 	return FcFalse;
   1408     if (!_FcStrSetInsert (set, new, pos))
   1409     {
   1410 	FcStrFree (new);
   1411 	return FcFalse;
   1412     }
   1413     return FcTrue;
   1414 }
   1415 
   1416 FcBool
   1417 FcStrSetAddTriple (FcStrSet *set, const FcChar8 *a, const FcChar8 *b, const FcChar8 *c)
   1418 {
   1419     FcChar8 *new = FcStrMakeTriple (a, b, c);
   1420     if (!new)
   1421 	return FcFalse;
   1422     if (!_FcStrSetInsert (set, new, set->num))
   1423     {
   1424 	FcStrFree (new);
   1425 	return FcFalse;
   1426     }
   1427     return FcTrue;
   1428 }
   1429 
   1430 const FcChar8 *
   1431 FcStrTripleSecond (FcChar8 *str)
   1432 {
   1433     FcChar8 *second = str + strlen((char *) str) + 1;
   1434 
   1435     if (*second == '\0')
   1436 	return 0;
   1437     return second;
   1438 }
   1439 
   1440 const FcChar8 *
   1441 FcStrTripleThird (FcChar8 *str)
   1442 {
   1443     FcChar8 *second = str + strlen ((char *) str) + 1;
   1444     FcChar8 *third = second + strlen ((char *) second) + 1;
   1445 
   1446     if (*third == '\0')
   1447 	return 0;
   1448     return third;
   1449 }
   1450 
   1451 FcBool
   1452 FcStrSetAddFilename (FcStrSet *set, const FcChar8 *s)
   1453 {
   1454     FcChar8 *new = FcStrCopyFilename (s);
   1455     if (!new)
   1456 	return FcFalse;
   1457     if (!_FcStrSetInsert (set, new, set->num))
   1458     {
   1459 	FcStrFree (new);
   1460 	return FcFalse;
   1461     }
   1462     return FcTrue;
   1463 }
   1464 
   1465 FcBool
   1466 FcStrSetAddFilenamePairWithSalt (FcStrSet *set, const FcChar8 *a, const FcChar8 *b, const FcChar8 *salt)
   1467 {
   1468     FcChar8 *new_a = NULL;
   1469     FcChar8 *new_b = NULL;
   1470     FcBool  ret;
   1471 
   1472     if (a)
   1473     {
   1474 	new_a = FcStrCopyFilename (a);
   1475 	if (!new_a)
   1476 	    return FcFalse;
   1477     }
   1478     if (b)
   1479     {
   1480 	new_b = FcStrCopyFilename(b);
   1481 	if (!new_b)
   1482 	{
   1483 	    if (new_a)
   1484 		FcStrFree(new_a);
   1485 	    return FcFalse;
   1486 	}
   1487     }
   1488     /* Override maps with new one if exists */
   1489     FcStrSetDel (set, new_a);
   1490     ret = FcStrSetAddTriple (set, new_a, new_b, salt);
   1491     if (new_a)
   1492 	FcStrFree (new_a);
   1493     if (new_b)
   1494 	FcStrFree (new_b);
   1495     return ret;
   1496 }
   1497 
   1498 FcBool
   1499 FcStrSetAddLangs (FcStrSet *strs, const char *languages)
   1500 {
   1501     const char *p = languages, *next;
   1502     FcChar8 lang[128] = {0}, *normalized_lang;
   1503     size_t len;
   1504     FcBool ret = FcFalse;
   1505 
   1506     if (!languages)
   1507 	return FcFalse;
   1508 
   1509     while ((next = strchr (p, ':')))
   1510     {
   1511 	len = next - p;
   1512 	len = FC_MIN (len, 127);
   1513 	strncpy ((char *) lang, p, len);
   1514 	lang[len] = 0;
   1515 	/* ignore an empty item */
   1516 	if (*lang)
   1517 	{
   1518 	    normalized_lang = FcLangNormalize ((const FcChar8 *) lang);
   1519 	    if (normalized_lang)
   1520 	    {
   1521 		FcStrSetAdd (strs, normalized_lang);
   1522 		FcStrFree (normalized_lang);
   1523 		ret = FcTrue;
   1524 	    }
   1525 	}
   1526 	p = next + 1;
   1527     }
   1528     if (*p)
   1529     {
   1530 	normalized_lang = FcLangNormalize ((const FcChar8 *) p);
   1531 	if (normalized_lang)
   1532 	{
   1533 	    FcStrSetAdd (strs, normalized_lang);
   1534 	    FcStrFree (normalized_lang);
   1535 	    ret = FcTrue;
   1536 	}
   1537     }
   1538 
   1539     return ret;
   1540 }
   1541 
   1542 FcBool
   1543 FcStrSetDel (FcStrSet *set, const FcChar8 *s)
   1544 {
   1545     int	i;
   1546 
   1547     for (i = 0; i < set->num; i++)
   1548 	if (!FcStrCmp (set->strs[i], s))
   1549 	{
   1550 	    FcStrFree (set->strs[i]);
   1551 	    /*
   1552 	     * copy remaining string pointers and trailing
   1553 	     * NULL
   1554 	     */
   1555 	    memmove (&set->strs[i], &set->strs[i+1],
   1556 		     (set->num - i) * sizeof (FcChar8 *));
   1557 	    set->num--;
   1558 	    return FcTrue;
   1559 	}
   1560     return FcFalse;
   1561 }
   1562 
   1563 FcBool
   1564 FcStrSetDeleteAll (FcStrSet *set)
   1565 {
   1566     int i;
   1567 
   1568     if (FcRefIsConst (&set->ref))
   1569 	return FcFalse;
   1570 
   1571     for (i = set->num; i > 0; i--)
   1572     {
   1573 	FcStrFree (set->strs[i - 1]);
   1574 	set->num--;
   1575     }
   1576     return FcTrue;
   1577 }
   1578 
   1579 /* TODO Make public */
   1580 static FcStrSet *
   1581 FcStrSetReference (FcStrSet *set)
   1582 {
   1583     if (FcRefIsConst (&set->ref))
   1584 	return set;
   1585 
   1586     FcRefInc (&set->ref);
   1587     return set;
   1588 }
   1589 
   1590 void
   1591 FcStrSetDestroy (FcStrSet *set)
   1592 {
   1593     if (set)
   1594     {
   1595 	int	i;
   1596 
   1597 	/* We rely on this in FcGetDefaultLangs for caching. */
   1598 	if (FcRefIsConst (&set->ref))
   1599 	    return;
   1600 
   1601 	if (FcRefDec (&set->ref) != 1)
   1602 	    return;
   1603 
   1604 	for (i = 0; i < set->num; i++)
   1605 	    FcStrFree (set->strs[i]);
   1606 	if (set->strs)
   1607 	    free (set->strs);
   1608 	free (set);
   1609     }
   1610 }
   1611 
   1612 FcStrList *
   1613 FcStrListCreate (FcStrSet *set)
   1614 {
   1615     FcStrList	*list;
   1616 
   1617     list = malloc (sizeof (FcStrList));
   1618     if (!list)
   1619 	return 0;
   1620     list->set = set;
   1621     FcStrSetReference (set);
   1622     list->n = 0;
   1623     return list;
   1624 }
   1625 
   1626 void
   1627 FcStrListFirst (FcStrList *list)
   1628 {
   1629     list->n = 0;
   1630 }
   1631 
   1632 FcChar8 *
   1633 FcStrListNext (FcStrList *list)
   1634 {
   1635     if (list->n >= list->set->num)
   1636 	return 0;
   1637     return list->set->strs[list->n++];
   1638 }
   1639 
   1640 void
   1641 FcStrListDone (FcStrList *list)
   1642 {
   1643     FcStrSetDestroy (list->set);
   1644     free (list);
   1645 }
   1646 
   1647 #define __fcstr__
   1648 #include "fcaliastail.h"
   1649 #undef __fcstr__
   1650