about summary refs log tree commit diff
path: root/REORG.TODO/iconv/strtab.c
diff options
context:
space:
mode:
authorZack Weinberg <zackw@panix.com>2017-06-08 15:39:03 -0400
committerZack Weinberg <zackw@panix.com>2017-06-08 15:39:03 -0400
commit5046dbb4a7eba5eccfd258f92f4735c9ffc8d069 (patch)
tree4470480d904b65cf14ca524f96f79eca818c3eaf /REORG.TODO/iconv/strtab.c
parent199fc19d3aaaf57944ef036e15904febe877fc93 (diff)
downloadglibc-5046dbb4a7eba5eccfd258f92f4735c9ffc8d069.tar.gz
glibc-5046dbb4a7eba5eccfd258f92f4735c9ffc8d069.tar.xz
glibc-5046dbb4a7eba5eccfd258f92f4735c9ffc8d069.zip
Prepare for radical source tree reorganization. zack/build-layout-experiment
All top-level files and directories are moved into a temporary storage
directory, REORG.TODO, except for files that will certainly still
exist in their current form at top level when we're done (COPYING,
COPYING.LIB, LICENSES, NEWS, README), all old ChangeLog files (which
are moved to the new directory OldChangeLogs, instead), and the
generated file INSTALL (which is just deleted; in the new order, there
will be no generated files checked into version control).
Diffstat (limited to 'REORG.TODO/iconv/strtab.c')
-rw-r--r--REORG.TODO/iconv/strtab.c339
1 files changed, 339 insertions, 0 deletions
diff --git a/REORG.TODO/iconv/strtab.c b/REORG.TODO/iconv/strtab.c
new file mode 100644
index 0000000000..89b28c5dde
--- /dev/null
+++ b/REORG.TODO/iconv/strtab.c
@@ -0,0 +1,339 @@
+/* C string table handling.
+   Copyright (C) 2000-2017 Free Software Foundation, Inc.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2000.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   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, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/cdefs.h>
+#include <sys/param.h>
+
+
+struct Strent
+{
+  const char *string;
+  size_t len;
+  struct Strent *next;
+  struct Strent *left;
+  struct Strent *right;
+  size_t offset;
+  char reverse[0];
+};
+
+
+struct memoryblock
+{
+  struct memoryblock *next;
+  char memory[0];
+};
+
+
+struct Strtab
+{
+  struct Strent *root;
+  struct memoryblock *memory;
+  char *backp;
+  size_t left;
+  size_t total;
+
+  struct Strent null;
+};
+
+
+/* Cache for the pagesize.  We correct this value a bit so that `malloc'
+   is not allocating more than a page.  */
+static size_t ps;
+
+
+#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);
+    }
+
+  ret = (struct Strtab *) calloc (1, sizeof (struct Strtab));
+  if (ret != NULL)
+    {
+      ret->null.len = 1;
+      ret->null.string = "";
+    }
+  return ret;
+}
+
+
+static void
+morememory (struct Strtab *st, size_t len)
+{
+  struct memoryblock *newmem;
+
+  if (len < ps)
+    len = ps;
+  newmem = (struct memoryblock *) malloc (len);
+  if (newmem == NULL)
+    abort ();
+
+  newmem->next = st->memory;
+  st->memory = newmem;
+  st->backp = newmem->memory;
+  st->left = len - offsetof (struct memoryblock, memory);
+}
+
+
+void
+strtabfree (struct Strtab *st)
+{
+  struct memoryblock *mb = st->memory;
+
+  while (mb != NULL)
+    {
+      void *old = mb;
+      mb = mb->next;
+      free (old);
+    }
+
+  free (st);
+}
+
+
+static struct Strent *
+newstring (struct Strtab *st, const char *str, size_t len)
+{
+  struct Strent *newstr;
+  size_t align;
+  int i;
+
+  /* Compute the amount of padding needed to make the structure aligned.  */
+  align = ((__alignof__ (struct Strent)
+	    - (((uintptr_t) st->backp)
+	       & (__alignof__ (struct Strent) - 1)))
+	   & (__alignof__ (struct Strent) - 1));
+
+  /* Make sure there is enough room in the memory block.  */
+  if (st->left < align + sizeof (struct Strent) + len)
+    {
+      morememory (st, sizeof (struct Strent) + len);
+      align = 0;
+    }
+
+  /* Create the reserved string.  */
+  newstr = (struct Strent *) (st->backp + align);
+  newstr->string = str;
+  newstr->len = len;
+  newstr->next = NULL;
+  newstr->left = NULL;
+  newstr->right = NULL;
+  newstr->offset = 0;
+  for (i = len - 2; i >= 0; --i)
+    newstr->reverse[i] = str[len - 2 - i];
+  newstr->reverse[len - 1] = '\0';
+  st->backp += align + sizeof (struct Strent) + len;
+  st->left -= align + sizeof (struct Strent) + len;
+
+  return newstr;
+}
+
+
+/* XXX This function should definitely be rewritten to use a balancing
+   tree algorithm (AVL, red-black trees).  For now a simple, correct
+   implementation is enough.  */
+static struct Strent **
+searchstring (struct Strent **sep, struct Strent *newstr)
+{
+  int cmpres;
+
+  /* More strings?  */
+  if (*sep == NULL)
+    {
+      *sep = newstr;
+      return sep;
+    }
+
+  /* Compare the strings.  */
+  cmpres = memcmp ((*sep)->reverse, newstr->reverse,
+		   MIN ((*sep)->len, newstr->len) - 1);
+  if (cmpres == 0)
+    /* We found a matching string.  */
+    return sep;
+  else if (cmpres > 0)
+    return searchstring (&(*sep)->left, newstr);
+  else
+    return searchstring (&(*sep)->right, newstr);
+}
+
+
+/* Add new string.  The actual string is assumed to be permanent.  */
+struct Strent *
+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);
+
+  /* Search in the array for the place to insert the string.  If there
+     is no string with matching prefix and no string with matching
+     leading substring, create a new entry.  */
+  sep = searchstring (&st->root, newstr);
+  if (*sep != newstr)
+    {
+      /* 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;
+	  st->left += newstr->len;
+
+	  newstr->next = (*sep)->next;
+	  (*sep)->next = newstr;
+	}
+      else if ((*sep)->len != newstr->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;
+	}
+      else
+	{
+	  /* We have an exact match.  Free the memory we allocated.  */
+	  st->left += st->backp - (char *) newstr;
+	  st->backp = (char *) newstr;
+
+	  newstr = *sep;
+	}
+    }
+  else
+    st->total += newstr->len;
+
+  return newstr;
+}
+
+
+static void
+copystrings (struct Strent *nodep, char **freep, size_t *offsetp)
+{
+  struct Strent *subs;
+
+  if (nodep->left != NULL)
+    copystrings (nodep->left, freep, offsetp);
+
+  /* Process the current node.  */
+  nodep->offset = *offsetp;
+  *freep = (char *) mempcpy (*freep, nodep->string, nodep->len);
+  *offsetp += nodep->len;
+
+  for (subs = nodep->next; subs != NULL; subs = subs->next)
+    {
+      assert (subs->len < nodep->len);
+      subs->offset = nodep->offset + nodep->len - subs->len;
+    }
+
+  if (nodep->right != NULL)
+    copystrings (nodep->right, freep, offsetp);
+}
+
+
+void *
+strtabfinalize (struct Strtab *st, size_t *size)
+{
+  size_t copylen;
+  char *endp;
+  char *retval;
+
+  /* Fill in the information.  */
+  endp = retval = (char *) xmalloc (st->total + 1);
+
+  /* Always put an empty string at the beginning so that a zero offset
+     can mean error.  */
+  *endp++ = '\0';
+
+  /* Now run through the tree and add all the string while also updating
+     the offset members of the elfstrent records.  */
+  copylen = 1;
+  copystrings (st->root, &endp, &copylen);
+  assert (copylen == st->total + 1);
+  assert (endp == retval + st->total + 1);
+  *size = copylen;
+
+  return retval;
+}
+
+
+size_t
+strtaboffset (struct Strent *se)
+{
+  return se->offset;
+}