#include "assoc.h"

#if !defined(_lint)
static char rcsid[] OPTIONAL = "$Id: assoc.c,v 1.11 1997/08/19 01:19:22 root Exp $";
#endif

#ifdef TEST
#define tprintf	printf
#define		NULLCHAR		((char *)0)
#else
#include "global.h"
#endif

static char assocstr[] = "%-*.*s : %s\n";

static AarrayPtr assoc_alloc (AarrayPPtr pool, int sorted, char *label);
static int assoc_add (AarrayPPtr pool, char *label, char *value, int length, int sorted);
#if 0	/* not used, yet */
static void assoc_clr (AarrayPPtr pool);
static void assoc_sort (AarrayPtr pool);



void
assoc_sort (AarrayPtr pool)
{
AarrayPtr aa;
int didone;
char *tmp;

	do	{
		didone = 0;
		for (aa = pool; aa && aa->next; aa = aa->next)	{
			if (strcmp (aa->name, aa->next->name) > 0)	{
				tmp = aa->name;
				aa->name = aa->next->name;
				aa->next->name = tmp;
				tmp = (char *)aa->macro;
				aa->macro = aa->next->macro;
				aa->next->macro = (unsigned char *)tmp;
				didone = 1;
			}
		}
	} while (didone);
}
#endif


unsigned char *
assoc_lookup (AarrayPtr pool, char *label)
{
AarrayPtr aa;

	if ((aa = assoc_find (pool, label)) == NULLASSOC)
		return (unsigned char *)0;
	else
		return aa->macro;
}


AarrayPtr
assoc_find (AarrayPtr pool, char *label)
{
AarrayPtr aa;

	if (label == NULLCHAR)
		return NULLASSOC;
	for (aa = pool; aa; aa = aa->next)
		if (!strcmp (label, aa->name))
			return aa;
	return NULLASSOC;
}


void
assoc_list (AarrayPtr pool, int maxlen, char *label)
{
AarrayPtr aa = NULLASSOC;

	if (pool == NULLASSOC)
		return;
	if (label != NULLCHAR)
		aa = assoc_find (pool, label);
	if ((label == NULLCHAR) || aa != NULLASSOC)
		tprintf (assocstr, maxlen, maxlen, "Name","Macro definition");
	if (label != NULLCHAR)	{
		if (aa != NULLASSOC)
			tprintf (assocstr, maxlen, maxlen, aa->name, (char *) aa->macro);
	} else	{
		for (aa = pool; aa; aa = aa->next)
			tprintf (assocstr, maxlen, maxlen, aa->name, (char *) aa->macro);
	}
}

int
assoc_addstr (AarrayPPtr pool, char *label, char *value, int sorted)
{
int len;

	len = (int) strlen (value);
	if (!len)
		return (assoc_free (pool, label));
	else
		return (assoc_add (pool, label, value, (int) (strlen(value) + 1), sorted));
}


static int
assoc_add (AarrayPPtr pool, char *label, char *value, int length, int sorted)
{
AarrayPtr aa;

	if ((aa = assoc_find (*pool, label)) == NULLASSOC)	{
		aa = assoc_alloc (pool, sorted, label);
		if (aa == NULLASSOC)
			return 0;
		aa->name = strdup (label);
	}
	if (aa->macro)
		free (aa->macro);
	aa->macro = (unsigned char *)mallocw (strlen (value) + 1);
	memcpy (aa->macro, value, (unsigned int)length);
	return 1;
}


static AarrayPtr
assoc_alloc (AarrayPPtr pool, int sorted, char *label)
{
AarrayPtr aa;

	aa = (AarrayPtr) callocw (sizeof (Aarray), 1);
	if (aa != NULLASSOC)	{
		if (!sorted)	{
			aa->next = *pool;
			if (*pool)
				(*pool)->prev = aa;
			*pool = aa;
		} else	{
			AarrayPtr ap;
			for (ap = *pool; ap; ap = ap->next)	{
				if (strcmp (label, ap->name) <= 0)	{
					aa->next = ap;
					aa->prev = ap->prev;
					if (ap->prev)
						ap->prev->next = aa;
					else
						*pool = aa;
					ap->prev = aa;
					break;
				}
				if (ap->next == NULLASSOC)	{
					ap->next = aa;
					aa->prev = ap;
					break;
				}
			}
			if (*pool == NULLASSOC)
				*pool = aa;
		}
	}
	return aa;
}


#if 0
static void
assoc_clr (AarrayPPtr pool)
{
	while (*pool != NULLASSOC)
		(void) assoc_free (pool, (*pool)->name);
}
#endif


int
assoc_free (AarrayPPtr pool, char *label)
{
AarrayPtr aa, ap;

	if ((aa = assoc_find (*pool, label)) == NULLASSOC)
		return 0;
	free (aa->name);
	free (aa->macro);
	ap = aa->prev;
	if (ap != NULLASSOC)	{
		ap->next = aa->next;
		if (aa->next)
			aa->next->prev = ap;
	} else	{	/* first one in list */
		*pool = aa->next;
		if (*pool)
			(*pool)->prev = NULLASSOC;
	}
	free (aa);
	return 1;
}

#ifdef TEST

AarrayPtr Home = NULLASSOC;
#define sortit 1
#define llen 15

void
main (void)
{
	setbuf (stdout, NULL);
	printf ("Initial listing:\n");
	assoc_list (Home, llen, NULLCHAR);
	putchar ('\n');
	assoc_addstr (&Home, "Test1", "Value1", sortit);
	assoc_addstr (&Home, "Test2", "Value2", sortit);
	assoc_addstr (&Home, "Test3", "Value3", sortit);
	assoc_addstr (&Home, "Test4", "Value4", sortit);
	assoc_list (Home, llen, NULLCHAR);
	putchar ('\n');
#if 0
	assoc_sort (Home);
	printf ("Now sorted...\n");
	assoc_list (Home, llen, NULLCHAR);
	putchar ('\n');
#endif
	assoc_addstr (&Home, "Test1", "Value1b", sortit);
	assoc_addstr (&Home, "Test2", "Value2b", sortit);
	assoc_addstr (&Home, "Test3", "Value3b", sortit);	
	assoc_addstr (&Home, "Test4", "Value4b", sortit);	
	assoc_list (Home, llen, NULLCHAR);
	putchar ('\n');
	assoc_free (&Home, "Test1");
	assoc_free (&Home, "Test5");
	assoc_list (Home, llen, NULLCHAR);
	putchar ('\n');
	printf ("looking for deleted Test1...\n");
	assoc_list (Home, llen, "Test1");
	printf ("looking for Test3...\n");
	assoc_list (Home, llen, "Test3");
	printf ("Test4's value is %s\n", assoc_lookup (Home, "Test4"));
	assoc_clr (&Home);
	printf ("Printing empty list:\n");
	assoc_list (Home, llen, NULLCHAR);
}
#endif
