1999-01-18  Ulrich Drepper  <drepper@cygnus.com>

	* iconv/gconv_conf.c (add_module): Complete rewrite.  Use cleverer
	data structures and avoid creating intermediate representations
	first.  Rewrite also all helper functions.
	* iconv/gconv_db.c (find_derivation): Use new data structure for
	module database.
	* iconv/Versions: Remove __gconv_nmodules.
	* iconv/iconv_prog.c: Rewrite generation of charset name list to
	use new data structure.
	* iconv/gconv_int.h (struct gconv_module): Add new elements for
	database data structure.
	(__gconv_modules_db): Update type.
	(__gconv_transform_dummy): Removed.
	* iconv/gconv_builtin.h: Remove dummy transformation.
	* iconv/gconv_simple.c: Remove __gconv_transform_dummy.

	* sysdeps/unix/sysv/linux/sparc/sparc32/syscalls.list: Remove
	__syscall_vfork, add vfork.
	* sysdeps/unix/sysv/linux/sparc/sparc64/syscalls.list: Likewise.

	* Rules: Add dummp.c and dummy.o to common-generated.
This commit is contained in:
Ulrich Drepper 1999-01-18 23:15:16 +00:00
parent 464d646f3e
commit 2bd6088017
10 changed files with 502 additions and 378 deletions

View File

@ -1,3 +1,24 @@
1999-01-18 Ulrich Drepper <drepper@cygnus.com>
* iconv/gconv_conf.c (add_module): Complete rewrite. Use cleverer
data structures and avoid creating intermediate representations
first. Rewrite also all helper functions.
* iconv/gconv_db.c (find_derivation): Use new data structure for
module database.
* iconv/Versions: Remove __gconv_nmodules.
* iconv/iconv_prog.c: Rewrite generation of charset name list to
use new data structure.
* iconv/gconv_int.h (struct gconv_module): Add new elements for
database data structure.
(__gconv_modules_db): Update type.
(__gconv_transform_dummy): Removed.
* iconv/gconv_builtin.h: Remove dummy transformation.
* iconv/gconv_simple.c: Remove __gconv_transform_dummy.
* sysdeps/unix/sysv/linux/sparc/sparc32/syscalls.list: Remove
__syscall_vfork, add vfork.
* sysdeps/unix/sysv/linux/sparc/sparc64/syscalls.list: Likewise.
1999-01-18 Andreas Jaeger <aj@arthur.rhein-neckar.de> 1999-01-18 Andreas Jaeger <aj@arthur.rhein-neckar.de>
* posix/test-vfork.c: Include <sys/wait.h> for wait declaration. * posix/test-vfork.c: Include <sys/wait.h> for wait declaration.
@ -9,7 +30,7 @@
1999-01-18 Ulrich Drepper <drepper@cygnus.com> 1999-01-18 Ulrich Drepper <drepper@cygnus.com>
* Rules: Add dummp.y and dummy.o to common-generated. * Rules: Add dummp.c and dummy.o to common-generated.
Patch by Andreas Schwab. Patch by Andreas Schwab.
1999-01-18 10:07 -0500 Zack Weinberg <zack@rabi.phys.columbia.edu> 1999-01-18 10:07 -0500 Zack Weinberg <zack@rabi.phys.columbia.edu>

View File

