diff options
Diffstat (limited to 'builtin.c')
-rw-r--r-- | builtin.c | 649 |
1 files changed, 414 insertions, 235 deletions
@@ -73,15 +73,17 @@ extern void srandom(unsigned long seed); extern NODE **args_array; extern int max_args; extern NODE **fields_arr; -extern int output_is_tty; +extern bool output_is_tty; extern FILE *output_fp; #define POP_TWO_SCALARS(s1, s2) \ s2 = POP_SCALAR(); \ s1 = POP(); \ -if ((s1)->type == Node_var_array) \ - DEREF(s2), fatal(_("attempt to use array `%s' in a scalar context"), array_vname(s1)), 0 +do { if (s1->type == Node_var_array) { \ +DEREF(s2); \ +fatal(_("attempt to use array `%s' in a scalar context"), array_vname(s1)); \ +}} while (false) /* @@ -90,9 +92,6 @@ if ((s1)->type == Node_var_array) \ */ #define GAWK_RANDOM_MAX 0x7fffffffL -static void efwrite(const void *ptr, size_t size, size_t count, FILE *fp, - const char *from, struct redirect *rp, int flush); - /* efwrite --- like fwrite, but with error checking */ static void @@ -102,17 +101,26 @@ efwrite(const void *ptr, FILE *fp, const char *from, struct redirect *rp, - int flush) + bool flush) { errno = 0; - if (fwrite(ptr, size, count, fp) != count) + if (rp != NULL) { + if (rp->output.gawk_fwrite(ptr, size, count, fp, rp->output.opaque) != count) + goto wrerror; + } else if (fwrite(ptr, size, count, fp) != count) goto wrerror; if (flush && ((fp == stdout && output_is_tty) || (rp != NULL && (rp->flag & RED_NOBUF)))) { - fflush(fp); - if (ferror(fp)) - goto wrerror; + if (rp != NULL) { + rp->output.gawk_fflush(fp, rp->output.opaque); + if (rp->output.gawk_ferror(fp, rp->output.opaque)) + goto wrerror; + } else { + fflush(fp); + if (ferror(fp)) + goto wrerror; + } } return; @@ -133,7 +141,7 @@ do_exp(int nargs) tmp = POP_SCALAR(); if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) lintwarn(_("exp: received non-numeric argument")); - d = force_number(tmp); + d = force_number(tmp)->numbr; DEREF(tmp); errno = 0; res = exp(d); @@ -221,9 +229,9 @@ do_fflush(int nargs) DEREF(tmp); return make_number((AWKNUM) status); } - fp = rp->fp; + fp = rp->output.fp; if (fp != NULL) - status = fflush(fp); + status = rp->output.gawk_fflush(fp, rp->output.opaque); } else if ((fp = stdfile(tmp->stptr, tmp->stlen)) != NULL) { status = fflush(fp); } else { @@ -333,7 +341,7 @@ do_index(int nargs) size_t l1, l2; long ret; #if MBS_SUPPORT - int do_single_byte = FALSE; + bool do_single_byte = false; mbstate_t mbs1, mbs2; if (gawk_mb_cur_max > 1) { @@ -350,8 +358,10 @@ do_index(int nargs) if ((s2->flags & (STRING|STRCUR)) == 0) lintwarn(_("index: received non-string second argument")); } - force_string(s1); - force_string(s2); + + s1 = force_string(s1); + s2 = force_string(s2); + p1 = s1->stptr; p2 = s2->stptr; l1 = s1->stlen; @@ -471,7 +481,7 @@ do_int(int nargs) tmp = POP_SCALAR(); if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) lintwarn(_("int: received non-numeric argument")); - d = force_number(tmp); + d = force_number(tmp)->numbr; d = double_to_int(d); DEREF(tmp); return make_number((AWKNUM) d); @@ -503,12 +513,12 @@ do_length(int nargs) tmp = POP(); if (tmp->type == Node_var_array) { - static short warned = FALSE; + static bool warned = false; if (do_posix) fatal(_("length: received array argument")); if (do_lint && ! warned) { - warned = TRUE; + warned = true; lintwarn(_("`length(array)' is a gawk extension")); } return make_number((AWKNUM) tmp->table_size); @@ -518,7 +528,7 @@ do_length(int nargs) if (do_lint && (tmp->flags & (STRING|STRCUR)) == 0) lintwarn(_("length: received non-string argument")); - (void) force_string(tmp); + tmp = force_string(tmp); #if MBS_SUPPORT if (gawk_mb_cur_max > 1) { @@ -549,7 +559,7 @@ do_log(int nargs) tmp = POP_SCALAR(); if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) lintwarn(_("log: received non-numeric argument")); - arg = (double) force_number(tmp); + arg = force_number(tmp)->numbr; if (arg < 0.0) warning(_("log: received negative argument %g"), arg); d = log(arg); @@ -558,6 +568,42 @@ do_log(int nargs) } +#ifdef HAVE_MPFR + +/* + * mpz2mpfr --- convert an arbitrary-precision integer to a float + * without any loss of precision. The returned value is only + * good for temporary use. + */ + + +static mpfr_ptr +mpz2mpfr(mpz_ptr zi) +{ + size_t prec; + static mpfr_t mpfrval; + static bool inited = false; + int tval; + + /* estimate minimum precision for exact conversion */ + prec = mpz_sizeinbase(zi, 2); /* most significant 1 bit position starting at 1 */ + prec -= (size_t) mpz_scan1(zi, 0); /* least significant 1 bit index starting at 0 */ + if (prec < MPFR_PREC_MIN) + prec = MPFR_PREC_MIN; + else if (prec > MPFR_PREC_MAX) + prec = MPFR_PREC_MAX; + + if (! inited) { + mpfr_init2(mpfrval, prec); + inited = true; + } else + mpfr_set_prec(mpfrval, prec); + tval = mpfr_set_z(mpfrval, zi, ROUND_MODE); + IEEE_FMT(mpfrval, tval); + return mpfrval; +} +#endif + /* * format_tree() formats arguments of sprintf, * and accordingly to a fmt_string providing a format like in @@ -615,8 +661,8 @@ format_tree( size_t cur_arg = 0; NODE *r = NULL; - int i; - int toofew = FALSE; + int i, nc; + bool toofew = false; char *obuf, *obufout; size_t osiz, ofre; const char *chbuf; @@ -624,11 +670,11 @@ format_tree( int cs1; NODE *arg; long fw, prec, argnum; - int used_dollar; - int lj, alt, big_flag, bigbig_flag, small_flag, have_prec, need_format; + bool used_dollar; + bool lj, alt, big_flag, bigbig_flag, small_flag, have_prec, need_format; long *cur = NULL; uintmax_t uval; - int sgn; + bool sgn; int base; /* * Although this is an array, the elements serve two different @@ -647,14 +693,20 @@ format_tree( char *cend = &cpbufs[0].stackbuf[sizeof(cpbufs[0].stackbuf)]; char *cp; const char *fill; - AWKNUM tmpval; - char signchar = FALSE; + AWKNUM tmpval = 0.0; + char signchar = '\0'; size_t len; - int zero_flag = FALSE; - int quote_flag = FALSE; + bool zero_flag = false; + bool quote_flag = false; int ii, jj; char *chp; size_t copy_count, char_count; +#ifdef HAVE_MPFR + mpz_ptr zi; + mpfr_ptr mf; +#endif + enum { MP_INT_WITH_PREC = 1, MP_INT_WITHOUT_PREC, MP_FLOAT } fmt_type; + static const char sp[] = " "; static const char zero_string[] = "0"; static const char lchbuf[] = "0123456789abcdef"; @@ -717,7 +769,7 @@ format_tree( goto out; \ } else if (cur_arg >= num_args) { \ arg = 0; /* shutup the compiler */ \ - toofew = TRUE; \ + toofew = true; \ break; \ } else { \ arg = the_args[cur_arg]; \ @@ -725,8 +777,8 @@ format_tree( } \ } - need_format = FALSE; - used_dollar = FALSE; + need_format = false; + used_dollar = false; s0 = s1 = fmt_string; while (n0-- > 0) { @@ -734,7 +786,7 @@ format_tree( s1++; continue; } - need_format = TRUE; + need_format = true; bchunk(s0, s1 - s0); s0 = s1; cur = &fw; @@ -742,11 +794,18 @@ format_tree( prec = 0; base = 0; argnum = 0; - have_prec = FALSE; - signchar = FALSE; - zero_flag = FALSE; - quote_flag = FALSE; - lj = alt = big_flag = bigbig_flag = small_flag = FALSE; + base = 0; + have_prec = false; + signchar = '\0'; + zero_flag = false; + quote_flag = false; +#ifdef HAVE_MPFR + mf = NULL; + zi = NULL; +#endif + fmt_type = 0; + + lj = alt = big_flag = bigbig_flag = small_flag = false; fill = sp; cp = cend; chbuf = lchbuf; @@ -763,7 +822,7 @@ check_pos: break; /* reject as a valid format */ goto retry; case '%': - need_format = FALSE; + need_format = false; /* * 29 Oct. 2002: * The C99 standard pages 274 and 279 seem to imply that @@ -795,7 +854,7 @@ check_pos: * screws up floating point formatting. */ if (cur == & fw) - zero_flag = TRUE; + zero_flag = true; if (lj) goto retry; /* FALL through */ @@ -822,7 +881,7 @@ check_pos: *cur = *cur * 10 + *s1++ - '0'; } if (prec < 0) /* negative precision is discarded */ - have_prec = FALSE; + have_prec = false; if (cur == &prec) cur = NULL; if (n0 == 0) /* badly formatted control string */ @@ -837,7 +896,7 @@ check_pos: if (cur == &fw) { argnum = fw; fw = 0; - used_dollar = TRUE; + used_dollar = true; if (argnum <= 0) { msg(_("fatal: arg count with `$' must be > 0")); goto out; @@ -870,30 +929,31 @@ check_pos: n0--; } if (val >= num_args) { - toofew = TRUE; + toofew = true; break; } arg = the_args[val]; } else { parse_next_arg(); } - *cur = force_number(arg); + (void) force_number(arg); + *cur = get_number_si(arg); if (*cur < 0 && cur == &fw) { *cur = -*cur; lj++; } if (cur == &prec) { if (*cur >= 0) - have_prec = TRUE; + have_prec = true; else - have_prec = FALSE; + have_prec = false; cur = NULL; } goto retry; case ' ': /* print ' ' or '-' */ /* 'space' flag is ignored */ /* if '+' already present */ - if (signchar != FALSE) + if (signchar != false) goto check_pos; /* FALL THROUGH */ case '+': /* print '+' or '-' */ @@ -913,16 +973,16 @@ check_pos: if (cur != &fw) break; cur = ≺ - have_prec = TRUE; + have_prec = true; goto retry; case '#': - alt = TRUE; + alt = true; goto check_pos; case '\'': #if defined(HAVE_LOCALE_H) /* allow quote_flag if there is a thousands separator. */ if (loc.thousands_sep[0] != '\0') - quote_flag = TRUE; + quote_flag = true; goto check_pos; #else goto retry; @@ -931,61 +991,61 @@ check_pos: if (big_flag) break; else { - static short warned = FALSE; + static bool warned = false; if (do_lint && ! warned) { lintwarn(_("`l' is meaningless in awk formats; ignored")); - warned = TRUE; + warned = true; } if (do_posix) { msg(_("fatal: `l' is not permitted in POSIX awk formats")); goto out; } } - big_flag = TRUE; + big_flag = true; goto retry; case 'L': if (bigbig_flag) break; else { - static short warned = FALSE; + static bool warned = false; if (do_lint && ! warned) { lintwarn(_("`L' is meaningless in awk formats; ignored")); - warned = TRUE; + warned = true; } if (do_posix) { msg(_("fatal: `L' is not permitted in POSIX awk formats")); goto out; } } - bigbig_flag = TRUE; + bigbig_flag = true; goto retry; case 'h': if (small_flag) break; else { - static short warned = FALSE; + static bool warned = false; if (do_lint && ! warned) { lintwarn(_("`h' is meaningless in awk formats; ignored")); - warned = TRUE; + warned = true; } if (do_posix) { msg(_("fatal: `h' is not permitted in POSIX awk formats")); goto out; } } - small_flag = TRUE; + small_flag = true; goto retry; case 'c': - need_format = FALSE; + 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); if (arg->flags & NUMBER) { - uval = (uintmax_t) arg->numbr; + uval = get_number_uj(arg); #if MBS_SUPPORT if (gawk_mb_cur_max > 1) { char buf[100]; @@ -1052,7 +1112,7 @@ out2: prec = 1; goto pr_tail; case 's': - need_format = FALSE; + need_format = false; parse_next_arg(); arg = force_string(arg); if (fw == 0 && ! have_prec) @@ -1066,9 +1126,18 @@ out2: goto pr_tail; case 'd': case 'i': - need_format = FALSE; + need_format = false; parse_next_arg(); - tmpval = force_number(arg); + (void) force_number(arg); +#ifdef HAVE_MPFR + if (is_mpg_float(arg)) + goto mpf0; + else if (is_mpg_integer(arg)) + goto mpz0; + else +#endif + tmpval = arg->numbr; + /* * Check for Nan or Inf. */ @@ -1086,12 +1155,12 @@ out2: if (tmpval < 0) { tmpval = -tmpval; - sgn = TRUE; + sgn = true; } else { if (tmpval == -0.0) /* avoid printing -0 */ tmpval = 0.0; - sgn = FALSE; + sgn = false; } /* * Use snprintf return value to tell if there @@ -1127,7 +1196,7 @@ out2: if (loc.grouping[ii+1] == 0) jj = 0; /* keep using current val in loc.grouping[ii] */ else if (loc.grouping[ii+1] == CHAR_MAX) - quote_flag = FALSE; + quote_flag = false; else { ii++; jj = 0; @@ -1177,9 +1246,80 @@ out2: base += 2; /* FALL THROUGH */ case 'o': base += 8; - need_format = FALSE; + need_format = false; parse_next_arg(); - tmpval = force_number(arg); + (void) force_number(arg); +#ifdef HAVE_MPFR + if (is_mpg_integer(arg)) { +mpz0: + zi = arg->mpg_i; + + if (cs1 != 'd' && cs1 != 'i') { + if (mpz_sgn(zi) <= 0) { + /* + * Negative value or 0 requires special handling. + * Unlike MPFR, GMP does not allow conversion + * to (u)intmax_t. So we first convert GMP type to + * a MPFR type. + */ + mf = mpz2mpfr(zi); + goto mpf1; + } + signchar = '\0'; /* Don't print '+' */ + } + + /* See comments above about when to fill with zeros */ + zero_flag = (! lj + && ((zero_flag && ! have_prec) + || (fw == 0 && have_prec))); + + fmt_type = have_prec ? MP_INT_WITH_PREC : MP_INT_WITHOUT_PREC; + goto fmt0; + + } else if (is_mpg_float(arg)) { +mpf0: + mf = arg->mpg_numbr; + if (! mpfr_number_p(mf)) { + /* inf or NaN */ + cs1 = 'g'; + fmt_type = MP_FLOAT; + goto fmt1; + } + + if (cs1 != 'd' && cs1 != 'i') { +mpf1: + /* + * The output of printf("%#.0x", 0) is 0 instead of 0x, hence <= in + * the comparison below. + */ + if (mpfr_sgn(mf) <= 0) { + if (! mpfr_fits_intmax_p(mf, ROUND_MODE)) { + /* -ve number is too large */ + cs1 = 'g'; + fmt_type = MP_FLOAT; + goto fmt1; + } + + tmpval = uval = (uintmax_t) mpfr_get_sj(mf, ROUND_MODE); + if (! alt && have_prec && prec == 0 && tmpval == 0) + goto pr_tail; /* printf("%.0x", 0) is no characters */ + goto int0; + } + signchar = '\0'; /* Don't print '+' */ + } + + /* See comments above about when to fill with zeros */ + zero_flag = (! lj + && ((zero_flag && ! have_prec) + || (fw == 0 && have_prec))); + + (void) mpfr_get_z(mpzval, mf, MPFR_RNDZ); /* convert to GMP integer */ + fmt_type = have_prec ? MP_INT_WITH_PREC : MP_INT_WITHOUT_PREC; + zi = mpzval; + goto fmt0; + } else +#endif + tmpval = arg->numbr; /* * ``The result of converting a zero value with a @@ -1198,14 +1338,16 @@ out2: if (tmpval < 0) { uval = (uintmax_t) (intmax_t) tmpval; - if ((AWKNUM)(intmax_t)uval != - double_to_int(tmpval)) + if ((AWKNUM)(intmax_t)uval != double_to_int(tmpval)) goto out_of_range; } else { uval = (uintmax_t) tmpval; if ((AWKNUM)uval != double_to_int(tmpval)) goto out_of_range; } +#ifdef HAVE_MPFR + int0: +#endif /* * When to fill with zeroes is of course not simple. * First: No zero fill if left-justifying. @@ -1229,7 +1371,7 @@ out2: if (loc.grouping[ii+1] == 0) jj = 0; /* keep using current val in loc.grouping[ii] */ else if (loc.grouping[ii+1] == CHAR_MAX) - quote_flag = FALSE; + quote_flag = false; else { ii++; jj = 0; @@ -1288,7 +1430,7 @@ out2: lintwarn(_("[s]printf: value %g is out of range for `%%%c' format"), (double) tmpval, cs1); cs1 = 'g'; - goto format_float; + goto fmt1; case 'F': #if ! defined(PRINTF_HAS_F_FORMAT) || PRINTF_HAS_F_FORMAT != 1 @@ -1300,13 +1442,30 @@ out2: case 'e': case 'f': case 'E': - need_format = FALSE; + need_format = false; parse_next_arg(); - tmpval = force_number(arg); - format_float: + (void) force_number(arg); + + if (! is_mpg_number(arg)) + tmpval = arg->numbr; +#ifdef HAVE_MPFR + else if (is_mpg_float(arg)) { + mf = arg->mpg_numbr; + fmt_type = MP_FLOAT; + } else { + /* arbitrary-precision integer, convert to MPFR float */ + assert(mf == NULL); + mf = mpz2mpfr(arg->mpg_i); + fmt_type = MP_FLOAT; + } +#endif + fmt1: if (! have_prec) prec = DEFAULT_G_PRECISION; - chksize(fw + prec + 9); /* 9 == slop */ +#ifdef HAVE_MPFR + fmt0: +#endif + chksize(fw + prec + 11); /* 11 == slop */ cp = cpbuf; *cp++ = '%'; if (lj) @@ -1319,25 +1478,46 @@ out2: *cp++ = '0'; if (quote_flag) *cp++ = '\''; - strcpy(cp, "*.*"); - cp += 3; - *cp++ = cs1; - *cp = '\0'; + #if defined(LC_NUMERIC) if (quote_flag && ! use_lc_numeric) setlocale(LC_NUMERIC, ""); #endif - { - int n; - while ((n = snprintf(obufout, ofre, cpbuf, - (int) fw, (int) prec, - (double) tmpval)) >= ofre) - chksize(n) + + switch (fmt_type) { +#ifdef HAVE_MPFR + case MP_INT_WITH_PREC: + sprintf(cp, "*.*Z%c", cs1); + while ((nc = mpfr_snprintf(obufout, ofre, cpbuf, + (int) fw, (int) prec, zi)) >= ofre) + chksize(nc) + break; + case MP_INT_WITHOUT_PREC: + sprintf(cp, "*Z%c", cs1); + while ((nc = mpfr_snprintf(obufout, ofre, cpbuf, + (int) fw, zi)) >= ofre) + chksize(nc) + break; + case MP_FLOAT: + sprintf(cp, "*.*R*%c", cs1); + while ((nc = mpfr_snprintf(obufout, ofre, cpbuf, + (int) fw, (int) prec, ROUND_MODE, mf)) >= ofre) + chksize(nc) + break; +#endif + default: + sprintf(cp, "*.*%c", cs1); + while ((nc = snprintf(obufout, ofre, cpbuf, + (int) fw, (int) prec, + (double) tmpval)) >= ofre) + chksize(nc) } + #if defined(LC_NUMERIC) if (quote_flag && ! use_lc_numeric) setlocale(LC_NUMERIC, "C"); #endif + len = strlen(obufout); ofre -= len; obufout += len; @@ -1378,6 +1558,7 @@ out: if (obuf != NULL) efree(obuf); } + if (r == NULL) gawk_exit(EXIT_FATAL); return r; @@ -1402,7 +1583,7 @@ printf_common(int nargs) } } - force_string(args_array[0]); + args_array[0] = force_string(args_array[0]); r = format_tree(args_array[0]->stptr, args_array[0]->stlen, args_array, nargs); for (i = 0; i < nargs; i++) DEREF(args_array[i]); @@ -1456,7 +1637,7 @@ do_printf(int nargs, int redirtype) fatal(_("attempt to use array `%s' in a scalar context"), array_vname(redir_exp)); rp = redirect(redir_exp, redirtype, & errflg); if (rp != NULL) - fp = rp->fp; + fp = rp->output.fp; } else fp = output_fp; @@ -1470,9 +1651,9 @@ do_printf(int nargs, int redirtype) DEREF(tmp); return; } - efwrite(tmp->stptr, sizeof(char), tmp->stlen, fp, "printf", rp, TRUE); + efwrite(tmp->stptr, sizeof(char), tmp->stlen, fp, "printf", rp, true); if (rp != NULL && (rp->flag & RED_TWOWAY) != 0) - fflush(rp->fp); + rp->output.gawk_fflush(rp->output.fp, rp->output.opaque); DEREF(tmp); } else gawk_exit(EXIT_FATAL); @@ -1489,7 +1670,7 @@ do_sqrt(int nargs) tmp = POP_SCALAR(); if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) lintwarn(_("sqrt: received non-numeric argument")); - arg = (double) force_number(tmp); + arg = (double) force_number(tmp)->numbr; DEREF(tmp); if (arg < 0.0) warning(_("sqrt: called with negative argument %g"), arg); @@ -1508,19 +1689,26 @@ do_substr(int nargs) double d_index = 0, d_length = 0; size_t src_len; - if (nargs == 3) - POP_NUMBER(d_length); - POP_NUMBER(d_index); + if (nargs == 3) { + t1 = POP_NUMBER(); + d_length = get_number_d(t1); + DEREF(t1); + } + + t1 = POP_NUMBER(); + d_index = get_number_d(t1); + DEREF(t1); + t1 = POP_STRING(); if (nargs == 3) { if (! (d_length >= 1)) { - if (do_lint == LINT_ALL) + if (do_lint == DO_LINT_ALL) lintwarn(_("substr: length %g is not >= 1"), d_length); - else if (do_lint == LINT_INVALID && ! (d_length >= 0)) + else if (do_lint == DO_LINT_INVALID && ! (d_length >= 0)) lintwarn(_("substr: length %g is not >= 0"), d_length); DEREF(t1); - return Nnull_string; + return dupnode(Nnull_string); } if (do_lint) { if (double_to_int(d_length) != d_length) @@ -1571,10 +1759,10 @@ do_substr(int nargs) if (t1->stlen == 0) { /* substr("", 1, 0) produces a warning only if LINT_ALL */ - if (do_lint && (do_lint == LINT_ALL || ((indx | length) != 0))) + if (do_lint && (do_lint == DO_LINT_ALL || ((indx | length) != 0))) lintwarn(_("substr: source string is zero length")); DEREF(t1); - return Nnull_string; + return dupnode(Nnull_string); } /* get total len of input string, for following checks */ @@ -1591,7 +1779,7 @@ do_substr(int nargs) lintwarn(_("substr: start index %g is past end of string"), d_index); DEREF(t1); - return Nnull_string; + return dupnode(Nnull_string); } if (length > src_len - indx) { if (do_lint) @@ -1661,7 +1849,7 @@ do_strftime(int nargs) format = def_strftime_format; /* traditional date format */ formatlen = strlen(format); (void) time(& fclock); /* current time of day */ - do_gmt = FALSE; + do_gmt = false; if (PROCINFO_node != NULL) { sub = make_string("strftime", 8); @@ -1689,12 +1877,13 @@ do_strftime(int nargs) do_gmt = (t3->stlen > 0); DEREF(t3); } - + if (nargs >= 2) { t2 = POP_SCALAR(); if (do_lint && (t2->flags & (NUMCUR|NUMBER)) == 0) lintwarn(_("strftime: received non-numeric second argument")); - clock_val = (long) force_number(t2); + (void) force_number(t2); + clock_val = get_number_si(t2); if (clock_val < 0) fatal(_("strftime: second argument less than 0 or too big for time_t")); fclock = (time_t) clock_val; @@ -1704,6 +1893,7 @@ do_strftime(int nargs) tmp = POP_SCALAR(); if (do_lint && (tmp->flags & (STRING|STRCUR)) == 0) lintwarn(_("strftime: received non-string first argument")); + t1 = force_string(tmp); format = t1->stptr; formatlen = t1->stlen; @@ -1786,13 +1976,13 @@ do_mktime(int nargs) & hour, & minute, & second, & dst); - if (do_lint /* Ready? Set! Go: */ - && ( (second < 0 || second > 60) - || (minute < 0 || minute > 60) - || (hour < 0 || hour > 23) - || (day < 1 || day > 31) - || (month < 1 || month > 12) )) - lintwarn(_("mktime: at least one of the values is out of the default range")); + if (do_lint /* Ready? Set! Go: */ + && ( (second < 0 || second > 60) + || (minute < 0 || minute > 60) + || (hour < 0 || hour > 23) + || (day < 1 || day > 31) + || (month < 1 || month > 12) )) + lintwarn(_("mktime: at least one of the values is out of the default range")); t1->stptr[t1->stlen] = save; DEREF(t1); @@ -1853,11 +2043,9 @@ do_system(int nargs) return make_number((AWKNUM) ret); } -extern NODE **fmt_list; /* declared in eval.c */ - /* do_print --- print items, separated by OFS, terminated with ORS */ -void +void do_print(int nargs, int redirtype) { struct redirect *rp = NULL; @@ -1865,7 +2053,7 @@ do_print(int nargs, int redirtype) FILE *fp = NULL; int i; NODE *redir_exp = NULL; - NODE *tmp; + NODE *tmp = NULL; assert(nargs <= max_args); @@ -1875,7 +2063,7 @@ do_print(int nargs, int redirtype) fatal(_("attempt to use array `%s' in a scalar context"), array_vname(redir_exp)); rp = redirect(redir_exp, redirtype, & errflg); if (rp != NULL) - fp = rp->fp; + fp = rp->output.fp; } else fp = output_fp; @@ -1886,12 +2074,10 @@ do_print(int nargs, int redirtype) DEREF(args_array[i]); fatal(_("attempt to use array `%s' in a scalar context"), array_vname(tmp)); } - if (do_lint && tmp->type == Node_var_new) - lintwarn(_("reference to uninitialized variable `%s'"), - tmp->vname); + if ((tmp->flags & (NUMBER|STRING)) == NUMBER) { if (OFMTidx == CONVFMTidx) - (void) force_string(tmp); + args_array[i] = force_string(tmp); else args_array[i] = format_val(OFMT, OFMTidx, tmp); } @@ -1909,18 +2095,18 @@ do_print(int nargs, int redirtype) } for (i = nargs; i > 0; i--) { - efwrite(args_array[i]->stptr, sizeof(char), args_array[i]->stlen, fp, "print", rp, FALSE); + efwrite(args_array[i]->stptr, sizeof(char), args_array[i]->stlen, fp, "print", rp, false); DEREF(args_array[i]); if (i != 1 && OFSlen > 0) efwrite(OFS, sizeof(char), (size_t) OFSlen, - fp, "print", rp, FALSE); + fp, "print", rp, false); } if (ORSlen > 0) - efwrite(ORS, sizeof(char), (size_t) ORSlen, fp, "print", rp, TRUE); + efwrite(ORS, sizeof(char), (size_t) ORSlen, fp, "print", rp, true); if (rp != NULL && (rp->flag & RED_TWOWAY) != 0) - fflush(rp->fp); + rp->output.gawk_fflush(rp->output.fp, rp->output.opaque); } /* do_print_rec --- special case printing of $0, for speed */ @@ -1939,7 +2125,7 @@ do_print_rec(int nargs, int redirtype) redir_exp = TOP(); rp = redirect(redir_exp, redirtype, & errflg); if (rp != NULL) - fp = rp->fp; + fp = rp->output.fp; DEREF(redir_exp); decr_sp(); } else @@ -1956,13 +2142,13 @@ do_print_rec(int nargs, int redirtype) if (do_lint && f0 == Nnull_string) lintwarn(_("reference to uninitialized field `$%d'"), 0); - efwrite(f0->stptr, sizeof(char), f0->stlen, fp, "print", rp, FALSE); + efwrite(f0->stptr, sizeof(char), f0->stlen, fp, "print", rp, false); if (ORSlen > 0) - efwrite(ORS, sizeof(char), (size_t) ORSlen, fp, "print", rp, TRUE); + efwrite(ORS, sizeof(char), (size_t) ORSlen, fp, "print", rp, true); if (rp != NULL && (rp->flag & RED_TWOWAY) != 0) - fflush(rp->fp); + rp->output.gawk_fflush(rp->output.fp, rp->output.opaque); } #if MBS_SUPPORT @@ -2115,8 +2301,8 @@ do_atan2(int nargs) if ((t2->flags & (NUMCUR|NUMBER)) == 0) lintwarn(_("atan2: received non-numeric second argument")); } - d1 = force_number(t1); - d2 = force_number(t2); + d1 = force_number(t1)->numbr; + d2 = force_number(t2)->numbr; DEREF(t1); DEREF(t2); return make_number((AWKNUM) atan2(d1, d2)); @@ -2133,7 +2319,7 @@ do_sin(int nargs) tmp = POP_SCALAR(); if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) lintwarn(_("sin: received non-numeric argument")); - d = sin((double) force_number(tmp)); + d = sin((double) force_number(tmp)->numbr); DEREF(tmp); return make_number((AWKNUM) d); } @@ -2149,14 +2335,14 @@ do_cos(int nargs) tmp = POP_SCALAR(); if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) lintwarn(_("cos: received non-numeric argument")); - d = cos((double) force_number(tmp)); + d = cos((double) force_number(tmp)->numbr); DEREF(tmp); return make_number((AWKNUM) d); } /* do_rand --- do the rand function */ -static int firstrand = TRUE; +static bool firstrand = true; /* Some systems require this array to be integer aligned. Sigh. */ #define SIZEOF_STATE 256 static uint32_t istate[SIZEOF_STATE/sizeof(uint32_t)]; @@ -2169,7 +2355,7 @@ do_rand(int nargs ATTRIBUTE_UNUSED) if (firstrand) { (void) initstate((unsigned) 1, state, SIZEOF_STATE); /* don't need to srandom(1), initstate() does it for us. */ - firstrand = FALSE; + firstrand = false; setstate(state); } /* @@ -2192,7 +2378,7 @@ do_srand(int nargs) if (firstrand) { (void) initstate((unsigned) 1, state, SIZEOF_STATE); /* don't need to srandom(1), we're changing the seed below */ - firstrand = FALSE; + firstrand = false; (void) setstate(state); } @@ -2202,7 +2388,7 @@ do_srand(int nargs) tmp = POP_SCALAR(); if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) lintwarn(_("srand: received non-numeric argument")); - srandom((unsigned int) (save_seed = (long) force_number(tmp))); + srandom((unsigned int) (save_seed = (long) force_number(tmp)->numbr)); DEREF(tmp); } return make_number((AWKNUM) ret); @@ -2283,7 +2469,7 @@ do_match(int nargs) it->flags |= MAYBE_NUM; /* user input */ sub = make_number((AWKNUM) (ii)); - lhs = assoc_lookup(dest, sub, FALSE); + lhs = assoc_lookup(dest, sub); unref(*lhs); *lhs = it; unref(sub); @@ -2306,7 +2492,7 @@ do_match(int nargs) it = make_number((AWKNUM) subpat_start + 1); sub = make_string(buf, slen); - lhs = assoc_lookup(dest, sub, FALSE); + lhs = assoc_lookup(dest, sub); unref(*lhs); *lhs = it; unref(sub); @@ -2319,7 +2505,7 @@ do_match(int nargs) it = make_number((AWKNUM) subpat_len); sub = make_string(buf, slen); - lhs = assoc_lookup(dest, sub, FALSE); + lhs = assoc_lookup(dest, sub); unref(*lhs); *lhs = it; unref(sub); @@ -2353,7 +2539,7 @@ do_match(int nargs) * #! /usr/local/bin/mawk -f * * BEGIN { - * TRUE = 1; FALSE = 0 + * true = 1; false = 0 * print "--->", mygsub("abc", "b+", "FOO") * print "--->", mygsub("abc", "x*", "X") * print "--->", mygsub("abc", "b*", "X") @@ -2365,10 +2551,10 @@ do_match(int nargs) * function mygsub(str, regex, replace, origstr, newstr, eosflag, nonzeroflag) * { * origstr = str; - * eosflag = nonzeroflag = FALSE + * eosflag = nonzeroflag = false * while (match(str, regex)) { * if (RLENGTH > 0) { # easy case - * nonzeroflag = TRUE + * nonzeroflag = true * if (RSTART == 1) { # match at front of string * newstr = newstr replace * } else { @@ -2381,7 +2567,7 @@ do_match(int nargs) * # which we don't really want, so skip over it * newstr = newstr substr(str, 1, 1) * str = substr(str, 2) - * nonzeroflag = FALSE + * nonzeroflag = false * } else { * # 0-length match * if (RSTART == 1) { @@ -2395,7 +2581,7 @@ do_match(int nargs) * if (eosflag) * break * else - * eosflag = TRUE + * eosflag = true * } * if (length(str) > 0) * newstr = newstr str # rest of string @@ -2462,7 +2648,7 @@ do_sub(int nargs, unsigned int flags) long how_many = 1; /* one substitution for sub, also gensub default */ int global; long current; - int lastmatchnonzero; + bool lastmatchnonzero; char *mb_indices = NULL; if ((flags & GENSUB) != 0) { @@ -2479,15 +2665,16 @@ do_sub(int nargs, unsigned int flags) if (t1->stlen > 0 && (t1->stptr[0] == 'g' || t1->stptr[0] == 'G')) how_many = -1; else { - d = force_number(t1); - + (void) force_number(t1); + d = get_number_d(t1); if ((t1->flags & NUMCUR) != 0) goto set_how_many; how_many = 1; } } else { - d = force_number(t1); + (void) force_number(t1); + d = get_number_d(t1); set_how_many: if (d < 1) how_many = 1; @@ -2599,7 +2786,7 @@ set_how_many: } } - lastmatchnonzero = FALSE; + lastmatchnonzero = false; bp = buf; for (current = 1;; current++) { matches++; @@ -2631,7 +2818,7 @@ set_how_many: if (matchstart == matchend && lastmatchnonzero && matchstart == text) { - lastmatchnonzero = FALSE; + lastmatchnonzero = false; matches--; goto empty; } @@ -2700,7 +2887,7 @@ set_how_many: } else *bp++ = *scan; if (matchstart != matchend) - lastmatchnonzero = TRUE; + lastmatchnonzero = true; } else { /* * don't want this match, skip over it by copying @@ -2793,8 +2980,8 @@ do_lshift(int nargs) if ((s2->flags & (NUMCUR|NUMBER)) == 0) lintwarn(_("lshift: received non-numeric second argument")); } - val = force_number(s1); - shift = force_number(s2); + val = force_number(s1)->numbr; + shift = force_number(s2)->numbr; if (do_lint) { if (val < 0 || shift < 0) lintwarn(_("lshift(%f, %f): negative values will give strange results"), val, shift); @@ -2830,8 +3017,8 @@ do_rshift(int nargs) if ((s2->flags & (NUMCUR|NUMBER)) == 0) lintwarn(_("rshift: received non-numeric second argument")); } - val = force_number(s1); - shift = force_number(s2); + val = force_number(s1)->numbr; + shift = force_number(s2)->numbr; if (do_lint) { if (val < 0 || shift < 0) lintwarn(_("rshift(%f, %f): negative values will give strange results"), val, shift); @@ -2856,33 +3043,30 @@ do_rshift(int nargs) NODE * do_and(int nargs) { - NODE *s1, *s2; - uintmax_t uleft, uright, res; - AWKNUM left, right; + NODE *s1; + uintmax_t res, uval; + AWKNUM val; + int i; - POP_TWO_SCALARS(s1, s2); - if (do_lint) { - if ((s1->flags & (NUMCUR|NUMBER)) == 0) - lintwarn(_("and: received non-numeric first argument")); - if ((s2->flags & (NUMCUR|NUMBER)) == 0) - lintwarn(_("and: received non-numeric second argument")); - } - left = force_number(s1); - right = force_number(s2); - if (do_lint) { - if (left < 0 || right < 0) - lintwarn(_("and(%f, %f): negative values will give strange results"), left, right); - if (double_to_int(left) != left || double_to_int(right) != right) - lintwarn(_("and(%f, %f): fractional values will be truncated"), left, right); - } + res = ~0; /* start off with all ones */ + if (nargs < 2) + fatal(_("and: called with less than two arguments")); - DEREF(s1); - DEREF(s2); + for (i = 1; nargs > 0; nargs--, i++) { + s1 = POP_SCALAR(); + if (do_lint && (s1->flags & (NUMCUR|NUMBER)) == 0) + lintwarn(_("and: argument %d is non-numeric"), i); - uleft = (uintmax_t) left; - uright = (uintmax_t) right; + val = force_number(s1)->numbr; + if (do_lint && val < 0) + lintwarn(_("and: argument %d negative value %g will give strange results"), i, val); + + uval = (uintmax_t) val; + res &= uval; + + DEREF(s1); + } - res = uleft & uright; return make_integer(res); } @@ -2891,33 +3075,30 @@ do_and(int nargs) NODE * do_or(int nargs) { - NODE *s1, *s2; - uintmax_t uleft, uright, res; - AWKNUM left, right; + NODE *s1; + uintmax_t res, uval; + AWKNUM val; + int i; - POP_TWO_SCALARS(s1, s2); - if (do_lint) { - if ((s1->flags & (NUMCUR|NUMBER)) == 0) - lintwarn(_("or: received non-numeric first argument")); - if ((s2->flags & (NUMCUR|NUMBER)) == 0) - lintwarn(_("or: received non-numeric second argument")); - } - left = force_number(s1); - right = force_number(s2); - if (do_lint) { - if (left < 0 || right < 0) - lintwarn(_("or(%f, %f): negative values will give strange results"), left, right); - if (double_to_int(left) != left || double_to_int(right) != right) - lintwarn(_("or(%f, %f): fractional values will be truncated"), left, right); - } + res = 0; + if (nargs < 2) + fatal(_("or: called with less than two arguments")); - DEREF(s1); - DEREF(s2); + for (i = 1; nargs > 0; nargs--, i++) { + s1 = POP_SCALAR(); + if (do_lint && (s1->flags & (NUMCUR|NUMBER)) == 0) + lintwarn(_("or: argument %d is non-numeric"), i); - uleft = (uintmax_t) left; - uright = (uintmax_t) right; + val = force_number(s1)->numbr; + if (do_lint && val < 0) + lintwarn(_("or: argument %d negative value %g will give strange results"), i, val); + + uval = (uintmax_t) val; + res |= uval; + + DEREF(s1); + } - res = uleft | uright; return make_integer(res); } @@ -2926,36 +3107,33 @@ do_or(int nargs) NODE * do_xor(int nargs) { - NODE *s1, *s2; - uintmax_t uleft, uright, res; - AWKNUM left, right; + NODE *s1; + uintmax_t res, uval; + AWKNUM val; + int i; - POP_TWO_SCALARS(s1, s2); - left = force_number(s1); - right = force_number(s2); + if (nargs < 2) + fatal(_("xor: called with less than two arguments")); - if (do_lint) { - if ((s1->flags & (NUMCUR|NUMBER)) == 0) - lintwarn(_("xor: received non-numeric first argument")); - if ((s2->flags & (NUMCUR|NUMBER)) == 0) - lintwarn(_("xor: received non-numeric second argument")); - } - left = force_number(s1); - right = force_number(s2); - if (do_lint) { - if (left < 0 || right < 0) - lintwarn(_("xor(%f, %f): negative values will give strange results"), left, right); - if (double_to_int(left) != left || double_to_int(right) != right) - lintwarn(_("xor(%f, %f): fractional values will be truncated"), left, right); - } + res = 0; /* silence compiler warning */ + for (i = 1; nargs > 0; nargs--, i++) { + s1 = POP_SCALAR(); + if (do_lint && (s1->flags & (NUMCUR|NUMBER)) == 0) + lintwarn(_("xor: argument %d is non-numeric"), i); - DEREF(s1); - DEREF(s2); + val = force_number(s1)->numbr; + if (do_lint && val < 0) + lintwarn(_("xor: argument %d negative value %g will give strange results"), i, val); - uleft = (uintmax_t) left; - uright = (uintmax_t) right; + uval = (uintmax_t) val; + if (i == 1) + res = uval; + else + res ^= uval; + + DEREF(s1); + } - res = uleft ^ uright; return make_integer(res); } @@ -2971,12 +3149,10 @@ do_compl(int nargs) tmp = POP_SCALAR(); if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) lintwarn(_("compl: received non-numeric argument")); - d = force_number(tmp); + d = force_number(tmp)->numbr; DEREF(tmp); if (do_lint) { - if ((tmp->flags & (NUMCUR|NUMBER)) == 0) - lintwarn(_("compl: received non-numeric argument")); if (d < 0) lintwarn(_("compl(%f): negative value will give strange results"), d); if (double_to_int(d) != d) @@ -2998,11 +3174,11 @@ do_strtonum(int nargs) tmp = POP_SCALAR(); if ((tmp->flags & (NUMBER|NUMCUR)) != 0) - d = (AWKNUM) force_number(tmp); - else if (isnondecimal(tmp->stptr, use_lc_numeric)) + d = (AWKNUM) force_number(tmp)->numbr; + else if (get_numbase(tmp->stptr, use_lc_numeric) != 10) d = nondec2awknum(tmp->stptr, tmp->stlen); else - d = (AWKNUM) force_number(tmp); + d = (AWKNUM) force_number(tmp)->numbr; DEREF(tmp); return make_number((AWKNUM) d); @@ -3252,7 +3428,10 @@ do_dcngettext(int nargs) } #endif - POP_NUMBER(d); /* third argument */ + t2 = POP_NUMBER(); /* third argument */ + d = get_number_d(t2); + DEREF(t2); + number = (unsigned long) double_to_int(d); t2 = POP_STRING(); /* second argument */ string2 = t2->stptr; |