summaryrefslogtreecommitdiff
path: root/str_array.c
diff options
context:
space:
mode:
Diffstat (limited to 'str_array.c')
-rw-r--r--str_array.c173
1 files changed, 116 insertions, 57 deletions
diff --git a/str_array.c b/str_array.c
index 8fb6ba8a..33c9ddcc 100644
--- a/str_array.c
+++ b/str_array.c
@@ -3,7 +3,7 @@
*/
/*
- * Copyright (C) 1986, 1988, 1989, 1991-2011 the Free Software Foundation, Inc.
+ * Copyright (C) 1986, 1988, 1989, 1991-2013 the Free Software Foundation, Inc.
*
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
@@ -55,14 +55,10 @@ static NODE **str_list(NODE *symbol, NODE *subs);
static NODE **str_copy(NODE *symbol, NODE *newsymb);
static NODE **str_dump(NODE *symbol, NODE *ndump);
-#ifdef ARRAYDEBUG
-static NODE **str_option(NODE *opt, NODE *val);
-#endif
-
-
-array_ptr str_array_func[] = {
+afunc_t str_array_func[] = {
str_array_init,
- (array_ptr) 0,
+ (afunc_t) 0,
+ null_length,
str_lookup,
str_exists,
str_clear,
@@ -70,9 +66,26 @@ array_ptr str_array_func[] = {
str_list,
str_copy,
str_dump,
-#ifdef ARRAYDEBUG
- str_option
-#endif
+ (afunc_t) 0,
+};
+
+static NODE **env_remove(NODE *symbol, NODE *subs);
+static NODE **env_store(NODE *symbol, NODE *subs);
+static NODE **env_clear(NODE *symbol, NODE *subs);
+
+/* special case for ENVIRON */
+afunc_t env_array_func[] = {
+ str_array_init,
+ (afunc_t) 0,
+ null_length,
+ str_lookup,
+ str_exists,
+ env_clear,
+ env_remove,
+ str_list,
+ str_copy,
+ str_dump,
+ env_store,
};
static inline NODE **str_find(NODE *symbol, NODE *s1, size_t code1, unsigned long hash1);
@@ -85,18 +98,23 @@ static unsigned long awk_hash(const char *s, size_t len, unsigned long hsize, si
unsigned long (*hash)(const char *s, size_t len, unsigned long hsize, size_t *code) = awk_hash;
-/* str_array_init --- check relevant environment variables */
+/* str_array_init --- array initialization routine */
static NODE **
str_array_init(NODE *symbol ATTRIBUTE_UNUSED, NODE *subs ATTRIBUTE_UNUSED)
{
- long newval;
- const char *val;
+ if (symbol == NULL) { /* first time */
+ long newval;
+ const char *val;
+
+ /* check relevant environment variables */
+ if ((newval = getenv_long("STR_CHAIN_MAX")) > 0)
+ STR_CHAIN_MAX = newval;
+ if ((val = getenv("AWK_HASH")) != NULL && strcmp(val, "gst") == 0)
+ hash = gst_hash_string;
+ } else
+ null_array(symbol);
- if ((newval = getenv_long("STR_CHAIN_MAX")) > 0)
- STR_CHAIN_MAX = newval;
- if ((val = getenv("AWK_HASH")) != NULL && strcmp(val, "gst") == 0)
- hash = gst_hash_string;
return (NODE **) ! NULL;
}
@@ -158,7 +176,7 @@ str_lookup(NODE *symbol, NODE *subs)
* never be used.
*/
- if (subs->flags & NUMCUR) {
+ if ((subs->flags & (MPFN|MPZN|NUMCUR)) == NUMCUR) {
tmp->numbr = subs->numbr;
tmp->flags |= NUMCUR;
}
@@ -187,16 +205,15 @@ str_lookup(NODE *symbol, NODE *subs)
static NODE **
str_exists(NODE *symbol, NODE *subs)
{
- NODE **lhs;
unsigned long hash1;
size_t code1;
- assert(symbol->table_size > 0);
+ if (symbol->table_size == 0)
+ return NULL;
subs = force_string(subs);
hash1 = hash(subs->stptr, subs->stlen, (unsigned long) symbol->array_size, & code1);
- lhs = str_find(symbol, subs, code1, hash1);
- return lhs;
+ return str_find(symbol, subs, code1, hash1);
}
/* str_clear --- flush all the values in symbol[] */
@@ -226,8 +243,7 @@ str_clear(NODE *symbol, NODE *subs ATTRIBUTE_UNUSED)
if (symbol->buckets != NULL)
efree(symbol->buckets);
- init_array(symbol); /* re-initialize symbol */
- symbol->flags &= ~ARRAYMAXED;
+ symbol->ainit(symbol, NULL); /* re-initialize symbol */
return NULL;
}
@@ -242,7 +258,8 @@ str_remove(NODE *symbol, NODE *subs)
NODE *s2;
size_t s1_len;
- assert(symbol->table_size > 0);
+ if (symbol->table_size == 0)
+ return NULL;
s2 = force_string(subs);
hash1 = hash(s2->stptr, s2->stlen, (unsigned long) symbol->array_size, NULL);
@@ -272,8 +289,7 @@ str_remove(NODE *symbol, NODE *subs)
if (--symbol->table_size == 0) {
if (symbol->buckets != NULL)
efree(symbol->buckets);
- init_array(symbol); /* re-initialize symbol */
- symbol->flags &= ~ARRAYMAXED;
+ symbol->ainit(symbol, NULL); /* re-initialize symbol */
}
return (NODE **) ! NULL; /* return success */
@@ -335,6 +351,7 @@ str_copy(NODE *symbol, NODE *newsymb)
newchain->ahcode = chain->ahcode;
*pnew = newchain;
+ newchain->ahnext = NULL;
pnew = & newchain->ahnext;
}
}
@@ -357,15 +374,18 @@ str_list(NODE *symbol, NODE *t)
BUCKET *b;
unsigned long num_elems, list_size, i, k = 0;
int elem_size = 1;
+ assoc_kind_t assoc_kind;
- assert(symbol->table_size > 0);
+ if (symbol->table_size == 0)
+ return NULL;
- if ((t->flags & (AINDEX|AVALUE)) == (AINDEX|AVALUE))
+ assoc_kind = (assoc_kind_t) t->flags;
+ if ((assoc_kind & (AINDEX|AVALUE)) == (AINDEX|AVALUE))
elem_size = 2;
/* allocate space for array */
num_elems = symbol->table_size;
- if ((t->flags & (AINDEX|AVALUE|ADELETE)) == (AINDEX|ADELETE))
+ if ((assoc_kind & (AINDEX|AVALUE|ADELETE)) == (AINDEX|ADELETE))
num_elems = 1;
list_size = elem_size * num_elems;
@@ -377,17 +397,17 @@ str_list(NODE *symbol, NODE *t)
for (b = symbol->buckets[i]; b != NULL; b = b->ahnext) {
/* index */
subs = b->ahname;
- if (t->flags & AINUM)
+ if ((assoc_kind & AINUM) != 0)
(void) force_number(subs);
list[k++] = dupnode(subs);
/* value */
- if (t->flags & AVALUE) {
+ if ((assoc_kind & AVALUE) != 0) {
val = b->ahvalue;
if (val->type == Node_val) {
- if ((t->flags & AVNUM) != 0)
+ if ((assoc_kind & AVNUM) != 0)
(void) force_number(val);
- else if ((t->flags & AVSTR) != 0)
+ else if ((assoc_kind & AVSTR) != 0)
val = force_string(val);
}
list[k++] = val;
@@ -443,7 +463,7 @@ str_dump(NODE *symbol, NODE *ndump)
fprintf(output_fp, "flags: %s\n", flags2str(symbol->flags));
}
indent(indent_level);
- fprintf(output_fp, "STR_CHAIN_MAX: %lu\n", STR_CHAIN_MAX);
+ fprintf(output_fp, "STR_CHAIN_MAX: %lu\n", (unsigned long) STR_CHAIN_MAX);
indent(indent_level);
fprintf(output_fp, "array_size: %lu\n", (unsigned long) symbol->array_size);
indent(indent_level);
@@ -670,27 +690,6 @@ grow_table(NODE *symbol)
}
-#ifdef ARRAYDEBUG
-
-static NODE **
-str_option(NODE *opt, NODE *val)
-{
- int newval;
- NODE *tmp;
- NODE **ret = (NODE **) ! NULL;
-
- tmp = force_string(opt);
- (void) force_number(val);
- if (STREQ(tmp->stptr, "STR_CHAIN_MAX")) {
- newval = (int) val->numbr;
- if (newval > 0)
- STR_CHAIN_MAX = newval;
- } else
- ret = NULL;
- return ret;
-}
-#endif
-
/*
From bonzini@gnu.org Mon Oct 28 16:05:26 2002
@@ -757,3 +756,63 @@ scramble(unsigned long x)
return x;
}
+
+/* env_remove --- for ENVIRON, remove value from real environment */
+
+static NODE **
+env_remove(NODE *symbol, NODE *subs)
+{
+ NODE **val = str_remove(symbol, subs);
+
+ if (val != NULL)
+ (void) unsetenv(subs->stptr);
+
+ return val;
+}
+
+/* env_clear --- clear out the environment when ENVIRON is deleted */
+
+static NODE **
+env_clear(NODE *symbol, NODE *subs)
+{
+ extern char **environ;
+ NODE **val = str_clear(symbol, subs);
+
+ environ = NULL; /* ZAP! */
+
+ /* str_clear zaps the vtable, reset it */
+ symbol->array_funcs = env_array_func;
+
+ return val;
+}
+
+/* env_store --- post assign function for ENVIRON, put new value into env */
+
+static NODE **
+env_store(NODE *symbol, NODE *subs)
+{
+ NODE **val = str_exists(symbol, subs);
+ const char *newval;
+
+ assert(val != NULL);
+
+ newval = (*val)->stptr;
+ if (newval == NULL)
+ newval = "";
+
+ (void) setenv(subs->stptr, newval, 1);
+
+ return val;
+}
+
+/* init_env_array --- set up the pointers for ENVIRON. A bit hacky. */
+
+void
+init_env_array(NODE *env_node)
+{
+ /* If POSIX simply don't reset the vtable and things work as before */
+ if (do_posix)
+ return;
+
+ env_node->array_funcs = env_array_func;
+}