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.
This commit is contained in:
George Koehler 2018-05-04 18:21:01 -04:00
parent b4be612832
commit 154509038d

View file

@ -10,29 +10,44 @@
int read(int fd, void* buffer, size_t count) 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. */ /* We're only allowed to read from fd 0, 1 or 2. */
if ((fd < 0) || (fd > 2)) if ((fd < 0) || (fd > 2))
{ {
errno = EBADF; errno = EBADF;
return -1; return -1;
} }
/* Empty buffer? */ /* We need room for at least 1 char plus '\n'. */
if (count < 2)
if (count == 0) {
return 0; errno = EINVAL;
return -1;
/* Read one byte. */ }
cpm_bc_register = CPM_BDOS_CONSOLE_INPUT; /* 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(); cpm_bdos();
if (cpm_a_register == '\r') return (int)before_n + 1;
cpm_a_register = '\n';
*(char*)buffer = cpm_a_register;
return 1;
} }