diff options
Diffstat (limited to 'builtin.c')
-rw-r--r-- | builtin.c | 509 |
1 files changed, 378 insertions, 131 deletions
@@ -129,10 +129,14 @@ wrerror: if (fp == stdout && errno == EPIPE) gawk_exit(EXIT_FATAL); + /* otherwise die verbosely */ - fatal(_("%s to \"%s\" failed (%s)"), from, - rp ? rp->value : _("standard output"), - errno ? strerror(errno) : _("reason unknown")); + if ((rp != NULL) ? is_non_fatal_redirect(rp->value) : is_non_fatal_std(fp)) + update_ERRNO_int(errno); + else + fatal(_("%s to \"%s\" failed (%s)"), from, + rp ? rp->value : _("standard output"), + errno ? strerror(errno) : _("reason unknown")); } /* do_exp --- exponential function */ @@ -144,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); @@ -350,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")); } @@ -465,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); @@ -480,6 +484,12 @@ do_isarray(int nargs) { NODE *tmp; int ret = 1; + static bool warned = false; + + if (do_lint && ! warned) { + warned = true; + lintwarn(_("`isarray' is deprecated. Use `typeof' instead")); + } tmp = POP(); if (tmp->type != Node_var_array) { @@ -524,7 +534,7 @@ do_length(int nargs) assert(tmp->type == Node_val); - 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); @@ -553,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) @@ -712,7 +722,7 @@ format_tree( emalloc(obuf, char *, INITIAL_OUT_SIZE, "format_tree"); obufout = obuf; osiz = INITIAL_OUT_SIZE; - ofre = osiz - 2; + ofre = osiz - 1; cur_arg = 1; @@ -1039,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) { @@ -1574,7 +1583,7 @@ mpf1: bchunk(s0, s1 - s0); olen_final = obufout - obuf; if (ofre > 0) - erealloc(obuf, char *, olen_final + 2, "format_tree"); + erealloc(obuf, char *, olen_final + 1, "format_tree"); r = make_str_node(obuf, olen_final, ALREADY_MALLOCED); obuf = NULL; out: @@ -1645,7 +1654,7 @@ do_printf(int nargs, int redirtype) FILE *fp = NULL; NODE *tmp; struct redirect *rp = NULL; - int errflg; /* not used, sigh */ + int errflg = 0; NODE *redir_exp = NULL; if (nargs == 0) { @@ -1656,7 +1665,7 @@ do_printf(int nargs, int redirtype) redir_exp = TOP(); if (redir_exp->type != Node_val) fatal(_("attempt to use array `%s' in a scalar context"), array_vname(redir_exp)); - rp = redirect(redir_exp, redirtype, & errflg); + rp = redirect(redir_exp, redirtype, & errflg, true); DEREF(redir_exp); decr_sp(); } @@ -1669,14 +1678,22 @@ do_printf(int nargs, int redirtype) redir_exp = PEEK(nargs); if (redir_exp->type != Node_val) fatal(_("attempt to use array `%s' in a scalar context"), array_vname(redir_exp)); - rp = redirect(redir_exp, redirtype, & errflg); + rp = redirect(redir_exp, redirtype, & errflg, true); if (rp != NULL) { if ((rp->flag & RED_TWOWAY) != 0 && rp->output.fp == NULL) { + if (is_non_fatal_redirect(redir_exp->stptr)) { + update_ERRNO_int(EBADF); + return; + } (void) close_rp(rp, CLOSE_ALL); fatal(_("printf: attempt to write to closed write end of two-way pipe")); } fp = rp->output.fp; } + else if (errflg) { + update_ERRNO_int(errflg); + return; + } } else if (do_debug) /* only the debugger can change the default output */ fp = output_fp; else @@ -1709,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); @@ -1850,7 +1867,7 @@ do_substr(int nargs) * way to do things. */ memset(& mbs, 0, sizeof(mbs)); - emalloc(substr, char *, (length * gawk_mb_cur_max) + 2, "do_substr"); + emalloc(substr, char *, (length * gawk_mb_cur_max) + 1, "do_substr"); wp = t1->wstptr + indx; for (cp = substr; length > 0; length--) { result = wcrtomb(cp, *wp, & mbs); @@ -1899,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; @@ -1913,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); @@ -1948,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); @@ -2024,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); @@ -2082,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; @@ -2110,22 +2124,12 @@ do_system(int nargs) ; /* leave it alone, full 16 bits */ else if (do_traditional) #ifdef __MINGW32__ - ret = (((unsigned)status) & ~0xC0000000); + ret = (((unsigned)status) & ~0xC0000000); #else ret = (status / 256.0); #endif - else if (WIFEXITED(status)) - ret = WEXITSTATUS(status); /* normal exit */ - else if (WIFSIGNALED(status)) { - bool coredumped = false; -#ifdef WCOREDUMP - coredumped = WCOREDUMP(status); -#endif - /* use 256 since exit values are 8 bits */ - ret = WTERMSIG(status) + - (coredumped ? 512 : 256); - } else - ret = 0; /* shouldn't get here */ + else + ret = sanitize_exit_status(status); } if ((BINMODE & BINMODE_INPUT) != 0) @@ -2146,7 +2150,7 @@ void do_print(int nargs, int redirtype) { struct redirect *rp = NULL; - int errflg; /* not used, sigh */ + int errflg = 0; FILE *fp = NULL; int i; NODE *redir_exp = NULL; @@ -2158,14 +2162,22 @@ do_print(int nargs, int redirtype) redir_exp = PEEK(nargs); if (redir_exp->type != Node_val) fatal(_("attempt to use array `%s' in a scalar context"), array_vname(redir_exp)); - rp = redirect(redir_exp, redirtype, & errflg); + rp = redirect(redir_exp, redirtype, & errflg, true); if (rp != NULL) { if ((rp->flag & RED_TWOWAY) != 0 && rp->output.fp == NULL) { + if (is_non_fatal_redirect(redir_exp->stptr)) { + update_ERRNO_int(EBADF); + return; + } (void) close_rp(rp, CLOSE_ALL); fatal(_("print: attempt to write to closed write end of two-way pipe")); } fp = rp->output.fp; } + else if (errflg) { + update_ERRNO_int(errflg); + return; + } } else if (do_debug) /* only the debugger can change the default output */ fp = output_fp; else @@ -2179,8 +2191,10 @@ do_print(int nargs, int redirtype) fatal(_("attempt to use array `%s' in a scalar context"), array_vname(tmp)); } - if ((tmp->flags & STRCUR) == 0 || (tmp->stfmt != -1 && tmp->stfmt != OFMTidx)) - args_array[i] = format_val(OFMT, OFMTidx, tmp); + if ( (tmp->flags & STRCUR) == 0 + || ( tmp->stfmt != STFMT_UNUSED + && tmp->stfmt != OFMTidx)) + args_array[i] = format_val(OFMT, OFMTidx, tmp); } if (redir_exp != NULL) { @@ -2217,15 +2231,19 @@ do_print_rec(int nargs, int redirtype) FILE *fp = NULL; NODE *f0; struct redirect *rp = NULL; - int errflg; /* not used, sigh */ + int errflg = 0; NODE *redir_exp = NULL; assert(nargs == 0); if (redirtype != 0) { redir_exp = TOP(); - rp = redirect(redir_exp, redirtype, & errflg); + rp = redirect(redir_exp, redirtype, & errflg, true); if (rp != NULL) { if ((rp->flag & RED_TWOWAY) != 0 && rp->output.fp == NULL) { + if (is_non_fatal_redirect(redir_exp->stptr)) { + update_ERRNO_int(EBADF); + return; + } (void) close_rp(rp, CLOSE_ALL); fatal(_("print: attempt to write to closed write end of two-way pipe")); } @@ -2236,6 +2254,11 @@ do_print_rec(int nargs, int redirtype) } else fp = output_fp; + if (errflg) { + update_ERRNO_int(errflg); + return; + } + if (fp == NULL) return; @@ -2329,7 +2352,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); @@ -2360,7 +2383,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); @@ -2393,9 +2416,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; @@ -2414,7 +2437,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); @@ -2430,7 +2453,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); @@ -2449,6 +2472,8 @@ static char *const state = (char *const) istate; NODE * do_rand(int nargs ATTRIBUTE_UNUSED) { + double tmprand; +#define RAND_DIVISOR ((double)GAWK_RANDOM_MAX+1.0) if (firstrand) { (void) initstate((unsigned) 1, state, SIZEOF_STATE); /* don't need to srandom(1), initstate() does it for us. */ @@ -2460,7 +2485,66 @@ do_rand(int nargs ATTRIBUTE_UNUSED) * * 0 <= n < 1 */ - return make_number((AWKNUM) (random() % GAWK_RANDOM_MAX) / GAWK_RANDOM_MAX); + /* + * Date: Wed, 28 Aug 2013 17:52:46 -0700 + * From: Bob Jewett <jewett@bill.scs.agilent.com> + * + * Call random() twice to fill in more bits in the value + * of the double. Also, there is a bug in random() such + * that when the values of successive values are combined + * like (rand1*rand2)^2, (rand3*rand4)^2, ... the + * resulting time series is not white noise. The + * following also seems to fix that bug. + * + * The add/subtract 0.5 keeps small bits from filling + * below 2^-53 in the double, not that anyone should be + * looking down there. + * + * Date: Wed, 25 Sep 2013 10:45:38 -0600 (MDT) + * From: "Nelson H. F. Beebe" <beebe@math.utah.edu> + * (4) The code is typical of many published fragments for converting + * from integer to floating-point, and I discuss the serious pitfalls + * in my book, because it leads to platform-dependent behavior at the + * end points of the interval [0,1] + * + * (5) the documentation in the gawk info node says + * + * `rand()' + * Return a random number. The values of `rand()' are uniformly + * distributed between zero and one. The value could be zero but is + * never one.(1) + * + * The division by RAND_DIVISOR may not guarantee that 1.0 is never + * returned: the programmer forgot the platform-dependent issue of + * rounding. + * + * For points 4 and 5, the safe way is a loop: + * + * double + * rand(void) // return value in [0.0, 1.0) + * { + * value = internal_rand(); + * + * while (value == 1.0) + * value = internal_rand(); + * + * return (value); + * } + */ + + do { + long d1, d2; + /* + * Do the calls in predictable order to avoid + * compiler differences in order of evaluation. + */ + d1 = random(); + d2 = random(); + tmprand = 0.5 + ( (d1/RAND_DIVISOR + d2) / RAND_DIVISOR ); + tmprand -= 0.5; + } while (tmprand == 1.0); + + return make_number((AWKNUM) tmprand); } /* do_srand --- seed the random number generator */ @@ -2483,7 +2567,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); @@ -2573,7 +2657,7 @@ do_match(int nargs) sprintf(buff, "%d", ii); ilen = strlen(buff); - amt = ilen + subseplen + strlen("length") + 2; + amt = ilen + subseplen + strlen("length") + 1; if (oldamt == 0) { emalloc(buf, char *, amt, "do_match"); @@ -2747,56 +2831,48 @@ do_sub(int nargs, unsigned int flags) int ampersands; int matches = 0; Regexp *rp; - NODE *s; /* subst. pattern */ - NODE *t; /* string to make sub. in; $0 if none given */ + NODE *rep_node; /* replacement text */ + NODE *target; /* string to make sub. in; $0 if none given */ NODE *tmp; NODE **lhs = NULL; long how_many = 1; /* one substitution for sub, also gensub default */ - int global; + bool global; long current; bool lastmatchnonzero; char *mb_indices = NULL; if ((flags & GENSUB) != 0) { double d; - NODE *t1; + NODE *glob_flag; tmp = PEEK(3); rp = re_update(tmp); - t = POP_STRING(); /* original string */ - - t1 = POP_SCALAR(); /* value of global flag */ - if ((t1->flags & (STRCUR|STRING)) != 0) { - if (t1->stlen > 0 && (t1->stptr[0] == 'g' || t1->stptr[0] == 'G')) - how_many = -1; - else { - (void) force_number(t1); - d = get_number_d(t1); - if ((t1->flags & NUMCUR) != 0) - goto set_how_many; + target = POP_STRING(); /* original string */ - warning(_("gensub: third argument `%.*s' treated as 1"), - (int) t1->stlen, t1->stptr); - how_many = 1; - } - } else { - (void) force_number(t1); - d = get_number_d(t1); -set_how_many: + glob_flag = POP_SCALAR(); /* value of global flag */ + 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); 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(t1); - + DEREF(glob_flag); } else { - /* take care of regexp early, in case re_update is fatal */ tmp = PEEK(2); @@ -2808,30 +2884,30 @@ set_how_many: /* original string */ if ((flags & LITERAL) != 0) - t = POP_STRING(); + target = POP_STRING(); else { lhs = POP_ADDRESS(); - t = force_string(*lhs); + target = force_string(*lhs); } } global = (how_many == -1); - s = POP_STRING(); /* replacement text */ + rep_node = POP_STRING(); /* replacement text */ decr_sp(); /* regexp, already updated above */ /* do the search early to avoid work on non-match */ - if (research(rp, t->stptr, 0, t->stlen, RE_NEED_START) == -1 || - RESTART(rp, t->stptr) > t->stlen) + if (research(rp, target->stptr, 0, target->stlen, RE_NEED_START) == -1 || + RESTART(rp, target->stptr) > target->stlen) goto done; - t->flags |= STRING; + target->flags |= STRING; - text = t->stptr; - textlen = t->stlen; + text = target->stptr; + textlen = target->stlen; - repl = s->stptr; - replend = repl + s->stlen; + repl = rep_node->stptr; + replend = repl + rep_node->stlen; repllen = replend - repl; ampersands = 0; @@ -2849,6 +2925,7 @@ set_how_many: index_multibyte_buffer(repl, mb_indices, repllen); } + /* compute length of replacement string, number of ampersands */ for (scan = repl; scan < replend; scan++) { if ((gawk_mb_cur_max == 1 || (repllen > 0 && mb_indices[scan - repl] == 1)) && (*scan == '&')) { @@ -2895,24 +2972,32 @@ set_how_many: lastmatchnonzero = false; - /* guesstimate how much room to allocate; +2 forces > 0 */ - buflen = textlen + (ampersands + 1) * repllen + 2; - emalloc(buf, char *, buflen + 2, "do_sub"); + /* guesstimate how much room to allocate; +1 forces > 0 */ + buflen = textlen + (ampersands + 1) * repllen + 1; + emalloc(buf, char *, buflen + 1, "do_sub"); buf[buflen] = '\0'; - buf[buflen + 1] = '\0'; bp = buf; for (current = 1;; current++) { matches++; - matchstart = t->stptr + RESTART(rp, t->stptr); - matchend = t->stptr + REEND(rp, t->stptr); + matchstart = target->stptr + RESTART(rp, target->stptr); + matchend = target->stptr + REEND(rp, target->stptr); /* * create the result, copying in parts of the original - * string + * string. note that length of replacement string can + * vary since ampersand is actual text of regexp match. */ - len = matchstart - text + repllen - + ampersands * (matchend - matchstart); + + /* + * add 1 to len to handle "empty" case where + * matchend == matchstart and we force a match on a single + * char. Use 'matchend - text' instead of 'matchstart - text' + * because we may not actually make any substitution depending + * on the 'global' and 'how_many' values. + */ + len = matchend - text + repllen + + ampersands * (matchend - matchstart) + 1; sofar = bp - buf; while (buflen < (sofar + len + 1)) { buflen *= 2; @@ -2959,13 +3044,13 @@ set_how_many: if (flags & GENSUB) { /* gensub, behave sanely */ if (isdigit((unsigned char) scan[1])) { int dig = scan[1] - '0'; - if (dig < NUMSUBPATS(rp, t->stptr) && SUBPATSTART(rp, tp->stptr, dig) != -1) { + if (dig < NUMSUBPATS(rp, target->stptr) && SUBPATSTART(rp, tp->stptr, dig) != -1) { char *start, *end; - start = t->stptr - + SUBPATSTART(rp, t->stptr, dig); - end = t->stptr - + SUBPATEND(rp, t->stptr, dig); + start = target->stptr + + SUBPATSTART(rp, target->stptr, dig); + end = target->stptr + + SUBPATEND(rp, target->stptr, dig); for (cp = start; cp < end; cp++) *bp++ = *cp; @@ -3021,19 +3106,29 @@ set_how_many: textlen = text + textlen - matchend; text = matchend; +#if 0 + if (bp - buf > sofar + len) + fprintf(stderr, "debug: len = %zu, but used %ld\n", len, (long)((bp - buf) - (long)sofar)); +#endif + if ((current >= how_many && ! global) || ((long) textlen <= 0 && matchstart == matchend) - || research(rp, t->stptr, text - t->stptr, textlen, RE_NEED_START) == -1) + || research(rp, target->stptr, text - target->stptr, textlen, RE_NEED_START) == -1) break; } sofar = bp - buf; - if (buflen - sofar - textlen - 1) { - buflen = sofar + textlen + 2; + if (buflen < (sofar + textlen + 1)) { + buflen = sofar + textlen + 1; erealloc(buf, char *, buflen, "do_sub"); bp = buf + sofar; } - for (scan = matchend; scan < text + textlen; scan++) + /* + * Note that text == matchend, since that assignment is made before + * exiting the 'for' loop above. Thus we copy in the rest of the + * original string. + */ + for (scan = text; scan < text + textlen; scan++) *bp++ = *scan; *bp = '\0'; textlen = bp - buf; @@ -3042,7 +3137,7 @@ set_how_many: efree(mb_indices); done: - DEREF(s); + DEREF(rep_node); if ((matches == 0 || (flags & LITERAL) != 0) && buf != NULL) { efree(buf); @@ -3052,18 +3147,18 @@ done: if (flags & GENSUB) { if (matches > 0) { /* return the result string */ - DEREF(t); + DEREF(target); assert(buf != NULL); return make_str_node(buf, textlen, ALREADY_MALLOCED); } /* return the original string */ - return t; + return target; } /* For a string literal, must not change the original string. */ if ((flags & LITERAL) != 0) - DEREF(t); + DEREF(target); else if (matches > 0) { unref(*lhs); *lhs = make_str_node(buf, textlen, ALREADY_MALLOCED); @@ -3234,9 +3329,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; @@ -3271,9 +3366,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; @@ -3313,7 +3408,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; @@ -3345,7 +3440,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; @@ -3377,7 +3472,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; @@ -3406,7 +3501,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); @@ -3431,11 +3526,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; @@ -3452,7 +3547,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; @@ -3464,8 +3559,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) { @@ -3498,14 +3596,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; @@ -3513,11 +3618,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: @@ -3753,6 +3860,125 @@ do_bindtextdomain(int nargs) return make_string(the_result, strlen(the_result)); } +/* do_intdiv --- do integer division, return quotient and remainder in dest array */ + +/* + * We define the semantics as: + * numerator = int(numerator) + * denominator = int(denonmator) + * quotient = int(numerator / denomator) + * remainder = int(numerator % denomator) + */ + +NODE * +do_intdiv(int nargs) +{ + NODE *numerator, *denominator, *result; + double num, denom, quotient, remainder; + NODE *sub, **lhs; + + result = POP_PARAM(); + if (result->type != Node_var_array) + fatal(_("intdiv: third argument is not an array")); + assoc_clear(result); + + denominator = POP_SCALAR(); + numerator = POP_SCALAR(); + + if (do_lint) { + if ((fixtype(numerator)->flags & NUMBER) == 0) + lintwarn(_("intdiv: received non-numeric first argument")); + if ((fixtype(denominator)->flags & NUMBER) == 0) + lintwarn(_("intdiv: received non-numeric second argument")); + } + + (void) force_number(numerator); + (void) force_number(denominator); + num = double_to_int(get_number_d(numerator)); + denom = double_to_int(get_number_d(denominator)); + + if (denom == 0.0) + fatal(_("intdiv: division by zero attempted")); + + quotient = double_to_int(num / denom); + /* + * FIXME: This code is duplicated, factor it out to a + * separate function. + */ +#ifdef HAVE_FMOD + remainder = fmod(num, denom); +#else /* ! HAVE_FMOD */ + (void) modf(num / denom, & remainder); + remainder = num - remainder * denom; +#endif /* ! HAVE_FMOD */ + remainder = double_to_int(remainder); + + sub = make_string("quotient", 8); + lhs = assoc_lookup(result, sub); + unref(*lhs); + *lhs = make_number((AWKNUM) quotient); + + sub = make_string("remainder", 9); + lhs = assoc_lookup(result, sub); + unref(*lhs); + *lhs = make_number((AWKNUM) remainder); + + return make_number((AWKNUM) 0.0); +} + +/* do_typeof --- return a string with the type of the arg */ + +NODE * +do_typeof(int nargs) +{ + NODE *arg; + char *res = "unknown"; + bool deref = true; + + arg = POP(); + switch (arg->type) { + case Node_var_array: + /* Node_var_array is never UPREF'ed */ + res = "array"; + deref = false; + break; + case Node_val: + case Node_var: + switch (arg->flags & (STRING|NUMBER|MAYBE_NUM)) { + case STRING: + res = "string"; + 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"; + deref = false; + break; + default: + fatal(_("typeof: unknown argument type `%s'"), + nodetype2str(arg->type)); + break; + } + + if (deref) + DEREF(arg); + return make_string(res, strlen(res)); +} /* mbc_byte_count --- return number of bytes for corresponding numchars multibyte characters */ @@ -3809,3 +4035,24 @@ mbc_char_count(const char *ptr, size_t numbytes) return sum; } + +/* sanitize_exit_status --- convert a 16 bit Unix exit status into something reasonable */ + +int sanitize_exit_status(int status) +{ + int ret = 0; + + if (WIFEXITED(status)) + ret = WEXITSTATUS(status); /* normal exit */ + else if (WIFSIGNALED(status)) { + bool coredumped = false; +#ifdef WCOREDUMP + coredumped = WCOREDUMP(status); +#endif + /* use 256 since exit values are 8 bits */ + ret = WTERMSIG(status) + (coredumped ? 512 : 256); + } else + ret = 0; /* shouldn't get here */ + + return ret; +} |