#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef USE_NLLIBC
#include <nllibc.h>
#endif

#include "nlllib.h"
#include "memory.h"

typedef struct memory {
  struct memory *next;
  struct memory *prev;
#define MEMORY_MAGIC 0xDEADBEEF
  int magic;
  int size;
} *memory_t;

static memory_t head = NULL;

int memory_check(void)
{
  if (head)
    return NLL_ERRCODE_MEMORY_NOT_EMPTY;

  return 0;
}

void *memory_alloc(int size)
{
#ifdef NLL_DIRECT_MALLOC
  return malloc(size);
#else
  memory_t memory;

  memory = malloc(sizeof(*memory) + size);
  if (!memory)
    return NULL;

  memset(memory, 0, sizeof(*memory));
  memory->magic = MEMORY_MAGIC;
  memory->size = size;

  if (head)
    head->prev = memory;
  memory->next = head;
  memory->prev = NULL;
  head = memory;

  return memory + 1;
#endif
}

int memory_free(void *p)
{
#ifdef NLL_DIRECT_MALLOC
  free(p);
  return 0;
#else
  memory_t memory;

  memory = (memory_t)p - 1;

  if (memory->magic != MEMORY_MAGIC)
    return NLL_ERRCODE_MEMORY_INVALID_TYPE;

  if (memory->prev)
    memory->prev->next = memory->next;
  if (memory->next)
    memory->next->prev = memory->prev;
  if (head == memory)
    head = memory->next;

  memset(memory, 0, sizeof(*memory));
  free(memory);

  return 0;
#endif
}

int memory_init(void)
{
  head = NULL;

  return 0;
}
