(root)/
fontconfig-2.14.2/
src/
fcstr.c
       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__