summaryrefslogtreecommitdiffstats
path: root/contrib/awk/eval.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/awk/eval.c')
-rw-r--r--contrib/awk/eval.c76
1 files changed, 56 insertions, 20 deletions
diff --git a/contrib/awk/eval.c b/contrib/awk/eval.c
index aa2e881..b314019 100644
--- a/contrib/awk/eval.c
+++ b/contrib/awk/eval.c
@@ -3,7 +3,7 @@
*/
/*
- * Copyright (C) 1986, 1988, 1989, 1991-1997 the Free Software Foundation, Inc.
+ * Copyright (C) 1986, 1988, 1989, 1991-1999 the Free Software Foundation, Inc.
*
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
@@ -25,8 +25,6 @@
#include "awk.h"
-#include <assert.h>
-
extern double pow P((double x, double y));
extern double modf P((double x, double *yp));
extern double fmod P((double x, double y));
@@ -566,14 +564,26 @@ register NODE *volatile tree;
break;
case Node_K_next:
+ if (in_begin_rule)
+ fatal("`next' cannot be called from a BEGIN rule");
+ else if (in_end_rule)
+ fatal("`next' cannot be called from an END rule");
+
if (in_function())
pop_fcall_stack();
+
longjmp(rule_tag, TAG_CONTINUE);
break;
case Node_K_nextfile:
+ if (in_begin_rule)
+ fatal("`nextfile' cannot be called from a BEGIN rule");
+ else if (in_end_rule)
+ fatal("`nextfile' cannot be called from an END rule");
+
if (in_function())
pop_fcall_stack();
+
do_nextfile();
break;
@@ -759,7 +769,8 @@ int iscond;
register size_t len;
char *str;
register char *dest;
- int count;
+ int alloc_count, str_count;
+ int i;
/*
* This is an efficiency hack for multiple adjacent string
@@ -773,16 +784,16 @@ int iscond;
/*
* But first, no arbitrary limits. Count the number of
* nodes and malloc the treelist and strlist arrays.
- * There will be count + 1 items to concatenate. We
+ * There will be alloc_count + 1 items to concatenate. We
* also leave room for an extra pointer at the end to
- * use as a sentinel. Thus, start count at 2.
+ * use as a sentinel. Thus, start alloc_count at 2.
*/
save_tree = tree;
- for (count = 2; tree && tree->type == Node_concat; tree = tree->lnode)
- count++;
+ for (alloc_count = 2; tree && tree->type == Node_concat; tree = tree->lnode)
+ alloc_count++;
tree = save_tree;
- emalloc(treelist, NODE **, sizeof(NODE *) * count, "tree_eval");
- emalloc(strlist, NODE **, sizeof(NODE *) * count, "tree_eval");
+ emalloc(treelist, NODE **, sizeof(NODE *) * alloc_count, "tree_eval");
+ emalloc(strlist, NODE **, sizeof(NODE *) * alloc_count, "tree_eval");
/* Now, here we go. */
treep = treelist;
@@ -795,15 +806,26 @@ int iscond;
* Now, evaluate to strings in LIFO order, accumulating
* the string length, so we can do a single malloc at the
* end.
+ *
+ * Evaluate the expressions first, then get their
+ * lengthes, in case one of the expressions has a
+ * side effect that changes one of the others.
+ * See test/nasty.awk.
*/
strp = strlist;
len = 0;
while (treep >= treelist) {
*strp = force_string(tree_eval(*treep--));
- len += (*strp)->stlen;
strp++;
}
*strp = NULL;
+
+ str_count = strp - strlist;
+ strp = strlist;
+ for (i = 0; i < str_count; i++) {
+ len += (*strp)->stlen;
+ strp++;
+ }
emalloc(str, char *, len+2, "tree_eval");
str[len] = str[len+1] = '\0'; /* for good measure */
dest = str;
@@ -1397,6 +1419,11 @@ NODE *arg_list; /* Node_expression_list of calling args. */
* r_get_lhs:
* This returns a POINTER to a node pointer. get_lhs(ptr) is the current
* value of the var, or where to store the var's new value
+ *
+ * For the special variables, don't unref their current value if it's
+ * the same as the internal copy; perhaps the current one is used in
+ * a concatenation or some other expression somewhere higher up in the
+ * call chain. Ouch.
*/
NODE **
@@ -1409,8 +1436,11 @@ Func_ptr *assign;
if (assign)
*assign = NULL; /* for safety */
- if (ptr->type == Node_param_list)
+ if (ptr->type == Node_param_list) {
+ if ((ptr->flags & FUNC) != 0)
+ fatal("can't use function name `%s' as variable or array", ptr->vname);
ptr = stack_ptr[ptr->param_cnt];
+ }
switch (ptr->type) {
case Node_var_array:
@@ -1444,26 +1474,32 @@ Func_ptr *assign;
break;
case Node_FNR:
- unref(FNR_node->var_value);
- FNR_node->var_value = make_number((AWKNUM) FNR);
+ if (FNR_node->var_value->numbr != FNR) {
+ unref(FNR_node->var_value);
+ FNR_node->var_value = make_number((AWKNUM) FNR);
+ }
aptr = &(FNR_node->var_value);
if (assign != NULL)
*assign = set_FNR;
break;
case Node_NR:
- unref(NR_node->var_value);
- NR_node->var_value = make_number((AWKNUM) NR);
+ if (NR_node->var_value->numbr != NR) {
+ unref(NR_node->var_value);
+ NR_node->var_value = make_number((AWKNUM) NR);
+ }
aptr = &(NR_node->var_value);
if (assign != NULL)
*assign = set_NR;
break;
case Node_NF:
- if (NF == -1)
- (void) get_field(HUGE-1, assign); /* parse record */
- unref(NF_node->var_value);
- NF_node->var_value = make_number((AWKNUM) NF);
+ if (NF == -1 || NF_node->var_value->numbr != NF) {
+ if (NF == -1)
+ (void) get_field(HUGE-1, assign); /* parse record */
+ unref(NF_node->var_value);
+ NF_node->var_value = make_number((AWKNUM) NF);
+ }
aptr = &(NF_node->var_value);
if (assign != NULL)
*assign = set_NF;
OpenPOWER on IntegriCloud