]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - iconv/strtab.c
Prefer https to http for gnu.org and fsf.org URLs
[thirdparty/glibc.git] / iconv / strtab.c
index d567f57e8806b56dada4bf3d897915410259d63e..97c39ab53856c2dda5de5c8723cfce7941a9661f 100644 (file)
@@ -1,5 +1,5 @@
 /* C string table handling.
-   Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+   Copyright (C) 2000-2019 Free Software Foundation, Inc.
    Written by Ulrich Drepper <drepper@redhat.com>, 2000.
 
    This program is free software; you can redistribute it and/or modify
@@ -13,8 +13,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software Foundation,
-   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
 
 #ifdef HAVE_CONFIG_H
 # include <config.h>
@@ -66,7 +65,7 @@ struct Strtab
 static size_t ps;
 
 
-extern void *xmalloc (size_t n) __attribute_malloc__;
+#include <programs/xmalloc.h>
 
 /* Prototypes for our functions that are used from iconvconfig.c.  If
    you change these, change also iconvconfig.c.  */
@@ -90,13 +89,21 @@ extern size_t strtaboffset (struct Strent *se);
 struct Strtab *
 strtabinit (void)
 {
+  struct Strtab *ret;
+
   if (ps == 0)
     {
       ps = sysconf (_SC_PAGESIZE) - 2 * sizeof (void *);
       assert (sizeof (struct memoryblock) < ps);
     }
 
-  return (struct Strtab *) calloc (1, sizeof (struct Strtab));
+  ret = (struct Strtab *) calloc (1, sizeof (struct Strtab));
+  if (ret != NULL)
+    {
+      ret->null.len = 1;
+      ret->null.string = "";
+    }
+  return ret;
 }
 
 
@@ -141,10 +148,6 @@ newstring (struct Strtab *st, const char *str, size_t len)
   size_t align;
   int i;
 
-  /* Compute the string length if the caller doesn't know it.  */
-  if (len == 0)
-    len = strlen (str) + 1;
-
   /* Compute the amount of padding needed to make the structure aligned.  */
   align = ((__alignof__ (struct Strent)
            - (((uintptr_t) st->backp)
@@ -177,7 +180,7 @@ newstring (struct Strtab *st, const char *str, size_t len)
 
 
 /* XXX This function should definitely be rewritten to use a balancing
-   tree algorith (AVL, red-black trees).  For now a simple, correct
+   tree algorithm (AVL, red-black trees).  For now a simple, correct
    implementation is enough.  */
 static struct Strent **
 searchstring (struct Strent **sep, struct Strent *newstr)
@@ -193,7 +196,7 @@ searchstring (struct Strent **sep, struct Strent *newstr)
 
   /* Compare the strings.  */
   cmpres = memcmp ((*sep)->reverse, newstr->reverse,
-                  MIN ((*sep)->len, newstr->len));
+                  MIN ((*sep)->len, newstr->len) - 1);
   if (cmpres == 0)
     /* We found a matching string.  */
     return sep;
@@ -211,6 +214,14 @@ strtabadd (struct Strtab *st, const char *str, size_t len)
   struct Strent *newstr;
   struct Strent **sep;
 
+  /* Compute the string length if the caller doesn't know it.  */
+  if (len == 0)
+    len = strlen (str) + 1;
+
+  /* Make sure all "" strings get offset 0.  */
+  if (len == 1)
+    return &st->null;
+
   /* Allocate memory for the new string and its associated information.  */
   newstr = newstring (st, str, len);
 
@@ -223,6 +234,19 @@ strtabadd (struct Strtab *st, const char *str, size_t len)
       /* This is not the same entry.  This means we have a prefix match.  */
       if ((*sep)->len > newstr->len)
        {
+         struct Strent *subs;
+
+         for (subs = (*sep)->next; subs; subs = subs->next)
+           if (subs->len == newstr->len)
+             {
+               /* We have an exact match with a substring.  Free the memory
+                  we allocated.  */
+               st->left += st->backp - (char *) newstr;
+               st->backp = (char *) newstr;
+
+               return subs;
+             }
+
          /* We have a new substring.  This means we don't need the reverse
             string of this entry anymore.  */
          st->backp -= newstr->len;
@@ -236,10 +260,11 @@ strtabadd (struct Strtab *st, const char *str, size_t len)
          /* When we get here it means that the string we are about to
             add has a common prefix with a string we already have but
             it is longer.  In this case we have to put it first.  */
+         st->total += newstr->len - (*sep)->len;
          newstr->next = *sep;
+         newstr->left = (*sep)->left;
+         newstr->right = (*sep)->right;
          *sep = newstr;
-
-         st->total += newstr->len - (*sep)->len;
        }
       else
        {
@@ -300,7 +325,7 @@ strtabfinalize (struct Strtab *st, size_t *size)
   copylen = 1;
   copystrings (st->root, &endp, &copylen);
   assert (copylen == st->total + 1);
-  assert (endp = retval + st->total + 1);
+  assert (endp == retval + st->total + 1);
   *size = copylen;
 
   return retval;