/* amiga.c: */

#include "mkisofs.h"
#undef malloc
#include <stdlib.h>
#include <stdio.h>
#include <exec/memory.h>

#ifdef AMIGA
#ifdef LATTICE
#include <proto/exec.h>
#else
#include <clib/exec_protos.h>
#endif
#endif

#ifdef LATTICE
void __regargs _CXBRK (void)
{
  fprintf (stderr, "\nuser interrupt\n");
  exit (1);
}
#endif

void* xmalloc (size_t p_size)
{
  void *result = malloc (p_size);
  if (!result) {
    fprintf (stderr, "\nmkisofs: out of memory, cannot allocate %d bytes!\n",
    	     (int) p_size);
    exit (10);
  }
  return result;
}

char* xstrdup (char* p_string)
{
  char *result = xmalloc (strlen (p_string) + 1);
  strcpy (result, p_string);
  return result;
}

/* -------------------- Memory Management -------------------- */

#define MALLOC_FOREVER_CHUNKSIZE 16384
#define MALLOC_MAX_CHUNKS 2048

typedef struct mem_node {
  struct mem_node  *next;
  char		   *chunk;
  unsigned int	   offset;
} t_mem_node;

static t_mem_node *g_mem_list = NULL;
static char **g_chunk_table = NULL;

static void malloc_forever_cleanup (void)
{
  int i;

  for (i=0; i<MALLOC_MAX_CHUNKS && g_chunk_table[i]; i++)
    FreeMem (g_chunk_table[i], MALLOC_FOREVER_CHUNKSIZE);
  
  FreeMem (g_chunk_table, sizeof (char*) * MALLOC_MAX_CHUNKS);
}

void* malloc_forever (size_t p_size)
{
  static int next_chunk_number = -1;
  t_mem_node *ptr = g_mem_list, *old;

  if (next_chunk_number == -1) {
    next_chunk_number++;
    g_chunk_table = (char**) AllocMem (sizeof (char*) * MALLOC_MAX_CHUNKS,
    				       MEMF_ANY | MEMF_CLEAR);
    if (!g_chunk_table) {
      fprintf (stderr, "\nout of memory!\n");
      exit (1);
    }
    atexit (malloc_forever_cleanup);
  }

  if (p_size > MALLOC_FOREVER_CHUNKSIZE)
    return xmalloc (p_size);

  /* even sizes only: */
  if (p_size & 1)
    p_size++;

  for (old = NULL; ptr; old = ptr, ptr = ptr->next) {
    if (p_size <= MALLOC_FOREVER_CHUNKSIZE - ptr->offset) {
      char *result = ptr->chunk + ptr->offset;
      ptr->offset += p_size;
      if (MALLOC_FOREVER_CHUNKSIZE - 8 < ptr->offset) {
        if (old)
	  old->next = ptr->next;
	else
	  g_mem_list = ptr->next;
        free (ptr);
      }
      return (void*) result;
    }
  }

  if (next_chunk_number == MALLOC_MAX_CHUNKS) {
    fprintf (stderr, "error: internal memory management table overflow\n");
    exit (0);
  }

  ptr = xmalloc (sizeof (*ptr));
  ptr->chunk = g_chunk_table[next_chunk_number++] =
    AllocMem (MALLOC_FOREVER_CHUNKSIZE, MEMF_ANY);
  if (!ptr->chunk) {
    fprintf (stderr, "out of memory!\n");
    exit (1);
  }
  ptr->offset = p_size;
  ptr->next = g_mem_list;
  g_mem_list = ptr;
  return (void*) ptr->chunk;
}

char* strdup_forever (char *p_str)
{
  char* result = malloc_forever (strlen (p_str) + 1);
  strcpy (result, p_str);
  return result;
}
