#include <stdio.h>
#include "Code.h"

static int numDomains;
/* not static because some routines are macro implementations */
CodeDomain codeDomains[MAXCODEDOMAINS];

Trap Code_Initialize()
{
  numDomains = 0;

  return OK;
}

/*
 * ERRORS:
 *
 * CODE_DOMAINEXISTS: FATAL
 * Could not register domain %s: domain is already registered.
 *
 * CODE_DOMAINLISTFULL: FATAL
 * Could not register domain %s: domain table is full.
 */
Trap Code_RegisterDomain(domain)
     CodeDomain *domain;
{
  int i;

  for (i = 0; i < numDomains; i++)
    if (!strcmp(domain->Domain, codeDomains[i].Domain))
      Return(CODE_DOMAINEXISTS, domain->Domain);

  if (numDomains == MAXCODEDOMAINS)
    Return(CODE_DOMAINLISTFULL, domain->Domain);

  memcpy(&codeDomains[numDomains], domain, sizeof(CodeDomain));
  numDomains++;

  return OK;
}

Trap Code_FreeBlock(block)
     CodeBlock *block;
{
  if (block->malloced)
    free(block->data);

  free(block);
  return OK;
}

/*
 * ERRORS:
 *
 * CODE_DOMAINUNKNOWN: FATAL
 * The domain %s has never been registered.
 */
Trap Code_SetDomain(block, domain)
     CodeBlock *block;
     char *domain;
{
  int i;

  for (i = 0; i < numDomains; i++)
    if (!strcmp(domain, codeDomains[i].Domain))
      {
	block->domain = i;
	return OK;
      }

  Return(CODE_DOMAINUNKNOWN, domain);
}

Trap Code_InitBlock(block, domain, data, sizeHint)
     CodeBlock *block;
     char *domain;
     char *data;
     int sizeHint;
{
  if (Code_SetDomain(block, domain) &&
      Error_Severity == S_FATAL)
    return CHECK;

  if (data != NULL)
    {
      block->data = data;
      block->dataSize = sizeHint;
      block->malloced = 0;
    }
  else
    {
      if (sizeHint == 0)
	sizeHint = 512;
      block->data = (char *)malloc(sizeHint);
      block->dataSize = sizeHint;
      block->malloced = 1;
    }

  block->current = block->data;
  block->initialSize = block->dataSize;

  if (block->data == NULL)
    Return(GENERAL_MALLOC, sizeHint);

  return OK;
}

Trap Code_CreateBlock(block, domain, data, sizeHint)
     CodeBlock **block;
     char *domain;
     char *data;
     int sizeHint;
{
  CodeBlock *b;

  b = (CodeBlock *)malloc(sizeof(CodeBlock));
  if (b == NULL)
    Return(GENERAL_MALLOC, sizeof(CodeBlock));

  if (Code_InitBlock(b, domain, data, sizeHint) &&
      Error_Severity == S_FATAL)
    {
      free(b);
      return CHECK;
    }

  *block = b;
}

Trap Code_Expand(block, min)
     CodeBlock *block;
     int min;
{
  int delta;

  if (block->malloced == 0)
    Return(GENERAL_MALLOC, 0);	/* XXX inaccurate */

  delta = (min > block->initialSize) ? min : block->initialSize;

  block->data = (char *)realloc(block->data, block->dataSize + delta);
  if (block->data == 0)
    Return(GENERAL_MALLOC, block->dataSize + delta);	/* XXX also */

  block->dataSize += delta;
  return OK;
}
