aboutsummaryrefslogtreecommitdiffstats
path: root/builtin.c
diff options
context:
space:
mode:
Diffstat (limited to 'builtin.c')
-rw-r--r--builtin.c509
1 files changed, 378 insertions, 131 deletions
diff --git a/builtin.c b/builtin.c
index 0163b81c..b295cd24 100644
--- a/builtin.c
+++ b/builtin.c
@@ -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;
+}