diff options
47 files changed, 944 insertions, 394 deletions
@@ -16,6 +16,86 @@ * symbol.c (get_symbols): Add FUNCTAB and SYMTAB to the list for the -d option. Thanks to Hermann Peifer for the report. +2016-06-30 Arnold D. Robbins <arnold@skeeve.com> + + * node.c (r_force_number): Coding style change. + +2016-06-30 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * awk.h (STFMT_UNUSED): New define indicating that the string + representation does not depend on CONVFMT or OFMT. + (force_string): Use STFMT_UNUSED to improve code clarity. + * array.c (value_info): Fix stfmt logic. + * builtin.c (do_print): Use STFMT_UNUSED to improve code clarity. + * field.c (set_record): Ditto. + * gawkapi.c (api_sym_update_scalar): Ditto. + * int_array.c (is_integer): Check stfmt equals STFMT_UNUSED before + bothering to inspect the string. + * mpfr.c (mpg_format_val): Use STFMT_UNUSED to improve code clarity. + Remove buggy cast to char in stfmt assignment. + * node.c (r_format_val): Ditto. + * str_array.c (str_lookup): Use STFMT_UNUSED to improve code clarity. + * symbol.c (check_param_names): Ditto. + +2016-06-29 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * node.c (r_force_number): Optimize by trimming leading and trailing + white space before we inspect the string contents. + (get_ieee_magic_val): Must terminate the string with '\0' before + calling strtod. + +2016-06-27 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * gawkapi.h (awk_string): Add comment about the potential lack of + NUL-termination. + +2016-06-27 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * awk.h: Add a comment regarding the potential lack of NUL-termination + for Node_val strings. + +2016-06-27 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * node.c (r_format_val): Do not free stptr unless STRCUR is set. + This is safer than testing for non-NULL stptr, since, for example, + pp_number copies a node and calls r_format_val, but does not bother + to set stptr to NULL beforehand. + +2016-06-26 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * node.c (r_force_number): When checking for trailing spaces, protect + against running off the end of the string. + * mpfr.c (force_mpnum): Ditto. + +2016-06-26 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * builtin.c (do_print): There's actually no reason to test whether a + value is a number, since the STRCUR flag and stfmt value contain all + the necessary info, as in awk.h:force_string. + +2016-06-26 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * builtin.c (do_print): Do not use OFMT to print strnum values. We + accomplish this by calling format_val for a NUMBER only + if there is no string currently available, or if stfmt equals + neither -1 nor OFMTidx. + +2016-06-26 Arnold D. Robbins <arnold@skeeve.com> + + * awk.h: Edit some comments. Add others. Minor coding style changes. + * builtin.c (format_tree): Restore a comment. + (do_mktime): Restore saving/restoring of byte after format string. + (do_sub): Coding style. Use %.*s in warning message. + (nondec2awknum): Restore saving/restoring of byte after string value + being converted. + * eval.c: Minor coding style edits. + * int_array.c (is_integer): Fix order of checks for not + updating string value: check length == 0 before testing values. + Coding style edits. + * mpfr.c (do_mpfr_strtonum): Coding style edits. + * node.c (r_force_number): Restore saving/restoring of byte after + string value being converted. Edit comments some. + 2016-06-26 Arnold D. Robbins <arnold@skeeve.com> Repair change of 2015-08-25 to handling of MAYBE_NUM. @@ -26,6 +106,22 @@ Thanks to Andrew Schorr for reporting the problem. A test case will eventually be merged into master. + Only in stable and master. + +2016-06-20 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * builtin.c (do_strftime): Call fixtype before checking flags for + STRING type. + (do_print): Call fixtype before checking whether argument is a NUMBER. + * eval.c (set_BINMODE): Call fixtype before checking value type. + No need to call force_number if the flags say it's a number. + (r_get_field): Fix lint check for non-numeric argument. + * io.c (redirect): Call fixtype before checking whether it's a string. + +2016-06-18 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * node.c (r_force_number): Fix typo in comment. + 2016-06-16 Arnold D. Robbins <arnold@skeeve.com> * awk.h: Add comment headers for several functions. @@ -36,6 +132,103 @@ * config.sub: Update from GNULIB. +2016-06-14 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * awk.h (boolval): New inline function to standardize testing whether + a node's value is true. + * builtin.c (do_strftime): Use boolval to handle 3rd argument. + * eval.c (set_IGNORECASE, eval_condition): Use new boolval function. + * io.c (pty_vs_pipe): Use new boolval function. + +2016-06-14 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * builtin.c (do_strftime): Fix handling of 3rd argument to work + as a standard boolean: non-null or non-zero. + +2016-06-14 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * gawkapi.c (node_to_awk_value): When caller requests AWK_SCALAR + or AWK_UNDEFINED, we need to call fixtype before we check the type. + +2016-06-13 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * awkgram.y: Eliminate STRCUR tests. Must use STRING to test whether + a scalar is a string. + +2016-06-12 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * awk.h: Improve comment about STRING and NUMBER type assignment. + (nondec2awknum): Add endptr argument. + (fixtype): New inline function to clarify a scalar's type. + * array.c (sort_up_value_type): Call fixtype before checking the value + types. + * awkgram.y (yylex): Pass NULL endptr argument to nondec2awknum. + (valinfo): Remove dead tests: either STRING or NUMBER or both + must be set, so there's no reason to continue with checks for NUMCUR or + STRCUR. + * builtin.c (do_exp, do_int, do_log, do_sqrt, do_sin, do_cos, do_srand): + Fix lint check for non-numeric argument. + (do_string): Fix lint check for 1st and 2nd args being strings. + (do_length): Fix assert to allow for Node_typedregex. + Fix lint check for non-string argument. + (format_tree): Fix type detection for '%c' arguments. + (do_strftime): Fix lint check for non-numeric 2nd argument and + lint check for non-string 1st argument. + (do_mktime): Fix lint check for non-string argument. Eliminate useless + logic to save and restore terminating NUL. + (do_system, do_tolower, do_toupper): Fix lint check for non-string + argument. + (do_atan2, do_lshift, do_rshift, do_and, do_or, do_xor, do_compl, + do_intdiv): Fix lint checks for non-numeric args. + (do_sub): Attempt to clean up treatment of 3rd argument to gensub + despite vague documentation of expected behavior. + (do_strnum): Fix bug in number detection logic, and pass new endptr + arg to nondec2awknum. + (nondec2awknum): Add endptr argument so caller can detect how much + of the string was consumed. Eliminate unnecessary logic to save + and restore terminating NUL char. + (do_typeof): Use a switch to specify which cases are supported, and + issue a warning message when a corrupt type is detected. + * debug.c (print_memory): At least one of NUMBER and STRING should + be set, so no need to check for NUMCUR or STRCUR in addition. + * eval.c (cmp_nodes): Use fixtype function to fix arg types. + (set_IGNORECASE): Fix logic for acting on value type. Note that + setting IGNORECASE to a string value of "0" with NUMCUR set now enables + ignorecase, so that's a subtle change in behavior that seems to match + the docs. + (set_LINT): Try to clean up configuration logic based on type. + * ext.c (get_argument): Remove unused variable pcount. + * gawkapi.c (node_to_awk_value): Remove pointless test for NUMCUR + after calling force_number. Similarly, no need to test for STRCUR + after calling force_string. + * int_array.c (is_integer): Reject cases where a string value is + present that will not be correctly regenerated from the integer; + in particular, this could happen where blank space padding is present, + leading zeroes are present, or for hex or octal values. + Also fix some bugs where a strnum was converted to a NUMBER without + turning off the STRING bit. + * io.c (redirect_string): Make lint warning message more accurate. + (redirect): Change not_string test to use STRING bit, not STRCUR. + (pty_vs_pipe): Use fixtype to correct logic for detecting whether a + value is anumber. + * mpfr.c (mpg_force_number): If NUMCUR is set, there's no need to + test is_mpg_number. If it's not, the NODE is corrupt and we've got + bigger problems. Fix flag manipulation logic. Always set NUMCUR and + clear MAYBE_NUM, + (set_PREC): Fix logic using fixtype function. + (do_mpfr_atan2, do_mpfr_intdiv): Fix lint check for non-numeric + arguments. + (do_mpfr_func, do_mpfr_int, do_mpfr_compl, get_intval, do_mpfr_srand): + Fix lint check for non-numeric argument. + (do_mpfr_strtonum): Use fixtype and stop testing for NUMCUR bit. + * node.c (r_force_number): Eliminate pointless save and restore of + terminating NUL char. Always set NUMCUR and clear MAYBE_NUM, and + convert STRING to NUMBER if appropriate, fixing bugs in flag + manipulations. For non-decimal data, need to consider whether there + is trailing non-numeric data in deciding whether a MAYBE_NUM should + be converted to a NUMBER, so take advantage of new endptr arg + to nondec2awknum. + 2016-06-14 Arnold D. Robbins <arnold@skeeve.com> * builtin.c (do_sub): Fix sub for long runs of backslashes. @@ -704,7 +704,14 @@ value_info(NODE *n) if ((n->flags & (STRING|STRCUR)) == STRCUR) { fprintf(output_fp, "]["); fprintf(output_fp, "stfmt=%d, ", n->stfmt); - fprintf(output_fp, "CONVFMT=\"%s\"", n->stfmt <= -1 ? "<unused>" + /* + * If not STFMT_UNUSED, could be CONVFMT or OFMT if last + * used in a print statement. If immutable, could be that it + * was originally set as a string, or it's a number that has + * an integer value. + */ + fprintf(output_fp, "FMT=\"%s\"", + n->stfmt == STFMT_UNUSED ? "<unused>" : fmt_list[n->stfmt]->stptr); } @@ -1157,17 +1164,8 @@ sort_up_value_type(const void *p1, const void *p2) } /* two scalars */ - /* 2. Resolve MAYBE_NUM, so that have only NUMBER or STRING */ - if ((n1->flags & MAYBE_NUM) != 0) - (void) force_number(n1); - if ((n2->flags & MAYBE_NUM) != 0) - (void) force_number(n2); - - /* 2.5. Resolve INTIND, so that is STRING, and not NUMBER */ - if ((n1->flags & INTIND) != 0) - (void) force_string(n1); - if ((n2->flags & INTIND) != 0) - (void) force_string(n2); + (void) fixtype(n1); + (void) fixtype(n2); if ((n1->flags & NUMBER) != 0 && (n2->flags & NUMBER) != 0) { return cmp_numbers(n1, n2); @@ -392,8 +392,11 @@ typedef struct exp_node { /* type = Node_val */ /* - * STRING and NUMBER are mutually exclusive. They represent the - * type of a value as assigned. + * STRING and NUMBER are mutually exclusive, except for the special + * case of an uninitialized value, represented internally by + * Nnull_string. They represent the type of a value as assigned. + * Nnull_string has both STRING and NUMBER attributes, but all other + * scalar values should have precisely one of these bits set. * * STRCUR and NUMCUR are not mutually exclusive. They represent that * the particular type of value is up to date. For example, @@ -408,7 +411,8 @@ typedef struct exp_node { * * MAYBE_NUM is the joker. It means "this is string data, but * the user may have really wanted it to be a number. If we have - * to guess, like in a comparison, turn it into a number." + * to guess, like in a comparison, turn it into a number if the string + * is indeed numeric." * For example, gawk -v a=42 .... * Here, `a' gets STRING|STRCUR|MAYBE_NUM and then when used where * a number is needed, it gets turned into a NUMBER and STRING @@ -472,6 +476,13 @@ typedef struct exp_node { #define re_cnt flags /* Node_val */ +/* + * Note that the string in stptr may not be NUL-terminated, but it is + * guaranteed to have at least one extra byte that may be temporarily set + * to '\0'. This is helpful when calling functions such as strtod that require + * a NUL-terminated argument. In particular, field values $n for n > 0 and + * n < NF will not have a NUL terminator, since they point into the $0 buffer. + */ #define stptr sub.val.sp #define stlen sub.val.slen #define valref sub.val.sref @@ -486,6 +497,16 @@ typedef struct exp_node { #define numbr sub.val.fltnum #endif +/* + * If stfmt is set to STFMT_UNUSED, it means that the string representation + * stored in stptr is not a function of the value of CONVFMT or OFMT. That + * indicates that either the string value was explicitly assigned, or it + * was converted from a NUMBER that has an integer value. When stfmt is not + * set to STFMT_UNUSED, it is an offset into the fmt_list array of distinct + * CONVFMT and OFMT node pointers. + */ +#define STFMT_UNUSED -1 + /* Node_arrayfor */ #define for_list sub.nodep.r.av #define for_list_size sub.nodep.reflags @@ -1401,7 +1422,7 @@ extern NODE *do_or(int nargs); extern NODE *do_xor(int nargs); extern NODE *do_compl(int nargs); extern NODE *do_strtonum(int nargs); -extern AWKNUM nondec2awknum(char *str, size_t len); +extern AWKNUM nondec2awknum(char *str, size_t len, char **endptr); extern NODE *do_dcgettext(int nargs); extern NODE *do_dcngettext(int nargs); extern NODE *do_bindtextdomain(int nargs); @@ -1787,7 +1808,7 @@ force_string(NODE *s) return dupnode(s->re_exp); if ((s->flags & STRCUR) != 0 - && (s->stfmt == -1 || s->stfmt == CONVFMTidx) + && (s->stfmt == STFMT_UNUSED || s->stfmt == CONVFMTidx) ) return s; return format_val(CONVFMT, CONVFMTidx, s); @@ -1820,6 +1841,51 @@ force_number(NODE *n) #endif /* GAWKDEBUG */ + +/* fixtype --- make a node decide if it's a number or a string */ + +/* + * In certain contexts, the true type of a scalar value matters, and we + * must ascertain whether it is a NUMBER or a STRING. In such situations, + * please use this function to resolve the type. + * + * It is safe to assume that the return value will be the same NODE, + * since force_number on a MAYBE_NUM should always return the same NODE, + * and force_string on an INTIND should as well. + * + * There is no way to handle a Node_typedregex correctly, so we ignore + * that case. + */ + +static inline NODE * +fixtype(NODE *n) +{ + assert(n->type == Node_val || n->type == Node_typedregex); + if (n->type == Node_val) { + if ((n->flags & MAYBE_NUM) != 0) + return force_number(n); + if ((n->flags & INTIND) != 0) + return force_string(n); + } + return n; +} + +/* boolval --- return true/false based on awk's criteria */ + +/* + * In awk, a value is considered to be true if it is nonzero _or_ + * non-null. Otherwise, the value is false. + */ + +static inline int +boolval(NODE *t) +{ + (void) fixtype(t); + if ((t->flags & NUMBER) != 0) + return ! iszero(t); + return (t->stlen > 0); +} + /* emalloc_real --- malloc with error checking */ static inline void * @@ -3822,7 +3822,7 @@ regular_print: && ((yyvsp[0])->nexti->memory->flags & (MPFN|MPZN)) == 0 ) { NODE *n = (yyvsp[0])->nexti->memory; - if ((n->flags & (STRCUR|STRING)) != 0) { + if ((n->flags & STRING) != 0) { n->numbr = (AWKNUM) (n->stlen == 0); n->flags &= ~(STRCUR|STRING); n->flags |= (NUMCUR|NUMBER); @@ -3924,7 +3924,7 @@ regular_print: #line 1791 "awkgram.y" /* yacc.c:1646 */ { if ((yyvsp[0])->lasti->opcode == Op_push_i - && ((yyvsp[0])->lasti->memory->flags & (STRCUR|STRING)) == 0 + && ((yyvsp[0])->lasti->memory->flags & STRING) == 0 ) { NODE *n = (yyvsp[0])->lasti->memory; (void) force_number(n); @@ -6422,7 +6422,7 @@ retry: } #endif if (base != 10) - d = nondec2awknum(tokstart, strlen(tokstart)); + d = nondec2awknum(tokstart, strlen(tokstart), NULL); else d = atof(tokstart); yylval->memory = make_number(d); @@ -6908,7 +6908,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r) } else if (do_intl /* --gen-po */ && r->builtin == do_dcgettext /* dcgettext(...) */ && subn->nexti->lasti->opcode == Op_push_i /* 1st arg is constant */ - && (subn->nexti->lasti->memory->flags & STRCUR) != 0) { /* it's a string constant */ + && (subn->nexti->lasti->memory->flags & STRING) != 0) { /* it's a string constant */ /* ala xgettext, dcgettext("some string" ...) dumps the string */ NODE *str = subn->nexti->lasti->memory; @@ -6920,9 +6920,9 @@ snode(INSTRUCTION *subn, INSTRUCTION *r) } else if (do_intl /* --gen-po */ && r->builtin == do_dcngettext /* dcngettext(...) */ && subn->nexti->lasti->opcode == Op_push_i /* 1st arg is constant */ - && (subn->nexti->lasti->memory->flags & STRCUR) != 0 /* it's a string constant */ + && (subn->nexti->lasti->memory->flags & STRING) != 0 /* it's a string constant */ && subn->nexti->lasti->nexti->lasti->opcode == Op_push_i /* 2nd arg is constant too */ - && (subn->nexti->lasti->nexti->lasti->memory->flags & STRCUR) != 0) { /* it's a string constant */ + && (subn->nexti->lasti->nexti->lasti->memory->flags & STRING) != 0) { /* it's a string constant */ /* ala xgettext, dcngettext("some string", "some plural" ...) dumps the string */ NODE *str1 = subn->nexti->lasti->memory; NODE *str2 = subn->nexti->lasti->nexti->lasti->memory; @@ -7031,18 +7031,6 @@ valinfo(NODE *n, Func_print print_func, FILE *fp) else #endif print_func(fp, "%.17g\n", n->numbr); - } else if ((n->flags & STRCUR) != 0) { - pp_string_fp(print_func, fp, n->stptr, n->stlen, '"', false); - print_func(fp, "\n"); - } else if ((n->flags & NUMCUR) != 0) { -#ifdef HAVE_MPFR - if (is_mpg_float(n)) - print_func(fp, "%s\n", mpg_fmt("%.17R*g", ROUND_MODE, n->mpg_numbr)); - else if (is_mpg_integer(n)) - print_func(fp, "%s\n", mpg_fmt("%Zd", n->mpg_i)); - else -#endif - print_func(fp, "%.17g\n", n->numbr); } else print_func(fp, "?? flags %s\n", flags2str(n->flags)); } @@ -1722,7 +1722,7 @@ non_post_simp_exp && ($2->nexti->memory->flags & (MPFN|MPZN)) == 0 ) { NODE *n = $2->nexti->memory; - if ((n->flags & (STRCUR|STRING)) != 0) { + if ((n->flags & STRING) != 0) { n->numbr = (AWKNUM) (n->stlen == 0); n->flags &= ~(STRCUR|STRING); n->flags |= (NUMCUR|NUMBER); @@ -1790,7 +1790,7 @@ non_post_simp_exp | '-' simp_exp %prec UNARY { if ($2->lasti->opcode == Op_push_i - && ($2->lasti->memory->flags & (STRCUR|STRING)) == 0 + && ($2->lasti->memory->flags & STRING) == 0 ) { NODE *n = $2->lasti->memory; (void) force_number(n); @@ -4002,7 +4002,7 @@ retry: } #endif if (base != 10) - d = nondec2awknum(tokstart, strlen(tokstart)); + d = nondec2awknum(tokstart, strlen(tokstart), NULL); else d = atof(tokstart); yylval->memory = make_number(d); @@ -4488,7 +4488,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r) } else if (do_intl /* --gen-po */ && r->builtin == do_dcgettext /* dcgettext(...) */ && subn->nexti->lasti->opcode == Op_push_i /* 1st arg is constant */ - && (subn->nexti->lasti->memory->flags & STRCUR) != 0) { /* it's a string constant */ + && (subn->nexti->lasti->memory->flags & STRING) != 0) { /* it's a string constant */ /* ala xgettext, dcgettext("some string" ...) dumps the string */ NODE *str = subn->nexti->lasti->memory; @@ -4500,9 +4500,9 @@ snode(INSTRUCTION *subn, INSTRUCTION *r) } else if (do_intl /* --gen-po */ && r->builtin == do_dcngettext /* dcngettext(...) */ && subn->nexti->lasti->opcode == Op_push_i /* 1st arg is constant */ - && (subn->nexti->lasti->memory->flags & STRCUR) != 0 /* it's a string constant */ + && (subn->nexti->lasti->memory->flags & STRING) != 0 /* it's a string constant */ && subn->nexti->lasti->nexti->lasti->opcode == Op_push_i /* 2nd arg is constant too */ - && (subn->nexti->lasti->nexti->lasti->memory->flags & STRCUR) != 0) { /* it's a string constant */ + && (subn->nexti->lasti->nexti->lasti->memory->flags & STRING) != 0) { /* it's a string constant */ /* ala xgettext, dcngettext("some string", "some plural" ...) dumps the string */ NODE *str1 = subn->nexti->lasti->memory; NODE *str2 = subn->nexti->lasti->nexti->lasti->memory; @@ -4611,18 +4611,6 @@ valinfo(NODE *n, Func_print print_func, FILE *fp) else #endif print_func(fp, "%.17g\n", n->numbr); - } else if ((n->flags & STRCUR) != 0) { - pp_string_fp(print_func, fp, n->stptr, n->stlen, '"', false); - print_func(fp, "\n"); - } else if ((n->flags & NUMCUR) != 0) { -#ifdef HAVE_MPFR - if (is_mpg_float(n)) - print_func(fp, "%s\n", mpg_fmt("%.17R*g", ROUND_MODE, n->mpg_numbr)); - else if (is_mpg_integer(n)) - print_func(fp, "%s\n", mpg_fmt("%Zd", n->mpg_i)); - else -#endif - print_func(fp, "%.17g\n", n->numbr); } else print_func(fp, "?? flags %s\n", flags2str(n->flags)); } @@ -148,7 +148,7 @@ do_exp(int nargs) double d, res; tmp = POP_SCALAR(); - if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) + if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0) lintwarn(_("exp: received non-numeric argument")); d = force_number(tmp)->numbr; DEREF(tmp); @@ -354,9 +354,9 @@ do_index(int nargs) POP_TWO_SCALARS(s1, s2); if (do_lint) { - if ((s1->flags & (STRING|STRCUR)) == 0) + if ((fixtype(s1)->flags & STRING) == 0) lintwarn(_("index: received non-string first argument")); - if ((s2->flags & (STRING|STRCUR)) == 0) + if ((fixtype(s2)->flags & STRING) == 0) lintwarn(_("index: received non-string second argument")); } @@ -469,7 +469,7 @@ do_int(int nargs) double d; tmp = POP_SCALAR(); - if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) + if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0) lintwarn(_("int: received non-numeric argument")); d = force_number(tmp)->numbr; d = double_to_int(d); @@ -532,9 +532,9 @@ do_length(int nargs) return make_number(size); } - assert(tmp->type == Node_val); + assert(tmp->type == Node_val || tmp->type == Node_typedregex); - if (do_lint && (tmp->flags & (STRING|STRCUR)) == 0) + if (do_lint && (fixtype(tmp)->flags & STRING) == 0) lintwarn(_("length: received non-string argument")); tmp = force_string(tmp); @@ -563,7 +563,7 @@ do_log(int nargs) double d, arg; tmp = POP_SCALAR(); - if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) + if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0) lintwarn(_("log: received non-numeric argument")); arg = force_number(tmp)->numbr; if (arg < 0.0) @@ -1049,8 +1049,7 @@ check_pos: need_format = false; parse_next_arg(); /* user input that looks numeric is numeric */ - if ((arg->flags & (MAYBE_NUM|NUMBER)) == MAYBE_NUM) - (void) force_number(arg); + fixtype(arg); if ((arg->flags & NUMBER) != 0) { uval = get_number_uj(arg); if (gawk_mb_cur_max > 1) { @@ -1727,7 +1726,7 @@ do_sqrt(int nargs) double arg; tmp = POP_SCALAR(); - if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) + if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0) lintwarn(_("sqrt: received non-numeric argument")); arg = (double) force_number(tmp)->numbr; DEREF(tmp); @@ -1917,7 +1916,7 @@ do_strftime(int nargs) unref(sub); if (val != NULL) { - if (do_lint && (val->flags & STRING) == 0) + if (do_lint && (fixtype(val)->flags & STRING) == 0) lintwarn(_("strftime: format value in PROCINFO[\"strftime\"] has numeric type")); val = force_string(val); format = val->stptr; @@ -1931,16 +1930,13 @@ do_strftime(int nargs) if (nargs == 3) { t3 = POP_SCALAR(); - if ((t3->flags & (NUMCUR|NUMBER)) != 0) - do_gmt = (t3->numbr != 0); - else - do_gmt = (t3->stlen > 0); + do_gmt = boolval(t3); DEREF(t3); } if (nargs >= 2) { t2 = POP_SCALAR(); - if (do_lint && (t2->flags & (NUMCUR|NUMBER)) == 0) + if (do_lint && (fixtype(t2)->flags & NUMBER) == 0) lintwarn(_("strftime: received non-numeric second argument")); (void) force_number(t2); clock_val = get_number_d(t2); @@ -1966,7 +1962,7 @@ do_strftime(int nargs) } tmp = POP_SCALAR(); - if (do_lint && (tmp->flags & (STRING|STRCUR)) == 0) + if (do_lint && (fixtype(tmp)->flags & STRING) == 0) lintwarn(_("strftime: received non-string first argument")); t1 = force_string(tmp); @@ -2042,7 +2038,7 @@ do_mktime(int nargs) char save; t1 = POP_SCALAR(); - if (do_lint && (t1->flags & (STRING|STRCUR)) == 0) + if (do_lint && (fixtype(t1)->flags & STRING) == 0) lintwarn(_("mktime: received non-string argument")); t1 = force_string(t1); @@ -2100,7 +2096,7 @@ do_system(int nargs) (void) flush_io(); /* so output is synchronous with gawk's */ tmp = POP_SCALAR(); - if (do_lint && (tmp->flags & (STRING|STRCUR)) == 0) + if (do_lint && (fixtype(tmp)->flags & STRING) == 0) lintwarn(_("system: received non-string argument")); cmd = force_string(tmp)->stptr; @@ -2206,13 +2202,10 @@ do_print(int nargs, int redirtype) } if (tmp->type == Node_typedregex) - args_array[i] = force_string(tmp); - else if ((tmp->flags & (NUMBER|STRING)) == NUMBER) { - if (OFMTidx == CONVFMTidx) - args_array[i] = force_string(tmp); - else - args_array[i] = format_val(OFMT, OFMTidx, tmp); - } + args_array[i] = force_string(tmp); + else if (!((tmp->flags & STRCUR) != 0 + && (tmp->stfmt == STFMT_UNUSED || tmp->stfmt == OFMTidx))) + args_array[i] = format_val(OFMT, OFMTidx, tmp); } if (redir_exp != NULL) { @@ -2370,7 +2363,7 @@ do_tolower(int nargs) NODE *t1, *t2; t1 = POP_SCALAR(); - if (do_lint && (t1->flags & (STRING|STRCUR)) == 0) + if (do_lint && (fixtype(t1)->flags & STRING) == 0) lintwarn(_("tolower: received non-string argument")); t1 = force_string(t1); t2 = make_string(t1->stptr, t1->stlen); @@ -2401,7 +2394,7 @@ do_toupper(int nargs) NODE *t1, *t2; t1 = POP_SCALAR(); - if (do_lint && (t1->flags & (STRING|STRCUR)) == 0) + if (do_lint && (fixtype(t1)->flags & STRING) == 0) lintwarn(_("toupper: received non-string argument")); t1 = force_string(t1); t2 = make_string(t1->stptr, t1->stlen); @@ -2434,9 +2427,9 @@ do_atan2(int nargs) POP_TWO_SCALARS(t1, t2); if (do_lint) { - if ((t1->flags & (NUMCUR|NUMBER)) == 0) + if ((fixtype(t1)->flags & NUMBER) == 0) lintwarn(_("atan2: received non-numeric first argument")); - if ((t2->flags & (NUMCUR|NUMBER)) == 0) + if ((fixtype(t2)->flags & NUMBER) == 0) lintwarn(_("atan2: received non-numeric second argument")); } d1 = force_number(t1)->numbr; @@ -2455,7 +2448,7 @@ do_sin(int nargs) double d; tmp = POP_SCALAR(); - if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) + if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0) lintwarn(_("sin: received non-numeric argument")); d = sin((double) force_number(tmp)->numbr); DEREF(tmp); @@ -2471,7 +2464,7 @@ do_cos(int nargs) double d; tmp = POP_SCALAR(); - if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) + if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0) lintwarn(_("cos: received non-numeric argument")); d = cos((double) force_number(tmp)->numbr); DEREF(tmp); @@ -2585,7 +2578,7 @@ do_srand(int nargs) srandom((unsigned int) (save_seed = (long) time((time_t *) 0))); else { tmp = POP_SCALAR(); - if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) + if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0) lintwarn(_("srand: received non-numeric argument")); srandom((unsigned int) (save_seed = (long) force_number(tmp)->numbr)); DEREF(tmp); @@ -2869,31 +2862,25 @@ do_sub(int nargs, unsigned int flags) target = POP_STRING(); /* original string */ glob_flag = POP_SCALAR(); /* value of global flag */ - if ((glob_flag->flags & (STRCUR|STRING)) != 0) { - if (glob_flag->stlen > 0 && (glob_flag->stptr[0] == 'g' || glob_flag->stptr[0] == 'G')) - how_many = -1; - else { - (void) force_number(glob_flag); - d = get_number_d(glob_flag); - if ((glob_flag->flags & NUMCUR) != 0) - goto set_how_many; - - warning(_("gensub: third argument `%.*s' treated as 1"), - (int) glob_flag->stlen, glob_flag->stptr); - how_many = 1; - } - } else { + if ( (glob_flag->flags & STRING) != 0 + && glob_flag->stlen > 0 + && (glob_flag->stptr[0] == 'g' || glob_flag->stptr[0] == 'G')) + how_many = -1; + else { (void) force_number(glob_flag); d = get_number_d(glob_flag); -set_how_many: if (d < 1) how_many = 1; else if (d < LONG_MAX) how_many = d; else how_many = LONG_MAX; - if (d <= 0) - warning(_("gensub: third argument %g treated as 1"), d); + if (d <= 0) { + (void) force_string(glob_flag); + warning(_("gensub: third argument `%.*s' treated as 1"), + (int) glob_flag->stlen, + glob_flag->stptr); + } } DEREF(glob_flag); } else { @@ -3357,9 +3344,9 @@ do_lshift(int nargs) POP_TWO_SCALARS(s1, s2); if (do_lint) { - if ((s1->flags & (NUMCUR|NUMBER)) == 0) + if ((fixtype(s1)->flags & NUMBER) == 0) lintwarn(_("lshift: received non-numeric first argument")); - if ((s2->flags & (NUMCUR|NUMBER)) == 0) + if ((fixtype(s2)->flags & NUMBER) == 0) lintwarn(_("lshift: received non-numeric second argument")); } val = force_number(s1)->numbr; @@ -3394,9 +3381,9 @@ do_rshift(int nargs) POP_TWO_SCALARS(s1, s2); if (do_lint) { - if ((s1->flags & (NUMCUR|NUMBER)) == 0) + if ((fixtype(s1)->flags & NUMBER) == 0) lintwarn(_("rshift: received non-numeric first argument")); - if ((s2->flags & (NUMCUR|NUMBER)) == 0) + if ((fixtype(s2)->flags & NUMBER) == 0) lintwarn(_("rshift: received non-numeric second argument")); } val = force_number(s1)->numbr; @@ -3436,7 +3423,7 @@ do_and(int nargs) for (i = 1; nargs > 0; nargs--, i++) { s1 = POP_SCALAR(); - if (do_lint && (s1->flags & (NUMCUR|NUMBER)) == 0) + if (do_lint && (fixtype(s1)->flags & NUMBER) == 0) lintwarn(_("and: argument %d is non-numeric"), i); val = force_number(s1)->numbr; @@ -3468,7 +3455,7 @@ do_or(int nargs) for (i = 1; nargs > 0; nargs--, i++) { s1 = POP_SCALAR(); - if (do_lint && (s1->flags & (NUMCUR|NUMBER)) == 0) + if (do_lint && (fixtype(s1)->flags & NUMBER) == 0) lintwarn(_("or: argument %d is non-numeric"), i); val = force_number(s1)->numbr; @@ -3500,7 +3487,7 @@ do_xor(int nargs) res = 0; /* silence compiler warning */ for (i = 1; nargs > 0; nargs--, i++) { s1 = POP_SCALAR(); - if (do_lint && (s1->flags & (NUMCUR|NUMBER)) == 0) + if (do_lint && (fixtype(s1)->flags & NUMBER) == 0) lintwarn(_("xor: argument %d is non-numeric"), i); val = force_number(s1)->numbr; @@ -3529,7 +3516,7 @@ do_compl(int nargs) uintmax_t uval; tmp = POP_SCALAR(); - if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) + if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0) lintwarn(_("compl: received non-numeric argument")); d = force_number(tmp)->numbr; DEREF(tmp); @@ -3554,11 +3541,11 @@ do_strtonum(int nargs) NODE *tmp; AWKNUM d; - tmp = POP_SCALAR(); - if ((tmp->flags & (NUMBER|NUMCUR)) != 0) - d = (AWKNUM) force_number(tmp)->numbr; + tmp = fixtype(POP_SCALAR()); + if ((tmp->flags & NUMBER) != 0) + d = (AWKNUM) tmp->numbr; else if (get_numbase(tmp->stptr, use_lc_numeric) != 10) - d = nondec2awknum(tmp->stptr, tmp->stlen); + d = nondec2awknum(tmp->stptr, tmp->stlen, NULL); else d = (AWKNUM) force_number(tmp)->numbr; @@ -3575,7 +3562,7 @@ do_strtonum(int nargs) */ AWKNUM -nondec2awknum(char *str, size_t len) +nondec2awknum(char *str, size_t len, char **endptr) { AWKNUM retval = 0.0; char save; @@ -3587,8 +3574,11 @@ nondec2awknum(char *str, size_t len) * User called strtonum("0x") or some such, * so just quit early. */ - if (len <= 2) + if (len <= 2) { + if (endptr) + *endptr = start; return (AWKNUM) 0.0; + } for (str += 2, len -= 2; len > 0; len--, str++) { switch (*str) { @@ -3621,14 +3611,21 @@ nondec2awknum(char *str, size_t len) val = *str - 'A' + 10; break; default: + if (endptr) + *endptr = str; goto done; } retval = (retval * 16) + val; } + if (endptr) + *endptr = str; } else if (*str == '0') { for (; len > 0; len--) { - if (! isdigit((unsigned char) *str)) + if (! isdigit((unsigned char) *str)) { + if (endptr) + *endptr = str; goto done; + } else if (*str == '8' || *str == '9') { str = start; goto decimal; @@ -3636,11 +3633,13 @@ nondec2awknum(char *str, size_t len) retval = (retval * 8) + (*str - '0'); str++; } + if (endptr) + *endptr = str; } else { decimal: save = str[len]; str[len] = '\0'; - retval = strtod(str, NULL); + retval = strtod(str, endptr); str[len] = save; } done: @@ -3902,9 +3901,9 @@ do_intdiv(int nargs) numerator = POP_SCALAR(); if (do_lint) { - if ((numerator->flags & (NUMCUR|NUMBER)) == 0) + if ((fixtype(numerator)->flags & NUMBER) == 0) lintwarn(_("intdiv: received non-numeric first argument")); - if ((denominator->flags & (NUMCUR|NUMBER)) == 0) + if ((fixtype(denominator)->flags & NUMBER) == 0) lintwarn(_("intdiv: received non-numeric second argument")); } @@ -3963,14 +3962,26 @@ do_typeof(int nargs) break; case Node_val: case Node_var: - if (arg == Nnull_string) - res = "unassigned"; - else if ((arg->flags & STRING) != 0) { + switch (arg->flags & (STRING|NUMBER|MAYBE_NUM)) { + case STRING: res = "string"; - if ((arg->flags & MAYBE_NUM) != 0) - res = "strnum"; - } else if ((arg->flags & NUMBER) != 0) + break; + case NUMBER: res = "number"; + break; + case STRING|MAYBE_NUM: + res = "strnum"; + break; + case NUMBER|STRING: + if (arg == Nnull_string) { + res = "unassigned"; + break; + } + /* fall through */ + default: + warning(_("typeof detected invalid flags combination `%s'; please file a bug report."), flags2str(arg->flags)); + break; + } break; case Node_var_new: res = "untyped"; @@ -3704,17 +3704,6 @@ print_memory(NODE *m, NODE *func, Func_print print_func, FILE *fp) print_func(fp, "%g", m->numbr); } else if ((m->flags & STRING) != 0) pp_string_fp(print_func, fp, m->stptr, m->stlen, '"', false); - else if ((m->flags & NUMCUR) != 0) { -#ifdef HAVE_MPFR - if ((m->flags & MPFN) != 0) - print_func(fp, "%s", mpg_fmt("%R*g", ROUND_MODE, m->mpg_numbr)); - else if ((m->flags & MPZN) != 0) - print_func(fp, "%s", mpg_fmt("%Zd", m->mpg_i)); - else -#endif - print_func(fp, "%g", m->numbr); - } else if ((m->flags & STRCUR) != 0) - pp_string_fp(print_func, fp, m->stptr, m->stlen, '"', false); else print_func(fp, "-?-"); print_func(fp, " [%s]", flags2str(m->flags)); @@ -582,14 +582,8 @@ cmp_nodes(NODE *t1, NODE *t2) if (t1 == t2) return 0; - if ((t1->flags & MAYBE_NUM) != 0) - (void) force_number(t1); - if ((t2->flags & MAYBE_NUM) != 0) - (void) force_number(t2); - if ((t1->flags & INTIND) != 0) - t1 = force_string(t1); - if ((t2->flags & INTIND) != 0) - t2 = force_string(t2); + (void) fixtype(t1); + (void) fixtype(t2); if ((t1->flags & NUMBER) != 0 && (t2->flags & NUMBER) != 0) return cmp_numbers(t1, t2); @@ -698,7 +692,6 @@ void set_IGNORECASE() { static bool warned = false; - NODE *n = IGNORECASE_node->var_value; if ((do_lint || do_traditional) && ! warned) { warned = true; @@ -707,19 +700,8 @@ set_IGNORECASE() load_casetable(); if (do_traditional) IGNORECASE = false; - else if ((n->flags & (NUMCUR|NUMBER)) != 0) - IGNORECASE = ! iszero(n); - else if ((n->flags & (STRING|STRCUR)) != 0) { - if ((n->flags & MAYBE_NUM) == 0) { - (void) force_string(n); - IGNORECASE = (n->stlen > 0); - } else { - (void) force_number(n); - IGNORECASE = ! iszero(n); - } - } else - IGNORECASE = false; /* shouldn't happen */ - + else + IGNORECASE = boolval(IGNORECASE_node->var_value); set_RS(); /* set_RS() calls set_FS() if need be, for us */ } @@ -730,7 +712,7 @@ set_BINMODE() { static bool warned = false; char *p; - NODE *v = BINMODE_node->var_value; + NODE *v = fixtype(BINMODE_node->var_value); if ((do_lint || do_traditional) && ! warned) { warned = true; @@ -739,7 +721,6 @@ set_BINMODE() if (do_traditional) BINMODE = TEXT_TRANSLATE; else if ((v->flags & NUMBER) != 0) { - (void) force_number(v); BINMODE = get_number_si(v); /* Make sure the value is rational. */ if (BINMODE < TEXT_TRANSLATE) @@ -947,49 +928,30 @@ set_LINT() { #ifndef NO_LINT int old_lint = do_lint; - NODE *n = LINT_node->var_value; - - if ((n->flags & (STRING|STRCUR)) != 0) { - if ((n->flags & MAYBE_NUM) == 0) { - const char *lintval; - size_t lintlen; - - n = force_string(LINT_node->var_value); - lintval = n->stptr; - lintlen = n->stlen; - if (lintlen > 0) { - do_flags |= DO_LINT_ALL; - if (lintlen == 5 && strncmp(lintval, "fatal", 5) == 0) - lintfunc = r_fatal; - else if (lintlen == 7 && strncmp(lintval, "invalid", 7) == 0) { - do_flags &= ~ DO_LINT_ALL; - do_flags |= DO_LINT_INVALID; - } else - lintfunc = warning; - } else { - do_flags &= ~(DO_LINT_ALL|DO_LINT_INVALID); - lintfunc = warning; + NODE *n = fixtype(LINT_node->var_value); + + lintfunc = r_warning; /* reset to default */ + if ((n->flags & STRING) != 0) { + const char *lintval; + size_t lintlen; + + lintval = n->stptr; + lintlen = n->stlen; + if (lintlen > 0) { + do_flags |= DO_LINT_ALL; + if (lintlen == 5 && strncmp(lintval, "fatal", 5) == 0) + lintfunc = r_fatal; + else if (lintlen == 7 && strncmp(lintval, "invalid", 7) == 0) { + do_flags &= ~DO_LINT_ALL; + do_flags |= DO_LINT_INVALID; } } else { - (void) force_number(n); - if (! iszero(n)) - do_flags |= DO_LINT_ALL; - else - do_flags &= ~(DO_LINT_ALL|DO_LINT_INVALID); - lintfunc = warning; - } - } else if ((n->flags & (NUMCUR|NUMBER)) != 0) { - (void) force_number(n); - if (! iszero(n)) - do_flags |= DO_LINT_ALL; - else do_flags &= ~(DO_LINT_ALL|DO_LINT_INVALID); - lintfunc = warning; - } else - do_flags &= ~(DO_LINT_ALL|DO_LINT_INVALID); /* shouldn't happen */ - - if (! do_lint) - lintfunc = warning; + } + } else if (! iszero(n)) + do_flags |= DO_LINT_ALL; + else + do_flags &= ~(DO_LINT_ALL|DO_LINT_INVALID); /* explicitly use warning() here, in case lintfunc == r_fatal */ if (old_lint != do_lint && old_lint && ! do_lint) @@ -1192,7 +1154,7 @@ r_get_field(NODE *n, Func_ptr *assign, bool reference) if (assign) *assign = NULL; if (do_lint) { - if ((n->flags & NUMBER) == 0) { + if ((fixtype(n)->flags & NUMBER) == 0) { lintwarn(_("attempt to field reference from non-numeric value")); if (n->stlen == 0) lintwarn(_("attempt to field reference from null string")); @@ -1546,15 +1508,7 @@ eval_condition(NODE *t) if (t == node_Boolean[true]) return true; - if ((t->flags & MAYBE_NUM) != 0) - force_number(t); - else if ((t->flags & INTIND) != 0) - force_string(t); - - if ((t->flags & NUMBER) != 0) - return ! iszero(t); - - return (t->stlen != 0); + return boolval(t); } /* cmp_scalars -- compare two nodes on the stack */ @@ -288,7 +288,7 @@ set_record(const char *buf, int cnt) n->stlen = cnt; n->valref = 1; n->type = Node_val; - n->stfmt = -1; + n->stfmt = STFMT_UNUSED; n->flags = (STRING|STRCUR|MAYBE_NUM|FIELD); fields_arr[0] = n; @@ -430,24 +430,21 @@ node_to_awk_value(NODE *node, awk_value_t *val, awk_valtype_t wanted) val->val_type = AWK_NUMBER; (void) force_number(node); - if ((node->flags & NUMCUR) != 0) { - val->num_value = get_number_d(node); - ret = awk_true; - } + val->num_value = get_number_d(node); + ret = awk_true; break; case AWK_STRING: val->val_type = AWK_STRING; (void) force_string(node); - if ((node->flags & STRCUR) != 0) { - val->str_value.str = node->stptr; - val->str_value.len = node->stlen; - ret = awk_true; - } + val->str_value.str = node->stptr; + val->str_value.len = node->stlen; + ret = awk_true; break; case AWK_SCALAR: + fixtype(node); if ((node->flags & NUMBER) != 0) { val->val_type = AWK_NUMBER; } else if ((node->flags & STRING) != 0) { @@ -459,6 +456,7 @@ node_to_awk_value(NODE *node, awk_value_t *val, awk_valtype_t wanted) case AWK_UNDEFINED: /* return true and actual type for request of undefined */ + fixtype(node); if (node == Nnull_string) { val->val_type = AWK_UNDEFINED; ret = awk_true; @@ -687,7 +685,7 @@ api_sym_update_scalar(awk_ext_id_t id, /* make_str_node(s, l, ALREADY_MALLOCED): */ r->numbr = 0; r->flags = (MALLOC|STRING|STRCUR); - r->stfmt = -1; + r->stfmt = STFMT_UNUSED; r->stptr = value->str_value.str; r->stlen = value->str_value.len; return awk_true; @@ -278,6 +278,12 @@ enum { * The API deals exclusively with regular chars; these strings may * be multibyte encoded in the current locale's encoding and character * set. Gawk will convert internally to wide characters if necessary. + * + * Note that the string may not be terminated with a '\0' character. + * In particular, this happens for field values $n where n > 0 and n < NF, + * since the string points directly into the $0 buffer. All other strings, + * including those created by extensions, should be NUL-terminated. In general + * though, extension code should not assume that the string is NUL-terminated! */ typedef struct awk_string { char *str; /* data */ diff --git a/int_array.c b/int_array.c index a8de3d55..e7913dea 100644 --- a/int_array.c +++ b/int_array.c @@ -89,6 +89,25 @@ is_integer(NODE *symbol, NODE *subs) if (subs == Nnull_string || do_mpfr) return NULL; + /* + * Protect against MAYBE_NUM values where the string may not regenerate + * correctly. There could be white space and/or a non-decimal value. + * If stfmt is not STFMT_UNUSED, it means that the string value was + * generated using CONVFMT or OFMT, so there is no info there. + */ + if ((subs->flags & STRCUR) != 0 && subs->stfmt == STFMT_UNUSED) { + char *cp = subs->stptr; + + if ( subs->stlen == 0 + || cp[0] == '0' + || isspace((unsigned char) cp[0]) + || isspace((unsigned char) cp[subs->stlen - 1]) + || ( subs->stlen >= 2 + && (cp[0] == '-' || cp[0] == '+') + && cp[1] == '0')) + return NULL; + } + if ((subs->flags & NUMINT) != 0) return & success_node; @@ -107,49 +126,51 @@ is_integer(NODE *symbol, NODE *subs) * a[-3]=1; print "-3" in a -- true */ - if ((subs->flags & (STRING|STRCUR)) != 0) { - char *cp = subs->stptr, *cpend, *ptr; - char save; - size_t len = subs->stlen; - - if (len == 0 || (! isdigit((unsigned char) *cp) && *cp != '-')) - return NULL; - if (len > 1 && - ((*cp == '0') /* "00", "011" .. */ - || (*cp == '-' && *(cp + 1) == '0') /* "-0", "-011" .. */ - ) - ) - return NULL; - if (len == 1 && *cp != '-') { /* single digit */ - subs->numbr = (long) (*cp - '0'); - if ((subs->flags & MAYBE_NUM) != 0) { - subs->flags &= ~MAYBE_NUM; - subs->flags |= NUMBER; - } - subs->flags |= (NUMCUR|NUMINT); - return & success_node; - } + /* must be a STRING */ + char *cp = subs->stptr, *cpend, *ptr; + char save; + size_t len = subs->stlen; - cpend = cp + len; - save = *cpend; - *cpend = '\0'; + if (len == 0 || (! isdigit((unsigned char) *cp) && *cp != '-')) + return NULL; - errno = 0; - l = strtol(cp, & ptr, 10); - *cpend = save; - if (errno != 0 || ptr != cpend) - return NULL; - subs->numbr = l; + if (len > 1 && + ((*cp == '0') /* "00", "011" .. */ + || (*cp == '-' && *(cp + 1) == '0') /* "-0", "-011" .. */ + ) + ) + return NULL; + if (len == 1 && *cp != '-') { /* single digit */ + subs->numbr = (long) (*cp - '0'); if ((subs->flags & MAYBE_NUM) != 0) { - subs->flags &= ~MAYBE_NUM; + subs->flags &= ~(MAYBE_NUM|STRING); subs->flags |= NUMBER; } - subs->flags |= NUMCUR; - if (l <= INT32_MAX && l >= INT32_MIN) { - subs->flags |= NUMINT; - return & success_node; - } + subs->flags |= (NUMCUR|NUMINT); + return & success_node; + } + + cpend = cp + len; + save = *cpend; + *cpend = '\0'; + + errno = 0; + l = strtol(cp, & ptr, 10); + *cpend = save; + if (errno != 0 || ptr != cpend) + return NULL; + + subs->numbr = l; + if ((subs->flags & MAYBE_NUM) != 0) { + subs->flags &= ~(MAYBE_NUM|STRING); + subs->flags |= NUMBER; } + subs->flags |= NUMCUR; + if (l <= INT32_MAX && l >= INT32_MIN) { + subs->flags |= NUMINT; + return & success_node; + } + return NULL; } @@ -785,7 +785,7 @@ redirect_string(const char *str, size_t explen, bool not_string, cant_happen(); } if (do_lint && not_string) - lintwarn(_("expression in `%s' redirection only has numeric value"), + lintwarn(_("expression in `%s' redirection is a number"), what); if (str == NULL || *str == '\0') @@ -1083,7 +1083,7 @@ redirect_string(const char *str, size_t explen, bool not_string, struct redirect * redirect(NODE *redir_exp, int redirtype, int *errflg, bool failure_fatal) { - bool not_string = ((redir_exp->flags & STRCUR) == 0); + bool not_string = ((fixtype(redir_exp)->flags & STRING) == 0); redir_exp = force_string(redir_exp); return redirect_string(redir_exp->stptr, redir_exp->stlen, not_string, @@ -3895,14 +3895,8 @@ pty_vs_pipe(const char *command) * in_PROCINFO function now checks that for us. */ val = in_PROCINFO(command, "pty", NULL); - if (val) { - if ((val->flags & MAYBE_NUM) != 0) - (void) force_number(val); - if ((val->flags & NUMBER) != 0) - return ! iszero(val); - else - return (val->stlen != 0); - } + if (val) + return boolval(val); #endif /* HAVE_TERMIOS_H */ return false; } @@ -327,7 +327,7 @@ force_mpnum(NODE *n, int do_nondec, int use_locale) IEEE_FMT(n->mpg_numbr, tval); done: /* trailing space is OK for NUMBER */ - while (isspace((unsigned char) *ptr)) + while (ptr < cpend && isspace((unsigned char) *ptr)) ptr++; *cpend = save; if (errno == 0 && ptr == cpend) @@ -341,20 +341,17 @@ done: static NODE * mpg_force_number(NODE *n) { - unsigned int newflags = 0; - - if (is_mpg_number(n) && (n->flags & NUMCUR) != 0) + if ((n->flags & NUMCUR) != 0) return n; - - if ((n->flags & MAYBE_NUM) != 0) { - n->flags &= ~MAYBE_NUM; - newflags = NUMBER; - } + n->flags |= NUMCUR; if (force_mpnum(n, (do_non_decimal_data && ! do_traditional), true)) { - n->flags |= newflags; - n->flags |= NUMCUR; - } + if ((n->flags & MAYBE_NUM) != 0) { + n->flags &= ~(MAYBE_NUM|STRING); + n->flags |= NUMBER; + } + } else + n->flags &= ~MAYBE_NUM; return n; } @@ -373,7 +370,7 @@ mpg_format_val(const char *format, int index, NODE *s) if (is_mpg_integer(s) || mpfr_integer_p(s->mpg_numbr)) { /* integral value, use %d */ r = format_tree("%d", 2, dummy, 2); - s->stfmt = -1; + s->stfmt = STFMT_UNUSED; } else { r = format_tree(format, fmt_list[index]->stlen, dummy, 2); assert(r != NULL); @@ -521,11 +518,9 @@ set_PREC() if (! do_mpfr) return; - val = PREC_node->var_value; - if ((val->flags & MAYBE_NUM) != 0) - force_number(val); + val = fixtype(PREC_node->var_value); - if ((val->flags & STRCUR) != 0) { + if ((val->flags & STRING) != 0) { int i, j; /* emulate IEEE-754 binary format */ @@ -675,9 +670,9 @@ do_mpfr_atan2(int nargs) t1 = POP_SCALAR(); if (do_lint) { - if ((t1->flags & (NUMCUR|NUMBER)) == 0) + if ((fixtype(t1)->flags & NUMBER) == 0) lintwarn(_("atan2: received non-numeric first argument")); - if ((t2->flags & (NUMCUR|NUMBER)) == 0) + if ((fixtype(t2)->flags & NUMBER) == 0) lintwarn(_("atan2: received non-numeric second argument")); } force_number(t1); @@ -707,7 +702,7 @@ do_mpfr_func(const char *name, int tval; t1 = POP_SCALAR(); - if (do_lint && (t1->flags & (NUMCUR|NUMBER)) == 0) + if (do_lint && (fixtype(t1)->flags & NUMBER) == 0) lintwarn(_("%s: received non-numeric argument"), name); force_number(t1); @@ -773,7 +768,7 @@ do_mpfr_int(int nargs) NODE *tmp, *r; tmp = POP_SCALAR(); - if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) + if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0) lintwarn(_("int: received non-numeric argument")); force_number(tmp); @@ -803,7 +798,7 @@ do_mpfr_compl(int nargs) mpz_ptr zptr; tmp = POP_SCALAR(); - if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) + if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0) lintwarn(_("compl: received non-numeric argument")); force_number(tmp); @@ -851,7 +846,7 @@ get_intval(NODE *t1, int argnum, const char *op) { mpz_ptr pz; - if (do_lint && (t1->flags & (NUMCUR|NUMBER)) == 0) + if (do_lint && (fixtype(t1)->flags & NUMBER) == 0) lintwarn(_("%s: received non-numeric argument #%d"), op, argnum); (void) force_number(t1); @@ -1076,25 +1071,22 @@ do_mpfr_strtonum(int nargs) { NODE *tmp, *r; - tmp = POP_SCALAR(); - if ((tmp->flags & (NUMBER|NUMCUR)) == 0) { + tmp = fixtype(POP_SCALAR()); + if ((tmp->flags & NUMBER) == 0) { r = mpg_integer(); /* will be changed to MPFR float if necessary in force_mpnum() */ r->stptr = tmp->stptr; r->stlen = tmp->stlen; force_mpnum(r, true, use_lc_numeric); r->stptr = NULL; r->stlen = 0; + } else if (is_mpg_float(tmp)) { + int tval; + r = mpg_float(); + tval = mpfr_set(r->mpg_numbr, tmp->mpg_numbr, ROUND_MODE); + IEEE_FMT(r->mpg_numbr, tval); } else { - (void) force_number(tmp); - if (is_mpg_float(tmp)) { - int tval; - r = mpg_float(); - tval = mpfr_set(r->mpg_numbr, tmp->mpg_numbr, ROUND_MODE); - IEEE_FMT(r->mpg_numbr, tval); - } else { - r = mpg_integer(); - mpz_set(r->mpg_i, tmp->mpg_i); - } + r = mpg_integer(); + mpz_set(r->mpg_i, tmp->mpg_i); } DEREF(tmp); @@ -1172,7 +1164,7 @@ do_mpfr_srand(int nargs) else { NODE *tmp; tmp = POP_SCALAR(); - if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) + if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0) lintwarn(_("srand: received non-numeric argument")); force_number(tmp); if (is_mpg_float(tmp)) @@ -1213,9 +1205,9 @@ do_mpfr_intdiv(int nargs) numerator = POP_SCALAR(); if (do_lint) { - if ((numerator->flags & (NUMCUR|NUMBER)) == 0) + if ((fixtype(numerator)->flags & NUMBER) == 0) lintwarn(_("intdiv: received non-numeric first argument")); - if ((denominator->flags & (NUMCUR|NUMBER)) == 0) + if ((fixtype(denominator)->flags & NUMBER) == 0) lintwarn(_("intdiv: received non-numeric second argument")); } @@ -30,7 +30,7 @@ static int is_ieee_magic_val(const char *val); static NODE *r_make_number(double x); -static AWKNUM get_ieee_magic_val(const char *val); +static AWKNUM get_ieee_magic_val(char *val); extern NODE **fmt_list; /* declared in eval.c */ NODE *(*make_number)(double) = r_make_number; @@ -61,23 +61,35 @@ r_force_number(NODE *n) char *cpend; char save; char *ptr; - unsigned int newflags; extern double strtod(); if ((n->flags & NUMCUR) != 0) return n; - /* all the conditionals are an attempt to avoid the expensive strtod */ + /* + * We should always set NUMCUR and clear MAYBE_NUM, and we may possibly + * change STRING to NUMBER if MAYBE_NUM was set and it's a good numeric + * string. + */ - /* Note: only set NUMCUR if we actually convert some digits */ + /* All the conditionals are an attempt to avoid the expensive strtod */ + n->flags |= NUMCUR; n->numbr = 0.0; - if (n->stlen == 0) { - return n; - } + /* Trim leading white space, bailing out if there's nothing else */ + for (cp = n->stptr, cpend = cp + n->stlen; + cp < cpend && isspace((unsigned char) *cp); cp++) + continue; + + if (cp == cpend) + goto badnum; + + /* At this point, we know the string is not entirely white space */ + /* Trim trailing white space */ + while (isspace((unsigned char) cpend[-1])) + cpend--; - cp = n->stptr; /* * 2/2007: * POSIX, by way of severe language lawyering, seems to @@ -86,80 +98,52 @@ r_force_number(NODE *n) * This also allows hexadecimal floating point. Ugh. */ if (! do_posix) { - if (is_alpha((unsigned char) *cp)) { - return n; - } else if (n->stlen == 4 && is_ieee_magic_val(n->stptr)) { - if ((n->flags & MAYBE_NUM) != 0) - n->flags &= ~MAYBE_NUM; - n->flags |= NUMBER|NUMCUR; - n->flags &= ~STRING; - n->numbr = get_ieee_magic_val(n->stptr); - - return n; + if (is_alpha((unsigned char) *cp)) + goto badnum; + else if (cpend == cp+4 && is_ieee_magic_val(cp)) { + n->numbr = get_ieee_magic_val(cp); + goto goodnum; } /* else fall through */ } - /* else not POSIX, so + /* else POSIX, so fall through */ - cpend = cp + n->stlen; - while (cp < cpend && isspace((unsigned char) *cp)) - cp++; - - if ( cp == cpend /* only spaces, or */ - || (! do_posix /* not POSIXLY paranoid and */ + if ( (! do_posix /* not POSIXLY paranoid and */ && (is_alpha((unsigned char) *cp) /* letter, or */ /* CANNOT do non-decimal and saw 0x */ || (! do_non_decimal_data && is_hex(cp))))) { - return n; + goto badnum; } - if ((n->flags & MAYBE_NUM) != 0) { - newflags = NUMBER; - n->flags &= ~MAYBE_NUM; - } else - newflags = 0; - if (cpend - cp == 1) { /* only one character */ if (isdigit((unsigned char) *cp)) { /* it's a digit! */ n->numbr = (AWKNUM)(*cp - '0'); - n->flags |= newflags; - n->flags |= NUMCUR; - n->flags &= ~STRING; - if (cp == n->stptr) /* no leading spaces */ + if (n->stlen == 1) /* no white space */ n->flags |= NUMINT; + goto goodnum; } - return n; + goto badnum; } - if (do_non_decimal_data) { /* main.c assures false if do_posix */ - errno = 0; - if (! do_traditional && get_numbase(cp, true) != 10) { - n->numbr = nondec2awknum(cp, cpend - cp); - n->flags |= NUMCUR; - n->flags &= ~STRING; - ptr = cpend; - goto finish; - } + errno = 0; + if (do_non_decimal_data /* main.c assures false if do_posix */ + && ! do_traditional && get_numbase(cp, true) != 10) { + /* nondec2awknum() saves and restores the byte after the string itself */ + n->numbr = nondec2awknum(cp, cpend - cp, &ptr); + } else { + save = *cpend; + *cpend = '\0'; + n->numbr = (AWKNUM) strtod((const char *) cp, &ptr); + *cpend = save; } - errno = 0; - save = *cpend; - *cpend = '\0'; - n->numbr = (AWKNUM) strtod((const char *) cp, &ptr); - - /* POSIX says trailing space is OK for NUMBER */ - while (isspace((unsigned char) *ptr)) - ptr++; - *cpend = save; -finish: if (errno == 0) { - if (ptr == cpend) { - n->flags |= newflags; - n->flags |= NUMCUR; - } + if (ptr == cpend) + goto goodnum; /* else keep the leading numeric value without updating flags */ + /* fall through to badnum */ } else { errno = 0; /* @@ -168,8 +152,21 @@ finish: * We force the numeric value to 0 in such cases. */ n->numbr = 0; + /* + * Or should we accept it as a NUMBER even though strtod + * threw an error? + */ + /* fall through to badnum */ } +badnum: + n->flags &= ~MAYBE_NUM; + return n; +goodnum: + if ((n->flags & MAYBE_NUM) != 0) { + n->flags &= ~(MAYBE_NUM|STRING); + n->flags |= NUMBER; + } return n; } @@ -227,7 +224,7 @@ r_format_val(const char *format, int index, NODE *s) * Once upon a time, we just blindly did this: * sprintf(sp, format, s->numbr); * s->stlen = strlen(sp); - * s->stfmt = (char) index; + * s->stfmt = index; * but that's no good if, e.g., OFMT is %s. So we punt, * and just always format the value ourselves. */ @@ -242,7 +239,7 @@ r_format_val(const char *format, int index, NODE *s) if (val == s->numbr) { /* integral value, but outside range of %ld, use %.0f */ r = format_tree("%.0f", 4, dummy, 2); - s->stfmt = -1; + s->stfmt = STFMT_UNUSED; } else { r = format_tree(format, fmt_list[index]->stlen, dummy, 2); assert(r != NULL); @@ -269,13 +266,13 @@ r_format_val(const char *format, int index, NODE *s) (void) sprintf(sp, "%ld", num); s->stlen = strlen(sp); } - s->stfmt = -1; + s->stfmt = STFMT_UNUSED; if ((s->flags & INTIND) != 0) { s->flags &= ~(INTIND|NUMBER); s->flags |= STRING; } } - if (s->stptr != NULL) + if ((s->flags & STRCUR) != 0) efree(s->stptr); emalloc(s->stptr, char *, s->stlen + 1, "format_val"); memcpy(s->stptr, sp, s->stlen + 1); @@ -386,7 +383,7 @@ make_str_node(const char *s, size_t len, int flags) r->numbr = 0; r->flags = (MALLOC|STRING|STRCUR); r->valref = 1; - r->stfmt = -1; + r->stfmt = STFMT_UNUSED; r->wstptr = NULL; r->wstlen = 0; @@ -940,14 +937,18 @@ is_ieee_magic_val(const char *val) /* get_ieee_magic_val --- return magic value for string */ static AWKNUM -get_ieee_magic_val(const char *val) +get_ieee_magic_val(char *val) { static bool first = true; static AWKNUM inf; static AWKNUM nan; + char save; char *ptr; + save = val[4]; + val[4] = '\0'; AWKNUM v = strtod(val, &ptr); + val[4] = save; if (val == ptr) { /* Older strtod implementations don't support inf or nan. */ if (first) { diff --git a/str_array.c b/str_array.c index d9b5d2a4..f66b22cc 100644 --- a/str_array.c +++ b/str_array.c @@ -168,7 +168,7 @@ str_lookup(NODE *symbol, NODE *subs) * flag on it since other variables could be using the same * reference-counted value. */ - if (subs->stfmt != -1 || (subs->flags & MAYBE_NUM) != 0) { + if (subs->stfmt != STFMT_UNUSED || (subs->flags & MAYBE_NUM) != 0) { NODE *tmp; /* @@ -652,7 +652,7 @@ check_param_names(void) memset(& n, 0, sizeof n); n.type = Node_val; n.flags = STRING|STRCUR; - n.stfmt = -1; + n.stfmt = STFMT_UNUSED; /* * assoc_list() returns an array with two elements per awk array diff --git a/test/ChangeLog b/test/ChangeLog index 74eaae4a..d495e573 100644 --- a/test/ChangeLog +++ b/test/ChangeLog @@ -4,6 +4,21 @@ avoid buffer flushing on obscure systems. * dumpvars.ok, symtab6.ok, symtab8.ok: Update after code changes. +2016-06-26 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * strnum2.ok: Fix results, since print for a strnum should not be + affected by OFMT or CONVFMT. + +2016-06-22 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * strnum2.awk, strnum2.ok: Improve test case to show both OFMT and + CONVFMT conversions. + +2016-06-20 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * Makefile.am (strnum2): New test. + * strnum2.awk, strnum2.ok: New files. + 2016-06-14 Arnold D. Robbins <arnold@skeeve.com> * Makefile.am (subback): New test. @@ -21,6 +36,18 @@ * mixed1.ok: Adjust to match what the code produces. Thanks to John E. Malmberg <wb8tyw@qsl.net> for the report. +2016-06-13 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * Makefile.am (forcenum, ignrcas3, intarray, lintexp, lintindex, + lintint, lintlength, lintset, mpfrstrtonum, mpgforcenum, printfchar, + strtonum1): New tests. + * forcenum.awk, forcenum.ok, ignrcas3.awk, ignrcas3.ok, intarray.awk, + intarray.ok, lintexp.awk, lintexp.ok, lintindex.awk, lintindex.ok, + lintint.awk, lintint.ok, lintlength.awk, lintlength.ok, lintset.awk, + lintset.ok, mpfrstrtonum.awk, mpfrstrtonum.ok, mpgforcenum.awk, + mpgforcenum.ok, printfchar.awk, printfchar.ok, strtonum1.awk, + strtonum1.ok: New files. + 2016-06-08 Arnold D. Robbins <arnold@skeeve.com> * symtab10.awk, symtab10.in, symtab10.ok: New files. diff --git a/test/Makefile.am b/test/Makefile.am index 7ec75508..499107c5 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -300,6 +300,8 @@ EXTRA_DIST = \ fnparydl-mpfr.ok \ fnparydl.awk \ fnparydl.ok \ + forcenum.awk \ + forcenum.ok \ fordel.awk \ fordel.ok \ fork.awk \ @@ -463,6 +465,8 @@ EXTRA_DIST = \ igncfs.ok \ ignrcas2.awk \ ignrcas2.ok \ + ignrcas3.awk \ + ignrcas3.ok \ ignrcase.awk \ ignrcase.in \ ignrcase.ok \ @@ -505,6 +509,8 @@ EXTRA_DIST = \ inplace3.2.bak.ok \ inputred.awk \ inputred.ok \ + intarray.awk \ + intarray.ok \ intest.awk \ intest.ok \ intformat.awk \ @@ -526,9 +532,19 @@ EXTRA_DIST = \ leadnl.ok \ lint.awk \ lint.ok \ + lintexp.awk \ + lintexp.ok \ + lintindex.awk \ + lintindex.ok \ + lintint.awk \ + lintint.ok \ + lintlength.awk \ + lintlength.ok \ lintold.awk \ lintold.in \ lintold.ok \ + lintset.awk \ + lintset.ok \ lintwarn.awk \ lintwarn.ok \ litoct.awk \ @@ -608,6 +624,10 @@ EXTRA_DIST = \ mpfrsort.ok \ mpfrsqrt.awk \ mpfrsqrt.ok \ + mpfrstrtonum.awk \ + mpfrstrtonum.ok \ + mpgforcenum.awk \ + mpgforcenum.ok \ mtchi18n.awk \ mtchi18n.in \ mtchi18n.ok \ @@ -772,6 +792,8 @@ EXTRA_DIST = \ printfbad3.ok \ printfbad4.awk \ printfbad4.ok \ + printfchar.awk \ + printfchar.ok \ printfloat.awk \ printhuge.awk \ printhuge.ok \ @@ -977,11 +999,15 @@ EXTRA_DIST = \ strftlng.ok \ strnum1.awk \ strnum1.ok \ + strnum2.awk \ + strnum2.ok \ strtod.awk \ strtod.in \ strtod.ok \ strtonum.awk \ strtonum.ok \ + strtonum1.awk \ + strtonum1.ok \ subamp.awk \ subamp.in \ subamp.ok \ @@ -1133,7 +1159,7 @@ BASIC_TESTS = \ octsub ofmt ofmta ofmtbig ofmtfidl ofmts ofs1 onlynl opasnidx opasnslf \ paramasfunc1 paramasfunc2 \ paramdup paramres paramtyp paramuninitglobal parse1 parsefld parseme \ - pcntplus posix2008sub prdupval prec printf0 printf1 prmarscl prmreuse \ + pcntplus posix2008sub prdupval prec printf0 printf1 printfchar prmarscl prmreuse \ prt1eval prtoeval \ rand randtest range1 readbuf rebrackloc rebt8b1 redfilnm \ regeq regexpbrack regexpbrack2 \ @@ -1141,7 +1167,7 @@ BASIC_TESTS = \ reparse resplit rri1 rs rscompat rsnul1nl rsnulbig rsnulbig2 rstest1 rstest2 \ rstest3 rstest4 rstest5 rswhite \ scalar sclforin sclifin sigpipe1 sortempty sortglos splitargv splitarr splitdef \ - splitvar splitwht strcat1 strnum1 strtod subamp subback subi18n \ + splitvar splitwht strcat1 strnum1 strnum2 strtod subamp subback subi18n \ subsepnm subslash substr swaplns synerr1 synerr2 tradanch tweakfld \ uninit2 uninit3 uninit4 uninit5 uninitialized unterm uparrfs \ wideidx wideidx2 widesub widesub2 widesub3 widesub4 wjposer1 \ @@ -1157,13 +1183,13 @@ GAWK_EXT_TESTS = \ colonwarn clos1way clos1way2 clos1way3 clos1way4 clos1way5 clos1way6 \ crlf dbugeval dbugeval2 dbugtypedre1 dbugtypedre2 delsub \ devfd devfd1 devfd2 dumpvars errno exit \ - fieldwdth fpat1 fpat2 fpat3 fpat4 fpat5 fpatnull fsfwfs funlen \ + fieldwdth forcenum fpat1 fpat2 fpat3 fpat4 fpat5 fpatnull fsfwfs funlen \ functab1 functab2 functab3 fwtest fwtest2 fwtest3 \ genpot gensub gensub2 getlndir gnuops2 gnuops3 gnureops gsubind \ - icasefs icasers id igncdym igncfs ignrcas2 ignrcase \ + icasefs icasers id igncdym igncfs ignrcas2 ignrcas3 ignrcase \ incdupe incdupe2 incdupe3 incdupe4 incdupe5 incdupe6 incdupe7 \ - include include2 indirectbuiltin indirectcall indirectcall2 \ - lint lintold lintwarn \ + include include2 indirectbuiltin indirectcall indirectcall2 intarray \ + lint lintexp lintindex lintint lintlength lintold lintset lintwarn \ mixed1 manyfiles match1 match2 match3 mbstr1 mbstr2 \ muldimposix \ nastyparm negtime next nondec nondec2 \ @@ -1175,7 +1201,7 @@ GAWK_EXT_TESTS = \ rsstart2 rsstart3 rstest6 shadow shadowbuiltin \ sortfor sortu split_after_fpat \ splitarg4 strftime \ - strtonum switch2 symtab1 symtab2 symtab3 symtab4 symtab5 symtab6 \ + strtonum strtonum1 switch2 symtab1 symtab2 symtab3 symtab4 symtab5 symtab6 \ symtab7 symtab8 symtab9 symtab10 \ typedregex1 typedregex2 typedregex3 typeof1 typeof2 typeof3 typeof4 \ timeout \ @@ -1188,7 +1214,7 @@ INET_TESTS = inetdayu inetdayt inetechu inetecht MACHINE_TESTS = double1 double2 fmtspcl intformat MPFR_TESTS = mpfrnr mpfrnegzero mpfrmemok1 mpfrrem mpfrrnd mpfrieee \ - mpfrexprange mpfrsort mpfrsqrt mpfrbigint + mpfrexprange mpfrsort mpfrsqrt mpfrbigint mpfrstrtonum mpgforcenum LOCALE_CHARSET_TESTS = \ asort asorti backbigs1 backsmalls1 backsmalls2 \ @@ -1201,7 +1227,7 @@ SHLIB_TESTS = \ # List of the tests which should be run with --lint option: NEED_LINT = \ - defref fmtspcl lintwarn noeffect nofmtch shadow \ + defref fmtspcl lintexp lintindex lintint lintlength lintwarn noeffect nofmtch shadow \ uninit2 uninit3 uninit4 uninit5 uninitialized # List of the tests which should be run with --lint-old option: @@ -1728,6 +1754,16 @@ nondec2:: @$(AWK) --non-decimal-data -v a=0x1 -f "$(srcdir)"/$@.awk >_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +intarray:: + @echo $@ + @$(AWK) --non-decimal-data -f "$(srcdir)"/$@.awk >_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +forcenum:: + @echo $@ + @$(AWK) --non-decimal-data -f "$(srcdir)"/$@.awk >_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + nofile:: @echo $@ @$(AWK) '{}' no/such/file >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -1974,6 +2010,16 @@ mpfrsqrt: @$(AWK) -M -f "$(srcdir)"/$@.awk > _$@ 2>&1 @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +mpfrstrtonum: + @echo $@ + @$(AWK) -M -f "$(srcdir)"/$@.awk > _$@ 2>&1 + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +mpgforcenum: + @echo $@ + @$(AWK) -M -f "$(srcdir)"/$@.awk > _$@ 2>&1 + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + mpfrrem: @echo $@ @$(AWK) -M -f "$(srcdir)"/$@.awk > _$@ 2>&1 diff --git a/test/Makefile.in b/test/Makefile.in index dda34978..be42a250 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -557,6 +557,8 @@ EXTRA_DIST = \ fnparydl-mpfr.ok \ fnparydl.awk \ fnparydl.ok \ + forcenum.awk \ + forcenum.ok \ fordel.awk \ fordel.ok \ fork.awk \ @@ -720,6 +722,8 @@ EXTRA_DIST = \ igncfs.ok \ ignrcas2.awk \ ignrcas2.ok \ + ignrcas3.awk \ + ignrcas3.ok \ ignrcase.awk \ ignrcase.in \ ignrcase.ok \ @@ -762,6 +766,8 @@ EXTRA_DIST = \ inplace3.2.bak.ok \ inputred.awk \ inputred.ok \ + intarray.awk \ + intarray.ok \ intest.awk \ intest.ok \ intformat.awk \ @@ -783,9 +789,19 @@ EXTRA_DIST = \ leadnl.ok \ lint.awk \ lint.ok \ + lintexp.awk \ + lintexp.ok \ + lintindex.awk \ + lintindex.ok \ + lintint.awk \ + lintint.ok \ + lintlength.awk \ + lintlength.ok \ lintold.awk \ lintold.in \ lintold.ok \ + lintset.awk \ + lintset.ok \ lintwarn.awk \ lintwarn.ok \ litoct.awk \ @@ -865,6 +881,10 @@ EXTRA_DIST = \ mpfrsort.ok \ mpfrsqrt.awk \ mpfrsqrt.ok \ + mpfrstrtonum.awk \ + mpfrstrtonum.ok \ + mpgforcenum.awk \ + mpgforcenum.ok \ mtchi18n.awk \ mtchi18n.in \ mtchi18n.ok \ @@ -1029,6 +1049,8 @@ EXTRA_DIST = \ printfbad3.ok \ printfbad4.awk \ printfbad4.ok \ + printfchar.awk \ + printfchar.ok \ printfloat.awk \ printhuge.awk \ printhuge.ok \ @@ -1234,11 +1256,15 @@ EXTRA_DIST = \ strftlng.ok \ strnum1.awk \ strnum1.ok \ + strnum2.awk \ + strnum2.ok \ strtod.awk \ strtod.in \ strtod.ok \ strtonum.awk \ strtonum.ok \ + strtonum1.awk \ + strtonum1.ok \ subamp.awk \ subamp.in \ subamp.ok \ @@ -1389,7 +1415,7 @@ BASIC_TESTS = \ octsub ofmt ofmta ofmtbig ofmtfidl ofmts ofs1 onlynl opasnidx opasnslf \ paramasfunc1 paramasfunc2 \ paramdup paramres paramtyp paramuninitglobal parse1 parsefld parseme \ - pcntplus posix2008sub prdupval prec printf0 printf1 prmarscl prmreuse \ + pcntplus posix2008sub prdupval prec printf0 printf1 printfchar prmarscl prmreuse \ prt1eval prtoeval \ rand randtest range1 readbuf rebrackloc rebt8b1 redfilnm \ regeq regexpbrack regexpbrack2 \ @@ -1397,7 +1423,7 @@ BASIC_TESTS = \ reparse resplit rri1 rs rscompat rsnul1nl rsnulbig rsnulbig2 rstest1 rstest2 \ rstest3 rstest4 rstest5 rswhite \ scalar sclforin sclifin sigpipe1 sortempty sortglos splitargv splitarr splitdef \ - splitvar splitwht strcat1 strnum1 strtod subamp subback subi18n \ + splitvar splitwht strcat1 strnum1 strnum2 strtod subamp subback subi18n \ subsepnm subslash substr swaplns synerr1 synerr2 tradanch tweakfld \ uninit2 uninit3 uninit4 uninit5 uninitialized unterm uparrfs \ wideidx wideidx2 widesub widesub2 widesub3 widesub4 wjposer1 \ @@ -1413,13 +1439,13 @@ GAWK_EXT_TESTS = \ colonwarn clos1way clos1way2 clos1way3 clos1way4 clos1way5 clos1way6 \ crlf dbugeval dbugeval2 dbugtypedre1 dbugtypedre2 delsub \ devfd devfd1 devfd2 dumpvars errno exit \ - fieldwdth fpat1 fpat2 fpat3 fpat4 fpat5 fpatnull fsfwfs funlen \ + fieldwdth forcenum fpat1 fpat2 fpat3 fpat4 fpat5 fpatnull fsfwfs funlen \ functab1 functab2 functab3 fwtest fwtest2 fwtest3 \ genpot gensub gensub2 getlndir gnuops2 gnuops3 gnureops gsubind \ - icasefs icasers id igncdym igncfs ignrcas2 ignrcase \ + icasefs icasers id igncdym igncfs ignrcas2 ignrcas3 ignrcase \ incdupe incdupe2 incdupe3 incdupe4 incdupe5 incdupe6 incdupe7 \ - include include2 indirectbuiltin indirectcall indirectcall2 \ - lint lintold lintwarn \ + include include2 indirectbuiltin indirectcall indirectcall2 intarray \ + lint lintexp lintindex lintint lintlength lintold lintset lintwarn \ mixed1 manyfiles match1 match2 match3 mbstr1 mbstr2 \ muldimposix \ nastyparm negtime next nondec nondec2 \ @@ -1431,7 +1457,7 @@ GAWK_EXT_TESTS = \ rsstart2 rsstart3 rstest6 shadow shadowbuiltin \ sortfor sortu split_after_fpat \ splitarg4 strftime \ - strtonum switch2 symtab1 symtab2 symtab3 symtab4 symtab5 symtab6 \ + strtonum strtonum1 switch2 symtab1 symtab2 symtab3 symtab4 symtab5 symtab6 \ symtab7 symtab8 symtab9 symtab10 \ typedregex1 typedregex2 typedregex3 typeof1 typeof2 typeof3 typeof4 \ timeout \ @@ -1441,7 +1467,7 @@ EXTRA_TESTS = inftest regtest INET_TESTS = inetdayu inetdayt inetechu inetecht MACHINE_TESTS = double1 double2 fmtspcl intformat MPFR_TESTS = mpfrnr mpfrnegzero mpfrmemok1 mpfrrem mpfrrnd mpfrieee \ - mpfrexprange mpfrsort mpfrsqrt mpfrbigint + mpfrexprange mpfrsort mpfrsqrt mpfrbigint mpfrstrtonum mpgforcenum LOCALE_CHARSET_TESTS = \ asort asorti backbigs1 backsmalls1 backsmalls2 \ @@ -1455,7 +1481,7 @@ SHLIB_TESTS = \ # List of the tests which should be run with --lint option: NEED_LINT = \ - defref fmtspcl lintwarn noeffect nofmtch shadow \ + defref fmtspcl lintexp lintindex lintint lintlength lintwarn noeffect nofmtch shadow \ uninit2 uninit3 uninit4 uninit5 uninitialized @@ -2168,6 +2194,16 @@ nondec2:: @$(AWK) --non-decimal-data -v a=0x1 -f "$(srcdir)"/$@.awk >_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +intarray:: + @echo $@ + @$(AWK) --non-decimal-data -f "$(srcdir)"/$@.awk >_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +forcenum:: + @echo $@ + @$(AWK) --non-decimal-data -f "$(srcdir)"/$@.awk >_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + nofile:: @echo $@ @$(AWK) '{}' no/such/file >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -2413,6 +2449,16 @@ mpfrsqrt: @$(AWK) -M -f "$(srcdir)"/$@.awk > _$@ 2>&1 @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +mpfrstrtonum: + @echo $@ + @$(AWK) -M -f "$(srcdir)"/$@.awk > _$@ 2>&1 + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +mpgforcenum: + @echo $@ + @$(AWK) -M -f "$(srcdir)"/$@.awk > _$@ 2>&1 + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + mpfrrem: @echo $@ @$(AWK) -M -f "$(srcdir)"/$@.awk > _$@ 2>&1 @@ -3406,6 +3452,11 @@ printf1: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +printfchar: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + prmarscl: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -3598,6 +3649,11 @@ strnum1: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +strnum2: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + strtod: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -3903,6 +3959,11 @@ igncfs: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +ignrcas3: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + ignrcase: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -3933,11 +3994,36 @@ lint: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +lintexp: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +lintindex: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +lintint: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +lintlength: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + lintold: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint-old < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +lintset: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + lintwarn: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -4073,6 +4159,11 @@ strtonum: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +strtonum1: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + switch2: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ diff --git a/test/Maketests b/test/Maketests index 59ff889a..f42ecdc6 100644 --- a/test/Maketests +++ b/test/Maketests @@ -700,6 +700,11 @@ printf1: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +printfchar: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + prmarscl: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -892,6 +897,11 @@ strnum1: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +strnum2: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + strtod: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -1197,6 +1207,11 @@ igncfs: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +ignrcas3: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + ignrcase: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -1227,11 +1242,36 @@ lint: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +lintexp: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +lintindex: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +lintint: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + +lintlength: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + lintold: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint-old < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +lintset: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + lintwarn: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @@ -1367,6 +1407,11 @@ strtonum: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +strtonum1: + @echo $@ + @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + switch2: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ diff --git a/test/forcenum.awk b/test/forcenum.awk new file mode 100644 index 00000000..54c536c9 --- /dev/null +++ b/test/forcenum.awk @@ -0,0 +1,8 @@ +BEGIN { + # first, make some strnums + nf = split("|5apple|+NaN| 6|0x1az|011Q|027", f, "|") + for (i = 1; i <= nf; i++) { + x = f[i]+0 # trigger strnum conversion to number or string + printf "[%s] -> %g (type %s)\n", f[i], f[i], typeof(f[i]) + } +} diff --git a/test/forcenum.ok b/test/forcenum.ok new file mode 100644 index 00000000..c74eefc7 --- /dev/null +++ b/test/forcenum.ok @@ -0,0 +1,7 @@ +[] -> 0 (type string) +[5apple] -> 5 (type string) +[+NaN] -> nan (type number) +[ 6] -> 6 (type number) +[0x1az] -> 26 (type string) +[011Q] -> 9 (type string) +[027] -> 23 (type number) diff --git a/test/ignrcas3.awk b/test/ignrcas3.awk new file mode 100644 index 00000000..e74eea64 --- /dev/null +++ b/test/ignrcas3.awk @@ -0,0 +1,7 @@ +BEGIN { + x = "0" + print x+0 # trigger NUMCUR + IGNORECASE = x # should enable ignorecase, since x is a non-null string + y = "aBc" + print (y ~ /abc/) +} diff --git a/test/ignrcas3.ok b/test/ignrcas3.ok new file mode 100644 index 00000000..0d66ea1a --- /dev/null +++ b/test/ignrcas3.ok @@ -0,0 +1,2 @@ +0 +1 diff --git a/test/intarray.awk b/test/intarray.awk new file mode 100644 index 00000000..2c30bd5f --- /dev/null +++ b/test/intarray.awk @@ -0,0 +1,10 @@ +BEGIN { + nf = split("5 |05|0x4|00| 5|-0x12| 011|-013", f, "|") + for (i = 1; i <= nf; i++) { + delete g + z = f[i]+0 # trigger numeric conversion + g[f[i]] + for (x in g) + printf "[%s]\n", x + } +} diff --git a/test/intarray.ok b/test/intarray.ok new file mode 100644 index 00000000..d4df7b8c --- /dev/null +++ b/test/intarray.ok @@ -0,0 +1,8 @@ +[5 ] +[05] +[0x4] +[00] +[ 5] +[-0x12] +[ 011] +[-013] diff --git a/test/lintexp.awk b/test/lintexp.awk new file mode 100644 index 00000000..082d7447 --- /dev/null +++ b/test/lintexp.awk @@ -0,0 +1,9 @@ +BEGIN { + split("0|0a", f, "|") + z = exp(f[1]) # no warning, since strnum converted to number + x = f[2]+0 # trigger NUMCUR + z = exp(f[2]) # should print a warning + x = "0" + y = x+0 # trigger NUMCUR + z = exp(x) # should print a warning, since x is still a string! +} diff --git a/test/lintexp.ok b/test/lintexp.ok new file mode 100644 index 00000000..33122f6d --- /dev/null +++ b/test/lintexp.ok @@ -0,0 +1,2 @@ +gawk: lintexp.awk:5: warning: exp: received non-numeric argument +gawk: lintexp.awk:8: warning: exp: received non-numeric argument diff --git a/test/lintindex.awk b/test/lintindex.awk new file mode 100644 index 00000000..8e6d7e56 --- /dev/null +++ b/test/lintindex.awk @@ -0,0 +1,10 @@ +BEGIN { + x = 537 + y = 3 + z = index(x, y) # should print lint warning + # now that STRCUR has been trigged on x and y, check that we still + # get the warning + z = index(x, y) # should print lint warning + if (z != 2) + print "oops" +} diff --git a/test/lintindex.ok b/test/lintindex.ok new file mode 100644 index 00000000..b89db6a5 --- /dev/null +++ b/test/lintindex.ok @@ -0,0 +1,4 @@ +gawk: lintindex.awk:4: warning: index: received non-string first argument +gawk: lintindex.awk:4: warning: index: received non-string second argument +gawk: lintindex.awk:7: warning: index: received non-string first argument +gawk: lintindex.awk:7: warning: index: received non-string second argument diff --git a/test/lintint.awk b/test/lintint.awk new file mode 100644 index 00000000..f4f687b0 --- /dev/null +++ b/test/lintint.awk @@ -0,0 +1,9 @@ +BEGIN { + split("0|0a", f, "|") + z = int(f[1]) # no warning, since strnum converted to number + x = f[2]+0 # trigger NUMCUR + z = int(f[2]) # should print a warning + x = "0" + y = x+0 # trigger NUMCUR + z = int(x) # should print a warning, since x is still a string! +} diff --git a/test/lintint.ok b/test/lintint.ok new file mode 100644 index 00000000..5bd5d589 --- /dev/null +++ b/test/lintint.ok @@ -0,0 +1,2 @@ +gawk: lintint.awk:5: warning: int: received non-numeric argument +gawk: lintint.awk:8: warning: int: received non-numeric argument diff --git a/test/lintlength.awk b/test/lintlength.awk new file mode 100644 index 00000000..ad217912 --- /dev/null +++ b/test/lintlength.awk @@ -0,0 +1,6 @@ +BEGIN { + x = 5 + z = length(x) # should issue a warning + y = (x "") # trigger STRCUR + z = length(x) # should still issue a warning +} diff --git a/test/lintlength.ok b/test/lintlength.ok new file mode 100644 index 00000000..cb369f7f --- /dev/null +++ b/test/lintlength.ok @@ -0,0 +1,2 @@ +gawk: lintlength.awk:3: warning: length: received non-string argument +gawk: lintlength.awk:5: warning: length: received non-string argument diff --git a/test/lintset.awk b/test/lintset.awk new file mode 100644 index 00000000..8d52eeb4 --- /dev/null +++ b/test/lintset.awk @@ -0,0 +1,5 @@ +BEGIN { + split("0a", f) # set f[0] to a strnum that is really a string + LINT = f[1] # lint should be enabled + x = exp("0") # should generate a warning +} diff --git a/test/lintset.ok b/test/lintset.ok new file mode 100644 index 00000000..7d67c614 --- /dev/null +++ b/test/lintset.ok @@ -0,0 +1 @@ +gawk: lintset.awk:4: warning: exp: received non-numeric argument diff --git a/test/mpfrstrtonum.awk b/test/mpfrstrtonum.awk new file mode 100644 index 00000000..79d6ad13 --- /dev/null +++ b/test/mpfrstrtonum.awk @@ -0,0 +1,5 @@ +BEGIN { + x = "011" + print x+0 # trigger NUMCUR + print strtonum(x) +} diff --git a/test/mpfrstrtonum.ok b/test/mpfrstrtonum.ok new file mode 100644 index 00000000..48a9ed43 --- /dev/null +++ b/test/mpfrstrtonum.ok @@ -0,0 +1,2 @@ +11 +9 diff --git a/test/mpgforcenum.awk b/test/mpgforcenum.awk new file mode 100644 index 00000000..b2d0b6f1 --- /dev/null +++ b/test/mpgforcenum.awk @@ -0,0 +1,5 @@ +BEGIN { + split("5apple", f) # make a strnum + x = f[1]+0 # force strnum conversion to number or string + print typeof(f[1]) # should be string +} diff --git a/test/mpgforcenum.ok b/test/mpgforcenum.ok new file mode 100644 index 00000000..ee8a39c3 --- /dev/null +++ b/test/mpgforcenum.ok @@ -0,0 +1 @@ +string diff --git a/test/printfchar.awk b/test/printfchar.awk new file mode 100644 index 00000000..9e703c31 --- /dev/null +++ b/test/printfchar.awk @@ -0,0 +1,7 @@ +BEGIN { + x[65] + for (i in x) { + # i should be a string + printf "%c\n", i # should print 1st char of string + } +} diff --git a/test/printfchar.ok b/test/printfchar.ok new file mode 100644 index 00000000..1e8b3149 --- /dev/null +++ b/test/printfchar.ok @@ -0,0 +1 @@ +6 diff --git a/test/strnum2.awk b/test/strnum2.awk new file mode 100644 index 00000000..44931d5f --- /dev/null +++ b/test/strnum2.awk @@ -0,0 +1,18 @@ +BEGIN { + split(" 1.234 ", f, "|") # create a numeric string (strnum) value + OFMT = "%.1f" + CONVFMT = "%.2f" + + # Check whether a strnum is displayed the same way before and + # after force_number is called. Also, should numeric strings + # be formatted with OFMT and CONVFMT or show the original string value? + + print f[1] # OFMT + print (f[1] "") # CONVFMT + + # force conversion to NUMBER if it has not happened already + x = f[1]+0 + + print f[1] # OFMT + print (f[1] "") # CONVFMT +} diff --git a/test/strnum2.ok b/test/strnum2.ok new file mode 100644 index 00000000..63898bd4 --- /dev/null +++ b/test/strnum2.ok @@ -0,0 +1,4 @@ + 1.234 + 1.234 + 1.234 + 1.234 diff --git a/test/strtonum1.awk b/test/strtonum1.awk new file mode 100644 index 00000000..79d6ad13 --- /dev/null +++ b/test/strtonum1.awk @@ -0,0 +1,5 @@ +BEGIN { + x = "011" + print x+0 # trigger NUMCUR + print strtonum(x) +} diff --git a/test/strtonum1.ok b/test/strtonum1.ok new file mode 100644 index 00000000..48a9ed43 --- /dev/null +++ b/test/strtonum1.ok @@ -0,0 +1,2 @@ +11 +9 |