This is the mail archive of the newlib@sourceware.org mailing list for the newlib project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [patch] *scanf: Allow language-dependent radix character


On Dec 17 18:24, Jeff Johnston wrote:
> In addition to any else's comments, one issue I would note is that the value of
> BUF, which is used as the size of buf for floating point, assumes a single character decimal point.
> I believe that should be incremented by MB_LEN_MAX in the MB case to compensate for the decimal point.

Oh, hum.  The current definition for BUF in the FLOATING_POINT case is:

  #if ((MAXEXP+MAXFRACT+3) > MB_LEN_MAX)
  #  define BUF (MAXEXP+MAXFRACT+3)        /* 3 = sign + decimal point + NUL */
  #else
  #  define BUF MB_LEN_MAX
  #endif

Keeping everything else as is and just handling the decimal point with
MB_LEN_MAX, I'd get:

   #if ((MAXEXP+MAXFRACT+MB_LEN_MAX+2) > MB_LEN_MAX	/* Always true */
   #  define BUF (MAXEXP+MAXFRACT+MB_LEN_MAX+2)
   #else
   ...

So I guess I can reduce that to just 

  #define BUF (MAXEXP+MAXFRACT+MB_LEN_MAX+2) /* decimal point + sign + NUL */

In the non-MB case, MB_LEN_MAX is 1 anyway so it's equivalent to the old
definition.

> A minor issue is that _ungetc_r can possibly fail and there is no check.

None of the other ungetc calls check for errors.  The problem is, what
do you do *if* ungetc errors?  It's an undefined case, so you probably
can only hope for the best.

Revised patch attached.


Thanks,
Corinna


 	* vfscanf.c (BUF): Change definition to take multibyte decimal point
	into account.
	(__SVFSCANF_R): Handle radix char language-dependent
 	per POSIX.
 	(__SVFWSCANF_R): Ditto.


Index: libc/stdio/vfscanf.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio/vfscanf.c,v
retrieving revision 1.54
diff -u -p -r1.54 vfscanf.c
--- libc/stdio/vfscanf.c	29 Apr 2013 21:06:23 -0000	1.54
+++ libc/stdio/vfscanf.c	18 Dec 2013 09:43:17 -0000
@@ -162,6 +162,7 @@ Supporting OS subroutines required:
 #ifdef FLOATING_POINT
 #include <math.h>
 #include <float.h>
+#include <locale.h>
 
 /* Currently a test is made to see if long double processing is warranted.
    This could be changed in the future should the _ldtoa_r code be
@@ -174,11 +175,7 @@ extern _LONG_DOUBLE _strtold _PARAMS((ch
 
 #include "floatio.h"
 
-#if ((MAXEXP+MAXFRACT+3) > MB_LEN_MAX)
-#  define BUF (MAXEXP+MAXFRACT+3)        /* 3 = sign + decimal point + NUL */
-#else
-#  define BUF MB_LEN_MAX
-#endif
+#define BUF (MAXEXP+MAXFRACT+MB_LEN_MAX+2) /* decimal point + sign + NUL */
 
 /* An upper bound for how long a long prints in decimal.  4 / 13 approximates
    log (2).  Add one char for roundoff compensation and one for the sign.  */
@@ -1288,6 +1285,10 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap
 	  unsigned width_left = 0;
 	  char nancount = 0;
 	  char infcount = 0;
+	  const char *decpt = _localeconv_r (rptr)->decimal_point;
+#ifdef _MB_CAPABLE
+	  int decptpos = 0;
+#endif
 #ifdef hardway
 	  if (width == 0 || width > sizeof (buf) - 1)
 #else
@@ -1416,14 +1417,6 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap
 		      goto fok;
 		    }
 		  break;
-		case '.':
-		  if (flags & DPTOK)
-		    {
-		      flags &= ~(SIGNOK | DPTOK);
-		      leading_zeroes = zeroes;
-		      goto fok;
-		    }
-		  break;
 		case 'e':
 		case 'E':
 		  /* no exponent without some digits */
@@ -1442,6 +1435,53 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap
 		      goto fok;
 		    }
 		  break;
