/*
- * $RCSId: xc/lib/fontconfig/src/fcstr.c,v 1.10 2002/08/31 22:17:32 keithp Exp $
+ * fontconfig/src/fcstr.c
*
* Copyright © 2000 Keith Packard
*
* 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"
+#ifdef _WIN32
+#include <windows.h>
+#endif
FcChar8 *
FcStrCopy (const FcChar8 *s)
{
- FcChar8 *r;
+ int len;
+ FcChar8 *r;
if (!s)
return 0;
- r = (FcChar8 *) malloc (strlen ((char *) s) + 1);
+ len = strlen ((char *) s) + 1;
+ r = (FcChar8 *) malloc (len);
if (!r)
return 0;
- FcMemAlloc (FC_MEM_STRING, strlen ((char *) s) + 1);
- strcpy ((char *) r, (char *) s);
+ FcMemAlloc (FC_MEM_STRING, len);
+ memcpy (r, s, len);
return r;
}
free (s);
}
+
+#include "../fc-case/fccase.h"
+
+#define FcCaseFoldUpperCount(cf) \
+ ((cf)->method == FC_CASE_FOLD_FULL ? 1 : (cf)->count)
+
+#define FC_STR_CANON_BUF_LEN 1024
+
+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)
+{
+ FcChar8 r;
+
+ if (w->read)
+ {
+ if ((r = *w->read++))
+ return r;
+ w->read = 0;
+ }
+ r = *w->src++;
+
+ if ((r & 0xc0) == 0xc0)
+ return FcStrCaseWalkerLong (w, r);
+ if ('A' <= r && r <= 'Z')
+ r = r - 'A' + 'a';
+ return r;
+}
+
+static FcChar8
+FcStrCaseWalkerNextIgnoreBlanks (FcCaseWalker *w)
+{
+ FcChar8 r;
+
+ if (w->read)
+ {
+ if ((r = *w->read++))
+ return r;
+ w->read = 0;
+ }
+ do
+ {
+ r = *w->src++;
+ } while (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))
+ len++;
+ d = dst = malloc (len + 1);
+ if (!d)
+ return 0;
+ FcMemAlloc (FC_MEM_STRING, len + 1);
+ FcStrCaseWalkerInit (s, &w);
+ while ((*d++ = FcStrCaseWalkerNext (&w)));
+ return dst;
+}
+
int
FcStrCmpIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
{
- FcChar8 c1, c2;
+ FcCaseWalker w1, w2;
+ FcChar8 c1, c2;
+
+ if (s1 == s2) return 0;
+
+ FcStrCaseWalkerInit (s1, &w1);
+ FcStrCaseWalkerInit (s2, &w2);
for (;;)
{
- c1 = *s1++;
- c2 = *s2++;
- if (!c1 || (c1 != c2 && (c1 = FcToLower(c1)) != (c2 = FcToLower(c2))))
+ c1 = FcStrCaseWalkerNext (&w1);
+ c2 = FcStrCaseWalkerNext (&w2);
+ if (!c1 || (c1 != c2))
break;
}
return (int) c1 - (int) c2;
int
FcStrCmpIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2)
{
- FcChar8 c1, c2;
+ FcCaseWalker w1, w2;
+ FcChar8 c1, c2;
+
+ if (s1 == s2) return 0;
+
+ FcStrCaseWalkerInit (s1, &w1);
+ FcStrCaseWalkerInit (s2, &w2);
for (;;)
{
- do
- c1 = *s1++;
- while (c1 == ' ');
- do
- c2 = *s2++;
- while (c2 == ' ');
- if (!c1 || (c1 != c2 && (c1 = FcToLower(c1)) != (c2 = FcToLower(c2))))
+ c1 = FcStrCaseWalkerNextIgnoreBlanks (&w1);
+ c2 = FcStrCaseWalkerNextIgnoreBlanks (&w2);
+ if (!c1 || (c1 != c2))
break;
}
return (int) c1 - (int) c2;
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)))
+ 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)
{
- FcChar8 c1, c2;
+ FcCaseWalker w1, w2;
+ FcChar8 c1, c2;
+
+ FcStrCaseWalkerInit (s1, &w1);
+ FcStrCaseWalkerInit (s2, &w2);
for (;;)
{
- do
- c1 = *s1++;
- while (c1 == ' ');
- do
- c2 = *s2++;
- while (c2 == ' ');
- if (!c1 || (c1 != c2 && (c1 = FcToLower(c1)) != (c2 = FcToLower(c2))))
+ c1 = FcStrCaseWalkerNextIgnoreBlanks (&w1);
+ c2 = FcStrCaseWalkerNextIgnoreBlanks (&w2);
+ if (!c1 || (c1 != c2))
break;
}
return c1 == c2 || !c2;
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)
{
- FcChar8 c1, c2;
+ FcCaseWalker w1, w2;
+ FcChar8 c1, c2;
+
+ FcStrCaseWalkerInit (s1, &w1);
+ FcStrCaseWalkerInit (s2, &w2);
for (;;)
{
- c1 = *s1++;
- c2 = *s2++;
- if (!c1 || (c1 != c2 && (c1 = FcToLower(c1)) != (c2 = FcToLower(c2))))
+ c1 = FcStrCaseWalkerNext (&w1);
+ c2 = FcStrCaseWalkerNext (&w2);
+ if (!c1 || (c1 != c2))
break;
}
return c1 == c2 || !c2;
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;
+}
+
const FcChar8 *
FcStrStrIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
{
- FcChar8 c1, c2;
- const FcChar8 * p = s1;
- const FcChar8 * b = s2;
+ FcCaseWalker w1, w2;
+ FcChar8 c1, c2;
+ const FcChar8 *cur;
if (!s1 || !s2)
return 0;
if (s1 == s2)
return s1;
-
-again:
- c2 = *s2++;
- c2 = FcToLower (c2);
-
- if (!c2)
- return 0;
-
- for (;;)
+
+ FcStrCaseWalkerInit (s1, &w1);
+ FcStrCaseWalkerInit (s2, &w2);
+
+ c2 = FcStrCaseWalkerNext (&w2);
+
+ for (;;)
{
- p = s1;
- c1 = *s1++;
- if (!c1 || (c1 = FcToLower (c1)) == c2)
+ cur = w1.src;
+ c1 = FcStrCaseWalkerNext (&w1);
+ if (!c1)
break;
- }
+ if (c1 == c2)
+ {
+ FcCaseWalker w1t = w1;
+ FcCaseWalker w2t = w2;
+ FcChar8 c1t, c2t;
- if (c1 != c2)
- return 0;
+ for (;;)
+ {
+ c1t = FcStrCaseWalkerNext (&w1t);
+ c2t = FcStrCaseWalkerNext (&w2t);
- for (;;)
- {
- c1 = *s1;
- c2 = *s2;
- if (c1 && c2 && (c1 = FcToLower (c1)) != (c2 = FcToLower (c2)))
- {
- s1 = p + 1;
- s2 = b;
- goto again;
+ if (!c2t)
+ return cur;
+ if (c2t != c1t)
+ break;
+ }
}
- if (!c2)
- return p;
- if (!c1)
- return 0;
- ++ s1;
- ++ s2;
}
-
return 0;
}
++ s1;
++ s2;
}
-
- return 0;
+ /* never reached. */
}
int
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)
{
FcMemAlloc (FC_MEM_STRING, buf->len + 1);
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)
{
if (*s == '~')
{
FcChar8 *home = FcConfigHome ();
+ FcChar8 *full;
int size;
if (!home)
return 0;
size = strlen ((char *) home) + strlen ((char *) s);
- new = (FcChar8 *) malloc (size);
- if (!new)
+ full = (FcChar8 *) malloc (size);
+ if (!full)
return 0;
- FcMemAlloc (FC_MEM_STRING, size);
- strcpy ((char *) new, (char *) home);
- strcat ((char *) new, (char *) s + 1);
+ strcpy ((char *) full, (char *) home);
+ strcat ((char *) full, (char *) s + 1);
+ new = FcStrCanonFilename (full);
+ free (full);
}
else
- {
- 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);
- }
+ new = FcStrCanonFilename (s);
return new;
}
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;
+ FcMemAlloc (FC_MEM_STRING, size);
+ slash = NULL;
+ f = file;
+ 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 (s, sizeof (full) -1,
+ full, NULL);
+
+ if (size == 0)
+ perror ("GetFullPathName");
+
+ FcConvertDosPath (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;
+ strcat ((char *) cwd, "/");
+ full = FcStrPlus (cwd, s);
+ file = FcStrCanonAbsoluteFilename (full);
+ FcStrFree (full);
+ return file;
+ }
+#endif
+}
+
+
FcStrSet *
FcStrSetCreate (void)
{
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)
+ {
+ FcMemFree (FC_MEM_STRSET, (set->size + 1) * sizeof (FcChar8 *));
free (set->strs);
+ }
+ set->size = set->size + 1;
set->strs = strs;
}
set->strs[set->num++] = s;
for (i = 0; i < set->num; i++)
FcStrFree (set->strs[i]);
- FcMemFree (FC_MEM_STRSET, (set->size) * sizeof (FcChar8 *));
if (set->strs)
+ {
+ FcMemFree (FC_MEM_STRSET, (set->size + 1) * sizeof (FcChar8 *));
free (set->strs);
+ }
FcMemFree (FC_MEM_STRSET, sizeof (FcStrSet));
free (set);
}
FcMemFree (FC_MEM_STRLIST, sizeof (FcStrList));
free (list);
}
+
+#define __fcstr__
+#include "fcaliastail.h"
+#undef __fcstr__