[PATCH] gethex doesn't cope with multibyte decimalpoints
Jeff Johnston
jjohnstn@redhat.com
Sun Feb 8 06:58:00 GMT 2009
Corinna Vinschen wrote:
> Hi,
>
> AFAICS, there's a bug in gethex(). The function assumes that the
> decimalpoint is a single char. This is incorrect for multibyte
> charsets. Actually the decimalpoint var should be a multibyte char and
> comparisons in the code should always compare the entire string, isn't
> it? I attached a patch. Note especially the change of the while loop
> which now has to step forward instead of backward since backward
> stepping screws up multibyte comparisons.
>
>
>
This isn't going to work unfortunately. The decimal point location
(decpt) is calculated by adding 1 to the string pointer s which in the
multibyte case is wrong. This value is used to figure out the exponent
to adjust the result by (see the calculation of e). Changing to reading
left to right makes the calculation of the result wrong if the number of
hex digits is larger than 8. For example, if you have 10 hex digits,
you want the bottom 8 to form one long integer and the top 2 digits by
themselves not the other way around.
I believe the right answer is to assume that the decimal point is a
single multibyte character. With that, convert the string to wchar
first and the decimal point to a wchar, then do all the processing the
same after that (looking for the wchar decimal point). A check may be
necessary to ensure that no wchar is > 256 before checking in the hexdig
table. I believe this would make the algorithm work for either case.
> Corinna
>
>
> * libc/stdlib/gdtoa-gethex.c (gethex): Allow multibyte decimal point.
> Fix compiler warnings due to different signedness of pointer types.
>
>
> Index: libc/stdlib/gdtoa-gethex.c
> ===================================================================
> RCS file: /cvs/src/src/newlib/libc/stdlib/gdtoa-gethex.c,v
> retrieving revision 1.1
> diff -u -p -r1.1 gdtoa-gethex.c
> --- libc/stdlib/gdtoa-gethex.c 22 Jun 2006 17:59:52 -0000 1.1
> +++ libc/stdlib/gdtoa-gethex.c 6 Feb 2009 13:53:12 -0000
> @@ -152,10 +152,12 @@ _DEFUN(gethex, (ptr, sp, fpi, exp, bp, s
> __ULong L, lostbits, *x;
> Long e, e1;
> #ifdef USE_LOCALE
> - unsigned char decimalpoint = *localeconv()->decimal_point;
> + unsigned char *decimalpoint = (unsigned char *)
> + localeconv()->decimal_point;
> #else
> -#define decimalpoint '.'
> +#define decimalpoint "."
> #endif
> + size_t dplen = strlen ((char *) decimalpoint);
>
> if (!hexdig['0'])
> hexdig_init();
> @@ -170,7 +172,7 @@ _DEFUN(gethex, (ptr, sp, fpi, exp, bp, s
> e = 0;
> if (!hexdig[*s]) {
> zret = 1;
> - if (*s != decimalpoint)
> + if (!strncmp ((char *) s, (char *) decimalpoint, dplen))
> goto pcheck;
> decpt = ++s;
> if (!hexdig[*s])
> @@ -184,7 +186,7 @@ _DEFUN(gethex, (ptr, sp, fpi, exp, bp, s
> }
> while(hexdig[*s])
> s++;
> - if (*s == decimalpoint && !decpt) {
> + if (!strncmp ((char *) s, (char *) decimalpoint, dplen) && !decpt) {
> decpt = ++s;
> while(hexdig[*s])
> s++;
> @@ -225,15 +227,17 @@ _DEFUN(gethex, (ptr, sp, fpi, exp, bp, s
> x = b->_x;
> n = 0;
> L = 0;
> - while(s1 > s0) {
> - if (*--s1 == decimalpoint)
> + while (s0 < s1) {
> + if (!strncmp ((char *) s0, (char *) decimalpoint, dplen)) {
> + s0 += dplen;
> continue;
> + }
> if (n == 32) {
> *x++ = L;
> L = 0;
> n = 0;
> }
> - L |= (hexdig[*s1] & 0x0f) << n;
> + L = (L << 4) | (hexdig[*s0++] & 0x0f);
> n += 4;
> }
> *x++ = L;
>
>
More information about the Newlib
mailing list