diff options
author | Ulrich Drepper <drepper@redhat.com> | 2000-06-19 21:12:06 +0000 |
---|---|---|
committer | Ulrich Drepper <drepper@redhat.com> | 2000-06-19 21:12:06 +0000 |
commit | d620426811688301eb1cbe6e63773d6430b2706e (patch) | |
tree | 555eb9182298ec1e56db8a5de4f62daa2e654321 /iconv | |
parent | 01da56ba764e6abc52bfe9a1feeb79d3d67346d1 (diff) | |
download | glibc-d620426811688301eb1cbe6e63773d6430b2706e.tar.gz glibc-d620426811688301eb1cbe6e63773d6430b2706e.tar.xz glibc-d620426811688301eb1cbe6e63773d6430b2706e.zip |
Update.
2000-06-19 Ulrich Drepper <drepper@redhat.com> * iconv/gconv.h (__gconv_trans_fct): Add new parameter. General namespace cleanup. (struct __gconv_trans_data): Add next field. (struct __gconv_step_data): Make __trans a pointer. * iconv/gconv_conf.c: Split out code to find gconv directories from __gconv_read_conf in new functions. * iconv/gconv_int.h: Define new data structure and declare new functions for handling of gconv directory list. * iconv/gconv_open.c: Allow more than one error handling step being used. Call function to load error handling module if it is none of the builtin transformations. * iconv/gconv_close.c: Add code to free transliteration data. * iconv/gconv_trans.c: Add functions to load and unload modules implementing transliteration etc. * iconv/skeleton.c: Call all context functions now that more than one module is allowed. * iconv/loop.c (STANDARD_ERR_HANDLING): New macro. * iconv/gconv_simple.c: Use STANDARD_ERR_HANDLING macro for places where the full error handling using transliteration is needed. * iconvdata/8bit-gap.c: Likewise. * iconvdata/8bit-generic.c: Likewise. * iconvdata/ansi_x3.110.c: Likewise. * iconvdata/big5.c: Likewise. * iconvdata/big5hkscs.c: Likewise. * iconvdata/euc-cn.c: Likewise. * iconvdata/euc-jp.c: Likewise. * iconvdata/euc-kr.c: Likewise. * iconvdata/euc-tw.c: Likewise. * iconvdata/gbgbk.c: Likewise. * iconvdata/gbk.c: Likewise. * iconvdata/iso-2022-cn.c: Likewise. * iconvdata/iso-2022-jp.c: Likewise. * iconvdata/iso-2022-kr.c: Likewise. * iconvdata/iso646.c: Likewise. * iconvdata/iso8859-1.c: Likewise. * iconvdata/iso_6937-2.c: Likewise. * iconvdata/iso_6937.c: Likewise. * iconvdata/johab.c: Likewise. * iconvdata/sjis.c: Likewise. * iconvdata/t.61.c: Likewise. * iconvdata/uhc.c: Likewise. * iconvdata/unicode.c: Likewise. * iconvdata/utf-16.c: Likewise. * libio/iofwide.c: Reset __trans member of __gconv_trans_data structure correctly after last change. * wcsmbs/btowc.c: Likewise. * wcsmbs/mbrtowc.c: Likewise. * wcsmbs/mbsnrtowcs.c: Likewise. * wcsmbs/mbsrtowcs.c: Likewise. * wcsmbs/wcrtomb.c: Likewise. * wcsmbs/wcsnrtombs.c: Likewise. * wcsmbs/wcsrtombs.c: Likewise. * wcsmbs/wctob.c: Likewise. * localedata/Makefile: Set -Wno-format for some files since gcc does not know all the format specifiers. 2000-06-18 Ulrich Drepper <drepper@redhat.com> * locale/loadlocale.c (_nl_unload_locale): Remove a bit of unneeded code. * locale/lc-time.c (_nl_init_era_entries): Likewise.
Diffstat (limited to 'iconv')
-rw-r--r-- | iconv/gconv.h | 12 | ||||
-rw-r--r-- | iconv/gconv_close.c | 14 | ||||
-rw-r--r-- | iconv/gconv_conf.c | 153 | ||||
-rw-r--r-- | iconv/gconv_int.h | 36 | ||||
-rw-r--r-- | iconv/gconv_open.c | 255 | ||||
-rw-r--r-- | iconv/gconv_simple.c | 59 | ||||
-rw-r--r-- | iconv/gconv_trans.c | 180 | ||||
-rw-r--r-- | iconv/loop.c | 32 | ||||
-rw-r--r-- | iconv/skeleton.c | 10 |
9 files changed, 586 insertions, 165 deletions
diff --git a/iconv/gconv.h b/iconv/gconv.h index 0164b62c8b..50458e2aeb 100644 --- a/iconv/gconv.h +++ b/iconv/gconv.h @@ -76,21 +76,22 @@ typedef void (*__gconv_end_fct) (struct __gconv_step *); /* Type of a transliteration/transscription function. */ -typedef int (*__gconv_trans_fct) (struct __gconv_step *step, - struct __gconv_step_data *step_data, +typedef int (*__gconv_trans_fct) (struct __gconv_step *, + struct __gconv_step_data *, void *, __const unsigned char *, __const unsigned char **, __const unsigned char *, unsigned char **, size_t *); /* Function to call to provide transliteration module with context. */ -typedef int (*__gconv_trans_context_fct) (struct __gconv_trans_data *data, +typedef int (*__gconv_trans_context_fct) (struct __gconv_trans_data *, __const unsigned char *, __const unsigned char *, unsigned char *, unsigned char *); /* Function to query module about supported encoded character sets. */ -typedef int (*__gconv_trans_query_fct) (__const char **, size_t *); +typedef int (*__gconv_trans_query_fct) (__const char *, __const char ***, + size_t *); /* Constructor and destructor for local data for transliteration. */ typedef int (*__gconv_trans_init_fct) (void **, const char *); @@ -103,6 +104,7 @@ struct __gconv_trans_data __gconv_trans_context_fct __trans_context_fct; __gconv_trans_end_fct __trans_end_fct; void *__data; + struct __gconv_trans_data *__next; }; @@ -158,7 +160,7 @@ struct __gconv_step_data any module; always use STATEP! */ /* Transliteration information. */ - struct __gconv_trans_data __trans; + struct __gconv_trans_data *__trans; }; diff --git a/iconv/gconv_close.c b/iconv/gconv_close.c index 79dcb0b3a1..002e2c4dce 100644 --- a/iconv/gconv_close.c +++ b/iconv/gconv_close.c @@ -38,6 +38,20 @@ __gconv_close (__gconv_t cd) drunp = cd->__data; do { + struct __gconv_trans_data *transp; + + transp = drunp->__trans; + while (transp != NULL) + { + struct __gconv_trans_data *curp = transp; + transp = transp->__next; + + if (__builtin_expect (curp->__trans_end_fct != NULL, 0)) + curp->__trans_end_fct (curp->__data); + + free (curp); + } + if (!(drunp->__flags & __GCONV_IS_LAST) && drunp->__outbuf != NULL) free (drunp->__outbuf); } diff --git a/iconv/gconv_conf.c b/iconv/gconv_conf.c index 0d25c22416..480b459134 100644 --- a/iconv/gconv_conf.c +++ b/iconv/gconv_conf.c @@ -1,5 +1,5 @@ /* Handle configuration data. - Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc. + Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997. @@ -18,6 +18,7 @@ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include <assert.h> #include <ctype.h> #include <errno.h> #include <limits.h> @@ -34,6 +35,14 @@ /* This is the default path where we look for module lists. */ static const char default_gconv_path[] = GCONV_PATH; +/* The path element in use. */ +const struct path_elem *__gconv_path_elem; +/* Maximum length of a single path element. */ +size_t __gconv_max_path_elem_len; + +/* We use the following struct if we couldn't allocate memory. */ +static const struct path_elem empty_path_elem; + /* Name of the file containing the module information in the directories along the path. */ static const char gconv_conf_filename[] = "gconv-modules"; @@ -497,48 +506,125 @@ read_conf_file (const char *filename, const char *directory, size_t dir_len, /* Otherwise ignore the line. */ } - if (line != NULL) - free (line); + free (line); + fclose (fp); } +/* Determine the directories we are looking for data in. */ +void +__gconv_get_path (void) +{ + struct path_elem *result; + __libc_lock_define_initialized (static, lock); + + __libc_lock_lock (lock); + + /* Make sure there wasn't a second thread doing it already. */ + result = (struct path_elem *) __gconv_path_elem; + if (result == NULL) + { + /* Determine the complete path first. */ + const char *user_path; + char *gconv_path; + size_t gconv_path_len; + char *elem; + char *oldp; + char *cp; + int nelems; + + user_path = __secure_getenv ("GCONV_PATH"); + if (user_path == NULL) + { + /* No user-defined path. Make a modifiable copy of the + default path. */ + gconv_path = strdupa (default_gconv_path); + gconv_path_len = sizeof (default_gconv_path); + } + else + { + /* Append the default path to the user-defined path. */ + size_t user_len = strlen (user_path); + + gconv_path_len = user_len + 1 + sizeof (default_gconv_path); + gconv_path = alloca (gconv_path_len); + __mempcpy (__mempcpy (__mempcpy (gconv_path, user_path, user_len), + ":", 1), + default_gconv_path, sizeof (default_gconv_path)); + } + + /* In a first pass we calculate the number of elements. */ + oldp = NULL; + cp = strchr (gconv_path, ':'); + nelems = 1; + while (cp != NULL) + { + if (cp != oldp + 1) + ++nelems; + oldp = cp; + cp = strchr (cp + 1, ':'); + } + + /* Allocate the memory for the result. */ + result = (struct path_elem *) malloc ((nelems + 1) + * sizeof (struct path_elem) + + gconv_path_len + nelems); + if (result != NULL) + { + char *strspace = (char *) &result[nelems + 1]; + int n = 0; + + /* Separate the individual parts. */ + __gconv_max_path_elem_len = 0; + elem = __strtok_r (gconv_path, ":", &gconv_path); + assert (elem != NULL); + do + { + result[n].name = strspace; + strspace = __stpcpy (strspace, elem); + if (strspace[-1] != '/') + *strspace++ = '/'; + + result[n].len = strspace - result[n].name; + if (result[n].len > __gconv_max_path_elem_len) + __gconv_max_path_elem_len = result[n].len; + + *strspace++ = '\0'; + ++n; + } + while ((elem = __strtok_r (NULL, ":", &gconv_path)) != NULL); + + result[n].name = NULL; + result[n].len = 0; + } + + __gconv_path_elem = result ?: &empty_path_elem; + } + + __libc_lock_unlock (lock); +} + + /* Read all configuration files found in the user-specified and the default path. */ void __gconv_read_conf (void) { - const char *user_path = __secure_getenv ("GCONV_PATH"); - char *gconv_path, *elem; void *modules = NULL; size_t nmodules = 0; int save_errno = errno; size_t cnt; - if (user_path == NULL) - /* No user-defined path. Make a modifiable copy of the default path. */ - gconv_path = strdupa (default_gconv_path); - else - { - /* Append the default path to the user-defined path. */ - size_t user_len = strlen (user_path); - - gconv_path = alloca (user_len + 1 + sizeof (default_gconv_path)); - __mempcpy (__mempcpy (__mempcpy (gconv_path, user_path, user_len), - ":", 1), - default_gconv_path, sizeof (default_gconv_path)); - } + /* Find out where we have to look. */ + if (__gconv_path_elem == NULL) + __gconv_get_path (); - elem = __strtok_r (gconv_path, ":", &gconv_path); - while (elem != NULL) + for (cnt = 0; __gconv_path_elem[cnt].name != NULL; ++cnt) { -#ifndef MAXPATHLEN - /* We define a reasonable limit. */ -# define MAXPATHLEN 4096 -#endif - char real_elem[MAXPATHLEN]; + char real_elem[__gconv_max_path_elem_len + sizeof (gconv_conf_filename)]; - if (__realpath (elem, real_elem) != NULL) + if (__realpath (__gconv_path_elem[cnt].name, real_elem) != NULL) { size_t elem_len = strlen (real_elem); char *filename; @@ -551,9 +637,6 @@ __gconv_read_conf (void) /* Read the next configuration file. */ read_conf_file (filename, real_elem, elem_len, &modules, &nmodules); } - - /* Get next element in the path. */ - elem = __strtok_r (NULL, ":", &gconv_path); } /* Add the internal modules. */ @@ -586,3 +669,15 @@ __gconv_read_conf (void) /* Restore the error number. */ __set_errno (save_errno); } + + + +/* Free all resources if necessary. */ +static void __attribute__ ((unused)) +free_mem (void) +{ + if (__gconv_path_elem != NULL && __gconv_path_elem != &empty_path_elem) + free ((void *) __gconv_path_elem); +} + +text_set_element (__libc_subfreeres, free_mem); diff --git a/iconv/gconv_int.h b/iconv/gconv_int.h index 5bdf7143e6..6d199715ca 100644 --- a/iconv/gconv_int.h +++ b/iconv/gconv_int.h @@ -26,6 +26,19 @@ __BEGIN_DECLS +/* Type to represent search path. */ +struct path_elem +{ + const char *name; + size_t len; +}; + +/* Variable with search path for `gconv' implementation. */ +extern const struct path_elem *__gconv_path_elem; +/* Maximum length of a single path element. */ +extern size_t __gconv_max_path_elem_len; + + /* Structure for alias definition. Simply to strings. */ struct gconv_alias { @@ -83,6 +96,21 @@ struct gconv_module }; +/* Internal data structure to represent transliteration module. */ +struct trans_struct +{ + const char *name; + struct trans_struct *next; + + const char **csnames; + size_t ncsnames; + __gconv_trans_fct trans_fct; + __gconv_trans_context_fct trans_context_fct; + __gconv_trans_init_fct trans_init_fct; + __gconv_trans_end_fct trans_end_fct; +}; + + /* Flags for `gconv_open'. */ enum { @@ -161,6 +189,9 @@ extern int __gconv_find_transform (const char *toset, const char *fromset, /* Read all the configuration data and cache it. */ extern void __gconv_read_conf (void); +/* Determine the directories we are looking in. */ +extern void __gconv_get_path (void); + /* Comparison function to search alias. */ extern int __gconv_alias_compare (const void *p1, const void *p2); @@ -185,9 +216,14 @@ extern void __gconv_get_builtin_trans (const char *name, struct __gconv_step *step) internal_function; +/* Try to load transliteration step module. */ +extern int __gconv_translit_find (struct trans_struct *trans) + internal_function; + /* Transliteration using the locale's data. */ extern int __gconv_transliterate (struct __gconv_step *step, struct __gconv_step_data *step_data, + void *trans_data, __const unsigned char *inbufstart, __const unsigned char **inbufp, __const unsigned char *inbufend, diff --git a/iconv/gconv_open.c b/iconv/gconv_open.c index d2963fa8ee..2374703e21 100644 --- a/iconv/gconv_open.c +++ b/iconv/gconv_open.c @@ -38,6 +38,7 @@ __gconv_open (const char *toset, const char *fromset, __gconv_t *handle, int conv_flags = 0; const char *errhand; const char *ignore; + struct trans_struct *trans = NULL; /* Find out whether any error handling method is specified. */ errhand = strchr (toset, '/'); @@ -51,17 +52,85 @@ __gconv_open (const char *toset, const char *fromset, __gconv_t *handle, { /* Make copy without the error handling description. */ char *newtoset = (char *) alloca (errhand - toset + 1); + char *tok; + char *ptr; newtoset[errhand - toset] = '\0'; toset = memcpy (newtoset, toset, errhand - toset); - flags = __GCONV_IGNORE_ERRORS; + /* Find the appropriate transliteration handlers. */ + tok = strdupa (errhand); - if (__strcasecmp (errhand, "IGNORE") == 0) + tok = __strtok_r (tok, ",", &ptr); + while (tok != NULL) { - /* Found it. This means we should ignore conversion errors. */ - flags = __GCONV_IGNORE_ERRORS; - errhand = NULL; + if (__strcasecmp (tok, "TRANSLIT") == 0) + { + /* It's the builtin transliteration handling. We only + support it for working on the internal encoding. */ + static const char *internal_trans_names[1] = { "INTERNAL" }; + struct trans_struct *lastp = NULL; + struct trans_struct *runp; + + for (runp = trans; runp != NULL; runp = runp->next) + if (runp->trans_fct == __gconv_transliterate) + break; + else + lastp = runp; + + if (runp == NULL) + { + struct trans_struct *newp; + + newp = (struct trans_struct *) alloca (sizeof (*newp)); + memset (newp, '\0', sizeof (*newp)); + + /* We leave the `name' field zero to signal that + this is an internal transliteration step. */ + newp->csnames = internal_trans_names; + newp->ncsnames = 1; + newp->trans_fct = __gconv_transliterate; + + if (lastp == NULL) + trans = newp; + else + lastp->next = newp; + } + } + else if (__strcasecmp (tok, "IGNORE") == 0) + /* Set the flag to ignore all errors. */ + flags = __GCONV_IGNORE_ERRORS; + else + { + /* `tok' is possibly a module name. We'll see later + whether we can find it. But first see that we do + not already a module of this name. */ + struct trans_struct *lastp = NULL; + struct trans_struct *runp; + + for (runp = trans; runp != NULL; runp = runp->next) + if (runp->name != NULL + && __strcasecmp (tok, runp->name) == 0) + break; + else + lastp = runp; + + if (runp == NULL) + { + struct trans_struct *newp; + + newp = (struct trans_struct *) alloca (sizeof (*newp)); + memset (newp, '\0', sizeof (*newp)); + newp->name = tok; + + if (lastp == NULL) + trans = newp; + else + lastp->next = newp; + } + } + + tok = __strtok_r (NULL, ",", &ptr); } } } @@ -81,31 +150,18 @@ __gconv_open (const char *toset, const char *fromset, __gconv_t *handle, res = __gconv_find_transform (toset, fromset, &steps, &nsteps, flags); if (res == __GCONV_OK) { - const char **csnames = NULL; - size_t ncsnames = 0; - __gconv_trans_fct trans_fct = NULL; - __gconv_trans_context_fct trans_context_fct = NULL; - __gconv_trans_init_fct trans_init_fct = NULL; - __gconv_trans_end_fct trans_end_fct = NULL; - - if (errhand != NULL) + /* Find the modules. */ + struct trans_struct *lastp = NULL; + struct trans_struct *runp; + + for (runp = trans; runp != NULL; runp = runp->next) { - /* Find the appropriate transliteration handling. */ - if (__strcasecmp (errhand, "TRANSLIT") == 0) - { - /* It's the builtin transliteration handling. We only - suport for it working on the internal encoding. */ - static const char *internal_trans_names[1] = { "INTERNAL" }; - - csnames = internal_trans_names; - ncsnames = 1; - trans_fct = __gconv_transliterate; - /* No context, init, or end function. */ - } - else if (__strcasecmp (errhand, "WORK AROUND A GCC BUG") == 0) - { - trans_init_fct = (__gconv_trans_init_fct) 1; - } + if (runp->name == NULL + || __builtin_expect (__gconv_translit_find (runp), 0) == 0) + lastp = runp; + else + /* This means we haven't found the module. Remove it. */ + (lastp == NULL ? trans : lastp->next) = runp->next; } /* Allocate room for handle. */ @@ -154,32 +210,51 @@ __gconv_open (const char *toset, const char *fromset, __gconv_t *handle, result->__data[cnt].__outbuf = (char *) malloc (size); if (result->__data[cnt].__outbuf == NULL) - { - res = __GCONV_NOMEM; - break; - } + goto bail; + result->__data[cnt].__outbufend = result->__data[cnt].__outbuf + size; - /* Now see whether we can use the transliteration module - for this step. */ - for (n = 0; n < ncsnames; ++n) - if (__strcasecmp (steps[cnt].__from_name, csnames[n]) == 0) - { - /* Match! Now try the initializer. */ - if (trans_init_fct == NULL - || (trans_init_fct (&result->__data[cnt].__trans.__data, - steps[cnt].__to_name) - == __GCONV_OK)) - { - result->__data[cnt].__trans.__trans_fct = trans_fct; - result->__data[cnt].__trans.__trans_context_fct = - trans_context_fct; - result->__data[cnt].__trans.__trans_end_fct = - trans_end_fct; - } - break; - } + /* Now see whether we can use any of the transliteration + modules for this step. */ + for (runp = trans; runp != NULL; runp = runp->next) + for (n = 0; n < runp->ncsnames; ++n) + if (__strcasecmp (steps[cnt].__from_name, + runp->csnames[n]) == 0) + { + void *data = NULL; + + /* Match! Now try the initializer. */ + if (runp->trans_init_fct == NULL + || (runp->trans_init_fct (data, steps[cnt].__to_name) + == __GCONV_OK)) + { + /* Append at the end of the list. */ + struct __gconv_trans_data *newp; + struct __gconv_trans_data *endp; + struct __gconv_trans_data *lastp; + + newp = (struct __gconv_trans_data *) + malloc (sizeof (struct __gconv_trans_data)); + if (newp == NULL) + goto bail; + + newp->__trans_fct = runp->trans_fct; + newp->__trans_context_fct = runp->trans_context_fct; + newp->__trans_end_fct = runp->trans_end_fct; + + lastp = NULL; + for (endp = result->__data[cnt].__trans; + endp != NULL; endp = endp->__next) + lastp = endp; + + if (lastp == NULL) + result->__data[cnt].__trans = newp; + else + lastp->__next = newp; + } + break; + } } /* Now handle the last entry. */ @@ -194,34 +269,72 @@ __gconv_open (const char *toset, const char *fromset, __gconv_t *handle, /* Now see whether we can use the transliteration module for this step. */ - for (n = 0; n < ncsnames; ++n) - if (__strcasecmp (steps[cnt].__from_name, csnames[n]) == 0) - { - /* Match! Now try the initializer. */ - if (trans_init_fct == NULL - || trans_init_fct (&result->__data[cnt].__trans.__data, - steps[cnt].__to_name) - == __GCONV_OK) - { - result->__data[cnt].__trans.__trans_fct = trans_fct; - result->__data[cnt].__trans.__trans_context_fct = - trans_context_fct; - result->__data[cnt].__trans.__trans_end_fct = - trans_end_fct; - } - break; - } + for (runp = trans; runp != NULL; runp = runp->next) + for (n = 0; n < runp->ncsnames; ++n) + if (__strcasecmp (steps[cnt].__from_name, runp->csnames[n]) == 0) + { + void *data = NULL; + + /* Match! Now try the initializer. */ + if (runp->trans_init_fct == NULL + || (runp->trans_init_fct (data, steps[cnt].__to_name) + == __GCONV_OK)) + { + /* Append at the end of the list. */ + struct __gconv_trans_data *newp; + struct __gconv_trans_data *endp; + struct __gconv_trans_data *lastp; + + newp = (struct __gconv_trans_data *) + malloc (sizeof (struct __gconv_trans_data)); + if (newp == NULL) + goto bail; + + newp->__trans_fct = runp->trans_fct; + newp->__trans_context_fct = runp->trans_context_fct; + newp->__trans_end_fct = runp->trans_end_fct; + + lastp = NULL; + for (endp = result->__data[cnt].__trans; + endp != NULL; endp = endp->__next) + lastp = endp; + + if (lastp == NULL) + result->__data[cnt].__trans = newp; + else + lastp->__next = newp; + } + break; + } } if (res != __GCONV_OK) { /* Something went wrong. Free all the resources. */ - int serrno = errno; + int serrno; + bail: + serrno = errno; if (result != NULL) { while (cnt-- > 0) - free (result->__data[cnt].__outbuf); + { + struct __gconv_trans_data *transp; + + transp = result->__data[cnt].__trans; + while (transp != NULL) + { + struct __gconv_trans_data *curp = transp; + transp = transp->__next; + + if (__builtin_expect (curp->__trans_end_fct != NULL, 0)) + curp->__trans_end_fct (curp->__data); + + free (curp); + } + + free (result->__data[cnt].__outbuf); + } free (result); result = NULL; diff --git a/iconv/gconv_simple.c b/iconv/gconv_simple.c index 390574582f..019aac2a3f 100644 --- a/iconv/gconv_simple.c +++ b/iconv/gconv_simple.c @@ -797,25 +797,7 @@ ucs4le_internal_loop_single (struct __gconv_step *step, /* XXX unaligned. */ \ if (__builtin_expect (*((uint32_t *) inptr), 0) > 0x7f) \ { \ - if (step_data->__trans.__trans_fct != NULL) \ - { \ - result = DL_CALL_FCT (step_data->__trans.__trans_fct, \ - (step, step_data, *inptrp, &inptr, inend, \ - &outptr, irreversible)); \ - if (result != __GCONV_OK) \ - break; \ - } \ - else if (! ignore_errors_p ()) \ - { \ - /* This is no correct ANSI_X3.4-1968 character. */ \ - result = __GCONV_ILLEGAL_INPUT; \ - break; \ - } \ - else \ - { \ - ++*irreversible; \ - inptr += 4; \ - } \ + STANDARD_ERR_HANDLER (4); \ } \ else \ /* It's an one byte sequence. */ \ @@ -1186,24 +1168,7 @@ ucs4le_internal_loop_single (struct __gconv_step *step, { \ if (__builtin_expect (*((uint32_t *) inptr), 0) >= 0x10000) \ { \ - if (step_data->__trans.__trans_fct != NULL) \ - { \ - result = DL_CALL_FCT (step_data->__trans.__trans_fct, \ - (step, step_data, *inptrp, &inptr, inend, \ - &outptr, irreversible)); \ - if (result != __GCONV_OK) \ - break; \ - } \ - else if (! ignore_errors_p ()) \ - { \ - result = __GCONV_ILLEGAL_INPUT; \ - break; \ - } \ - else \ - { \ - inptr += 4; \ - ++*irreversible; \ - } \ + STANDARD_ERR_HANDLER (4); \ } \ else \ *((uint16_t *) outptr)++ = *((uint32_t *) inptr)++; \ @@ -1253,25 +1218,7 @@ ucs4le_internal_loop_single (struct __gconv_step *step, uint32_t val = *((uint32_t *) inptr); \ if (__builtin_expect (val, 0) >= 0x10000) \ { \ - if (step_data->__trans.__trans_fct != NULL) \ - { \ - result = DL_CALL_FCT (step_data->__trans.__trans_fct, \ - (step, step_data, *inptrp, &inptr, inend, \ - &outptr, irreversible)); \ - if (result != __GCONV_OK) \ - break; \ - } \ - else if (! ignore_errors_p ()) \ - { \ - result = __GCONV_ILLEGAL_INPUT; \ - break; \ - } \ - else \ - { \ - inptr += 4; \ - ++*irreversible; \ - } \ - continue; \ + STANDARD_ERR_HANDLER (4); \ } \ *((uint16_t *) outptr)++ = bswap_16 (val); \ inptr += 4; \ diff --git a/iconv/gconv_trans.c b/iconv/gconv_trans.c index 269917b531..4d6e7766fd 100644 --- a/iconv/gconv_trans.c +++ b/iconv/gconv_trans.c @@ -18,9 +18,13 @@ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include <assert.h> #include <dlfcn.h> +#include <search.h> #include <stdint.h> +#include <string.h> +#include <bits/libc-lock.h> #include "gconv_int.h" #include "../locale/localeinfo.h" @@ -28,6 +32,7 @@ int __gconv_transliterate (struct __gconv_step *step, struct __gconv_step_data *step_data, + void *trans_data __attribute__ ((unused)), const unsigned char *inbufstart, const unsigned char **inbufp, const unsigned char *inbufend, @@ -218,3 +223,178 @@ __gconv_transliterate (struct __gconv_step *step, /* Haven't found a match. */ return __GCONV_ILLEGAL_INPUT; } + + +/* Structure to represent results of found (or not) transliteration + modules. */ +struct known_trans +{ + /* This structure must remain the first member. */ + struct trans_struct info; + + const char *fname; + void *handle; + int open_count; +}; + + +/* Tree with results of previous calls to __gconv_translit_find. */ +static void *search_tree; + +/* We modify global data. */ +__libc_lock_define_initialized (static, lock); + + +/* Compare two transliteration entries. */ +static int +trans_compare (const void *p1, const void *p2) +{ + struct known_trans *s1 = (struct known_trans *) p1; + struct known_trans *s2 = (struct known_trans *) p2; + + return strcmp (s1->info.name, s2->info.name); +} + + +/* Open (maybe reopen) the module named in the struct. Get the function + and data structure pointers we need. */ +static int +open_translit (struct known_trans *trans) +{ + __gconv_trans_query_fct queryfct; + + trans->handle = __libc_dlopen (trans->fname); + if (trans->handle == NULL) + /* Not available. */ + return 1; + + /* Find the required symbol. */ + queryfct = __libc_dlsym (trans->handle, "gconv_trans_context"); + if (queryfct == NULL) + { + /* We cannot live with that. */ + close_and_out: + __libc_dlclose (trans->handle); + trans->handle = NULL; + return 1; + } + + /* Get the context. */ + if (queryfct (trans->info.name, &trans->info.csnames, &trans->info.ncsnames) + != 0) + goto close_and_out; + + /* Of course we also have to have the actual function. */ + trans->info.trans_fct = __libc_dlsym (trans->handle, "gconv_trans"); + if (trans->info.trans_fct == NULL) + goto close_and_out; + + /* Now the optional functions. */ + trans->info.trans_init_fct = + __libc_dlsym (trans->handle, "gconv_trans_init"); + trans->info.trans_context_fct = + __libc_dlsym (trans->handle, "gconv_trans_context"); + trans->info.trans_end_fct = + __libc_dlsym (trans->handle, "gconv_trans_end"); + + trans->open_count = 1; + + return 0; +} + + +int +internal_function +__gconv_translit_find (struct trans_struct *trans) +{ + struct known_trans **found; + const struct path_elem *runp; + int res = 1; + + /* We have to have a name. */ + assert (trans->name != NULL); + + /* Acquire the lock. */ + __libc_lock_lock (lock); + + /* See whether we know this module already. */ + found = __tfind (trans, &search_tree, trans_compare); + if (found != NULL) + { + /* Is this module available? */ + if ((*found)->handle != NULL) + { + /* Maybe we have to reopen the file. */ + if ((*found)->handle != (void *) -1) + /* The object is not unloaded. */ + res = 0; + else if (open_translit (*found) == 0) + { + /* Copy the data. */ + *trans = (*found)->info; + res = 0; + } + } + } + else + { + size_t name_len = strlen (trans->name) + 1; + int need_so = 0; + struct known_trans *newp; + + /* We have to continue looking for the module. */ + if (__gconv_path_elem == NULL) + __gconv_get_path (); + + /* See whether we have to append .so. */ + if (name_len <= 3 || memcmp (&trans->name[name_len - 3], ".so", 3) != 0) + need_so = 1; + + /* Create a new entry. */ + newp = (struct known_trans *) malloc (sizeof (struct known_trans) + + (__gconv_max_path_elem_len + + name_len + 3) + + name_len); + if (newp != NULL) + { + char *cp; + + /* Clear the struct. */ + memset (newp, '\0', sizeof (struct known_trans)); + + /* Store a copy of the module name. */ + newp->info.name = (char *) (newp + 1); + cp = __mempcpy ((char *) newp->info.name, trans->name, name_len); + + newp->fname = cp; + + /* Seach in all the directories. */ + for (runp = __gconv_path_elem; runp->name != NULL; ++runp) + { + cp = __mempcpy (__stpcpy ((char *) newp->fname, runp->name), + trans->name, name_len); + if (need_so) + memcpy (cp, ".so", sizeof (".so")); + + if (open_translit (newp) == 0) + { + /* We found a module. */ + res = 0; + break; + } + } + + /* In any case we'll add the entry to our search tree. */ + if (__tsearch (newp, &search_tree, trans_compare) == NULL) + { + /* Yickes, this should not happen. Unload the object. */ + res = 1; + /* XXX unload here. */ + } + } + } + + __libc_lock_unlock (lock); + + return res; +} diff --git a/iconv/loop.c b/iconv/loop.c index ebbc1362b3..04ae50b974 100644 --- a/iconv/loop.c +++ b/iconv/loop.c @@ -173,6 +173,38 @@ #define ignore_errors_p() (flags & __GCONV_IGNORE_ERRORS) +/* Error handling with transliteration/transcription function use and + ignoring of errors. Note that we cannot use the do while (0) trick + since `break' and `continue' must reach certain points. */ +#define STANDARD_ERR_HANDLER(Incr) \ + { \ + struct __gconv_trans_data *trans; \ + \ + result = __GCONV_ILLEGAL_INPUT; \ + /* First try the transliteration methods. */ \ + for (trans = step_data->__trans; trans != NULL; trans = trans->__next) \ + { \ + result = DL_CALL_FCT (trans->__trans_fct, \ + (step, step_data, trans->__data, *inptrp, \ + &inptr, inend, &outptr, irreversible)); \ + if (result != __GCONV_ILLEGAL_INPUT) \ + break; \ + } \ + /* If any of them recognized the input stop. */ \ + if (result != __GCONV_ILLEGAL_INPUT) \ + break; \ + \ + /* Next see whether we have to ignore the error. If not, stop. */ \ + if (! ignore_errors_p ()) \ + break; \ + \ + /* When we come here it means we ignore the character. */ \ + ++*irreversible; \ + inptr += Incr; \ + continue; \ + } + + /* The function returns the status, as defined in gconv.h. */ static inline int FCTNAME (LOOPFCT) (struct __gconv_step *step, diff --git a/iconv/skeleton.c b/iconv/skeleton.c index 8dbebb81ac..854cc70bee 100644 --- a/iconv/skeleton.c +++ b/iconv/skeleton.c @@ -379,6 +379,8 @@ FUNCTION_NAME (struct __gconv_step *step, struct __gconv_step_data *data, do { + struct __gconv_trans_data *trans; + /* Remember the start value for this round. */ inptr = *inptrp; /* The outbuf buffer is empty. */ @@ -429,10 +431,10 @@ FUNCTION_NAME (struct __gconv_step *step, struct __gconv_step_data *data, /* Give the transliteration module the chance to store the original text and the result in case it needs a context. */ - if (data->__trans.__trans_context_fct != NULL) - DL_CALL_FCT (data->__trans.__trans_context_fct, - (data->__trans.__data, inptr, *inptrp, - outstart, outbuf)); + for (trans = data->__trans; trans != NULL; trans = trans->__next) + if (trans->__trans_context_fct != NULL) + DL_CALL_FCT (trans->__trans_context_fct, + (trans->__data, inptr, *inptrp, outstart, outbuf)); /* We finished one use of the loops. */ ++data->__invocation_counter; |