/* COM/EXE loader for DOSRUN
   (C)1999 LGB (Gabor Lenart), lgb@vlug.vein.hu
   this source file is heavily based on Arpi/ESP-Team's code from old dosrun
 */


#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "memory.h"
#include "dosrun.h"
#include "derrno.h"


extern int dta_seg,dta_ofs;
int prg_id=1;



static int load_exe ( int fd )
{
  word header[14];
  int exesize,headsize,addr,base,minmem;
  read(fd,&header,sizeof(header));
  if (header[1]) exesize=((header[2]-1)<<9)+header[1]; else
    exesize=header[2]<<9;
  headsize=header[4]<<4;
  minmem=header[5]<<4;
  addr=dosmem_alloc((exesize-headsize+0x100+16)>>4,8);
  if (!addr) return -DNOMEM;
  printf("Loading EXE file to %04Xh.\n",addr);
  lseek(fd,headsize,SEEK_SET);
  base=((addr+0x100)>>4);
  if (read(fd,(void*)(addr+0x100),exesize-headsize)!=exesize-headsize) return -DFORMAT;
  if (header[3]) { /* some relocation code */
    word *reloc=(word*)malloc(header[3]<<2);
    word *r=reloc;
    int a;
    if (!reloc) return -DNOMEM;
    printf("Loading %d relocation points.\n",header[3]);
    read(fd,reloc,header[3]<<2);
    for (a=0;a<header[3];a++) {
      *(word*)(((base+r[1])<<4)+*r)+=base;
      r+=2;
    } /* for */
    free(reloc);
  } /* if */
  DS=ES=base-0x10; /* DS and ES points to PSP by default */
  EIP=header[10];
  CS=header[11]+base;
  ESP=header[8];
  SS=header[7]+base;
  return addr;
}


static int load_com ( int fd )
{
  int addr=dosmem_alloc(0x1000,8);
  if (!addr) return -DNOMEM;
  printf("Loading COM file to %04Xh.\n",addr);
  read(fd,(void*)(addr+0x100),0xff00);
  ES=DS=SS=CS=addr>>4;
  ESP=0xFFFE;
  EIP=0x100;
  *DOS_PW(SS,0xFFFE)=0; /* push 0 */
  return addr;
}



int load_prg ( char *name , char **arg , char **env )
{
  int fd=open(name,O_RDONLY),ret;
  word signature;
  if (fd==-1) {
    derrno=DNOENT;
    return 0;
  }
  read(fd,&signature,2);
  lseek(fd,0,SEEK_SET);
  if (signature==0x4D5A||signature==0x5A4D) ret=load_exe(fd); else ret=load_com(fd);
  close(fd);
  if (ret<=0) {
    derrno=-ret;
    return 0;
  }
// prg_id=addr>>4;  /* DOS use PSP address as PID, AFAIK */
//  dosmem_setowner(addr,prg_id);
  /* setup DTA */
  dta_seg=ret>>4;
  dta_ofs=0x80;
  fprintf(stderr,"CS:IP=%04X:%04X SS:SP=%04X:%04X PSP=%04X\n",CS,IP,SS,SP,ret>>4);
  return ret;
}
