Author: aandrejevic Date: Fri Sep 25 22:00:57 2015 New Revision: 69356
URL: http://svn.reactos.org/svn/reactos?rev=69356&view=rev Log: [NTVDM] Fix DOS character device I/O. Implement CON line buffering. Make sure INT 21h functions 01h, 06h, 07h, 08h, 0Ah and 3Fh work as expected for CON input.
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/bios.c trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/condrv.c trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.c trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.h trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.c trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.h
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/bios.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/d... ============================================================================== --- trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/bios.c [iso-8859-1] (original) +++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/bios.c [iso-8859-1] Fri Sep 25 22:00:57 2015 @@ -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 @@ 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 @@ 1, &BytesRead);
+ /* Restore the old mode and return the character */ + if (Descriptor) Descriptor->DeviceInfo = OldDeviceInfo; return Sda->ByteBuffer; }
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/condrv.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/d... ============================================================================== --- trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/condrv.c [iso-8859-1] (original) +++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/condrv.c [iso-8859-1] Fri Sep 25 22:00:57 2015 @@ -63,15 +63,8 @@
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;
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/d... ============================================================================== --- trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.c [iso-8859-1] (original) +++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.c [iso-8859-1] Fri Sep 25 22:00:57 2015 @@ -44,9 +44,6 @@ /* Easy accessors to useful DOS data area parts */ PDOS_SYSVARS SysVars; PDOS_SDA Sda; - -/* Echo state for INT 21h, AH = 01h and AH = 3Fh */ -BOOLEAN DoEcho = FALSE;
/* PRIVATE FUNCTIONS **********************************************************/
@@ -162,7 +159,54 @@ 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);
@@ -177,8 +221,6 @@
return FALSE; } - -/* PUBLIC FUNCTIONS ***********************************************************/
VOID WINAPI DosInt20h(LPWORD Stack) { @@ -217,14 +259,9 @@ { 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 @@ /* 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 @@ break; }
+ /* 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 0x07: 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 @@ /* 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"); - - 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; - + if (InputBuffer->MaxLength == 0) break; + + /* 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 @@
DPRINT("DosReadFile(0x%04X)\n", getBX());
- DoEcho = TRUE; ErrorCode = DosReadFile(getBX(), MAKELONG(getDX(), getDS()), getCX(), &BytesRead); - DoEcho = FALSE;
if (ErrorCode == ERROR_SUCCESS) {
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/d... ============================================================================== --- trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.h [iso-8859-1] (original) +++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.h [iso-8859-1] Fri Sep 25 22:00:57 2015 @@ -246,6 +246,7 @@ 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 @@
/* 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 @@
BOOLEAN DosBIOSInitialize(VOID);
+BOOLEAN DosControlBreak(VOID); +VOID DosEchoCharacter(CHAR Character); + /* * DOS Kernel Functions * See dos.c
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/d... ============================================================================== --- trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.c [iso-8859-1] (original) +++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.c [iso-8859-1] Fri Sep 25 22:00:57 2015 @@ -691,9 +691,154 @@ 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 {
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/d... ============================================================================== --- trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.h [iso-8859-1] (original) +++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.h [iso-8859-1] Fri Sep 25 22:00:57 2015 @@ -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)