* PERFORMANCE OF THIS SOFTWARE.
*/
+#include "fcint.h"
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
-#include "fcint.h"
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;
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;
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
}
else
{
- size = buf->size + 1024;
+ size = buf->size + 64;
new = malloc (size);
if (new)
{
if (!new)
return 0;
FcMemAlloc (FC_MEM_STRING, size);
- strcpy ((char *) new, (const char *) s);
+ memcpy (new, s, size);
}
return new;
}
return FcStrCopy (slash + 1);
}
+FcChar8 *
+FcStrCanonFilename (const FcChar8 *s)
+{
+ FcChar8 *file;
+ FcChar8 *f;
+ const FcChar8 *slash;
+
+ if (*s != '/')
+ {
+ FcChar8 *full;
+
+ 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 = FcStrCanonFilename (full);
+ FcStrFree (full);
+ return file;
+ }
+ file = malloc (strlen ((char *) s) + 1);
+ if (!file)
+ return NULL;
+ slash = NULL;
+ f = file;
+ for (;;) {
+ if (*s == '/' || *s == '\0')
+ {
+ if (slash)
+ {
+ switch (s - slash) {
+ 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;
+}
+
FcStrSet *
FcStrSetCreate (void)
{
FcMemFree (FC_MEM_STRLIST, sizeof (FcStrList));
free (list);
}
+