#include "libc.c"

#define BUFFER_SIZE 100
#define CODE_SIZE 16000

#define NULL 0

typedef short (*pf_t)();

extern void readline();
extern void bzero();
extern void gets();
extern short getch();
extern void putc();
extern void load_program();
extern short strcmp();
extern void readfile();
extern short findsector2();
extern void tohex();
extern short get_fat();
extern char* link_program();
extern void exit();

short
get_fat(i)
short i;
{
   char buffer[300];

   strcpy(buffer, "{hello16-0,aout-1,prog-2,c-3,}");

   return buffer[i];
}

/**
typedef short * FILE;
FILE * fopen();
void fclose();
int feof();
int fgetc();
void
readfile(cmd,code)
char * cmd;
char * code;
{
   FILE * fin;
   char ch;
   short i;
   fin = fopen("hello16", "rb");
   i = 0;
   if(fin != NULL) {
      ch = fgetc(fin);
      while(!feof(fin)) {
         code[i] = ch;
         i++;
      }
      fclose(fin);
   }
}
**/

void
gets(ptr)
char * ptr;
{
   short ch;
   short i;

   i = 0;
   ch = getch();
   while (ch != '\r' && ch != '\n') {
      if (ch == '\b' && i > 0) {
         putc(ch);
         ch = getch(); 
         i--;
         ptr[i] = '\0';
         continue;
      }
      else if(ch == '\b') {
         ch = getch(); 
         continue;
      }
      putc(ch);
      ptr[i] = ch;
      i++;
      ch = getch();
   }
   ptr[i] = '\0';
printf("\r\n");
printf("ptr -> ");
printf(ptr);
printf("\r\n");
}

void
bzero(ptr,size)
char * ptr;
short size;
{
   short i;
   for(i = 0; i < size; i++) {
      ptr[i] = '\0';
   }
}

short
findsector2(cmd)
char * cmd;
{
   short i,j,ch;
   char buffer[1024];
   char name[1024];
   char sector[1024];

printf("find sector: cmd == \"%s\"\r\n", cmd);

   bzero(buffer, 1024);
   bzero(name, 1024);
   bzero(sector, 1024);

   for(i = 0; get_fat(i) != '}'; i++) {
      ch = get_fat(i);
      buffer[i] = ch;
   }

   buffer[i] = '}';

printf("fat=(%s)\r\n", buffer);

   j = 0;
   for(i = 1; buffer[i] != '}'; i++) {
      if(buffer[i] == '-') {
printf("name=(%s)\r\n", name);
         if(strcmp(name, cmd) == 0) {
            bzero(sector, 1024);
            i++;
            j = 0;
            while(buffer[i] != ',') {
               sector[j] = buffer[i];
               i++;
               j++;
            }
            break;
         }
         else {
            j = 0;
            bzero(name, 1024);
            bzero(sector, 1024);
            i++;
            while(buffer[i] != ',') {
               ch = buffer[i];
               sector[j] = ch;
               i++;
               j++;
            }
            j = 0;
            bzero(sector, 1024);
            i++;
            continue;
         }
      }
      if(buffer[i] != ',') {
         name[j] = buffer[i];
         j++;
      }
      else {
         j = 0;
         bzero(name, 1024);
      }
   }


printf("FAT = (%s)\r\n", buffer);

printf("NAME = (%s)\r\n", name);

printf("SECTOR = (%s)\r\n", sector);
printf("SECTOR = (%d)\r\n", atoi(sector));

   return atoi(sector);
}


void
load_program(cmd,code)
char * cmd;
char * code;
{
   short sector,i;
   printf("LOAD: %s\r\n", cmd);
   printf("CODE ADDRESS = %d\r\n", code);
   sector = findsector2(cmd);
   printf("SECTOR: %d\r\n", sector);
   readfile(sector,code);
}

short
strcmp(arg1,arg2)
char * arg1;
char * arg2;
{
   short ret,i,ch1,ch2;
   ret = 0;
   for(i = 0; arg1[i] && arg2[i]; i++) {
      ch1 = arg1[i];
      ch2 = arg2[i];
      if(ch1 == ch2) {

      }
      else if(ch1 < ch2) {
         ret = -1;
         break;
      }
      else if(ch1 > ch2) {
         ret = 1;
         break;
      }
   }
   return ret;
}

