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

struct gcentry {
  void *varaddr;
  char varname[50];
  struct gcentry *next;
};

struct gcallocation {
  void *start;
  void *end;
  size_t size;
  struct gcallocation *prev, *next;
};

struct gcentry *root = NULL;
struct gcallocation *allocations = NULL;

void append_variable (void *varaddr, char *varname) {
  struct gcentry *e;
  
  e = malloc (sizeof (*e));
  if (NULL == e) {
    perror ("allocating gcentry in append_variable");
    exit (EXIT_FAILURE);
  }
  e->varaddr = varaddr;
  strcpy (e->varname, varname);
  e->next = root;
  root = e;
}

void release (struct gcentry *e) {
  struct gcallocation *a = allocations;
  struct gcentry *etmp;
  int found;
  
  while (a) {
    etmp = e;
    found = 0;
    while (etmp) {
      char *bptr = *(char **)etmp->varaddr;
      /* 
       * Check if the pointer still points to a valid range.
       */
      if (bptr >= (char *)a->start && bptr <= (char *)a->end) {
	found = 1;
	printf ("found a->start %p\n", a->start);
	break;
      }
      etmp = etmp->next;
    }
    if (!found) {
      /*
       * The memory is no longer used by any pointers.  We can safely free it.
       */
      printf ("!found a->start %p\n", a->start);
      
      if (a->prev)
	a->prev->next = a->next;
      else 
	allocations = a->next;

      if (a->next) 
	a->next->prev = a->prev;
      
      free (a);
    }
    a = a->next;
  }
}

void *alloc (size_t s) {
  struct gcallocation *a;
  release (root);
  
  a = malloc (sizeof (*a) + s);
  
  if (NULL == a) {
    perror ("unable to alloc");
    exit (EXIT_FAILURE);
  }
  
  a->start = a + 1;
  a->end = ((char *)a->start) + s;
  a->size = s;
  a->prev = NULL;
  
  if (allocations)
    allocations->prev = a;
  
  a->next = allocations;
  allocations = a;
  
  return a->start;
}

#define variable(type,var) type var = NULL; append_variable(&var, #var)

/* Test code */

int main (int argc, char *argv[]) {
  variable (char *, p);
  variable (char *, p2);
  
  while (1) {
    p = alloc (5);
    strcpy (p, "abcd");
    printf ("p %s\n", p); 
    p2 = p;
  }
  
  return EXIT_SUCCESS;
}
