/********************************************
mawk_hash.c
libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
based on mawk code coming with the below copyright:
copyright 1991, Michael D. Brennan
This is a source file for mawk, an implementation of
the AWK programming language.
Mawk is distributed without warranty under the terms of
the GNU General Public License, version 2, 1991.
********************************************/
#include "mawk.h"
#include "memory.h"
#include "symtype.h"
#include "cell.h"
#include <string.h>
unsigned mawk_hash(register const char *s)
{
register unsigned h = 0;
while (*s)
h += h + *s++;
return h;
}
static HASHNODE *delete(mawk_state_t *, const char *);
/*
mawk_insert a string in the symbol table.
Caller knows the symbol is not there
-- used for initialization
the name must persist (can not be free'd as long as symbol is in the table
and it won't be free'd at the end either)!
*/
SYMTAB *mawk_insert(mawk_state_t *MAWK, const char *name)
{
register HASHNODE *p = MAWK_ZMALLOC(MAWK, HASHNODE);
register unsigned h;
p->link = MAWK->hash_table[h = mawk_hash(name) % HASH_PRIME];
p->symtab.name = name;
MAWK->hash_table[h] = p;
return &p->symtab;
}
/* Find s in the symbol table,
if not there and alloc !=0 mawk_insert it (s must be dup'ed) */
SYMTAB *mawk_find(mawk_state_t *MAWK, const char *s, int alloc)
{
register HASHNODE *p;
HASHNODE *q;
unsigned h;
p = MAWK->hash_table[h = mawk_hash(s) % HASH_PRIME];
q = (HASHNODE *) 0;
while (1) {
if (!p) {
if (alloc) {
p = MAWK_ZMALLOC(MAWK, HASHNODE);
p->symtab.type = ST_NONE;
p->symtab.name = strcpy(mawk_zmalloc(MAWK, strlen(s) + 1), s);
break;
}
else
return NULL;
}
if (strcmp(p->symtab.name, s) == 0) { /* found */
if (!q) /* already at the front */
return &p->symtab;
else { /* delete from the list */
q->link = p->link;
break;
}
}
q = p;
p = p->link;
}
/* put p on front of the list */
p->link = MAWK->hash_table[h];
MAWK->hash_table[h] = p;
return &p->symtab;
}
/* remove a node from the mawk_hash table
return a ptr to the node */
static HASHNODE *delete(mawk_state_t *MAWK, const char *s)
{
register HASHNODE *p;
HASHNODE *q = (HASHNODE *) 0;
unsigned h;
p = MAWK->hash_table[MAWK->last_hash = h = mawk_hash(s) % HASH_PRIME];
while (p) {
if (strcmp(p->symtab.name, s) == 0) { /* found */
if (q)
q->link = p->link;
else
MAWK->hash_table[h] = p->link;
return p;
}
else {
q = p;
p = p->link;
}
}
#ifdef DEBUG /* we should not ever get here */
mawk_bozo(MAWK, "delete");
#endif
return (HASHNODE *) 0;
}
#ifdef MAWK_MEM_PEDANTIC
#include <stdio.h>
static void mawk_delete_cell(mawk_state_t *MAWK, SYMTAB *stp)
{
switch(stp->type) {
case ST_NONE:
break;
case ST_VAR:
case ST_BUILTIN:
case ST_FIELD:
if (stp->stval.cp != NULL)
mawk_cell_destroy(MAWK, stp->stval.cp);
break;
case ST_ARRAY:
mawk_array_destroy(MAWK, stp->stval.array);
break;
case ST_FUNCT:
if (stp->stval.fbp->nargs > 0)
mawk_zfree(MAWK, stp->stval.fbp->typev, stp->stval.fbp->nargs);
if (stp->stval.fbp->code != NULL)
mawk_zfree(MAWK, stp->stval.fbp->code, stp->stval.fbp->size);
MAWK_ZFREE(MAWK, stp->stval.fbp);
break;
}
/* we should decide if name was dynamically allocated (from scan)...
if ((stp->name != NULL) && (stp->name_dyna)) {
int len = strlen(stp->name) + 1;
fprintf(stderr, "FR: '%s'\n", stp->name);
mawk_zfree(MAWK, (PTR) stp->name, len);
stp->name = NULL;
}*/
}
#define mawk_delete_node(p) MAWK_ZFREE(MAWK, p)
void mawk_delete(mawk_state_t *MAWK, const char *name, int cell_destroy)
{
register HASHNODE *p = delete(MAWK, name);
if (p != NULL) {
SYMTAB *stp = &p->symtab;
if (cell_destroy)
mawk_delete_cell(MAWK, stp);
mawk_delete_node(p);
}
}
#endif
/* store a global id on the save list,
return a ptr to the local symtab */
SYMTAB *mawk_save_id(mawk_state_t *MAWK, const char *s)
{
HASHNODE *p, *q;
unsigned h;
p = delete(MAWK, s);
q = MAWK_ZMALLOC(MAWK, HASHNODE);
q->symtab.type = ST_LOCAL_NONE;
q->symtab.name = p->symtab.name;
/* put q in the mawk_hash table */
q->link = MAWK->hash_table[h = MAWK->last_hash];
MAWK->hash_table[h] = q;
/* save p */
p->link = MAWK->save_list;
MAWK->save_list = p;
return &q->symtab;
}
/* restore all global indentifiers */
void mawk_restore_ids(mawk_state_t * MAWK)
{
register HASHNODE *p, *q;
register unsigned h;
q = MAWK->save_list;
MAWK->save_list = (HASHNODE *) 0;
while (q) {
p = q;
q = q->link;
mawk_zfree(MAWK, delete(MAWK, p->symtab.name), sizeof(HASHNODE));
p->link = MAWK->hash_table[h = MAWK->last_hash];
MAWK->hash_table[h] = p;
}
}
/* search the symbol table backwards for the
disassembler. This is slow -- so what
*/
const char *mawk_reverse_uk = "unknown";
const char *mawk_reverse_find(mawk_state_t *MAWK, int type, PTR ptr)
{
mawk_cell_t *cp;
mawk_array_t array;
int i;
HASHNODE *p;
switch (type) {
case ST_VAR:
case ST_FIELD:
cp = *(mawk_cell_t **) ptr;
break;
case ST_ARRAY:
array = *(mawk_array_t *) ptr;
break;
default:
return mawk_reverse_uk;
}
for (i = 0; i < HASH_PRIME; i++) {
p = MAWK->hash_table[i];
while (p) {
if (p->symtab.type == type) {
switch (type) {
case ST_VAR:
case ST_FIELD:
if (cp == p->symtab.stval.cp)
return p->symtab.name;
break;
case ST_ARRAY:
if (array == p->symtab.stval.array)
return p->symtab.name;
break;
}
}
p = p->link;
}
}
return mawk_reverse_uk;
}
#ifdef MAWK_MEM_PEDANTIC
/* free global hash entries */
void mawk_hash_clear(mawk_state_t *MAWK)
{
register HASHNODE *p, *next;
int n;
for(n = 0; n < HASH_PRIME; n++) {
for(p = MAWK->hash_table[n]; p != NULL; p = next) {
next = p->link;
mawk_delete_cell(MAWK, &(p->symtab));
mawk_delete_node(p);
}
}
}
#endif