aboutsummaryrefslogtreecommitdiffstats
path: root/builtin.c
diff options
context:
space:
mode:
Diffstat (limited to 'builtin.c')
-rw-r--r--builtin.c649
1 files changed, 414 insertions, 235 deletions
diff --git a/builtin.c b/builtin.c
index be99cbca..e883fbcc 100644
--- a/builtin.c
+++ b/builtin.c
@@ -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 = &prec;
- 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;