NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

bin/44013: awk fails to parse numeric constants when LC_NUMERIC is set



>Number:         44013
>Category:       bin
>Synopsis:       awk fails to parse numeric constants when LC_NUMERIC is set
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    bin-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Oct 30 08:30:00 +0000 2010
>Originator:     Dominik Zaczkowski
>Release:        5.1_RC4
>Organization:
>Environment:
NetBSD kraina-oz.ath.cx 5.1_RC4 NetBSD 5.1_RC4 (GENERIC) #0: Thu Oct 28 
23:40:02 CEST 2010  
root%kraina-oz.ath.cx@localhost:/usr/obj/usr/obj/netbsd-5/src/sys/arch/i386/compile/GENERIC
 i386
>Description:
AWK standard(?) 
http://www.opengroup.org/onlinepubs/009695399/utilities/awk.html says that 
LC_NUMERIC should affect only input and constants in program should always use 
'.' for decimal separator. AWK however tries to respect LC_NUMERIC for fp 
constants, in result its impossible to put fp constant in program when 
LC_NUMERIC is set to locale in which decimal separator is something different 
than '.'
>How-To-Repeat:
dominik@kraina-oz$ awk 'BEGIN {print 5 * 0.5}'
awk: syntax error at source line 1
 context is
        BEGIN {print 5 * >>>  0.5 <<< 
awk: illegal statement at source line 1

in pl locale ',' is decimal separator...
dominik@kraina-oz$ locale|grep LC_NUMERIC
LC_NUMERIC="pl_PL.ISO8859-2"
dominik@kraina-oz$ awk 'BEGIN {print 5 * 0,5}' 
0 5


dominik@kraina-oz$ LC_NUMERIC=C awk 'BEGIN {print 5 * 0.5}'
2.5

>Fix:
My fix is to provide locale independent version of strtod.
cd /usr/src && patch < this_patch_below


--- dist/nawk/lex.c     2010-10-29 15:54:06.000000000 +0200
+++ /root/lex.c 2010-10-29 15:53:03.000000000 +0200
@@ -26,10 +26,13 @@
 #include "nbtool_config.h"
 #endif
 
+#include <sys/cdefs.h>                 /* for __restrict */
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
+#include <locale.h>
 #include "awk.h"
 #include "awkgram.h"
 
@@ -50,6 +53,7 @@
 int peek(void);
 int gettok(char **, int *);
 int binsearch(const char *, const Keyword *, int);
+static double c_locale_strtod(const char * __restrict nptr, char ** __restrict 
endptr);
 
 const Keyword keywords[] ={    /* keep sorted: binary searched */
        { "BEGIN",      XBEGIN,         XBEGIN },
@@ -156,7 +160,7 @@
                        }
                }
                *bp = 0;
-               strtod(buf, &rem);      /* parse the number */
+               c_locale_strtod(buf, &rem);     /* parse the number */
                if (rem == (char *)buf) {       /* it wasn't a valid number at 
all */
                        buf[1] = 0;     /* return one character as token */
                        retc = buf[0];  /* character is its own type */
@@ -201,7 +205,8 @@
                if (isalpha(c) || c == '_')
                        return word(buf);
                if (isdigit(c)) {
-                       yylval.cp = setsymtab(buf, tostring(buf), atof(buf), 
CON|NUM, symtab);
+                       yylval.cp = setsymtab(buf, tostring(buf),
+                           c_locale_strtod(buf, NULL), CON|NUM, symtab);
                        /* should this also have STR set? */
                        RET(NUMBER);
                }
@@ -594,3 +599,14 @@
        for (i = strlen(s)-1; i >= 0; i--)
                unput(s[i]);
 }
+
+static double
+c_locale_strtod(const char * __restrict nptr, char ** __restrict endptr)
+{
+       double ret;
+
+       setlocale(LC_NUMERIC, "C");
+       ret = strtod(nptr, endptr);
+       setlocale(LC_NUMERIC, "");
+       return ret;
+}



Home | Main Index | Thread Index | Old Index