diff --git a/MBBSEmu.Tests/ExportedModules/Majorbbs/cncall_Tests.cs b/MBBSEmu.Tests/ExportedModules/Majorbbs/cncall_Tests.cs index 2d20052f..84dbea51 100644 --- a/MBBSEmu.Tests/ExportedModules/Majorbbs/cncall_Tests.cs +++ b/MBBSEmu.Tests/ExportedModules/Majorbbs/cncall_Tests.cs @@ -21,7 +21,7 @@ public void cncall_Test(string inputString, ushort nxtcmdStartingOffset, string Reset(); //Set Input Values - var inputLength = (ushort)inputString.Length; + var inputLength = (ushort) (inputString.Length - 1); mbbsModule.Memory.SetArray("INPUT", Encoding.ASCII.GetBytes(inputString)); mbbsModule.Memory.SetWord("INPLEN", inputLength); diff --git a/MBBSEmu.Tests/ExportedModules/Majorbbs/endcnc_Tests.cs b/MBBSEmu.Tests/ExportedModules/Majorbbs/endcnc_Tests.cs index 6a1ae198..0d89e81c 100644 --- a/MBBSEmu.Tests/ExportedModules/Majorbbs/endcnc_Tests.cs +++ b/MBBSEmu.Tests/ExportedModules/Majorbbs/endcnc_Tests.cs @@ -9,14 +9,13 @@ public class endcnc_Tests : ExportedModuleTestBase { private const int ENDCNC_ORDINAL = 191; - [Theory] - //Simple commands with nxtcmd == input + [Theory] [InlineData("123 ABC\0", 1, 0, "23\0ABC\0", 2)] [InlineData("123 ABC\0", 3, 0, "ABC\0", 1)] [InlineData("123 ABC\0", 4, 0, "ABC\0", 1)] [InlineData("123 ABC\0", 5, 0, "BC\0", 1)] - [InlineData("\0", 0, 1, "", 0)] + [InlineData("\0", 0, 1, "\0", 0)] public void endcnc_Test(string inputString, ushort nxtcmdStartingOffset, char expectedResult, string expectedInputString, ushort expectedMargc) { //Reset State @@ -26,7 +25,7 @@ public void endcnc_Test(string inputString, ushort nxtcmdStartingOffset, char ex var inputLength = (ushort)inputString.Length; mbbsModule.Memory.SetArray("INPUT", Encoding.ASCII.GetBytes(inputString)); - mbbsModule.Memory.SetWord("INPLEN", inputLength); + mbbsModule.Memory.SetWord("INPLEN", (ushort) (inputLength - 1)); //Set nxtcmd var currentNxtcmd = mbbsEmuMemoryCore.GetPointer("NXTCMD"); @@ -38,7 +37,7 @@ public void endcnc_Test(string inputString, ushort nxtcmdStartingOffset, char ex //Gather Results var actualResult = mbbsEmuCpuCore.Registers.AX; - var actualInputString = Encoding.ASCII.GetString(mbbsEmuMemoryCore.GetArray("INPUT", mbbsEmuMemoryCore.GetWord("INPLEN"))); + var actualInputString = Encoding.ASCII.GetString(mbbsEmuMemoryCore.GetArray("INPUT", (ushort) (mbbsEmuMemoryCore.GetWord("INPLEN") + 1))); var actualMargc = mbbsEmuMemoryCore.GetWord("MARGC"); //Verify Results Assert.Equal(expectedInputString, actualInputString); diff --git a/MBBSEmu.Tests/ExportedModules/Majorbbs/rstrin_Tests.cs b/MBBSEmu.Tests/ExportedModules/Majorbbs/rstrin_Tests.cs index 91db7091..089d5553 100644 --- a/MBBSEmu.Tests/ExportedModules/Majorbbs/rstrin_Tests.cs +++ b/MBBSEmu.Tests/ExportedModules/Majorbbs/rstrin_Tests.cs @@ -24,7 +24,7 @@ public void rstrin_Test(string inputCommand) //Set Input Values mbbsEmuMemoryCore.SetArray("INPUT", Encoding.ASCII.GetBytes(inputCommand)); - mbbsEmuMemoryCore.SetWord("INPLEN", (ushort)inputCommand.Length); + mbbsEmuMemoryCore.SetWord("INPLEN", (ushort) (inputCommand.Length - 1)); ExecuteApiTest(HostProcess.ExportedModules.Majorbbs.Segment, RSTRIN_ORDINAL, new List()); diff --git a/MBBSEmu/HostProcess/ExportedModules/Majorbbs.cs b/MBBSEmu/HostProcess/ExportedModules/Majorbbs.cs index 7adccb5f..17b29ac4 100644 --- a/MBBSEmu/HostProcess/ExportedModules/Majorbbs.cs +++ b/MBBSEmu/HostProcess/ExportedModules/Majorbbs.cs @@ -370,10 +370,10 @@ public void ProcessChannelInput(ushort channelNumber) var inputPointer = Module.Memory.GetVariablePointer("INPUT"); Module.Memory.SetZero(inputPointer, 0xFF); var inputFromChannel = ChannelDictionary[channelNumber].InputCommand; - var inputLength = (ushort)ChannelDictionary[ChannelNumber].InputCommand.Length; + var inputLength = (ushort)(ChannelDictionary[ChannelNumber].InputCommand.Length - 1); Module.Memory.SetArray(inputPointer, inputFromChannel); Module.Memory.SetByte(inputPointer + inputFromChannel.Length, 0); - Module.Memory.SetWord("INPLEN", inputLength); + inputLength = setINPLEN(inputPointer); ChannelDictionary[channelNumber].UsrPtr.Flags = 0; @@ -381,9 +381,8 @@ public void ProcessChannelInput(ushort channelNumber) //Set Concex flag on 0 input //TODO -- Need to verify this is correct - if (Module.Memory.GetWord("INPLEN") == 0) + if (inputLength == 0) ChannelDictionary[channelNumber].UsrPtr.Flags |= (uint)EnumRuntimeFlags.Concex; - } /// @@ -3717,7 +3716,7 @@ private void rstrin() if (inputLength == 0) return; - for (var i = inputPointer.Offset; i < inputPointer.Offset + (inputLength - 1); i++) + for (var i = inputPointer.Offset; i < inputPointer.Offset + inputLength; i++) { if (Module.Memory.GetByte(inputPointer.Segment, i) == 0) Module.Memory.SetByte(inputPointer.Segment, i, (byte)' '); @@ -4289,9 +4288,10 @@ private void parsin() margvPointer.Offset += FarPtr.Size; } - Module.Memory.SetWord("INPLEN", (ushort)parsedInput.Length); + Module.Memory.SetArray("INPUT", Encoding.ASCII.GetBytes(parsedInput)); Module.Memory.SetWord("MARGC", margCount); + //setINPLEN(); } /// @@ -5577,7 +5577,7 @@ private void endcnc() var nxtcmdPointer = Module.Memory.GetPointer("NXTCMD"); var inputLength = Module.Memory.GetWord("INPLEN"); - var remainingCharactersInCommand = inputLength - (nxtcmdPointer.Offset - inputPointer.Offset); + var remainingCharactersInCommand = inputLength - (nxtcmdPointer.Offset - inputPointer.Offset) + 1; //Check to see if nxtcmd is on a space, if so, increment it by 1 if (Module.Memory.GetByte(nxtcmdPointer) == 0x20) @@ -5595,7 +5595,7 @@ private void endcnc() //Get Remaining Characters & Save to Input var remainingInput = Module.Memory.GetArray(nxtcmdPointer, (ushort)(remainingCharactersInCommand)); Module.Memory.SetArray(inputPointer, remainingInput); - Module.Memory.SetWord("INPLEN", (ushort)remainingCharactersInCommand); + setINPLEN(inputPointer); Module.Memory.SetPointer("NXTCMD", inputPointer); parsin(); @@ -5647,7 +5647,7 @@ private void cncall() Registers.SetPointer(nxtcmdPointer); //Set NXTCMD to the end of the INPUT - var newNxtcmd = new FarPtr(inputPointer.Segment, (ushort)(inputPointer.Offset + inputLength - 1)); + var newNxtcmd = new FarPtr(inputPointer.Segment, (ushort)(inputPointer.Offset + inputLength)); Module.Memory.SetPointer("NXTCMD", newNxtcmd); } @@ -8243,5 +8243,25 @@ private void cncuid() //Sets DX:AX registers to the return value Registers.SetPointer(returnPointer); } + + /// + /// Sets the INPLEN variable based on the length of INPUT + /// + /// The value written to INPLEN + private ushort setINPLEN() => setINPLEN(Module.Memory.GetVariablePointer("INPUT")); + + /// + /// Sets the INPLEN variable based on the length of the string from input + /// + /// Null-terminated string pointer + /// The value written to INPLEN + private ushort setINPLEN(FarPtr input) + { + var sz = (ushort) Module.Memory.GetString(input, true).Length; + + Module.Memory.SetWord("INPLEN", sz); + + return sz; + } } } diff --git a/MBBSEmu/HostProcess/MbbsHost.cs b/MBBSEmu/HostProcess/MbbsHost.cs index 67c3ba41..d7a34fee 100644 --- a/MBBSEmu/HostProcess/MbbsHost.cs +++ b/MBBSEmu/HostProcess/MbbsHost.cs @@ -356,11 +356,9 @@ private void WorkerThread() //If the channel has been registered with BEGIN_POLLING if (session.PollingRoutine != null) { + session.Status.Enqueue(EnumUserStatus.POLLING_STATUS); ProcessPollingRoutine(session); - - //Keep the user in Polling Status if the polling routine is still there - if (session.PollingRoutine != FarPtr.Empty) - session.Status.Enqueue(EnumUserStatus.POLLING_STATUS); + session.Status.Dequeue(); } break; @@ -852,7 +850,7 @@ private void ProcessIncomingCharacter(SessionBase session) } //Enter or Return - case 0xD when !session.TransparentMode && (session.SessionState != EnumSessionState.InFullScreenDisplay && session.SessionState != EnumSessionState.InFullScreenEditor): + case 0xD when (session.SessionState != EnumSessionState.InFullScreenDisplay && session.SessionState != EnumSessionState.InFullScreenEditor): { //If we're in transparent mode or BTUCHI has changed the character to null, don't echo if (!session.TransparentMode && session.CharacterProcessed > 0) @@ -861,6 +859,13 @@ private void ProcessIncomingCharacter(SessionBase session) //If BTUCHI Injected a deferred Execution Status, respect that vs. processing the input if (session.GetStatus() == EnumUserStatus.CYCLE) { + //If we're cycling, ignore \r for triggering STTROU and add it to the input buffer for STSROU to handle + if (session.TransparentMode) + { + session.InputBuffer.WriteByte(session.CharacterProcessed); + break; + } + //Set Status == 3, which means there is a Command Ready session.Status.Clear(); //Clear the 240 session.Status.Enqueue(EnumUserStatus.CR_TERMINATED_STRING_AVAILABLE); //Enqueue Status of 3 @@ -870,6 +875,7 @@ private void ProcessIncomingCharacter(SessionBase session) //Always Enqueue Input Ready session.Status.Enqueue(EnumUserStatus.CR_TERMINATED_STRING_AVAILABLE); + break; } diff --git a/MBBSEmu/Session/LineBreaker.cs b/MBBSEmu/Session/LineBreaker.cs index 3a003e96..d9172306 100644 --- a/MBBSEmu/Session/LineBreaker.cs +++ b/MBBSEmu/Session/LineBreaker.cs @@ -5,6 +5,8 @@ namespace MBBSEmu.Session { public class LineBreaker { + public const byte BACKSPACE = 8; + public const byte DELETE = 127; public const byte ESCAPE = 0x1B; public const int MAX_LINE = 512; public const int MAX_OUTPUT_BUFFER = 4096; @@ -124,8 +126,12 @@ public void SendBreakingIntoLines(byte[] buffer) case ESCAPE: // escape _parseState = ParseState.ESCAPE; break; + case DELETE: // ignore case (byte) '\n': // ignore break; + case BACKSPACE: + _lineBufferLength = Math.Max(0, _lineBufferLength - 1); + break; default: _lineBuffer[_lineBufferLength] = b; _lineBufferToRawBuffer[_lineBufferLength++] = _rawBufferLength - 1;