@ -1,7 +1,7 @@
libc { libc {
GLIBC_2.1 { GLIBC_2.1 {
# global variables # global variables
__gconv_alias_db; __gconv_nmodules; __gconv_modules_db; __gconv_alias_db; __gconv_modules_db;
# i* # i*
iconv_open; iconv; iconv_close; iconv_open; iconv; iconv_close;

View File

@ -79,8 +79,3 @@ BUILTIN_TRANSFORMATION (NULL, "INTERNAL", 8, "UNICODELITTLE//",
1, "=INTERNAL->ucs2little", 1, "=INTERNAL->ucs2little",
__gconv_transform_internal_ucs2little, NULL, NULL, __gconv_transform_internal_ucs2little, NULL, NULL,
4, 4, 2, 2) 4, 4, 2, 2)
BUILTIN_TRANSFORMATION ("(.*)", NULL, 0, "\\1", 1, "=dummy",
__gconv_transform_dummy, NULL, NULL,
1, 1, 1, 1)

View File

@ -1,5 +1,5 @@
/* Handle configuration data. /* Handle configuration data.
Copyright (C) 1997, 1998 Free Software Foundation, Inc. Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997. Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
@ -83,99 +83,84 @@ builtin_aliases[] =
#endif #endif
/* Function for searching module. */ /* Test whether there is already a matching module known. */
static int static int
module_compare (const void *p1, const void *p2) internal_function
detect_conflict (const char *alias, size_t alias_len)
{ {
const struct gconv_module *s1 = (const struct gconv_module *) p1; struct gconv_module *node = __gconv_modules_db;
const struct gconv_module *s2 = (const struct gconv_module *) p2;
int result;
if (s1->from_pattern == NULL) while (node != NULL)
{ {
if (s2->from_pattern == NULL) int cmpres = strncmp (alias, node->from_constpfx,
result = strcmp (s1->from_constpfx, s2->from_constpfx); MIN (alias_len, node->from_constpfx_len));
else
result = -1; if (cmpres == 0)
{
struct gconv_module *runp;
if (alias_len < node->from_constpfx_len)
/* Cannot possibly match. */
return 0;
/* This means the prefix and the alias are identical. If
there is now a simple extry or a regular expression
matching this name we have found a conflict. If there is
no conflict with the elements in the `same' list there
cannot be a conflict. */
runp = node;
do
{
if (runp->from_pattern == NULL)
{
/* This is a simple entry and therefore we have a
conflict if the strings are really the same. */
if (alias_len == node->from_constpfx_len)
return 1;
} }
else if (s2->from_pattern == NULL)
result = 1;
else
result = strcmp (s1->from_pattern, s2->from_pattern);
if (result == 0)
result = strcmp (s1->to_string, s2->to_string);
return result;
}
/* This function is used to test for a conflict which could be introduced
if adding a new alias.
This function is a *very* ugly hack. The action-function is not
supposed to alter the parameter. But we have to do this. We will if
necessary compile the regular expression so that we can see whether it
matches the alias name. This is safe in this environment and for the
sake of performance we do it this way. The alternative would be to
compile all regular expressions right from the start or to forget about
the compilation though we might need it later.
The second ugliness is that we have no possibility to pass parameters
to the function. Therefore we use a global variable. This is no problem
since we are for sure alone even in multi-threaded applications. */
/* This is alias we want to check. */
static const char *alias_to_test;
/* This variable is set to a nonzero value once we have found a matching
entry. */
static int abort_conflict_search;
static void
detect_conflict (const void *p, VISIT value, int level)
{
struct gconv_module *s = *(struct gconv_module **) p;
if ((value != endorder && value != leaf) || s->from_constpfx == NULL
|| abort_conflict_search)
return;
/* Before we test the whole expression (if this is a regular expression)
make sure the constant prefix matches. In case this is no regular
expression this is the whole string. */
if (strcmp (alias_to_test, s->from_constpfx) == 0)
{
if (s->from_pattern == NULL)
/* This is a simple string and therefore we have a conflict. */
abort_conflict_search = 1;
else else
{ {
/* Make sure the regular expression is compiled (if possible). */ /* Compile the regular expression if necessary. */
if (s->from_regex == NULL) if (runp->from_regex == NULL)
{ {
/* Beware, this is what I warned you about in the comment if (__regcomp (&runp->from_regex_mem,
above. We are modifying the object. */ runp->from_pattern,
if (__regcomp (&s->from_regex_mem, s->from_pattern,
REG_EXTENDED | REG_ICASE) != 0) REG_EXTENDED | REG_ICASE) != 0)
/* Something is wrong. Remember this. */ /* Something is wrong. Remember this. */
s->from_regex = (regex_t *) -1L; runp->from_regex = (regex_t *) -1L;
else else
s->from_regex = &s->from_regex_mem; runp->from_regex = &runp->from_regex_mem;
} }
if (s->from_regex != (regex_t *) -1L) if (runp->from_regex != (regex_t *) -1L)
{ {
regmatch_t match[1]; regmatch_t match[1];
if (__regexec (s->from_regex, alias_to_test, 1, match, 0) == 0 /* Try to match the regular expression. */
if (__regexec (runp->from_regex, alias, 1, match, 0) == 0
&& match[0].rm_so == 0 && match[0].rm_so == 0
&& alias_to_test[match[0].rm_eo] == '\0') && alias[match[0].rm_eo] == '\0')
/* The whole string matched. This is also a conflict. */ /* They match, therefore it is a conflict. */
abort_conflict_search = 1; return 1;
} }
} }
runp = runp->same;
} }
while (runp != NULL);
if (alias_len == node->from_constpfx_len)
return 0;
node = node->matching;
}
else if (cmpres < 0)
node = node->left;
else
node = node->right;
}
return node != NULL;
} }
@ -207,13 +192,8 @@ add_alias (char *rp, void *modules)
return; return;
*wp++ = '\0'; *wp++ = '\0';
/* Test whether this alias conflicts with any available module. See /* Test whether this alias conflicts with any available module. */
the comment before the function `detect_conflict' for a description if (detect_conflict (from, to - from - 1))
of this ugly hack. */
alias_to_test = from;
abort_conflict_search = 0;
__twalk (modules, detect_conflict);
if (abort_conflict_search)
/* It does conflict, don't add the alias. */ /* It does conflict, don't add the alias. */
return; return;
@ -234,8 +214,74 @@ add_alias (char *rp, void *modules)
} }
/* Insert a data structure for a new module in the search tree. */
static inline void
internal_function
insert_module (struct gconv_module *newp)
{
struct gconv_module **rootp = &__gconv_modules_db;
while (*rootp != NULL)
{
struct gconv_module *root = *rootp;
size_t minlen = MIN (newp->from_constpfx_len, root->from_constpfx_len);
int cmpres;
cmpres = strncmp (newp->from_constpfx, root->from_constpfx, minlen);
if (cmpres == 0)
{
/* This can mean two things: the prefix is entirely the same or
it matches only for the minimum length of both strings. */
if (newp->from_constpfx_len == root->from_constpfx_len)
{
/* Both prefixes are identical. Insert the string at the
end of the `same' list if it is not already there. */
const char *from_pattern = (newp->from_pattern
?: newp->from_constpfx);
while (strcmp (from_pattern,
root->from_pattern ?: root->from_constpfx) != 0
|| strcmp (newp->to_string, root->to_string) != 0)
{
rootp = &root->same;
root = *rootp;
if (root == NULL)
break;
}
if (root != NULL)
/* This is a no new conversion. */
return;
break;
}
/* The new element either has a prefix which is itself a
prefix for the prefix of the current node or vice verse.
In the first case we insert the node right here. Otherwise
we have to descent further. */
if (newp->from_constpfx_len < root->from_constpfx_len)
{
newp->matching = root;
break;
}
rootp = &root->matching;
}
else if (cmpres < 0)
rootp = &root->left;
else
rootp = &root->right;
}
/* Plug in the new node here. */
*rootp = newp;
}
/* Add new module. */ /* Add new module. */
static inline void static inline void
internal_function
add_module (char *rp, const char *directory, size_t dir_len, void **modules, add_module (char *rp, const char *directory, size_t dir_len, void **modules,
size_t *nmodules, int modcounter) size_t *nmodules, int modcounter)
{ {
@ -259,7 +305,7 @@ add_module (char *rp, const char *directory, size_t dir_len, void **modules,
while (*rp != '\0' && !isspace (*rp)) while (*rp != '\0' && !isspace (*rp))
{ {
if (!isalnum (*rp) && *rp != '-' && *rp != '/' && *rp != '.' if (!isalnum (*rp) && *rp != '-' && *rp != '/' && *rp != '.'
&& *rp != '_') && *rp != '_' && *rp != '(' && *rp != ')')
from_is_regex = 1; from_is_regex = 1;
++rp; ++rp;
} }
@ -293,7 +339,7 @@ add_module (char *rp, const char *directory, size_t dir_len, void **modules,
*wp++ = '\0'; *wp++ = '\0';
cost_hi = strtol (rp, &endp, 10); cost_hi = strtol (rp, &endp, 10);
if (rp == endp) if (rp == endp || cost_hi < 1)
/* No useful information. */ /* No useful information. */
cost_hi = 1; cost_hi = 1;
} }
@ -328,7 +374,8 @@ add_module (char *rp, const char *directory, size_t dir_len, void **modules,
else else
const_len = to - from - 1; const_len = to - from - 1;
new_module = (struct gconv_module *) malloc (sizeof (struct gconv_module) new_module = (struct gconv_module *) calloc (1,
sizeof (struct gconv_module)
+ (wp - from) + (wp - from)
+ dir_len + need_ext); + dir_len + need_ext);
if (new_module != NULL) if (new_module != NULL)
@ -340,13 +387,9 @@ add_module (char *rp, const char *directory, size_t dir_len, void **modules,
from, to - from); from, to - from);
if (from_is_regex) if (from_is_regex)
new_module->from_pattern = new_module->from_constpfx; new_module->from_pattern = new_module->from_constpfx;
else
new_module->from_pattern = NULL;
new_module->from_constpfx_len = const_len; new_module->from_constpfx_len = const_len;
new_module->from_regex = NULL;
new_module->to_string = memcpy ((char *) new_module->from_constpfx new_module->to_string = memcpy ((char *) new_module->from_constpfx
+ (to - from), to, module - to); + (to - from), to, module - to);
@ -388,28 +431,9 @@ add_module (char *rp, const char *directory, size_t dir_len, void **modules,
} }
} }
if (__tfind (new_module, modules, module_compare) == NULL) /* Now insert the new module data structure in our search tree. */
{ insert_module (new_module);
if (__tsearch (new_module, modules, module_compare) == NULL)
/* Something went wrong while inserting the new module. */
free (new_module);
else
++*nmodules;
} }
}
}
static void
insert_module (const void *nodep, VISIT value, int level)
{
if (value == preorder || value == leaf)
__gconv_modules_db[__gconv_nmodules++] = *(struct gconv_module **) nodep;
}
static void
nothing (void *unused __attribute__ ((unused)))
{
} }
@ -495,15 +519,14 @@ __gconv_read_conf (void)
{ {
/* Append the default path to the user-defined path. */ /* Append the default path to the user-defined path. */
size_t user_len = strlen (user_path); size_t user_len = strlen (user_path);
char *tmp;
gconv_path = alloca (user_len + 1 + sizeof (default_gconv_path)); gconv_path = alloca (user_len + 1 + sizeof (default_gconv_path));
tmp = __mempcpy (gconv_path, user_path, user_len); __mempcpy (__mempcpy (__mempcpy (gconv_path, user_path, user_len),
*tmp++ = ':'; ":", 1),
__mempcpy (tmp, default_gconv_path, sizeof (default_gconv_path)); default_gconv_path, sizeof (default_gconv_path));
} }
elem = strtok_r (gconv_path, ":", &gconv_path); elem = __strtok_r (gconv_path, ":", &gconv_path);
while (elem != NULL) while (elem != NULL)
{ {
#ifndef MAXPATHLEN #ifndef MAXPATHLEN
@ -515,43 +538,38 @@ __gconv_read_conf (void)
if (__realpath (elem, real_elem) != NULL) if (__realpath (elem, real_elem) != NULL)
{ {
size_t elem_len = strlen (real_elem); size_t elem_len = strlen (real_elem);
char *filename, *tmp; char *filename;
filename = alloca (elem_len + 1 + sizeof (gconv_conf_filename)); filename = alloca (elem_len + 1 + sizeof (gconv_conf_filename));
tmp = __mempcpy (filename, real_elem, elem_len); __mempcpy (__mempcpy (__mempcpy (filename, real_elem, elem_len),
*tmp++ = '/'; "/", 1),
__mempcpy (tmp, gconv_conf_filename, sizeof (gconv_conf_filename)); gconv_conf_filename, sizeof (gconv_conf_filename));
/* Read the next configuration file. */ /* Read the next configuration file. */
read_conf_file (filename, real_elem, elem_len, &modules, &nmodules); read_conf_file (filename, real_elem, elem_len, &modules, &nmodules);
} }
/* Get next element in the path. */ /* Get next element in the path. */
elem = strtok_r (NULL, ":", &gconv_path); elem = __strtok_r (NULL, ":", &gconv_path);
} }
/* If the configuration files do not contain any valid module specification /* Add the internal modules. */
remember this by setting the pointer to the module array to NULL. */ for (cnt = 0; cnt < sizeof (builtin_modules) / sizeof (builtin_modules[0]);
nmodules += sizeof (builtin_modules) / sizeof (builtin_modules[0]); ++cnt)
if (nmodules == 0)
__gconv_modules_db = NULL;
else
{ {
__gconv_modules_db = if (builtin_modules[cnt].from_pattern == NULL)
(struct gconv_module **) malloc (nmodules
* sizeof (struct gconv_module));
if (__gconv_modules_db != NULL)
{ {
size_t cnt; struct gconv_alias fake_alias;
/* Insert all module entries into the array. */ fake_alias.fromname = builtin_modules[cnt].from_constpfx;
__twalk (modules, insert_module);
/* Finally insert the builtin transformations. */ if (__tfind (&fake_alias, &__gconv_alias_db, __gconv_alias_compare)
for (cnt = 0; cnt < (sizeof (builtin_modules) != NULL)
/ sizeof (struct gconv_module)); ++cnt) /* It'll conflict so don't add it. */
__gconv_modules_db[__gconv_nmodules++] = &builtin_modules[cnt]; continue;
} }
insert_module (&builtin_modules[cnt]);
} }
/* Add aliases for builtin conversions. */ /* Add aliases for builtin conversions. */
@ -562,10 +580,6 @@ __gconv_read_conf (void)
add_alias (copy, modules); add_alias (copy, modules);
} }
if (nmodules != 0)
/* Now remove the tree data structure. */
__tdestroy (modules, nothing);
/* Restore the error number. */ /* Restore the error number. */
__set_errno (save_errno); __set_errno (save_errno);
} }

