[Top][All Lists]
[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