bug-gnu-utils
[Top][All Lists]
Advanced

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

Re: Possible bug in gawk: local FS not used


From: Aharon Robbins
Subject: Re: Possible bug in gawk: local FS not used
Date: Fri, 15 May 2009 14:35:54 +0300

Greetings. Re this:

> Date: Mon, 11 May 2009 20:22:35 +0200
> From: Jean-Philippe =?utf-8?Q?Gu=C3=A9rard?= <address@hidden>
> To: address@hidden
> Subject: Possible bug in gawk: local FS not used
>
> Hello,
>
> I might have stumbled upon a gawk bug. Its seems that a local FS 
> variable is not taken into account. The following script demonstrates 
> this behaviour:
>
> ----------------------------------------------------------------------
> #!/usr/bin/gawk -f
>
> function test_global(){
>
>  # FS is a global variable
>
>  FS="1"
>  getline < FILE
>  print $2
>  close( FILE )
>
> }
>
> function test_local( FS ){
>
>  # FS is a local variable
>
>  FS="1"
>  getline < FILE
>  print $2
>  close( FILE )
>
> }
>
> BEGIN {
>
>  FILE="/tmp/test.txt"
>  system( "echo 121212 > " FILE )
>
>  FS="2"
>  print "global FS"
>  test_global()
>
>  FS="2"
>  print "local FS"
>  test_local()
>
> }
> ----------------------------------------------------------------------
>
> With GNU Awk 3.1.6, I get the following result:
> ----------------------------------------------------------------------
> $ ./test.awk 
> global FS
> 2
> local FS
> 1
> ----------------------------------------------------------------------
>
> If I understand well, when parsing the input line, the global FS 
> variable is always used, even if a local FS exists.
>
> Could you confirm if this is a bug or intended?
>
> Thanks in advance,
>
> Regards,
> -- 
> Jean-Philippe Guérard
> http://tigreraye.org

This is regular old-fashioned shadowning of a global variable by a local one.
So, the behavior as such is "intended".  However, given this:

> Date: Mon, 11 May 2009 23:31:56 +0200
> From: Dave B <address@hidden>
> To: address@hidden
> Subject: Re: Possible bug in gawk: local FS not used
>
> [...]
>
> To the point, the POSIX standard says this:
>
> "The same name shall not be used as both a function parameter name and as
> the name of a function or a special awk variable"
>
> which probably makes mawk the more correct implementations in this regard.

Indeed, the POSIX standard does say this, and apparently has for a while. It's
something that I missed. I also note that Unix nawk does not behave this way.

So, since this is a conflict with POSIX, the behavior you found should be
classified as a bug.

Here is a patch.  This will be making its way to CVS, along with test suite
and documentation patches, shortly.

Thanks,

Arnold
-----------------------------------------------------------------------
Fri May 15 14:10:44 2009  Arnold D. Robbins  <address@hidden>

        Function arguments cannot be reserved variable names, per POSIX.

        * main.c (struct varinit): Add flags member.
        (varinit): Add values for flags member (one or both of NON_STANDARD
        or NO_INSTALL). Add entries for the rest of the gawk variables and
        sort them, so that the table can be searched by ...
        (is_std_var): New routine to see if a name is a standard variable.
        * awk.h (is_std_var): Add declaration.
        * awkgram.y (func_install): Use new routine and issue error.

Index: awk.h
===================================================================
RCS file: /d/mongo/cvsrep/gawk-stable/awk.h,v
retrieving revision 1.24
diff -u -r1.24 awk.h
--- awk.h       21 Mar 2009 20:31:03 -0000      1.24
+++ awk.h       15 May 2009 11:07:35 -0000
@@ -1141,6 +1141,7 @@
 /* main.c */
 extern int main P((int argc, char **argv));
 extern int arg_assign P((char *arg, int initing));
+extern int is_std_var P((const char *var));
 /* msg.c */
 extern void err P((const char *s, const char *emsg, va_list argp)) 