View File

@ -1,5 +1,5 @@
/* Provide access to the collection of available transformation modules. /* Provide access to the collection of available transformation modules.
Copyright (C) 1997, 1998 Free Software Foundation, Inc. Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997. Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
@ -18,9 +18,11 @@
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */ Boston, MA 02111-1307, USA. */
#include <limits.h>
#include <search.h> #include <search.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/param.h>
#include <bits/libc-lock.h> #include <bits/libc-lock.h>
#include <ldsodefs.h> #include <ldsodefs.h>
@ -32,8 +34,7 @@
void *__gconv_alias_db; void *__gconv_alias_db;
/* Array with available modules. */ /* Array with available modules. */
size_t __gconv_nmodules; struct gconv_module *__gconv_modules_db;
struct gconv_module **__gconv_modules_db;
/* We modify global data. */ /* We modify global data. */
__libc_lock_define_initialized (static, lock) __libc_lock_define_initialized (static, lock)
@ -55,14 +56,20 @@ __gconv_alias_compare (const void *p1, const void *p2)
struct derivation_step struct derivation_step
{ {
const char *result_set; const char *result_set;
size_t result_set_len;
int cost_lo;
int cost_hi;
struct gconv_module *code; struct gconv_module *code;
struct derivation_step *last; struct derivation_step *last;
struct derivation_step *next; struct derivation_step *next;
}; };
#define NEW_STEP(result, module, last_mod) \ #define NEW_STEP(result, hi, lo, module, last_mod) \
({ struct derivation_step *newp = alloca (sizeof (struct derivation_step)); \ ({ struct derivation_step *newp = alloca (sizeof (struct derivation_step)); \
newp->result_set = result; \ newp->result_set = result; \
newp->result_set_len = strlen (result); \
newp->cost_hi = hi; \
newp->cost_lo = lo; \
newp->code = module; \ newp->code = module; \
newp->last = last_mod; \ newp->last = last_mod; \
newp->next = NULL; \ newp->next = NULL; \
@ -276,9 +283,9 @@ find_derivation (const char *toset, const char *toset_expand,
struct gconv_step **handle, size_t *nsteps) struct gconv_step **handle, size_t *nsteps)
{ {
__libc_lock_define_initialized (static, lock) __libc_lock_define_initialized (static, lock)
struct derivation_step *first, *current, **lastp, *best = NULL; struct derivation_step *first, *current, **lastp, *solution = NULL;
int best_cost_hi = 0; int best_cost_hi = INT_MAX;
int best_cost_lo = 0; int best_cost_lo = INT_MAX;
int result; int result;
result = derivation_lookup (fromset_expand ?: fromset, toset_expand ?: toset, result = derivation_lookup (fromset_expand ?: fromset, toset_expand ?: toset,
@ -299,75 +306,99 @@ find_derivation (const char *toset, const char *toset_expand,
return result; return result;
} }
/* ### TODO /* For now we use a simple algorithm with quadratic runtime behaviour.
For now we use a simple algorithm with quadratic runtime behaviour.
The task is to match the `toset' with any of the available rules, The task is to match the `toset' with any of the available rules,
starting from FROMSET. */ starting from FROMSET. */
if (fromset_expand != NULL) if (fromset_expand != NULL)
{ {
first = NEW_STEP (fromset_expand, NULL, NULL); first = NEW_STEP (fromset_expand, 0, 0, NULL, NULL);
first->next = NEW_STEP (fromset, NULL, NULL); first->next = NEW_STEP (fromset, 0, 0, NULL, NULL);
lastp = &first->next->next; lastp = &first->next->next;
} }
else else
{ {
first = NEW_STEP (fromset, NULL, NULL); first = NEW_STEP (fromset, 0, 0, NULL, NULL);
lastp = &first->next; lastp = &first->next;
} }
current = first; for (current = first; current != NULL; current = current->next)
while (current != NULL)
{ {
/* Now match all the available module specifications against the /* Now match all the available module specifications against the
current charset name. If any of them matches check whether current charset name. If any of them matches check whether
we already have a derivation for this charset. If yes, use the we already have a derivation for this charset. If yes, use the
one with the lower costs. Otherwise add the new charset at the one with the lower costs. Otherwise add the new charset at the
end. */ end.
size_t cnt;
for (cnt = 0; cnt < __gconv_nmodules; ++cnt) The module database is organized in a tree form which allows to
search for prefixes. So we search for the first entry with a
matching prefix and any other matching entry can be found from
this place. */
struct gconv_module *node = __gconv_modules_db;
/* Maybe it is not necessary anymore to look for a solution for
this entry since the cost is already as high (or heigher) as
the cost for the best solution so far. */
if (current->cost_hi > best_cost_hi
|| (current->cost_hi == best_cost_hi
&& current->cost_lo >= best_cost_lo))
continue;
while (node != NULL)
{
int cmpres = strncmp (current->result_set, node->from_constpfx,
MIN (current->result_set_len,
node->from_constpfx_len));
if (cmpres == 0)
{
/* Walk through the list of modules with this prefix and
try to match the name. */
struct gconv_module *runp;
if (current->result_set_len < node->from_constpfx_len)
/* Cannot possibly match. */
break;
/* Check all the modules with this prefix. */
runp = node;
do
{ {
const char *result_set = NULL; const char *result_set = NULL;
if (__gconv_modules_db[cnt]->from_pattern == NULL) if (runp->from_pattern == NULL)
{ {
if (__strcasecmp (current->result_set, /* This is a simple entry and therefore we have a
__gconv_modules_db[cnt]->from_constpfx) == 0) found an matching entry if the strings are really
equal. */
if (current->result_set_len == runp->from_constpfx_len)
{ {
if (strcmp (__gconv_modules_db[cnt]->to_string, "-") == 0) if (strcmp (runp->to_string, "-") == 0)
result_set = toset_expand ?: toset; result_set = toset_expand ?: toset;
else else
result_set = __gconv_modules_db[cnt]->to_string; result_set = runp->to_string;
} }
} }
else else
/* We have a regular expression. First see if the prefix
matches. */
if (__strncasecmp (current->result_set,
__gconv_modules_db[cnt]->from_constpfx,
__gconv_modules_db[cnt]->from_constpfx_len)
== 0)
{ {
/* First compile the regex if not already done. */ /* Compile the regular expression if necessary. */
if (__gconv_modules_db[cnt]->from_regex == NULL) if (runp->from_regex == NULL)
{ {
if (__regcomp (&__gconv_modules_db[cnt]->from_regex_mem, if (__regcomp (&runp->from_regex_mem,
__gconv_modules_db[cnt]->from_pattern, runp->from_pattern,
REG_EXTENDED | REG_ICASE) != 0) REG_EXTENDED | REG_ICASE) != 0)
/* Something is wrong. Remember this. */ /* Something is wrong. Remember this. */
__gconv_modules_db[cnt]->from_regex = (regex_t *) -1L; runp->from_regex = (regex_t *) -1L;
else else
__gconv_modules_db[cnt]->from_regex runp->from_regex = &runp->from_regex_mem;
= &__gconv_modules_db[cnt]->from_regex_mem;
} }
if (__gconv_modules_db[cnt]->from_regex != (regex_t *) -1L) if (runp->from_regex != (regex_t *) -1L)
{ {
/* Try to match the from name. */
regmatch_t match[4]; regmatch_t match[4];
if (__regexec (__gconv_modules_db[cnt]->from_regex, /* Try to match the regular expression. */
current->result_set, 4, match, 0) == 0 if (__regexec (runp->from_regex, current->result_set,
4, match, 0) == 0
&& match[0].rm_so == 0 && match[0].rm_so == 0
&& current->result_set[match[0].rm_eo] == '\0') && current->result_set[match[0].rm_eo] == '\0')
{ {
@ -379,14 +410,13 @@ find_derivation (const char *toset, const char *toset_expand,
if (wp + (LEN) >= constr + len - 1) \ if (wp + (LEN) >= constr + len - 1) \
{ \ { \
char *newp = alloca (len += 128); \ char *newp = alloca (len += 128); \
memcpy (newp, constr, wp - constr); \ wp = __mempcpy (newp, constr, wp - constr); \
wp = newp + (wp - constr); \
constr = newp; \ constr = newp; \
} }
size_t len = 128; size_t len = 128;
char *constr = alloca (len); char *constr = alloca (len);
char *wp = constr; char *wp = constr;
const char *cp = __gconv_modules_db[cnt]->to_string; const char *cp = runp->to_string;
while (*cp != '\0') while (*cp != '\0')
{ {
@ -437,64 +467,126 @@ find_derivation (const char *toset, const char *toset_expand,
if (result_set != NULL) if (result_set != NULL)
{ {
int cost_hi = runp->cost_hi + current->cost_hi;
int cost_lo = runp->cost_lo + current->cost_lo;
struct derivation_step *step;
/* We managed to find a derivation. First see whether /* We managed to find a derivation. First see whether
this is what we are looking for. */ this is what we are looking for. */
if (__strcasecmp (result_set, toset) == 0 if (__strcasecmp (result_set, toset) == 0
|| (toset_expand != NULL || (toset_expand != NULL
&& __strcasecmp (result_set, toset_expand) == 0)) && __strcasecmp (result_set, toset_expand) == 0))
{ {
/* Determine the costs. If they are lower than the if (solution == NULL || cost_hi < best_cost_hi
previous solution (or this is the first solution) || (cost_hi == best_cost_hi
remember this solution. */ && cost_lo < best_cost_lo))
int cost_hi = __gconv_modules_db[cnt]->cost_hi;
int cost_lo = __gconv_modules_db[cnt]->cost_lo;
struct derivation_step *runp = current;
while (runp->code != NULL)
{ {
cost_hi += runp->code->cost_hi;
cost_lo += runp->code->cost_lo;
runp = runp->last;
}
if (best == NULL || cost_hi < best_cost_hi
|| (cost_hi == best_cost_hi && cost_lo < best_cost_lo))
{
best = NEW_STEP (result_set, __gconv_modules_db[cnt],
current);
best_cost_hi = cost_hi; best_cost_hi = cost_hi;
best_cost_lo = cost_lo; best_cost_lo = cost_lo;
} }
}
/* Append this solution to list. */
if (solution == NULL)
solution = NEW_STEP (result_set, 0, 0, runp,
current);
else else
{ {
/* Append at the end if there is no entry with this name. */ while (solution->next != NULL)
struct derivation_step *runp = first; solution = solution->next;
while (runp != NULL) solution->next = NEW_STEP (result_set, 0, 0,
{ runp, current);
if (__strcasecmp (result_set, runp->result_set) == 0)
break;
runp = runp->next;
} }
}
if (runp == NULL) else if (cost_hi < best_cost_hi
|| (cost_hi == best_cost_hi
&& cost_lo < best_cost_lo))
{ {
*lastp = NEW_STEP (result_set, __gconv_modules_db[cnt], /* Append at the end if there is no entry with
current); this name. */
for (step = first; step != NULL; step = step->next)
if (__strcasecmp (result_set, step->result_set)
== 0)
break;
if (step == NULL)
{
*lastp = NEW_STEP (result_set,
cost_hi, cost_lo,
runp, current);
lastp = &(*lastp)->next; lastp = &(*lastp)->next;
} }
else if (step->cost_hi > cost_hi
|| (step->cost_hi == cost_hi
&& step->cost_lo > cost_lo))
{
step->code = runp;
step->last = current;
/* Update the cost for all steps. */
for (step = first; step != NULL;
step = step->next)
{
struct derivation_step *back;
if (step->code == NULL)
/* This is one of the entries we started
from. */
continue;
step->cost_hi = step->code->cost_hi;
step->cost_lo = step->code->cost_lo;
for (back = step->last; back->code != NULL;
back = back->last)
{
step->cost_hi += back->code->cost_hi;
step->cost_lo += back->code->cost_lo;
}
}
for (step = solution; step != NULL;
step = step->next)
{
step->cost_hi = (step->code->cost_hi
+ step->last->cost_hi);
step->cost_lo = (step->code->cost_lo
+ step->last->cost_lo);
if (step->cost_hi < best_cost_hi
|| (step->cost_hi == best_cost_hi
&& step->cost_lo < best_cost_lo))
{
solution = step;
best_cost_hi = step->cost_hi;
best_cost_lo = step->cost_lo;
}
}
} }
} }
} }
/* Go on with the next entry. */ runp = runp->same;
current = current->next; }
while (runp != NULL);
if (current->result_set_len == node->from_constpfx_len)
break;
node = node->matching;
}
else if (cmpres < 0)
node = node->left;
else
node = node->right;
}
} }
if (best != NULL) if (solution != NULL)
/* We really found a way to do the transformation. Now build a data /* We really found a way to do the transformation. Now build a data
structure describing the transformation steps.*/ structure describing the transformation steps.*/
result = gen_steps (best, toset_expand ?: toset, fromset_expand ?: fromset, result = gen_steps (solution, toset_expand ?: toset,
handle, nsteps); fromset_expand ?: fromset, handle, nsteps);
else else
{ {
/* We haven't found a transformation. Clear the result values. */ /* We haven't found a transformation. Clear the result values. */
@ -620,20 +712,35 @@ __gconv_close_transform (struct gconv_step *steps, size_t nsteps)
} }
/* Free the modules mentioned. */
static void
internal_function
free_modules_db (struct gconv_module *node)
{
if (node->left != NULL)
free_modules_db (node->left);
if (node->right != NULL)
free_modules_db (node->right);
if (node->same != NULL)
free_modules_db (node->same);
do
{
struct gconv_module *act = node;
node = node->matching;
free (act);
}
while (node != NULL);
}
/* Free all resources if necessary. */ /* Free all resources if necessary. */
static void __attribute__ ((unused)) static void __attribute__ ((unused))
free_mem (void) free_mem (void)
{ {
size_t cnt;
if (__gconv_alias_db != NULL) if (__gconv_alias_db != NULL)
__tdestroy (__gconv_alias_db, free); __tdestroy (__gconv_alias_db, free);
for (cnt = 0; cnt < __gconv_nmodules; ++cnt) free_modules_db (__gconv_modules_db);
/* Modules which names do not start with a slash are builtin
transformations and the memory is not allocated dynamically. */
if (__gconv_modules_db[cnt]->module_name[0] == '/')
free (__gconv_modules_db[cnt]);
if (known_derivations != NULL) if (known_derivations != NULL)
__tdestroy (known_derivations, free_derivation); __tdestroy (known_derivations, free_derivation);

View File

@ -1,4 +1,4 @@
/* Copyright (C) 1997, 1998 Free Software Foundation, Inc. /* Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997. Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
@ -75,6 +75,11 @@ struct gconv_module
int cost_lo; int cost_lo;
const char *module_name; const char *module_name;
struct gconv_module *left; /* Prefix smaller. */
struct gconv_module *same; /* List of entries with identical prefix. */
struct gconv_module *matching;/* Next node with more specific prefix. */
struct gconv_module *right; /* Prefix larger. */
}; };
@ -85,7 +90,7 @@ extern void *__gconv_alias_db;
/* Array with available modules. */ /* Array with available modules. */
extern size_t __gconv_nmodules; extern size_t __gconv_nmodules;
extern struct gconv_module **__gconv_modules_db; extern struct gconv_module *__gconv_modules_db;
/* Return in *HANDLE decriptor for transformation from FROMSET to TOSET. */ /* Return in *HANDLE decriptor for transformation from FROMSET to TOSET. */
@ -102,7 +107,7 @@ extern int __gconv_close (gconv_t cd)
bytes in buffer starting at *OUTBUF. Return number of written bytes in buffer starting at *OUTBUF. Return number of written
characters in *CONVERTED if this pointer is not null. */ characters in *CONVERTED if this pointer is not null. */
extern int __gconv (gconv_t __cd, const char **__inbuf, const char *inbufend, extern int __gconv (gconv_t __cd, const char **__inbuf, const char *inbufend,
char **__outbuf, char *outbufend, size_t *__converted) char **__outbuf, char *outbufend, size_t *converted)
internal_function; internal_function;
/* Return in *HANDLE a pointer to an array with *NSTEPS elements describing /* Return in *HANDLE a pointer to an array with *NSTEPS elements describing
@ -152,7 +157,6 @@ extern void __gconv_get_builtin_trans (const char *__name,
const char **__inbuf, const char *__inbufend, \ const char **__inbuf, const char *__inbufend, \
size_t *__written, int __do_flush) size_t *__written, int __do_flush)
__BUILTIN_TRANS (__gconv_transform_dummy);
__BUILTIN_TRANS (__gconv_transform_ascii_internal); __BUILTIN_TRANS (__gconv_transform_ascii_internal);
__BUILTIN_TRANS (__gconv_transform_internal_ascii); __BUILTIN_TRANS (__gconv_transform_internal_ascii);
__BUILTIN_TRANS (__gconv_transform_utf8_internal); __BUILTIN_TRANS (__gconv_transform_utf8_internal);

View File

@ -46,38 +46,6 @@ static const unsigned char encoding_byte[] =
}; };
int
__gconv_transform_dummy (struct gconv_step *step, struct gconv_step_data *data,
const char **inbuf, const char *inbufend,
size_t *written, int do_flush)
{
size_t do_write;
/* We have no stateful encoding. So we don't have to do anything
special. */
if (do_flush)
do_write = 0;
else
{
do_write = MIN (inbufend - *inbuf, data->outbufend - data->outbuf);
memcpy (data->outbuf, inbuf, do_write);
*inbuf -= do_write;
*data->outbuf += do_write;
}
/* ### TODO Actually, this number must be devided according to the
size of the input charset. I.e., if the input is in UCS4 the
number of copied bytes must be divided by 4. */
if (written != NULL)
*written = do_write;
return GCONV_OK;
}
/* Transform from the internal, UCS4-like format, to UCS4. The /* Transform from the internal, UCS4-like format, to UCS4. The
difference between the internal ucs4 format and the real UCS4 difference between the internal ucs4 format and the real UCS4
format is, if any, the endianess. The Unicode/ISO 10646 says that format is, if any, the endianess. The Unicode/ISO 10646 says that

View File

@ -99,7 +99,7 @@ static int process_block (iconv_t cd, const char *addr, size_t len,
FILE *output); FILE *output);
static int process_fd (iconv_t cd, int fd, FILE *output); static int process_fd (iconv_t cd, int fd, FILE *output);
static int process_file (iconv_t cd, FILE *input, FILE *output); static int process_file (iconv_t cd, FILE *input, FILE *output);
static void print_known_names (void); static void print_known_names (void) internal_function;
int int
@ -503,9 +503,38 @@ do_print (const void *nodep, VISIT value, int level)
} }
static void static void
internal_function
add_known_names (struct gconv_module *node)
{
if (node->left != NULL)
add_known_names (node->left);
if (node->right != NULL)
add_known_names (node->right);
if (node->same != NULL)
add_known_names (node->same);
do
{
if (node->from_pattern == NULL)
{
if (strcmp (node->from_constpfx, "INTERNAL"))
tsearch (node->from_constpfx, &printlist,
(__compar_fn_t) strverscmp);
if (strcmp (node->to_string, "INTERNAL"))
tsearch (node->to_string, &printlist, (__compar_fn_t) strverscmp);
}
else
if (strcmp (node->from_pattern, "INTERNAL"))
tsearch (node->from_pattern, &printlist, (__compar_fn_t) strverscmp);
node = node->matching;
}
while (node != NULL);
}
static void
internal_function
print_known_names (void) print_known_names (void)
{ {
size_t cnt;
iconv_t h; iconv_t h;
/* We must initialize the internal databases first. */ /* We must initialize the internal databases first. */
@ -516,22 +545,7 @@ print_known_names (void)
twalk (__gconv_alias_db, insert_print_list); twalk (__gconv_alias_db, insert_print_list);
/* Add the from- and to-names from the known modules. */ /* Add the from- and to-names from the known modules. */
for (cnt = 0; cnt < __gconv_nmodules; ++cnt) add_known_names (__gconv_modules_db);
{
if (__gconv_modules_db[cnt]->from_pattern == NULL)
{
if (strcmp (__gconv_modules_db[cnt]->from_constpfx, "INTERNAL"))
tsearch (__gconv_modules_db[cnt]->from_constpfx, &printlist,
(__compar_fn_t) strverscmp);
if (strcmp (__gconv_modules_db[cnt]->to_string, "INTERNAL"))
tsearch (__gconv_modules_db[cnt]->to_string, &printlist,
(__compar_fn_t) strverscmp);
}
else
if (strcmp (__gconv_modules_db[cnt]->from_pattern, "INTERNAL"))
tsearch (__gconv_modules_db[cnt]->from_pattern, &printlist,
(__compar_fn_t) strverscmp);
}
fputs (_("\ fputs (_("\
The following list contain all the coded character sets known. This does\n\ The following list contain all the coded character sets known. This does\n\

View File

@ -1,5 +1,7 @@
# File name Caller Syscall name # args Strong name Weak names # File name Caller Syscall name # args Strong name Weak names
vfork - vfork 0 vfork
s_getgroups getgroups getgroups 2 __syscall_getgroups s_getgroups getgroups getgroups 2 __syscall_getgroups
s_getpagesize getpagesize getpagesize 0 __syscall_getpagesize s_getpagesize getpagesize getpagesize 0 __syscall_getpagesize
s_llseek llseek _llseek 5 __syscall__llseek s_llseek llseek _llseek 5 __syscall__llseek
@ -37,7 +39,6 @@ s_sigprocmask sigprocmask sigprocmask 3 __syscall_sigprocmask
s_sigsuspend sigsuspend sigsuspend 3 __syscall_sigsuspend s_sigsuspend sigsuspend sigsuspend 3 __syscall_sigsuspend
s_sysctl sysctl _sysctl 1 __syscall__sysctl s_sysctl sysctl _sysctl 1 __syscall__sysctl
s_ustat ustat ustat 2 __syscall_ustat s_ustat ustat ustat 2 __syscall_ustat
s_vfork vfork vfork 0 __syscall_vfork
sys_fstat fxstat fstat 2 __syscall_fstat sys_fstat fxstat fstat 2 __syscall_fstat
sys_lstat lxstat lstat 2 __syscall_lstat sys_lstat lxstat lstat 2 __syscall_lstat
sys_mknod xmknod mknod 3 __syscall_mknod sys_mknod xmknod mknod 3 __syscall_mknod

View File

@ -11,6 +11,7 @@ setrlimit - setrlimit 2 setrlimit setrlimit64
ftruncate - ftruncate 2 __ftruncate ftruncate ftruncate64 ftruncate - ftruncate 2 __ftruncate ftruncate ftruncate64
truncate - truncate 2 truncate truncate64 truncate - truncate 2 truncate truncate64
mmap - mmap 6 __mmap mmap __mmap64 mmap64 mmap - mmap 6 __mmap mmap __mmap64 mmap64
vfork - vfork 0 vfork
# Override select.S in parent directory: # Override select.S in parent directory:
select - select 5 __select select select - select 5 __select select
@ -56,7 +57,6 @@ s_sigprocmask sigprocmask sigprocmask 3 __syscall_sigprocmask
s_sigsuspend sigsuspend sigsuspend 3 __syscall_sigsuspend s_sigsuspend sigsuspend sigsuspend 3 __syscall_sigsuspend
s_sysctl sysctl _sysctl 1 __syscall__sysctl s_sysctl sysctl _sysctl 1 __syscall__sysctl
s_ustat ustat ustat 2 __syscall_ustat s_ustat ustat ustat 2 __syscall_ustat
s_vfork vfork vfork 0 __syscall_vfork
sys_fstat fxstat fstat 2 __syscall_fstat sys_fstat fxstat fstat 2 __syscall_fstat
sys_lstat lxstat lstat 2 __syscall_lstat sys_lstat lxstat lstat 2 __syscall_lstat
sys_mknod xmknod mknod 3 __syscall_mknod sys_mknod xmknod mknod 3 __syscall_mknod