Blame int_array.c

Packit Service f629e6
/*
Packit Service f629e6
 * int_array.c - routines for arrays of integer indices.
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
/*
Packit Service f629e6
 * Copyright (C) 1986, 1988, 1989, 1991-2013, 2016, 2017,
Packit Service f629e6
 * the Free Software Foundation, Inc.
Packit Service f629e6
 *
Packit Service f629e6
 * This file is part of GAWK, the GNU implementation of the
Packit Service f629e6
 * AWK Programming Language.
Packit Service f629e6
 *
Packit Service f629e6
 * GAWK is free software; you can redistribute it and/or modify
Packit Service f629e6
 * it under the terms of the GNU General Public License as published by
Packit Service f629e6
 * the Free Software Foundation; either version 3 of the License, or
Packit Service f629e6
 * (at your option) any later version.
Packit Service f629e6
 *
Packit Service f629e6
 * GAWK is distributed in the hope that it will be useful,
Packit Service f629e6
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service f629e6
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service f629e6
 * GNU General Public License for more details.
Packit Service f629e6
 *
Packit Service f629e6
 * You should have received a copy of the GNU General Public License
Packit Service f629e6
 * along with this program; if not, write to the Free Software
Packit Service f629e6
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
#include "awk.h"
Packit Service f629e6
Packit Service f629e6
extern FILE *output_fp;
Packit Service f629e6
extern void indent(int indent_level);
Packit Service f629e6
extern NODE **is_integer(NODE *symbol, NODE *subs);
Packit Service f629e6
Packit Service f629e6
static size_t INT_CHAIN_MAX = 2;
Packit Service f629e6
Packit Service f629e6
static NODE **int_array_init(NODE *symbol, NODE *subs);
Packit Service f629e6
static NODE **int_lookup(NODE *symbol, NODE *subs);
Packit Service f629e6
static NODE **int_exists(NODE *symbol, NODE *subs);
Packit Service f629e6
static NODE **int_clear(NODE *symbol, NODE *subs);
Packit Service f629e6
static NODE **int_remove(NODE *symbol, NODE *subs);
Packit Service f629e6
static NODE **int_list(NODE *symbol, NODE *t);
Packit Service f629e6
static NODE **int_copy(NODE *symbol, NODE *newsymb);
Packit Service f629e6
static NODE **int_dump(NODE *symbol, NODE *ndump);
Packit Service f629e6
Packit Service f629e6
static uint32_t int_hash(uint32_t k, uint32_t hsize);
Packit Service f629e6
static inline NODE **int_find(NODE *symbol, long k, uint32_t hash1);
Packit Service f629e6
static NODE **int_insert(NODE *symbol, long k, uint32_t hash1);
Packit Service f629e6
static void grow_int_table(NODE *symbol);
Packit Service f629e6
Packit Service f629e6
afunc_t int_array_func[] = {
Packit Service f629e6
	int_array_init,
Packit Service f629e6
	is_integer,
Packit Service f629e6
	null_length,
Packit Service f629e6
	int_lookup,
Packit Service f629e6
	int_exists,
Packit Service f629e6
	int_clear,
Packit Service f629e6
	int_remove,
Packit Service f629e6
	int_list,
Packit Service f629e6
	int_copy,
Packit Service f629e6
	int_dump,
Packit Service f629e6
	(afunc_t) 0,
Packit Service f629e6
};
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/* int_array_init --- array initialization routine */
Packit Service f629e6
Packit Service f629e6
static NODE **
Packit Service f629e6
int_array_init(NODE *symbol, NODE *subs ATTRIBUTE_UNUSED)
Packit Service f629e6
{
Packit Service f629e6
	if (symbol == NULL) {	/* first time */
Packit Service f629e6
		long newval;
Packit Service f629e6
Packit Service f629e6
		/* check relevant environment variables */
Packit Service f629e6
		if ((newval = getenv_long("INT_CHAIN_MAX")) > 0)
Packit Service f629e6
			INT_CHAIN_MAX = newval;
Packit Service f629e6
	} else
Packit Service f629e6
		null_array(symbol);
Packit Service f629e6
Packit Service f629e6
	return & success_node;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/*
Packit Service f629e6
 * standard_integer_string -- check whether the string matches what
Packit Service f629e6
 * sprintf("%ld", <value>) would produce. This is accomplished by accepting
Packit Service f629e6
 * only strings that look like /^0$/ or /^-?[1-9][0-9]*$/. This should be
Packit Service f629e6
 * faster than comparing vs. the results of actually calling sprintf.
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
static bool
Packit Service f629e6
standard_integer_string(const char *s, size_t len)
Packit Service f629e6
{
Packit Service f629e6
	const char *end;
Packit Service f629e6
Packit Service f629e6
	if (len == 0)
Packit Service f629e6
		return false;
Packit Service f629e6
	if (*s == '0' && len == 1)
Packit Service f629e6
		return true;
Packit Service f629e6
	end = s + len;
Packit Service f629e6
	/* ignore leading minus sign */
Packit Service f629e6
	if (*s == '-' && ++s == end)
Packit Service f629e6
		return false;
Packit Service f629e6
	/* check first char is [1-9] */
Packit Service f629e6
	if (*s < '1' || *s > '9')
Packit Service f629e6
		return false;
Packit Service f629e6
	while (++s < end) {
Packit Service f629e6
		if (*s < '0' || *s > '9')
Packit Service f629e6
			return false;
Packit Service f629e6
	}
Packit Service f629e6
	return true;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* is_integer --- check if subscript is an integer */
Packit Service f629e6
Packit Service f629e6
NODE **
Packit Service f629e6
is_integer(NODE *symbol, NODE *subs)
Packit Service f629e6
{
Packit Service f629e6
#ifndef CHECK_INTEGER_USING_FORCE_NUMBER
Packit Service f629e6
	long l;
Packit Service f629e6
#endif
Packit Service f629e6
	AWKNUM d;
Packit Service f629e6
Packit Service f629e6
	if ((subs->flags & NUMINT) != 0)
Packit Service f629e6
		/* quick exit */
Packit Service f629e6
		return & success_node;
Packit Service f629e6
Packit Service f629e6
	if (subs == Nnull_string || do_mpfr)
Packit Service f629e6
		return NULL;
Packit Service f629e6
Packit Service f629e6
#ifdef CHECK_INTEGER_USING_FORCE_NUMBER
Packit Service f629e6
	/*
Packit Service f629e6
	 * This approach is much simpler, because we remove all of the strtol
Packit Service f629e6
	 * logic below. But this may be slower in some usage cases.
Packit Service f629e6
	 */
Packit Service f629e6
	if ((subs->flags & NUMCUR) == 0) {
Packit Service f629e6
		str2number(subs);
Packit Service f629e6
Packit Service f629e6
		/* check again in case force_number set NUMINT */
Packit Service f629e6
		if ((subs->flags & NUMINT) != 0)
Packit Service f629e6
			return & success_node;
Packit Service f629e6
	}
Packit Service f629e6
#else /* CHECK_INTEGER_USING_FORCE_NUMBER */
Packit Service f629e6
	if ((subs->flags & NUMCUR) != 0) {
Packit Service f629e6
#endif /* CHECK_INTEGER_USING_FORCE_NUMBER */
Packit Service f629e6
		d = subs->numbr;
Packit Service f629e6
		if (d <= INT32_MAX && d >= INT32_MIN && d == (int32_t) d) {
Packit Service f629e6
			/*
Packit Service f629e6
			 * The numeric value is an integer, but we must
Packit Service f629e6
			 * protect against strings that cannot be generated
Packit Service f629e6
			 * from sprintf("%ld", <subscript>). This can happen
Packit Service f629e6
			 * with strnum or string values. We could skip this
Packit Service f629e6
			 * check for pure NUMBER values, but unfortunately the
Packit Service f629e6
			 * code does not currently distinguish between NUMBER
Packit Service f629e6
			 * and strnum values.
Packit Service f629e6
			 */
Packit Service f629e6
			if (   (subs->flags & STRCUR) == 0
Packit Service f629e6
			    || standard_integer_string(subs->stptr, subs->stlen)) {
Packit Service f629e6
				subs->flags |= NUMINT;
Packit Service f629e6
				return & success_node;
Packit Service f629e6
			}
Packit Service f629e6
		}
Packit Service f629e6
		return NULL;
Packit Service f629e6
#ifndef CHECK_INTEGER_USING_FORCE_NUMBER
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	/* a[3]=1; print "3" in a    -- true
Packit Service f629e6
	 * a[3]=1; print "+3" in a   -- false
Packit Service f629e6
	 * a[3]=1; print "03" in a   -- false
Packit Service f629e6
	 * a[-3]=1; print "-3" in a  -- true
Packit Service f629e6
	 */
Packit Service f629e6
Packit Service f629e6
	/* must be a STRING */
Packit Service f629e6
	char *cp = subs->stptr, *cpend, *ptr;
Packit Service f629e6
	char save;
Packit Service f629e6
	size_t len = subs->stlen;
Packit Service f629e6
Packit Service f629e6
	if (len == 0 || (! isdigit((unsigned char) *cp) && *cp != '-'))
Packit Service f629e6
		return NULL;
Packit Service f629e6
Packit Service f629e6
	if (len > 1 &&
Packit Service f629e6
		((*cp == '0')		/* "00", "011" .. */
Packit Service f629e6
			|| (*cp == '-' && *(cp + 1) == '0')	/* "-0", "-011" .. */
Packit Service f629e6
		)
Packit Service f629e6
	)
Packit Service f629e6
		return NULL;
Packit Service f629e6
	if (len == 1 && *cp != '-') {	/* single digit */
Packit Service f629e6
		subs->numbr = (long) (*cp - '0');
Packit Service f629e6
		if ((subs->flags & USER_INPUT) != 0) {
Packit Service f629e6
			/* leave USER_INPUT set */
Packit Service f629e6
			subs->flags &= ~STRING;
Packit Service f629e6
			subs->flags |= NUMBER;
Packit Service f629e6
		}
Packit Service f629e6
		subs->flags |= (NUMCUR|NUMINT);
Packit Service f629e6
		return & success_node;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	cpend = cp + len;
Packit Service f629e6
	save = *cpend;
Packit Service f629e6
	*cpend = '\0';
Packit Service f629e6
Packit Service f629e6
	errno = 0;
Packit Service f629e6
	l = strtol(cp, & ptr, 10);
Packit Service f629e6
	*cpend = save;
Packit Service f629e6
	if (errno != 0 || ptr != cpend)
Packit Service f629e6
		return NULL;
Packit Service f629e6
Packit Service f629e6
	subs->numbr = l;
Packit Service f629e6
	if ((subs->flags & USER_INPUT) != 0) {
Packit Service f629e6
		/* leave USER_INPUT set */
Packit Service f629e6
		subs->flags &= ~STRING;
Packit Service f629e6
		subs->flags |= NUMBER;
Packit Service f629e6
	}
Packit Service f629e6
	subs->flags |= NUMCUR;
Packit Service f629e6
	if (l <= INT32_MAX && l >= INT32_MIN) {
Packit Service f629e6
		subs->flags |= NUMINT;
Packit Service f629e6
		return & success_node;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	return NULL;
Packit Service f629e6
#endif /* CHECK_INTEGER_USING_FORCE_NUMBER */
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/*
Packit Service f629e6
 * int_lookup --- Find SYMBOL[SUBS] in the assoc array.  Install it with value ""
Packit Service f629e6
 * if it isn't there. Returns a pointer ala get_lhs to where its value is stored.
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
static NODE **
Packit Service f629e6
int_lookup(NODE *symbol, NODE *subs)
Packit Service f629e6
{
Packit Service f629e6
	uint32_t hash1;
Packit Service f629e6
	long k;
Packit Service f629e6
	unsigned long size;
Packit Service f629e6
	NODE **lhs;
Packit Service f629e6
	NODE *xn;
Packit Service f629e6
Packit Service f629e6
	/*
Packit Service f629e6
	 * N.B: symbol->table_size is the total # of non-integers (symbol->xarray)
Packit Service f629e6
	 *	and integer elements. Also, symbol->xarray must have at least one
Packit Service f629e6
	 *	item in it, and can not exist if there are no integer elements.
Packit Service f629e6
	 * 	In that case, symbol->xarray is promoted to 'symbol' (See int_remove).
Packit Service f629e6
	 */
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
	if (! is_integer(symbol, subs)) {
Packit Service f629e6
		xn = symbol->xarray;
Packit Service f629e6
		if (xn == NULL) {
Packit Service f629e6
			xn = symbol->xarray = make_array();
Packit Service f629e6
			xn->vname = symbol->vname;	/* shallow copy */
Packit Service f629e6
			xn->flags |= XARRAY;
Packit Service f629e6
		} else if ((lhs = xn->aexists(xn, subs)) != NULL)
Packit Service f629e6
			return lhs;
Packit Service f629e6
		symbol->table_size++;
Packit Service f629e6
		return assoc_lookup(xn, subs);
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	k = subs->numbr;
Packit Service f629e6
	if (symbol->buckets == NULL)
Packit Service f629e6
		grow_int_table(symbol);
Packit Service f629e6
Packit Service f629e6
 	hash1 = int_hash(k, symbol->array_size);
Packit Service f629e6
	if ((lhs = int_find(symbol, k, hash1)) != NULL)
Packit Service f629e6
		return lhs;
Packit Service f629e6
Packit Service f629e6
	/* It's not there, install it */
Packit Service f629e6
Packit Service f629e6
	symbol->table_size++;
Packit Service f629e6
Packit Service f629e6
	/* first see if we would need to grow the array, before installing */
Packit Service f629e6
	size = symbol->table_size;
Packit Service f629e6
	if ((xn = symbol->xarray) != NULL)
Packit Service f629e6
		size -= xn->table_size;
Packit Service f629e6
Packit Service f629e6
	if ((symbol->flags & ARRAYMAXED) == 0
Packit Service f629e6
		    && (size / symbol->array_size) > INT_CHAIN_MAX) {
Packit Service f629e6
		grow_int_table(symbol);
Packit Service f629e6
		/* have to recompute hash value for new size */
Packit Service f629e6
		hash1 = int_hash(k, symbol->array_size);
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	return int_insert(symbol, k, hash1);
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/*
Packit Service f629e6
 * int_exists --- test whether the array element symbol[subs] exists or not,
Packit Service f629e6
 *	return pointer to value if it does.
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
static NODE **
Packit Service f629e6
int_exists(NODE *symbol, NODE *subs)
Packit Service f629e6
{
Packit Service f629e6
	long k;
Packit Service f629e6
	uint32_t hash1;
Packit Service f629e6
Packit Service f629e6
	if (! is_integer(symbol, subs)) {
Packit Service f629e6
		NODE *xn = symbol->xarray;
Packit Service f629e6
		if (xn == NULL)
Packit Service f629e6
			return NULL;
Packit Service f629e6
		return xn->aexists(xn, subs);
Packit Service f629e6
	}
Packit Service f629e6
	if (symbol->buckets == NULL)
Packit Service f629e6
		return NULL;
Packit Service f629e6
Packit Service f629e6
	k = subs->numbr;
Packit Service f629e6
	hash1 = int_hash(k, symbol->array_size);
Packit Service f629e6
	return int_find(symbol, k, hash1);
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* int_clear --- flush all the values in symbol[] */
Packit Service f629e6
Packit Service f629e6
static NODE **
Packit Service f629e6
int_clear(NODE *symbol, NODE *subs ATTRIBUTE_UNUSED)
Packit Service f629e6
{
Packit Service f629e6
	unsigned long i;
Packit Service f629e6
	int j;
Packit Service f629e6
	BUCKET *b, *next;
Packit Service f629e6
	NODE *r;
Packit Service f629e6
Packit Service f629e6
	if (symbol->xarray != NULL) {
Packit Service f629e6
		NODE *xn = symbol->xarray;
Packit Service f629e6
		assoc_clear(xn);
Packit Service f629e6
		freenode(xn);
Packit Service f629e6
		symbol->xarray = NULL;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	for (i = 0; i < symbol->array_size; i++) {
Packit Service f629e6
		for (b = symbol->buckets[i]; b != NULL;	b = next) {
Packit Service f629e6
			next = b->ainext;
Packit Service f629e6
			for (j = 0; j < b->aicount; j++) {
Packit Service f629e6
				r = b->aivalue[j];
Packit Service f629e6
				if (r->type == Node_var_array) {
Packit Service f629e6
					assoc_clear(r);	/* recursively clear all sub-arrays */
Packit Service f629e6
					efree(r->vname);
Packit Service f629e6
					freenode(r);
Packit Service f629e6
				} else
Packit Service f629e6
					unref(r);
Packit Service f629e6
			}
Packit Service f629e6
			freebucket(b);
Packit Service f629e6
		}
Packit Service f629e6
		symbol->buckets[i] = NULL;
Packit Service f629e6
	}
Packit Service f629e6
	if (symbol->buckets != NULL)
Packit Service f629e6
		efree(symbol->buckets);
Packit Service f629e6
	symbol->ainit(symbol, NULL);	/* re-initialize symbol */
Packit Service f629e6
	return NULL;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/* int_remove --- If SUBS is already in the table, remove it. */
Packit Service f629e6
Packit Service f629e6
static NODE **
Packit Service f629e6
int_remove(NODE *symbol, NODE *subs)
Packit Service f629e6
{
Packit Service f629e6
	uint32_t hash1;
Packit Service f629e6
	BUCKET *b, *prev = NULL;
Packit Service f629e6
	long k;
Packit Service f629e6
	int i;
Packit Service f629e6
	NODE *xn = symbol->xarray;
Packit Service f629e6
Packit Service f629e6
	if (symbol->table_size == 0 || symbol->buckets == NULL)
Packit Service f629e6
		return NULL;
Packit Service f629e6
Packit Service f629e6
	if (! is_integer(symbol, subs)) {
Packit Service f629e6
		if (xn == NULL || xn->aremove(xn, subs) == NULL)
Packit Service f629e6
			return NULL;
Packit Service f629e6
		if (xn->table_size == 0) {
Packit Service f629e6
			freenode(xn);
Packit Service f629e6
			symbol->xarray = NULL;
Packit Service f629e6
		}
Packit Service f629e6
		symbol->table_size--;
Packit Service f629e6
		assert(symbol->table_size > 0);
Packit Service f629e6
		return & success_node;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	k = subs->numbr;
Packit Service f629e6
	hash1 = int_hash(k, symbol->array_size);
Packit Service f629e6
Packit Service f629e6
	for (b = symbol->buckets[hash1]; b != NULL; prev = b, b = b->ainext) {
Packit Service f629e6
		for (i = 0; i < b->aicount; i++) {
Packit Service f629e6
			if (k != b->ainum[i])
Packit Service f629e6
				continue;
Packit Service f629e6
Packit Service f629e6
			/* item found */
Packit Service f629e6
			if (i == 0 && b->aicount == 2) {
Packit Service f629e6
				/* removing the 1st item; move 2nd item from position 1 to 0 */
Packit Service f629e6
Packit Service f629e6
				b->ainum[0] = b->ainum[1];
Packit Service f629e6
				b->aivalue[0] = b->aivalue[1];
Packit Service f629e6
			} /* else
Packit Service f629e6
				removing the only item or the 2nd item */
Packit Service f629e6
Packit Service f629e6
			goto removed;
Packit Service f629e6
		}
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if (b == NULL)	/* item not in array */
Packit Service f629e6
		return NULL;
Packit Service f629e6
Packit Service f629e6
removed:
Packit Service f629e6
	b->aicount--;
Packit Service f629e6
Packit Service f629e6
	if (b->aicount == 0) {
Packit Service f629e6
		/* detach bucket */
Packit Service f629e6
		if (prev != NULL)
Packit Service f629e6
			prev->ainext = b->ainext;
Packit Service f629e6
		else
Packit Service f629e6
			symbol->buckets[hash1] = b->ainext;
Packit Service f629e6
Packit Service f629e6
		/* delete bucket */
Packit Service f629e6
		freebucket(b);
Packit Service f629e6
	} else if (b != symbol->buckets[hash1]) {
Packit Service f629e6
		BUCKET *head = symbol->buckets[hash1];
Packit Service f629e6
Packit Service f629e6
		assert(b->aicount == 1);
Packit Service f629e6
		/* move the last element from head to bucket to make it full. */
Packit Service f629e6
		i = --head->aicount;	/* head has one less element */
Packit Service f629e6
		b->ainum[1] = head->ainum[i];
Packit Service f629e6
		b->aivalue[1] = head->aivalue[i];
Packit Service f629e6
		b->aicount++;	/* bucket has one more element */
Packit Service f629e6
		if (i == 0) {
Packit Service f629e6
			/* head is now empty; delete head */
Packit Service f629e6
			symbol->buckets[hash1] = head->ainext;
Packit Service f629e6
			freebucket(head);
Packit Service f629e6
		}
Packit Service f629e6
	} /* else
Packit Service f629e6
		do nothing */
Packit Service f629e6
Packit Service f629e6
	symbol->table_size--;
Packit Service f629e6
	if (xn == NULL && symbol->table_size == 0) {
Packit Service f629e6
		efree(symbol->buckets);
Packit Service f629e6
		symbol->ainit(symbol, NULL);	/* re-initialize array 'symbol' */
Packit Service f629e6
	} else if (xn != NULL && symbol->table_size == xn->table_size) {
Packit Service f629e6
		/* promote xn (str_array) to symbol */
Packit Service f629e6
		xn->flags &= ~XARRAY;
Packit Service f629e6
		xn->parent_array = symbol->parent_array;
Packit Service f629e6
		efree(symbol->buckets);
Packit Service f629e6
		*symbol = *xn;
Packit Service f629e6
		freenode(xn);
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	return & success_node;	/* return success */
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/* int_copy --- duplicate input array "symbol" */
Packit Service f629e6
Packit Service f629e6
static NODE **
Packit Service f629e6
int_copy(NODE *symbol, NODE *newsymb)
Packit Service f629e6
{
Packit Service f629e6
	BUCKET **old, **new, **pnew;
Packit Service f629e6
	BUCKET *chain, *newchain;
Packit Service f629e6
	int j;
Packit Service f629e6
	unsigned long i, cursize;
Packit Service f629e6
Packit Service f629e6
	assert(symbol->buckets != NULL);
Packit Service f629e6
Packit Service f629e6
	/* find the current hash size */
Packit Service f629e6
	cursize = symbol->array_size;
Packit Service f629e6
Packit Service f629e6
	/* allocate new table */
Packit Service f629e6
	ezalloc(new, BUCKET **, cursize * sizeof(BUCKET *), "int_copy");
Packit Service f629e6
Packit Service f629e6
	old = symbol->buckets;
Packit Service f629e6
Packit Service f629e6
	for (i = 0; i < cursize; i++) {
Packit Service f629e6
		for (chain = old[i], pnew = & new[i]; chain != NULL;
Packit Service f629e6
				chain = chain->ainext
Packit Service f629e6
		) {
Packit Service f629e6
			getbucket(newchain);
Packit Service f629e6
			newchain->aicount = chain->aicount;
Packit Service f629e6
			newchain->ainext = NULL;
Packit Service f629e6
			for (j = 0; j < chain->aicount; j++) {
Packit Service f629e6
				NODE *oldval;
Packit Service f629e6
Packit Service f629e6
				/*
Packit Service f629e6
				 * copy the corresponding key and
Packit Service f629e6
				 * value from the original input list
Packit Service f629e6
				 */
Packit Service f629e6
				newchain->ainum[j] = chain->ainum[j];
Packit Service f629e6
Packit Service f629e6
				oldval = chain->aivalue[j];
Packit Service f629e6
				if (oldval->type == Node_val)
Packit Service f629e6
					newchain->aivalue[j] = dupnode(oldval);
Packit Service f629e6
				else {
Packit Service f629e6
					NODE *r;
Packit Service f629e6
					r = make_array();
Packit Service f629e6
					r->vname = estrdup(oldval->vname, strlen(oldval->vname));
Packit Service f629e6
					r->parent_array = newsymb;
Packit Service f629e6
					newchain->aivalue[j] = assoc_copy(oldval, r);
Packit Service f629e6
				}
Packit Service f629e6
			}
Packit Service f629e6
Packit Service f629e6
			*pnew = newchain;
Packit Service f629e6
			newchain->ainext = NULL;
Packit Service f629e6
			pnew = & newchain->ainext;
Packit Service f629e6
		}
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if (symbol->xarray != NULL) {
Packit Service f629e6
		NODE *xn, *n;
Packit Service f629e6
		xn = symbol->xarray;
Packit Service f629e6
		n = make_array();
Packit Service f629e6
		n->vname = newsymb->vname;	/* shallow copy */
Packit Service f629e6
		(void) xn->acopy(xn, n);
Packit Service f629e6
		newsymb->xarray = n;
Packit Service f629e6
	} else
Packit Service f629e6
		newsymb->xarray = NULL;
Packit Service f629e6
Packit Service f629e6
	newsymb->table_size = symbol->table_size;
Packit Service f629e6
	newsymb->buckets = new;
Packit Service f629e6
	newsymb->array_size = cursize;
Packit Service f629e6
	newsymb->flags = symbol->flags;
Packit Service f629e6
Packit Service f629e6
	return NULL;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/* int_list --- return a list of array items */
Packit Service f629e6
Packit Service f629e6
static NODE**
Packit Service f629e6
int_list(NODE *symbol, NODE *t)
Packit Service f629e6
{
Packit Service f629e6
	NODE **list = NULL;
Packit Service f629e6
	unsigned long num_elems, list_size, i, k = 0;
Packit Service f629e6
	BUCKET *b;
Packit Service f629e6
	NODE *r, *subs, *xn;
Packit Service f629e6
	int j, elem_size = 1;
Packit Service f629e6
	long num;
Packit Service f629e6
	static char buf[100];
Packit Service f629e6
	assoc_kind_t assoc_kind;
Packit Service f629e6
Packit Service f629e6
	if (symbol->table_size == 0)
Packit Service f629e6
		return NULL;
Packit Service f629e6
Packit Service f629e6
	assoc_kind = (assoc_kind_t) t->flags;
Packit Service f629e6
	num_elems = symbol->table_size;
Packit Service f629e6
	if ((assoc_kind & (AINDEX|AVALUE|ADELETE)) == (AINDEX|ADELETE))
Packit Service f629e6
		num_elems = 1;
Packit Service f629e6
Packit Service f629e6
	if ((assoc_kind & (AINDEX|AVALUE)) == (AINDEX|AVALUE))
Packit Service f629e6
		elem_size = 2;
Packit Service f629e6
	list_size = elem_size * num_elems;
Packit Service f629e6
Packit Service f629e6
	if (symbol->xarray != NULL) {
Packit Service f629e6
		xn = symbol->xarray;
Packit Service f629e6
		list = xn->alist(xn, t);
Packit Service f629e6
		assert(list != NULL);
Packit Service f629e6
		if (num_elems == 1 || num_elems == xn->table_size)
Packit Service f629e6
			return list;
Packit Service f629e6
		erealloc(list, NODE **, list_size * sizeof(NODE *), "int_list");
Packit Service f629e6
		k = elem_size * xn->table_size;
Packit Service f629e6
	} else
Packit Service f629e6
		emalloc(list, NODE **, list_size * sizeof(NODE *), "int_list");
Packit Service f629e6
Packit Service f629e6
	/* populate it */
Packit Service f629e6
Packit Service f629e6
	for (i = 0; i < symbol->array_size; i++) {
Packit Service f629e6
		for (b = symbol->buckets[i]; b != NULL;	b = b->ainext) {
Packit Service f629e6
			for (j = 0; j < b->aicount; j++) {
Packit Service f629e6
				/* index */
Packit Service f629e6
				num = b->ainum[j];
Packit Service f629e6
				if ((assoc_kind & AISTR) != 0) {
Packit Service f629e6
					sprintf(buf, "%ld", num);
Packit Service f629e6
					subs = make_string(buf, strlen(buf));
Packit Service f629e6
					subs->numbr = num;
Packit Service f629e6
					subs->flags |= (NUMCUR|NUMINT);
Packit Service f629e6
				} else {
Packit Service f629e6
					subs = make_number((AWKNUM) num);
Packit Service f629e6
					subs->flags |= (INTIND|NUMINT);
Packit Service f629e6
				}
Packit Service f629e6
				list[k++] = subs;
Packit Service f629e6
Packit Service f629e6
				/* value */
Packit Service f629e6
				if ((assoc_kind & AVALUE) != 0) {
Packit Service f629e6
					r = b->aivalue[j];
Packit Service f629e6
					if (r->type == Node_val) {
Packit Service f629e6
						if ((assoc_kind & AVNUM) != 0)
Packit Service f629e6
							(void) force_number(r);
Packit Service f629e6
						else if ((assoc_kind & AVSTR) != 0)
Packit Service f629e6
							r = force_string(r);
Packit Service f629e6
					}
Packit Service f629e6
					list[k++] = r;
Packit Service f629e6
				}
Packit Service f629e6
Packit Service f629e6
				if (k >= list_size)
Packit Service f629e6
					return list;
Packit Service f629e6
			}
Packit Service f629e6
		}
Packit Service f629e6
	}
Packit Service f629e6
	return list;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/* int_kilobytes --- calculate memory consumption of the assoc array */
Packit Service f629e6
Packit Service f629e6
AWKNUM
Packit Service f629e6
int_kilobytes(NODE *symbol)
Packit Service f629e6
{
Packit Service f629e6
	unsigned long i, bucket_cnt = 0;
Packit Service f629e6
	BUCKET *b;
Packit Service f629e6
	AWKNUM kb;
Packit Service f629e6
	extern AWKNUM str_kilobytes(NODE *symbol);
Packit Service f629e6
Packit Service f629e6
	for (i = 0; i < symbol->array_size; i++) {
Packit Service f629e6
		for (b = symbol->buckets[i]; b != NULL; b = b->ainext)
Packit Service f629e6
			bucket_cnt++;
Packit Service f629e6
	}
Packit Service f629e6
	kb = (((AWKNUM) bucket_cnt) * sizeof (BUCKET) +
Packit Service f629e6
			((AWKNUM) symbol->array_size) * sizeof (BUCKET *)) / 1024.0;
Packit Service f629e6
Packit Service f629e6
	if (symbol->xarray != NULL)
Packit Service f629e6
		kb += str_kilobytes(symbol->xarray);
Packit Service f629e6
Packit Service f629e6
	return kb;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/* int_dump --- dump array info */
Packit Service f629e6
Packit Service f629e6
static NODE **
Packit Service f629e6
int_dump(NODE *symbol, NODE *ndump)
Packit Service f629e6
{
Packit Service f629e6
#define HCNT	31
Packit Service f629e6
Packit Service f629e6
	int indent_level;
Packit Service f629e6
	BUCKET *b;
Packit Service f629e6
	NODE *xn = NULL;
Packit Service f629e6
	unsigned long str_size = 0, int_size = 0;
Packit Service f629e6
	unsigned long i;
Packit Service f629e6
	size_t j, bucket_cnt;
Packit Service f629e6
	static size_t hash_dist[HCNT + 1];
Packit Service f629e6
Packit Service f629e6
	indent_level = ndump->alevel;
Packit Service f629e6
Packit Service f629e6
	if (symbol->xarray != NULL) {
Packit Service f629e6
		xn = symbol->xarray;
Packit Service f629e6
		str_size = xn->table_size;
Packit Service f629e6
	}
Packit Service f629e6
	int_size = symbol->table_size - str_size;
Packit Service f629e6
Packit Service f629e6
	if ((symbol->flags & XARRAY) == 0)
Packit Service f629e6
		fprintf(output_fp, "%s `%s'\n",
Packit Service f629e6
				(symbol->parent_array == NULL) ? "array" : "sub-array",
Packit Service f629e6
				array_vname(symbol));
Packit Service f629e6
Packit Service f629e6
	indent_level++;
Packit Service f629e6
	indent(indent_level);
Packit Service f629e6
	fprintf(output_fp, "array_func: int_array_func\n");
Packit Service f629e6
	if (symbol->flags != 0) {
Packit Service f629e6
		indent(indent_level);
Packit Service f629e6
		fprintf(output_fp, "flags: %s\n", flags2str(symbol->flags));
Packit Service f629e6
	}
Packit Service f629e6
	indent(indent_level);
Packit Service f629e6
	fprintf(output_fp, "INT_CHAIN_MAX: %lu\n", (unsigned long) INT_CHAIN_MAX);
Packit Service f629e6
	indent(indent_level);
Packit Service f629e6
	fprintf(output_fp, "array_size: %lu (int)\n", (unsigned long) symbol->array_size);
Packit Service f629e6
	indent(indent_level);
Packit Service f629e6
	fprintf(output_fp, "table_size: %lu (total), %lu (int), %lu (str)\n",
Packit Service f629e6
			(unsigned long) symbol->table_size, int_size, str_size);
Packit Service f629e6
	indent(indent_level);
Packit Service f629e6
	fprintf(output_fp, "Avg # of items per chain (int): %.2g\n",
Packit Service f629e6
			((AWKNUM) int_size) / symbol->array_size);
Packit Service f629e6
Packit Service f629e6
	indent(indent_level);
Packit Service f629e6
	fprintf(output_fp, "memory: %.2g kB (total)\n", int_kilobytes(symbol));
Packit Service f629e6
Packit Service f629e6
	/* hash value distribution */
Packit Service f629e6
Packit Service f629e6
	memset(hash_dist, '\0', (HCNT + 1) * sizeof(size_t));
Packit Service f629e6
	for (i = 0; i < symbol->array_size; i++) {
Packit Service f629e6
		bucket_cnt = 0;
Packit Service f629e6
		for (b = symbol->buckets[i]; b != NULL;	b = b->ainext)
Packit Service f629e6
			bucket_cnt += b->aicount;
Packit Service f629e6
		if (bucket_cnt >= HCNT)
Packit Service f629e6
			bucket_cnt = HCNT;
Packit Service f629e6
		hash_dist[bucket_cnt]++;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	indent(indent_level);
Packit Service f629e6
	fprintf(output_fp, "Hash distribution:\n");
Packit Service f629e6
	indent_level++;
Packit Service f629e6
	for (j = 0; j <= HCNT; j++) {
Packit Service f629e6
		if (hash_dist[j] > 0) {
Packit Service f629e6
			indent(indent_level);
Packit Service f629e6
			if (j == HCNT)
Packit Service f629e6
				fprintf(output_fp, "[>=%lu]:%lu\n",
Packit Service f629e6
					(unsigned long) HCNT, (unsigned long) hash_dist[j]);
Packit Service f629e6
			else
Packit Service f629e6
				fprintf(output_fp, "[%lu]:%lu\n",
Packit Service f629e6
					(unsigned long) j, (unsigned long) hash_dist[j]);
Packit Service f629e6
		}
Packit Service f629e6
	}
Packit Service f629e6
	indent_level--;
Packit Service f629e6
Packit Service f629e6
	/* dump elements */
Packit Service f629e6
Packit Service f629e6
	if (ndump->adepth >= 0) {
Packit Service f629e6
		NODE *subs;
Packit Service f629e6
		const char *aname;
Packit Service f629e6
Packit Service f629e6
		fprintf(output_fp, "\n");
Packit Service f629e6
Packit Service f629e6
		aname = make_aname(symbol);
Packit Service f629e6
		subs = make_number((AWKNUM) 0);
Packit Service f629e6
		subs->flags |= (INTIND|NUMINT);
Packit Service f629e6
Packit Service f629e6
		for (i = 0; i < symbol->array_size; i++) {
Packit Service f629e6
			for (b = symbol->buckets[i]; b != NULL; b = b->ainext) {
Packit Service f629e6
				for (j = 0; j < b->aicount; j++) {
Packit Service f629e6
					subs->numbr = b->ainum[j];
Packit Service f629e6
					assoc_info(subs, b->aivalue[j], ndump, aname);
Packit Service f629e6
				}
Packit Service f629e6
			}
Packit Service f629e6
		}
Packit Service f629e6
		unref(subs);
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if (xn != NULL)	{
Packit Service f629e6
		fprintf(output_fp, "\n");
Packit Service f629e6
		xn->adump(xn, ndump);
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	return NULL;
Packit Service f629e6
Packit Service f629e6
#undef HCNT
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/* int_hash --- calculate the hash function of the integer subs */
Packit Service f629e6
Packit Service f629e6
static uint32_t
Packit Service f629e6
int_hash(uint32_t k, uint32_t hsize)
Packit Service f629e6
{
Packit Service f629e6
Packit Service f629e6
/*
Packit Service f629e6
 * Code snippet copied from:
Packit Service f629e6
 *	Hash functions (http://www.azillionmonkeys.com/qed/hash.html).
Packit Service f629e6
 *	Copyright 2004-2008 by Paul Hsieh. Licenced under LGPL 2.1.
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
	/* This is the final mixing function used by Paul Hsieh in SuperFastHash. */
Packit Service f629e6
Packit Service f629e6
	k ^= k << 3;
Packit Service f629e6
	k += k >> 5;
Packit Service f629e6
	k ^= k << 4;
Packit Service f629e6
	k += k >> 17;
Packit Service f629e6
	k ^= k << 25;
Packit Service f629e6
	k += k >> 6;
Packit Service f629e6
Packit Service f629e6
	if (k >= hsize)
Packit Service f629e6
		k %= hsize;
Packit Service f629e6
	return k;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* int_find --- locate symbol[subs] */
Packit Service f629e6
Packit Service f629e6
static inline NODE **
Packit Service f629e6
int_find(NODE *symbol, long k, uint32_t hash1)
Packit Service f629e6
{
Packit Service f629e6
	BUCKET *b;
Packit Service f629e6
	int i;
Packit Service f629e6
Packit Service f629e6
	assert(symbol->buckets != NULL);
Packit Service f629e6
	for (b = symbol->buckets[hash1]; b != NULL; b = b->ainext) {
Packit Service f629e6
		for (i = 0; i < b->aicount; i++) {
Packit Service f629e6
			if (b->ainum[i] == k)
Packit Service f629e6
				return (b->aivalue + i);
Packit Service f629e6
		}
Packit Service f629e6
	}
Packit Service f629e6
	return NULL;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/* int_insert --- install subs in the assoc array */
Packit Service f629e6
Packit Service f629e6
static NODE **
Packit Service f629e6
int_insert(NODE *symbol, long k, uint32_t hash1)
Packit Service f629e6
{
Packit Service f629e6
	BUCKET *b;
Packit Service f629e6
	int i;
Packit Service f629e6
Packit Service f629e6
	b = symbol->buckets[hash1];
Packit Service f629e6
Packit Service f629e6
	/* Only the first bucket in the chain can be partially full, but is never empty. */
Packit Service f629e6
Packit Service f629e6
	if (b == NULL || (i = b->aicount) == 2) {
Packit Service f629e6
		getbucket(b);
Packit Service f629e6
		b->aicount = 0;
Packit Service f629e6
		b->ainext = symbol->buckets[hash1];
Packit Service f629e6
		symbol->buckets[hash1] = b;
Packit Service f629e6
		i = 0;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	b->ainum[i] = k;
Packit Service f629e6
	b->aivalue[i] = dupnode(Nnull_string);
Packit Service f629e6
	b->aicount++;
Packit Service f629e6
	return & b->aivalue[i];
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/* grow_int_table --- grow the hash table */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
grow_int_table(NODE *symbol)
Packit Service f629e6
{
Packit Service f629e6
	BUCKET **old, **new;
Packit Service f629e6
	BUCKET *chain, *next;
Packit Service f629e6
	int i, j;
Packit Service f629e6
	unsigned long oldsize, newsize, k;
Packit Service f629e6
Packit Service f629e6
	/*
Packit Service f629e6
	 * This is an array of primes. We grow the table by an order of
Packit Service f629e6
	 * magnitude each time (not just doubling) so that growing is a
Packit Service f629e6
	 * rare operation. We expect, on average, that it won't happen
Packit Service f629e6
	 * more than twice.  The final size is also chosen to be small
Packit Service f629e6
	 * enough so that MS-DOG mallocs can handle it. When things are
Packit Service f629e6
	 * very large (> 8K), we just double more or less, instead of
Packit Service f629e6
	 * just jumping from 8K to 64K.
Packit Service f629e6
	 */
Packit Service f629e6
Packit Service f629e6
	static const unsigned long sizes[] = {
Packit Service f629e6
		13, 127, 1021, 8191, 16381, 32749, 65497,
Packit Service f629e6
		131101, 262147, 524309, 1048583, 2097169,
Packit Service f629e6
		4194319, 8388617, 16777259, 33554467,
Packit Service f629e6
		67108879, 134217757, 268435459, 536870923,
Packit Service f629e6
		1073741827
Packit Service f629e6
	};
Packit Service f629e6
Packit Service f629e6
	/* find next biggest hash size */
Packit Service f629e6
	newsize = oldsize = symbol->array_size;
Packit Service f629e6
Packit Service f629e6
	for (i = 0, j = sizeof(sizes)/sizeof(sizes[0]); i < j; i++) {
Packit Service f629e6
		if (oldsize < sizes[i]) {
Packit Service f629e6
			newsize = sizes[i];
Packit Service f629e6
			break;
Packit Service f629e6
		}
Packit Service f629e6
	}
Packit Service f629e6
	if (newsize == oldsize) {	/* table already at max (!) */
Packit Service f629e6
		symbol->flags |= ARRAYMAXED;
Packit Service f629e6
		return;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	/* allocate new table */
Packit Service f629e6
	ezalloc(new, BUCKET **, newsize * sizeof(BUCKET *), "grow_int_table");
Packit Service f629e6
Packit Service f629e6
	old = symbol->buckets;
Packit Service f629e6
	symbol->buckets = new;
Packit Service f629e6
	symbol->array_size = newsize;
Packit Service f629e6
Packit Service f629e6
	/* brand new hash table */
Packit Service f629e6
	if (old == NULL)
Packit Service f629e6
		return;		/* DO NOT initialize symbol->table_size */
Packit Service f629e6
Packit Service f629e6
	/* old hash table there, move stuff to new, free old */
Packit Service f629e6
	/* note that symbol->table_size does not change if an old array. */
Packit Service f629e6
Packit Service f629e6
	for (k = 0; k < oldsize; k++) {
Packit Service f629e6
		long num;
Packit Service f629e6
		for (chain = old[k]; chain != NULL; chain = next) {
Packit Service f629e6
			for (i = 0; i < chain->aicount; i++) {
Packit Service f629e6
				num = chain->ainum[i];
Packit Service f629e6
				*int_insert(symbol, num, int_hash(num, newsize)) = chain->aivalue[i];
Packit Service f629e6
			}
Packit Service f629e6
			next = chain->ainext;
Packit Service f629e6
			freebucket(chain);
Packit Service f629e6
		}
Packit Service f629e6
	}
Packit Service f629e6
	efree(old);
Packit Service f629e6
}