From 154509038d7658595a4fff4d4b66f9bac4324f9c Mon Sep 17 00:00:00 2001 From: George Koehler Date: Fri, 4 May 2018 18:21:01 -0400 Subject: [PATCH] Enable the line editor in read() for CP/M. This changes the BDOS call from CPM_BDOS_CONSOLE_INPUT to CPN_BDOS_READ_CONSOLE_BUFFER. This allows commands like ^H to delete characters and ^C to exit to CCP. This is more like how Unix read(2) uses canonical mode of termios to read a line. This change has a disadvantage: the user buffer to read(2) must now be large enough for an entire line. This is because CP/M, unlike Unix, lacks a kernel buffer to hold the rest of the line. If you use a buffered input library like stdio to call read(2), then it works; but if you try to read part of a line or a single character, then it doesn't work. --- plat/cpm/libsys/read.c | 49 +++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/plat/cpm/libsys/read.c b/plat/cpm/libsys/read.c index 8a0ba0cb1..f81bda777 100644 --- a/plat/cpm/libsys/read.c +++ b/plat/cpm/libsys/read.c @@ -10,29 +10,44 @@ int read(int fd, void* buffer, size_t count) { - char i; - + short save; + unsigned char before_n; + /* We're only allowed to read from fd 0, 1 or 2. */ - if ((fd < 0) || (fd > 2)) { errno = EBADF; return -1; } - - /* Empty buffer? */ - - if (count == 0) - return 0; - - /* Read one byte. */ - - cpm_bc_register = CPM_BDOS_CONSOLE_INPUT; + + /* We need room for at least 1 char plus '\n'. */ + if (count < 2) + { + errno = EINVAL; + return -1; + } + + /* Make room to append '\n' later. */ + before_n = count > 255 ? 255 : count - 1; + + /* Borrow 2 bytes of RAM before the buffer. */ + /* This might overwrite count!!! */ + save = ((short*)buffer)[-1]; + + /* Read one line from the console. */ + ((unsigned char*)buffer)[-2] = before_n; + cpm_bc_register = CPM_BDOS_READ_CONSOLE_BUFFER; + cpm_de_register = (char*)buffer - 2; + cpm_bdos(); + before_n = ((unsigned char*)buffer)[-1]; + + ((char*)buffer)[before_n] = '\n'; /* Append '\n'. */ + ((short*)buffer)[-1] = save; /* Give back borrowed bytes. */ + + /* Echo '\n' to console. */ + cpm_bc_register = CPM_BDOS_PRINT_STRING; + cpm_de_register = "\r\n$"; cpm_bdos(); - if (cpm_a_register == '\r') - cpm_a_register = '\n'; - *(char*)buffer = cpm_a_register; - - return 1; + return (int)before_n + 1; }