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)
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);
return FALSE;
}
-/* PUBLIC FUNCTIONS ***********************************************************/
-
VOID WINAPI DosInt20h(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;
/* 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
{
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;
/* 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;
}
DPRINT("DosReadFile(0x%04X)\n", getBX());
- DoEcho = TRUE;
ErrorCode = DosReadFile(getBX(),
MAKELONG(getDX(), getDS()),
getCX(),
&BytesRead);
- DoEcho = FALSE;
if (ErrorCode == ERROR_SUCCESS)
{
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
{