From b3be7507c361145f24f72c584fa847a59ce64827 Mon Sep 17 00:00:00 2001 From: obrien Date: Fri, 2 Nov 2001 21:37:05 +0000 Subject: We use the stock 3.1.0 file (other than needing $FreeBSD$). --- contrib/awk/eval.c | 815 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 584 insertions(+), 231 deletions(-) (limited to 'contrib/awk') diff --git a/contrib/awk/eval.c b/contrib/awk/eval.c index 3d5e568..75c9aa8 100644 --- a/contrib/awk/eval.c +++ b/contrib/awk/eval.c @@ -3,7 +3,7 @@ */ /* - * Copyright (C) 1986, 1988, 1989, 1991-2000 the Free Software Foundation, Inc. + * Copyright (C) 1986, 1988, 1989, 1991-2001 the Free Software Foundation, Inc. * * This file is part of GAWK, the GNU implementation of the * AWK Programming Language. @@ -35,12 +35,14 @@ static int eval_condition P((NODE *tree)); static NODE *op_assign P((NODE *tree)); static NODE *func_call P((NODE *name, NODE *arg_list)); static NODE *match_op P((NODE *tree)); -static void push_args P((int count, NODE *arglist, NODE **oldstack, char *func_name)); +static void push_args P((int count, NODE *arglist, NODE **oldstack, + char *func_name, char **varnames)); static void pop_fcall_stack P((void)); static void pop_fcall P((void)); static int in_function P((void)); char *nodetype2str P((NODETYPE type)); char *flags2str P((int flagval)); +static int comp_func P((const void *p1, const void *p2)); #if __GNUC__ < 2 NODE *_t; /* used as a temporary in macros */ @@ -54,6 +56,13 @@ int ORSlen; int OFMTidx; int CONVFMTidx; +/* Profiling stuff */ +#ifdef PROFILING +#define INCREMENT(n) n++ +#else +#define INCREMENT(n) /* nothing */ +#endif + /* Macros and variables to save and restore function and loop bindings */ /* * the val variable allows return/continue/break-out-of-context to be @@ -114,7 +123,8 @@ char casetable[] = { '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', /* 'x' 'y' 'z' '{' '|' '}' '~' */ '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177', -#ifndef USE_PURE_ASCII + + /* Latin 1: */ C('\200'), C('\201'), C('\202'), C('\203'), C('\204'), C('\205'), C('\206'), C('\207'), C('\210'), C('\211'), C('\212'), C('\213'), C('\214'), C('\215'), C('\216'), C('\217'), C('\220'), C('\221'), C('\222'), C('\223'), C('\224'), C('\225'), C('\226'), C('\227'), @@ -131,24 +141,6 @@ char casetable[] = { C('\350'), C('\351'), C('\352'), C('\353'), C('\354'), C('\355'), C('\356'), C('\357'), C('\360'), C('\361'), C('\362'), C('\363'), C('\364'), C('\365'), C('\366'), C('\367'), C('\370'), C('\371'), C('\372'), C('\373'), C('\374'), C('\375'), C('\376'), C('\377'), -#else - C('\200'), C('\201'), C('\202'), C('\203'), C('\204'), C('\205'), C('\206'), C('\207'), - C('\210'), C('\211'), C('\212'), C('\213'), C('\214'), C('\215'), C('\216'), C('\217'), - C('\220'), C('\221'), C('\222'), C('\223'), C('\224'), C('\225'), C('\226'), C('\227'), - C('\230'), C('\231'), C('\232'), C('\233'), C('\234'), C('\235'), C('\236'), C('\237'), - C('\240'), C('\241'), C('\242'), C('\243'), C('\244'), C('\245'), C('\246'), C('\247'), - C('\250'), C('\251'), C('\252'), C('\253'), C('\254'), C('\255'), C('\256'), C('\257'), - C('\260'), C('\261'), C('\262'), C('\263'), C('\264'), C('\265'), C('\266'), C('\267'), - C('\270'), C('\271'), C('\272'), C('\273'), C('\274'), C('\275'), C('\276'), C('\277'), - C('\300'), C('\301'), C('\302'), C('\303'), C('\304'), C('\305'), C('\306'), C('\307'), - C('\310'), C('\311'), C('\312'), C('\313'), C('\314'), C('\315'), C('\316'), C('\317'), - C('\320'), C('\321'), C('\322'), C('\323'), C('\324'), C('\325'), C('\326'), C('\327'), - C('\330'), C('\331'), C('\332'), C('\333'), C('\334'), C('\335'), C('\336'), C('\337'), - C('\340'), C('\341'), C('\342'), C('\343'), C('\344'), C('\345'), C('\346'), C('\347'), - C('\350'), C('\351'), C('\352'), C('\353'), C('\354'), C('\355'), C('\356'), C('\357'), - C('\360'), C('\361'), C('\362'), C('\363'), C('\364'), C('\365'), C('\366'), C('\367'), - C('\370'), C('\371'), C('\372'), C('\373'), C('\374'), C('\375'), C('\376'), C('\377'), -#endif }; #else #include "You lose. You will need a translation table for your character set." @@ -223,6 +215,7 @@ static char *nodetypes[] = { "Node_redirect_pipe", "Node_redirect_pipein", "Node_redirect_input", + "Node_redirect_twoway", "Node_var", "Node_var_array", "Node_val", @@ -236,114 +229,94 @@ static char *nodetypes[] = { "Node_hashnode", "Node_ahash", "Node_array_ref", - "Node_NF", - "Node_NR", + "Node_BINMODE", + "Node_CONVFMT", + "Node_FIELDWIDTHS", "Node_FNR", "Node_FS", - "Node_RS", - "Node_FIELDWIDTHS", "Node_IGNORECASE", + "Node_LINT", + "Node_NF", + "Node_NR", + "Node_OFMT", "Node_OFS", "Node_ORS", - "Node_OFMT", - "Node_CONVFMT", - "Node_final", + "Node_RS", + "Node_TEXTDOMAIN", + "Node_final --- this should never appear", NULL }; +/* nodetype2str --- convert a node type into a printable value */ + char * -nodetype2str(type) -NODETYPE type; +nodetype2str(NODETYPE type) { static char buf[40]; if (type >= Node_illegal && type <= Node_final) return nodetypes[(int) type]; - sprintf(buf, "unknown nodetype %d", (int) type); + sprintf(buf, _("unknown nodetype %d"), (int) type); return buf; } /* flags2str --- make a flags value readable */ char * -flags2str(flagval) -int flagval; +flags2str(int flagval) +{ + static struct flagtab values[] = { + { MALLOC, "MALLOC" }, + { TEMP, "TEMP" }, + { PERM, "PERM" }, + { STRING, "STRING" }, + { STR, "STR" }, + { NUM, "NUM" }, + { NUMBER, "NUMBER" }, + { MAYBE_NUM, "MAYBE_NUM" }, + { ARRAYMAXED, "ARRAYMAXED" }, + { SCALAR, "SCALAR" }, + { FUNC, "FUNC" }, + { FIELD, "FIELD" }, + { INTLSTR, "INTLSTR" }, + { UNINITIALIZED, "UNINITIALIZED" }, + { 0, NULL }, + }; + + return genflags2str(flagval, values); +} + +/* genflags2str --- general routine to convert a flag value to a string */ + +char * +genflags2str(int flagval, struct flagtab *tab) { static char buffer[BUFSIZ]; char *sp; + int i, space_left, space_needed; sp = buffer; - - if (flagval & MALLOC) { - strcpy(sp, "MALLOC"); - sp += strlen(sp); - } - if (flagval & TEMP) { - if (sp != buffer) - *sp++ = '|'; - strcpy(sp, "TEMP"); - sp += strlen(sp); - } - if (flagval & PERM) { - if (sp != buffer) - *sp++ = '|'; - strcpy(sp, "PERM"); - sp += strlen(sp); - } - if (flagval & STRING) { - if (sp != buffer) - *sp++ = '|'; - strcpy(sp, "STRING"); - sp += strlen(sp); - } - if (flagval & STR) { - if (sp != buffer) - *sp++ = '|'; - strcpy(sp, "STR"); - sp += strlen(sp); - } - if (flagval & NUM) { - if (sp != buffer) - *sp++ = '|'; - strcpy(sp, "NUM"); - sp += strlen(sp); - } - if (flagval & NUMBER) { - if (sp != buffer) - *sp++ = '|'; - strcpy(sp, "NUMBER"); - sp += strlen(sp); - } - if (flagval & MAYBE_NUM) { - if (sp != buffer) - *sp++ = '|'; - strcpy(sp, "MAYBE_NUM"); - sp += strlen(sp); - } - if (flagval & ARRAYMAXED) { - if (sp != buffer) - *sp++ = '|'; - strcpy(sp, "ARRAYMAXED"); - sp += strlen(sp); - } - if (flagval & SCALAR) { - if (sp != buffer) - *sp++ = '|'; - strcpy(sp, "SCALAR"); - sp += strlen(sp); - } - if (flagval & FUNC) { - if (sp != buffer) - *sp++ = '|'; - strcpy(sp, "FUNC"); - sp += strlen(sp); - } - if (flagval & FIELD) { - if (sp != buffer) - *sp++ = '|'; - strcpy(sp, "FIELD"); - sp += strlen(sp); + space_left = BUFSIZ; + for (i = 0; tab[i].name != NULL; i++) { + /* + * note the trick, we want 1 or 0 for whether we need + * the '|' character. + */ + space_needed = (strlen(tab[i].name) + (sp != buffer)); + if (space_left < space_needed) + fatal(_("buffer overflow in genflags2str")); + + if ((flagval & tab[i].val) != 0) { + if (sp != buffer) { + *sp++ = '|'; + space_left--; + } + strcpy(sp, tab[i].name); + /* note ordering! */ + space_left -= strlen(sp); + sp += strlen(sp); + } } return buffer; @@ -355,8 +328,7 @@ int flagval; * statement */ int -interpret(tree) -register NODE *volatile tree; +interpret(register NODE *volatile tree) { jmp_buf volatile loop_tag_stack; /* shallow binding stack for loop_tag */ static jmp_buf rule_tag; /* tag the rule currently being run, for NEXT @@ -385,12 +357,17 @@ register NODE *volatile tree; tree = t->lnode; sourceline = tree->source_line; source = tree->source_file; + INCREMENT(tree->exec_count); switch (setjmp(rule_tag)) { case 0: /* normal non-jump */ /* test pattern, if any */ if (tree->lnode == NULL || - eval_condition(tree->lnode)) + eval_condition(tree->lnode)) { + /* using the lnode exec_count is kludgey */ + if (tree->lnode != NULL) + INCREMENT(tree->lnode->exec_count); (void) interpret(tree->rnode); + } break; case TAG_CONTINUE: /* NEXT statement */ return 1; @@ -410,10 +387,13 @@ register NODE *volatile tree; break; case Node_K_if: - if (eval_condition(tree->lnode)) + INCREMENT(tree->exec_count); + if (eval_condition(tree->lnode)) { + INCREMENT(tree->rnode->exec_count); (void) interpret(tree->rnode->lnode); - else + } else { (void) interpret(tree->rnode->rnode); + } break; case Node_K_while: @@ -421,6 +401,7 @@ register NODE *volatile tree; stable_tree = tree; while (eval_condition(stable_tree->lnode)) { + INCREMENT(stable_tree->exec_count); switch (setjmp(loop_tag)) { case 0: /* normal non-jump */ (void) interpret(stable_tree->rnode); @@ -441,6 +422,7 @@ register NODE *volatile tree; PUSH_BINDING(loop_tag_stack, loop_tag, loop_tag_valid); stable_tree = tree; do { + INCREMENT(stable_tree->exec_count); switch (setjmp(loop_tag)) { case 0: /* normal non-jump */ (void) interpret(stable_tree->rnode); @@ -462,6 +444,7 @@ register NODE *volatile tree; (void) interpret(tree->forloop->init); stable_tree = tree; while (eval_condition(stable_tree->forloop->cond)) { + INCREMENT(stable_tree->exec_count); switch (setjmp(loop_tag)) { case 0: /* normal non-jump */ (void) interpret(stable_tree->lnode); @@ -481,26 +464,65 @@ register NODE *volatile tree; case Node_K_arrayfor: { - volatile struct search l; /* For array_for */ Func_ptr after_assign = NULL; + NODE **list = 0; + NODE *volatile array; + volatile size_t i; + size_t j, num_elems; + volatile int retval = 0; + static int first = TRUE; + static int sort_indices = FALSE; #define hakvar forloop->init #define arrvar forloop->incr + /* get the array */ + array = tree->arrvar; + if (array->type == Node_param_list) + array = stack_ptr[array->param_cnt]; + if (array->type == Node_array_ref) + array = array->orig_array; + if ((array->flags & SCALAR) != 0) + fatal(_("attempt to use scalar `%s' as array"), array->vname); + + /* sanity: do nothing if empty */ + if (array->type == Node_var || array->var_array == NULL + || array->table_size == 0) { + break; /* from switch */ + } + + /* allocate space for array */ + num_elems = array->table_size; + emalloc(list, NODE **, num_elems * sizeof(NODE *), "for_loop"); + + /* populate it */ + for (i = j = 0; i < array->array_size; i++) { + NODE *t = array->var_array[i]; + + if (t == NULL) + continue; + + for (; t != NULL; t = t->ahnext) { + list[j++] = dupnode(t->ahname); + } + } + + if (first) { + first = FALSE; + sort_indices = (getenv("WHINY_USERS") != 0); + } + + if (sort_indices) + qsort(list, num_elems, sizeof(NODE *), comp_func); /* shazzam! */ + + /* now we can run the loop */ PUSH_BINDING(loop_tag_stack, loop_tag, loop_tag_valid); - lhs = get_lhs(tree->hakvar, &after_assign); - t = tree->arrvar; - if (t->type == Node_param_list) - t = stack_ptr[t->param_cnt]; - if (t->type == Node_array_ref) - t = t->orig_array; + + lhs = get_lhs(tree->hakvar, &after_assign, FALSE); stable_tree = tree; - if ((t->flags & SCALAR) != 0) - fatal("attempt to use scalar as array"); - for (assoc_scan(t, (struct search *)&l); - l.retval; - assoc_next((struct search *)&l)) { + for (i = 0; i < num_elems; i++) { + INCREMENT(stable_tree->exec_count); unref(*((NODE **) lhs)); - *lhs = dupnode(l.retval); + *lhs = dupnode(list[i]); if (after_assign) (*after_assign)(); switch (setjmp(loop_tag)) { @@ -510,17 +532,33 @@ register NODE *volatile tree; break; case TAG_BREAK: - RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid); - return 1; + retval = 1; + goto done; + default: cant_happen(); } } + + done: RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid); + + if (do_lint && num_elems != array->table_size) + lintwarn(_("for loop: array `%s' changed size from %d to %d during loop execution"), + array->vname, num_elems, array->table_size); + + for (i = 0; i < num_elems; i++) + unref(list[i]); + + free(list); + + if (retval == 1) + return 1; break; } case Node_K_break: + INCREMENT(tree->exec_count); if (! loop_tag_valid) { /* * Old AT&T nawk treats break outside of loops like @@ -530,11 +568,11 @@ register NODE *volatile tree; static int warned = FALSE; if (do_lint && ! warned) { - warning("use of `break' outside a loop is not portable"); + lintwarn(_("`break' outside a loop is not portable")); warned = TRUE; } if (! do_traditional || do_posix) - fatal("use of `break' outside a loop is not allowed"); + fatal(_("`break' outside a loop is not allowed")); if (in_function()) pop_fcall_stack(); longjmp(rule_tag, TAG_CONTINUE); @@ -543,6 +581,7 @@ register NODE *volatile tree; break; case Node_K_continue: + INCREMENT(tree->exec_count); if (! loop_tag_valid) { /* * Old AT&T nawk treats continue outside of loops like @@ -552,11 +591,11 @@ register NODE *volatile tree; static int warned = FALSE; if (do_lint && ! warned) { - warning("use of `continue' outside a loop is not portable"); + lintwarn(_("`continue' outside a loop is not portable")); warned = TRUE; } if (! do_traditional || do_posix) - fatal("use of `continue' outside a loop is not allowed"); + fatal(_("`continue' outside a loop is not allowed")); if (in_function()) pop_fcall_stack(); longjmp(rule_tag, TAG_CONTINUE); @@ -565,14 +604,17 @@ register NODE *volatile tree; break; case Node_K_print: + INCREMENT(tree->exec_count); do_print(tree); break; case Node_K_printf: + INCREMENT(tree->exec_count); do_printf(tree); break; case Node_K_delete: + INCREMENT(tree->exec_count); do_delete(tree->lnode, tree->rnode); break; @@ -581,11 +623,13 @@ register NODE *volatile tree; break; case Node_K_next: + INCREMENT(tree->exec_count); if (in_begin_rule) - fatal("`next' cannot be called from a 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"); + fatal(_("`next' cannot be called from an END rule")); + /* could add a lint check here */ if (in_function()) pop_fcall_stack(); @@ -593,11 +637,13 @@ register NODE *volatile tree; break; case Node_K_nextfile: + INCREMENT(tree->exec_count); if (in_begin_rule) - fatal("`nextfile' cannot be called from a 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"); + fatal(_("`nextfile' cannot be called from an END rule")); + /* could add a lint check here */ if (in_function()) pop_fcall_stack(); @@ -605,6 +651,7 @@ register NODE *volatile tree; break; case Node_K_exit: + INCREMENT(tree->exec_count); /* * In A,K,&W, p. 49, it says that an exit statement "... * causes the program to behave as if the end of input had @@ -622,6 +669,7 @@ register NODE *volatile tree; break; case Node_K_return: + INCREMENT(tree->exec_count); t = tree_eval(tree->lnode); ret_node = dupnode(t); free_temp(t); @@ -634,7 +682,8 @@ register NODE *volatile tree; * value. */ if (do_lint && tree->type == Node_var) - warning("statement has no effect"); + lintwarn(_("statement has no effect")); + INCREMENT(tree->exec_count); t = tree_eval(tree); free_temp(t); break; @@ -645,9 +694,7 @@ register NODE *volatile tree; /* r_tree_eval --- evaluate a subtree */ NODE * -r_tree_eval(tree, iscond) -register NODE *tree; -int iscond; +r_tree_eval(register NODE *tree, int iscond) { register NODE *r, *t1, *t2; /* return value & temporary subtrees */ register NODE **lhs; @@ -657,9 +704,8 @@ int iscond; #ifdef _CRAY long lx2; #endif - char namebuf[100]; -#ifdef DEBUG +#ifdef GAWKDEBUG if (tree == NULL) return Nnull_string; else if (tree->type == Node_val) { @@ -669,28 +715,39 @@ int iscond; } else if (tree->type == Node_var) { if (tree->var_value->stref <= 0) cant_happen(); + if ((tree->flags & UNINITIALIZED) != 0) + warning(_("reference to uninitialized variable `%s'"), + tree->vname); return tree->var_value; } #endif if (tree->type == Node_param_list) { - int paramnum = tree->param_cnt + 1; - if ((tree->flags & FUNC) != 0) - fatal("can't use function name `%s' as variable or array", + fatal(_("can't use function name `%s' as variable or array"), tree->vname); tree = stack_ptr[tree->param_cnt]; - if (tree == NULL) + + if (tree == NULL) { + if (do_lint) + lintwarn(_("reference to uninitialized argument `%s'"), + tree->vname); return Nnull_string; - sprintf(namebuf, "parameter #%d", paramnum); - tree->vname = namebuf; - } + } + + if (do_lint && (tree->flags & UNINITIALIZED) != 0) + lintwarn(_("reference to uninitialized argument `%s'"), + tree->vname); + } if (tree->type == Node_array_ref) tree = tree->orig_array; switch (tree->type) { case Node_var: + if (do_lint && (tree->flags & UNINITIALIZED) != 0) + lintwarn(_("reference to uninitialized variable `%s'"), + tree->vname); return tree->var_value; case Node_and: @@ -731,11 +788,14 @@ int iscond; case Node_ORS: case Node_OFMT: case Node_CONVFMT: - lhs = get_lhs(tree, (Func_ptr *) NULL); + case Node_BINMODE: + case Node_LINT: + case Node_TEXTDOMAIN: + lhs = get_lhs(tree, (Func_ptr *) NULL, TRUE); return *lhs; case Node_var_array: - fatal("attempt to use array `%s' in a scalar context", + fatal(_("attempt to use array `%s' in a scalar context"), tree->vname); case Node_unary_minus: @@ -755,26 +815,20 @@ int iscond; return match_op(tree); case Node_func: - fatal("function `%s' called with space between name and (,\n%s", + fatal(_("function `%s' called with space between name and `(',\n%s"), tree->lnode->param, - "or used in other expression context"); + _("or used in other expression context")); /* assignments */ case Node_assign: { Func_ptr after_assign = NULL; - if (iscond && do_lint) - warning("assignment used in conditional context"); + if (do_lint && iscond) + lintwarn(_("assignment used in conditional context")); r = tree_eval(tree->rnode); - lhs = get_lhs(tree->lnode, &after_assign); - if (r != *lhs) { - NODE *save; - - save = *lhs; - *lhs = dupnode(r); - unref(save); - } + lhs = get_lhs(tree->lnode, &after_assign, FALSE); + assign_val(lhs, r); free_temp(r); tree->lnode->flags |= SCALAR; if (after_assign) @@ -790,6 +844,7 @@ int iscond; register NODE **treep; register NODE **strp; register size_t len; + register size_t supposed_len; char *str; register char *dest; int alloc_count, str_count; @@ -812,7 +867,8 @@ int iscond; * use as a sentinel. Thus, start alloc_count at 2. */ save_tree = tree; - for (alloc_count = 2; tree && tree->type == Node_concat; tree = tree->lnode) + for (alloc_count = 2; tree != NULL && tree->type == Node_concat; + tree = tree->lnode) alloc_count++; tree = save_tree; emalloc(treelist, NODE **, sizeof(NODE *) * alloc_count, "tree_eval"); @@ -820,7 +876,7 @@ int iscond; /* Now, here we go. */ treep = treelist; - while (tree && tree->type == Node_concat) { + while (tree != NULL && tree->type == Node_concat) { *treep++ = tree->rnode; tree = tree->lnode; } @@ -834,11 +890,21 @@ int iscond; * lengthes, in case one of the expressions has a * side effect that changes one of the others. * See test/nasty.awk. + * + * dupnode the results a la do_print, to give us + * more predicable behavior; compare gawk 3.0.6 to + * nawk/mawk on test/nasty.awk. */ strp = strlist; - len = 0; + supposed_len = len = 0; while (treep >= treelist) { - *strp = force_string(tree_eval(*treep--)); + NODE *n; + + /* Here lies the wumpus's brother. R.I.P. */ + n = force_string(tree_eval(*treep--)); + *strp = dupnode(n); + free_temp(n); + supposed_len += (*strp)->stlen; strp++; } *strp = NULL; @@ -849,14 +915,16 @@ int iscond; len += (*strp)->stlen; strp++; } + if (do_lint && supposed_len != len) + lintwarn(_("concatenation: side effects in one expression have changed the length of another!")); emalloc(str, char *, len+2, "tree_eval"); str[len] = str[len+1] = '\0'; /* for good measure */ dest = str; strp = strlist; - while (*strp) { + while (*strp != NULL) { memcpy(dest, (*strp)->stptr, (*strp)->stlen); dest += (*strp)->stlen; - free_temp(*strp); + unref(*strp); strp++; } r = make_str_node(str, len, ALREADY_MALLOCED); @@ -943,7 +1011,7 @@ int iscond; case Node_quotient: if (x2 == 0) - fatal("division by zero attempted"); + fatal(_("division by zero attempted")); #ifdef _CRAY /* special case for integer division, put in for Cray */ lx2 = x2; @@ -958,7 +1026,7 @@ int iscond; case Node_mod: if (x2 == 0) - fatal("division by zero attempted in mod"); + fatal(_("division by zero attempted in `%%'")); #ifdef HAVE_FMOD return tmp_number(fmod(x1, x2)); #else /* ! HAVE_FMOD */ @@ -973,11 +1041,11 @@ int iscond; return tmp_number(x1 - x2); case Node_var_array: - fatal("attempt to use array `%s' in a scalar context", + fatal(_("attempt to use array `%s' in a scalar context"), tree->vname); default: - fatal("illegal type (%s) in tree_eval", nodetype2str(tree->type)); + fatal(_("illegal type (%s) in tree_eval"), nodetype2str(tree->type)); } return 0; } @@ -985,8 +1053,7 @@ int iscond; /* eval_condition --- is TREE true or false? Returns 0==false, non-zero==true */ static int -eval_condition(tree) -register NODE *tree; +eval_condition(register NODE *tree) { register NODE *t1; register int ret; @@ -1038,8 +1105,7 @@ register NODE *tree; /* cmp_nodes --- compare two nodes, returning negative, 0, positive */ int -cmp_nodes(t1, t2) -register NODE *t1, *t2; +cmp_nodes(register NODE *t1, register NODE *t2) { register int ret; register size_t len1, len2; @@ -1083,8 +1149,7 @@ register NODE *t1, *t2; /* op_assign --- do +=, -=, etc. */ static NODE * -op_assign(tree) -register NODE *tree; +op_assign(register NODE *tree) { AWKNUM rval, lval; NODE **lhs; @@ -1102,7 +1167,7 @@ register NODE *tree; switch(tree->type) { case Node_preincrement: case Node_predecrement: - lhs = get_lhs(tree->lnode, &after_assign); + lhs = get_lhs(tree->lnode, &after_assign, TRUE); lval = force_number(*lhs); unref(*lhs); *lhs = make_number(lval + @@ -1114,7 +1179,7 @@ register NODE *tree; case Node_postincrement: case Node_postdecrement: - lhs = get_lhs(tree->lnode, &after_assign); + lhs = get_lhs(tree->lnode, &after_assign, TRUE); lval = force_number(*lhs); unref(*lhs); *lhs = make_number(lval + @@ -1135,7 +1200,7 @@ register NODE *tree; rval = force_number(tmp); free_temp(tmp); - lhs = get_lhs(tree->lnode, &after_assign); + lhs = get_lhs(tree->lnode, &after_assign, FALSE); lval = force_number(*lhs); unref(*lhs); @@ -1162,7 +1227,7 @@ register NODE *tree; case Node_assign_quotient: if (rval == (AWKNUM) 0) - fatal("division by zero attempted in /="); + fatal(_("division by zero attempted in `/='")); #ifdef _CRAY /* special case for integer division, put in for Cray */ ltemp = rval; @@ -1180,7 +1245,7 @@ register NODE *tree; case Node_assign_mod: if (rval == (AWKNUM) 0) - fatal("division by zero attempted in %%="); + fatal(_("division by zero attempted in `%%='")); #ifdef HAVE_FMOD *lhs = make_number(fmod(lval, rval)); #else /* ! HAVE_FMOD */ @@ -1252,14 +1317,34 @@ pop_fcall() if (arg->type == Node_param_list) arg = stack_ptr[arg->param_cnt]; n = *sp++; - if ((arg->type == Node_var /* || arg->type == Node_var_array */) - && n->type == Node_var_array) { - /* should we free arg->var_value ? */ - arg->var_array = n->var_array; - arg->type = Node_var_array; - arg->array_size = n->array_size; - arg->table_size = n->table_size; - arg->flags = n->flags; + if (n->type == Node_var_array || n->type == Node_array_ref) { + NODETYPE old_type; /* for check, below */ + + old_type = arg->type; + + /* + * subtlety: if arg->type is Node_var but n->type + * is Node_var_array, then the array routines noticed + * that a variable name was really an array and + * changed the type. But when v->name was pushed + * on the stack, it came out of the varnames array, + * and was not malloc'ed, so we shouldn't free it. + * See the corresponding code in push_args(). + * Thanks to Juergen Kahrs for finding a test case + * that shows this. + */ + if (old_type == Node_var_array || old_type == Node_array_ref) + free(n->vname); + + if (arg->type == Node_var) { + /* type changed, copy array back for call by reference */ + /* should we free arg->var_value ? */ + arg->var_array = n->var_array; + arg->type = Node_var_array; + arg->array_size = n->array_size; + arg->table_size = n->table_size; + arg->flags = n->flags; + } } /* n->lnode overlays the array size, don't unref it if array */ if (n->type != Node_var_array && n->type != Node_array_ref) @@ -1295,14 +1380,18 @@ pop_fcall_stack() /* push_args --- push function arguments onto the stack */ static void -push_args(count, arglist, oldstack, func_name) -int count; -NODE *arglist; -NODE **oldstack; -char *func_name; +push_args(int count, + NODE *arglist, + NODE **oldstack, + char *func_name, + char **varnames) { struct fcall *f; NODE *arg, *argp, *r, **sp, *n; + int i; + int num_args; + + num_args = count; /* save for later use */ if (fcall_list_size == 0) { /* first time */ emalloc(fcall_list, struct fcall *, 10 * sizeof(struct fcall), @@ -1319,7 +1408,7 @@ char *func_name; memset(f, '\0', sizeof(struct fcall)); if (count > 0) - emalloc(f->stack, NODE **, count*sizeof(NODE *), "func_call"); + emalloc(f->stack, NODE **, count*sizeof(NODE *), "push_args"); f->count = count; f->fname = func_name; /* not used, for debugging, just in case */ f->arglist = arglist; @@ -1328,11 +1417,12 @@ char *func_name; sp = f->stack; /* for each calling arg. add NODE * on stack */ - for (argp = arglist; count > 0 && argp != NULL; argp = argp->rnode) { + for (argp = arglist, i = 0; count > 0 && argp != NULL; argp = argp->rnode) { + static char from[] = N_("%s (from %s)"); arg = argp->lnode; getnode(r); r->type = Node_var; - + r->flags = 0; /* call by reference for arrays; see below also */ if (arg->type == Node_param_list) { /* we must also reassign f here; see below */ @@ -1340,26 +1430,43 @@ char *func_name; arg = f->prevstack[arg->param_cnt]; } if (arg->type == Node_var_array) { + char *p; + size_t len; + r->type = Node_array_ref; r->flags &= ~SCALAR; r->orig_array = arg; - r->vname = arg->vname; + len = strlen(varnames[i]) + strlen(arg->vname) + + strlen(gettext(from)) - 4 + 1; + emalloc(p, char *, len, "push_args"); + sprintf(p, _(from), varnames[i], arg->vname); + r->vname = p; } else if (arg->type == Node_array_ref) { - *r = *arg; + char *p; + size_t len; + + *r = *arg; + len = strlen(varnames[i]) + strlen(arg->vname) + + strlen(gettext(from)) - 4 + 1; + emalloc(p, char *, len, "push_args"); + sprintf(p, _(from), varnames[i], arg->vname); + r->vname = p; } else { n = tree_eval(arg); r->lnode = dupnode(n); r->rnode = (NODE *) NULL; if ((n->flags & SCALAR) != 0) r->flags |= SCALAR; + r->vname = varnames[i]; free_temp(n); } *sp++ = r; + i++; count--; } if (argp != NULL) /* left over calling args. */ warning( - "function `%s' called with more arguments than declared", + _("function `%s' called with more arguments than declared"), func_name); /* add remaining params. on stack with null value */ @@ -1369,6 +1476,9 @@ char *func_name; r->lnode = Nnull_string; r->flags &= ~SCALAR; r->rnode = (NODE *) NULL; + r->vname = varnames[i++]; + r->flags = UNINITIALIZED; + r->param_cnt = num_args - count; *sp++ = r; } @@ -1389,9 +1499,8 @@ char *func_name; NODE **stack_ptr; static NODE * -func_call(name, arg_list) -NODE *name; /* name is a Node_val giving function name */ -NODE *arg_list; /* Node_expression_list of calling args. */ +func_call(NODE *name, /* name is a Node_val giving function name */ + NODE *arg_list) /* Node_expression_list of calling args. */ { register NODE *r; NODE *f; @@ -1404,11 +1513,12 @@ NODE *arg_list; /* Node_expression_list of calling args. */ /* retrieve function definition node */ f = lookup(name->stptr); if (f == NULL || f->type != Node_func) - fatal("function `%s' not defined", name->stptr); + fatal(_("function `%s' not defined"), name->stptr); #ifdef FUNC_TRACE - fprintf(stderr, "function %s called\n", name->stptr); + fprintf(stderr, _("function %s called\n"), name->stptr); #endif - push_args(f->lnode->param_cnt, arg_list, stack_ptr, name->stptr); + push_args(f->lnode->param_cnt, arg_list, stack_ptr, name->stptr, + f->parmlist); /* * Execute function body, saving context, as a return statement @@ -1431,6 +1541,7 @@ NODE *arg_list; /* Node_expression_list of calling args. */ PUSH_BINDING(func_tag_stack, func_tag, func_tag_valid); save_ret_node = ret_node; ret_node = Nnull_string; /* default return value */ + INCREMENT(f->exec_count); /* count function calls */ if (setjmp(func_tag) == 0) (void) interpret(f->rnode); @@ -1452,6 +1563,24 @@ NODE *arg_list; /* Node_expression_list of calling args. */ return r; } +#ifdef PROFILING +/* dump_fcall_stack --- print a backtrace of the awk function calls */ + +void +dump_fcall_stack(FILE *fp) +{ + int i; + + if (curfcall < 0) + return; + + fprintf(fp, _("\n\t# Function Call Stack:\n\n")); + for (i = curfcall; i >= 0; i--) + fprintf(fp, "\t# %3d. %s\n", i+1, fcall_list[i].fname); + fprintf(fp, _("\t# -- main --\n")); +} +#endif /* PROFILING */ + /* * r_get_lhs: * This returns a POINTER to a node pointer. get_lhs(ptr) is the current @@ -1464,9 +1593,7 @@ NODE *arg_list; /* Node_expression_list of calling args. */ */ NODE ** -r_get_lhs(ptr, assign) -register NODE *ptr; -Func_ptr *assign; +r_get_lhs(register NODE *ptr, Func_ptr *assign, int reference) { register NODE **aptr = NULL; register NODE *n; @@ -1475,19 +1602,25 @@ Func_ptr *assign; *assign = NULL; /* for safety */ if (ptr->type == Node_param_list) { if ((ptr->flags & FUNC) != 0) - fatal("can't use function name `%s' as variable or array", ptr->vname); + fatal(_("can't use function name `%s' as variable or array"), ptr->vname); ptr = stack_ptr[ptr->param_cnt]; } switch (ptr->type) { case Node_array_ref: case Node_var_array: - fatal("attempt to use array `%s' in a scalar context", + fatal(_("attempt to use array `%s' in a scalar context"), ptr->vname); case Node_var: + if (! reference) + ptr->flags &= ~UNINITIALIZED; + else if (do_lint && (ptr->flags & UNINITIALIZED) != 0) + lintwarn(_("reference to uninitialized variable `%s'"), + ptr->vname); + aptr = &(ptr->var_value); -#ifdef DEBUG +#ifdef GAWKDEBUG if (ptr->var_value->stref <= 0) cant_happen(); #endif @@ -1549,6 +1682,18 @@ Func_ptr *assign; *assign = set_IGNORECASE; break; + case Node_BINMODE: + aptr = &(BINMODE_node->var_value); + if (assign != NULL) + *assign = set_BINMODE; + break; + + case Node_LINT: + aptr = &(LINT_node->var_value); + if (assign != NULL) + *assign = set_LINT; + break; + case Node_OFMT: aptr = &(OFMT_node->var_value); if (assign != NULL) @@ -1573,8 +1718,32 @@ Func_ptr *assign; *assign = set_OFS; break; + case Node_TEXTDOMAIN: + aptr = &(TEXTDOMAIN_node->var_value); + if (assign != NULL) + *assign = set_TEXTDOMAIN; + break; + case Node_param_list: - aptr = &(stack_ptr[ptr->param_cnt]->var_value); + { + NODE *n = stack_ptr[ptr->param_cnt]; + + /* + * This test should always be true, due to the code + * above, before the switch, that handles parameters. + */ + if (n->type != Node_var_array) + aptr = &n->var_value; + else + fatal(_("attempt to use array `%s' in a scalar context"), + n->vname); + + if (! reference) + n->flags &= ~UNINITIALIZED; + else if (do_lint && (n->flags & UNINITIALIZED) != 0) + lintwarn(_("reference to uninitialized argument `%s'"), + n->vname); + } break; case Node_field_spec: @@ -1582,10 +1751,17 @@ Func_ptr *assign; int field_num; n = tree_eval(ptr->lnode); + if (do_lint) { + if ((n->flags & NUMBER) == 0) { + lintwarn(_("attempt to field reference from non-numeric value")); + if (n->stlen == 0) + lintwarn(_("attempt to reference from null string")); + } + } field_num = (int) force_number(n); free_temp(n); if (field_num < 0) - fatal("attempt to access field %d", field_num); + fatal(_("attempt to access field %d"), field_num); if (field_num == 0 && field0_valid) { /* short circuit */ aptr = &fields_arr[0]; if (assign != NULL) @@ -1595,32 +1771,45 @@ Func_ptr *assign; aptr = get_field(field_num, assign); break; } + case Node_subscript: n = ptr->lnode; if (n->type == Node_param_list) { - int i = n->param_cnt + 1; - n = stack_ptr[n->param_cnt]; if ((n->flags & SCALAR) != 0) - fatal("attempt to use scalar parameter %d as an array", i); + fatal(_("attempt to use scalar parameter `%s' as an array"), n->vname); } if (n->type == Node_array_ref) { n = n->orig_array; assert(n->type == Node_var_array || n->type == Node_var); } if (n->type == Node_func) { - fatal("attempt to use function `%s' as array", + fatal(_("attempt to use function `%s' as array"), n->lnode->param); } - aptr = assoc_lookup(n, concat_exp(ptr->rnode)); + aptr = assoc_lookup(n, concat_exp(ptr->rnode), reference); break; case Node_func: - fatal("`%s' is a function, assignment is not allowed", + fatal(_("`%s' is a function, assignment is not allowed"), ptr->lnode->param); case Node_builtin: - fatal("assignment is not allowed to result of builtin function"); +#if 1 + /* in gawk for a while */ + fatal(_("assignment is not allowed to result of builtin function")); +#else + /* + * This is how Christos at Deshaw did it. + * Does this buy us anything? + */ + if (ptr->proc == NULL) + fatal(_("assignment is not allowed to result of builtin function")); + ptr->callresult = (*ptr->proc)(ptr->subnode); + aptr = &ptr->callresult; + break; +#endif + default: fprintf(stderr, "type = %s\n", nodetype2str(ptr->type)); fflush(stderr); @@ -1632,8 +1821,7 @@ Func_ptr *assign; /* match_op --- do ~ and !~ */ static NODE * -match_op(tree) -register NODE *tree; +match_op(register NODE *tree) { register NODE *t1; register Regexp *rp; @@ -1680,7 +1868,7 @@ set_IGNORECASE() if ((do_lint || do_traditional) && ! warned) { warned = TRUE; - warning("IGNORECASE not supported in compatibility mode"); + lintwarn(_("`IGNORECASE' is a gawk extension")); } if (do_traditional) IGNORECASE = FALSE; @@ -1696,6 +1884,59 @@ set_IGNORECASE() set_FS_if_not_FIELDWIDTHS(); } +/* set_BINMODE --- set translation mode (OS/2, DOS, others) */ + +void +set_BINMODE() +{ + static int warned = FALSE; + char *p, *cp, save; + NODE *v; + int digits = FALSE; + + if ((do_lint || do_traditional) && ! warned) { + warned = TRUE; + lintwarn(_("`BINMODE' is a gawk extension")); + } + if (do_traditional) + BINMODE = 0; + else if ((BINMODE_node->var_value->flags & STRING) != 0) { + v = BINMODE_node->var_value; + p = v->stptr; + save = p[v->stlen]; + p[v->stlen] = '\0'; + + for (cp = p; *cp != '\0'; cp++) { + if (ISDIGIT(*cp)) { + digits = TRUE; + break; + } + } + + if (! digits || (BINMODE_node->var_value->flags & MAYBE_NUM) == 0) { + BINMODE = 0; + if (strcmp(p, "r") == 0) + BINMODE = 1; + else if (strcmp(p, "w") == 0) + BINMODE = 2; + else if (strcmp(p, "rw") == 0 || strcmp(p, "wr") == 0) + BINMODE = 3; + + if (BINMODE == 0 && v->stlen != 0) { + /* arbitrary string, assume both */ + BINMODE = 3; + warning("BINMODE: arbitary string value treated as \"rw\""); + } + } else + BINMODE = (int) force_number(BINMODE_node->var_value); + + p[v->stlen] = save; + } else if ((BINMODE_node->var_value->flags & NUMBER) != 0) + BINMODE = (int) force_number(BINMODE_node->var_value); + else + BINMODE = 0; /* shouldn't happen */ +} + /* set_OFS --- update OFS related variables when OFS assigned to */ void @@ -1723,8 +1964,7 @@ static int fmt_ok P((NODE *n)); static int fmt_index P((NODE *n)); static int -fmt_ok(n) -NODE *n; +fmt_ok(NODE *n) { NODE *tmp = force_string(n); char *p = tmp->stptr; @@ -1733,13 +1973,13 @@ NODE *n; return 0; while (*p && strchr(" +-#", *p) != NULL) /* flags */ p++; - while (*p && isdigit(*p)) /* width - %*.*g is NOT allowed */ + while (*p && ISDIGIT(*p)) /* width - %*.*g is NOT allowed */ p++; - if (*p == '\0' || (*p != '.' && ! isdigit(*p))) + if (*p == '\0' || (*p != '.' && ! ISDIGIT(*p))) return 0; if (*p == '.') p++; - while (*p && isdigit(*p)) /* precision */ + while (*p && ISDIGIT(*p)) /* precision */ p++; if (*p == '\0' || strchr("efgEG", *p) == NULL) return 0; @@ -1751,8 +1991,7 @@ NODE *n; /* fmt_index --- track values of OFMT and CONVFMT to keep semantics correct */ static int -fmt_index(n) -NODE *n; +fmt_index(NODE *n) { register int ix = 0; static int fmt_num = 4; @@ -1769,10 +2008,10 @@ NODE *n; /* not found */ n->stptr[n->stlen] = '\0'; if (do_lint && ! fmt_ok(n)) - warning("bad %sFMT specification", + lintwarn(_("bad `%sFMT' specification `%s'"), n == CONVFMT_node->var_value ? "CONV" : n == OFMT_node->var_value ? "O" - : ""); + : "", n->stptr); if (fmt_hiwater >= fmt_num) { fmt_num *= 2; @@ -1799,3 +2038,117 @@ set_CONVFMT() CONVFMTidx = fmt_index(CONVFMT_node->var_value); CONVFMT = fmt_list[CONVFMTidx]->stptr; } + +/* set_LINT --- update LINT as appropriate */ + +void +set_LINT() +{ + int old_lint = do_lint; + + if ((LINT_node->var_value->flags & (STRING|STR)) != 0) { + if ((LINT_node->var_value->flags & MAYBE_NUM) == 0) { + char *lintval; + size_t lintlen; + + do_lint = (force_string(LINT_node->var_value)->stlen > 0); + lintval = LINT_node->var_value->stptr; + lintlen = LINT_node->var_value->stlen; + if (do_lint) { + if (lintlen == 5 && strncmp(lintval, "fatal", 5) == 0) + lintfunc = r_fatal; + else + lintfunc = warning; + } else + lintfunc = warning; + } else + do_lint = (force_number(LINT_node->var_value) != 0.0); + } else if ((LINT_node->var_value->flags & (NUM|NUMBER)) != 0) { + do_lint = (force_number(LINT_node->var_value) != 0.0); + lintfunc = warning; + } else + do_lint = FALSE; /* shouldn't happen */ + + if (! do_lint) + lintfunc = warning; + + /* explicitly use warning() here, in case lintfunc == r_fatal */ + if (old_lint != do_lint && old_lint) + warning(_("turning off `--lint' due to assignment to `LINT'")); +} + +/* set_TEXTDOMAIN --- update TEXTDOMAIN variable when TEXTDOMAIN assigned to */ + +void +set_TEXTDOMAIN() +{ + int len; + + TEXTDOMAIN = force_string(TEXTDOMAIN_node->var_value)->stptr; + len = TEXTDOMAIN_node->var_value->stlen; + TEXTDOMAIN[len] = '\0'; + /* + * Note: don't call textdomain(); this value is for + * the awk program, not for gawk itself. + */ +} + +/* + * assign_val --- do mechanics of assignment, for calling from multiple + * places. + */ + +NODE * +assign_val(NODE **lhs_p, NODE *rhs) +{ + NODE *save; + + if (rhs != *lhs_p) { + save = *lhs_p; + *lhs_p = dupnode(rhs); + unref(save); + } + return *lhs_p; +} + +/* update_ERRNO --- update the value of ERRNO */ + +void +update_ERRNO() +{ + char *cp; + + cp = strerror(errno); + cp = gettext(cp); + unref(ERRNO_node->var_value); + ERRNO_node->var_value = make_string(cp, strlen(cp)); +} + +/* comp_func --- array index comparison function for qsort */ + +static int +comp_func(const void *p1, const void *p2) +{ + size_t len1, len2; + char *str1, *str2; + NODE *t1, *t2; + + t1 = *((NODE **) p1); + t2 = *((NODE **) p2); + +/* + t1 = force_string(t1); + t2 = force_string(t2); +*/ + len1 = t1->stlen; + str1 = t1->stptr; + + len2 = t2->stlen; + str2 = t2->stptr; + + /* Array indexes are strings, compare as such, always! */ + if (len1 == len2 || len1 < len2) + return strncmp(str1, str2, len1); + else + return strncmp(str1, str2, len2); +} -- cgit v1.1