/*
- * $XFree86: xc/lib/fontconfig/src/fcstr.c,v 1.7 2002/07/13 05:43:25 keithp Exp $
+ * fontconfig/src/fcstr.c
*
- * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
+ * Copyright © 2000 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
- * documentation, and that the name of Keith Packard not be used in
+ * documentation, and that the name of the author(s) not be used in
* advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. Keith Packard makes no
+ * specific, written prior permission. The authors make no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
- * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+#include "fcint.h"
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
-#include "fcint.h"
+
+
+/* Objects MT-safe for readonly access. */
FcChar8 *
FcStrCopy (const FcChar8 *s)
{
- FcChar8 *r;
-
- if (!s)
- return 0;
- r = (FcChar8 *) malloc (strlen ((char *) s) + 1);
- if (!r)
- return 0;
- FcMemAlloc (FC_MEM_STRING, strlen ((char *) s) + 1);
- strcpy ((char *) r, (char *) s);
- return r;
+ return FcStrdup (s);
}
FcChar8 *
FcStrPlus (const FcChar8 *s1, const FcChar8 *s2)
{
- int l = strlen ((char *)s1) + strlen ((char *) s2) + 1;
+ int s1l = strlen ((char *) s1);
+ int s2l = strlen ((char *) s2);
+ int l = s1l + s2l + 1;
FcChar8 *s = malloc (l);
if (!s)
return 0;
- FcMemAlloc (FC_MEM_STRING, l);
- strcpy ((char *) s, (char *) s1);
- strcat ((char *) s, (char *) s2);
+ memcpy (s, s1, s1l);
+ memcpy (s + s1l, s2, s2l + 1);
return s;
}
void
FcStrFree (FcChar8 *s)
{
- FcMemFree (FC_MEM_STRING, strlen ((char *) s) + 1);
free (s);
}
+
+#include "../fc-case/fccase.h"
+
+#define FcCaseFoldUpperCount(cf) \
+ ((cf)->method == FC_CASE_FOLD_FULL ? 1 : (cf)->count)
+
+typedef struct _FcCaseWalker {
+ const FcChar8 *read;
+ const FcChar8 *src;
+ FcChar8 utf8[FC_MAX_CASE_FOLD_CHARS + 1];
+} FcCaseWalker;
+
+static void
+FcStrCaseWalkerInit (const FcChar8 *src, FcCaseWalker *w)
+{
+ w->src = src;
+ w->read = 0;
+}
+
+static FcChar8
+FcStrCaseWalkerLong (FcCaseWalker *w, FcChar8 r)
+{
+ FcChar32 ucs4;
+ int slen;
+ int len = strlen((char*)w->src);
+
+ slen = FcUtf8ToUcs4 (w->src - 1, &ucs4, len + 1);
+ if (slen <= 0)
+ return r;
+ if (FC_MIN_FOLD_CHAR <= ucs4 && ucs4 <= FC_MAX_FOLD_CHAR)
+ {
+ int min = 0;
+ int max = FC_NUM_CASE_FOLD;
+
+ while (min <= max)
+ {
+ int mid = (min + max) >> 1;
+ FcChar32 low = fcCaseFold[mid].upper;
+ FcChar32 high = low + FcCaseFoldUpperCount (&fcCaseFold[mid]);
+
+ if (high <= ucs4)
+ min = mid + 1;
+ else if (ucs4 < low)
+ max = mid - 1;
+ else
+ {
+ const FcCaseFold *fold = &fcCaseFold[mid];
+ int dlen;
+
+ switch (fold->method) {
+ case FC_CASE_FOLD_EVEN_ODD:
+ if ((ucs4 & 1) != (fold->upper & 1))
+ return r;
+ /* fall through ... */
+ default:
+ dlen = FcUcs4ToUtf8 (ucs4 + fold->offset, w->utf8);
+ break;
+ case FC_CASE_FOLD_FULL:
+ dlen = fold->count;
+ memcpy (w->utf8, fcCaseFoldChars + fold->offset, dlen);
+ break;
+ }
+
+ /* consume rest of src utf-8 bytes */
+ w->src += slen - 1;
+
+ /* read from temp buffer */
+ w->utf8[dlen] = '\0';
+ w->read = w->utf8;
+ return *w->read++;
+ }
+ }
+ }
+ return r;
+}
+
+static FcChar8
+FcStrCaseWalkerNext (FcCaseWalker *w, const char *delims)
+{
+ FcChar8 r;
+
+ if (w->read)
+ {
+ if ((r = *w->read++))
+ return r;
+ w->read = 0;
+ }
+ do
+ {
+ r = *w->src++;
+ } while (r != 0 && delims && strchr (delims, r));
+
+ if ((r & 0xc0) == 0xc0)
+ return FcStrCaseWalkerLong (w, r);
+ if ('A' <= r && r <= 'Z')
+ r = r - 'A' + 'a';
+ return r;
+}
+
+FcChar8 *
+FcStrDowncase (const FcChar8 *s)
+{
+ FcCaseWalker w;
+ int len = 0;
+ FcChar8 *dst, *d;
+
+ FcStrCaseWalkerInit (s, &w);
+ while (FcStrCaseWalkerNext (&w, NULL))
+ len++;
+ d = dst = malloc (len + 1);
+ if (!d)
+ return 0;
+ FcStrCaseWalkerInit (s, &w);
+ while ((*d++ = FcStrCaseWalkerNext (&w, NULL)));
+ return dst;
+}
+
int
FcStrCmpIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
{
- FcChar8 c1, c2;
-
- for (;;)
+ FcCaseWalker w1, w2;
+ FcChar8 c1, c2;
+
+ if (s1 == s2) return 0;
+
+ FcStrCaseWalkerInit (s1, &w1);
+ FcStrCaseWalkerInit (s2, &w2);
+
+ for (;;)
{
- c1 = *s1++;
- c2 = *s2++;
- if (!c1 || !c2)
- break;
- c1 = FcToLower (c1);
- c2 = FcToLower (c2);
- if (c1 != c2)
+ c1 = FcStrCaseWalkerNext (&w1, NULL);
+ c2 = FcStrCaseWalkerNext (&w2, NULL);
+ if (!c1 || (c1 != c2))
break;
}
return (int) c1 - (int) c2;
int
FcStrCmpIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2)
{
- FcChar8 c1, c2;
-
- for (;;)
- {
- do
- c1 = *s1++;
- while (c1 == ' ');
- do
- c2 = *s2++;
- while (c2 == ' ');
- if (!c1 || !c2)
- break;
- c1 = FcToLower (c1);
- c2 = FcToLower (c2);
- if (c1 != c2)
+ return FcStrCmpIgnoreCaseAndDelims (s1, s2, (const FcChar8 *)" ");
+}
+
+int
+FcStrCmpIgnoreCaseAndDelims (const FcChar8 *s1, const FcChar8 *s2, const FcChar8 *delims)
+{
+ FcCaseWalker w1, w2;
+ FcChar8 c1, c2;
+
+ if (s1 == s2) return 0;
+
+ FcStrCaseWalkerInit (s1, &w1);
+ FcStrCaseWalkerInit (s2, &w2);
+
+ for (;;)
+ {
+ c1 = FcStrCaseWalkerNext (&w1, (const char *)delims);
+ c2 = FcStrCaseWalkerNext (&w2, (const char *)delims);
+ if (!c1 || (c1 != c2))
break;
}
return (int) c1 - (int) c2;
FcStrCmp (const FcChar8 *s1, const FcChar8 *s2)
{
FcChar8 c1, c2;
-
+
if (s1 == s2)
return 0;
- for (;;)
+ for (;;)
{
c1 = *s1++;
c2 = *s2++;
- if (!c1 || !c2)
- break;
- if (c1 != c2)
+ if (!c1 || c1 != c2)
break;
}
return (int) c1 - (int) c2;
}
+/*
+ * Return a hash value for a string
+ */
+
+FcChar32
+FcStrHashIgnoreCase (const FcChar8 *s)
+{
+ FcChar32 h = 0;
+ FcCaseWalker w;
+ FcChar8 c;
+
+ FcStrCaseWalkerInit (s, &w);
+ while ((c = FcStrCaseWalkerNext (&w, NULL)))
+ h = ((h << 3) ^ (h >> 3)) ^ c;
+ return h;
+}
+
+/*
+ * Is the head of s1 equal to s2?
+ */
+
+static FcBool
+FcStrIsAtIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2)
+{
+ FcCaseWalker w1, w2;
+ FcChar8 c1, c2;
+
+ FcStrCaseWalkerInit (s1, &w1);
+ FcStrCaseWalkerInit (s2, &w2);
+
+ for (;;)
+ {
+ c1 = FcStrCaseWalkerNext (&w1, " ");
+ c2 = FcStrCaseWalkerNext (&w2, " ");
+ if (!c1 || (c1 != c2))
+ break;
+ }
+ return c1 == c2 || !c2;
+}
+
+/*
+ * Does s1 contain an instance of s2 (ignoring blanks and case)?
+ */
+
+const FcChar8 *
+FcStrContainsIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2)
+{
+ while (*s1)
+ {
+ if (FcStrIsAtIgnoreBlanksAndCase (s1, s2))
+ return s1;
+ s1++;
+ }
+ return 0;
+}
+
+static FcBool
+FcCharIsPunct (const FcChar8 c)
+{
+ if (c < '0')
+ return FcTrue;
+ if (c <= '9')
+ return FcFalse;
+ if (c < 'A')
+ return FcTrue;
+ if (c <= 'Z')
+ return FcFalse;
+ if (c < 'a')
+ return FcTrue;
+ if (c <= 'z')
+ return FcFalse;
+ if (c <= '~')
+ return FcTrue;
+ return FcFalse;
+}
+
+/*
+ * Is the head of s1 equal to s2?
+ */
+
+static FcBool
+FcStrIsAtIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
+{
+ FcCaseWalker w1, w2;
+ FcChar8 c1, c2;
+
+ FcStrCaseWalkerInit (s1, &w1);
+ FcStrCaseWalkerInit (s2, &w2);
+
+ for (;;)
+ {
+ c1 = FcStrCaseWalkerNext (&w1, NULL);
+ c2 = FcStrCaseWalkerNext (&w2, NULL);
+ if (!c1 || (c1 != c2))
+ break;
+ }
+ return c1 == c2 || !c2;
+}
+
+/*
+ * Does s1 contain an instance of s2 (ignoring blanks and case)?
+ */
+
+const FcChar8 *
+FcStrContainsIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
+{
+ while (*s1)
+ {
+ if (FcStrIsAtIgnoreCase (s1, s2))
+ return s1;
+ s1++;
+ }
+ return 0;
+}
+
+/*
+ * Does s1 contain an instance of s2 on a word boundary (ignoring case)?
+ */
+
+const FcChar8 *
+FcStrContainsWord (const FcChar8 *s1, const FcChar8 *s2)
+{
+ FcBool wordStart = FcTrue;
+ int s1len = strlen ((char *) s1);
+ int s2len = strlen ((char *) s2);
+
+ while (s1len >= s2len)
+ {
+ if (wordStart &&
+ FcStrIsAtIgnoreCase (s1, s2) &&
+ (s1len == s2len || FcCharIsPunct (s1[s2len])))
+ {
+ return s1;
+ }
+ wordStart = FcFalse;
+ if (FcCharIsPunct (*s1))
+ wordStart = FcTrue;
+ s1++;
+ s1len--;
+ }
+ return 0;
+}
+
+/*
+ * returns the number of strings (ignoring delimitors and case) being matched
+ */
+
+int
+FcStrMatchIgnoreCaseAndDelims (const FcChar8 *s1, const FcChar8 *s2, const FcChar8 *delims)
+{
+ FcCaseWalker w1, w2;
+ FcChar8 c1, c2;
+
+ if (s1 == s2) return 0;
+
+ FcStrCaseWalkerInit (s1, &w1);
+ FcStrCaseWalkerInit (s2, &w2);
+
+ for (;;)
+ {
+ c1 = FcStrCaseWalkerNext (&w1, (const char *)delims);
+ c2 = FcStrCaseWalkerNext (&w2, (const char *)delims);
+ if (!c1 || (c1 != c2))
+ break;
+ }
+ return w1.src - s1 - 1;
+}
+
+FcBool
+FcStrGlobMatch (const FcChar8 *glob,
+ const FcChar8 *string)
+{
+ FcChar8 c;
+
+ while ((c = *glob++))
+ {
+ switch (c) {
+ case '*':
+ /* short circuit common case */
+ if (!*glob)
+ return FcTrue;
+ /* short circuit another common case */
+ if (strchr ((char *) glob, '*') == 0)
+ {
+ size_t l1, l2;
+
+ l1 = strlen ((char *) string);
+ l2 = strlen ((char *) glob);
+ if (l1 < l2)
+ return FcFalse;
+ string += (l1 - l2);
+ }
+ while (*string)
+ {
+ if (FcStrGlobMatch (glob, string))
+ return FcTrue;
+ string++;
+ }
+ return FcFalse;
+ case '?':
+ if (*string++ == '\0')
+ return FcFalse;
+ break;
+ default:
+ if (*string++ != c)
+ return FcFalse;
+ break;
+ }
+ }
+ return *string == '\0';
+}
+
+const FcChar8 *
+FcStrStrIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
+{
+ FcCaseWalker w1, w2;
+ FcChar8 c1, c2;
+ const FcChar8 *cur;
+
+ if (!s1 || !s2)
+ return 0;
+
+ if (s1 == s2)
+ return s1;
+
+ FcStrCaseWalkerInit (s1, &w1);
+ FcStrCaseWalkerInit (s2, &w2);
+
+ c2 = FcStrCaseWalkerNext (&w2, NULL);
+
+ for (;;)
+ {
+ cur = w1.src;
+ c1 = FcStrCaseWalkerNext (&w1, NULL);
+ if (!c1)
+ break;
+ if (c1 == c2)
+ {
+ FcCaseWalker w1t = w1;
+ FcCaseWalker w2t = w2;
+ FcChar8 c1t, c2t;
+
+ for (;;)
+ {
+ c1t = FcStrCaseWalkerNext (&w1t, NULL);
+ c2t = FcStrCaseWalkerNext (&w2t, NULL);
+
+ if (!c2t)
+ return cur;
+ if (c2t != c1t)
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+const FcChar8 *
+FcStrStr (const FcChar8 *s1, const FcChar8 *s2)
+{
+ FcChar8 c1, c2;
+ const FcChar8 * p = s1;
+ const FcChar8 * b = s2;
+
+ if (!s1 || !s2)
+ return 0;
+
+ if (s1 == s2)
+ return s1;
+
+again:
+ c2 = *s2++;
+
+ if (!c2)
+ return 0;
+
+ for (;;)
+ {
+ p = s1;
+ c1 = *s1++;
+ if (!c1 || c1 == c2)
+ break;
+ }
+
+ if (c1 != c2)
+ return 0;
+
+ for (;;)
+ {
+ c1 = *s1;
+ c2 = *s2;
+ if (c1 && c2 && c1 != c2)
+ {
+ s1 = p + 1;
+ s2 = b;
+ goto again;
+ }
+ if (!c2)
+ return p;
+ if (!c1)
+ return 0;
+ ++ s1;
+ ++ s2;
+ }
+ /* never reached. */
+}
+
int
FcUtf8ToUcs4 (const FcChar8 *src_orig,
FcChar32 *dst,
if (len == 0)
return 0;
-
+
s = *src++;
len--;
-
+
if (!(s & 0x80))
{
result = s;
extra = 0;
- }
+ }
else if (!(s & 0x40))
{
return -1;
}
if (extra > len)
return -1;
-
+
while (extra--)
{
result <<= 6;
int clen;
FcChar32 c;
FcChar32 max;
-
+
n = 0;
max = 0;
while (len)
{
int bits;
FcChar8 *d = dest;
-
+
if (ucs4 < 0x80) { *d++= ucs4; bits= -6; }
else if (ucs4 < 0x800) { *d++= ((ucs4 >> 6) & 0x1F) | 0xC0; bits= 0; }
else if (ucs4 < 0x10000) { *d++= ((ucs4 >> 12) & 0x0F) | 0xE0; bits= 6; }
if (len < 2)
return 0;
-
+
a = GetUtf16 (src, endian); src += 2; len -= 2;
-
- /*
- * Check for surrogate
+
+ /*
+ * Check for surrogate
*/
if ((a & 0xfc00) == 0xd800)
{
if ((b & 0xfc00) != 0xdc00)
return 0;
result = ((((FcChar32) a & 0x3ff) << 10) |
- ((FcChar32) b & 0x3ff)) | 0x10000;
+ ((FcChar32) b & 0x3ff)) + 0x10000;
}
else
result = a;
int clen;
FcChar32 c;
FcChar32 max;
-
+
n = 0;
max = 0;
while (len)
void
FcStrBufInit (FcStrBuf *buf, FcChar8 *init, int size)
{
- buf->buf = init;
+ if (init)
+ {
+ buf->buf = init;
+ buf->size = size;
+ } else
+ {
+ buf->buf = buf->buf_static;
+ buf->size = sizeof (buf->buf_static);
+ }
buf->allocated = FcFalse;
buf->failed = FcFalse;
buf->len = 0;
- buf->size = size;
}
void
{
FcChar8 *ret;
- ret = malloc (buf->len + 1);
+ if (buf->failed)
+ ret = NULL;
+ else
+ ret = malloc (buf->len + 1);
if (ret)
{
memcpy (ret, buf->buf, buf->len);
return ret;
}
+FcChar8 *
+FcStrBufDoneStatic (FcStrBuf *buf)
+{
+ FcStrBufChar (buf, '\0');
+
+ if (buf->failed)
+ return NULL;
+
+ return buf->buf;
+}
+
FcBool
FcStrBufChar (FcStrBuf *buf, FcChar8 c)
{
FcChar8 *new;
int size;
+ if (buf->failed)
+ return FcFalse;
+
if (buf->allocated)
{
size = buf->size * 2;
}
else
{
- size = buf->size + 1024;
+ size = buf->size + 64;
new = malloc (size);
if (new)
{
return FcTrue;
}
+FcBool
+FcStrUsesHome (const FcChar8 *s)
+{
+ return *s == '~';
+}
+
+FcChar8 *
+FcStrBuildFilename (const FcChar8 *path,
+ ...)
+{
+ va_list ap;
+ FcStrSet *sset;
+ FcStrList *list;
+ FcChar8 *s, *ret = NULL, *p;
+ size_t len = 0;
+
+ if (!path)
+ return NULL;
+
+ sset = FcStrSetCreateEx (FCSS_ALLOW_DUPLICATES | FCSS_GROW_BY_64);
+ if (!sset)
+ return NULL;
+
+ if (!FcStrSetAdd (sset, path))
+ goto bail0;
+
+ va_start (ap, path);
+ while (1)
+ {
+ s = (FcChar8 *)va_arg (ap, FcChar8 *);
+ if (!s)
+ break;
+ if (!FcStrSetAdd (sset, s))
+ goto bail1;
+ }
+ list = FcStrListCreate (sset);
+ while ((s = FcStrListNext (list)))
+ {
+ len += strlen ((const char *)s) + 1;
+ }
+ list->n = 0;
+ ret = malloc (sizeof (FcChar8) * (len + 1));
+ if (!ret)
+ goto bail2;
+ p = ret;
+ while ((s = FcStrListNext (list)))
+ {
+ if (p != ret)
+ {
+ p[0] = FC_DIR_SEPARATOR;
+ p++;
+ }
+ len = strlen ((const char *)s);
+ memcpy (p, s, len);
+ p += len;
+ }
+ *p = 0;
+
+bail2:
+ FcStrListDone (list);
+bail1:
+ va_end (ap);
+bail0:
+ FcStrSetDestroy (sset);
+
+ return ret;
+}
+
FcChar8 *
FcStrCopyFilename (const FcChar8 *s)
{
FcChar8 *new;
-
+
if (*s == '~')
{
- FcChar8 *home = (FcChar8 *) getenv ("HOME");
- int size = strlen ((char *) home) + strlen ((char *) s);
+ FcChar8 *home = FcConfigHome ();
+ FcChar8 *full;
+ int size;
if (!home)
- return 0;
- new = (FcChar8 *) malloc (size);
- if (!new)
- return 0;
- FcMemAlloc (FC_MEM_STRING, size);
- strcpy ((char *) new, (char *) home);
- strcat ((char *) new, (char *) s + 1);
+ return NULL;
+ size = strlen ((char *) home) + strlen ((char *) s);
+ full = (FcChar8 *) malloc (size);
+ if (!full)
+ return NULL;
+ strcpy ((char *) full, (char *) home);
+ strcat ((char *) full, (char *) s + 1);
+ new = FcStrCanonFilename (full);
+ free (full);
}
else
+ new = FcStrCanonFilename (s);
+
+ return new;
+}
+
+FcChar8 *
+FcStrLastSlash (const FcChar8 *path)
+{
+ FcChar8 *slash;
+
+ slash = (FcChar8 *) strrchr ((const char *) path, '/');
+#ifdef _WIN32
{
- int size = strlen ((char *) s) + 1;
- new = (FcChar8 *) malloc (size);
- if (!new)
- return 0;
- FcMemAlloc (FC_MEM_STRING, size);
- strcpy ((char *) new, (const char *) s);
+ FcChar8 *backslash;
+
+ backslash = (FcChar8 *) strrchr ((const char *) path, '\\');
+ if (!slash || (backslash && backslash > slash))
+ slash = backslash;
}
- return new;
+#endif
+
+ return slash;
}
FcChar8 *
FcChar8 *slash;
FcChar8 *dir;
- slash = (FcChar8 *) strrchr ((char *) file, '/');
+ slash = FcStrLastSlash (file);
if (!slash)
return FcStrCopy ((FcChar8 *) ".");
dir = malloc ((slash - file) + 1);
if (!dir)
return 0;
- FcMemAlloc (FC_MEM_STRING, (slash - file) + 1);
strncpy ((char *) dir, (const char *) file, slash - file);
dir[slash - file] = '\0';
return dir;
{
FcChar8 *slash;
- slash = (FcChar8 *) strrchr ((char *) file, '/');
+ slash = FcStrLastSlash (file);
if (!slash)
return FcStrCopy (file);
return FcStrCopy (slash + 1);
}
+static FcChar8 *
+FcStrCanonAbsoluteFilename (const FcChar8 *s)
+{
+ FcChar8 *file;
+ FcChar8 *f;
+ const FcChar8 *slash;
+ int size;
+
+ size = strlen ((char *) s) + 1;
+ file = malloc (size);
+ if (!file)
+ return NULL;
+ slash = NULL;
+ f = file;
+#ifdef _WIN32
+ if (*s == '/' && *(s+1) == '/') /* Network path, do not squash // */
+ *f++ = *s++;
+#endif
+ for (;;) {
+ if (*s == '/' || *s == '\0')
+ {
+ if (slash)
+ {
+ switch (s - slash) {
+ case 1:
+ f -= 1; /* squash // and trim final / from file */
+ break;
+ case 2:
+ if (!strncmp ((char *) slash, "/.", 2))
+ {
+ f -= 2; /* trim /. from file */
+ }
+ break;
+ case 3:
+ if (!strncmp ((char *) slash, "/..", 3))
+ {
+ f -= 3; /* trim /.. from file */
+ while (f > file) {
+ if (*--f == '/')
+ break;
+ }
+ }
+ break;
+ }
+ }
+ slash = s;
+ }
+ if (!(*f++ = *s++))
+ break;
+ }
+ return file;
+}
+
+#ifdef _WIN32
+/*
+ * Convert '\\' to '/' , remove double '/'
+ */
+static void
+FcConvertDosPath (char *str)
+{
+ size_t len = strlen (str);
+ char *p = str;
+ char *dest = str;
+ char *end = str + len;
+ char last = 0;
+
+ if (*p == '\\')
+ {
+ *p = '/';
+ p++;
+ dest++;
+ }
+ while (p < end)
+ {
+ if (*p == '\\')
+ *p = '/';
+
+ if (*p != '/'
+ || last != '/')
+ {
+ *dest++ = *p;
+ }
+
+ last = *p;
+ p++;
+ }
+
+ *dest = 0;
+}
+#endif
+
+FcChar8 *
+FcStrCanonFilename (const FcChar8 *s)
+{
+#ifdef _WIN32
+ FcChar8 full[FC_MAX_FILE_LEN + 2];
+ int size = GetFullPathName ((LPCSTR) s, sizeof (full) -1,
+ (LPSTR) full, NULL);
+
+ if (size == 0)
+ perror ("GetFullPathName");
+
+ FcConvertDosPath ((char *) full);
+ return FcStrCanonAbsoluteFilename (full);
+#else
+ if (s[0] == '/')
+ return FcStrCanonAbsoluteFilename (s);
+ else
+ {
+ FcChar8 *full;
+ FcChar8 *file;
+
+ FcChar8 cwd[FC_MAX_FILE_LEN + 2];
+ if (getcwd ((char *) cwd, FC_MAX_FILE_LEN) == NULL)
+ return NULL;
+ full = FcStrBuildFilename (cwd, s, NULL);
+ file = FcStrCanonAbsoluteFilename (full);
+ FcStrFree (full);
+ return file;
+ }
+#endif
+}
+
+
FcStrSet *
FcStrSetCreate (void)
{
+ return FcStrSetCreateEx (FCSS_DEFAULT);
+}
+
+FcStrSet *
+FcStrSetCreateEx (unsigned int control)
+{
FcStrSet *set = malloc (sizeof (FcStrSet));
if (!set)
return 0;
- FcMemAlloc (FC_MEM_STRSET, sizeof (FcStrSet));
- set->ref = 1;
+ FcRefInit (&set->ref, 1);
set->num = 0;
set->size = 0;
set->strs = 0;
+ set->control = control;
return set;
}
static FcBool
+_FcStrSetGrow (FcStrSet *set, int growElements)
+{
+ /* accommodate an additional NULL entry at the end of the array */
+ FcChar8 **strs = malloc ((set->size + growElements + 1) * sizeof (FcChar8 *));
+ if (!strs)
+ return FcFalse;
+ if (set->num)
+ memcpy (strs, set->strs, set->num * sizeof (FcChar8 *));
+ if (set->strs)
+ free (set->strs);
+ set->size = set->size + growElements;
+ set->strs = strs;
+ return FcTrue;
+}
+
+static FcBool
_FcStrSetAppend (FcStrSet *set, FcChar8 *s)
{
- if (FcStrSetMember (set, s))
+ if (!FcStrSetHasControlBit (set, FCSS_ALLOW_DUPLICATES))
{
- FcStrFree (s);
- return FcTrue;
+ if (FcStrSetMember (set, s))
+ {
+ FcStrFree (s);
+ return FcTrue;
+ }
}
if (set->num == set->size)
{
- FcChar8 **strs = malloc ((set->size + 2) * sizeof (FcChar8 *));
-
- if (!strs)
- return FcFalse;
- FcMemAlloc (FC_MEM_STRSET, (set->size + 2) * sizeof (FcChar8 *));
- set->size = set->size + 1;
- if (set->num)
- memcpy (strs, set->strs, set->num * sizeof (FcChar8 *));
- if (set->strs)
- free (set->strs);
- set->strs = strs;
+ int growElements = FcStrSetHasControlBit (set, FCSS_GROW_BY_64) ? 64 : 1;
+ if (!_FcStrSetGrow(set, growElements))
+ return FcFalse;
}
set->strs[set->num++] = s;
set->strs[set->num] = 0;
}
FcBool
+FcStrSetAddLangs (FcStrSet *strs, const char *languages)
+{
+ const char *p = languages, *next;
+ FcChar8 lang[128] = {0}, *normalized_lang;
+ size_t len;
+ FcBool ret = FcFalse;
+
+ if (!languages)
+ return FcFalse;
+
+ while ((next = strchr (p, ':')))
+ {
+ len = next - p;
+ len = FC_MIN (len, 127);
+ strncpy ((char *) lang, p, len);
+ lang[len] = 0;
+ /* ignore an empty item */
+ if (*lang)
+ {
+ normalized_lang = FcLangNormalize ((const FcChar8 *) lang);
+ if (normalized_lang)
+ {
+ FcStrSetAdd (strs, normalized_lang);
+ FcStrFree (normalized_lang);
+ ret = FcTrue;
+ }
+ }
+ p = next + 1;
+ }
+ if (*p)
+ {
+ normalized_lang = FcLangNormalize ((const FcChar8 *) p);
+ if (normalized_lang)
+ {
+ FcStrSetAdd (strs, normalized_lang);
+ FcStrFree (normalized_lang);
+ ret = FcTrue;
+ }
+ }
+
+ return ret;
+}
+
+FcBool
FcStrSetDel (FcStrSet *set, const FcChar8 *s)
{
int i;
* copy remaining string pointers and trailing
* NULL
*/
- memmove (&set->strs[i], &set->strs[i+1],
+ memmove (&set->strs[i], &set->strs[i+1],
(set->num - i) * sizeof (FcChar8 *));
set->num--;
return FcTrue;
return FcFalse;
}
+/* TODO Make public */
+static FcStrSet *
+FcStrSetReference (FcStrSet *set)
+{
+ if (FcRefIsConst (&set->ref))
+ return set;
+
+ FcRefInc (&set->ref);
+ return set;
+}
+
void
FcStrSetDestroy (FcStrSet *set)
{
- if (--set->ref == 0)
- {
- int i;
-
- for (i = 0; i < set->num; i++)
- FcStrFree (set->strs[i]);
- FcMemFree (FC_MEM_STRSET, (set->size) * sizeof (FcChar8 *));
- if (set->strs)
- free (set->strs);
- FcMemFree (FC_MEM_STRSET, sizeof (FcStrSet));
- free (set);
- }
+ int i;
+
+ /* We rely on this in FcGetDefaultLangs for caching. */
+ if (FcRefIsConst (&set->ref))
+ return;
+
+ if (FcRefDec (&set->ref) != 1)
+ return;
+
+ for (i = 0; i < set->num; i++)
+ FcStrFree (set->strs[i]);
+ if (set->strs)
+ free (set->strs);
+ free (set);
}
FcStrList *
list = malloc (sizeof (FcStrList));
if (!list)
return 0;
- FcMemAlloc (FC_MEM_STRLIST, sizeof (FcStrList));
list->set = set;
- set->ref++;
+ FcStrSetReference (set);
list->n = 0;
return list;
}
+void
+FcStrListFirst (FcStrList *list)
+{
+ list->n = 0;
+}
+
FcChar8 *
FcStrListNext (FcStrList *list)
{
FcStrListDone (FcStrList *list)
{
FcStrSetDestroy (list->set);
- FcMemFree (FC_MEM_STRLIST, sizeof (FcStrList));
free (list);
}
+
+#define __fcstr__
+#include "fcaliastail.h"
+#undef __fcstr__