diff --git a/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/bios.c b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/bios.c index a3c98f93a69..a1ccb186afa 100644 --- a/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/bios.c +++ b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/bios.c @@ -17,6 +17,7 @@ #include "../dem.h" #include "dos.h" #include "dosfiles.h" +#include "handle.h" #include "memory.h" #include "bios/bios.h" @@ -45,6 +46,16 @@ PBIOS_DATA BiosData; CHAR DosReadCharacter(WORD FileHandle) { WORD BytesRead; + PDOS_FILE_DESCRIPTOR Descriptor = NULL; + WORD OldDeviceInfo; + + /* Find the standard input descriptor and switch it to binary mode */ + Descriptor = DosGetHandleFileDescriptor(FileHandle); + if (Descriptor) + { + OldDeviceInfo = Descriptor->DeviceInfo; + Descriptor->DeviceInfo |= FILE_INFO_BINARY; + } Sda->ByteBuffer = '\0'; DPRINT("DosReadCharacter\n"); @@ -55,6 +66,8 @@ CHAR DosReadCharacter(WORD FileHandle) 1, &BytesRead); + /* Restore the old mode and return the character */ + if (Descriptor) Descriptor->DeviceInfo = OldDeviceInfo; return Sda->ByteBuffer; } diff --git a/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/condrv.c b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/condrv.c index a69c748bb3a..5c0b286f9e1 100644 --- a/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/condrv.c +++ b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/condrv.c @@ -63,15 +63,8 @@ WORD NTAPI ConDrvReadInput(PDOS_DEVICE_NODE Device, DWORD Buffer, PWORD Length) Pointer[BytesRead++] = Character; - if (Character != 0 && DoEcho) - DosPrintCharacter(DOS_OUTPUT_HANDLE, Character); - /* Stop on first carriage return */ - if (Character == '\r') - { - if (DoEcho) DosPrintCharacter(DOS_OUTPUT_HANDLE, '\n'); - break; - } + if (Character == '\r') break; } *Length = BytesRead; diff --git a/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.c b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.c index 151186cef9e..18e5081c3ca 100644 --- a/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.c +++ b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.c @@ -45,9 +45,6 @@ PDOS_DATA DosData; PDOS_SYSVARS SysVars; PDOS_SDA Sda; -/* Echo state for INT 21h, AH = 01h and AH = 3Fh */ -BOOLEAN DoEcho = FALSE; - /* PRIVATE FUNCTIONS **********************************************************/ static BOOLEAN DosChangeDrive(BYTE Drive) @@ -162,7 +159,54 @@ static BOOLEAN DosChangeDirectory(LPSTR Directory) return TRUE; } -static BOOLEAN DosControlBreak(VOID) +/* PUBLIC FUNCTIONS ***********************************************************/ + +VOID DosEchoCharacter(CHAR Character) +{ + switch (Character) + { + case '\0': + { + /* Nothing */ + break; + } + + case '\r': + case '\n': + { + /* Print both a carriage return and a newline */ + DosPrintCharacter(DOS_OUTPUT_HANDLE, '\r'); + DosPrintCharacter(DOS_OUTPUT_HANDLE, '\n'); + break; + } + + case '\b': + { + /* Erase the character */ + DosPrintCharacter(DOS_OUTPUT_HANDLE, '\b'); + DosPrintCharacter(DOS_OUTPUT_HANDLE, ' '); + DosPrintCharacter(DOS_OUTPUT_HANDLE, '\b'); + break; + } + + default: + { + /* Check if this is a special character */ + if (Character < 0x20) + { + DosPrintCharacter(DOS_OUTPUT_HANDLE, '^'); + Character += 'A' - 1; + } + else + { + /* Echo the character */ + DosPrintCharacter(DOS_OUTPUT_HANDLE, Character); + } + } + } +} + +BOOLEAN DosControlBreak(VOID) { setCF(0); @@ -178,8 +222,6 @@ static BOOLEAN DosControlBreak(VOID) return FALSE; } -/* PUBLIC FUNCTIONS ***********************************************************/ - VOID WINAPI DosInt20h(LPWORD Stack) { /* @@ -217,14 +259,9 @@ VOID WINAPI DosInt21h(LPWORD Stack) { DPRINT("INT 21h, AH = 01h\n"); - // FIXME: Under DOS 2+, input / output handle may be redirected!!!! - DoEcho = TRUE; Character = DosReadCharacter(DOS_INPUT_HANDLE); - DoEcho = FALSE; - - // FIXME: Check whether Ctrl-C / Ctrl-Break is pressed, and call INT 23h if so. - // Check also Ctrl-P and set echo-to-printer flag. - // Ctrl-Z is not interpreted. + DosEchoCharacter(Character); + if (Character == 0x03 && DosControlBreak()) break; setAL(Character); break; @@ -300,8 +337,11 @@ VOID WINAPI DosInt21h(LPWORD Stack) /* Input */ if (DosCheckInput()) { + CHAR Character = DosReadCharacter(DOS_INPUT_HANDLE); + DosEchoCharacter(Character); + Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_ZF; - setAL(DosReadCharacter(DOS_INPUT_HANDLE)); + setAL(Character); } else { @@ -314,17 +354,21 @@ VOID WINAPI DosInt21h(LPWORD Stack) break; } - /* Character Input without Echo */ + /* Direct Character Input without Echo */ case 0x07: + { + DPRINT("Direct char input without echo\n"); + setAL(DosReadCharacter(DOS_INPUT_HANDLE)); + break; + } + + /* Character Input without Echo */ case 0x08: { DPRINT("Char input without echo\n"); Character = DosReadCharacter(DOS_INPUT_HANDLE); - - // FIXME: For 0x07, do not check Ctrl-C/Break. - // For 0x08, do check those control sequences and if needed, - // call INT 0x23. + if (Character == 0x03 && DosControlBreak()) break; setAL(Character); break; @@ -353,82 +397,19 @@ VOID WINAPI DosInt21h(LPWORD Stack) /* Read Buffered Input */ case 0x0A: { - WORD Count = 0; + WORD BytesRead; PDOS_INPUT_BUFFER InputBuffer = (PDOS_INPUT_BUFFER)SEG_OFF_TO_PTR(getDS(), getDX()); DPRINT("Read Buffered Input\n"); + if (InputBuffer->MaxLength == 0) break; - while (Count < InputBuffer->MaxLength) - { - /* Try to read a character (wait) */ - Character = DosReadCharacter(DOS_INPUT_HANDLE); - - switch (Character) - { - /* Extended character */ - case '\0': - { - /* Read the scancode */ - DosReadCharacter(DOS_INPUT_HANDLE); - break; - } - - /* Ctrl-C */ - case 0x03: - { - DosPrintCharacter(DOS_OUTPUT_HANDLE, '^'); - DosPrintCharacter(DOS_OUTPUT_HANDLE, 'C'); - - if (DosControlBreak()) - { - /* Set the character to a newline to exit the loop */ - Character = '\r'; - } - - break; - } - - /* Backspace */ - case '\b': - { - if (Count > 0) - { - Count--; - - /* Erase the character */ - DosPrintCharacter(DOS_OUTPUT_HANDLE, '\b'); - DosPrintCharacter(DOS_OUTPUT_HANDLE, ' '); - DosPrintCharacter(DOS_OUTPUT_HANDLE, '\b'); - } - - break; - } - - default: - { - /* Append it to the buffer */ - InputBuffer->Buffer[Count] = Character; - - /* Check if this is a special character */ - if (Character < 0x20 && Character != 0x0A && Character != 0x0D) - { - DosPrintCharacter(DOS_OUTPUT_HANDLE, '^'); - Character += 'A' - 1; - } - - /* Echo the character */ - DosPrintCharacter(DOS_OUTPUT_HANDLE, Character); - } - } - - if (Character == '\r') break; - if (Character == '\b') continue; - Count++; /* Carriage returns are NOT counted */ - } - - /* Update the length */ - InputBuffer->Length = Count; + /* Read from standard input */ + DosReadFile(DOS_INPUT_HANDLE, + MAKELONG(getDX() + FIELD_OFFSET(DOS_INPUT_BUFFER, Buffer), getDS()), + InputBuffer->MaxLength, + &BytesRead); + InputBuffer->Length = LOBYTE(BytesRead); break; } @@ -1054,12 +1035,10 @@ VOID WINAPI DosInt21h(LPWORD Stack) DPRINT("DosReadFile(0x%04X)\n", getBX()); - DoEcho = TRUE; ErrorCode = DosReadFile(getBX(), MAKELONG(getDX(), getDS()), getCX(), &BytesRead); - DoEcho = FALSE; if (ErrorCode == ERROR_SUCCESS) { diff --git a/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.h b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.h index 40ce3921730..f8db858fa17 100644 --- a/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.h +++ b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.h @@ -246,6 +246,7 @@ typedef struct _DOS_DATA WORD DosVersion; // DOS version to report to programs (can be different from the true one) DOS_SDA Sda; CHAR CurrentDirectories[NUM_DRIVES][DOS_DIR_LENGTH]; + BYTE UnreadConInputBuffer[128]; BYTE DosStack[384]; BYTE Sft[ANYSIZE_ARRAY]; } DOS_DATA, *PDOS_DATA; @@ -293,7 +294,6 @@ C_ASSERT(sizeof(BIOS_DATA) == 0x100); /* VARIABLES ******************************************************************/ -extern BOOLEAN DoEcho; // FIXME: Maybe move inside BiosData? (it's set by BIOS but used by CON driver in DOS BIOS) extern PBIOS_DATA BiosData; extern PDOS_DATA DosData; extern PDOS_SYSVARS SysVars; @@ -324,6 +324,9 @@ VOID DosPrintCharacter(WORD FileHandle, CHAR Character); BOOLEAN DosBIOSInitialize(VOID); +BOOLEAN DosControlBreak(VOID); +VOID DosEchoCharacter(CHAR Character); + /* * DOS Kernel Functions * See dos.c diff --git a/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.c b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.c index 07cce82558d..ddcc3ffdfad 100644 --- a/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.c +++ b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.c @@ -691,9 +691,154 @@ WORD DosReadFile(WORD FileHandle, PDOS_DEVICE_NODE Node = DosGetDriverNode(Descriptor->DevicePointer); if (!Node->ReadRoutine) return ERROR_INVALID_FUNCTION; - /* Read the device */ - Node->ReadRoutine(Node, Buffer, &Count); - *BytesRead = Count; + if (Descriptor->DeviceInfo & FILE_INFO_BINARY) + { + /* Read from the device directly */ + Node->ReadRoutine(Node, Buffer, &Count); + *BytesRead = Count; + } + else if (Descriptor->DeviceInfo & FILE_INFO_STDIN) + { + /* Line-buffered CON input */ + PCHAR ConBuffer = NULL; + PCHAR Pointer = FAR_POINTER(Buffer); + + /* Check if the buffer is empty */ + if (!SysVars->UnreadConInput) + { + ULONG LineSize = 0; + + SysVars->UnreadConInput = FIELD_OFFSET(DOS_DATA, UnreadConInputBuffer); + ConBuffer = (PCHAR)SEG_OFF_TO_PTR(DOS_DATA_SEGMENT, SysVars->UnreadConInput); + + while (TRUE) + { + USHORT Amount = 1; + CHAR Character; + + /* Read a character from the CON device */ + Node->ReadRoutine(Node, + MAKELONG(DOS_DATA_OFFSET(Sda.ByteBuffer), + DOS_DATA_SEGMENT), + &Amount); + if (Amount == 0) break; + + Character = Sda->ByteBuffer; + + if (LineSize == 127 && Character != '\r' && Character != '\b') + { + /* Line buffer full */ + // TODO: Should we beep? + continue; + } + + switch (Character) + { + /* Extended character */ + case '\0': + { + /* Read the scancode and discard it */ + Amount = 1; + Node->ReadRoutine(Node, + MAKELONG(DOS_DATA_OFFSET(Sda.ByteBuffer), + DOS_DATA_SEGMENT), + &Amount); + break; + } + + /* Ctrl-C */ + case 0x03: + { + DosEchoCharacter(Character); + + if (DosControlBreak()) + { + /* Set the character to CR to end the loop */ + Character = '\r'; + } + + break; + } + + case '\b': + { + if (LineSize > 0) + { + LineSize--; + if (ConBuffer[LineSize] == 0) LineSize--; + + DosEchoCharacter(Character); + } + + break; + } + + default: + { + /* Store the character in the buffer */ + ConBuffer[LineSize++] = Character; + DosEchoCharacter(Character); + } + } + + /* Stop on a carriage return */ + if (Character == '\r') break; + } + } + + *BytesRead = 0; + ConBuffer = (PCHAR)SEG_OFF_TO_PTR(DOS_DATA_SEGMENT, SysVars->UnreadConInput); + + while (*BytesRead < Count) + { + Pointer[(*BytesRead)++] = *ConBuffer; + + if (*ConBuffer == '\r') + { + /* A carriage return turns into a line feed */ + *ConBuffer = '\n'; + } + else if (*ConBuffer == '\n') + { + /* A line feed marks the true end of the line */ + SysVars->UnreadConInput = 0; + break; + } + else + { + /* Move to the next character */ + SysVars->UnreadConInput++; + ConBuffer++; + } + } + } + else + { + /* Translated input from a character device that isn't CON */ + PCHAR Pointer = FAR_POINTER(Buffer); + + while (*BytesRead < Count) + { + USHORT Amount = 1; + CHAR Character; + + /* Read a character from the device */ + Node->ReadRoutine(Node, + MAKELONG(DOS_DATA_OFFSET(Sda.ByteBuffer), + DOS_DATA_SEGMENT), + &Amount); + if (Amount == 0) break; + + Character = Sda->ByteBuffer; + // TODO: Process it somehow? + + /* Store the character in the output buffer */ + Pointer[(*BytesRead)++] = Character; + + /* Check for EOF */ + if (Character == 0x1A) break; + } + } } else { diff --git a/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.h b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.h index 1097eb6edbe..4d7a651fab6 100644 --- a/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.h +++ b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.h @@ -8,6 +8,9 @@ /* DEFINES ********************************************************************/ +#define FILE_INFO_STDIN (1 << 0) +#define FILE_INFO_STDOUT (1 << 1) +#define FILE_INFO_BINARY (1 << 5) #define FILE_INFO_DEVICE (1 << 7) #pragma pack(push, 1)