From f1d5c60ddef851078544e6b8456b18534b9a2a95 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Fri, 16 Jun 2000 00:39:38 +0000 Subject: Update. 2000-06-15 Ulrich Drepper * iconv/gconv.h (__gconv_fct): Change type of fifth parameter to unsigned char **. (__gconv_init_fct): Remove two parameters. * iconv/gconv_int.h (__gconv_transliterate): Renamed from gconv_transliterate. Remove two parameters. Change prototypes of builtin functions according to __gconv_fct change. * iconv/skeleton.c: Change type of fifth parameter. make sure it is != NULL only during error handling. Stop in this case after the conversion. * iconv/gconv_trans.c: Replace with real implementation for __gconv_transliterate. * iconv/gconv_open.c: Adjust for renaming of __gconv_transliterate. * iconv/gconv.c: Change calls to downstream functions once again. Use NULL for the fifth parameter instead of pointer to output buffer. * libio/iofwide.c: Likewise. * 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. * iconv/gconv_simple.c: Remove two parameters from error handling function call. * 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. --- iconv/gconv.c | 6 +-- iconv/gconv.h | 6 +-- iconv/gconv_int.h | 21 +++++---- iconv/gconv_open.c | 2 +- iconv/gconv_simple.c | 6 +-- iconv/gconv_trans.c | 122 +++++++++++++++++++++++++++++++++++++++++++++------ iconv/skeleton.c | 26 ++++++++--- 7 files changed, 149 insertions(+), 40 deletions(-) (limited to 'iconv') diff --git a/iconv/gconv.c b/iconv/gconv.c index 19f95622a2..0b7b917b6a 100644 --- a/iconv/gconv.c +++ b/iconv/gconv.c @@ -46,8 +46,8 @@ __gconv (__gconv_t cd, const unsigned char **inbuf, if (inbuf == NULL || *inbuf == NULL) /* We just flush. */ result = DL_CALL_FCT (cd->__steps->__fct, - (cd->__steps, cd->__data, NULL, NULL, - cd->__data[0].__outbuf, irreversible, 1, 0)); + (cd->__steps, cd->__data, NULL, NULL, NULL, + irreversible, 1, 0)); else { const unsigned char *last_start; @@ -59,7 +59,7 @@ __gconv (__gconv_t cd, const unsigned char **inbuf, last_start = *inbuf; result = DL_CALL_FCT (cd->__steps->__fct, (cd->__steps, cd->__data, inbuf, inbufend, - cd->__data[0].__outbuf, irreversible, 0, 0)); + NULL, irreversible, 0, 0)); } while (result == __GCONV_EMPTY_INPUT && last_start != *inbuf && *inbuf + cd->__steps->__min_needed_from <= inbufend); diff --git a/iconv/gconv.h b/iconv/gconv.h index 2bba133d0c..0164b62c8b 100644 --- a/iconv/gconv.h +++ b/iconv/gconv.h @@ -68,7 +68,7 @@ struct __gconv_trans_data; /* Type of a conversion function. */ typedef int (*__gconv_fct) (struct __gconv_step *, struct __gconv_step_data *, __const unsigned char **, __const unsigned char *, - unsigned char *, size_t *, int, int); + unsigned char **, size_t *, int, int); /* Constructor and destructor for local data for conversion step. */ typedef int (*__gconv_init_fct) (struct __gconv_step *); @@ -80,8 +80,8 @@ typedef int (*__gconv_trans_fct) (struct __gconv_step *step, struct __gconv_step_data *step_data, __const unsigned char *, __const unsigned char **, - __const unsigned char *, unsigned char *, - unsigned char **, unsigned char *, size_t *); + __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, diff --git a/iconv/gconv_int.h b/iconv/gconv_int.h index 87287d7b26..34dff7d522 100644 --- a/iconv/gconv_int.h +++ b/iconv/gconv_int.h @@ -181,15 +181,13 @@ extern void __gconv_get_builtin_trans (const char *name, internal_function; /* Transliteration using the locale's data. */ -extern int gconv_transliterate (struct __gconv_step *step, - struct __gconv_step_data *step_data, - __const unsigned char *inbufstart, - __const unsigned char **inbufp, - __const unsigned char *inbufend, - unsigned char *outbufstart, - unsigned char **outbufp, - unsigned char *outbufend, - size_t *irreversible); +extern int __gconv_transliterate (struct __gconv_step *step, + struct __gconv_step_data *step_data, + __const unsigned char *inbufstart, + __const unsigned char **inbufp, + __const unsigned char *inbufend, + unsigned char **outbufstart, + size_t *irreversible); /* Builtin transformations. */ @@ -198,8 +196,9 @@ extern int gconv_transliterate (struct __gconv_step *step, extern int Name (struct __gconv_step *step, \ struct __gconv_step_data *data, \ const unsigned char **inbuf, \ - const unsigned char *inbufend, unsigned char *outbufstart, \ - size_t *irreversible, int do_flush, int consume_incomplete) + const unsigned char *inbufend, \ + unsigned char **outbufstart, size_t *irreversible, \ + int do_flush, int consume_incomplete) __BUILTIN_TRANS (__gconv_transform_ascii_internal); __BUILTIN_TRANS (__gconv_transform_internal_ascii); diff --git a/iconv/gconv_open.c b/iconv/gconv_open.c index 984ca9dc5d..14f1d5e0f9 100644 --- a/iconv/gconv_open.c +++ b/iconv/gconv_open.c @@ -86,7 +86,7 @@ __gconv_open (const char *toset, const char *fromset, __gconv_t *handle, csnames = internal_trans_names; ncsnames = 1; - trans_fct = gconv_transliterate; + trans_fct = __gconv_transliterate; /* No context, init, or end function. */ } else if (strcasecmp (errhand, "WORK AROUND A GCC BUG") == 0) diff --git a/iconv/gconv_simple.c b/iconv/gconv_simple.c index 5033f3ef83..390574582f 100644 --- a/iconv/gconv_simple.c +++ b/iconv/gconv_simple.c @@ -801,7 +801,7 @@ ucs4le_internal_loop_single (struct __gconv_step *step, { \ result = DL_CALL_FCT (step_data->__trans.__trans_fct, \ (step, step_data, *inptrp, &inptr, inend, \ - *outptrp, &outptr, outend, irreversible)); \ + &outptr, irreversible)); \ if (result != __GCONV_OK) \ break; \ } \ @@ -1190,7 +1190,7 @@ ucs4le_internal_loop_single (struct __gconv_step *step, { \ result = DL_CALL_FCT (step_data->__trans.__trans_fct, \ (step, step_data, *inptrp, &inptr, inend, \ - *outptrp, &outptr, outend, irreversible)); \ + &outptr, irreversible)); \ if (result != __GCONV_OK) \ break; \ } \ @@ -1257,7 +1257,7 @@ ucs4le_internal_loop_single (struct __gconv_step *step, { \ result = DL_CALL_FCT (step_data->__trans.__trans_fct, \ (step, step_data, *inptrp, &inptr, inend, \ - *outptrp, &outptr, outend, irreversible)); \ + &outptr, irreversible)); \ if (result != __GCONV_OK) \ break; \ } \ diff --git a/iconv/gconv_trans.c b/iconv/gconv_trans.c index 56c3ff6be6..829ff5f981 100644 --- a/iconv/gconv_trans.c +++ b/iconv/gconv_trans.c @@ -18,6 +18,7 @@ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include #include #include "gconv_int.h" @@ -25,26 +26,121 @@ int -gconv_transliterate (struct __gconv_step *step, - struct __gconv_step_data *step_data, - const unsigned char *inbufstart, - const unsigned char **inbufp, - const unsigned char *inbufend, - unsigned char *outbufstart, - unsigned char **outbufp, unsigned char *outbufend, - size_t *irreversible) +__gconv_transliterate (struct __gconv_step *step, + struct __gconv_step_data *step_data, + const unsigned char *inbufstart, + const unsigned char **inbufp, + const unsigned char *inbufend, + unsigned char **outbufstart, size_t *irreversible) { /* Find out about the locale's transliteration. */ - uint_fast32_t size = _NL_CURRENT_WORD (LC_CTYPE, - _NL_CTYPE_TRANSLIT_HASH_SIZE); - uint_fast32_t layers = _NL_CURRENT_WORD (LC_CTYPE, - _NL_CTYPE_TRANSLIT_HASH_LAYERS); + uint_fast32_t size; + uint_fast32_t layers; + uint32_t *from_idx; + uint32_t *from_tbl; + uint32_t *to_idx; + uint32_t *to_tbl; + uint32_t *winbuf; + uint32_t *winbufend; + uint_fast32_t low; + uint_fast32_t high; /* If there is no transliteration information in the locale don't do anything and return the error. */ + size = _NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_TRANSLIT_HASH_SIZE); if (size == 0) return __GCONV_ILLEGAL_INPUT; - /* XXX For now we don't do anything. */ + /* Get the rest of the values. */ + layers = _NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_TRANSLIT_HASH_LAYERS); + from_idx = (uint32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TRANSLIT_FROM_IDX); + from_tbl = (uint32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TRANSLIT_FROM_TBL); + to_idx = (uint32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TRANSLIT_TO_IDX); + to_tbl = (uint32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TRANSLIT_TO_TBL); + + /* The input buffer. There are actually 4-byte values. */ + winbuf = (uint32_t *) *inbufp; + winbufend = (uint32_t *) inbufend; + + /* Test whether there is enough input. */ + if (winbuf + 1 > winbufend) + return (winbuf == winbufend + ? __GCONV_EMPTY_INPUT : __GCONV_INCOMPLETE_INPUT); + + /* The array starting at FROM_IDX contains indeces to the string table + in FROM_TBL. The indeces are sorted wrt to the strings. I.e., we + are doing binary search. */ + low = 0; + high = size; + while (low < high) + { + uint_fast32_t med = (low + high) / 2; + uint32_t idx; + int cnt; + + /* Compare the string at this index with the string at the current + position in the input buffer. */ + idx = from_idx[med]; + cnt = 0; + do + { + if (from_tbl[idx + cnt] != winbuf[cnt]) + /* Does not match. */ + break; + ++cnt; + } + while (from_tbl[idx + cnt] != L'\0' && winbuf + cnt < winbufend); + + if (cnt > 0 && from_tbl[idx + cnt] == L'\0') + { + /* Found a matching input sequence. Now try to convert the + possible replacements. */ + uint32_t idx2 = to_idx[med]; + + do + { + /* Determine length of replacement. */ + uint_fast32_t len = 0; + int res; + const unsigned char *toinptr; + + while (to_tbl[idx2 + len] != L'\0') + ++len; + + /* Try this input text. */ + toinptr = (const unsigned char *) &to_tbl[idx2]; + res = DL_CALL_FCT (step->__fct, + (step, step_data, &toinptr, + (const unsigned char *) &to_tbl[idx2 + len], + (unsigned char **) outbufstart, + irreversible, 0, 0)); + if (res != __GCONV_ILLEGAL_INPUT) + { + /* If the conversion succeeds we have to increment the + input buffer. */ + if (res == __GCONV_EMPTY_INPUT) + { + *inbufp += cnt * sizeof (uint32_t); + ++*irreversible; + } + + return res; + } + + /* Next replacement. */ + idx2 += len + 1; + } + while (to_tbl[idx2] != L'\0'); + + /* Nothing found, continue searching. */ + } + + if (winbuf + cnt >= winbufend || from_tbl[idx + cnt] < winbuf[cnt]) + low = idx; + else + high = idx; + } + + /* Haven't found a match. */ return __GCONV_ILLEGAL_INPUT; } diff --git a/iconv/skeleton.c b/iconv/skeleton.c index d64d7599b4..8dbebb81ac 100644 --- a/iconv/skeleton.c +++ b/iconv/skeleton.c @@ -271,7 +271,7 @@ gconv_init (struct __gconv_step *step) int FUNCTION_NAME (struct __gconv_step *step, struct __gconv_step_data *data, const unsigned char **inptrp, const unsigned char *inend, - unsigned char *outbufstart, size_t *irreversible, int do_flush, + unsigned char **outbufstart, size_t *irreversible, int do_flush, int consume_incomplete) { struct __gconv_step *next_step = step + 1; @@ -288,6 +288,9 @@ FUNCTION_NAME (struct __gconv_step *step, struct __gconv_step_data *data, { status = __GCONV_OK; + /* This should never happen during error handling. */ + assert (outbufstart == NULL); + #ifdef EMIT_SHIFT_TO_INIT /* Emit the escape sequence to reset the state. */ EMIT_SHIFT_TO_INIT; @@ -296,14 +299,15 @@ FUNCTION_NAME (struct __gconv_step *step, struct __gconv_step_data *data, successfully emitted the escape sequence. */ if (status == __GCONV_OK && ! (data->__flags & __GCONV_IS_LAST)) status = DL_CALL_FCT (fct, (next_step, next_data, NULL, NULL, - next_data->__outbuf, irreversible, 1, + NULL, irreversible, 1, consume_incomplete)); } else { /* We preserve the initial values of the pointer variables. */ const unsigned char *inptr = *inptrp; - unsigned char *outbuf = outbufstart; + unsigned char *outbuf = (__builtin_expect (outbufstart == NULL, 1) + ? data->__outbuf : *outbufstart); unsigned char *outend = data->__outbufend; unsigned char *outstart; /* This variable is used to count the number of characters we @@ -331,7 +335,10 @@ FUNCTION_NAME (struct __gconv_step *step, struct __gconv_step_data *data, || (MAX_NEEDED_TO > 1 && !FROM_DIRECTION)) && consume_incomplete && (data->__statep->__count & 7) != 0) { - /* Yep, we have some bytes left over. Process them now. */ + /* Yep, we have some bytes left over. Process them now. + But this must not happen while we are called from an + error handler. */ + assert (outbufstart == NULL); # if MAX_NEEDED_FROM > 1 if (MAX_NEEDED_TO == 1 || FROM_DIRECTION) @@ -412,6 +419,14 @@ FUNCTION_NAME (struct __gconv_step *step, struct __gconv_step_data *data, } #endif + /* If we were called as part of an error handling module we + don't do anything else here. */ + if (__builtin_expect (outbufstart != NULL, 0)) + { + *outbufstart = outbuf; + return status; + } + /* 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) @@ -443,8 +458,7 @@ FUNCTION_NAME (struct __gconv_step *step, struct __gconv_step_data *data, int result; result = DL_CALL_FCT (fct, (next_step, next_data, &outerr, - outbuf, next_data->__outbuf, - irreversible, 0, + outbuf, NULL, irreversible, 0, consume_incomplete)); if (result != __GCONV_EMPTY_INPUT) -- cgit v1.2.3