ATTRIBUTE_PRINTF(2, 0);
 #if _MSC_VER == 510
Index: awkgram.y
===================================================================
RCS file: /d/mongo/cvsrep/gawk-stable/awkgram.y,v
retrieving revision 1.22
diff -u -r1.22 awkgram.y
--- awkgram.y   1 May 2009 11:38:45 -0000       1.22
+++ awkgram.y   15 May 2009 11:16:40 -0000
@@ -3010,6 +3010,9 @@
                if (strcmp(n->param, params->param) == 0)
                        fatal(_("function `%s': can't use function name as 
parameter name"),
                                        params->param); 
+               else if (/* ! do_traditional && */ is_std_var(n->param))
+                       yyerror(_("function `%s': can't use special variable 
`%s' as a function parameter"),
+                               params->param, n->param);
        }
 
        thisfunc = NULL;        /* turn off warnings */
Index: main.c
===================================================================
RCS file: /d/mongo/cvsrep/gawk-stable/main.c,v
retrieving revision 1.19
diff -u -r1.19 main.c
--- main.c      17 Mar 2009 19:29:15 -0000      1.19
+++ main.c      15 May 2009 11:10:49 -0000
@@ -874,30 +874,38 @@
        const char *strval;
        AWKNUM numval;
        Func_ptr assign;
+       int flags;
+#define NO_INSTALL     0x01
+#define NON_STANDARD   0x02
 };
+
 static const struct varinit varinit[] = {
-{&CONVFMT_node,        "CONVFMT",      Node_CONVFMT,           "%.6g", 0,  
set_CONVFMT },
-{&NF_node,     "NF",           Node_NF,                NULL,   -1, NULL },
-{&FIELDWIDTHS_node, "FIELDWIDTHS", Node_FIELDWIDTHS,   "",     0,  NULL },
-{&NR_node,     "NR",           Node_NR,                NULL,   0,  set_NR },
-{&FNR_node,    "FNR",          Node_FNR,               NULL,   0,  set_FNR },
-{&FS_node,     "FS",           Node_FS,                " ",    0,  NULL },
-{&RS_node,     "RS",           Node_RS,                "\n",   0,  set_RS },
-{&IGNORECASE_node, "IGNORECASE", Node_IGNORECASE,      NULL,   0,  NULL },
-{&FILENAME_node, "FILENAME",   Node_var,               "",     0,  NULL },
-{&OFS_node,    "OFS",          Node_OFS,               " ",    0,  set_OFS },
-{&ORS_node,    "ORS",          Node_ORS,               "\n",   0,  set_ORS },
-{&OFMT_node,   "OFMT",         Node_OFMT,              "%.6g", 0,  set_OFMT },
-{&RLENGTH_node, "RLENGTH",     Node_var,               NULL,   0,  NULL },
-{&RSTART_node, "RSTART",       Node_var,               NULL,   0,  NULL },
-{&SUBSEP_node, "SUBSEP",       Node_SUBSEP,            "\034", 0,  NULL },
-{&ARGIND_node, "ARGIND",       Node_var,               NULL,   0,  NULL },
-{&ERRNO_node,  "ERRNO",        Node_var,               NULL,   0,  NULL },
-{&RT_node,     "RT",           Node_var,               "",     0,  NULL },
-{&BINMODE_node,        "BINMODE",      Node_BINMODE,           NULL,   0,  
NULL },
-{&LINT_node,   "LINT",         Node_LINT,              NULL,   0,  NULL },
-{&TEXTDOMAIN_node,     "TEXTDOMAIN",           Node_TEXTDOMAIN,        
"messages",     0,  set_TEXTDOMAIN },
-{0,            NULL,           Node_illegal,           NULL,   0,  NULL },
+{NULL,         "ARGC",         Node_illegal,           NULL,   0,  NULL,       
NO_INSTALL },
+{&ARGIND_node, "ARGIND",       Node_var,               NULL,   0,  NULL,       
NON_STANDARD },
+{NULL,         "ARGV",         Node_illegal,           NULL,   0,  NULL,       
NO_INSTALL },
+{&BINMODE_node,        "BINMODE",      Node_BINMODE,           NULL,   0,  
NULL,       NON_STANDARD },
+{&CONVFMT_node,        "CONVFMT",      Node_CONVFMT,           "%.6g", 0,  
set_CONVFMT,        0 },
+{NULL,         "ENVIRON",      Node_illegal,           NULL,   0,  NULL,       
NO_INSTALL },
+{&ERRNO_node,  "ERRNO",        Node_var,               NULL,   0,  NULL,       
NON_STANDARD },
+{&FIELDWIDTHS_node, "FIELDWIDTHS", Node_FIELDWIDTHS,   "",     0,  NULL,       
NON_STANDARD },
+{&FILENAME_node, "FILENAME",   Node_var,               "",     0,  NULL,       
0 },
+{&FNR_node,    "FNR",          Node_FNR,               NULL,   0,  set_FNR,    
0 },
+{&FS_node,     "FS",           Node_FS,                " ",    0,  NULL,       
0 },
+{&IGNORECASE_node, "IGNORECASE", Node_IGNORECASE,      NULL,   0,  NULL,       
NON_STANDARD },
+{&LINT_node,   "LINT",         Node_LINT,              NULL,   0,  NULL,       
NON_STANDARD },
+{&NF_node,     "NF",           Node_NF,                NULL,   -1, NULL,       
0 },
+{&NR_node,     "NR",           Node_NR,                NULL,   0,  set_NR,     
0 },
+{&OFMT_node,   "OFMT",         Node_OFMT,              "%.6g", 0,  set_OFMT,   
0 },
+{&OFS_node,    "OFS",          Node_OFS,               " ",    0,  set_OFS,    
0 },
+{&ORS_node,    "ORS",          Node_ORS,               "\n",   0,  set_ORS,    
0 },
+{NULL,         "PROCINFO",     Node_illegal,           NULL,   0,  NULL,       
NO_INSTALL | NON_STANDARD },
+{&RLENGTH_node, "RLENGTH",     Node_var,               NULL,   0,  NULL,       
0 },
+{&RS_node,     "RS",           Node_RS,                "\n",   0,  set_RS,     
0 },
+{&RSTART_node, "RSTART",       Node_var,               NULL,   0,  NULL,       
0 },
+{&RT_node,     "RT",           Node_var,               "",     0,  NULL,       
NON_STANDARD },
+{&SUBSEP_node, "SUBSEP",       Node_SUBSEP,            "\034", 0,  NULL,       
0 },
+{&TEXTDOMAIN_node,     "TEXTDOMAIN",           Node_TEXTDOMAIN,        
"messages",     0,  set_TEXTDOMAIN,     NON_STANDARD },
+{0,            NULL,           Node_illegal,           NULL,   0,  NULL,       
0 },
 };
 
 /* init_vars --- actually initialize everything in the symbol table */
@@ -908,6 +916,9 @@
        register const struct varinit *vp;
 
        for (vp = varinit; vp->name; vp++) {
+               if ((vp->flags & NO_INSTALL) != 0)
+                       continue;
+
                *(vp->spec) = install((char *) vp->name,
                  node(vp->strval == NULL ? make_number(vp->numval)
                                : make_string((char *) vp->strval,
@@ -1052,6 +1063,25 @@
        return PROCINFO_node;
 }
 
+/* is_std_var --- return true if a variable is a standard variable */
+
+int
+is_std_var(const char *var)
+{
+       register const struct varinit *vp;
+
+       for (vp = varinit; vp->name; vp++) {
+               if (strcmp(vp->name, var) == 0) {
+                       if ((do_traditional || do_posix) && (vp->flags & 
NON_STANDARD) != 0)
+                               continue;
+
+                       return TRUE;
+               }
+       }
+
+       return FALSE;
+}
+
 /* arg_assign --- process a command-line assignment */
 
 int





reply via email to

[Prev in Thread] Current Thread [Next in Thread]