/* nalloc.c */

/* Memory allocation routines Written By Lawrence Foard */
#include <stdio.h>
#include "nalloc.h"

static BIGBLK blks[MAXBLK];
static int inited = 0;

static void init()
{
  int a;
  inited = 1;
  for (a = 0; a < MAXBLK; a++) {
    blks[a].owner = NULL;
    blks[a].used = NULL;
    blks[a].blk = NULL;
  }
}

void na_clear(nalloc)
    NALLOC *nalloc;
{
  int a;
  for (a = 0; a < MAXBLK; a++)
    if (nalloc == blks[a].owner) {
      blks[a].owner = NULL;
      blks[a].used = 0;
    }
}

void na_close(nalloc)
    NALLOC *nalloc;
{
  int a;
  /* search block list freeing all owned by nalloc */
  for (a = 0; a < MAXBLK; a++)
    if (nalloc == blks[a].owner) {
      blks[a].owner = NULL;
      blks[a].used = 0;
    }
  free(nalloc);
}

NALLOC *na_open(size)
    int size;
{
  NALLOC *na = (NALLOC *) malloc(sizeof(NALLOC));
  if (!inited)
    init();
  na->size = size;
  na->offset = 0;
  na->free = NULL;
  na->curblk = 0;		/* Note this isn't correct but is checked
				 * anyways */
  return (na);
}

static int get_blk(na)
    NALLOC *na;
{
  int a;
  /* search for a block with no space used */
  /* NOTE: owned blocks with no used space are public property!!! */
  for (a = 0; a < MAXBLK; a++)
    if (!blks[a].used) {
      if (!blks[a].blk) {
	blks[a].blk = (char *) sbrk(SBSIZE);
#ifdef DEBUG
	fprintf(stderr, "new block %d used\n", a * SBSIZE);
#endif
      }
      blks[a].owner = na;
      return (a);
    }
  return (-1);
}

/* return a pointer to an area containing size bytes (size<SBSIZE) */
char *na_alloc(na, size)
    NALLOC *na;
    int size;
{
  char *p;
  /* make sure we still own the current block and that the data */
  /* will fit in it if we do */
  size += sizeof(int);
  if ((blks[na->curblk].owner != na) || (size > (SBSIZE - na->offset))) {
    na->curblk = get_blk(na);
    na->offset = 0;
  }
  p = (char *) (&(blks[na->curblk].blk[na->offset]));
  /* force p into integer alignment (yuck) */
  /* I'm not going to replace & with a division just because some silly */
  /* processor may have non power of two byte integers! */
  p = (char *) ((((unsigned int) p) + sizeof(int)) & ~(sizeof(int) - 1));
  na->offset += size;
  blks[na->curblk].used++;
  return (p);
}

char *na_ualloc(na, size)
    NALLOC *na;
    int size;
{
  char *p;
  /* make sure we still own the current block and that the data */
  /* will fit in it if we do */
  if ((blks[na->curblk].owner != na) || (size > (SBSIZE - na->offset))) {
    na->curblk = get_blk(na);
    na->offset = 0;
  }
  p = (char *) (&(blks[na->curblk].blk[na->offset]));
  na->offset += size;
  blks[na->curblk].used++;
  return (p);
}

/* reduces allocation given to last call by amount size */
void na_giveback(na, size)
    NALLOC *na;
    int size;
{
  na->offset -= size;
}

/* get an item out of nalloc free list */
char *na_get(na)
    NALLOC *na;
{
  if (na->free) {
    /* get next free list pointer */
    char *next = (char *) na->free;
    na->free = na->free->next;
    return (next);
  }
  return (na_alloc(na, na->size));
}

/* put an item back on the na free list */
void na_free(na, item)
    NALLOC *na;
    char *item;
{
  POINT *tmp = (POINT *) item;
  tmp->next = na->free;
  na->free = tmp;
}

/* do binary search to find block pointer belongs to */
int findit(ptr)
    char *ptr;
{
  int b;
  /* try linear search,eventually replace with binary */
  for (b = 0; b < (MAXBLK - 1); b++)
    if (blks[b].blk && (blks[b].blk <= ptr) && ((blks[b].blk + SBSIZE) > ptr))
      return (b);
#ifdef DEBUG
  fprintf(stderr, "pointer not found\n");
#endif
  return (-1);
#ifdef 0
  t = MAXBLK;
  b = 0;
  while (b < (t - 1)) {
    m = (b + t) / 2;
    /* see if this is it */
    if ((blks[m].blk <= ptr) && ((blks[m + 1].blk > ptr) || (blks[m + 1].blk))) {
      if ((ptr - blks[m].blk) > SBSIZE) {
	fprintf(stderr, "Pointer not in block\n");
	report();
	return (-1);
      }
      return (m);
    }
    if (blks[m].blk && (blks[m].blk < ptr))
      b = m;
    else
      t = m;
  }
  fprintf(stderr, "Pointer out of range\n");
  report();
  return (-1);
#endif /* 0 */
}

void na_unalloc(na, data)
    NALLOC *na;
    char *data;
{
  int a;
  /*
   * data-=sizeof(int); a= *((int*)data);
   */
  if (-1 == (a = findit(data))) {
    fprintf(stderr, "Can't find pointer\n");
    report();
    return;
  }
  if ((a < 0) || (a > MAXBLK)) {
    fprintf(stderr, "Attempt to unalloc messed up block\n");
    report();
    return;
  }
  if (blks[a].owner != na) {
    report();
    fprintf(stderr, "Attempt to unalloc unowned block\n");
    return;
  }
  if (blks[a].used <= 0) {
    report();
    fprintf(stderr, "Attempt to unalloc to many strings\n");
    return;
  }
  blks[a].used--;
  /*
   * if (findit(data)!=a) fprintf(stderr,"search failed\n");
   */
}

/* routines to deal with big chunks of memory */
char *bigalloc(size)
    int size;
{
  int a, b;
  char *ptr;
#ifdef DEBUG
  fprintf(stderr, "bigalloc=%d\n", size);
#endif
  /* round size up to nearest block */
  size = ((size - 1) / SBSIZE) + 1;
  /* assign it block pointers */
  for (a = 0; (a < (MAXBLK - size)) && (blks[a].blk); a++) ;
  if (a == (MAXBLK - size))
    return (NULL);
  ptr = (char *) sbrk(SBSIZE * size);
  for (b = 0; b < size; b++) {
    blks[a + b].owner = (NALLOC *) ptr;
    blks[a + b].used = 1;
    blks[a + b].blk = ptr + SBSIZE * b;
  }
  return (ptr);
}

void bigfree(ptr)
    char *ptr;
{
  int a;
  for (a = 0; a < MAXBLK; a++)
    if (blks[a].owner == (NALLOC *) ptr) {
      blks[a].owner = NULL;
      blks[a].used = 0;
    }
}

#ifdef BRAIN_DAMAGE

char toupper(c)
    char c;
{
  return (((c >= 'a') && (c <= 'z')) ? c - 'a' + 'A' : c);
}

void memcpy(dest, source, amt)
    char *dest;
    char *source;
    int amt;
{
  while (amt--)
    *dest++ = *source++;
}
#endif