/*  Small compiler  - maintenance of various lists
 *
 *  Name list (aliases)
 *  Include path list
 *
 *  Copyright (c) ITB CompuPhase, 2001-2003
 *
 *  This software is provided "as-is", without any express or implied warranty.
 *  In no event will the authors be held liable for any damages arising from
 *  the use of this software.
 *
 *  Permission is granted to anyone to use this software for any purpose,
 *  including commercial applications, and to alter it and redistribute it
 *  freely, subject to the following restrictions:
 *
 *  1.  The origin of this software must not be misrepresented; you must not
 *      claim that you wrote the original software. If you use this software in
 *      a product, an acknowledgment in the product documentation would be
 *      appreciated but is not required.
 *  2.  Altered source versions must be plainly marked as such, and must not be
 *      misrepresented as being the original software.
 *  3.  This notice may not be removed or altered from any source distribution.
 *
 *  Version: $Id$
 */


#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "embryo_cc_sc.h"

static stringpair  *
insert_stringpair(stringpair * root, char *first, char *second, int matchlength)
{
   stringpair         *cur, *pred;

   assert(root != NULL);
   assert(first != NULL);
   assert(second != NULL);
   /* create a new node, and check whether all is okay */
   if (!(cur = (stringpair *)malloc(sizeof(stringpair))))
      return NULL;
   cur->first = strdup(first);
   cur->second = strdup(second);
   cur->matchlength = matchlength;
   if (!cur->first || !cur->second)
     {
	if (cur->first)
	   free(cur->first);
	if (cur->second)
	   free(cur->second);
	free(cur);
	return NULL;
     }				/* if */
   /* link the node to the tree, find the position */
   for (pred = root; pred->next && strcmp(pred->next->first, first) < 0;
	pred = pred->next)
      /* nothing */ ;
   cur->next = pred->next;
   pred->next = cur;
   return cur;
}

static void
delete_stringpairtable(stringpair * root)
{
   stringpair         *cur, *next;

   assert(root != NULL);
   cur = root->next;
   while (cur)
     {
	next = cur->next;
	assert(cur->first != NULL);
	assert(cur->second != NULL);
	free(cur->first);
	free(cur->second);
	free(cur);
	cur = next;
     }				/* while */
   memset(root, 0, sizeof(stringpair));
}

static stringpair  *
find_stringpair(stringpair * cur, char *first, int matchlength)
{
   int                 result = 0;

   assert(matchlength > 0);	/* the function cannot handle zero-length comparison */
   assert(first != NULL);
   while (cur && result <= 0)
     {
	result = (int)*cur->first - (int)*first;
	if (result == 0 && matchlength == cur->matchlength)
	  {
	     result = strncmp(cur->first, first, matchlength);
	     if (result == 0)
		return cur;
	  }			/* if */
	cur = cur->next;
     }				/* while */
   return NULL;
}

static int
delete_stringpair(stringpair * root, stringpair * item)
{
   stringpair         *cur;

   assert(root != NULL);
   cur = root;
   while (cur->next)
     {
	if (cur->next == item)
	  {
	     cur->next = item->next;	/* unlink from list */
	     assert(item->first != NULL);
	     assert(item->second != NULL);
	     free(item->first);
	     free(item->second);
	     free(item);
	     return TRUE;
	  }			/* if */
	cur = cur->next;
     }				/* while */
   return FALSE;
}

/* ----- alias table --------------------------------------------- */
static stringpair   alias_tab = { NULL, NULL, NULL, 0 };    /* alias table */

stringpair *
insert_alias(char *name, char *alias)
{
   stringpair         *cur;

   assert(name != NULL);
   assert(strlen(name) <= sNAMEMAX);
   assert(alias != NULL);
   assert(strlen(alias) <= sEXPMAX);
   if (!(cur = insert_stringpair(&alias_tab, name, alias, strlen(name))))
      error(103);		/* insufficient memory (fatal error) */
   return cur;
}

int
lookup_alias(char *target, char *name)
{
   stringpair         *cur =
      find_stringpair(alias_tab.next, name, strlen(name));
   if (cur)
     {
	assert(strlen(cur->second) <= sEXPMAX);
	strcpy(target, cur->second);
     }				/* if */
   return !!cur;
}

void
delete_aliastable(void)
{
   delete_stringpairtable(&alias_tab);
}

/* ----- include paths list -------------------------------------- */
static stringlist   includepaths = { NULL, NULL };	/* directory list for include files */

stringlist *
insert_path(char *path)
{
   stringlist         *cur;

   assert(path != NULL);
   if (!(cur = (stringlist *)malloc(sizeof(stringlist))))
      error(103);		/* insufficient memory (fatal error) */
   if (!(cur->line = strdup(path)))
      error(103);		/* insufficient memory (fatal error) */
   cur->next = includepaths.next;
   includepaths.next = cur;
   return cur;
}

char *
get_path(int idx)
{
   stringlist         *cur = includepaths.next;

   while (cur && idx-- > 0)
      cur = cur->next;
   if (cur)
     {
	assert(cur->line != NULL);
	return cur->line;
     }				/* if */
   return NULL;
}

void
delete_pathtable(void)
{
   stringlist         *cur = includepaths.next, *next;

   while (cur)
     {
	next = cur->next;
	assert(cur->line != NULL);
	free(cur->line);
	free(cur);
	cur = next;
     }				/* while */
   memset(&includepaths, 0, sizeof(stringlist));
}

/* ----- text substitution patterns ------------------------------ */

static stringpair   substpair = { NULL, NULL, NULL, 0 };    /* list of substitution pairs */
static stringpair  *substindex['z' - 'A' + 1];	/* quick index to first character */

static void
adjustindex(char c)
{
   stringpair         *cur;

   assert((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_');
   assert('A' < '_' && '_' < 'z');

   for (cur = substpair.next; cur && cur->first[0] != c;
	cur = cur->next)
      /* nothing */ ;
   substindex[(int)c - 'A'] = cur;
}

stringpair *
insert_subst(char *pattern, char *substitution, int prefixlen)
{
   stringpair         *cur;

   assert(pattern != NULL);
   assert(substitution != NULL);
   if (!(cur = insert_stringpair(&substpair, pattern, substitution, prefixlen)))
      error(103);		/* insufficient memory (fatal error) */
   adjustindex(*pattern);
   return cur;
}

stringpair *
find_subst(char *name, int length)
{
   stringpair         *item;

   assert(name != NULL);
   assert(length > 0);
   assert((*name >= 'A' && *name <= 'Z') || (*name >= 'a' && *name <= 'z')
	  || *name == '_');
   item = substindex[(int)*name - 'A'];
   if (item)
      item = find_stringpair(item, name, length);
   return item;
}

int
delete_subst(char *name, int length)
{
   stringpair         *item;

   assert(name != NULL);
   assert(length > 0);
   assert((*name >= 'A' && *name <= 'Z') || (*name >= 'a' && *name <= 'z')
	  || *name == '_');
   item = substindex[(int)*name - 'A'];
   if (item)
      item = find_stringpair(item, name, length);
   if (!item)
      return FALSE;
   delete_stringpair(&substpair, item);
   adjustindex(*name);
   return TRUE;
}

void
delete_substtable(void)
{
   int                 i;

   delete_stringpairtable(&substpair);
   for (i = 0; i < (int)(sizeof(substindex) / sizeof(substindex[0])); i++)
      substindex[i] = NULL;
}
