Page 145

Write a function undef that will remove a name and definition from the table maintained by lookup and install.

#include <string.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

struct nlist {
	struct nlist *next;
	char *name;
	char *defn;
};

#define HASHSIZE 101
static struct nlist *hashtab[HASHSIZE];

struct nlist *install(char *name, char *defn);
struct nlist *lookup(char *name);
bool undef(char *name);

int main()
{
	install("name", "val");
	printf("After defining: %s\n", lookup("name")->defn);
	undef("name");
	struct nlist *res = lookup("name");
	printf("Exists? %d\n", res != NULL);
}

unsigned hash(char *s)
{
	unsigned hashval;

	for (hashval = 0; *s != '\0'; s++) {
		hashval = *s + 31 * hashval;
	}
	return hashval % HASHSIZE;
}

struct nlist *lookup(char *s)
{
	struct nlist *np;

	for (np = hashtab[hash(s)]; np != NULL; np = np->next) {
		if (strcmp(s, np->name) == 0) {
			return np;
		}
	}
	return NULL;
}

struct nlist *install(char *name, char *defn)
{
	struct nlist *np;
	unsigned hashval;

	if ((np = lookup(name)) == NULL) {
		np = (struct nlist *)malloc(sizeof(*np));
		if (np == NULL || (np->name = strdup(name)) == NULL) {
			return NULL;
		}
		hashval = hash(name);
		np->next = hashtab[hashval];
		hashtab[hashval] = np;
	} else {
		free((void *)np->defn);
	}
	if ((np->defn = strdup(defn)) == NULL) {
		return NULL;
	}
	return np;
}

bool undef(char *name)
{
	struct nlist *np = lookup(name);
	struct nlist *np_prev = NULL;
	unsigned hashval = hash(name);

	for (np = hashtab[hashval]; np != NULL; np_prev = np, np = np->next) {
		if (strcmp(name, np->name) == 0) {
			if (np_prev != NULL) {
				np_prev->next = np->next;
			} else {
				hashtab[hashval] = NULL;
			}
		}
	}

	if (np_prev != NULL) {
		free(np_prev->name);
		free(np_prev->defn);
		free(np_prev);
		return true;
	}

	return false;
}