#include "bios.h"
#include "emulator.h"
+#include "registers.h"
+
/* PRIVATE VARIABLES **********************************************************/
static WORD CurrentPsp = SYSTEM_PSP;
static WORD DosLastError = 0;
static DWORD DiskTransferArea;
+static BYTE CurrentDrive;
+static CHAR LastDrive = 'E';
+static CHAR CurrentDirectories[NUM_DRIVES][DOS_DIR_LENGTH];
static HANDLE DosSystemFileTable[DOS_SFT_SIZE];
static WORD DosSftRefCount[DOS_SFT_SIZE];
static BYTE DosAllocStrategy = DOS_ALLOC_BEST_FIT;
static BOOLEAN DosUmbLinked = FALSE;
+static WORD DosErrorLevel = 0x0000;
/* PRIVATE FUNCTIONS **********************************************************/
+/* Taken from base/shell/cmd/console.c */
+static BOOL IsConsoleHandle(HANDLE hHandle)
+{
+ DWORD dwMode;
+
+ /* Check whether the handle may be that of a console... */
+ if ((GetFileType(hHandle) & FILE_TYPE_CHAR) == 0) return FALSE;
+
+ /*
+ * It may be. Perform another test... The idea comes from the
+ * MSDN description of the WriteConsole API:
+ *
+ * "WriteConsole fails if it is used with a standard handle
+ * that is redirected to a file. If an application processes
+ * multilingual output that can be redirected, determine whether
+ * the output handle is a console handle (one method is to call
+ * the GetConsoleMode function and check whether it succeeds).
+ * If the handle is a console handle, call WriteConsole. If the
+ * handle is not a console handle, the output is redirected and
+ * you should call WriteFile to perform the I/O."
+ */
+ return GetConsoleMode(hHandle, &dwMode);
+}
+
static VOID DosCombineFreeBlocks(WORD StartBlock)
{
PDOS_MCB CurrentMcb = SEGMENT_TO_MCB(StartBlock), NextMcb;
ULONG TotalSize = 0;
WORD DestSegment;
- Ptr = SourceBuffer = (PCHAR)((ULONG_PTR)BaseAddress + TO_LINEAR(SourceSegment, 0));
+ Ptr = SourceBuffer = (PCHAR)SEG_OFF_TO_PTR(SourceSegment, 0);
/* Calculate the size of the environment block */
while (*Ptr)
Ptr = SourceBuffer;
- DestBuffer = (PCHAR)((ULONG_PTR)BaseAddress + TO_LINEAR(DestSegment, 0));
+ DestBuffer = (PCHAR)SEG_OFF_TO_PTR(DestSegment, 0);
while (*Ptr)
{
/* Copy the string */
WORD Result = ERROR_SUCCESS;
DWORD BytesWritten32 = 0;
HANDLE Handle = DosGetRealHandle(FileHandle);
+ WORD i;
DPRINT("DosWriteFile: FileHandle 0x%04X, Count 0x%04X\n",
FileHandle,
/* Make sure the handle is valid */
if (Handle == INVALID_HANDLE_VALUE) return ERROR_INVALID_HANDLE;
- /* Write the file */
- if (!WriteFile(Handle, Buffer, Count, &BytesWritten32, NULL))
+ if (IsConsoleHandle(Handle))
{
- /* Store the error code */
- Result = (WORD)GetLastError();
+ for (i = 0; i < Count; i++)
+ {
+ /* Call the BIOS to print the character */
+ BiosPrintCharacter(((LPBYTE)Buffer)[i], DOS_CHAR_ATTRIBUTE, Bda->VideoPage);
+ BytesWritten32++;
+ }
+ }
+ else
+ {
+ /* Write the file */
+ if (!WriteFile(Handle, Buffer, Count, &BytesWritten32, NULL))
+ {
+ /* Store the error code */
+ Result = (WORD)GetLastError();
+ }
}
/* The number of bytes written is always 16-bit */
return ERROR_SUCCESS;
}
+BOOLEAN DosFlushFileBuffers(WORD FileHandle)
+{
+ HANDLE Handle = DosGetRealHandle(FileHandle);
+
+ /* Make sure the handle is valid */
+ if (Handle == INVALID_HANDLE_VALUE) return FALSE;
+
+ /*
+ * No need to check whether the handle is a console handle since
+ * FlushFileBuffers() automatically does this check and calls
+ * FlushConsoleInputBuffer() for us.
+ */
+ // if (IsConsoleHandle(Handle))
+ // return (BOOLEAN)FlushConsoleInputBuffer(hFile);
+ // else
+ return (BOOLEAN)FlushFileBuffers(Handle);
+}
+
BOOLEAN DosDuplicateHandle(WORD OldHandle, WORD NewHandle)
{
BYTE SftIndex;
return TRUE;
}
+BOOLEAN DosChangeDrive(BYTE Drive)
+{
+ WCHAR DirectoryPath[DOS_CMDLINE_LENGTH];
+
+ /* Make sure the drive exists */
+ if (Drive > (LastDrive - 'A')) return FALSE;
+
+ /* Find the path to the new current directory */
+ swprintf(DirectoryPath, L"%c\\%S", Drive + 'A', CurrentDirectories[Drive]);
+
+ /* Change the current directory of the process */
+ if (!SetCurrentDirectory(DirectoryPath)) return FALSE;
+
+ /* Set the current drive */
+ CurrentDrive = Drive;
+
+ /* Return success */
+ return TRUE;
+}
+
+BOOLEAN DosChangeDirectory(LPSTR Directory)
+{
+ BYTE DriveNumber;
+ DWORD Attributes;
+ LPSTR Path;
+
+ /* Make sure the directory path is not too long */
+ if (strlen(Directory) >= DOS_DIR_LENGTH)
+ {
+ DosLastError = ERROR_PATH_NOT_FOUND;
+ return FALSE;
+ }
+
+ /* Get the drive number */
+ DriveNumber = Directory[0] - 'A';
+
+ /* Make sure the drive exists */
+ if (DriveNumber > (LastDrive - 'A'))
+ {
+ DosLastError = ERROR_PATH_NOT_FOUND;
+ return FALSE;
+ }
+
+ /* Get the file attributes */
+ Attributes = GetFileAttributesA(Directory);
+
+ /* Make sure the path exists and is a directory */
+ if ((Attributes == INVALID_FILE_ATTRIBUTES)
+ || !(Attributes & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ DosLastError = ERROR_PATH_NOT_FOUND;
+ return FALSE;
+ }
+
+ /* Check if this is the current drive */
+ if (DriveNumber == CurrentDrive)
+ {
+ /* Change the directory */
+ if (!SetCurrentDirectoryA(Directory))
+ {
+ DosLastError = LOWORD(GetLastError());
+ return FALSE;
+ }
+ }
+
+ /* Get the directory part of the path */
+ Path = strchr(Directory, '\\');
+ if (Path != NULL)
+ {
+ /* Skip the backslash */
+ Path++;
+ }
+
+ /* Set the directory for the drive */
+ if (Path != NULL)
+ {
+ strncpy(CurrentDirectories[DriveNumber], Path, DOS_DIR_LENGTH);
+ }
+ else
+ {
+ CurrentDirectories[DriveNumber][0] = '\0';
+ }
+
+ /* Return success */
+ return TRUE;
+}
+
VOID DosInitializePsp(WORD PspSegment, LPCSTR CommandLine, WORD ProgramSize, WORD Environment)
{
PDOS_PSP PspBlock = SEGMENT_TO_PSP(PspSegment);
/* Save the interrupt vectors */
PspBlock->TerminateAddress = IntVecTable[0x22];
- PspBlock->BreakAddress = IntVecTable[0x23];
- PspBlock->CriticalAddress = IntVecTable[0x24];
+ PspBlock->BreakAddress = IntVecTable[0x23];
+ PspBlock->CriticalAddress = IntVecTable[0x24];
/* Set the parent PSP */
PspBlock->ParentPsp = CurrentPsp;
PspBlock->FarCall[2] = 0xCB; // retf
/* Set the command line */
- PspBlock->CommandLineSize = (BYTE)min(strlen(CommandLine), DOS_CMDLINE_LENGTH);
+ PspBlock->CommandLineSize = (BYTE)min(strlen(CommandLine), DOS_CMDLINE_LENGTH - 1);
RtlCopyMemory(PspBlock->CommandLine, CommandLine, PspBlock->CommandLineSize);
PspBlock->CommandLine[PspBlock->CommandLineSize] = '\r';
}
BOOLEAN Success = FALSE, AllocatedEnvBlock = FALSE;
HANDLE FileHandle = INVALID_HANDLE_VALUE, FileMapping = NULL;
LPBYTE Address = NULL;
- LPSTR ProgramFilePath, Parameters[128];
- CHAR CommandLineCopy[128];
+ LPSTR ProgramFilePath, Parameters[256];
+ CHAR CommandLineCopy[DOS_CMDLINE_LENGTH];
INT ParamCount = 0;
WORD Segment = 0;
WORD MaxAllocSize;
/* Save a copy of the command line */
strcpy(CommandLineCopy, CommandLine);
+ // FIXME: Improve parsing (especially: "some_path\with spaces\program.exe" options)
+
/* Get the file name of the executable */
ProgramFilePath = strtok(CommandLineCopy, " \t");
/* Load the parameters in the local array */
- while ((ParamCount < 256)
+ while ((ParamCount < sizeof(Parameters)/sizeof(Parameters[0]))
&& ((Parameters[ParamCount] = strtok(NULL, " \t")) != NULL))
{
ParamCount++;
DosChangeMemoryOwner(EnvBlock, Segment);
/* Copy the program to Segment:0100 */
- RtlCopyMemory((PVOID)((ULONG_PTR)BaseAddress
- + TO_LINEAR(Segment, 0x100)),
+ RtlCopyMemory(SEG_OFF_TO_PTR(Segment, 0x100),
Address + (Header->e_cparhdr << 4),
min(FileSize - (Header->e_cparhdr << 4),
(ExeSize << 4) - sizeof(DOS_PSP)));
for (i = 0; i < Header->e_crlc; i++)
{
/* Get a pointer to the word that needs to be patched */
- RelocWord = (PWORD)((ULONG_PTR)BaseAddress
- + TO_LINEAR(Segment + HIWORD(RelocationTable[i]),
- 0x100 + LOWORD(RelocationTable[i])));
+ RelocWord = (PWORD)SEG_OFF_TO_PTR(Segment + HIWORD(RelocationTable[i]),
+ 0x100 + LOWORD(RelocationTable[i]));
/* Add the number of the EXE segment to it */
*RelocWord += Segment + (sizeof(DOS_PSP) >> 4);
}
/* Set the initial segment registers */
- EmulatorSetRegister(EMULATOR_REG_DS, Segment);
- EmulatorSetRegister(EMULATOR_REG_ES, Segment);
+ setDS(Segment);
+ setES(Segment);
/* Set the stack to the location from the header */
EmulatorSetStack(Segment + (sizeof(DOS_PSP) >> 4) + Header->e_ss,
DosChangeMemoryOwner(EnvBlock, Segment);
/* Copy the program to Segment:0100 */
- RtlCopyMemory((PVOID)((ULONG_PTR)BaseAddress
- + TO_LINEAR(Segment, 0x100)),
+ RtlCopyMemory(SEG_OFF_TO_PTR(Segment, 0x100),
Address,
FileSize);
EnvBlock);
/* Set the initial segment registers */
- EmulatorSetRegister(EMULATOR_REG_DS, Segment);
- EmulatorSetRegister(EMULATOR_REG_ES, Segment);
+ setDS(Segment);
+ setES(Segment);
/* Set the stack to the last word of the segment */
EmulatorSetStack(Segment, 0xFFFE);
if (CurrentMcb->BlockType != 'M' && CurrentMcb->BlockType !='Z') break;
/* If this block was allocated by the process, free it */
- if (CurrentMcb->OwnerPsp == Psp) DosFreeMemory(McbSegment);
+ if (CurrentMcb->OwnerPsp == Psp) DosFreeMemory(McbSegment + 1);
/* If this was the last block, quit */
if (CurrentMcb->BlockType == 'Z') break;
if (CurrentPsp == SYSTEM_PSP) VdmRunning = FALSE;
}
+ /* Save the return code - Normal termination */
+ DosErrorLevel = MAKEWORD(ReturnCode, 0x00);
+
/* Return control to the parent process */
EmulatorExecute(HIWORD(PspBlock->TerminateAddress),
LOWORD(PspBlock->TerminateAddress));
CHAR Character = '\0';
WORD BytesRead;
- /* Use the file reading function */
- DosReadFile(DOS_INPUT_HANDLE, &Character, sizeof(CHAR), &BytesRead);
+ if (IsConsoleHandle(DosGetRealHandle(DOS_INPUT_HANDLE)))
+ {
+ /* Call the BIOS */
+ Character = LOBYTE(BiosGetCharacter());
+ }
+ else
+ {
+ /* Use the file reading function */
+ DosReadFile(DOS_INPUT_HANDLE, &Character, sizeof(CHAR), &BytesRead);
+ }
return Character;
}
+BOOLEAN DosCheckInput(VOID)
+{
+ HANDLE Handle = DosGetRealHandle(DOS_INPUT_HANDLE);
+
+ if (IsConsoleHandle(Handle))
+ {
+ /* Call the BIOS */
+ return (BiosPeekCharacter() != 0xFFFF);
+ }
+ else
+ {
+ DWORD FileSizeHigh;
+ DWORD FileSize = GetFileSize(Handle, &FileSizeHigh);
+ LONG LocationHigh = 0;
+ DWORD Location = SetFilePointer(Handle, 0, &LocationHigh, FILE_CURRENT);
+
+ return ((Location != FileSize) || (LocationHigh != FileSizeHigh));
+ }
+}
+
VOID DosPrintCharacter(CHAR Character)
{
WORD BytesWritten;
InfoWord |= 1 << 7;
/* Return the device information word */
- EmulatorSetRegister(EMULATOR_REG_DX, InfoWord);
-
+ setDX(InfoWord);
return TRUE;
}
VOID DosInt21h(LPWORD Stack)
{
- INT i;
- CHAR Character;
+ BYTE Character;
SYSTEMTIME SystemTime;
PCHAR String;
PDOS_INPUT_BUFFER InputBuffer;
- DWORD Eax = EmulatorGetRegister(EMULATOR_REG_AX);
- DWORD Ecx = EmulatorGetRegister(EMULATOR_REG_CX);
- DWORD Edx = EmulatorGetRegister(EMULATOR_REG_DX);
- DWORD Ebx = EmulatorGetRegister(EMULATOR_REG_BX);
- WORD DataSegment = (WORD)EmulatorGetRegister(EMULATOR_REG_DS);
- WORD ExtSegment = (WORD)EmulatorGetRegister(EMULATOR_REG_ES);
/* Check the value in the AH register */
- switch (HIBYTE(Eax))
+ switch (getAH())
{
/* Terminate Program */
case 0x00:
break;
}
- /* Read Character And Echo */
+ /* Read Character from STDIN with Echo */
case 0x01:
{
Character = DosReadCharacter();
DosPrintCharacter(Character);
- EmulatorSetRegister(EMULATOR_REG_AX, (Eax & 0xFFFFFF00) | Character);
+
+ /* Let the BOP repeat if needed */
+ if (getCF()) break;
+
+ setAL(Character);
break;
}
- /* Print Character */
+ /* Write Character to STDOUT */
case 0x02:
{
- DosPrintCharacter(LOBYTE(Edx));
+ Character = getDL();
+ DosPrintCharacter(Character);
+
+ /*
+ * We return the output character (DOS 2.1+).
+ * Also, if we're going to output a TAB, then
+ * don't return a TAB but a SPACE instead.
+ * See Ralf Brown: http://www.ctyme.com/intr/rb-2554.htm
+ * for more information.
+ */
+ setAL(Character == '\t' ? ' ' : Character);
break;
}
- /* Read Character Without Echo */
+ /* Read Character from STDAUX */
+ case 0x03:
+ {
+ // FIXME: Really read it from STDAUX!
+ DPRINT1("INT 16h, 03h: Read character from STDAUX is HALFPLEMENTED\n");
+ setAL(DosReadCharacter());
+ break;
+ }
+
+ /* Write Character to STDAUX */
+ case 0x04:
+ {
+ // FIXME: Really write it to STDAUX!
+ DPRINT1("INT 16h, 04h: Write character to STDAUX is HALFPLEMENTED\n");
+ DosPrintCharacter(getDL());
+ break;
+ }
+
+ /* Write Character to Printer */
+ case 0x05:
+ {
+ // FIXME: Really write it to printer!
+ DPRINT1("INT 16h, 05h: Write character to printer is HALFPLEMENTED -\n\n");
+ DPRINT1("0x%p\n", getDL());
+ DPRINT1("\n\n-----------\n\n");
+ break;
+ }
+
+ /* Direct Console I/O */
+ case 0x06:
+ {
+ Character = getDL();
+
+ if (Character != 0xFF)
+ {
+ /* Output */
+ DosPrintCharacter(Character);
+
+ /*
+ * We return the output character (DOS 2.1+).
+ * See Ralf Brown: http://www.ctyme.com/intr/rb-2558.htm
+ * for more information.
+ */
+ setAL(Character);
+ }
+ else
+ {
+ /* Input */
+ if (DosCheckInput())
+ {
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_ZF;
+ setAL(DosReadCharacter());
+ }
+ else
+ {
+ /* No character available */
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_ZF;
+ setAL(0x00);
+ }
+ }
+
+ break;
+ }
+
+ /* Character Input without Echo */
case 0x07:
case 0x08:
{
- EmulatorSetRegister(EMULATOR_REG_AX,
- (Eax & 0xFFFFFF00) | DosReadCharacter());
+ Character = DosReadCharacter();
+
+ /* Let the BOP repeat if needed */
+ if (getCF()) break;
+
+ setAL(Character);
break;
}
- /* Print String */
+ /* Write string to STDOUT */
case 0x09:
{
- String = (PCHAR)((ULONG_PTR)BaseAddress
- + TO_LINEAR(DataSegment, LOWORD(Edx)));
+ String = (PCHAR)SEG_OFF_TO_PTR(getDS(), getDX());
- while ((*String) != '$')
+ while (*String != '$')
{
DosPrintCharacter(*String);
String++;
}
+ /*
+ * We return the terminating character (DOS 2.1+).
+ * See Ralf Brown: http://www.ctyme.com/intr/rb-2562.htm
+ * for more information.
+ */
+ setAL('$');
break;
}
/* Read Buffered Input */
case 0x0A:
{
- InputBuffer = (PDOS_INPUT_BUFFER)((ULONG_PTR)BaseAddress
- + TO_LINEAR(DataSegment,
- LOWORD(Edx)));
+ InputBuffer = (PDOS_INPUT_BUFFER)SEG_OFF_TO_PTR(getDS(), getDX());
- InputBuffer->Length = 0;
- for (i = 0; i < InputBuffer->MaxLength; i ++)
+ while (Stack[STACK_COUNTER] < InputBuffer->MaxLength)
{
+ /* Try to read a character */
Character = DosReadCharacter();
+
+ /* If it's not ready yet, let the BOP repeat */
+ if (getCF()) break;
+
+ /* Echo the character and append it to the buffer */
DosPrintCharacter(Character);
- InputBuffer->Buffer[InputBuffer->Length] = Character;
+ InputBuffer->Buffer[Stack[STACK_COUNTER]] = Character;
+
if (Character == '\r') break;
- InputBuffer->Length++;
+ Stack[STACK_COUNTER]++;
+ }
+
+ /* Update the length */
+ InputBuffer->Length = Stack[STACK_COUNTER];
+ break;
+ }
+
+ /* Get STDIN Status */
+ case 0x0B:
+ {
+ setAL(DosCheckInput() ? 0xFF : 0x00);
+ break;
+ }
+
+ /* Flush Buffer and Read STDIN */
+ case 0x0C:
+ {
+ BYTE InputFunction = getAL();
+
+ /* Flush STDIN buffer */
+ DosFlushFileBuffers(DOS_INPUT_HANDLE); // Maybe just create a DosFlushInputBuffer...
+
+ /*
+ * If the input function number contained in AL is valid, i.e.
+ * AL == 0x01 or 0x06 or 0x07 or 0x08 or 0x0A, call ourselves
+ * recursively with AL == AH.
+ */
+ if (InputFunction == 0x01 || InputFunction == 0x06 ||
+ InputFunction == 0x07 || InputFunction == 0x08 ||
+ InputFunction == 0x0A)
+ {
+ setAH(InputFunction);
+ /*
+ * Instead of calling ourselves really recursively as in:
+ * DosInt21h(Stack);
+ * prefer resetting the CF flag to let the BOP repeat.
+ */
+ setCF(1);
}
+ break;
+ }
+
+ /* Disk Reset */
+ case 0x0D:
+ {
+ PDOS_PSP PspBlock = SEGMENT_TO_PSP(CurrentPsp);
+
+ // TODO: Flush what's needed.
+ DPRINT1("INT 21h, 0Dh is UNIMPLEMENTED\n");
+
+ /* Clear CF in DOS 6 only */
+ if (PspBlock->DosVersion == 0x0006)
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
break;
}
+ /* Set Default Drive */
+ case 0x0E:
+ {
+ DosChangeDrive(getDL());
+ setAL(LastDrive - 'A' + 1);
+ break;
+ }
+
+ /* NULL Function for CP/M Compatibility */
+ case 0x18:
+ {
+ /*
+ * This function corresponds to the CP/M BDOS function
+ * "get bit map of logged drives", which is meaningless
+ * under MS-DOS.
+ *
+ * For: PTS-DOS 6.51 & S/DOS 1.0 - EXTENDED RENAME FILE USING FCB
+ * See Ralf Brown: http://www.ctyme.com/intr/rb-2584.htm
+ * for more information.
+ */
+ setAL(0x00);
+ break;
+ }
+
+ /* Get Default Drive */
+ case 0x19:
+ {
+ setAL(CurrentDrive);
+ break;
+ }
+
/* Set Disk Transfer Area */
case 0x1A:
{
- DiskTransferArea = MAKELONG(LOWORD(Edx), DataSegment);
+ DiskTransferArea = MAKELONG(getDX(), getDS());
+ break;
+ }
+
+ /* NULL Function for CP/M Compatibility */
+ case 0x1D:
+ case 0x1E:
+ {
+ /*
+ * Function 0x1D corresponds to the CP/M BDOS function
+ * "get bit map of read-only drives", which is meaningless
+ * under MS-DOS.
+ * See Ralf Brown: http://www.ctyme.com/intr/rb-2592.htm
+ * for more information.
+ *
+ * Function 0x1E corresponds to the CP/M BDOS function
+ * "set file attributes", which was meaningless under MS-DOS 1.x.
+ * See Ralf Brown: http://www.ctyme.com/intr/rb-2593.htm
+ * for more information.
+ */
+ setAL(0x00);
+ break;
+ }
+
+ /* NULL Function for CP/M Compatibility */
+ case 0x20:
+ {
+ /*
+ * This function corresponds to the CP/M BDOS function
+ * "get/set default user (sublibrary) number", which is meaningless
+ * under MS-DOS.
+ *
+ * For: S/DOS 1.0+ & PTS-DOS 6.51+ - GET OEM REVISION
+ * See Ralf Brown: http://www.ctyme.com/intr/rb-2596.htm
+ * for more information.
+ */
+ setAL(0x00);
break;
}
/* Set Interrupt Vector */
case 0x25:
{
- DWORD FarPointer = MAKELONG(LOWORD(Edx), DataSegment);
+ DWORD FarPointer = MAKELONG(getDX(), getDS());
/* Write the new far pointer to the IDT */
- ((PDWORD)BaseAddress)[LOBYTE(Eax)] = FarPointer;
+ ((PDWORD)BaseAddress)[getAL()] = FarPointer;
+ break;
+ }
+ /* Create New PSP */
+ case 0x26:
+ {
+ DPRINT1("INT 21h, 26h - Create New PSP is UNIMPLEMENTED\n");
break;
}
- /* Get system date */
+ /* Get System Date */
case 0x2A:
{
GetLocalTime(&SystemTime);
- EmulatorSetRegister(EMULATOR_REG_CX,
- (Ecx & 0xFFFF0000) | SystemTime.wYear);
- EmulatorSetRegister(EMULATOR_REG_DX,
- (Edx & 0xFFFF0000)
- | (SystemTime.wMonth << 8)
- | SystemTime.wDay);
- EmulatorSetRegister(EMULATOR_REG_AX,
- (Eax & 0xFFFFFF00) | SystemTime.wDayOfWeek);
+ setCX(SystemTime.wYear);
+ setDX(MAKEWORD(SystemTime.wDay, SystemTime.wMonth));
+ setAL(SystemTime.wDayOfWeek);
break;
}
- /* Set system date */
+ /* Set System Date */
case 0x2B:
{
GetLocalTime(&SystemTime);
- SystemTime.wYear = LOWORD(Ecx);
- SystemTime.wMonth = HIBYTE(Edx);
- SystemTime.wDay = LOBYTE(Edx);
-
- if (SetLocalTime(&SystemTime))
- {
- /* Return success */
- EmulatorSetRegister(EMULATOR_REG_AX, Eax & 0xFFFFFF00);
- }
- else
- {
- /* Return failure */
- EmulatorSetRegister(EMULATOR_REG_AX, Eax | 0xFF);
- }
+ SystemTime.wYear = getCX();
+ SystemTime.wMonth = getDH();
+ SystemTime.wDay = getDL();
+ /* Return success or failure */
+ setAL(SetLocalTime(&SystemTime) ? 0x00 : 0xFF);
break;
}
- /* Get system time */
+ /* Get System Time */
case 0x2C:
{
GetLocalTime(&SystemTime);
- EmulatorSetRegister(EMULATOR_REG_CX,
- (Ecx & 0xFFFF0000)
- | (SystemTime.wHour << 8)
- | SystemTime.wMinute);
- EmulatorSetRegister(EMULATOR_REG_DX,
- (Edx & 0xFFFF0000)
- | (SystemTime.wSecond << 8)
- | (SystemTime.wMilliseconds / 10));
+ setCX(MAKEWORD(SystemTime.wMinute, SystemTime.wHour));
+ setDX(MAKEWORD(SystemTime.wMilliseconds / 10, SystemTime.wSecond));
break;
}
- /* Set system time */
+ /* Set System Time */
case 0x2D:
{
GetLocalTime(&SystemTime);
- SystemTime.wHour = HIBYTE(Ecx);
- SystemTime.wMinute = LOBYTE(Ecx);
- SystemTime.wSecond = HIBYTE(Edx);
- SystemTime.wMilliseconds = LOBYTE(Edx) * 10;
-
- if (SetLocalTime(&SystemTime))
- {
- /* Return success */
- EmulatorSetRegister(EMULATOR_REG_AX, Eax & 0xFFFFFF00);
- }
- else
- {
- /* Return failure */
- EmulatorSetRegister(EMULATOR_REG_AX, Eax | 0xFF);
- }
+ SystemTime.wHour = getCH();
+ SystemTime.wMinute = getCL();
+ SystemTime.wSecond = getDH();
+ SystemTime.wMilliseconds = getDL() * 10; // In hundredths of seconds
+ /* Return success or failure */
+ setAL(SetLocalTime(&SystemTime) ? 0x00 : 0xFF);
break;
}
/* Get Disk Transfer Area */
case 0x2F:
{
- EmulatorSetRegister(EMULATOR_REG_ES, HIWORD(DiskTransferArea));
- EmulatorSetRegister(EMULATOR_REG_BX, LOWORD(DiskTransferArea));
-
+ setES(HIWORD(DiskTransferArea));
+ setBX(LOWORD(DiskTransferArea));
break;
}
{
PDOS_PSP PspBlock = SEGMENT_TO_PSP(CurrentPsp);
- EmulatorSetRegister(EMULATOR_REG_AX, PspBlock->DosVersion);
+ /*
+ * See Ralf Brown: http://www.ctyme.com/intr/rb-2711.htm
+ * for more information.
+ */
+
+ if (LOBYTE(PspBlock->DosVersion) < 5 || getAL() == 0x00)
+ {
+ /*
+ * Return DOS OEM number:
+ * 0x00 for IBM PC-DOS
+ * 0x02 for packaged MS-DOS
+ */
+ setBH(0x02);
+ }
+
+ if (LOBYTE(PspBlock->DosVersion) >= 5 && getAL() == 0x01)
+ {
+ /*
+ * Return version flag:
+ * 1 << 3 if DOS is in ROM,
+ * 0 (reserved) if not.
+ */
+ setBH(0x00);
+ }
+
+ /* Return DOS 24-bit user serial number in BL:CX */
+ setBL(0x00);
+ setCX(0x0000);
+
+ /* Return DOS version: Minor:Major in AH:AL */
+ setAX(PspBlock->DosVersion);
+
break;
}
/* Get Interrupt Vector */
case 0x35:
{
- DWORD FarPointer = ((PDWORD)BaseAddress)[LOBYTE(Eax)];
+ DWORD FarPointer = ((PDWORD)BaseAddress)[getAL()];
/* Read the address from the IDT into ES:BX */
- EmulatorSetRegister(EMULATOR_REG_ES, HIWORD(FarPointer));
- EmulatorSetRegister(EMULATOR_REG_BX, LOWORD(FarPointer));
-
+ setES(HIWORD(FarPointer));
+ setBX(LOWORD(FarPointer));
break;
}
+ /* SWITCH character - AVAILDEV */
+ case 0x37:
+ {
+ if (getAL() == 0x00)
+ {
+ /*
+ * DOS 2+ - "SWITCHAR" - GET SWITCH CHARACTER
+ * This setting is ignored by MS-DOS 4.0+.
+ * MS-DOS 5+ always return AL=00h/DL=2Fh.
+ * See Ralf Brown: http://www.ctyme.com/intr/rb-2752.htm
+ * for more information.
+ */
+ setDL('/');
+ setAL(0x00);
+ }
+ else if (getAL() == 0x01)
+ {
+ /*
+ * DOS 2+ - "SWITCHAR" - SET SWITCH CHARACTER
+ * This setting is ignored by MS-DOS 5+.
+ * See Ralf Brown: http://www.ctyme.com/intr/rb-2753.htm
+ * for more information.
+ */
+ // getDL();
+ setAL(0xFF);
+ }
+ else if (getAL() == 0x02)
+ {
+ /*
+ * DOS 2.x and 3.3+ only - "AVAILDEV" - SPECIFY \DEV\ PREFIX USE
+ * See Ralf Brown: http://www.ctyme.com/intr/rb-2754.htm
+ * for more information.
+ */
+ // setDL();
+ setAL(0xFF);
+ }
+ else if (getAL() == 0x03)
+ {
+ /*
+ * DOS 2.x and 3.3+ only - "AVAILDEV" - SPECIFY \DEV\ PREFIX USE
+ * See Ralf Brown: http://www.ctyme.com/intr/rb-2754.htm
+ * for more information.
+ */
+ // getDL();
+ setAL(0xFF);
+ }
+ else
+ {
+ setAL(0xFF);
+ }
+
+ break;
+ }
+
/* Create Directory */
case 0x39:
{
- String = (PCHAR)((ULONG_PTR)BaseAddress
- + TO_LINEAR(DataSegment, LOWORD(Edx)));
+ String = (PCHAR)SEG_OFF_TO_PTR(getDS(), getDX());
if (CreateDirectoryA(String, NULL))
{
else
{
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
- EmulatorSetRegister(EMULATOR_REG_AX,
- (Eax & 0xFFFF0000) | LOWORD(GetLastError()));
+ setAX(LOWORD(GetLastError()));
}
break;
/* Remove Directory */
case 0x3A:
{
- String = (PCHAR)((ULONG_PTR)BaseAddress
- + TO_LINEAR(DataSegment, LOWORD(Edx)));
+ String = (PCHAR)SEG_OFF_TO_PTR(getDS(), getDX());
if (RemoveDirectoryA(String))
{
else
{
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
- EmulatorSetRegister(EMULATOR_REG_AX,
- (Eax & 0xFFFF0000) | LOWORD(GetLastError()));
+ setAX(LOWORD(GetLastError()));
}
-
break;
}
/* Set Current Directory */
case 0x3B:
{
- String = (PCHAR)((ULONG_PTR)BaseAddress
- + TO_LINEAR(DataSegment, LOWORD(Edx)));
+ String = (PCHAR)SEG_OFF_TO_PTR(getDS(), getDX());
- if (SetCurrentDirectoryA(String))
+ if (DosChangeDirectory(String))
{
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
}
else
{
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
- EmulatorSetRegister(EMULATOR_REG_AX,
- (Eax & 0xFFFF0000) | LOWORD(GetLastError()));
+ setAX(DosLastError);
}
break;
{
WORD FileHandle;
WORD ErrorCode = DosCreateFile(&FileHandle,
- (LPCSTR)(ULONG_PTR)BaseAddress
- + TO_LINEAR(DataSegment, LOWORD(Edx)),
- LOWORD(Ecx));
+ (LPCSTR)SEG_OFF_TO_PTR(getDS(), getDX()),
+ getCX());
if (ErrorCode == 0)
{
- /* Clear CF */
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
-
- /* Return the handle in AX */
- EmulatorSetRegister(EMULATOR_REG_AX,
- (Eax & 0xFFFF0000) | FileHandle);
+ setAX(FileHandle);
}
else
{
- /* Set CF */
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
-
- /* Return the error code in AX */
- EmulatorSetRegister(EMULATOR_REG_AX,
- (Eax & 0xFFFF0000) | ErrorCode);
+ setAX(ErrorCode);
}
break;
case 0x3D:
{
WORD FileHandle;
- WORD ErrorCode = DosCreateFile(&FileHandle,
- (LPCSTR)(ULONG_PTR)BaseAddress
- + TO_LINEAR(DataSegment, LOWORD(Edx)),
- LOBYTE(Eax));
+ WORD ErrorCode = DosOpenFile(&FileHandle,
+ (LPCSTR)SEG_OFF_TO_PTR(getDS(), getDX()),
+ getAL());
if (ErrorCode == 0)
{
- /* Clear CF */
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
-
- /* Return the handle in AX */
- EmulatorSetRegister(EMULATOR_REG_AX,
- (Eax & 0xFFFF0000) | FileHandle);
+ setAX(FileHandle);
}
else
{
- /* Set CF */
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
-
- /* Return the error code in AX */
- EmulatorSetRegister(EMULATOR_REG_AX,
- (Eax & 0xFFFF0000) | ErrorCode);
+ setAX(ErrorCode);
}
break;
/* Close File */
case 0x3E:
{
- if (DosCloseHandle(LOWORD(Ebx)))
+ if (DosCloseHandle(getBX()))
{
- /* Clear CF */
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
}
else
{
- /* Set CF */
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
-
- /* Return the error code in AX */
- EmulatorSetRegister(EMULATOR_REG_AX,
- (Eax & 0xFFFF0000) | ERROR_INVALID_HANDLE);
+ setAX(ERROR_INVALID_HANDLE);
}
break;
}
- /* Read File */
+ /* Read from File or Device */
case 0x3F:
{
+ WORD Handle = getBX();
+ LPBYTE Buffer = (LPBYTE)SEG_OFF_TO_PTR(getDS(), getDX());
+ WORD Count = getCX();
WORD BytesRead = 0;
- WORD ErrorCode = DosReadFile(LOWORD(Ebx),
- (LPVOID)((ULONG_PTR)BaseAddress
- + TO_LINEAR(DataSegment, LOWORD(Edx))),
- LOWORD(Ecx),
- &BytesRead);
+ WORD ErrorCode = ERROR_SUCCESS;
- if (ErrorCode == 0)
+ if (IsConsoleHandle(DosGetRealHandle(Handle)))
{
- /* Clear CF */
- Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ while (Stack[STACK_COUNTER] < Count)
+ {
+ /* Read a character from the BIOS */
+ // FIXME: Security checks!
+ Buffer[Stack[STACK_COUNTER]] = LOBYTE(BiosGetCharacter());
- /* Return the number of bytes read in AX */
- EmulatorSetRegister(EMULATOR_REG_AX,
- (Eax & 0xFFFF0000) | BytesRead);
+ /* Stop if the BOP needs to be repeated */
+ if (getCF()) break;
+
+ /* Increment the counter */
+ Stack[STACK_COUNTER]++;
+ }
+
+ if (Stack[STACK_COUNTER] < Count)
+ ErrorCode = ERROR_NOT_READY;
+ else
+ BytesRead = Count;
}
else
{
- /* Set CF */
- Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ /* Use the file reading function */
+ ErrorCode = DosReadFile(Handle, Buffer, Count, &BytesRead);
+ }
- /* Return the error code in AX */
- EmulatorSetRegister(EMULATOR_REG_AX,
- (Eax & 0xFFFF0000) | ErrorCode);
+ if (ErrorCode == ERROR_SUCCESS)
+ {
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ setAX(BytesRead);
+ }
+ else if (ErrorCode != ERROR_NOT_READY)
+ {
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ setAX(ErrorCode);
}
break;
}
- /* Write File */
+ /* Write to File or Device */
case 0x40:
{
WORD BytesWritten = 0;
- WORD ErrorCode = DosWriteFile(LOWORD(Ebx),
- (LPVOID)((ULONG_PTR)BaseAddress
- + TO_LINEAR(DataSegment, LOWORD(Edx))),
- LOWORD(Ecx),
+ WORD ErrorCode = DosWriteFile(getBX(),
+ SEG_OFF_TO_PTR(getDS(), getDX()),
+ getCX(),
&BytesWritten);
- if (ErrorCode == 0)
+ if (ErrorCode == ERROR_SUCCESS)
{
- /* Clear CF */
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
-
- /* Return the number of bytes written in AX */
- EmulatorSetRegister(EMULATOR_REG_AX,
- (Eax & 0xFFFF0000) | BytesWritten);
+ setAX(BytesWritten);
}
else
{
- /* Set CF */
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
-
- /* Return the error code in AX */
- EmulatorSetRegister(EMULATOR_REG_AX,
- (Eax & 0xFFFF0000) | ErrorCode);
+ setAX(ErrorCode);
}
break;
/* Delete File */
case 0x41:
{
- LPSTR FileName = (LPSTR)((ULONG_PTR)BaseAddress + TO_LINEAR(DataSegment, Edx));
+ LPSTR FileName = (LPSTR)SEG_OFF_TO_PTR(getDS(), getDX());
/* Call the API function */
- if (DeleteFileA(FileName)) Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ if (DeleteFileA(FileName))
+ {
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ /*
+ * See Ralf Brown: http://www.ctyme.com/intr/rb-2797.htm
+ * "AX destroyed (DOS 3.3) AL seems to be drive of deleted file."
+ */
+ setAL(FileName[0] - 'A');
+ }
else
{
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
- EmulatorSetRegister(EMULATOR_REG_AX, GetLastError());
+ setAX(GetLastError());
}
break;
case 0x42:
{
DWORD NewLocation;
- WORD ErrorCode = DosSeekFile(LOWORD(Ebx),
- MAKELONG(LOWORD(Edx), LOWORD(Ecx)),
- LOBYTE(Eax),
+ WORD ErrorCode = DosSeekFile(getBX(),
+ MAKELONG(getDX(), getCX()),
+ getAL(),
&NewLocation);
- if (ErrorCode == 0)
+ if (ErrorCode == ERROR_SUCCESS)
{
- /* Clear CF */
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
/* Return the new offset in DX:AX */
- EmulatorSetRegister(EMULATOR_REG_DX,
- (Edx & 0xFFFF0000) | HIWORD(NewLocation));
- EmulatorSetRegister(EMULATOR_REG_AX,
- (Eax & 0xFFFF0000) | LOWORD(NewLocation));
+ setDX(HIWORD(NewLocation));
+ setAX(LOWORD(NewLocation));
}
else
{
- /* Set CF */
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
-
- /* Return the error code in AX */
- EmulatorSetRegister(EMULATOR_REG_AX,
- (Eax & 0xFFFF0000) | ErrorCode);
+ setAX(ErrorCode);
}
break;
case 0x43:
{
DWORD Attributes;
- LPSTR FileName = (LPSTR)((ULONG_PTR)BaseAddress + TO_LINEAR(DataSegment, Edx));
+ LPSTR FileName = (LPSTR)SEG_OFF_TO_PTR(getDS(), getDX());
- if (LOBYTE(Eax) == 0x00)
+ if (getAL() == 0x00)
{
/* Get the attributes */
Attributes = GetFileAttributesA(FileName);
if (Attributes == INVALID_FILE_ATTRIBUTES)
{
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
- EmulatorSetRegister(EMULATOR_REG_AX, GetLastError());
-
- break;
+ setAX(GetLastError());
+ }
+ else
+ {
+ /* Return the attributes that DOS can understand */
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ setCX(Attributes & 0x00FF);
}
-
- /* Return the attributes that DOS can understand */
- Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
- EmulatorSetRegister(EMULATOR_REG_CX,
- (Ecx & 0xFFFFFF00) | LOBYTE(Attributes));
}
- else if (LOBYTE(Eax) == 0x01)
+ else if (getAL() == 0x01)
{
/* Try to set the attributes */
- if (SetFileAttributesA(FileName, LOBYTE(Ecx)))
+ if (SetFileAttributesA(FileName, getCL()))
{
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
}
else
{
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
- EmulatorSetRegister(EMULATOR_REG_AX, GetLastError());
+ setAX(GetLastError());
}
}
else
{
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
- EmulatorSetRegister(EMULATOR_REG_AX, ERROR_INVALID_FUNCTION);
+ setAX(ERROR_INVALID_FUNCTION);
}
break;
/* IOCTL */
case 0x44:
{
- if (DosHandleIoctl(LOBYTE(Eax), LOWORD(Ebx)))
+ if (DosHandleIoctl(getAL(), getBX()))
{
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
}
else
{
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
- EmulatorSetRegister(EMULATOR_REG_AX, DosLastError);
+ setAX(DosLastError);
}
break;
case 0x45:
{
WORD NewHandle;
- HANDLE Handle = DosGetRealHandle(LOWORD(Ebx));
+ HANDLE Handle = DosGetRealHandle(getBX());
if (Handle != INVALID_HANDLE_VALUE)
{
/* The handle is invalid */
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
- EmulatorSetRegister(EMULATOR_REG_AX, ERROR_INVALID_HANDLE);
-
+ setAX(ERROR_INVALID_HANDLE);
break;
}
{
/* Too many files open */
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
- EmulatorSetRegister(EMULATOR_REG_AX, ERROR_TOO_MANY_OPEN_FILES);
-
+ setAX(ERROR_TOO_MANY_OPEN_FILES);
break;
}
/* Return the result */
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
- EmulatorSetRegister(EMULATOR_REG_AX, NewHandle);
-
+ setAX(NewHandle);
break;
}
/* Force Duplicate Handle */
case 0x46:
{
- if (DosDuplicateHandle(LOWORD(Ebx), LOWORD(Ecx)))
+ if (DosDuplicateHandle(getBX(), getCX()))
{
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
}
else
{
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
- EmulatorSetRegister(EMULATOR_REG_AX, ERROR_INVALID_HANDLE);
+ setAX(ERROR_INVALID_HANDLE);
+ }
+
+ break;
+ }
+
+ /* Get Current Directory */
+ case 0x47:
+ {
+ BYTE DriveNumber = getDL();
+ String = (PCHAR)SEG_OFF_TO_PTR(getDS(), getSI());
+
+ /* Get the real drive number */
+ if (DriveNumber == 0)
+ {
+ DriveNumber = CurrentDrive;
+ }
+ else
+ {
+ /* Decrement DriveNumber since it was 1-based */
+ DriveNumber--;
+ }
+
+ if (DriveNumber <= LastDrive - 'A')
+ {
+ /*
+ * Copy the current directory into the target buffer.
+ * It doesn't contain the drive letter and the backslash.
+ */
+ strncpy(String, CurrentDirectories[DriveNumber], DOS_DIR_LENGTH);
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ setAX(0x0100); // Undocumented, see Ralf Brown: http://www.ctyme.com/intr/rb-2933.htm
+ }
+ else
+ {
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ setAX(ERROR_INVALID_DRIVE);
}
break;
case 0x48:
{
WORD MaxAvailable = 0;
- WORD Segment = DosAllocateMemory(LOWORD(Ebx), &MaxAvailable);
+ WORD Segment = DosAllocateMemory(getBX(), &MaxAvailable);
if (Segment != 0)
{
- EmulatorSetRegister(EMULATOR_REG_AX, Segment);
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ setAX(Segment);
}
else
{
- EmulatorSetRegister(EMULATOR_REG_AX, DosLastError);
- EmulatorSetRegister(EMULATOR_REG_BX, MaxAvailable);
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ setAX(DosLastError);
+ setBX(MaxAvailable);
}
break;
/* Free Memory */
case 0x49:
{
- if (DosFreeMemory(ExtSegment))
+ if (DosFreeMemory(getES()))
{
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
}
else
{
- EmulatorSetRegister(EMULATOR_REG_AX, ERROR_ARENA_TRASHED);
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ setAX(ERROR_ARENA_TRASHED);
}
break;
{
WORD Size;
- if (DosResizeMemory(ExtSegment, LOWORD(Ebx), &Size))
+ if (DosResizeMemory(getES(), getBX(), &Size))
{
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
}
else
{
- EmulatorSetRegister(EMULATOR_REG_AX, DosLastError);
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
- EmulatorSetRegister(EMULATOR_REG_BX, Size);
+ setAX(DosLastError);
+ setBX(Size);
}
break;
/* Terminate With Return Code */
case 0x4C:
{
- DosTerminateProcess(CurrentPsp, LOBYTE(Eax));
+ DosTerminateProcess(CurrentPsp, getAL());
break;
}
- /* Get Current Process */
- case 0x51:
+ /* Get Return Code (ERRORLEVEL) */
+ case 0x4D:
+ {
+ /*
+ * According to Ralf Brown: http://www.ctyme.com/intr/rb-2976.htm
+ * DosErrorLevel is cleared after being read by this function.
+ */
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ setAX(DosErrorLevel);
+ DosErrorLevel = 0x0000; // Clear it
+ break;
+ }
+
+ /* Internal - Set Current Process ID (Set PSP Address) */
+ case 0x50:
{
- EmulatorSetRegister(EMULATOR_REG_BX, CurrentPsp);
+ // FIXME: Is it really what it's done ??
+ CurrentPsp = getBX();
+ break;
+ }
+ /* Get Current Process ID (Get PSP Address) */
+ case 0x51:
+ {
+ setBX(CurrentPsp);
break;
}
/* Get/Set Memory Management Options */
case 0x58:
{
- if (LOBYTE(Eax) == 0x00)
+ if (getAL() == 0x00)
{
/* Get allocation strategy */
-
- EmulatorSetRegister(EMULATOR_REG_AX, DosAllocStrategy);
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ setAX(DosAllocStrategy);
}
- else if (LOBYTE(Eax) == 0x01)
+ else if (getAL() == 0x01)
{
/* Set allocation strategy */
- if ((LOBYTE(Ebx) & (DOS_ALLOC_HIGH | DOS_ALLOC_HIGH_LOW))
+ if ((getBL() & (DOS_ALLOC_HIGH | DOS_ALLOC_HIGH_LOW))
== (DOS_ALLOC_HIGH | DOS_ALLOC_HIGH_LOW))
{
/* Can't set both */
- EmulatorSetRegister(EMULATOR_REG_AX, ERROR_INVALID_PARAMETER);
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ setAX(ERROR_INVALID_PARAMETER);
break;
}
- if ((LOBYTE(Ebx) & 0x3F) > DOS_ALLOC_LAST_FIT)
+ if ((getBL() & 0x3F) > DOS_ALLOC_LAST_FIT)
{
/* Invalid allocation strategy */
- EmulatorSetRegister(EMULATOR_REG_AX, ERROR_INVALID_PARAMETER);
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ setAX(ERROR_INVALID_PARAMETER);
break;
}
- DosAllocStrategy = LOBYTE(Ebx);
+ DosAllocStrategy = getBL();
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
}
- else if (LOBYTE(Eax) == 0x02)
+ else if (getAL() == 0x02)
{
/* Get UMB link state */
-
- Eax &= 0xFFFFFF00;
- if (DosUmbLinked) Eax |= 1;
- EmulatorSetRegister(EMULATOR_REG_AX, Eax);
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ setAL(DosUmbLinked ? 0x01 : 0x00);
}
- else if (LOBYTE(Eax) == 0x03)
+ else if (getAL() == 0x03)
{
/* Set UMB link state */
-
- if (Ebx) DosLinkUmb();
+ if (getBX()) DosLinkUmb();
else DosUnlinkUmb();
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
}
else
{
/* Invalid or unsupported function */
-
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
- EmulatorSetRegister(EMULATOR_REG_AX, ERROR_INVALID_FUNCTION);
+ setAX(ERROR_INVALID_FUNCTION);
}
break;
/* Unsupported */
default:
{
- DPRINT1("DOS Function INT 0x21, AH = 0x%02X NOT IMPLEMENTED!\n", HIBYTE(Eax));
+ DPRINT1("DOS Function INT 0x21, AH = 0x%02X NOT IMPLEMENTED!\n", getAH());
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
}
}
WCHAR Buffer[256];
LPWSTR SourcePtr, Environment;
LPSTR AsciiString;
- LPSTR DestPtr = (LPSTR)((ULONG_PTR)BaseAddress + TO_LINEAR(SYSTEM_ENV_BLOCK, 0));
+ LPSTR DestPtr = (LPSTR)SEG_OFF_TO_PTR(SYSTEM_ENV_BLOCK, 0);
DWORD AsciiSize;
+ CHAR CurrentDirectory[MAX_PATH];
+ CHAR DosDirectory[DOS_DIR_LENGTH];
+ LPSTR Path;
/* Initialize the MCB */
Mcb->BlockType = 'Z';
/* Free the memory allocated for environment strings */
FreeEnvironmentStringsW(Environment);
+ /* Clear the current directory buffer */
+ ZeroMemory(CurrentDirectories, sizeof(CurrentDirectories));
+
+ /* Get the current directory */
+ if (!GetCurrentDirectoryA(MAX_PATH, CurrentDirectory))
+ {
+ // TODO: Use some kind of default path?
+ return FALSE;
+ }
+
+ /* Convert that to a DOS path */
+ if (!GetShortPathNameA(CurrentDirectory, DosDirectory, DOS_DIR_LENGTH))
+ {
+ // TODO: Use some kind of default path?
+ return FALSE;
+ }
+
+ /* Set the drive */
+ CurrentDrive = DosDirectory[0] - 'A';
+
+ /* Get the directory part of the path */
+ Path = strchr(DosDirectory, '\\');
+ if (Path != NULL)
+ {
+ /* Skip the backslash */
+ Path++;
+ }
+
+ /* Set the directory */
+ if (Path != NULL)
+ {
+ strncpy(CurrentDirectories[CurrentDrive], Path, DOS_DIR_LENGTH);
+ }
+
/* Read CONFIG.SYS */
Stream = _wfopen(DOS_CONFIG_PATH, L"r");
if (Stream != NULL)