aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog36
-rw-r--r--array.c235
-rw-r--r--awk.h13
-rw-r--r--awkgram.c7
-rw-r--r--awkgram.y7
-rw-r--r--command.c2
-rw-r--r--command.y2
-rw-r--r--eval.c2
-rw-r--r--field.c65
-rw-r--r--io.c2
-rw-r--r--test/ChangeLog5
-rw-r--r--test/Makefile.am4
-rw-r--r--test/delsub.awk2
-rw-r--r--test/delsub.ok1
14 files changed, 269 insertions, 114 deletions
diff --git a/ChangeLog b/ChangeLog
index b80e151d..ac4c5fcd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,39 @@
+Wed May 4 23:04:06 2011 John Haque <j.eh@mchsi.com>
+
+ Fix the problem (crash) with disappearing array argument when
+ it is a subarray of another deleted array argument.
+
+ * awk.h (struct exp_node): Nuke unused field sub.nodep.number.
+ New field sub.nodep.rn.
+ (parent_array): New definition for sub.nodep.rn to keep track
+ of the parent of a subarray.
+ * awkgram.y (mk_symbol): Initialize parent_array to NULL.
+ * eval.c (r_interpret): In the case Op_sub_array, assign
+ parent_array.
+ * array.c (get_array): Initialize parent_array to NULL when
+ a Node_var_new becomes a Node_var_array.
+ (assoc_find): Add a fourth argument for the previous node
+ of the returned bucket.
+ (in_array, assoc_lookup): Adjust calls to assoc_find().
+ (adjust_fcall_stack): New routine to change a soon-to-be deleted
+ subarray parameter in the function call stack to a local array.
+ (do_delete): Simplify code, remove recursive usage. Call
+ adjust_fcall_stack() where appropriate.
+ (do_delete_loop): Call adjust_fcall_stack() before clearing the
+ array.
+ (asort_actual): Don't accept an array and its subarray as
+ arguments for asort() or asorti().
+ (asort_actual, dup_table): For asort(), appropriately assign
+ parent_array when creating the result array.
+ * field.c (do_split, do_patsplit): An array and its subarray not
+ accepted for the second and the fourth arguments. Remove
+ unnecessary dupnode of the field seperator node.
+
+ Unrelated:
+ * awkgram.y (LEX_DELETE, simple_variable): Change type argument
+ from Node_var_array to Node_var_new for calls to variable().
+ * io.c (devopen): Fix parsing GAWK_MSEC_SLEEP env variable.
+
Mon May 2 23:44:34 2011 Arnold D. Robbins <arnold@skeeve.com>
* dfa.c (parse_bracket_exp): Sync with GNU grep, since we
diff --git a/array.c b/array.c
index ee8ac9ee..380d4f32 100644
--- a/array.c
+++ b/array.c
@@ -45,7 +45,7 @@ static size_t AVG_CHAIN_MAX = 2; /* Modern machines are bigger, reduce this from
static size_t SUBSEPlen;
static char *SUBSEP;
-static NODE *assoc_find(NODE *symbol, NODE *subs, unsigned long hash1);
+static NODE *assoc_find(NODE *symbol, NODE *subs, unsigned long hash1, NODE **last);
static void grow_table(NODE *symbol);
static unsigned long gst_hash_string(const char *str, size_t len, unsigned long hsize, size_t *code);
@@ -198,6 +198,7 @@ get_array(NODE *symbol, int canfatal)
case Node_var_new:
symbol->type = Node_var_array;
symbol->var_array = NULL;
+ symbol->parent_array = NULL; /* main array has no parent */
/* fall through */
case Node_var_array:
break;
@@ -296,6 +297,7 @@ concat_exp(int nargs, int do_subsep)
return make_str_node(str, len, ALREADY_MALLOCED);
}
+
/* assoc_clear --- flush all the values in symbol[] */
void
@@ -317,6 +319,7 @@ assoc_clear(NODE *symbol)
freenode(r);
} else
unref(bucket->ahvalue);
+
unref(bucket); /* unref() will free the ahname_str */
}
symbol->var_array[i] = NULL;
@@ -393,15 +396,15 @@ awk_hash(const char *s, size_t len, unsigned long hsize, size_t *code)
/* assoc_find --- locate symbol[subs] */
static NODE * /* NULL if not found */
-assoc_find(NODE *symbol, NODE *subs, unsigned long hash1)
+assoc_find(NODE *symbol, NODE *subs, unsigned long hash1, NODE **last)
{
- NODE *bucket;
+ NODE *bucket, *prev;
const char *s1_str;
size_t s1_len;
NODE *s2;
- for (bucket = symbol->var_array[hash1]; bucket != NULL;
- bucket = bucket->ahnext) {
+ for (prev = NULL, bucket = symbol->var_array[hash1]; bucket != NULL;
+ prev = bucket, bucket = bucket->ahnext) {
/*
* This used to use cmp_nodes() here. That's wrong.
* Array indices are strings; compare as such, always!
@@ -413,10 +416,12 @@ assoc_find(NODE *symbol, NODE *subs, unsigned long hash1)
if (s1_len == s2->stlen) {
if (s1_len == 0 /* "" is a valid index */
|| memcmp(s1_str, s2->stptr, s1_len) == 0)
- return bucket;
+ break;
}
}
- return NULL;
+ if (last != NULL)
+ *last = prev;
+ return bucket;
}
/* in_array --- test whether the array element symbol[subs] exists or not,
@@ -435,7 +440,7 @@ in_array(NODE *symbol, NODE *subs)
return NULL;
hash1 = hash(subs->stptr, subs->stlen, (unsigned long) symbol->array_size, NULL);
- ret = assoc_find(symbol, subs, hash1);
+ ret = assoc_find(symbol, subs, hash1, NULL);
return (ret ? ret->ahvalue : NULL);
}
@@ -468,7 +473,7 @@ assoc_lookup(NODE *symbol, NODE *subs, int reference)
} else {
hash1 = hash(subs->stptr, subs->stlen,
(unsigned long) symbol->array_size, & code);
- bucket = assoc_find(symbol, subs, hash1);
+ bucket = assoc_find(symbol, subs, hash1, NULL);
if (bucket != NULL)
return &(bucket->ahvalue);
}
@@ -532,6 +537,94 @@ assoc_lookup(NODE *symbol, NODE *subs, int reference)
return &(bucket->ahvalue);
}
+
+/* adjust_fcall_stack: remove subarray(s) of symbol[] from
+ * function call stack.
+ */
+
+static void
+adjust_fcall_stack(NODE *symbol, int nsubs)
+{
+ NODE *func, *r, *n;
+ NODE **sp;
+ int pcount;
+
+ /*
+ * Solve the nasty problem of disappearing subarray arguments:
+ *
+ * function f(c, d) { delete c; .. use non-existent array d .. }
+ * BEGIN { a[0][0] = 1; f(a, a[0]); .. }
+ *
+ * The fix is to convert 'd' to a local empty array; This has
+ * to be done before clearing the parent array to avoid referring to
+ * already free-ed memory.
+ *
+ * Similar situations exist for builtins accepting more than
+ * one array argument: split, patsplit, asort and asorti. For example:
+ *
+ * BEGIN { a[0][0] = 1; split("abc", a, "", a[0]) }
+ *
+ * These cases do not involve the function call stack, and are
+ * handled individually in their respective routines.
+ */
+
+ func = frame_ptr->func_node;
+ if (func == NULL) /* in main */
+ return;
+ pcount = func->lnode->param_cnt;
+ sp = frame_ptr->stack;
+
+ for (; pcount > 0; pcount--) {
+ r = *sp++;
+ if (r->type != Node_array_ref
+ || r->orig_array->type != Node_var_array)
+ continue;
+ n = r->orig_array;
+
+ /* Case 1 */
+ if (n == symbol
+ && symbol->parent_array != NULL
+ && nsubs > 0
+ ) {
+ /* 'symbol' is a subarray, and 'r' is the same subarray:
+ *
+ * function f(c, d) { delete c[0]; .. }
+ * BEGIN { a[0][0] = 1; f(a, a[0]); .. }
+ *
+ * But excludes cases like (nsubs = 0):
+ *
+ * function f(c, d) { delete c; ..}
+ * BEGIN { a[0][0] = 1; f(a[0], a[0]); ...}
+ */
+ char *save;
+local_array:
+ save = r->vname;
+ memset(r, '\0', sizeof(NODE));
+ r->vname = save;
+ r->type = Node_var_array;
+ continue;
+ }
+
+ /* Case 2 */
+ for (n = n->parent_array; n != NULL; n = n->parent_array) {
+ assert(n->type == Node_var_array);
+ if (n == symbol) {
+ /* 'r' is a subarray of 'symbol':
+ *
+ * function f(c, d) { delete c; .. use d as array .. }
+ * BEGIN { a[0][0] = 1; f(a, a[0]); .. }
+ * OR
+ * BEGIN { a[0][0][0][0] = 1; f(a[0], a[0][0][0]); .. }
+ *
+ */
+
+ goto local_array;
+ }
+ }
+ }
+}
+
+
/* do_delete --- perform `delete array[s]' */
/*
@@ -543,8 +636,8 @@ void
do_delete(NODE *symbol, int nsubs)
{
unsigned long hash1;
- NODE *bucket, *last;
- NODE *subs;
+ NODE *subs, *bucket, *last, *r;
+ int i;
assert(symbol->type == Node_var_array);
@@ -568,81 +661,63 @@ do { \
} while (--n > 0)
if (nsubs == 0) { /* delete array */
+ adjust_fcall_stack(symbol, 0); /* fix function call stack; See above. */
assoc_clear(symbol);
return;
}
/* NB: subscripts are in reverse order on stack */
- subs = PEEK(nsubs - 1);
- if (subs->type != Node_val) {
- if (--nsubs > 0)
- free_subs(nsubs);
- fatal(_("attempt to use array `%s' in a scalar context"), array_vname(subs));
- }
- (void) force_string(subs);
- last = NULL; /* shut up gcc -Wall */
- hash1 = 0; /* ditto */
+ for (i = nsubs; i > 0; i--) {
+ subs = PEEK(i - 1);
+ if (subs->type != Node_val) {
+ free_subs(i);
+ fatal(_("attempt to use array `%s' in a scalar context"), array_vname(subs));
+ }
+ (void) force_string(subs);
- if (symbol->var_array != NULL) {
- hash1 = hash(subs->stptr, subs->stlen,
- (unsigned long) symbol->array_size, NULL);
- last = NULL;
- for (bucket = symbol->var_array[hash1]; bucket != NULL;
- last = bucket, bucket = bucket->ahnext) {
- /*
- * This used to use cmp_nodes() here. That's wrong.
- * Array indices are strings; compare as such, always!
- */
- const char *s1_str;
- size_t s1_len;
- NODE *s2;
+ last = NULL; /* shut up gcc -Wall */
+ hash1 = 0; /* ditto */
+ bucket = NULL; /* array may be empty */
- s1_str = bucket->ahname_str;
- s1_len = bucket->ahname_len;
- s2 = subs;
-
- if (s1_len == s2->stlen) {
- if (s1_len == 0 /* "" is a valid index */
- || memcmp(s1_str, s2->stptr, s1_len) == 0)
- break;
- }
+ if (symbol->var_array != NULL) {
+ hash1 = hash(subs->stptr, subs->stlen,
+ (unsigned long) symbol->array_size, NULL);
+ bucket = assoc_find(symbol, subs, hash1, &last);
}
- } else
- bucket = NULL; /* The array is empty. */
- if (bucket == NULL) {
- if (do_lint)
- lintwarn(_("delete: index `%s' not in array `%s'"),
- subs->stptr, array_vname(symbol));
- DEREF(subs);
+ if (bucket == NULL) {
+ if (do_lint)
+ lintwarn(_("delete: index `%s' not in array `%s'"),
+ subs->stptr, array_vname(symbol));
+ /* avoid memory leak, free all subs */
+ free_subs(i);
+ return;
+ }
- /* avoid memory leak, free rest of the subs */
- if (--nsubs > 0)
- free_subs(nsubs);
- return;
+ if (i > 1) {
+ if (bucket->ahvalue->type != Node_var_array) {
+ /* e.g.: a[1] = 1; delete a[1][1] */
+ free_subs(i);
+ fatal(_("attempt to use scalar `%s[\"%.*s\"]' as an array"),
+ symbol->vname,
+ (int) bucket->ahname_len,
+ bucket->ahname_str);
+ }
+ symbol = bucket->ahvalue;
+ }
+ DEREF(subs);
}
- DEREF(subs);
- if (bucket->ahvalue->type == Node_var_array) {
- NODE *r = bucket->ahvalue;
- do_delete(r, nsubs - 1);
- if (r->var_array != NULL || nsubs > 1)
- return;
- /* else
- cleared a sub-array, free the array node
- and the bucket in parent array */
+ r = bucket->ahvalue;
+ if (r->type == Node_var_array) {
+ adjust_fcall_stack(r, nsubs); /* fix function call stack; See above. */
+ assoc_clear(r);
+ /* cleared a sub-array, free Node_var_array */
efree(r->vname);
freenode(r);
- } else if (--nsubs > 0) {
- /* e.g.: a[1] = 1; delete a[1][1] */
- free_subs(nsubs);
- fatal(_("attempt to use scalar `%s[\"%.*s\"]' as an array"),
- symbol->vname,
- (int) bucket->ahname_len,
- bucket->ahname_str);
} else
- unref(bucket->ahvalue);
+ unref(r);
if (last != NULL)
last->ahnext = bucket->ahnext;
@@ -663,6 +738,7 @@ do { \
#undef free_subs
}
+
/* do_delete_loop --- simulate ``for (iggy in foo) delete foo[iggy]'' */
/*
@@ -692,6 +768,7 @@ do_delete_loop(NODE *symbol, NODE **lhs)
}
/* blast the array in one shot */
+ adjust_fcall_stack(symbol, 0);
assoc_clear(symbol);
}
@@ -923,6 +1000,7 @@ dup_table(NODE *symbol, NODE *newsymb)
emalloc(aname, char *, aname_len + 2, "dup_table");
sprintf(aname, "%s[\"%.*s\"]", newsymb->vname, (int) chain->ahname_len, chain->ahname_str);
r->vname = aname;
+ r->parent_array = newsymb;
bucket->ahvalue = dup_table(chain->ahvalue, r);
} else
bucket->ahvalue = dupnode(chain->ahvalue);
@@ -979,6 +1057,21 @@ asort_actual(int nargs, SORT_CTXT ctxt)
_("asorti: first argument not an array"));
}
+ if (dest != NULL) {
+ for (r = dest->parent_array; r != NULL; r = r->parent_array) {
+ if (r == array)
+ fatal(ctxt == ASORT ?
+ _("asort: cannot use a subarray of first arg for second arg") :
+ _("asorti: cannot use a subarray of first arg for second arg"));
+ }
+ for (r = array->parent_array; r != NULL; r = r->parent_array) {
+ if (r == dest)
+ fatal(ctxt == ASORT ?
+ _("asort: cannot use a subarray of second arg for first arg") :
+ _("asorti: cannot use a subarray of second arg for first arg"));
+ }
+ }
+
num_elems = array->table_size;
if (num_elems == 0 || array->var_array == NULL) { /* source array is empty */
if (dest != NULL && dest != array)
@@ -1005,6 +1098,7 @@ asort_actual(int nargs, SORT_CTXT ctxt)
memset(result, '\0', sizeof(NODE));
result->type = Node_var_array;
result->vname = array->vname;
+ result->parent_array = array->parent_array;
}
subs = make_str_node(buf, TSIZE, ALREADY_MALLOCED); /* fake it */
@@ -1041,6 +1135,7 @@ asort_actual(int nargs, SORT_CTXT ctxt)
arr->type = Node_var_array;
arr->var_array = NULL;
arr->vname = estrdup(arr_name, strlen(arr_name));
+ arr->parent_array = array; /* actual parent, not the temporary one. */
*assoc_lookup(result, subs, FALSE) = dup_table(val, arr);
}
}
diff --git a/awk.h b/awk.h
index add30f9d..fb567487 100644
--- a/awk.h
+++ b/awk.h
@@ -319,7 +319,7 @@ typedef struct exp_node {
char **param_list;
} x;
char *name;
- short number;
+ struct exp_node *rn;
unsigned long reflags;
# define CASE 1
# define CONSTANT 2
@@ -375,8 +375,8 @@ typedef struct exp_node {
* function name; see awkgram.y */
# define FIELD 512 /* this is a field */
# define INTLSTR 1024 /* use localized version */
-# define WSTRCUR 2048 /* wide str value is current */
-# define NUMIND 4096 /* numeric val of index is current */
+# define NUMIND 2048 /* numeric val of index is current */
+# define WSTRCUR 4096 /* wide str value is current */
} NODE;
@@ -419,9 +419,10 @@ typedef struct exp_node {
#define var_assign sub.nodep.x.aptr
/* Node_var_array: */
-#define var_array sub.nodep.r.av
-#define array_size sub.nodep.l.ll
-#define table_size sub.nodep.x.xl
+#define var_array sub.nodep.r.av
+#define array_size sub.nodep.l.ll
+#define table_size sub.nodep.x.xl
+#define parent_array sub.nodep.rn
/* Node_array_ref: */
#define orig_array lnode
diff --git a/awkgram.c b/awkgram.c
index 9b56293e..09628406 100644
--- a/awkgram.c
+++ b/awkgram.c
@@ -3005,7 +3005,7 @@ regular_loop:
char *arr = (yyvsp[(2) - (4)])->lextok;
(yyvsp[(2) - (4)])->opcode = Op_push_array;
- (yyvsp[(2) - (4)])->memory = variable(arr, Node_var_array);
+ (yyvsp[(2) - (4)])->memory = variable(arr, Node_var_new);
if ((yyvsp[(4) - (4)]) == NULL) {
static short warned = FALSE;
@@ -3044,7 +3044,7 @@ regular_loop:
error_ln((yyvsp[(1) - (4)])->source_line,
_("`delete array' is a gawk extension"));
}
- (yyvsp[(3) - (4)])->memory = variable(arr, Node_var_array);
+ (yyvsp[(3) - (4)])->memory = variable(arr, Node_var_new);
(yyvsp[(3) - (4)])->opcode = Op_push_array;
(yyvsp[(1) - (4)])->expr_count = 0;
(yyval) = list_append(list_create((yyvsp[(3) - (4)])), (yyvsp[(1) - (4)]));
@@ -4115,7 +4115,7 @@ regular_loop:
char *arr = (yyvsp[(1) - (2)])->lextok;
if ((n = lookup(arr)) != NULL && ! isarray(n))
yyerror(_("use of non-array as array"));
- (yyvsp[(1) - (2)])->memory = variable(arr, Node_var_array);
+ (yyvsp[(1) - (2)])->memory = variable(arr, Node_var_new);
(yyvsp[(1) - (2)])->opcode = Op_push_array;
(yyval) = list_prepend((yyvsp[(2) - (2)]), (yyvsp[(1) - (2)]));
}
@@ -6219,6 +6219,7 @@ mk_symbol(NODETYPE type, NODE *value)
r->flags = MALLOC;
r->lnode = value;
r->rnode = NULL;
+ r->parent_array = NULL;
r->var_assign = (Func_ptr) 0;
return r;
}
diff --git a/awkgram.y b/awkgram.y
index cf8b9e99..f739f1d1 100644
--- a/awkgram.y
+++ b/awkgram.y
@@ -986,7 +986,7 @@ simple_stmt
char *arr = $2->lextok;
$2->opcode = Op_push_array;
- $2->memory = variable(arr, Node_var_array);
+ $2->memory = variable(arr, Node_var_new);
if ($4 == NULL) {
static short warned = FALSE;
@@ -1024,7 +1024,7 @@ simple_stmt
error_ln($1->source_line,
_("`delete array' is a gawk extension"));
}
- $3->memory = variable(arr, Node_var_array);
+ $3->memory = variable(arr, Node_var_new);
$3->opcode = Op_push_array;
$1->expr_count = 0;
$$ = list_append(list_create($3), $1);
@@ -1711,7 +1711,7 @@ simple_variable
char *arr = $1->lextok;
if ((n = lookup(arr)) != NULL && ! isarray(n))
yyerror(_("use of non-array as array"));
- $1->memory = variable(arr, Node_var_array);
+ $1->memory = variable(arr, Node_var_new);
$1->opcode = Op_push_array;
$$ = list_prepend($2, $1);
}
@@ -3572,6 +3572,7 @@ mk_symbol(NODETYPE type, NODE *value)
r->flags = MALLOC;
r->lnode = value;
r->rnode = NULL;
+ r->parent_array = NULL;
r->var_assign = (Func_ptr) 0;
return r;
}
diff --git a/command.c b/command.c
index fa795715..2b3b3494 100644
--- a/command.c
+++ b/command.c
@@ -3020,7 +3020,7 @@ again:
/* force a quit, and let do_quit (in debug.c) exit */
if (! seen_eof) {
if (errno != 0) {
- fprintf(stderr, _("can't read command (%s)"), strerror(errno));
+ fprintf(stderr, _("can't read command (%s)\n"), strerror(errno));
exit_val = EXIT_FAILURE;
} /* else
exit_val = EXIT_SUCCESS; */
diff --git a/command.y b/command.y
index d9ecd0ab..bcaa74f0 100644
--- a/command.y
+++ b/command.y
@@ -1047,7 +1047,7 @@ again:
/* force a quit, and let do_quit (in debug.c) exit */
if (! seen_eof) {
if (errno != 0) {
- fprintf(stderr, _("can't read command (%s)"), strerror(errno));
+ fprintf(stderr, _("can't read command (%s)\n"), strerror(errno));
exit_val = EXIT_FAILURE;
} /* else
exit_val = EXIT_SUCCESS; */
diff --git a/eval.c b/eval.c
index f4d66b10..850953f6 100644
--- a/eval.c
+++ b/eval.c
@@ -455,6 +455,7 @@ flags2str(int flagval)
{ FUNC, "FUNC" },
{ FIELD, "FIELD" },
{ INTLSTR, "INTLSTR" },
+ { NUMIND, "NUMIND" },
#ifdef WSTRCUR
{ WSTRCUR, "WSTRCUR" },
#endif
@@ -1758,6 +1759,7 @@ top:
r->type = Node_var_array;
r->var_array = NULL;
r->vname = estrdup(arr_name, strlen(arr_name));
+ r->parent_array = t1;
*assoc_lookup(t1, t2, FALSE) = r;
} else if (r->type != Node_var_array) {
const char *arr_name = make_aname(t1, t2);
diff --git a/field.c b/field.c
index 659574ec..09e06e9d 100644
--- a/field.c
+++ b/field.c
@@ -956,12 +956,20 @@ do_split(int nargs)
if (arr->type != Node_var_array)
fatal(_("split: second argument is not an array"));
- assoc_clear(arr);
if (sep_arr != NULL) {
if (sep_arr == arr)
- fatal(_("split: can not use the same array for second and fourth args"));
+ fatal(_("split: cannot use the same array for second and fourth args"));
+
+ /* This checks need to be done before clearing any of the arrays */
+ for (tmp = sep_arr->parent_array; tmp != NULL; tmp = tmp->parent_array)
+ if (tmp == arr)
+ fatal(_("split: cannot use a subarray of second arg for fourth arg"));
+ for (tmp = arr->parent_array; tmp != NULL; tmp = tmp->parent_array)
+ if (tmp == sep_arr)
+ fatal(_("split: cannot use a subarray of fourth arg for second arg"));
assoc_clear(sep_arr);
}
+ assoc_clear(arr);
src = TOP_STRING();
if (src->stlen == 0) {
@@ -975,10 +983,10 @@ do_split(int nargs)
if ((sep->re_flags & FS_DFLT) != 0 && current_field_sep() != Using_FIELDWIDTHS && ! RS_is_null) {
parseit = parse_field;
- fs = dupnode(force_string(FS_node->var_value));
+ fs = force_string(FS_node->var_value);
rp = FS_regexp;
} else {
- fs = dupnode(sep->re_exp);
+ fs = sep->re_exp;
if (fs->stlen == 0) {
static short warned = FALSE;
@@ -1009,7 +1017,6 @@ do_split(int nargs)
decr_sp();
DEREF(src);
- unref(fs);
return tmp;
}
@@ -1036,39 +1043,41 @@ do_patsplit(int nargs)
fatal(_("patsplit: second argument is not an array"));
src = TOP_STRING();
- if (src->stlen == 0) {
- /*
- * Skip the work if first arg is the null string.
- */
- assoc_clear(arr);
- if (sep_arr != NULL)
- assoc_clear(sep_arr);
- decr_sp();
- DEREF(src);
- return make_number((AWKNUM) 0);
- }
- fpat = dupnode(sep->re_exp);
- if (fpat->stlen == 0) {
- unref(fpat);
+ fpat = sep->re_exp;
+ if (fpat->stlen == 0)
fatal(_("patsplit: third argument must be non-null"));
- }
- assoc_clear(arr);
+
if (sep_arr != NULL) {
if (sep_arr == arr)
- fatal(_("patsplit: can not use the same array for second and fourth args"));
+ fatal(_("patsplit: cannot use the same array for second and fourth args"));
+
+ /* This checks need to be done before clearing any of the arrays */
+ for (tmp = sep_arr->parent_array; tmp != NULL; tmp = tmp->parent_array)
+ if (tmp == arr)
+ fatal(_("patsplit: cannot use a subarray of second arg for fourth arg"));
+ for (tmp = arr->parent_array; tmp != NULL; tmp = tmp->parent_array)
+ if (tmp == sep_arr)
+ fatal(_("patsplit: cannot use a subarray of fourth arg for second arg"));
assoc_clear(sep_arr);
}
+ assoc_clear(arr);
- rp = re_update(sep);
-
- s = src->stptr;
- tmp = make_number((AWKNUM) fpat_parse_field(UNLIMITED, &s,
+ if (src->stlen == 0) {
+ /*
+ * Skip the work if first arg is the null string.
+ */
+ tmp = make_number((AWKNUM) 0);
+ } else {
+ rp = re_update(sep);
+ s = src->stptr;
+ tmp = make_number((AWKNUM) fpat_parse_field(UNLIMITED, &s,
(int) src->stlen, fpat, rp,
set_element, arr, sep_arr, FALSE));
- decr_sp();
+ }
+
+ decr_sp(); /* 1st argument not POP-ed */
DEREF(src);
- unref(fpat);
return tmp;
}
diff --git a/io.c b/io.c
index 6fc921c5..401b4def 100644
--- a/io.c
+++ b/io.c
@@ -1504,7 +1504,7 @@ devopen(const char *name, const char *mode)
*/
if ((ms2 = getenv("GAWK_MSEC_SLEEP")) != NULL) {
msleep = strtol(ms2, &end, 10);
- if (end != cp && msleep < 0)
+ if (end == ms2 || msleep < 0)
msleep = 1000;
else
msleep *= 1000;
diff --git a/test/ChangeLog b/test/ChangeLog
index 3754c554..ffaf4629 100644
--- a/test/ChangeLog
+++ b/test/ChangeLog
@@ -1,3 +1,8 @@
+Wed May 4 23:03:06 2011 Arnold D. Robbins <arnold@skeeve.com>
+
+ * delsub.awk, delsub.ok: New files.
+ * Makefile.am (delsub): New test.
+
Fri Apr 22 16:07:01 2011 John Haque <j.eh@mchsi.com>
* sortu.awk, sortu.ok: New files.
diff --git a/test/Makefile.am b/test/Makefile.am
index 8eeb80da..c4cfcebc 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -155,6 +155,8 @@ EXTRA_DIST = \
delarpm2.ok \
delfunc.awk \
delfunc.ok \
+ delsub.awk \
+ delsub.ok \
devfd.in1 \
devfd.in2 \
devfd.in4 \
@@ -775,7 +777,7 @@ GAWK_EXT_TESTS = \
aadelete1 aadelete2 aarray1 aasort aasorti \
arraysort \
argtest backw badargs beginfile1 binmode1 clos1way \
- devfd devfd1 devfd2 dumpvars \
+ delsub devfd devfd1 devfd2 dumpvars \
fieldwdth fpat1 funlen fsfwfs fwtest fwtest2 gensub gensub2 getlndir \
gnuops2 gnuops3 gnureops \
icasefs icasers igncdym igncfs ignrcas2 ignrcase indirectcall lint \
diff --git a/test/delsub.awk b/test/delsub.awk
new file mode 100644
index 00000000..0c3ffb0e
--- /dev/null
+++ b/test/delsub.awk
@@ -0,0 +1,2 @@
+function f(c, d, x) { delete c; x = d[0] }
+BEGIN { a[0][0] = 1; f(a, a[0]); print "still here" }
diff --git a/test/delsub.ok b/test/delsub.ok
new file mode 100644
index 00000000..ae3eb5bb
--- /dev/null
+++ b/test/delsub.ok
@@ -0,0 +1 @@
+still here