struct reloc {
   short addr0;
   short addr1;
   short is_label;
};

char*
link_program(code)
char * code;
{
   struct reloc reloc_array[10];
   char * name;
   char * word_ptr;
   char * code_ptr;
   char * temp_ptr;
   short 
   reloc_count,
   name_size, 
   entry_point,
   addr, 
   size, 
   addr0,
   addr1,
   addr2, 
   i, 
   j,
   fun_size,
   addr_size,
   code_size,
   fun_addr,
   offset; 
 
   reloc_count = 0;

   word_ptr = code;

   fun_size = *((short*)word_ptr);

   printf("fun_size == %d\r\n", fun_size);

   word_ptr += 2;

   for(i = 0; i < fun_size; i++) {
      name_size = *((short*)word_ptr);

      printf("name_size == %d\r\n", name_size);

      word_ptr += 2;

      name = word_ptr;

      printf("name == %s\r\n", name);

      word_ptr += name_size;

      entry_point = *((short*)word_ptr);

      printf("entry_point == %d\r\n", entry_point);

      word_ptr += 2;

      addr = *((short*)word_ptr);

      printf("addr == %d\r\n", addr);

      word_ptr += 2;

      size = *((short*)word_ptr);

      printf("size == %d\r\n", size);

      word_ptr += 2;

      for(j = 0; j < size; j++) {
         addr0 = *((short*)word_ptr);

         word_ptr += 2;

         fun_addr = addr0;

         printf("FUN_ADDR = %d\r\n", fun_addr);

         reloc_array[reloc_count].addr0 = fun_addr;
         reloc_array[reloc_count].addr1 = 0;
         reloc_array[reloc_count].is_label = 0;
         reloc_count++;

      }

   }

   size = *((short*)word_ptr);

   word_ptr += 2;

   printf("size == %d\r\n", size);

   for(i = 0; i < size; i++) {
      addr0 = *((short*)word_ptr);
      word_ptr += 2;
      addr1 = *((short*)word_ptr);
      word_ptr += 2;

/*
      reloc_array[reloc_count].addr0 = addr0;
      reloc_array[reloc_count].addr1 = addr1;
      reloc_array[reloc_count].is_label = 1;
      reloc_count++;

      printf("---\r\n");
      printf("addr0 == %d\r\n", addr0);
      printf("addr1 == %d\r\n", addr1);
      printf("---\r\n");
*/
   }

   code_size = *((short*)word_ptr);

   printf("code_size == %d\r\n", code_size);

   word_ptr += 2;

   code_ptr = word_ptr;

   printf("code_ptr == %d\r\n", code_ptr);

   printf("fun_addr == %d\r\n", fun_addr);

   printf("reloc_count == %d\r\n", reloc_count);

/**
   for(i = 0; i < reloc_count; i++) {
      temp_ptr = code_ptr + reloc_array[i].addr0;
printf("fun_addr == %d\r\n", reloc_array[i].addr0);
      if(reloc_array[i].is_label) {
         (*((short**)temp_ptr)) = code_ptr + reloc_array[i].addr1;
      }
      else {
         (*((short**)temp_ptr)) = printf;
      }
   }
**/

   temp_ptr = code_ptr + fun_addr;

   (*((short**)temp_ptr)) = (short*)printf;

   temp_ptr = code_ptr + addr0;

   (*((short**)temp_ptr)) = (short*)(code_ptr + addr1);

   return code_ptr;
}

int
main()
{
   char code[CODE_SIZE];
   char cmd[BUFFER_SIZE];
   pf_t main_ptr;
   short i,rc;

   rc = 0;

   while(1) {
      printf("run> ");
      bzero(cmd,BUFFER_SIZE);
      gets(cmd); 
      printf("\r\n");
      printf("cmd == %s\r\n", cmd);
      if(strcmp(cmd,"exit") == 0) {
         break;
      }
      printf("cmd: %s\r\n", cmd);
      bzero(code,CODE_SIZE);
      load_program(cmd,code);
/*
      for(i = 0; i < 30; i++) 
         printf("code[%d] == %d\r\n", i, code[i]);
*/
      main_ptr = (pf_t)link_program(code);
      printf("MAIN[");
      printf("\r\n");

      rc = main_ptr();

      printf("\r\n");
      printf("]\r\n");
      printf("rc == %d\r\n", rc);
   }
   return 0;
}

