c06a49c551
2001-08-27 Ulrich Drepper <drepper@redhat.com> * misc/syslog.c (vsyslog): Try a bit harder to use syslogd. If the connection went down after we first used it try to connect again and resend the message before printing to the console. Reported by Coserea Gh. Tudor <tudore@tudore.gecadsoftware.com>. 2001-08-27 Jakub Jelinek <jakub@redhat.com> * string/tst-strlen.c (main): Test strnlen (, -1) too. * sysdeps/generic/strnlen.c (__strnlen): Fix for maxlens with top bit set. 2001-08-27 Ulrich Drepper <drepper@redhat.com> * iconv/strtab.c (searchstring): Use correct length for comparison. (strtabadd): Account total size correct if new string has old string as substring.
314 lines
7.5 KiB
C
314 lines
7.5 KiB
C
/* C string table handling.
|
|
Copyright (C) 2000, 2001 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, write to the Free Software Foundation,
|
|
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
|
|
|
#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;
|
|
|
|
|
|
extern void *xmalloc (size_t n) __attribute_malloc__;
|
|
|
|
/* 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)
|
|
{
|
|
if (ps == 0)
|
|
{
|
|
ps = sysconf (_SC_PAGESIZE) - 2 * sizeof (void *);
|
|
assert (sizeof (struct memoryblock) < ps);
|
|
}
|
|
|
|
return (struct Strtab *) calloc (1, sizeof (struct Strtab));
|
|
}
|
|
|
|
|
|
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 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)
|
|
& (__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 algorith (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;
|
|
|
|
/* 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)
|
|
{
|
|
/* 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;
|
|
*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, ©len);
|
|
assert (copylen == st->total + 1);
|
|
assert (endp = retval + st->total + 1);
|
|
*size = copylen;
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
size_t
|
|
strtaboffset (struct Strent *se)
|
|
{
|
|
return se->offset;
|
|
}
|