]> 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 be79dc29ed97d7656922788ecf18344acc3493fe..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>
@@ -26,6 +25,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <sys/cdefs.h>
 #include <sys/param.h>
 
 
@@ -65,19 +65,45 @@ 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.  */
+/* Create new C string table object in memory.  */
+extern struct Strtab *strtabinit (void);
+
+/* Free resources allocated for C string table ST.  */
+extern void strtabfree (struct Strtab *st);
+
+/* Add string STR (length LEN is != 0) to C string table ST.  */
+extern struct Strent *strtabadd (struct Strtab *st, const char *str,
+                                size_t len);
+
+/* Finalize string table ST and store size in *SIZE and return a pointer.  */
+extern void *strtabfinalize (struct Strtab *st, size_t *size);
+
+/* Get offset in string table for string associated with SE.  */
+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;
 }
 
 
@@ -122,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)
@@ -158,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)
@@ -174,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;
@@ -192,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);
 
@@ -204,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;
@@ -217,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
        {
@@ -281,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;