aboutsummaryrefslogtreecommitdiffstats
path: root/builtin.c
diff options
context:
space:
mode:
Diffstat (limited to 'builtin.c')
-rw-r--r--builtin.c353
1 files changed, 334 insertions, 19 deletions
diff --git a/builtin.c b/builtin.c
index 35402f1e..0686041c 100644
--- a/builtin.c
+++ b/builtin.c
@@ -3,7 +3,7 @@
*/
/*
- * Copyright (C) 1986, 1988, 1989, 1991-1996 the Free Software Foundation, Inc.
+ * Copyright (C) 1986, 1988, 1989, 1991-1997 the Free Software Foundation, Inc.
*
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
@@ -25,6 +25,7 @@
#include "awk.h"
+#include <assert.h>
#undef HUGE
#undef CHARBITS
#undef INTBITS
@@ -871,25 +872,52 @@ NODE *tree;
{
NODE *t1, *t2, *t3;
NODE *r;
- register int indx;
+ register size_t indx;
size_t length;
+ double d_index, d_length;
t1 = force_string(tree_eval(tree->lnode));
t2 = tree_eval(tree->rnode->lnode);
- indx = (int) force_number(t2) - 1;
+ d_index = force_number(t2);
free_temp(t2);
- if (indx < 0) {
+
+ if (d_index < 1.0) {
if (do_lint)
- warning("substr: start index %d invalid, using 1",
- indx+1);
- indx = 0; /* awk indices start at 1, C at 0 */
+ warning("substr: start index %g invalid, using 1",
+ d_index);
+ d_index = 1;
}
+ if (do_lint && double_to_int(d_index) != d_index)
+ warning("substr: non-integer start index %g will be truncated",
+ d_index);
+
+ indx = d_index - 1; /* awk indices are from 1, C's are from 0 */
+
if (tree->rnode->rnode == NULL) { /* third arg. missing */
- length = t1->stlen - indx; /* use remainder of string */
+ /* use remainder of string */
+ length = t1->stlen - indx;
} else {
t3 = tree_eval(tree->rnode->rnode->lnode);
- length = (size_t) force_number(t3);
+ d_length = force_number(t3);
free_temp(t3);
+ if (d_length <= 0.0) {
+ if (do_lint)
+ warning("substr: length %g is <= 0", d_length);
+ free_temp(t1);
+ return Nnull_string;
+ }
+ if (do_lint && double_to_int(d_length) != d_length)
+ warning(
+ "substr: non-integer length %g will be truncated",
+ d_length);
+ length = d_length;
+ }
+
+ if (t1->stlen == 0) {
+ if (do_lint)
+ warning("substr: source string is zero length");
+ free_temp(t1);
+ return Nnull_string;
}
if ((indx + length) > t1->stlen) {
if (do_lint)
@@ -898,12 +926,10 @@ NODE *tree;
length, indx+1, t1->stlen);
length = t1->stlen - indx;
}
- if (indx >= t1->stlen || (long) length <= 0) {
- if (do_lint && indx >= t1->stlen)
- warning("substr: position %d is past end of string",
+ if (indx >= t1->stlen) {
+ if (do_lint)
+ warning("substr: start index %d is past end of string",
indx+1);
- if (do_lint && (long) length <= 0)
- warning("substr: length %d is <= 0", (long) length);
free_temp(t1);
return Nnull_string;
}
@@ -959,16 +985,17 @@ NODE *tree;
bufp = buf;
bufsize = sizeof(buf);
for (;;) {
+ *bufp = '\0';
buflen = strftime(bufp, bufsize, format, tm);
/*
* buflen can be zero EITHER because there's not enough
* room in the string, or because the control command
* goes to the empty string. Make a reasonable guess that
- * if the buffer is 4 times bigger than the length of the
+ * if the buffer is 1024 times bigger than the length of the
* format string, it's not failing for lack of room.
* Thanks to Paul Eggert for pointing out this issue.
*/
- if (buflen > 0 || bufsize >= 4 * formatlen)
+ if (buflen > 0 || bufsize >= 1024 * formatlen)
break;
bufsize *= 2;
if (bufp == buf)
@@ -1081,7 +1108,13 @@ register NODE *tree;
tree = save;
for (i = 0; tree != NULL; i++, tree = tree->rnode) {
- t[i] = tree_eval(tree->lnode);
+ NODE *n;
+
+ /* Here lies the wumpus. R.I.P. */
+ n = tree_eval(tree->lnode);
+ t[i] = dupnode(n);
+ free_temp(n);
+
if (t[i]->flags & NUMBER) {
if (OFMTidx == CONVFMTidx)
(void) force_string(t[i]);
@@ -1092,7 +1125,7 @@ register NODE *tree;
for (i = 0; i < numnodes; i++) {
efwrite(t[i]->stptr, sizeof(char), t[i]->stlen, fp, "print", rp, FALSE);
- free_temp(t[i]);
+ unref(t[i]);
if (i != numnodes - 1) {
if (OFSlen > 0)
efwrite(OFS, sizeof(char), (size_t) OFSlen,
@@ -1389,7 +1422,7 @@ int how_many, backdigs;
/*
* create a private copy of the string
*/
- if (t->stref > 1 || (t->flags & PERM)) {
+ if (t->stref > 1 || (t->flags & (PERM|FIELD)) != 0) {
unsigned int saveflags;
saveflags = t->flags;
@@ -1731,3 +1764,285 @@ double g; /* value to format */
}
}
#endif /* GFMT_WORKAROUND */
+
+#ifdef BITOPS
+#define BITS_PER_BYTE 8 /* if not true, you lose. too bad. */
+
+/* do_lshift --- perform a << operation */
+
+NODE *
+do_lshift(tree)
+NODE *tree;
+{
+ NODE *s1, *s2;
+ unsigned long uval, ushift, result;
+ AWKNUM val, shift;
+
+ s1 = tree_eval(tree->lnode);
+ s2 = tree_eval(tree->rnode->lnode);
+ val = force_number(s1);
+ shift = force_number(s2);
+ free_temp(s1);
+ free_temp(s2);
+
+ if (do_lint) {
+ if (val < 0 || shift < 0)
+ warning("lshift(%lf, %lf): negative values will give strange results", val, shift);
+ if (double_to_int(val) != val || double_to_int(shift) != shift)
+ warning("lshift(%lf, %lf): fractional values will be truncated", val, shift);
+ if (shift > (sizeof(unsigned long) * BITS_PER_BYTE))
+ warning("lshift(%lf, %lf): too large shift value will give strange results", val, shift);
+ }
+
+ uval = (unsigned long) val;
+ ushift = (unsigned long) shift;
+
+ result = uval << ushift;
+ return tmp_number((AWKNUM) result);
+}
+
+/* do_rshift --- perform a >> operation */
+
+NODE *
+do_rshift(tree)
+NODE *tree;
+{
+ NODE *s1, *s2;
+ unsigned long uval, ushift, result;
+ AWKNUM val, shift;
+
+ s1 = tree_eval(tree->lnode);
+ s2 = tree_eval(tree->rnode->lnode);
+ val = force_number(s1);
+ shift = force_number(s2);
+ free_temp(s1);
+ free_temp(s2);
+
+ if (do_lint) {
+ if (val < 0 || shift < 0)
+ warning("rshift(%lf, %lf): negative values will give strange results", val, shift);
+ if (double_to_int(val) != val || double_to_int(shift) != shift)
+ warning("rshift(%lf, %lf): fractional values will be truncated", val, shift);
+ if (shift > (sizeof(unsigned long) * BITS_PER_BYTE))
+ warning("rshift(%lf, %lf): too large shift value will give strange results", val, shift);
+ }
+
+ uval = (unsigned long) val;
+ ushift = (unsigned long) shift;
+
+ result = uval >> ushift;
+ return tmp_number((AWKNUM) result);
+}
+
+/* do_and --- perform an & operation */
+
+NODE *
+do_and(tree)
+NODE *tree;
+{
+ NODE *s1, *s2;
+ unsigned long uleft, uright, result;
+ AWKNUM left, right;
+
+ s1 = tree_eval(tree->lnode);
+ s2 = tree_eval(tree->rnode->lnode);
+ left = force_number(s1);
+ right = force_number(s2);
+ free_temp(s1);
+ free_temp(s2);
+
+ if (do_lint) {
+ if (left < 0 || right < 0)
+ warning("and(%lf, %lf): negative values will give strange results", left, right);
+ if (double_to_int(left) != left || double_to_int(right) != right)
+ warning("and(%lf, %lf): fractional values will be truncated", left, right);
+ }
+
+ uleft = (unsigned long) left;
+ uright = (unsigned long) right;
+
+ result = uleft & uright;
+ return tmp_number((AWKNUM) result);
+}
+
+/* do_or --- perform an | operation */
+
+NODE *
+do_or(tree)
+NODE *tree;
+{
+ NODE *s1, *s2;
+ unsigned long uleft, uright, result;
+ AWKNUM left, right;
+
+ s1 = tree_eval(tree->lnode);
+ s2 = tree_eval(tree->rnode->lnode);
+ left = force_number(s1);
+ right = force_number(s2);
+ free_temp(s1);
+ free_temp(s2);
+
+ if (do_lint) {
+ if (left < 0 || right < 0)
+ warning("or(%lf, %lf): negative values will give strange results", left, right);
+ if (double_to_int(left) != left || double_to_int(right) != right)
+ warning("or(%lf, %lf): fractional values will be truncated", left, right);
+ }
+
+ uleft = (unsigned long) left;
+ uright = (unsigned long) right;
+
+ result = uleft | uright;
+ return tmp_number((AWKNUM) result);
+}
+
+/* do_xor --- perform an ^ operation */
+
+NODE *
+do_xor(tree)
+NODE *tree;
+{
+ NODE *s1, *s2;
+ unsigned long uleft, uright, result;
+ AWKNUM left, right;
+
+ s1 = tree_eval(tree->lnode);
+ s2 = tree_eval(tree->rnode->lnode);
+ left = force_number(s1);
+ right = force_number(s2);
+ free_temp(s1);
+ free_temp(s2);
+
+ if (do_lint) {
+ if (left < 0 || right < 0)
+ warning("xor(%lf, %lf): negative values will give strange results", left, right);
+ if (double_to_int(left) != left || double_to_int(right) != right)
+ warning("xor(%lf, %lf): fractional values will be truncated", left, right);
+ }
+
+ uleft = (unsigned long) left;
+ uright = (unsigned long) right;
+
+ result = uleft ^ uright;
+ return tmp_number((AWKNUM) result);
+}
+
+/* do_compl --- perform a ~ operation */
+
+NODE *
+do_compl(tree)
+NODE *tree;
+{
+ NODE *tmp;
+ double d;
+ unsigned long uval;
+
+ tmp = tree_eval(tree->lnode);
+ d = force_number(tmp);
+ free_temp(tmp);
+
+ if (do_lint) {
+ if (uval < 0)
+ warning("compl(%lf): negative value will give strange results", d);
+ if (double_to_int(d) != d)
+ warning("compl(%lf): fractional value will be truncated", d);
+ }
+
+ uval = (unsigned long) d;
+ uval = ~ uval;
+ return tmp_number((AWKNUM) uval);
+}
+
+/* do_strtonum --- the strtonum function */
+
+NODE *
+do_strtonum(tree)
+NODE *tree;
+{
+ NODE *tmp;
+ double d, arg;
+
+ tmp = tree_eval(tree->lnode);
+
+ if ((tmp->flags & (NUM|NUMBER)) != 0)
+ d = (double) force_number(tmp);
+ else if (isnondecimal(tmp->stptr))
+ d = nondec2awknum(tmp->stptr, tmp->stlen);
+ else
+ d = (double) force_number(tmp);
+
+ free_temp(tmp);
+ return tmp_number((AWKNUM) d);
+}
+#endif /* BITOPS */
+
+#if defined(BITOPS) || defined(NONDECDATA)
+/* nondec2awknum --- convert octal or hex value to double */
+
+/*
+ * Because of awk's concatenation rules and the way awk.y:yylex()
+ * collects a number, this routine has to be willing to stop on the
+ * first invalid character.
+ */
+
+AWKNUM
+nondec2awknum(str, len)
+char *str;
+size_t len;
+{
+ AWKNUM retval = 0.0;
+ char save;
+ short val;
+
+ if (*str == '0' && (str[1] == 'x' || str[1] == 'X')) {
+ assert(len > 2);
+
+ for (str += 2, len -= 2; len > 0; len--, str++) {
+ switch (*str) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ val = *str - '0';
+ break;
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ val = *str - 'a' + 10;
+ break;
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ val = *str - 'A' + 10;
+ break;
+ default:
+ goto done;
+ }
+ retval = (retval * 16) + val;
+ }
+ } else if (*str == '0') {
+ for (; len > 0; len--) {
+ if (! isdigit(*str) || *str == '8' || *str == '9')
+ goto done;
+ retval = (retval * 8) + (*str - '0');
+ str++;
+ }
+ } else {
+ save = str[len];
+ retval = atof(str);
+ str[len] = save;
+ }
+done:
+ return retval;
+}
+#endif /* defined(BITOPS) || defined(NONDECDATA) */