From 17a8c92ba1cf40b7fb1244d80abff7ffee7539a8 Mon Sep 17 00:00:00 2001 From: Russell-S-Harper Date: Sun, 15 Jun 2025 13:32:25 -0400 Subject: [PATCH 1/4] Implement conio cgets --- include/conio.h | 18 +++++++ libsrc/conio/cgets.c | 117 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 libsrc/conio/cgets.c diff --git a/include/conio.h b/include/conio.h index cf84d1742..1bf994511 100644 --- a/include/conio.h +++ b/include/conio.h @@ -110,6 +110,24 @@ char cgetc (void); ** 1 (see below), a blinking cursor is displayed while waiting. */ +char *cgets (char *buffer); +/* Get a string of characters directly from the console. The standard interface +** is quirky: +** +** - set buffer[0] to the size of the buffer - 2, must be > 0 +** - call cgets +** - buffer[1] will have the number of characters read +** - the actual string starts at buffer + 2 +** - trailing CRLF are removed +** - terminating \0 is appended +** - therefore the maximum number of characters which can be read is the size +** of the buffer - 3! +** +** param: buffer - where to save the input +** return: buffer + 2 (i.e. start of the string) if successful, NULL otherwise +** author: Russell-S-Harper +*/ + int cscanf (const char* format, ...); /* Like scanf(), but uses direct keyboard input */ diff --git a/libsrc/conio/cgets.c b/libsrc/conio/cgets.c new file mode 100644 index 000000000..c0f7f8e0c --- /dev/null +++ b/libsrc/conio/cgets.c @@ -0,0 +1,117 @@ +/* Created: 2025-06-15 Russell-S-Harper +** Modified: +** Notes: +** +** char *cgets(char *buffer); +*/ + +#include +#include +#include + +#ifndef CRLF +#define CRLF "\r\n" +#endif /* CRLF */ + +enum {CGETS_SIZE, CGETS_READ, CGETS_DATA, CGETS_HDR_LEN = CGETS_DATA}; + +static char *cgetsx (char *buffer, int size); + +char *cgets (char *buffer) +/* Get a string of characters directly from the console. The standard interface +** is quirky: +** +** - set buffer[0] to the size of the buffer - 2, must be > 0 +** - call cgets +** - buffer[1] will have the number of characters read +** - the actual string starts at buffer + 2 +** - trailing CRLF are removed +** - terminating \0 is appended +** - therefore the maximum number of characters which can be read is the size +** of the buffer - 3! +** +** param: buffer - where to save the input +** return: buffer + 2 (or start of the string) if successful, NULL otherwise +** see: cgetsx for equivalent functionality but with a saner interface! +*/ +{ + /* Default to NULL */ + char *result = NULL; + + if (buffer && buffer[CGETS_SIZE]) { + /* Initialize just in case the caller didn't! */ + buffer[CGETS_READ] = 0; + buffer[CGETS_DATA] = '\0'; + + /* Call cgetsx to do the real work */ + result = cgetsx (buffer + CGETS_HDR_LEN, (unsigned char)buffer[CGETS_SIZE]); + + /* Trim trailing CRLF and set how many characters were read */ + if (result) { + result[strcspn (result, CRLF)] = '\0'; + buffer[CGETS_READ] = (unsigned char)strlen (result); + } + } + + /* Done */ + return result; +} + +static char *cgetsx (char *buffer, int size) +/* Like fgets but specifically for the console. Stops when CR/LF or size - 1 +** characters are read. Will append a terminating \0, so at most size - 1 +** characters can be read. Note that this function could be made public and +** have features like cursor vs no-cursor, and/or echo vs echo-pwd vs no-echo +** added to extend the functionality. +** +** param: buffer - where to save the input +** param: size - the size of buffer +** return: buffer if successful, NULL otherwise +*/ +{ + int i = 0; + unsigned char w, x, y; + char c; + + if (buffer && size > 1) { + /* Just need the width */ + screensize (&w, &y); + /* Actually just the last column! */ + --w; + cursor (1); + for (i = 0, --size; i < size; ) { + c = cgetc (); + /* Handle backspace */ + if (c == '\b') { + if (i > 0) { + /* Remove the character */ + buffer[--i] = '\0'; + /* Logic to account for line wrapping */ + y = wherey (); + x = wherex (); + y = x? y: y - 1; + x = x? x - 1: w; + /* Clear the character and the cursor */ + gotoxy (x, y); + cputs (" "); + gotoxy (x, y); + } + /* Handle CRLF */ + } else if (strchr (CRLF, c)) { + /* Clear the cursor and advance to the next line */ + cputs (" " CRLF); + buffer[i] = c; + buffer[++i] = '\0'; + break; + /* Handle regular characters */ + } else { + cputc (c); + buffer[i] = c; + buffer[++i] = '\0'; + } + } + cursor (0); + } + + return (i > 0)? buffer: NULL; +} From 00bb9d5376ad9dd37e6a0b4e0edd73525c549994 Mon Sep 17 00:00:00 2001 From: Russell-S-Harper Date: Fri, 20 Jun 2025 18:48:51 -0400 Subject: [PATCH 2/4] Edits to more closely match standard cgets --- include/conio.h | 3 ++- libsrc/conio/cgets.c | 52 +++++++++++++++++++------------------------- 2 files changed, 24 insertions(+), 31 deletions(-) diff --git a/include/conio.h b/include/conio.h index 1bf994511..1f88ac3ce 100644 --- a/include/conio.h +++ b/include/conio.h @@ -118,10 +118,11 @@ char *cgets (char *buffer); ** - call cgets ** - buffer[1] will have the number of characters read ** - the actual string starts at buffer + 2 -** - trailing CRLF are removed ** - terminating \0 is appended ** - therefore the maximum number of characters which can be read is the size ** of the buffer - 3! +** - note: CR/LF are NOT echoed, typically a following call to cputs or +** cprintf will need "\r\n" prepended - "standard" behavior ** ** param: buffer - where to save the input ** return: buffer + 2 (i.e. start of the string) if successful, NULL otherwise diff --git a/libsrc/conio/cgets.c b/libsrc/conio/cgets.c index c0f7f8e0c..bb24f97de 100644 --- a/libsrc/conio/cgets.c +++ b/libsrc/conio/cgets.c @@ -6,12 +6,9 @@ */ #include -#include #include - -#ifndef CRLF -#define CRLF "\r\n" -#endif /* CRLF */ +#include +#include enum {CGETS_SIZE, CGETS_READ, CGETS_DATA, CGETS_HDR_LEN = CGETS_DATA}; @@ -25,32 +22,29 @@ char *cgets (char *buffer) ** - call cgets ** - buffer[1] will have the number of characters read ** - the actual string starts at buffer + 2 -** - trailing CRLF are removed ** - terminating \0 is appended ** - therefore the maximum number of characters which can be read is the size ** of the buffer - 3! +** - note: CR/LF are NOT echoed, typically a following call to cputs or +** cprintf will need "\r\n" prepended - this is standard behavior! ** ** param: buffer - where to save the input -** return: buffer + 2 (or start of the string) if successful, NULL otherwise -** see: cgetsx for equivalent functionality but with a saner interface! +** return: buffer + 2 (i.e. start of the string) or NULL if buffer is NULL */ { - /* Default to NULL */ - char *result = NULL; + /* Return buffer + 2 or NULL if buffer is NULL */ + char *result = buffer? buffer + CGETS_HDR_LEN: NULL; - if (buffer && buffer[CGETS_SIZE]) { + if (result) { /* Initialize just in case the caller didn't! */ buffer[CGETS_READ] = 0; buffer[CGETS_DATA] = '\0'; - /* Call cgetsx to do the real work */ - result = cgetsx (buffer + CGETS_HDR_LEN, (unsigned char)buffer[CGETS_SIZE]); + /* Call cgetsx to do the real work, ignore the result! */ + cgetsx (result, (unsigned char)buffer[CGETS_SIZE]); - /* Trim trailing CRLF and set how many characters were read */ - if (result) { - result[strcspn (result, CRLF)] = '\0'; - buffer[CGETS_READ] = (unsigned char)strlen (result); - } + /* Set how many characters were read */ + buffer[CGETS_READ] = (unsigned char)strlen (result); } /* Done */ @@ -61,8 +55,8 @@ static char *cgetsx (char *buffer, int size) /* Like fgets but specifically for the console. Stops when CR/LF or size - 1 ** characters are read. Will append a terminating \0, so at most size - 1 ** characters can be read. Note that this function could be made public and -** have features like cursor vs no-cursor, and/or echo vs echo-pwd vs no-echo -** added to extend the functionality. +** have features added like cursor vs no-cursor, echo vs echo-pwd vs no-echo, +** or CR/LF handling to extend the functionality. ** ** param: buffer - where to save the input ** param: size - the size of buffer @@ -91,27 +85,25 @@ static char *cgetsx (char *buffer, int size) x = wherex (); y = x? y: y - 1; x = x? x - 1: w; - /* Clear the character and the cursor */ + /* Clear the character */ gotoxy (x, y); - cputs (" "); + cputc (' '); gotoxy (x, y); } - /* Handle CRLF */ - } else if (strchr (CRLF, c)) { - /* Clear the cursor and advance to the next line */ - cputs (" " CRLF); - buffer[i] = c; - buffer[++i] = '\0'; - break; /* Handle regular characters */ - } else { + } else if (isprint (c)) { cputc (c); buffer[i] = c; buffer[++i] = '\0'; + /* Handle CR/LF */ + } else if (c == '\r' || c == '\n') { + buffer[i] = '\0'; + break; } } cursor (0); } + /* Done */ return (i > 0)? buffer: NULL; } From 8bfaaa60baac9900b29035102428d1d8ed530357 Mon Sep 17 00:00:00 2001 From: Russell-S-Harper Date: Sat, 21 Jun 2025 06:01:13 -0400 Subject: [PATCH 3/4] Revising to align with stdio fgets --- include/conio.h | 26 +++++++-------- libsrc/conio/cgets.c | 77 +++++++++++++------------------------------- 2 files changed, 33 insertions(+), 70 deletions(-) diff --git a/include/conio.h b/include/conio.h index 1f88ac3ce..1bd59b052 100644 --- a/include/conio.h +++ b/include/conio.h @@ -110,22 +110,18 @@ char cgetc (void); ** 1 (see below), a blinking cursor is displayed while waiting. */ -char *cgets (char *buffer); -/* Get a string of characters directly from the console. The standard interface -** is quirky: +char* __fastcall__ cgets (char *buffer, int size); +/* Get a string of characters directly from the console. The function returns +** when size - 1 characters or either CR/LF are read. Note the parameters are +** more aligned with stdio fgets() as opposed to the quirky "standard" conio +** cgets(). Besides providing saner parameters, the function also echoes CRLF +** when either CR/LF are read but does NOT append either in the buffer. This is +** to correspond to stdio fgets() which echoes CRLF, but prevents a "gotcha" +** where the buffer might not be able to accommodate both CR and LF at the end. ** -** - set buffer[0] to the size of the buffer - 2, must be > 0 -** - call cgets -** - buffer[1] will have the number of characters read -** - the actual string starts at buffer + 2 -** - terminating \0 is appended -** - therefore the maximum number of characters which can be read is the size -** of the buffer - 3! -** - note: CR/LF are NOT echoed, typically a following call to cputs or -** cprintf will need "\r\n" prepended - "standard" behavior -** -** param: buffer - where to save the input -** return: buffer + 2 (i.e. start of the string) if successful, NULL otherwise +** param: buffer - where to save the input, must be non-NULL +** param: size - size of the buffer, must be > 1 +** return: buffer if successful, NULL on error ** author: Russell-S-Harper */ diff --git a/libsrc/conio/cgets.c b/libsrc/conio/cgets.c index bb24f97de..52e2da343 100644 --- a/libsrc/conio/cgets.c +++ b/libsrc/conio/cgets.c @@ -2,7 +2,7 @@ ** Modified: ** Notes: ** -** char *cgets(char *buffer); +** char* __fastcall__ cgets (char *buffer, int size); */ #include @@ -10,57 +10,22 @@ #include #include -enum {CGETS_SIZE, CGETS_READ, CGETS_DATA, CGETS_HDR_LEN = CGETS_DATA}; +#ifndef CRLF +#define CRLF "\r\n" +#endif /* CRLF */ -static char *cgetsx (char *buffer, int size); - -char *cgets (char *buffer) -/* Get a string of characters directly from the console. The standard interface -** is quirky: +char* __fastcall__ cgets (char *buffer, int size) +/* Get a string of characters directly from the console. The function returns +** when size - 1 characters or either CR/LF are read. Note the parameters are +** more aligned with stdio fgets() as opposed to the quirky "standard" conio +** cgets(). Besides providing saner parameters, the function also echoes CRLF +** when either CR/LF are read but does NOT append either in the buffer. This is +** to correspond to stdio fgets() which echoes CRLF, but prevents a "gotcha" +** where the buffer might not be able to accommodate both CR and LF at the end. ** -** - set buffer[0] to the size of the buffer - 2, must be > 0 -** - call cgets -** - buffer[1] will have the number of characters read -** - the actual string starts at buffer + 2 -** - terminating \0 is appended -** - therefore the maximum number of characters which can be read is the size -** of the buffer - 3! -** - note: CR/LF are NOT echoed, typically a following call to cputs or -** cprintf will need "\r\n" prepended - this is standard behavior! -** -** param: buffer - where to save the input -** return: buffer + 2 (i.e. start of the string) or NULL if buffer is NULL -*/ -{ - /* Return buffer + 2 or NULL if buffer is NULL */ - char *result = buffer? buffer + CGETS_HDR_LEN: NULL; - - if (result) { - /* Initialize just in case the caller didn't! */ - buffer[CGETS_READ] = 0; - buffer[CGETS_DATA] = '\0'; - - /* Call cgetsx to do the real work, ignore the result! */ - cgetsx (result, (unsigned char)buffer[CGETS_SIZE]); - - /* Set how many characters were read */ - buffer[CGETS_READ] = (unsigned char)strlen (result); - } - - /* Done */ - return result; -} - -static char *cgetsx (char *buffer, int size) -/* Like fgets but specifically for the console. Stops when CR/LF or size - 1 -** characters are read. Will append a terminating \0, so at most size - 1 -** characters can be read. Note that this function could be made public and -** have features added like cursor vs no-cursor, echo vs echo-pwd vs no-echo, -** or CR/LF handling to extend the functionality. -** -** param: buffer - where to save the input -** param: size - the size of buffer -** return: buffer if successful, NULL otherwise +** param: buffer - where to save the input, must be non-NULL +** param: size - size of the buffer, must be > 1 +** return: buffer if successful, NULL on error */ { int i = 0; @@ -73,8 +38,14 @@ static char *cgetsx (char *buffer, int size) /* Actually just the last column! */ --w; cursor (1); - for (i = 0, --size; i < size; ) { + for (buffer[i] = '\0', --size; i < size; ) { c = cgetc (); + /* Handle CR/LF */ + if (strchr (CRLF, c)) { + /* Echo CRLF, but don't append either CR/LF */ + cputs (CRLF); + break; + } /* Handle backspace */ if (c == '\b') { if (i > 0) { @@ -95,10 +66,6 @@ static char *cgetsx (char *buffer, int size) cputc (c); buffer[i] = c; buffer[++i] = '\0'; - /* Handle CR/LF */ - } else if (c == '\r' || c == '\n') { - buffer[i] = '\0'; - break; } } cursor (0); From 7f40affb59acefe4d8a9c8cb6a85868602c5ac90 Mon Sep 17 00:00:00 2001 From: Russell-S-Harper Date: Sat, 21 Jun 2025 08:48:41 -0400 Subject: [PATCH 4/4] Adding documentation and some minor reformatting to ensure consistency --- doc/funcref.sgml | 39 +++++++++++++++++++++++++++++++++++++++ include/conio.h | 2 +- libsrc/conio/cgets.c | 4 ++-- 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/doc/funcref.sgml b/doc/funcref.sgml index 5eab5adcd..7e632f71f 100644 --- a/doc/funcref.sgml +++ b/doc/funcref.sgml @@ -289,6 +289,7 @@ function. + @@ -2715,6 +2716,44 @@ see anything that you type. (See the description of +cgets