diff options
-rw-r--r-- | ChangeLog | 14 | ||||
-rw-r--r-- | iconv/gconv_conf.c | 115 | ||||
-rw-r--r-- | iconv/gconv_db.c | 28 | ||||
-rw-r--r-- | iconv/gconv_int.h | 1 | ||||
-rw-r--r-- | manual/search.texi | 4 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/tcsetattr.c | 4 |
6 files changed, 135 insertions, 31 deletions
diff --git a/ChangeLog b/ChangeLog index 77a6d9a2cc..acd528eb41 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,19 @@ 1998-12-17 Ulrich Drepper <drepper@cygnus.com> + * iconv/gconv_int.h (gconv_module): Add new element from_regex_mem. + * iconv/gconv_conf.c (module_compare): Make s1 and s2 const. + (detect_conflict): New function. + (add_alias): Call detect_conflict to see whether there is already + a module for the new name. + (add_module): Make sure there is no alias for the new name. + (read_conf_file): Call add_alias with new argument. + (__gconv_read_conf): Don't destroy module tree immediately after + walking it. We need it to test the internal conversions for + conflicts. + * iconv/gconv_db.c (find_derivation): Don't allocate memory for + regular expression. There is now room in the module descriptor. + (free_mem): Don't free memory for regular expression. + * sysdeps/unix/sysv/linux/bits/socket.h: Add AF_IRDA, PF_IRDA and MSG_TRYHARD. diff --git a/iconv/gconv_conf.c b/iconv/gconv_conf.c index 1b0f5b81d4..d3f516effa 100644 --- a/iconv/gconv_conf.c +++ b/iconv/gconv_conf.c @@ -87,8 +87,8 @@ builtin_aliases[] = static int module_compare (const void *p1, const void *p2) { - struct gconv_module *s1 = (struct gconv_module *) p1; - struct gconv_module *s2 = (struct gconv_module *) p2; + const struct gconv_module *s1 = (const struct gconv_module *) p1; + const struct gconv_module *s2 = (const struct gconv_module *) p2; int result; if (s1->from_pattern == NULL) @@ -110,9 +110,78 @@ module_compare (const void *p1, const void *p2) } +/* 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 + { + /* Make sure the regular expression is compiled (if possible). */ + if (s->from_regex == NULL) + { + /* Beware, this is what I warned you about in the comment + above. We are modifying the object. */ + if (__regcomp (&s->from_regex_mem, s->from_pattern, + REG_EXTENDED | REG_ICASE) != 0) + /* Something is wrong. Remember this. */ + s->from_regex = (regex_t *) -1L; + else + s->from_regex = &s->from_regex_mem; + } + + if (s->from_regex != (regex_t *) -1L) + { + regmatch_t match[1]; + + if (__regexec (s->from_regex, alias_to_test, 1, match, 0) == 0 + && match[0].rm_so == 0 + && alias_to_test[match[0].rm_eo] == '\0') + /* The whole string matched. This is also a conflict. */ + abort_conflict_search = 1; + } + } + } +} + + /* Add new alias. */ static inline void -add_alias (char *rp) +add_alias (char *rp, void *modules) { /* We now expect two more string. The strings are normalized (converted to UPPER case) and strored in the alias database. */ @@ -138,6 +207,16 @@ add_alias (char *rp) return; *wp++ = '\0'; + /* Test whether this alias conflicts with any available module. See + the comment before the function `detect_conflict' for a description + 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. */ + return; + new_alias = (struct gconv_alias *) malloc (sizeof (struct gconv_alias) + (wp - from)); if (new_alias != NULL) @@ -290,6 +369,25 @@ add_module (char *rp, const char *directory, size_t dir_len, void **modules, if (need_ext) memcpy (tmp - 1, gconv_module_ext, sizeof (gconv_module_ext)); + /* See whether we have already an alias with this name defined. + We do allow regular expressions matching this any alias since + this expression can also match other names and we test for aliases + before testing for modules. */ + if (! from_is_regex) + { + struct gconv_alias fake_alias; + + fake_alias.fromname = new_module->from_constpfx; + + if (__tfind (&fake_alias, &__gconv_alias_db, __gconv_alias_compare) + != NULL) + { + /* This module duplicates an alias. */ + free (new_module); + return; + } + } + if (__tfind (new_module, modules, module_compare) == NULL) { if (__tsearch (new_module, modules, module_compare) == NULL) @@ -364,7 +462,7 @@ read_conf_file (const char *filename, const char *directory, size_t dir_len, if (rp - word == sizeof ("alias") - 1 && memcmp (word, "alias", sizeof ("alias") - 1) == 0) - add_alias (rp); + add_alias (rp, *modules); else if (rp - word == sizeof ("module") - 1 && memcmp (word, "module", sizeof ("module") - 1) == 0) add_module (rp, directory, dir_len, modules, nmodules, modcounter++); @@ -449,9 +547,6 @@ __gconv_read_conf (void) /* Insert all module entries into the array. */ __twalk (modules, insert_module); - /* No remove the tree data structure. */ - __tdestroy (modules, nothing); - /* Finally insert the builtin transformations. */ for (cnt = 0; cnt < (sizeof (builtin_modules) / sizeof (struct gconv_module)); ++cnt) @@ -464,8 +559,12 @@ __gconv_read_conf (void) while (cnt > 0) { char *copy = strdupa (builtin_aliases[--cnt]); - add_alias (copy); + add_alias (copy, modules); } + + if (nmodules != 0) + /* Now remove the tree data structure. */ + __tdestroy (modules, nothing); /* Restore the error number. */ __set_errno (save_errno); diff --git a/iconv/gconv_db.c b/iconv/gconv_db.c index f5a67ffbab..11914547c7 100644 --- a/iconv/gconv_db.c +++ b/iconv/gconv_db.c @@ -348,17 +348,14 @@ find_derivation (const char *toset, const char *toset_expand, /* First compile the regex if not already done. */ if (__gconv_modules_db[cnt]->from_regex == NULL) { - regex_t *newp = (regex_t *) malloc (sizeof (regex_t)); - - if (__regcomp (newp, __gconv_modules_db[cnt]->from_pattern, + if (__regcomp (&__gconv_modules_db[cnt]->from_regex_mem, + __gconv_modules_db[cnt]->from_pattern, REG_EXTENDED | REG_ICASE) != 0) - { - /* Something is wrong. Remember this. */ - free (newp); - __gconv_modules_db[cnt]->from_regex = (regex_t *) -1L; - } + /* Something is wrong. Remember this. */ + __gconv_modules_db[cnt]->from_regex = (regex_t *) -1L; else - __gconv_modules_db[cnt]->from_regex = newp; + __gconv_modules_db[cnt]->from_regex + = &__gconv_modules_db[cnt]->from_regex_mem; } if (__gconv_modules_db[cnt]->from_regex != (regex_t *) -1L) @@ -627,15 +624,10 @@ free_mem (void) __tdestroy (__gconv_alias_db, free); for (cnt = 0; cnt < __gconv_nmodules; ++cnt) - { - if (__gconv_modules_db[cnt]->from_regex != NULL) - __regfree ((regex_t *) __gconv_modules_db[cnt]->from_regex); - - /* 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]); - } + /* 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) __tdestroy (known_derivations, free_derivation); diff --git a/iconv/gconv_int.h b/iconv/gconv_int.h index f0239195c9..bc67b0b050 100644 --- a/iconv/gconv_int.h +++ b/iconv/gconv_int.h @@ -67,6 +67,7 @@ struct gconv_module const char *from_constpfx; size_t from_constpfx_len; const regex_t *from_regex; + regex_t from_regex_mem; const char *to_string; diff --git a/manual/search.texi b/manual/search.texi index 0bcbc9b4d3..b43153a44b 100644 --- a/manual/search.texi +++ b/manual/search.texi @@ -498,10 +498,10 @@ structure there is another function which allows to apply a function on all elements of the tree. The function must have this type: @smallexample -int __action_fn_t (const void *nodep, VISIT value, int level); +void __action_fn_t (const void *nodep, VISIT value, int level); @end smallexample -The @var{nodep} is the data value of the current node (nce given as the +The @var{nodep} is the data value of the current node (once given as the @var{key} argument to @code{tsearch}). @var{level} is a numeric value which corresponds to the depth of the current node in the tree. The root node has the depth @math{0} and its children have a depth of diff --git a/sysdeps/unix/sysv/linux/tcsetattr.c b/sysdeps/unix/sysv/linux/tcsetattr.c index b919dbe1c4..4a352372c9 100644 --- a/sysdeps/unix/sysv/linux/tcsetattr.c +++ b/sysdeps/unix/sysv/linux/tcsetattr.c @@ -73,9 +73,7 @@ tcsetattr (fd, optional_actions, termios_p) return -1; } - termios_p->c_iflag &= ~IBAUD0; - - k_termios.c_iflag = termios_p->c_iflag; + k_termios.c_iflag = termios_p->c_iflag & ~IBAUD0; k_termios.c_oflag = termios_p->c_oflag; k_termios.c_cflag = termios_p->c_cflag; k_termios.c_lflag = termios_p->c_lflag; |