1
0
Fork 0

First CVS upload.

Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@80
This commit is contained in:
Sjoerd van der Berg 2002-07-27 13:08:48 +00:00
parent 7d1ca9bdd4
commit 42e5d0b779
158 changed files with 42940 additions and 0 deletions

7
src/dos/Makefile.am Normal file
View file

@ -0,0 +1,7 @@
AM_CPPFLAGS = -I$(top_srcdir)/include
noinst_LIBRARIES = libdos.a
libdos_a_SOURCES = dos.cpp dos_devices.cpp dos_execute.cpp dos_files.cpp dos_ioctl.cpp dos_memory.cpp \
dos_misc.cpp dos_classes.cpp dos_programs.cpp dos_tables.cpp \
drives.cpp drives.h drive_virtual.cpp drive_local.cpp \
dev_con.h

105
src/dos/dev_con.h Normal file
View file

@ -0,0 +1,105 @@
/*
* Copyright (C) 2002 The DOSBox Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
class device_CON : public DOS_Device {
public:
device_CON();
bool Read(Bit8u * data,Bit16u * size);
bool Write(Bit8u * data,Bit16u * size);
bool Seek(Bit32u * pos,Bit32u type);
bool Close();
Bit16u GetInformation(void);
private:
Bit8u cache;
};
bool device_CON::Read(Bit8u * data,Bit16u * size) {
Bit16u oldax=reg_ax;
Bit16u count=0;
if ((cache) && (*size)) {
data[count++]=cache;
cache=0;
}
while (*size>count) {
reg_ah=0;
CALLBACK_RunRealInt(0x16);
switch(reg_al) {
case 13:
data[count++]=0x0D;
// if (*size>count) data[count++]=0x0A;
// else cache=0x0A;
*size=count;
reg_ax=oldax;
return true;
default:
data[count++]=reg_al;
break;
case 0:
data[count++]=reg_al;
if (*size>count) data[count++]=reg_ah;
else cache=reg_ah;
break;
}
}
*size=count;
reg_ax=oldax;
return true;
}
extern void INT10_TeletypeOutput(Bit8u chr,Bit8u attr,bool showattr, Bit8u page);
bool device_CON::Write(Bit8u * data,Bit16u * size) {
//TODO Hack a way to call int 0x10
Bit16u oldax=reg_ax;Bit16u oldbx=reg_bx;
Bit16u count=0;
while (*size>count) {
/*
reg_al=data[count];
reg_ah=0x0e;
reg_bx=0x0007;
CALLBACK_RunRealInt(0x10);
*/
INT10_TeletypeOutput(data[count],7,false,0);
count++;
}
*size=count;
// reg_ax=oldax;reg_bx=oldbx;
return true;
}
bool device_CON::Seek(Bit32u * pos,Bit32u type) {
return false;
}
bool device_CON::Close() {
return false;
}
Bit16u device_CON::GetInformation(void) {
Bit16u head=mem_readw(BIOS_KEYBOARD_BUFFER_HEAD);
Bit16u tail=mem_readw(BIOS_KEYBOARD_BUFFER_TAIL);
if ((head==tail) && !cache) return 0x80D3; /* No Key Available */
return 0x8093; /* Key Available */
};
device_CON::device_CON() {
name="CON";
cache=0;
}

790
src/dos/dos.cpp Normal file
View file