+		default:
+#ifndef _MB_CAPABLE
+		  if ((unsigned char) c == (unsigned char) decpt[0]
+		      && (flags & DPTOK))
+		    {
+		      flags &= ~(SIGNOK | DPTOK);
+		      leading_zeroes = zeroes;
+		      goto fok;
+		    }
+		  break;
+#else
+		  if (flags & DPTOK)
+		    {
+		      while ((unsigned char) c
+			     == (unsigned char) decpt[decptpos])
+			{
+			  if (decpt[++decptpos] == '\0')
+			    {
+			      /* We read the complete decpt seq. */
+			      flags &= ~(SIGNOK | DPTOK);
+			      leading_zeroes = zeroes;
+			      p = stpncpy (p, decpt, decptpos);
+			      decptpos = 0;
+			      goto fskip;
+			    }
+			  ++nread;
+			  if (--fp->_r > 0)
+			    fp->_p++;
+			  else if (__srefill_r (rptr, fp))
+			    break;		/* EOF */
+			  c = *fp->_p;
+			}
+		      if (decptpos > 0)
+			{
+			  /* We read part of a multibyte decimal point,
+			     but the rest is invalid or we're at EOF,
+			     so back off. */
+			  while (decptpos-- > 0)
+			    {
+			      _ungetc_r (rptr, (unsigned char) decpt[decptpos],
+					 fp);
+			      --nread;
+			    }
+			}
+		    }
+		  break;
+#endif
 		}
 	      break;
 	    fok:
Index: libc/stdio/vfwscanf.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio/vfwscanf.c,v
retrieving revision 1.5
diff -u -p -r1.5 vfwscanf.c
--- libc/stdio/vfwscanf.c	26 Nov 2013 17:21:00 -0000	1.5
+++ libc/stdio/vfwscanf.c	18 Dec 2013 09:43:17 -0000
@@ -161,6 +161,9 @@ C99, POSIX-1.2008
 #ifdef FLOATING_POINT
 #include <math.h>
 #include <float.h>
+#ifdef __HAVE_LOCALE_INFO_EXTENDED__
+#include "../locale/lnumeric.h"
+#endif
 
 /* Currently a test is made to see if long double processing is warranted.
    This could be changed in the future should the _ldtoa_r code be
@@ -414,6 +417,7 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, a
   float *flp;
   _LONG_DOUBLE *ldp;
   double *dp;
+  wchar_t decpt;
 #endif
   long *lp;
 #ifndef _NO_LONGLONG
@@ -440,6 +444,27 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, a
 # define GET_ARG(n, ap, type) (va_arg (ap, type))
 #endif
 
+#ifdef FLOATING_POINT
+#ifdef _MB_CAPABLE
+#ifdef __HAVE_LOCALE_INFO_EXTENDED__
+	  decpt = *__get_current_numeric_locale ()->wdecimal_point;
+#else
+	  {
+	    size_t nconv;
+
+	    memset (&state, '\0', sizeof (state));
+	    nconv = _mbrtowc_r (data, &decpt,
+				_localeconv_r (data)->decimal_point,
+				MB_CUR_MAX, &state);
+	    if (nconv == (size_t) -1 || nconv == (size_t) -2)
+	      decpt = L'.';
+	  }
+#endif /* !__HAVE_LOCALE_INFO_EXTENDED__ */
+#else
+	  decpt = (wchar_t) *_localeconv_r (data)->decimal_point;
+#endif /* !_MB_CAPABLE */
+#endif /* FLOATING_POINT */
+
   _newlib_flockfile_start (fp);
 
   ORIENT (fp, 1);
@@ -1271,14 +1296,6 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, a
 		      goto fok;
 		    }
 		  break;
-		case L'.':
-		  if (flags & DPTOK)
-		    {
-		      flags &= ~(SIGNOK | DPTOK);
-		      leading_zeroes = zeroes;
-		      goto fok;
-		    }
-		  break;
 		case L'e':
 		case L'E':
 		  /* no exponent without some digits */
@@ -1297,6 +1314,14 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, a
 		      goto fok;
 		    }
 		  break;
+		default:
+		  if ((wchar_t) c == decpt && (flags & DPTOK))
+		    {
+		      flags &= ~(SIGNOK | DPTOK);
+		      leading_zeroes = zeroes;
+		      goto fok;
+		    }
+		  break;
 		}
 	      if (c != WEOF)
 		_ungetwc_r (rptr, c, fp);


-- 
Corinna Vinschen
Cygwin Maintainer
Red Hat

Attachment: pgp8R4PluqQVx.pgp
Description: PGP signature


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]