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/…
==============================================================================
--- 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/…
==============================================================================
--- 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/…
==============================================================================
--- 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/…
==============================================================================
--- 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/…
==============================================================================
--- 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/…
==============================================================================
--- 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)