@ -0,0 +1,790 @@
/*
* Copyright (C) 2002 The DOSBox Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include "dosbox.h"
#include "bios.h"
#include "mem.h"
#include "callback.h"
#include "regs.h"
#include "dos_inc.h"
DOS_Block dos;
static Bit8u dos_copybuf[0x10000];
static Bitu call_20,call_21,call_theend;
void DOS_SetError(Bit16u code) {
dos.errorcode=code;
};
#define DOSNAMEBUF 256
static Bitu DOS_21Handler(void) {
//TODO KEYBOARD Check for break
char name1[DOSNAMEBUF+1];
char name2[DOSNAMEBUF+1];
switch (reg_ah) {
case 0x00: /* Terminate Program */
E_Exit("DOS:Unhandled call %02X",reg_ah);
break;
case 0x01: /* Read character from STDIN, with echo */
{
Bit8u c;Bit16u n=1;
DOS_ReadFile(STDIN,&c,&n);
reg_al=c;
DOS_WriteFile(STDOUT,&c,&n);
}
break;
case 0x02: /* Write character to STDOUT */
{
Bit8u c=reg_dl;Bit16u n=1;
DOS_WriteFile(STDOUT,&c,&n);
}
break;
case 0x03: /* Read character from STDAUX */
case 0x04: /* Write Character to STDAUX */
case 0x05: /* Write Character to PRINTER */
E_Exit("DOS:Unhandled call %02X",reg_ah);
break;
case 0x06: /* Direct Console Output / Input */
switch (reg_dl) {
case 0xFF: /* Input */
{
//TODO Make this better according to standards
if (!DOS_GetSTDINStatus()) {
CALLBACK_SZF(true);
break;
}
Bit8u c;Bit16u n=1;
DOS_ReadFile(STDIN,&c,&n);
reg_al=c;
CALLBACK_SZF(false);
break;
}
default:
{
Bit8u c=reg_dl;Bit16u n=1;
DOS_WriteFile(STDOUT,&c,&n);
}
break;
};
break;
case 0x07: /* Character Input, without echo */
{
Bit8u c;Bit16u n=1;
DOS_ReadFile (STDIN,&c,&n);
reg_al=c;
break;
};
case 0x08: /* Direct Character Input, without echo */
{
Bit8u c;Bit16u n=1;
DOS_ReadFile (STDIN,&c,&n);
reg_al=c;
break;
};
case 0x09: /* Write string to STDOUT */
{
Bit8u c;Bit16u n=1;
PhysPt buf=real_phys(Segs[ds].value,reg_dx);
while ((c=mem_readb(buf++))!='$') {
DOS_WriteFile(STDOUT,&c,&n);
}
}
break;
case 0x0a: /* Buffered Input */
{
//TODO ADD Break checkin in STDIN but can't care that much for it
PhysPt data=real_phys(Segs[ds].value,reg_dx);
Bit8u free=mem_readb(data);
Bit8u read=0;Bit8u c;Bit16u n=1;
if (!free) break;
while (read<free) {
DOS_ReadFile(STDIN,&c,&n);
DOS_WriteFile(STDOUT,&c,&n);
if (c==13) {
DOS_ReadFile(STDIN,&c,&n);
break;
}
mem_writeb(data+read+2,c);
read++;
};
mem_writeb(data+1,read);
break;
};
case 0x0b: /* Get STDIN Status */
if (DOS_GetSTDINStatus()) reg_al=0xff;
else reg_al=0;
break;
case 0x0c: /* Flush Buffer and read STDIN call */
{
switch (reg_al) {
case 0x1:
case 0x6:
case 0x7:
case 0x8:
case 0xa:
{
Bit8u oldah=reg_ah;
reg_ah=reg_al;
DOS_21Handler();
reg_ah=oldah;
}
break;
default:
LOG_ERROR("DOS:0C:Illegal Flush STDIN Buffer call %d",reg_al);
break;
}
}
break;
//TODO Find out the values for when reg_al!=0
//TODO Hope this doesn't do anything special
case 0x0d: /* Disk Reset */
//Sure let's reset a virtual disk
break;
case 0x0e: /* Select Default Drive */
DOS_SetDefaultDrive(reg_dl);
reg_al=26;
break;
case 0x0f: /* Open File using FCB */
case 0x10: /* Close File using FCB */
case 0x11: /* Find First Matching File using FCB */
case 0x12: /* Find Next Matching File using FCB */
case 0x13: /* Delete File using FCB */
case 0x14: /* Sequential read from FCB */
case 0x15: /* Sequential write to FCB */
case 0x16: /* Create or truncate file using FCB */
case 0x17: /* Rename file using FCB */
case 0x21: /* Read random record from FCB */
case 0x22: /* Write random record to FCB */
case 0x23: /* Get file size for FCB */
case 0x24: /* Set Random Record number for FCB */
case 0x27: /* Random block read from FCB */
case 0x28: /* Random Block read to FCB */
LOG_ERROR("DOS:Unhandled call %02X, FCB Stuff",reg_ah);
reg_al=0xff; /* FCB Calls FAIL */
CALLBACK_SCF(true);
break;
case 0x29: /* Parse filename into FCB */
//TODO Give errors for unsupported functions
{
MEM_StrCopy(real_phys(Segs[ds].value,reg_si),name1,DOSNAMEBUF);
/* only detect the call program use to detect the existence of a harddisk */
if ((strlen((char *)name1)==2) && (name1[1]==':')) {
Bit8u drive=toupper(name1[0])-'A';
if (Drives[drive]) reg_al=0;
else reg_al=0xff;
break;
}
LOG_DEBUG("DOS:29:FCB Parse Filename:%s",name1);
};
reg_al=0xff; /* FCB Calls FAIL */
break;
case 0x18: /* NULL Function for CP/M compatibility or Extended rename FCB */
case 0x1d: /* NULL Function for CP/M compatibility or Extended rename FCB */
case 0x1e: /* NULL Function for CP/M compatibility or Extended rename FCB */
case 0x20: /* NULL Function for CP/M compatibility or Extended rename FCB */
case 0x6b: /* NULL Function */
case 0x61: /* UNUSED */
reg_al=0;
break;
case 0x19: /* Get current default drive */
reg_al=DOS_GetDefaultDrive();
break;
case 0x1a: /* Set Disk Transfer Area Address */
//TODO find out what a DTA does
dos.dta=RealMake(Segs[ds].value,reg_dx);
break;
case 0x1c: /* Get allocation info for specific drive */
LOG_DEBUG("DOS: Allocation Info call not supported correctly");
SetSegment_16(ds,0xf000);
reg_bx=0;
real_writeb(0xf000,0,0);
reg_al=0x7f;
reg_cx=0x200;
reg_dx=0x1000;
break; /* TODO maybe but hardly think a game needs this */
case 0x1b: /* Get allocation info for default drive */
LOG_DEBUG("DOS: Allocation Info call not supported correctly");
SetSegment_16(ds,0xf000);
reg_bx=0;
real_writeb(0xf000,0,0);
reg_al=0x7f;
reg_cx=0x200;
reg_dx=0x1000;
break;
case 0x1f: /* Get drive parameter block for default drive */
case 0x32: /* Get drive parameter block for specific drive */
E_Exit("DOS:Unhandled call %02X",reg_ah);
break; /* TODO maybe but hardly think a game needs this */
case 0x25: /* Set Interrupt Vector */
RealSetVec(reg_al,RealMake(Segs[ds].value,reg_dx));
break;
case 0x26: /* Create new PSP */
DOS_NewPSP(reg_dx);
break;
case 0x2a: /* Get System Date */
reg_al=0; /* It's always sunday TODO find that correct formula */
reg_cx=dos.date.year;
reg_dh=dos.date.month;
reg_dl=dos.date.day;
break;
case 0x2b: /* Set System Date */
//TODO Check for months with less then 31 days
if (reg_cx<1980) { reg_al=0xff;break;}
if ((reg_dh>12) || (reg_dh==0)) { reg_al=0xff;break;}
if ((reg_dl>31) || (reg_dl==0)) { reg_al=0xff;break;}
dos.date.year=reg_cx;
dos.date.month=reg_dh;
dos.date.day=reg_dl;
reg_al=0;
break;
case 0x2c: /* Get System Time */
//TODO Get time through bios calls date is fixed
{
Bit32u ticks=mem_readd(BIOS_TIMER);
Bit32u seconds=(ticks*10)/182;
reg_ch=(Bit8u)(seconds/3600);
reg_cl=(Bit8u)(seconds % 3600)/60;
reg_dh=(Bit8u)(seconds % 60);
reg_dl=(Bit8u)(ticks % 19)*5;
}
break;
case 0x2d: /* Set System Time */
LOG_DEBUG("DOS:Set System Time not supported");
reg_al=0; /* Noone is changing system time */
break;
case 0x2e: /* Set Verify flag */
dos.verify=(reg_al==1);
break;
case 0x2f: /* Get Disk Transfer Area */
SetSegment_16(es,RealSeg(dos.dta));
reg_bx=RealOff(dos.dta);
break;
case 0x30: /* Get DOS Version */
if (reg_al==0) reg_bh=0xFF; /* Fake Microsoft DOS */
if (reg_al==1) reg_bh=0x10; /* DOS is in HMA */
reg_al=dos.version.major;
reg_ah=dos.version.minor;
break;
case 0x31: /* Terminate and stay resident */
//TODO First get normal files executing
DOS_ResizeMemory(dos.psp,&reg_dx);
if (DOS_Terminate(true)) {
dos.return_code=reg_al;
dos.return_mode=RETURN_TSR;
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
case 0x33: /* Extended Break Checking */
switch (reg_al) {
case 0:reg_dl=dos.breakcheck;break; /* Get the breakcheck flag */
case 1:dos.breakcheck=(reg_dl>0);break; /* Set the breakcheck flag */
case 2:{bool old=dos.breakcheck;dos.breakcheck=(reg_dl>0);reg_dl=old;}break;
case 5:reg_dl=3;break; /* Always boot from c: :) */
case 6: /* Get true version number */
reg_bl=dos.version.major;
reg_bh=dos.version.minor;
reg_dl=dos.version.revision;
reg_dh=0x10; /* Dos in HMA */
break;
default:
E_Exit("DOS:Illegal 0x33 Call %2X",reg_al);
}
break;
case 0x34: /* Get INDos Flag */
SetSegment_16(es,RealSeg(dos.tables.indosflag));
reg_bx=RealOff(dos.tables.indosflag);
break;
case 0x35: /* Get interrupt vector */
reg_bx=real_readw(0,((Bit16u)reg_al)*4);
SetSegment_16(es,real_readw(0,((Bit16u)reg_al)*4+2));
break;
case 0x36: /* Get Free Disk Space */
{
Bit16u bytes,sectors,clusters,free;
if (DOS_GetFreeDiskSpace(reg_dl,&bytes,&sectors,&clusters,&free)) {
reg_ax=sectors;
reg_bx=free;
reg_cx=bytes;
reg_dx=clusters;
} else {
reg_ax=0xffff;
}
}
break;
case 0x37: /* Get/Set Switch char Get/Set Availdev thing */
//TODO Give errors for these functions to see if anyone actually uses this shit-
switch (reg_al) {
case 0:
reg_al=0;reg_dl=0x2f;break; /* always return '/' like dos 5.0+ */
case 1:
reg_al=0;break;
case 2:
reg_al=0;reg_dl=0x2f;break;
case 3:
reg_al=0;break;
};
LOG_DEBUG("DOS:0x37:Call for not supported switchchar");
break;
case 0x38: /* Set Country Code */
LOG_DEBUG("DOS:Setting country code not supported");
CALLBACK_SCF(true);
break;
if (reg_al==0) { /* Get country specidic information */
} else { /* Set country code */
}
break;
case 0x39: /* MKDIR Create directory */
MEM_StrCopy(real_phys(Segs[ds].value,reg_dx),name1,DOSNAMEBUF);
if (DOS_MakeDir(name1)) {
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
case 0x3a: /* RMDIR Remove directory */
MEM_StrCopy(real_phys(Segs[ds].value,reg_dx),name1,DOSNAMEBUF);
if (DOS_RemoveDir(name1)) {
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
case 0x3b: /* CHDIR Set current directory */
MEM_StrCopy(real_phys(Segs[ds].value,reg_dx),name1,DOSNAMEBUF);
if (DOS_ChangeDir(name1)) {
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
case 0x3c: /* CREATE Create of truncate file */
MEM_StrCopy(real_phys(Segs[ds].value,reg_dx),name1,DOSNAMEBUF);
if (DOS_CreateFile(name1,reg_cx,&reg_ax)) {
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
case 0x3d: /* OPEN Open existing file */
MEM_StrCopy(real_phys(Segs[ds].value,reg_dx),name1,DOSNAMEBUF);
if (DOS_OpenFile(name1,reg_al,&reg_ax)) {
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
case 0x3e: /* CLOSE Close file */
if (DOS_CloseFile(reg_bx)) {
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
case 0x3f: /* READ Read from file or device */
{
Bit16u toread=reg_cx;
if (DOS_ReadFile(reg_bx,dos_copybuf,&toread)) {
MEM_BlockWrite(real_phys(Segs[ds].value,reg_dx),dos_copybuf,toread);
reg_ax=toread;
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
}
case 0x40: /* WRITE Write to file or device */
{
Bit16u towrite=reg_cx;
MEM_BlockRead(real_phys(Segs[ds].value,reg_dx),dos_copybuf,towrite);
if (DOS_WriteFile(reg_bx,dos_copybuf,&towrite)) {
reg_ax=towrite;
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
};
case 0x41: /* UNLINK Delete file */
MEM_StrCopy(real_phys(Segs[ds].value,reg_dx),name1,DOSNAMEBUF);
if (DOS_UnlinkFile(name1)) {
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
case 0x42: /* LSEEK Set current file position */
{
Bit32u pos=(reg_cx<<16) + reg_dx;
if (DOS_SeekFile(reg_bx,&pos,reg_al)) {
reg_dx=(Bit16u)(pos >> 16);
reg_ax=(Bit16u)(pos & 0xFFFF);
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
}
case 0x43: /* Get/Set file attributes */
//TODO FIX THIS HACK
MEM_StrCopy(real_phys(Segs[ds].value,reg_dx),name1,DOSNAMEBUF);
switch (reg_al)
case 0x00: /* Get */
{
if (DOS_GetFileAttr(name1,&reg_cx)) {
CALLBACK_SCF(false);
} else {
CALLBACK_SCF(true);
reg_ax=dos.errorcode;
}
break;
case 0x01: /* Set */
LOG_DEBUG("DOS:Set File Attributes for %s not supported",name1);
CALLBACK_SCF(false);
break;
default:
E_Exit("DOS:0x43:Illegal subfunction %2X",reg_al);
}
break;
case 0x44: /* IOCTL Functions */
if (DOS_IOCTL(reg_al,reg_bx)) {
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
case 0x45: /* DUP Duplicate file handle */
if (DOS_DuplicateEntry(reg_bx,&reg_ax)) {
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
case 0x46: /* DUP2,FORCEDUP Force duplicate file handle */
E_Exit("Unhandled Dos 21 call %02X",reg_ah);
break;
case 0x47: /* CWD Get current directory */
//TODO Memory
if (DOS_GetCurrentDir(reg_dl,real_off(Segs[ds].value,reg_si))) {
reg_ax=0x0100;
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
case 0x48: /* Allocate memory */
{
Bit16u size=reg_bx;Bit16u seg;
if (DOS_AllocateMemory(&seg,&size)) {
reg_ax=seg;
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
reg_bx=size;
CALLBACK_SCF(true);
}
break;
}
case 0x49: /* Free memory */
if (DOS_FreeMemory(Segs[es].value)) {
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
case 0x4a: /* Resize memory block */
{
Bit16u size=reg_bx;
if (DOS_ResizeMemory(Segs[es].value,&size)) {
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
reg_bx=size;
CALLBACK_SCF(true);
}
break;
}
case 0x4b: /* EXEC Load and/or execute program */
{
MEM_StrCopy(real_phys(Segs[ds].value,reg_dx),name1,DOSNAMEBUF);
if (DOS_Execute(name1,(ParamBlock *)real_off(Segs[es].value,reg_bx),reg_al)) {
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
}
break;
//TODO Check for use of execution state AL=5
case 0x4c: /* EXIT Terminate with return code */
{
if (DOS_Terminate(false)) {
dos.return_code=reg_al;
dos.return_mode=RETURN_EXIT;
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
}
case 0x4d: /* Get Return code */
reg_al=dos.return_code;
reg_ah=dos.return_mode;
break;
case 0x4e: /* FINDFIRST Find first matching file */
MEM_StrCopy(real_phys(Segs[ds].value,reg_dx),name1,DOSNAMEBUF);
if (DOS_FindFirst(name1,reg_cx)) {
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
};
break;
case 0x4f: /* FINDNEXT Find next matching file */
if (DOS_FindNext()) {
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
};
break;
case 0x50: /* Set current PSP */
dos.psp=reg_bx;
break;
case 0x51: /* Get current PSP */
reg_bx=dos.psp;
break;
case 0x52: /* Get list of lists */
SetSegment_16(es,0);
reg_bx=0;
LOG_ERROR("Call is made for list of lists not supported let's hope for the best");
break;
//TODO Think hard how shit this is gonna be
//And will any game ever use this :)
case 0x53: /* Translate BIOS parameter block to drive parameter block */
//YEAH RIGHT
case 0x54: /* Get verify flag */
case 0x55: /* Create Child PSP*/
E_Exit("Unhandled Dos 21 call %02X",reg_ah);
break;
case 0x56: /* RENAME Rename file */
MEM_StrCopy(real_phys(Segs[ds].value,reg_dx),name1,DOSNAMEBUF);
MEM_StrCopy(real_phys(Segs[es].value,reg_di),name2,DOSNAMEBUF);
if (DOS_Rename(name1,name2)) {
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
case 0x57: /* Get/Set File's Date and Time */
reg_cx=0;
reg_dx=0;
LOG_DEBUG("DOS:57:Getting/Setting File Date is faked",reg_ah);
break;
case 0x58: /* Get/Set Memory allocation strategy */
LOG_DEBUG("DOS:58:Not Supported Set//Get memory allocation");
break;
case 0x59: /* Get Extended error information */
E_Exit("Unhandled Dos 21 call %02X",reg_ah);
break;
case 0x5a: /* Create temporary file */
{
Bit16u handle;
MEM_StrCopy(real_phys(Segs[ds].value,reg_dx),name1,DOSNAMEBUF);
if (DOS_CreateTempFile(name1,&handle)) {
reg_ax=handle;
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
}
break;
case 0x5b: /* Create new file */
{
MEM_StrCopy(real_phys(Segs[ds].value,reg_dx),name1,DOSNAMEBUF);
Bit16u handle;
if (DOS_OpenFile(name1,0,&handle)) {
DOS_CloseFile(handle);
DOS_SetError(DOSERR_ACCESS_DENIED);
reg_ax=dos.errorcode;
CALLBACK_SCF(false);
break;
}
if (DOS_CreateFile(name1,reg_cx,&handle)) {
reg_ax=handle;
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
}
case 0x5c: /* FLOCK File region locking */
case 0x5d: /* Network Functions */
case 0x5e: /* More Network Functions */
case 0x5f: /* And Even More Network Functions */
E_Exit("DOS:Unhandled call %02X",reg_ah);
break;
case 0x60: /* Canonicalize filename or path */
MEM_StrCopy(real_phys(Segs[ds].value,reg_dx),name1,DOSNAMEBUF);
if (DOS_Canonicalize(name1,real_off(Segs[es].value,reg_di))) {
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
case 0x62: /* Get Current PSP Address */
reg_bx=dos.psp;
break;
case 0x63: /* Weirdo double byte stuff */
reg_al=0xff;
LOG_WARN("DOS:0x63:Doubly byte characters not supported");
break;
case 0x64: /* Set device driver lookahead flag */
E_Exit("Unhandled Dos 21 call %02X",reg_ah);
break;
case 0x65: /* Get extented country information and a lot of other useless shit*/
/* Todo maybe fully support this for now we set it standard for USA */
{
LOG_DEBUG("DOS:65:Extended country information call");
Bit8u * data=real_off(Segs[es].value,reg_di);
switch (reg_al) {
case 1:
real_writeb(Segs[es].value,reg_di,reg_al);
real_writew(Segs[es].value,reg_di+1,4);
real_writew(Segs[es].value,reg_di+3,1);
real_writew(Segs[es].value,reg_di+5,37);
reg_cx=4;
CALLBACK_SCF(false);
break;
default:
E_Exit("DOS:0x65:Unhandled country information call %2X",reg_al);
};
break;
}
case 0x66: /* Get/Set global code page table */
if (reg_al==1) {
LOG_DEBUG("Getting global code page table");
reg_bx=reg_dx=437;
CALLBACK_SCF(false);
break;
}
LOG_ERROR("DOS:Setting code page table is not supported");
break;
case 0x67: /* Set handle countr */
/* Weird call to increase amount of file handles needs to allocate memory if >20 */
LOG_DEBUG("DOS:67:Set Handle Count not working");
CALLBACK_SCF(false);
break;
case 0x68: /* FFLUSH Commit file */
E_Exit("Unhandled Dos 21 call %02X",reg_ah);
break;
case 0x69: /* Get/Set disk serial number */
{
Bit8u * temp=real_off(Segs[ds].value,reg_dx);
switch(reg_al) {
case 0x00: /* Get */
LOG_DEBUG("DOS:Get Disk serial number");
CALLBACK_SCF(true);
break;
case 0x01:
LOG_DEBUG("DOS:Set Disk serial number");
default:
E_Exit("DOS:Illegal Get Serial Number call %2X",reg_al);
}
break;
}
case 0x6c: /* Extended Open/Create */
E_Exit("Unhandled Dos 21 call %02X",reg_ah);
break;
case 0x71: /* Unknown probably 4dos detection */
reg_ax=0x7100;
CALLBACK_SCF(true);
LOG_WARN("DOS:Windows long file name support call %2X",reg_al);
break;
case 0xE0:
LOG_DEBUG("DOS:E0:Unhandled, what should this call do?");
break;
default:
E_Exit("DOS:Unhandled call %02X",reg_ah);
break;
};
return CBRET_NONE;
/* That's it now let's get it working */
};
static Bitu DOS_20Handler(void) {
reg_ax=0x4c00;
DOS_21Handler();
return CBRET_NONE;
}
void DOS_Init(void) {
call_20=CALLBACK_Allocate();
CALLBACK_Setup(call_20,DOS_20Handler,CB_IRET);
RealSetVec(0x20,CALLBACK_RealPointer(call_20));
call_21=CALLBACK_Allocate();
CALLBACK_Setup(call_21,DOS_21Handler,CB_IRET);
RealSetVec(0x21,CALLBACK_RealPointer(call_21));
DOS_SetupFiles(); /* Setup system File tables */
DOS_SetupDevices(); /* Setup dos devices */
DOS_SetupMemory(); /* Setup first MCB */
DOS_SetupTables();
DOS_SetupPrograms();
DOS_SetupMisc(); /* Some additional dos interrupts */
DOS_SetDefaultDrive(25);
/* Execute the file that should be */
dos.version.major=5;
dos.version.minor=0;
// DOS_RunProgram(startname);
};

181
src/dos/dos_classes.cpp Normal file
View file

@ -0,0 +1,181 @@
/*
* Copyright (C) 2002 The DOSBox Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <string.h>
#include <stdlib.h>
#include "dosbox.h"
#include "mem.h"
#include "dos_inc.h"
/*
Work in progress, making classes for handling certain internal memory structures in dos
This should make it somewhat easier for porting to other endian machines and make
dos work a bit easier.
*/
struct sPSP {
Bit8u exit[2]; /* CP/M-like exit poimt */
Bit16u next_seg; /* Segment of first byte beyond memory allocated or program */
Bit8u fill_1; /* single char fill */
/* CPM Stuff dunno what this is*/
//TODO Add some checks for people using this i think
Bit8u far_call; /* far call opcode */
RealPt cpm_entry; /* CPM Service Request address*/
RealPt int_22; /* Terminate Address */
RealPt int_23; /* Break Address */
RealPt int_24; /* Critical Error Address */
Bit16u psp_parent; /* Parent PSP Segment */
Bit8u files[20]; /* File Table - 0xff is unused */
Bit16u environment; /* Segment of evironment table */
RealPt stack; /* SS:SP Save point for int 0x21 calls */
Bit16u max_files; /* Maximum open files */
RealPt file_table; /* Pointer to File Table PSP:0x18 */
RealPt prev_psp; /* Pointer to previous PSP */
RealPt dta; /* Pointer to current Process DTA */
Bit8u fill_2[16]; /* Lot's of unused stuff i can't care aboue */
Bit8u service[3]; /* INT 0x21 Service call int 0x21;retf; */
Bit8u fill_3[45]; /* This has some blocks with FCB info */
CommandTail cmdtail;
};
class DOS_PSP {
public:
DOS_PSP(Bit16u segment);
void MakeNew(Bit16u env,Bit16u memsize);
Bit16u base_seg;
private:
PhysPt off;
};
DOS_PSP::DOS_PSP(Bit16u segment) {
base_seg=segment;
off=Real2Phys(RealMake(segment,0));
};
void DOS_PSP::MakeNew(Bit16u env,Bit16u next_para) {
Bitu i;
for (i=0;i<256;i++) mem_writeb(off+i,0);
/* Standard blocks */
mem_writeb(off+offsetof(sPSP,exit[0]),0xcd);
mem_writeb(off+offsetof(sPSP,exit[1]),0x20);
mem_writeb(off+offsetof(sPSP,service[0]),0xcd);
mem_writeb(off+offsetof(sPSP,service[1]),0x21);
mem_writeb(off+offsetof(sPSP,service[2]),0xcb);
mem_writew(off+offsetof(sPSP,next_seg),next_para);
// mem_writew(off+offsetof(sPSP,psp_parent),dos.psp->base_seg);
/* Setup initial file table */
mem_writed(off+offsetof(sPSP,int_22),RealGetVec(0x22));
mem_writed(off+offsetof(sPSP,int_23),RealGetVec(0x23));
mem_writed(off+offsetof(sPSP,int_24),RealGetVec(0x24));
#if 0
newpsp->mem_size=prevpsp->mem_size;
newpsp->environment=0;
newpsp->int_22.full=real_getvec(0x22);
newpsp->int_23.full=real_getvec(0x23);
newpsp->int_24.full=real_getvec(0x24);
newpsp->psp_parent=dos.psp;
newpsp->prev_psp.full=0xFFFFFFFF;
Bit32u i;
Bit8u * prevfile=real_off(prevpsp->file_table.seg,prevpsp->file_table.off);
for (i=0;i<20;i++) newpsp->files[i]=prevfile[i];
newpsp->max_files=20;
newpsp->file_table.seg=pspseg;
newpsp->file_table.off=offsetof(PSP,files);
/* Save the old DTA in this psp */
newpsp->dta.seg=dos.dta.seg;
newpsp->dta.off=dos.dta.off;
/* Setup the DTA */
dos.dta.seg=pspseg;
dos.dta.off=0x80;
return;
#endif
}
void DOS_FCB::Set_drive(Bit8u a){
mem_writeb(off+offsetof(FCB,drive),a);
}
void DOS_FCB::Set_filename(char * a){
MEM_BlockWrite(off+offsetof(FCB,filename),a,8);
}
void DOS_FCB::Set_ext(char * a) {
MEM_BlockWrite(off+offsetof(FCB,ext),a,3);
}
void DOS_FCB::Set_current_block(Bit16u a){
mem_writew(off+offsetof(FCB,current_block),a);
}
void DOS_FCB::Set_record_size(Bit16u a){
mem_writew(off+offsetof(FCB,record_size),a);
}
void DOS_FCB::Set_filesize(Bit32u a){
mem_writed(off+offsetof(FCB,filesize),a);
}
void DOS_FCB::Set_date(Bit16u a){
mem_writew(off+offsetof(FCB,date),a);
}
void DOS_FCB::Set_time(Bit16u a){
mem_writew(off+offsetof(FCB,time),a);
}
Bit8u DOS_FCB::Get_drive(void){
return mem_readb(off+offsetof(FCB,drive));
}
void DOS_FCB::Get_filename(char * a){
MEM_BlockRead(off+offsetof(FCB,filename),a,8);
}
void DOS_FCB::Get_ext(char * a){
MEM_BlockRead(off+offsetof(FCB,ext),a,3);
}
Bit16u DOS_FCB::Get_current_block(void){
return mem_readw(off+offsetof(FCB,current_block));
}
Bit16u DOS_FCB::Get_record_size(void){
return mem_readw(off+offsetof(FCB,record_size));
}
Bit32u DOS_FCB::Get_filesize(void){
return mem_readd(off+offsetof(FCB,filesize));
}
Bit16u DOS_FCB::Get_date(void){
return mem_readw(off+offsetof(FCB,date));
}
Bit16u DOS_FCB::Get_time(void){
return mem_readw(off+offsetof(FCB,time));
}

77
src/dos/dos_devices.cpp Normal file
View file

@ -0,0 +1,77 @@
/*
* Copyright (C) 2002 The DOSBox Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <string.h>
#include "dosbox.h"
#include "callback.h"
#include "cpu.h"
#include "mem.h"
#include "bios.h"
#include "dos_inc.h"
#include "support.h"
#define MAX_DEVICES 10
/* Include all the devices */
#include "dev_con.h"
static DOS_Device * devices[MAX_DEVICES];
static Bit32u device_count;
Bit8u DOS_FindDevice(char * name) {
/* loop through devices */
Bit8u index=0;
while (index<device_count) {
if (devices[index]) {
if (strcasecmp(name,devices[index]->name)==0) return index;
}
index++;
}
return 255;
}
void DOS_AddDevice(DOS_Device * adddev) {
//TODO Give the Device a real handler in low memory that responds to calls
if (device_count<MAX_DEVICES) {
devices[device_count]=adddev;
device_count++;
/* Add the device in the main file Table */
Bit8u handle=DOS_FILES;Bit8u i;
for (i=0;i<DOS_FILES;i++) {
if (!Files[i]) {
handle=i;
Files[i]=adddev;
break;
}
}
if (handle==DOS_FILES) E_Exit("DOS:Not enough file handles for device");
adddev->fhandle=handle;
} else {
E_Exit("DOS:Too many devices added");
}
}
void DOS_SetupDevices(void) {
device_count=0;
DOS_Device * newdev;
newdev=new device_CON();
DOS_AddDevice(newdev);
}

439
src/dos/dos_execute.cpp Normal file
View file

@ -0,0 +1,439 @@
/*
* Copyright (C) 2002 The DOSBox Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <string.h>
#include "dosbox.h"
#include "mem.h"
#include "dos_inc.h"
#include "cpu.h"
#pragma pack(1)
struct EXE_Header {
Bit16u signature; /* EXE Signature MZ or ZM */
Bit16u extrabytes; /* Bytes on the last page */
Bit16u pages; /* Pages in file */
Bit16u relocations; /* Relocations in file */
Bit16u headersize; /* Paragraphs in header */
Bit16u minmemory; /* Minimum amount of memory */
Bit16u maxmemory; /* Maximum amount of memory */
Bit16u initSS;
Bit16u initSP;
Bit16u checksum;
Bit16u initIP;
Bit16u initCS;
Bit16u reloctable;
Bit16u overlay;
};
#pragma pack()
#define MAGIC1 0x5a4d
#define MAGIC2 0x4d5a
#define MAXENV 32768u
#define ENV_KEEPFREE 83 /* keep unallocated by environment variables */
/* The '65' added to nEnvSize does not cover the additional stuff:
+ 2 bytes: number of strings
+ 80 bytes: maximum absolute filename
+ 1 byte: '\0'
-- 1999/04/21 ska */
#define LOADNGO 0
#define LOAD 1
#define OVERLAY 3
bool DOS_Terminate(bool tsr) {
PSP * psp=(PSP *)real_off(dos.psp,0);
if (!tsr) {
/* Free Files owned by process */
for (Bit16u i=0;i<psp->max_files;i++) {
DOS_CloseFile(i);
}
DOS_FreeProcessMemory(dos.psp);
};
dos.psp=psp->psp_parent;
PSP * oldpsp=(PSP *)real_off(dos.psp,0);
/* Restore the DTA */
dos.dta=psp->dta;
/* Restore the old CS:IP from int 22h */
RealPt old22;
old22=RealGetVec(0x22);
SetSegment_16(cs,RealSeg(old22));
reg_ip=RealOff(old22);
/* Restore the SS:SP to the previous one */
SetSegment_16(ss,RealSeg(oldpsp->stack));
reg_sp=RealOff(oldpsp->stack);
/* Restore interrupt 22,23,24 */
RealSetVec(0x22,psp->int_22);
RealSetVec(0x23,psp->int_23);
RealSetVec(0x24,psp->int_24);
return true;
}
static bool MakeEnv(char * name,Bit16u * segment) {
/* If segment to copy environment is 0 copy the caller's environment */
PSP * psp=(PSP *)real_off(dos.psp,0);
Bit8u * envread,*envwrite;
Bit16u envsize=1;
bool parentenv=true;
if (*segment==0) {
if (!psp->environment) parentenv=false; //environment seg=0
envread=real_off(psp->environment,0);
} else {
if (!*segment) parentenv=false; //environment seg=0
envread=real_off(*segment,0);
}
//TODO Make a good DOS first psp
if (parentenv) {
for (envsize=0; ;envsize++) {
if (envsize>=MAXENV - ENV_KEEPFREE) {
DOS_SetError(DOSERR_ENVIRONMENT_INVALID);
return false;
}
if (readw(envread+envsize)==0) break;
}
envsize += 2; /* account for trailing \0\0 */
}
Bit16u size=long2para(envsize+ENV_KEEPFREE);
if (!DOS_AllocateMemory(segment,&size)) return false;
envwrite=real_off(*segment,0);
if (parentenv) {
bmemcpy(envwrite,envread,envsize);
envwrite+=envsize;
} else {
*envwrite++=0;
}
*((Bit16u *) envwrite)=1;
envwrite+=2;
//TODO put the filename here
return DOS_Canonicalize(name,envwrite);
};
bool DOS_NewPSP(Bit16u pspseg) {
PSP * newpsp=(PSP *)real_off(pspseg,0);
PSP * prevpsp=(PSP *)real_off(dos.psp,0);
memset((void *)newpsp,0,sizeof(PSP));
newpsp->exit[0]=0xcd;newpsp->exit[1]=0x20;
newpsp->service[0]=0xcd;newpsp->service[0]=0x21;newpsp->service[0]=0xcb;
newpsp->mem_size=prevpsp->mem_size;
newpsp->environment=0;
newpsp->int_22=RealGetVec(0x22);
newpsp->int_23=RealGetVec(0x23);
newpsp->int_24=RealGetVec(0x24);
newpsp->psp_parent=dos.psp;
newpsp->prev_psp=0xFFFFFFFF;
Bit32u i;
Bit8u * prevfile=Real2Host(prevpsp->file_table);
for (i=0;i<20;i++) newpsp->files[i]=prevfile[i];
newpsp->max_files=20;
newpsp->file_table=RealMake(pspseg,offsetof(PSP,files));
/* Save the old DTA in this psp */
newpsp->dta=dos.dta;
/* Setup the DTA */
dos.dta=RealMake(pspseg,0x80);
return true;
};
static void SetupPSP(Bit16u pspseg,Bit16u memsize,Bit16u envseg) {
PSP * psp=(PSP *)real_off(pspseg,0);
/* Fix the PSP index of this MCB */
MCB * pspmcb=(MCB *)real_off(pspseg-1,0);
pspmcb->psp_segment=pspseg;
MCB * envmcb=(MCB *)real_off(envseg-1,0);
envmcb->psp_segment=pspseg;
memset((void *)psp,0,sizeof(PSP));
Bit32u i;
psp->exit[0]=0xcd;psp->exit[1]=0x20;
psp->mem_size=memsize+pspseg;
psp->environment=envseg;
psp->int_22=RealGetVec(0x22);
psp->int_23=RealGetVec(0x23);
psp->int_24=RealGetVec(0x24);
psp->service[0]=0xcd;psp->service[0]=0x21;psp->service[0]=0xcb;
psp->psp_parent=dos.psp;
psp->prev_psp=RealMake(dos.psp,0);
for (i=0;i<20;i++) psp->files[i]=0xff;
psp->files[STDIN]=DOS_FindDevice("CON");
psp->files[STDOUT]=DOS_FindDevice("CON");
psp->files[STDERR]=DOS_FindDevice("CON");
psp->files[STDAUX]=DOS_FindDevice("CON");
psp->files[STDNUL]=DOS_FindDevice("CON");
psp->files[STDPRN]=DOS_FindDevice("CON");
psp->max_files=20;
psp->file_table=RealMake(pspseg,offsetof(PSP,files));
/* Save old DTA in psp */
psp->dta=dos.dta;
/* Setup the DTA */
dos.dta=RealMake(pspseg,0x80);
}
static void SetupCMDLine(Bit16u pspseg,ParamBlock * block) {
PSP * psp=(PSP *)real_off(pspseg,0);
if (block->exec.cmdtail) {
memcpy((void *)&psp->cmdtail,(void *)Real2Host(block->exec.cmdtail),128);
} else {
char temp[]="";
psp->cmdtail.count=strlen(temp);
strcpy((char *)&psp->cmdtail.buffer,temp);
psp->cmdtail.buffer[0]=0x0d;
}
}
static bool COM_Load(char * name,ParamBlock * block,Bit8u flag) {
Bit16u fhandle;
Bit16u size;Bit16u readsize;
Bit16u envseg,comseg;
Bit32u pos;
PSP * callpsp=(PSP *)real_off(dos.psp,0);
if (!DOS_OpenFile(name,OPEN_READ,&fhandle)) return false;
if (flag!=OVERLAY) {
/* Allocate a new Environment */
envseg=block->exec.envseg;
if (!MakeEnv(name,&envseg)) return false;
/* Allocate max memory for COM file and PSP */
size=0xffff;
DOS_AllocateMemory(&comseg,&size);
//TODO Errors check for minimun of 64kb in pages
if (Bit32u(size <<4)<0x1000) {
DOS_SetError(DOSERR_INSUFFICIENT_MEMORY);
DOS_FreeMemory(envseg);
return false;
}
DOS_AllocateMemory(&comseg,&size);
} else {
comseg=block->overlay.loadseg;
}
/* Memory allocated now load the program */
/* Now copy the File into allocated memory */
pos=0;
DOS_SeekFile(fhandle,&pos,0);
readsize=0xffff-256;
if (flag==OVERLAY) {
DOS_ReadFile(fhandle,real_host(comseg,0),&readsize);
} else {
DOS_ReadFile(fhandle,real_host(comseg,256),&readsize);
}
DOS_CloseFile(fhandle);
if (flag==OVERLAY) /* Everything what should be done for Overlays */
return true;
SetupPSP(comseg,size,envseg);
SetupCMDLine(comseg,block);
/* Setup termination Address */
RealSetVec(0x22,RealMake(Segs[cs].value,reg_ip));
/* Everything setup somewhat setup CS:IP and SS:SP */
/* First save the SS:SP of program that called execute */
callpsp->stack=RealMake(Segs[ss].value,reg_sp);
/* Clear out first Stack entry to point to int 20h at psp:0 */
real_writew(comseg,0xfffe,0);
dos.psp=comseg;
switch (flag) {
case LOADNGO:
SetSegment_16(cs,comseg);
SetSegment_16(ss,comseg);
SetSegment_16(ds,comseg);
SetSegment_16(es,comseg);
flags.intf=true;
reg_ip=0x100;
reg_sp=0xFFFE;
reg_ax=0;
reg_bx=reg_cx=reg_dx=reg_si=reg_di=reg_bp=0;
return true;
case LOAD:
block->exec.initsssp=RealMake(comseg,0xfffe);
block->exec.initcsip=RealMake(comseg,0x100);
return true;
}
return false;
}
static bool EXE_Load(char * name,ParamBlock * block,Bit8u flag) {
EXE_Header header;
Bit16u fhandle;Bit32u i;
Bit16u size,minsize,maxsize,freesize;Bit16u readsize;
Bit16u envseg,pspseg,exeseg;
Bit32u imagesize,headersize;
PSP * callpsp=(PSP *)real_off(dos.psp,0);
if (!DOS_OpenFile(name,OPEN_READ,&fhandle)) return false;
if (flag!=OVERLAY) {
/* Allocate a new Environment */
envseg=block->exec.envseg;
if (!MakeEnv(name,&envseg)) return false;
};
/* First Read the EXE Header */
readsize=sizeof(EXE_Header);
DOS_ReadFile(fhandle,(Bit8u*)&header,&readsize);
/* Calculate the size of the image to load */
headersize=header.headersize*16;
imagesize=header.pages*512-headersize;
if (flag!=OVERLAY) {
minsize=long2para(imagesize+(header.minmemory<<4)+256);
if (header.maxmemory!=0) maxsize=long2para(imagesize+(header.maxmemory<<4)+256);
else maxsize=0xffff;
freesize=0xffff;
/* Check for enough free memory */
DOS_AllocateMemory(&exeseg,&freesize);
if (minsize>freesize) {
DOS_SetError(DOSERR_INSUFFICIENT_MEMORY);
DOS_FreeMemory(envseg);
return false;
}
if (maxsize>freesize) {
size=freesize;
} else size=maxsize;
if ((header.minmemory|header.maxmemory)==0) {
size=freesize;
E_Exit("Special case exe header max and min=0");
}
if (!DOS_AllocateMemory(&pspseg,&size)) {
DOS_SetError(DOSERR_INSUFFICIENT_MEMORY);
DOS_FreeMemory(envseg);
return false;
}
SetupPSP(pspseg,size,envseg);
SetupCMDLine(pspseg,block);
exeseg=pspseg+16;
} else {
/* For OVERLAY */
exeseg=block->overlay.loadseg;
}
/* Load the image in 32k blocks */
DOS_SeekFile(fhandle,&headersize,0);
Bit8u * imageoff=real_off(exeseg,0);
//TODO File size checking and remove size
// Remove psp size
// imagesize=256;
// Maybe remove final page and add last bytes on page
if (header.extrabytes) {
imagesize-=512;
imagesize+=header.extrabytes;
};
while (imagesize>0x7FFF) {
readsize=0x8000;
DOS_ReadFile(fhandle,imageoff,&readsize);
if (readsize!=0x8000) {
E_Exit("Illegal header");
}
imageoff+=0x8000;
imagesize-=0x8000;
}
if (imagesize>0) {
readsize=(Bit16u) imagesize;
DOS_ReadFile(fhandle,imageoff,&readsize);
}
headersize=header.reloctable;
DOS_SeekFile(fhandle,&headersize,0);
RealPt reloc;
for (i=0;i<header.relocations;i++) {
readsize=4;
DOS_ReadFile(fhandle,(Bit8u *)&reloc,&readsize);
PhysPt address=Real2Phys(RealMake(RealSeg(reloc)+exeseg,RealOff(reloc)));
Bit16u change=mem_readw(address);
if (flag==OVERLAY) {
change+=block->overlay.relocation;
} else {
change+=exeseg;
};
mem_writew(address,change);
};
DOS_CloseFile(fhandle);
if (flag==OVERLAY) return true;
/* Setup termination Address */
RealSetVec(0x22,RealMake(Segs[cs].value,reg_ip));
/* Start up the actual EXE if we need to */
//TODO check for load and return
callpsp->stack=RealMake(Segs[ss].value,reg_sp);
dos.psp=pspseg;
SetSegment_16(cs,exeseg+header.initCS);
SetSegment_16(ss,exeseg+header.initSS);
SetSegment_16(ds,pspseg);
SetSegment_16(es,pspseg);
reg_ip=header.initIP;
reg_sp=header.initSP;
reg_ax=0;
reg_bx=reg_cx=reg_dx=reg_si=reg_di=reg_bp=0;
flags.intf=true;
return true;
};
bool DOS_Execute(char * name,ParamBlock * block,Bit8u flags) {
EXE_Header head;
Bit16u fhandle;
Bit16u size;
bool iscom=false;
if (!DOS_OpenFile(name,OPEN_READ,&fhandle)) return false;
size=sizeof(EXE_Header);
if (!DOS_ReadFile(fhandle,(Bit8u *)&head,&size)) {
DOS_CloseFile(fhandle);
return false;
}
if (!DOS_CloseFile(fhandle)) return false;
if (size<sizeof(EXE_Header)) iscom=true;
if ((head.signature!=MAGIC1) && (head.signature!=MAGIC2)) iscom=true;
if (iscom) {
return COM_Load(name,block,flags);
} else {
return EXE_Load(name,block,flags);
}
}

614
src/dos/dos_files.cpp Normal file
View file

@ -0,0 +1,614 @@
/*
* Copyright (C) 2002 The DOSBox Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <string.h>
#include <stdlib.h>
#include "dosbox.h"
#include "mem.h"
#include "cpu.h"
#include "dos_inc.h"
#include "drives.h"
#define DOS_FILESTART 4
DOS_File * Files[DOS_FILES];
DOS_Drive * Drives[DOS_DRIVES];
static Bit8u CurrentDrive=2; //Init on C:
Bit8u DOS_GetDefaultDrive(void) {
return CurrentDrive;
}
void DOS_SetDefaultDrive(Bit8u drive) {
CurrentDrive=drive;
}
bool DOS_MakeName(char * name,char * fullname,Bit8u * drive) {
//TODO Hope this is ok :)
char upname[DOS_PATHLENGTH];
Bit32u r=0;Bit32u w=0;Bit32u namestart=0;
bool hasdrive=false;
*drive=CurrentDrive;
char tempdir[DOS_NAMELENGTH];
//TODO Maybe check for illegal characters
while (name[r]!=0 && (r<DOS_PATHLENGTH)) {
Bit8u c=name[r++];
if ((c>='a') && (c<='z')) {upname[w++]=c-32;continue;}
if ((c>='A') && (c<='Z')) {upname[w++]=c;continue;}
if ((c>='0') && (c<='9')) {upname[w++]=c;continue;}
switch (c) {
case ':':
if (hasdrive) { DOS_SetError(DOSERR_PATH_NOT_FOUND);return false; }
else hasdrive=true;
if ((upname[0]>='A') && (upname[0]<='Z')) {
*drive=upname[0]-'A';
w=0;
} else {
DOS_SetError(DOSERR_PATH_NOT_FOUND);return false;
}
break;
case '/':
upname[w++]='\\';
break;
case ' ':
break;
case '\\': case '$': case '#': case '@': case '(': case ')':
case '!': case '%': case '{': case '}': case '`': case '~':
case '_': case '-': case '.': case '*': case '?': case '&':
upname[w++]=c;
break;
default:
DOS_SetError(DOSERR_PATH_NOT_FOUND);return false;
break;
}
}
upname[w]=0;
/* This should get us an upcase filename and no incorrect chars */
/* Now parse the new file name to make the final filename */
if ((*drive>=26)) {
DOS_SetError(DOSERR_INVALID_DRIVE);return false;
};
if (!Drives[*drive]) {
DOS_SetError(DOSERR_INVALID_DRIVE);return false;
};
if (upname[0]!='\\') strcpy(fullname,Drives[*drive]->curdir);
else fullname[0]=0;
Bit32u lastdir=0;Bit32u t=0;
while (fullname[t]!=0) {
if ((fullname[t]=='\\') && (fullname[t+1]!=0))lastdir=t;
t++;
};
r=0;w=0;
tempdir[0]=0;
bool stop=false;
while (!stop) {
if (upname[r]==0) stop=true;
if ((upname[r]=='\\') || (upname[r]==0)){
tempdir[w]=0;
if (tempdir[0]==0) { w=0;r++;continue;}
if (strcmp(tempdir,".")==0) {
tempdir[0]=0;
w=0;r++;
continue;
}
if (strcmp(tempdir,"..")==0) {
fullname[lastdir]=0;
Bit32u t=0;lastdir=0;
while (fullname[t]!=0) {
if ((fullname[t]=='\\') && (fullname[t+1]!=0))lastdir=t;
t++;
}
tempdir[0]=0;
w=0;r++;
continue;
}
lastdir=strlen(fullname);
//TODO Maybe another check for correct type because of .... stuff
if (lastdir!=0) strcat(fullname,"\\");
strcat(fullname,tempdir);
tempdir[0]=0;
w=0;r++;
continue;
}
tempdir[w++]=upname[r++];
}
return true;
}
bool DOS_GetCurrentDir(Bit8u drive,Bit8u * buffer) {
if (drive==0) drive=DOS_GetDefaultDrive();
else drive--;
if ((drive>DOS_DRIVES) || (!Drives[drive])) {
DOS_SetError(DOSERR_INVALID_DRIVE);
return false;
}
strcpy((char *) buffer,Drives[drive]->curdir);
return true;
}
bool DOS_ChangeDir(char * dir) {
Bit8u drive;char fulldir[DOS_PATHLENGTH];
if (!DOS_MakeName(dir,fulldir,&drive)) return false;
if (Drives[drive]->TestDir(fulldir)) {
strcpy(Drives[drive]->curdir,fulldir);
return true;
} else {
DOS_SetError(DOSERR_PATH_NOT_FOUND);
}
return false;
}
bool DOS_MakeDir(char * dir) {
Bit8u drive;char fulldir[DOS_PATHLENGTH];
if (!DOS_MakeName(dir,fulldir,&drive)) return false;
return Drives[drive]->MakeDir(fulldir);
}
bool DOS_RemoveDir(char * dir) {
Bit8u drive;char fulldir[DOS_PATHLENGTH];
if (!DOS_MakeName(dir,fulldir,&drive)) return false;
return Drives[drive]->RemoveDir(fulldir);
}
bool DOS_Rename(char * oldname,char * newname) {
Bit8u driveold;char fullold[DOS_PATHLENGTH];
Bit8u drivenew;char fullnew[DOS_PATHLENGTH];
if (!DOS_MakeName(oldname,fullold,&driveold)) return false;
if (!DOS_MakeName(newname,fullnew,&drivenew)) return false;
//TODO Test for different drives maybe
if (Drives[drivenew]->Rename(fullold,fullnew)) return true;
DOS_SetError(DOSERR_FILE_NOT_FOUND);
return false;
};
bool DOS_FindFirst(char * search,Bit16u attr) {
Bit8u drive;char fullsearch[DOS_PATHLENGTH];
if (!DOS_MakeName(search,fullsearch,&drive)) return false;
DTA_FindBlock * dtablock=(DTA_FindBlock *)Real2Host(dos.dta);
dtablock->sattr=attr | DOS_ATTR_ARCHIVE;
dtablock->sdrive=drive;
return Drives[drive]->FindFirst(fullsearch,dtablock);
};
bool DOS_FindNext(void) {
DTA_FindBlock * dtablock=(DTA_FindBlock *)Real2Host(dos.dta);
return Drives[dtablock->sdrive]->FindNext(dtablock);
};
bool DOS_ReadFile(Bit16u entry,Bit8u * data,Bit16u * amount) {
Bit32u handle=RealHandle(entry);
if (handle>=DOS_FILES) {
DOS_SetError(DOSERR_INVALID_HANDLE);
return false;
};
if (!Files[handle]) {
DOS_SetError(DOSERR_INVALID_HANDLE);
return false;
};
//TODO maybe another code :)
/*
if (!(Files[handle]->flags & OPEN_READ)) {
DOS_SetError(DOSERR_INVALID_HANDLE);
return false;
}
*/
Bit16u toread=*amount;
bool ret=Files[handle]->Read(data,&toread);
*amount=toread;
return ret;
};
bool DOS_WriteFile(Bit16u entry,Bit8u * data,Bit16u * amount) {
Bit32u handle=RealHandle(entry);
if (handle>=DOS_FILES) {
DOS_SetError(DOSERR_INVALID_HANDLE);
return false;
};
if (!Files[handle]) {
DOS_SetError(DOSERR_INVALID_HANDLE);
return false;
};
//TODO maybe another code :)
/*
if (!(Files[handle]->flags & OPEN_WRITE)) {
DOS_SetError(DOSERR_INVALID_HANDLE);
return false;
}
*/
Bit16u towrite=*amount;
bool ret=Files[handle]->Write(data,&towrite);
*amount=towrite;
return ret;
};
bool DOS_SeekFile(Bit16u entry,Bit32u * pos,Bit32u type) {
Bit32u handle=RealHandle(entry);
if (handle>=DOS_FILES) {
DOS_SetError(DOSERR_INVALID_HANDLE);
return false;
};
if (!Files[handle]) {
DOS_SetError(DOSERR_INVALID_HANDLE);
return false;
};
return Files[handle]->Seek(pos,type);
};
bool DOS_CloseFile(Bit16u entry) {
Bit32u handle=RealHandle(entry);
if (handle>=DOS_FILES) {
DOS_SetError(DOSERR_INVALID_HANDLE);
return false;
};
if (!Files[handle]) {
DOS_SetError(DOSERR_INVALID_HANDLE);
return false;
};
//TODO Figure this out with devices :)
PSP * psp=(PSP *)real_off(dos.psp,0);
Bit8u * table=Real2Host(psp->file_table);
table[entry]=0xFF;
/* Devices won't allow themselves to be closed or killed */
if (Files[handle]->Close()) {
delete Files[handle];
Files[handle]=0;
}
return true;
}
bool DOS_CreateFile(char * name,Bit16u attributes,Bit16u * entry) {
char fullname[DOS_PATHLENGTH];Bit8u drive;
PSP * psp=(PSP *)real_off(dos.psp,0);
if (!DOS_MakeName(name,fullname,&drive)) return false;
/* Check for a free file handle */
Bit8u handle=DOS_FILES;Bit8u i;
for (i=0;i<DOS_FILES;i++) {
if (!Files[i]) {
handle=i;
break;
}
}
if (handle==DOS_FILES) {
DOS_SetError(DOSERR_TOO_MANY_OPEN_FILES);
return false;
}
/* We have a position in the main table now find one in the psp table */
Bit8u * table=Real2Host(psp->file_table);
*entry=0xff;
for (i=0;i<psp->max_files;i++) {
if (table[i]==0xFF) {
*entry=i;
break;
}
}
if (*entry==0xff) {
DOS_SetError(DOSERR_TOO_MANY_OPEN_FILES);
return false;
}
bool foundit=Drives[drive]->FileCreate(&Files[handle],fullname,attributes);
if (foundit) {
table[*entry]=handle;
return true;
} else {
return false;
}
}
bool DOS_OpenFile(char * name,Bit8u flags,Bit16u * entry) {
/* First check for devices */
PSP * psp=(PSP *)real_off(dos.psp,0);
Bit8u handle=DOS_FindDevice((char *)name);
bool device=false;char fullname[DOS_PATHLENGTH];Bit8u drive;Bit8u i;
if (handle!=255) {
device=true;
} else {
/* First check if the name is correct */
if (!DOS_MakeName(name,fullname,&drive)) return false;
/* Check for a free file handle */
for (i=0;i<DOS_FILES;i++) {
if (!Files[i]) {
handle=i;
break;
}
}
if (handle==255) {
DOS_SetError(DOSERR_TOO_MANY_OPEN_FILES);
return false;
}
}
/* We have a position in the main table now find one in the psp table */
Bit8u * table=Real2Host(psp->file_table);
*entry=0xff;
for (i=0;i<psp->max_files;i++) {
if (table[i]==0xFF) {
*entry=i;
break;
}
}
if (*entry==0xff) {
DOS_SetError(DOSERR_TOO_MANY_OPEN_FILES);
return false;
}
bool exists=false;
if (!device) exists=Drives[drive]->FileOpen(&Files[handle],fullname,flags);
if (exists || device ) {
table[*entry]=handle;
return true;
} else {
DOS_SetError(DOSERR_FILE_NOT_FOUND);
return false;
}
}
bool DOS_UnlinkFile(char * name) {
char fullname[DOS_PATHLENGTH];Bit8u drive;
if (!DOS_MakeName(name,fullname,&drive)) return false;
return Drives[drive]->FileUnlink(fullname);
}
bool DOS_GetFileAttr(char * name,Bit16u * attr) {
char fullname[DOS_PATHLENGTH];Bit8u drive;
if (!DOS_MakeName(name,fullname,&drive)) return false;
if (Drives[drive]->GetFileAttr(fullname,attr)) {
return true;
} else {
DOS_SetError(DOSERR_FILE_NOT_FOUND);
return false;
}
}
bool DOS_Canonicalize(char * name,Bit8u * big) {
//TODO Add Better support for devices and shit but will it be needed i doubt it :)
Bit8u drive;
char fullname[DOS_PATHLENGTH];
if (!DOS_MakeName(name,fullname,&drive)) return false;
big[0]=drive+'A';
big[1]=':';
big[2]='\\';
strcpy((char *)&big[3],fullname);
return true;
};
bool DOS_GetFreeDiskSpace(Bit8u drive,Bit16u * bytes,Bit16u * sectors,Bit16u * clusters,Bit16u * free) {
if (drive==0) drive=DOS_GetDefaultDrive();
else drive--;
if ((drive>DOS_DRIVES) || (!Drives[drive])) {
DOS_SetError(DOSERR_INVALID_DRIVE);
return false;
}
return Drives[drive]->FreeSpace(bytes,sectors,clusters,free);
}
bool DOS_DuplicateEntry(Bit16u entry,Bit16u * newentry) {
Bit8u handle=RealHandle(entry);
if (handle>=DOS_FILES) {
DOS_SetError(DOSERR_INVALID_HANDLE);
return false;
};
if (!Files[handle]) {
DOS_SetError(DOSERR_INVALID_HANDLE);
return false;
};
PSP * psp=(PSP *)real_off(dos.psp,0);
Bit8u * table=Real2Host(psp->file_table);
*newentry=0xff;
for (Bit16u i=0;i<psp->max_files;i++) {
if (table[i]==0xFF) {
*newentry=i;
break;
}
}
if (*newentry==0xff) {
DOS_SetError(DOSERR_TOO_MANY_OPEN_FILES);
return false;
}
table[*newentry]=handle;
return true;
};
bool DOS_CreateTempFile(char * name,Bit16u * entry) {
/* First add random crap to the end of the name and try to open */
/* Todo maybe check for euhm existence of the path name */
char * tempname;
tempname=name+strlen(name);
do {
Bit32u i;
for (i=0;i<8;i++) {
tempname[i]=(rand()%26)+'A';
}
tempname[8]='.';
for (i=9;i<12;i++) {
tempname[i]=(rand()%26)+'A';
}
tempname[13]=0;
} while (!DOS_CreateFile(name,0,entry));
return true;
}
#if 0
void FCB_MakeName (DOS_FCB* fcb, char* outname, Bit8u* outdrive){
char naam[15];
Bit8u drive=fcb->Get_drive();
if(drive!=0){
naam[0]=(drive-1)+'A';
naam[1]=':';
naam[2]='\0';}
else{
naam[0]='\0';
};
char temp[9];
fcb->Get_filename(temp);
temp[9]='.';
strncat(naam,temp,9);
char ext[3];
fcb->Get_ext(ext);
if(drive!=0) {
strncat(&naam[11],ext,3);
naam[14]='\0';
}else{
strncat(&naam[9],ext,3);
naam[12]='\0';
};
DOS_MakeName(naam,outname, outdrive);
return;
}
bool DOS_FCBOpen(Bit16u seg,Bit16u offset) {
DOS_FCB fcb(seg,offset);
Bit8u drive;
char fullname[DOS_PATHLENGTH];
FCB_MakeName (&fcb, fullname, &drive);
if(DOS_FileExists(fullname)==false) return false;
struct stat stat_block;
stat(fullname, &stat_block);
fcb.Set_filesize((Bit32u)stat_block.st_size);
Bit16u constant =0;
fcb.Set_current_block(constant);
constant=0x80;
fcb.Set_record_size(constant);
struct tm *time;
time=localtime(&stat_block.st_mtime);
constant=(time->tm_hour<<11)+(time->tm_min<<5)+(time->tm_sec/2); /* standard way. */
fcb->Set_time(constant);
constant=((time->tm_year-80)<<9)+((time->tm_mon+1)<<5)+(time->tm_mday);
fcb->Set_date(constant);
fcb->Set_drive(drive +1);
return true;
}
bool FCB_Close(void)
{ return true;}
bool FCB_FindFirst(Bit16u seg,Bit16u offset)
{FCB* fcb = new FCB(seg,offset);
Bit8u drive;
Bitu i;
char fullname[DOS_PATHLENGTH];
FCB_MakeName (fcb, fullname, &drive);
DTA_FindBlock * dtablock=(DTA_FindBlock *)Real2Host(dos.dta);
if(Drives[drive]->FindFirst(fullname,dtablock)==false) return false;
char naam[8];
char ext[3];
char * point=strrchr(dtablock->name,'.');
if(point==NULL|| *(point+1)=='\0') {
ext[0]=' ';
ext[1]=' ';
ext[2]=' ';
}else
{strcpy(ext,point+1);
Bitu i;
i=strlen(point+1);
while(i!=3) ext[i-1]=' ';
}
if(point!=NULL) *point='\0';
strcpy (naam,dtablock->name);
i=strlen(dtablock->name);
while(i!=8) naam[i-1]=' ';
FCB* fcbout= new FCB((PhysPt)Real2Host(dos.dta));
fcbout->Set_drive(drive +1);
fcbout->Set_filename(naam);
fcbout->Set_ext(ext);
return true;
}
bool FCB_FindNext(Bit16u seg,Bit16u offset)
{FCB* fcb = new FCB(seg,offset);
Bit8u drive;
Bitu i;
char fullname[DOS_PATHLENGTH];
FCB_MakeName (fcb, fullname, &drive);
DTA_FindBlock * dtablock=(DTA_FindBlock *)Real2Host(dos.dta);
if(Drives[dtablock->sdrive]->FindNext(dtablock)==false) return false;
char naam[8];
char ext[3];
char * point=strrchr(dtablock->name,'.');
if(point==NULL|| *(point+1)=='\0') {
ext[0]=' ';
ext[1]=' ';
ext[2]=' ';
}else
{strcpy(ext,point+1);
Bitu i;
i=strlen(point+1);
while(i!=3) ext[i-1]=' ';
}
if(point!=NULL) *point='\0';
strcpy (naam,dtablock->name);
i=strlen(dtablock->name);
while(i!=8) naam[i-1]=' ';
FCB* fcbout= new FCB((PhysPt)Real2Host(dos.dta));
fcbout->Set_drive(drive +1);
fcbout->Set_filename(naam);
fcbout->Set_ext(ext);
return true;
}
#endif
bool DOS_FileExists(char * name) {
Bit16u handle;
if (DOS_OpenFile(name,0,&handle)) {
DOS_CloseFile(handle);
return true;
}
return false;
}
bool DOS_SetDrive(Bit8u drive) {
if (Drives[drive]) {
DOS_SetDefaultDrive(drive);
return true;
} else {
return false;
}
};
void DOS_SetupFiles (void) {
/* Setup the File Handles */
Bit32u i;
for (i=0;i<DOS_FILES;i++) {
Files[i]=0;
}
/* Setup the Virtual Disk System */
for (i=0;i<DOS_DRIVES;i++) {
Drives[i]=0;
}
Drives[25]=new Virtual_Drive();
}

60
src/dos/dos_ioctl.cpp Normal file
View file

@ -0,0 +1,60 @@
/*
* Copyright (C) 2002 The DOSBox Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <string.h>
#include "dosbox.h"
#include "callback.h"
#include "mem.h"
#include "cpu.h"
#include "dos_inc.h"
#define MAX_DEVICE 20
static DOS_File * dos_devices[MAX_DEVICE];
bool DOS_IOCTL(Bit8u call,Bit16u entry) {
Bit32u handle=RealHandle(entry);
if (handle>=DOS_FILES) {
DOS_SetError(DOSERR_INVALID_HANDLE);
return false;
};
if (!Files[handle]) {
DOS_SetError(DOSERR_INVALID_HANDLE);
return false;
};
switch(reg_al) {
case 0x00: /* Get Device Information */
reg_dx=Files[handle]->GetInformation();
return true;
case 0x07: /* Get Output Status */
LOG_DEBUG("DOS:IOCTL:07:Fakes output status is ready for handle %d",handle);
reg_al=0xff;
return true;
default:
LOG_ERROR("DOS:IOCTL Call %2X Handle %2X unhandled",reg_al,handle);
return false;
};
return false;
};
bool DOS_GetSTDINStatus(void) {
Bit32u handle=RealHandle(STDIN);
if (Files[handle]->GetInformation() & 64) return false;
return true;
};

162
src/dos/dos_memory.cpp Normal file
View file

@ -0,0 +1,162 @@
/*
* Copyright (C) 2002 The DOSBox Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "dosbox.h"
#include "mem.h"
#include "dos_inc.h"
#define MEM_START 0x60 //First Segment that DOS can use
//#define MEM_START 4000 //First Segment that DOS can use
static void DOS_CompressMemory(void) {
MCB * pmcb;MCB * pmcbnext;
Bit16u mcb_segment;
mcb_segment=dos.firstMCB;
pmcb=(MCB *)real_off(mcb_segment,0);
while (pmcb->type!=0x5a) {
pmcbnext=pmcbnext=(MCB *)real_off(mcb_segment+pmcb->size+1,0);
if ((pmcb->psp_segment==0) && (pmcbnext->psp_segment==0)) {
pmcb->size+=pmcbnext->size+1;
pmcb->type=pmcbnext->type;
} else {
mcb_segment+=pmcb->size+1;
pmcb=(MCB *)real_off(mcb_segment,0);
}
}
}
void DOS_FreeProcessMemory(Bit16u pspseg) {
MCB * pmcb;
Bit16u mcb_segment=dos.firstMCB;
pmcb=(MCB *)real_off(mcb_segment,0);
while (true) {
if (pmcb->psp_segment==pspseg) {
pmcb->psp_segment=MCB_FREE;
}
mcb_segment+=pmcb->size+1;
if (pmcb->type==0x5a) break;
pmcb=(MCB *)real_off(mcb_segment,0);
}
DOS_CompressMemory();
};
bool DOS_AllocateMemory(Bit16u * segment,Bit16u * blocks) {
MCB * pmcb;MCB * pmcbnext;
Bit16u bigsize=0;Bit16u mcb_segment;
bool stop=false;mcb_segment=dos.firstMCB;
DOS_CompressMemory();
while(!stop) {
pmcb=(MCB *)real_off(mcb_segment,0);
if (pmcb->psp_segment==0) {
/* Check for enough free memory in current block */
if (pmcb->size<(*blocks)) {
if (bigsize<pmcb->size) {
bigsize=pmcb->size;
}
} else if (pmcb->size==*blocks) {
pmcb->psp_segment=dos.psp;
*segment=mcb_segment+1;
return true;
} else {
/* If so allocate it */
pmcbnext=(MCB *)real_off(mcb_segment+*blocks+1,0);
pmcbnext->psp_segment=MCB_FREE;
pmcbnext->type=pmcb->type;
pmcbnext->size=pmcb->size-*blocks-1;
pmcb->size=*blocks;
pmcb->type=0x4D;
pmcb->psp_segment=dos.psp;
//TODO Filename
*segment=mcb_segment+1;
return true;
}
}
/* Onward to the next MCB if there is one */
if (pmcb->type==0x5a) {
*blocks=bigsize;
DOS_SetError(DOSERR_INSUFFICIENT_MEMORY);
return false;
}
mcb_segment+=pmcb->size+1;
}
return false;
};
bool DOS_ResizeMemory(Bit16u segment,Bit16u * blocks) {
DOS_CompressMemory();
MCB * pmcb,* pmcbnext,* pmcbnew;
pmcb=(MCB *)real_off(segment-1,0);
pmcbnext=(MCB *)real_off(segment+pmcb->size,0);
Bit16u total=pmcb->size;
if (pmcb->type!=0x5a) {
if (pmcbnext->psp_segment==MCB_FREE) {
total+=pmcbnext->size+1;
}
};
if (*blocks<total) {
if (pmcb->type!=0x5a) {
pmcb->type=pmcbnext->type;
}
pmcb->size=*blocks;
pmcbnew=(MCB *)real_off(segment+*blocks,0);
pmcbnew->size=total-*blocks-1;
pmcbnew->type=pmcb->type;
pmcbnew->psp_segment=MCB_FREE;
pmcb->type=0x4D;
return true;
}
if (*blocks==total) {
if (pmcb->type!=0x5a) {
pmcb->type=pmcbnext->type;
}
pmcb->size=*blocks;
return true;
}
*blocks=total;
DOS_SetError(DOSERR_INSUFFICIENT_MEMORY);
return false;
};
bool DOS_FreeMemory(Bit16u segment) {
//TODO Check if allowed to free this segment
MCB * pmcb;
pmcb=(MCB *)real_off(segment-1,0);
pmcb->psp_segment=MCB_FREE;
DOS_CompressMemory();
return true;
}
void DOS_SetupMemory(void) {
//TODO Maybe allocate some memory for dos transfer buffers
//Although i could use bios regions for that for max free low memory
MCB * mcb=(MCB *) real_off(MEM_START,0);
mcb->psp_segment=MCB_FREE; //Free
mcb->size=0x9FFE - MEM_START;
mcb->type=0x5a; //Last Block
dos.firstMCB=MEM_START;
}

69
src/dos/dos_misc.cpp Normal file
View file

@ -0,0 +1,69 @@
/*
* Copyright (C) 2002 The DOSBox Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "dosbox.h"
#include "callback.h"
#include "mem.h"
#include "regs.h"
#include "dos_inc.h"
static Bitu call_int2f,call_int2a;
struct MultiplexBlock {
MultiplexHandler * handler;
MultiplexBlock * next;
};
static MultiplexBlock * first_multiplex;
void DOS_AddMultiplexHandler(MultiplexHandler * handler) {
MultiplexBlock * new_multiplex=new(MultiplexBlock);
new_multiplex->next=first_multiplex;
new_multiplex->handler=handler;
first_multiplex=new_multiplex;
}
static Bitu INT2F_Handler(void) {
MultiplexBlock * loop_multiplex=first_multiplex;
while (loop_multiplex) {
if ((*loop_multiplex->handler)()) return CBRET_NONE;
loop_multiplex=loop_multiplex->next;
}
LOG_WARN("DOS:Multiplex Unhandled call %4X",reg_ax);
return CBRET_NONE;
};
static Bitu INT2A_Handler(void) {
return CBRET_NONE;
};
void DOS_SetupMisc(void) {
/* Setup the dos multiplex interrupt */
first_multiplex=0;
call_int2f=CALLBACK_Allocate();
CALLBACK_Setup(call_int2f,&INT2F_Handler,CB_IRET);
RealSetVec(0x2f,CALLBACK_RealPointer(call_int2f));
/* Setup the dos network interrupt */
call_int2a=CALLBACK_Allocate();
CALLBACK_Setup(call_int2a,&INT2A_Handler,CB_IRET);
RealSetVec(0x2A<<2,CALLBACK_RealPointer(call_int2a));
};

210
src/dos/dos_programs.cpp Normal file
View file

@ -0,0 +1,210 @@
/*
* Copyright (C) 2002 The DOSBox Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "programs.h"
#include "support.h"
#include "drives.h"
#include "cross.h"
class MOUNT : public Program {
public:
MOUNT(PROGRAM_Info * program_info);
void Run(void);
};
MOUNT::MOUNT(PROGRAM_Info * info):Program(info) {
}
void MOUNT::Run(void) {
/* Parse the command line */
/* if the command line is empty show current mounts */
if (!*prog_info->cmd_line) {
WriteOut("Current mounted drives are\n");
for (int d=0;d<DOS_DRIVES;d++) {
if (Drives[d]) {
WriteOut("Drive %c is mounted as %s\n",d+'A',Drives[d]->GetInfo());
}
}
return;
}
char drive;
drive=toupper(*prog_info->cmd_line);
char * dir=strchr(prog_info->cmd_line,' ');
if (dir) {
if (!*dir) dir=0;
else dir=trim(dir);
};
if (!isalpha(drive) || !dir) {
WriteOut("Usage MOUNT Drive-Letter Local-Directory\nSo a MOUNT c c:\\windows mounts windows directory as the c: drive in DOSBox\n");
return;
};
struct stat test;
if (stat(dir,&test)) {
WriteOut("Directory %s Doesn't exist",dir);
return;
}
/* Not a switch so a normal directory/file */
if (!(test.st_mode & S_IFDIR)) {
WriteOut("%s isn't a directory",dir);
return;
}
if (Drives[drive-'A']) {
WriteOut("Drive %c already mounted with %s\n",drive,Drives[drive-'A']->GetInfo());
return;
}
char fulldir[DOS_PATHLENGTH];
strcpy(fulldir,dir);
static char theend[2]={CROSS_FILESPLIT,0};
char * last=strrchr(fulldir,CROSS_FILESPLIT);
if (!last || *(++last)) strcat(fulldir,theend);
Drives[drive-'A']=new localDrive(fulldir);
WriteOut("Mounting drive %c as %s\n",drive,fulldir);
}
static void MOUNT_ProgramStart(PROGRAM_Info * info) {
MOUNT * tempmount=new MOUNT(info);
tempmount->Run();
delete tempmount;
}
class MEM : public Program {
public:
MEM(PROGRAM_Info * program_info);
void Run(void);
};
MEM::MEM(PROGRAM_Info * info):Program(info) {
}
void MEM::Run(void) {
}
static void MEM_ProgramStart(PROGRAM_Info * info) {
MEM mem(info);
mem.Run();
}
#if !defined (WIN32) /* Unix */
class UPCASE : public Program {
public:
UPCASE(PROGRAM_Info * program_info);
void Run(void);
void upcasedir(char * directory);
};
UPCASE::UPCASE(PROGRAM_Info * info):Program(info) {
}
void UPCASE::upcasedir(char * directory) {
DIR * sdir;
char fullname[512];
char newname[512];
struct dirent *tempdata;
struct stat finfo;
if(!(sdir=opendir(directory))) {
WriteOut("Failed to open directory %s\n",directory);
return;
}
WriteOut("Scanning directory %s\n",fullname);
while (tempdata=readdir(sdir)) {
if (strcmp(tempdata->d_name,".")==0) continue;
if (strcmp(tempdata->d_name,"..")==0) continue;
strcpy(fullname,directory);
strcat(fullname,"/");
strcat(fullname,tempdata->d_name);
strcpy(newname,directory);
strcat(newname,"/");
upcase(tempdata->d_name);
strcat(newname,tempdata->d_name);
WriteOut("Renaming %s to %s\n",fullname,newname);
rename(fullname,newname);
stat(fullname,&finfo);
if(S_ISDIR(finfo.st_mode)) {
upcasedir(fullname);
}
}
closedir(sdir);
}
void UPCASE::Run(void) {
/* First check if the directory exists */
struct stat info;
WriteOut("UPCASE 0.1 Directory case convertor.\n");
if (!strlen(prog_info->cmd_line)) {
WriteOut("Usage UPCASE [local directory]\n");
WriteOut("This tool will convert all files and subdirectories in a directory.\n");
WriteOut("Be VERY sure this directory contains only dos related material.\n");
WriteOut("Otherwise you might horribly screw up your filesystem.\n");
return;
}
if (stat(prog_info->cmd_line,&info)) {
WriteOut("%s doesn't exist\n",prog_info->cmd_line);
return;
}
if(!S_ISDIR(info.st_mode)) {
WriteOut("%s isn't a directory\n",prog_info->cmd_line);
return;
}
WriteOut("Converting the wrong directories can be very harmfull, please be carefull.\n");
WriteOut("Are you really really sure you want to convert %s to upcase?Y/N\n",prog_info->cmd_line);
Bit8u key;Bit16u n=1;
DOS_ReadFile(STDIN,&key,&n);
if (toupper(key)=='Y') {
upcasedir(prog_info->cmd_line);
} else {
WriteOut("Okay better not do it.\n");
}
}
static void UPCASE_ProgramStart(PROGRAM_Info * info) {
UPCASE * tempUPCASE=new UPCASE(info);
tempUPCASE->Run();
delete tempUPCASE;
}
#endif
void DOS_SetupPrograms(void) {
PROGRAMS_MakeFile("MOUNT.COM",MOUNT_ProgramStart);
// PROGRAMS_MakeFile("MEM.COM",MEM_ProgramStart); /*next release */
#if !defined (WIN32) /* Unix */
PROGRAMS_MakeFile("UPCASE.COM",UPCASE_ProgramStart);
#endif
}

54
src/dos/dos_tables.cpp Normal file
View file

@ -0,0 +1,54 @@
/*
* Copyright (C) 2002 The DOSBox Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "dosbox.h"
#include "mem.h"
#include "dos_inc.h"
#pragma pack(1)
struct DOS_TableCase {
Bit16u size;
Bit8u chars[256];
};
#pragma pack()
RealPt DOS_TableUpCase;
RealPt DOS_TableLowCase;
static Bit16u dos_memseg=0xd000;
Bit16u DOS_GetMemory(Bit16u pages) {
if (pages+dos_memseg>=0xe000) {
E_Exit("DOS:Not enough memory for internal tables");
}
Bit16u page=dos_memseg;
dos_memseg+=pages;
return page;
}
void DOS_SetupTables(void) {
dos.tables.indosflag=RealMake(DOS_GetMemory(1),0);
mem_writeb(Real2Phys(dos.tables.indosflag),0);
};

277
src/dos/drive_local.cpp Normal file
View file

@ -0,0 +1,277 @@
/*
* Copyright (C) 2002 The DOSBox Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include "dosbox.h"
#include "dos_system.h"
#include "drives.h"
#include "support.h"
#include "cross.h"
class localFile : public DOS_File {
public:
localFile(FILE * handle,Bit16u devinfo);
bool Read(Bit8u * data,Bit16u * size);
bool Write(Bit8u * data,Bit16u * size);
bool Seek(Bit32u * pos,Bit32u type);
bool Close();
Bit16u GetInformation(void);
private:
FILE * fhandle;
Bit16u info;
};
bool localDrive:: FileCreate(DOS_File * * file,char * name,Bit16u attributes) {
//TODO Maybe care for attributes but not likely
char newname[512];
strcpy(newname,basedir);
strcat(newname,name);
CROSS_FILENAME(newname);
FILE * hand=fopen(newname,"wb+");
if (!hand) return false;
/* Make the 16 bit device information */
*file=new localFile(hand,0x202);
return true;
};
bool localDrive::FileOpen(DOS_File * * file,char * name,Bit32u flags) {
char * type;
switch (flags) {
case OPEN_READ:type="rb";break;
case OPEN_WRITE:type="rb+";break;
case OPEN_READWRITE:type="rb+";break;
default:
//TODO FIX IT
type="rb+";
// return false;
};
char newname[512];
strcpy(newname,basedir);
strcat(newname,name);
CROSS_FILENAME(newname);
FILE * hand=fopen(newname,type);
Bit32u err=errno;
if (!hand) return false;
*file=new localFile(hand,0x202);
return true;
};
bool localDrive::FileUnlink(char * name) {
char newname[512];
strcpy(newname,basedir);
strcat(newname,name);
CROSS_FILENAME(newname);
if (!unlink(newname)) return true;
return false;
};
bool localDrive::FindFirst(char * search,DTA_FindBlock * dta) {
//TODO Find some way for lowcase and highcase drives oneday
char name[512];
strcpy(name,basedir);
strcat(name,search);
CROSS_FILENAME(name);
char * last=strrchr(name, CROSS_FILESPLIT);
*last=0;
last++;
/* Check the wildcard string for an extension */
strcpy(wild_name,last);
wild_ext=strrchr(wild_name,'.');
if (wild_ext) {
*wild_ext++=0;
}
strcpy(directory,name);
/* make sure / is last sign */
if (pdir) closedir(pdir);
if(directory[(strlen(directory)-1)]!=CROSS_FILESPLIT) strcat(directory, "/");
if((pdir=opendir(directory))==NULL) return false;
return FindNext(dta);
}
bool localDrive::FindNext(DTA_FindBlock * dta) {
Bit8u tempattr=0;
struct dirent *tempdata;
struct stat stat_block;
char werkbuffer[512];
if(pdir==NULL){
return false;
};
start:
if((tempdata=readdir(pdir))==NULL) {
closedir(pdir);
pdir=NULL;
return false;
}
strcpy(werkbuffer,tempdata->d_name);
if (wild_ext) {
char * ext=strrchr(werkbuffer,'.');
if (!ext) ext="*";
else *ext++=0;
if(!wildcmp(wild_ext,ext)) goto start;
}
if(!wildcmp(wild_name,werkbuffer)) goto start;
werkbuffer[0]='\0';
strcpy(werkbuffer,directory);
strcat(werkbuffer,tempdata->d_name);
if(stat(werkbuffer,&stat_block)!=0){
/*nu is er iets fout!*/ exit(1);
}
if(S_ISDIR(stat_block.st_mode)) tempattr=DOS_ATTR_DIRECTORY;
else tempattr=DOS_ATTR_ARCHIVE;
if(!(dta->sattr & tempattr)) goto start;
/*file is oke so filldtablok */
if(strlen(tempdata->d_name)<=DOS_NAMELENGTH) strcpy(dta->name,upcase(tempdata->d_name));
dta->attr=tempattr;
dta->size=(Bit32u) stat_block.st_size;
struct tm *time;
time=localtime(&stat_block.st_mtime);
dta->time=(time->tm_hour<<11)+(time->tm_min<<5)+(time->tm_sec/2); /* standard way. */
dta->date=((time->tm_year-80)<<9)+((time->tm_mon+1)<<5)+(time->tm_mday);
return true;
}
bool localDrive::GetFileAttr(char * name,Bit16u * attr) {
char newname[512];
strcpy(newname,basedir);
strcat(newname,name);
CROSS_FILENAME(newname);
FILE * hand=fopen(newname,"rb");
if (hand) {
fclose(hand);
*attr=DOS_ATTR_ARCHIVE;
return true;
}
*attr=0;
return false;
};
bool localDrive::MakeDir(char * dir) {
char newdir[512];
strcpy(newdir,basedir);
strcat(newdir,dir);
CROSS_FILENAME(newdir);
#if defined (WIN32) /* MS Visual C++ */
int temp=mkdir(newdir);
#else
int temp=mkdir(newdir,0);
#endif
return (temp==0);
}
bool localDrive::RemoveDir(char * dir) {
char newdir[512];
strcpy(newdir,basedir);
strcat(newdir,dir);
int temp=rmdir(newdir);
return (temp==0);
}
bool localDrive::TestDir(char * dir) {
char newdir[512];
strcpy(newdir,basedir);
strcat(newdir,dir);
int temp=access(newdir,F_OK);
return (temp==0);
}
bool localDrive::Rename(char * oldname,char * newname) {
char newold[512];
strcpy(newold,basedir);
strcat(newold,oldname);
CROSS_FILENAME(newold);
char newnew[512];
strcpy(newnew,basedir);
strcat(newnew,newnew);
CROSS_FILENAME(newname);
int temp=rename(newold,newnew);
return (temp==0);
};
bool localDrive::FreeSpace(Bit16u * bytes,Bit16u * sectors,Bit16u * clusters,Bit16u * free) {
/* Always report 100 mb free should be enough */
/* Total size is always 1 gb */
*bytes=512;
*sectors=127;
*clusters=16513;
*free=1700;
return true;
};
localDrive::localDrive(char * startdir) {
strcpy(basedir,startdir);
sprintf(info,"local directory %s",startdir);
pdir=NULL;
}
bool localFile::Read(Bit8u * data,Bit16u * size) {
*size=fread(data,1,*size,fhandle);
return true;
};
bool localFile::Write(Bit8u * data,Bit16u * size) {
*size=fwrite(data,1,*size,fhandle);
return true;
}
bool localFile::Seek(Bit32u * pos,Bit32u type) {
int seektype;
switch (type) {
case DOS_SEEK_SET:seektype=SEEK_SET;break;
case DOS_SEEK_CUR:seektype=SEEK_CUR;break;
case DOS_SEEK_END:seektype=SEEK_END;break;
default:
//TODO Give some doserrorcode;
return false;//ERROR
}
fpos_t temppos;
int ret=fseek(fhandle,*pos,seektype);
fgetpos(fhandle,&temppos);
//TODO Hope we don't encouter files with 64 bits size
Bit32u * fake_pos=(Bit32u*)&temppos;
*pos=*fake_pos;
return true;
}
bool localFile::Close() {
fclose(fhandle);
return true;
}
Bit16u localFile::GetInformation(void) {
return info;
}
localFile::localFile(FILE * handle,Bit16u devinfo) {
fhandle=handle;
info=devinfo;
}

205
src/dos/drive_virtual.cpp Normal file
View file

@ -0,0 +1,205 @@
/*
* Copyright (C) 2002 The DOSBox Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dosbox.h"
#include "dos_system.h"
#include "drives.h"
#include "support.h"
struct VFILE_Block {
char * name;
Bit8u * data;
Bit32u size;
VFILE_Block * next;
};
static VFILE_Block * first_file;
void VFILE_Register(char * name,Bit8u * data,Bit32u size) {
VFILE_Block * new_file=new VFILE_Block;
new_file->name=name;
new_file->data=data;
new_file->size=size;
new_file->next=first_file;
first_file=new_file;
}
class Virtual_File : public DOS_File {
public:
Virtual_File(Bit8u * in_data,Bit32u in_size);
bool Read(Bit8u * data,Bit16u * size);
bool Write(Bit8u * data,Bit16u * size);
bool Seek(Bit32u * pos,Bit32u type);
bool Close();
Bit16u GetInformation(void);
private:
Bit32u file_size;
Bit32u file_pos;
Bit8u * file_data;
};
Virtual_File::Virtual_File(Bit8u * in_data,Bit32u in_size) {
file_size=in_size;
file_data=in_data;
file_pos=0;
}
bool Virtual_File::Read(Bit8u * data,Bit16u * size) {
Bit32u left=file_size-file_pos;
if (left<=*size) {
memcpy(data,&file_data[file_pos],left);
*size=(Bit16u)left;
} else {
memcpy(data,&file_data[file_pos],*size);
}
file_pos+=*size;
return true;
};
bool Virtual_File::Write(Bit8u * data,Bit16u * size){
/* Not really writeable */
return false;
};
bool Virtual_File::Seek(Bit32u * new_pos,Bit32u type){
switch (type) {
case DOS_SEEK_SET:
if (*new_pos<=file_size) file_pos=*new_pos;
else return false;
break;
case DOS_SEEK_CUR:
if ((*new_pos+file_pos)<=file_size) file_pos=*new_pos+file_pos;
else return false;
break;
case DOS_SEEK_END:
if (*new_pos<=file_size) file_pos=file_size-*new_pos;
else return false;
break;
}
*new_pos=file_pos;
return true;
};
bool Virtual_File::Close(){
return true;
};
Bit16u Virtual_File::GetInformation(void) {
return 0;
}
Virtual_Drive::Virtual_Drive() {
strcpy(info,"Internal Virtual Drive");
search_file=0;
}
bool Virtual_Drive::FileOpen(DOS_File * * file,char * name,Bit32u flags) {
/* Scan through the internal list of files */
VFILE_Block * cur_file=first_file;
while (cur_file) {
if (strcasecmp(name,cur_file->name)==0) {
/* We have a match */
*file=new Virtual_File(cur_file->data,cur_file->size);
return true;
}
cur_file=cur_file->next;
}
return false;
}
bool Virtual_Drive::FileCreate(DOS_File * * file,char * name,Bit16u attributes) {
return false;
}
bool Virtual_Drive::FileUnlink(char * name) {
return false;
}
bool Virtual_Drive::RemoveDir(char * dir) {
return false;
}
bool Virtual_Drive::MakeDir(char * dir) {
return false;
}
bool Virtual_Drive::TestDir(char * dir) {
return false;
}
static void FillDTABlock(DTA_FindBlock * dta,VFILE_Block * fill_file) {
strcpy(dta->name,fill_file->name);
dta->size=fill_file->size;
dta->attr=DOS_ATTR_ARCHIVE;
dta->time=2;
dta->date=6;
}
bool Virtual_Drive::FindFirst(char * search,DTA_FindBlock * dta) {
search_file=first_file;
strcpy(search_string,search);
while (search_file) {
if (wildcmp(search_string,search_file->name)) {
FillDTABlock(dta,search_file);
search_file=search_file->next;
return true;
}
search_file=search_file->next;
}
return false;
}
bool Virtual_Drive::FindNext(DTA_FindBlock * dta) {
while (search_file) {
if (wildcmp(search_string,search_file->name)) {
FillDTABlock(dta,search_file);
search_file=search_file->next;
return true;
}
search_file=search_file->next;
}
return false;
}
bool Virtual_Drive::GetFileAttr(char * name,Bit16u * attr) {
return false;
}
bool Virtual_Drive::Rename(char * oldname,char * newname) {
return false;
}
bool Virtual_Drive::FreeSpace(Bit16u * bytes,Bit16u * sectors,Bit16u * clusters,Bit16u * free) {
/* Always report 100 mb free should be enough */
/* Total size is always 1 gb */
*bytes=512;
*sectors=127;
*clusters=16513;
*free=00;
return true;
}

31
src/dos/drives.cpp Normal file
View file

@ -0,0 +1,31 @@
/*
* Copyright (C) 2002 The DOSBox Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "dosbox.h"
#include "dos_system.h"
#include "drives.h"
DOS_Drive::DOS_Drive() {
curdir[0]=0;
info[0]=0;
}
char * DOS_Drive::GetInfo(void) {
return info;
}

71
src/dos/drives.h Normal file
View file

@ -0,0 +1,71 @@
/*
* Copyright (C) 2002 The DOSBox Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _DRIVES_H__
#define _DRIVES_H__
#include <sys/types.h>
#include <dirent.h>
class localDrive : public DOS_Drive {
public:
localDrive(char * startdir);
bool FileOpen(DOS_File * * file,char * name,Bit32u flags);
bool FileCreate(DOS_File * * file,char * name,Bit16u attributes);
bool FileUnlink(char * name);
bool RemoveDir(char * dir);
bool MakeDir(char * dir);
bool TestDir(char * dir);
bool FindFirst(char * search,DTA_FindBlock * dta);
bool FindNext(DTA_FindBlock * dta);
bool GetFileAttr(char * name,Bit16u * attr);
bool Rename(char * oldname,char * newname);
bool FreeSpace(Bit16u * bytes,Bit16u * sectors,Bit16u * clusters,Bit16u * free);
private:
bool FillDTABlock(DTA_FindBlock * dta);
char basedir[512];
char directory[512];
char wild_name[15];
char * wild_ext;
DIR *pdir;
};
struct VFILE_Block;
class Virtual_Drive: public DOS_Drive {
public:
Virtual_Drive();
bool FileOpen(DOS_File * * file,char * name,Bit32u flags);
bool FileCreate(DOS_File * * file,char * name,Bit16u attributes);
bool FileUnlink(char * name);
bool RemoveDir(char * dir);
bool MakeDir(char * dir);
bool TestDir(char * dir);
bool FindFirst(char * search,DTA_FindBlock * dta);
bool FindNext(DTA_FindBlock * dta);
bool GetFileAttr(char * name,Bit16u * attr);
bool Rename(char * oldname,char * newname);
bool FreeSpace(Bit16u * bytes,Bit16u * sectors,Bit16u * clusters,Bit16u * free);
private:
VFILE_Block * search_file;
char search_string[255];
};
#endif