#ifndef _STATE_TOOLS_H
#define _STATE_TOOLS_H


/*

SAVE AND RELOAD PROGRAM STATE...

Author: Matthew W. Coan
Date: Sun Jul 30 21:55:09 EDT 2017

*/

#include <fstream> 
#include <iostream>
#include <cstdlib>
#include <unistd.h>

extern "C" {
extern char * stk_ptr;
extern size_t stk_size;
extern char * stk_alloc(size_t size);
extern void set_eax(size_t value);
extern size_t get_eax();
extern const char * program_name;
extern void * malloc(size_t size);
extern void free(void * ptr);
}

using namespace std;
char * ptr = 0;
char * end = 0;
int word = 0;

#define SIZE 16

class Node {
public:
   void * ptr;
   size_t size;
   Node * next;
   Node() {
      ptr = 0;
      size = 0U;
      next = 0;
   }
};

Node * p_head = 0;
Node * node = 0;
size_t the_temp = 0U;
char * buffer = 0;

inline
void * __malloc(size_t size) 
{
   Node * n = (Node*)malloc(sizeof(Node));
   n->ptr = malloc(size);
   n->size = size;
   n->next = p_head;
   p_head = n;
}

inline
void __free(void * ptr)
{
   for(Node * n = p_head; n; n = n->next) {
      if(n->ptr == ptr) {
         free(ptr);
         break;
      }
   }
}

inline 
void * operator new(const size_t size) throw(bad_alloc)
{
   return __malloc(size);
}

inline 
void * operator new[](const size_t size) throw(bad_alloc)
{
   return __malloc(size);
}

inline 
void operator delete(void * ptr) throw()
{
   __free(ptr);
}

inline 
void operator delete[](void * ptr) throw()
{
   __free(ptr);
}

inline
char * get_stack_pointer() 
{
   __asm("movl %esp,%eax");
   __asm("addl $8,%eax");
   __asm("leave");
   __asm("ret");
   return 0;
}

#define state_init()\
   stk_ptr = get_stack_pointer()

#define state_save()\
   ofstream stream("state.dat", ios::ate | ios::binary | ios::out | ios::trunc);\
   if(stream) {\
      stk_size = stk_ptr-get_stack_pointer();\
      set_eax(stk_size);\
      __asm("subl %eax,%esp");\
      stream.write(reinterpret_cast< char* >(&stk_size), sizeof(size_t));\
      stream.write(get_stack_pointer(), stk_size);\
cout << "WRITE: " << stk_size << endl;\
cout << "PTR: " << (size_t)get_stack_pointer() << endl;\
      stream.flush();\
      stream.close();\
   }\
   __asm("START_ADDRESS:")

#define state_load()\
   ifstream stream("state.dat", ios::in | ios::binary);\
   if(stream) {\
      stream.read(reinterpret_cast< char* >(&stk_size), sizeof(size_t));\
      set_eax(stk_size);\
      __asm("subl %eax,%esp");\
cout << "READ: " << stk_size << endl;\
cout << "PTR: " << (size_t)get_stack_pointer() << endl;\
      stream.read(get_stack_pointer(), stk_size);\
      stream.close();\
      __asm("jmp START_ADDRESS");\
   }

#endif
