]> git.wh0rd.org - fontconfig.git/blobdiff - src/fcstr.c
Eliminate ./ and ../ elements from font directory names when scanning.
[fontconfig.git] / src / fcstr.c
index e67563dcf55bef38db8e98d95b26977a09983ed3..37bad6b16379f4cd5cf7128d3b163d5eae5d54e6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * $RCSId: xc/lib/fontconfig/src/fcstr.c,v 1.10 2002/08/31 22:17:32 keithp Exp $
  *
- * Copyright © 2000 Keith Packard
+ * 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
  * 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;
 }
 
@@ -63,16 +65,162 @@ FcStrFree (FcChar8 *s)
     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;
@@ -81,17 +229,19 @@ FcStrCmpIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
 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;
@@ -114,6 +264,23 @@ FcStrCmp (const FcChar8 *s1, const FcChar8 *s2)
     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?
  */
@@ -121,17 +288,17 @@ FcStrCmp (const FcChar8 *s1, const FcChar8 *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;
@@ -160,13 +327,17 @@ FcStrContainsIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *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;
@@ -191,52 +362,45 @@ FcStrContainsIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
 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;
 }
 
@@ -287,8 +451,7 @@ again:
        ++ s1;
        ++ s2;
     }
-
-    return 0;
+    /* never reached. */
 }
 
 int
@@ -545,7 +708,7 @@ FcStrBufChar (FcStrBuf *buf, FcChar8 c)
        }
        else
        {
-           size = buf->size + 1024;
+           size = buf->size + 64;
            new = malloc (size);
            if (new)
            {
@@ -619,7 +782,7 @@ FcStrCopyFilename (const FcChar8 *s)
        if (!new)
            return 0;
        FcMemAlloc (FC_MEM_STRING, size);
-       strcpy ((char *) new, (const char *) s);
+       memcpy (new, s, size);
     }
     return new;
 }
@@ -672,6 +835,63 @@ FcStrBasename (const FcChar8 *file)
     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)
 {