From a13c318d4baed5abdf4e46311e504c9be4f7f20b Mon Sep 17 00:00:00 2001 From: Steve Kemp Date: Thu, 20 Jun 2024 21:04:30 +0300 Subject: [PATCH 1/3] Ctrl-C only works at the start of a line --- consolein/consolein.go | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/consolein/consolein.go b/consolein/consolein.go index e75fe60..53f5b28 100644 --- a/consolein/consolein.go +++ b/consolein/consolein.go @@ -276,12 +276,17 @@ func (ci *ConsoleIn) ReadLine(max uint8) (string, error) { // Ctrl-C ? // if x == 0x03 { - ctrlCount += 1 - // If we've hit our limit of consecutive Ctrl-Cs - // then we return the interrupted error-code - if ctrlCount == ci.InterruptCount { - return "", ErrInterrupted + // Ctrl-C should only take effect at the start of the line. + // i.e. When the text is empty. + if text == "" { + ctrlCount += 1 + + // If we've hit our limit of consecutive Ctrl-Cs + // then we return the interrupted error-code + if ctrlCount == ci.InterruptCount { + return "", ErrInterrupted + } } continue } From 19c37d4d15e56db666e510b82ee3798f5b357485 Mon Sep 17 00:00:00 2001 From: Steve Kemp Date: Thu, 20 Jun 2024 21:07:13 +0300 Subject: [PATCH 2/3] If the user fills the buffer, return. --- consolein/consolein.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/consolein/consolein.go b/consolein/consolein.go index 53f5b28..0ca52ab 100644 --- a/consolein/consolein.go +++ b/consolein/consolein.go @@ -219,7 +219,7 @@ func (ci *ConsoleIn) ReadLine(max uint8) (string, error) { return "", err } - // Esc + // Esc? if x == 27 { // remove the character from our text, and overwrite on the console for len(text) > 0 { @@ -232,7 +232,7 @@ func (ci *ConsoleIn) ReadLine(max uint8) (string, error) { continue } - // Ctrl-N + // Ctrl-N? if x == 14 { if offset >= 1 { @@ -253,7 +253,7 @@ func (ci *ConsoleIn) ReadLine(max uint8) (string, error) { continue } - // Ctrl-P ? + // Ctrl-P? if x == 16 { if offset >= len(ci.history) { continue @@ -274,7 +274,6 @@ func (ci *ConsoleIn) ReadLine(max uint8) (string, error) { } // Ctrl-C ? - // if x == 0x03 { // Ctrl-C should only take effect at the start of the line. @@ -302,7 +301,7 @@ func (ci *ConsoleIn) ReadLine(max uint8) (string, error) { if len(ci.history) == 0 { ci.history = append(ci.history, text) } else { - // otherwise only add if different to previous entry + // otherwise only add if different to previous entry. if text != ci.history[len(ci.history)-1] { ci.history = append(ci.history, text) } @@ -325,12 +324,13 @@ func (ci *ConsoleIn) ReadLine(max uint8) (string, error) { continue } - // If the user has entered the maximum then we'll - // avoid further input + // If the user has entered the maximum then we'll say their + // input-time is over now. if len(text) >= int(max) { - continue + break } - // Otherwise if it was a printable character we'll keep it. + + // Finally if it was a printable character we'll keep it. if unicode.IsPrint(rune(x)) { fmt.Printf("%c", x) text += string(x) From 7686b78c11a29e30952c733c0a10d75dbc5c71ee Mon Sep 17 00:00:00 2001 From: Steve Kemp Date: Thu, 20 Jun 2024 22:13:22 +0300 Subject: [PATCH 3/3] Use a better way of keeping track of file-handles We used to assume that the address of the FCB entry which was used for opening a file would be used for later read/write operations, so we could cache our file-handles keyed on that address. I've just noticed that multi-file projects in turbo-pascal jump around with their FCB addresses. So on open/make file requests we store the original FCB address in FCB.AL[0,1] - which will be stable across operations, even if the FCB is in a different address. I guess we could use file-no instead, but for the moment this seems simple. If N files are opened from the same FCB address we'll be in trouble, but we'll cross that bridge later. This closes #127. --- cpm/cpm_bdos.go | 43 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/cpm/cpm_bdos.go b/cpm/cpm_bdos.go index 04c26aa..2b5adea 100644 --- a/cpm/cpm_bdos.go +++ b/cpm/cpm_bdos.go @@ -424,6 +424,10 @@ func BdosSysCallFileOpen(cpm *CPM) error { fcbPtr.RC = fLen } + // Write our cache-key in the FCB + fcbPtr.Al[0] = uint8(ptr & 0xFF) + fcbPtr.Al[1] = uint8(ptr >> 8) + // Update the FCB in memory. cpm.Memory.SetRange(ptr, fcbPtr.AsBytes()...) @@ -483,6 +487,10 @@ func BdosSysCallFileOpen(cpm *CPM) error { slog.Int("record_count", int(fcbPtr.RC)), slog.Int64("file_size", fileSize)) + // Write our cache-key in the FCB + fcbPtr.Al[0] = uint8(ptr & 0xFF) + fcbPtr.Al[1] = uint8(uint16(ptr >> 8)) + // Update the FCB in memory. cpm.Memory.SetRange(ptr, fcbPtr.AsBytes()...) @@ -509,8 +517,11 @@ func BdosSysCallFileClose(cpm *CPM) error { // Create a structure with the contents fcbPtr := fcb.FromBytes(xxx) + // Get our cache-key from the FCB + key := uint16(uint16(fcbPtr.Al[1])<<8 + uint16(fcbPtr.Al[0])) + // Get the file handle from our cache. - obj, ok := cpm.files[ptr] + obj, ok := cpm.files[key] if !ok { cpm.Logger.Debug("SysCallFileClose tried to close a file that wasn't open", slog.Int("fcb", int(ptr))) @@ -554,10 +565,12 @@ func BdosSysCallFileClose(cpm *CPM) error { } // delete the entry from the cache. - delete(cpm.files, ptr) + delete(cpm.files, key) // Update the FCB in RAM - // cpm.Memory.SetRange(ptr, fcbPtr.AsBytes()...) + fcbPtr.Al[0] = 0x00 + fcbPtr.Al[1] = 0x00 + cpm.Memory.SetRange(ptr, fcbPtr.AsBytes()...) // Record success cpm.CPU.States.AF.Hi = 0x00 @@ -787,8 +800,11 @@ func BdosSysCallRead(cpm *CPM) error { // Create a structure with the contents fcbPtr := fcb.FromBytes(xxx) + // Get our cache-key from the FCB + key := uint16(uint16(fcbPtr.Al[1])<<8 + uint16(fcbPtr.Al[0])) + // Get the file handle in our cache. - obj, ok := cpm.files[ptr] + obj, ok := cpm.files[key] if !ok { cpm.Logger.Error("SysCallRead: Attempting to read from a file that isn't open") cpm.CPU.States.AF.Hi = 0xFF @@ -893,8 +909,11 @@ func BdosSysCallWrite(cpm *CPM) error { // Create a structure with the contents fcbPtr := fcb.FromBytes(xxx) + // Get our cache-key from the FCB + key := uint16(uint16(fcbPtr.Al[1])<<8 + uint16(fcbPtr.Al[0])) + // Get the file handle in our cache. - obj, ok := cpm.files[ptr] + obj, ok := cpm.files[key] if !ok { cpm.Logger.Error("SysCallWrite: Attempting to write to a file that isn't open") cpm.CPU.States.AF.Hi = 0xFF @@ -1023,6 +1042,10 @@ func BdosSysCallMakeFile(cpm *CPM) error { fcbPtr.RC = fLen } + // Write our cache-key in the FCB + fcbPtr.Al[0] = uint8(ptr & 0xFF) + fcbPtr.Al[1] = uint8(ptr >> 8) + // Save the file-handle cpm.files[ptr] = FileCache{name: fileName, handle: file} @@ -1269,8 +1292,11 @@ func BdosSysCallReadRand(cpm *CPM) error { // Create a structure with the contents fcbPtr := fcb.FromBytes(xxx) + // Get our cache-key from the FCB + key := uint16(uint16(fcbPtr.Al[1])<<8 + uint16(fcbPtr.Al[0])) + // Get the file handle in our cache. - obj, ok := cpm.files[ptr] + obj, ok := cpm.files[key] if !ok { cpm.Logger.Error("SysCallReadRand: Attempting to read from a file that isn't open") cpm.CPU.States.AF.Hi = 0xFF @@ -1319,8 +1345,11 @@ func BdosSysCallWriteRand(cpm *CPM) error { // Create a structure with the contents fcbPtr := fcb.FromBytes(xxx) + // Get our cache-key from the FCB + key := uint16(uint16(fcbPtr.Al[1])<<8 + uint16(fcbPtr.Al[0])) + // Get the file handle in our cache. - obj, ok := cpm.files[ptr] + obj, ok := cpm.files[key] if !ok { cpm.Logger.Error("SysCallWriteRand: Attempting to write to a file that isn't open") cpm.CPU.States.AF.Hi = 0xFF