10000 Implement conio cgets by Russell-S-Harper · Pull Request #2705 · cc65/cc65 · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Implement conio cgets #2705

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 23, 2025
Merged

Implement conio cgets #2705

merged 4 commits into from
Jun 23, 2025

Conversation

Russell-S-Harper
Copy link
Contributor

The function cgets reads a string directly from the console. Uses cgetc to retrieve character input, and other conio functions to handle multiline input and backspace. Like other conio functions it does not scroll the screen or check for writing out of bounds.

Tested okay on CX16 emulator. It doesn't use any "tricks", other than when processing backspaces it outputs an extra blank just to make sure any cursor remnants aren't left behind*, so should be reasonably compatible with other platforms.

* reason is CX16 does have cursor but doesn't seem to honor the setting 100%!

@mrdudz
Copy link
Contributor
mrdudz commented Jun 18, 2025

Have you tested this on some other target(s)?

Also, please add the function in the documentation

That said, without testing, the function feels "too simple" to me - it should perhaps filter more (all?) "non printable" codes - else you get surprises on some targets, like eg when pressing the cursor keys on a C64

@mrdudz
Copy link
Contributor
mrdudz commented Jun 18, 2025

BTW

when processing backspaces it outputs an extra blank just to make sure any cursor remnants aren't left behind*, so should be reasonably compatible with other platforms.

that should not be necessary, cgetc() should disable the cursor when needed, there shouldn't be any need to clean up behind it. To move the cursor left, without messing up anything else on the screen, a "backspace" should probably be converted into something like "cursor left, space, cursor left" - that would clean up the last character of course, not the cursor itself (perhaps that is what you mean?)

@mrdudz
Copy link
Contributor
mrdudz commented Jun 18, 2025

Another thing.... i see some magic with CRLF - imho this shouldnt be required, cgetc() should always provide "\n" on "enter" (ie CH_ENTER)

@Russell-S-Harper
Copy link
Contributor Author
Russell-S-Harper commented Jun 18, 2025

That said, without testing, the function feels "too simple" to me - it should perhaps filter more (all?) "non printable" codes - else you get surprises on some targets, like eg when pressing the cursor keys on a C64

Can use ctype isprint, that's similar to what some earlier versions use e.g. TurboC.

@Russell-S-Harper
Copy link
Contributor Author
Russell-S-Harper commented Jun 18, 2025

BTW

when processing backspaces it outputs an extra blank just to make sure any cursor remnants aren't left behind*, so should be reasonably compatible with other platforms.

that should not be necessary, cgetc() should disable the cursor when needed, there shouldn't be any need to clean up behind it. To move the cursor left, without messing up anything else on the screen, a "backspace" should probably be converted into something like "cursor left, space, cursor left" - that would clean up the last character of course, not the cursor itself (perhaps that is what you mean?)

Yes, I mean the cursor itself. It "should" clear the cursor automatically prior to any conio goto calls but in CX16 it doesn't, e.g. see screenshot below with cursor remnants left after backspacing. This is with deliberate cursor (0) calls prior to backspacing, tried many other approaches without success.

image

The version without cursor clearing does work in C64. I don't have hardware or an original ROM for Apple][ so I can't test there.

The options are:

  • release without cursor clearing, confirmed okay for C64, confirmed not working 100% for CX16, unknown for Apple][
  • release with cursor clearing, confirmed okay for C64 and CX16, unknown for Apple][
  • don't release until issue with CX16 is resolved

In all cases, file a bug report in CX16: "conio goto functions not hiding cursor."

@mrdudz
Copy link
Contributor
mrdudz commented Jun 18, 2025

The options are:

  • release without cursor clearing, confirmed okay for C64, confirmed not working 100% for CX16, unknown for Apple][
  • release with cursor clearing, confirmed okay for C64 and CX16, unknown for Apple][
  • don't release until issue with CX16 is resolved

In all cases, file a bug report in CX16: "conio goto functions not hiding cursor."

Please don't "fix" it in cgets - it only hides an error that is elsewhere, and adds unnecessary side effects to the function itself for all targets. So please make sure the function is clean and works on a different target (c64,apple2,atari800 should be all mature enough for testing) and if it does, go ahead and try fixing the actual problem in the cx16 library :)

@Russell-S-Harper
Copy link
Contributor Author

Another thing.... i see some magic with CRLF - imho this shouldnt be required, cgetc() should always provide "\n" on "enter" (ie CH_ENTER)

In various sources, they use \r, \r or \n, or \r and \n.

Given that Ctrl-M for \r can be entered directly in Apple][ and other platforms, recommend keeping CRLF to cover all cases. We need CRLF to output a new line to console anyway.

@mrdudz
Copy link
Contributor
mrdudz commented Jun 19, 2025

We need CRLF to output a new line to console anyway.

well, not really (using conio anyway)

BUT that raises another question: do either '\n' or '\r' get added into the resulting string? IMHO - no :)

include/conio.h Outdated
** - terminating \0 is appended
** - therefore the maximum number of characters which can be read is the size
** of the buffer - 3!
**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see this just now... where does this "standard interface" come from? regular gets() doesn't work that way at least?

For conio, why not implement something like

// b points to buffer
// len is max len of the buffer (including the terminating 0)
// if len is 0, then len is not checked (to behave like sgets()
char *sgetsn(char *b, int len)
{
  ...
}

and then on top of that something like

char *cgets(char *b)
{
   return cgetsn(b, 0);
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "standard" interface I used is what I found online, some examples:

https://doxygen.reactos.org/df/db9/cgets_8c_source.html
https://www.pcjs.org/documents/books/mspl13/c/clibref/
https://github.com/gandrewstone/GameMaker/blob/master/tools/BORLANDC/CRTL/CLIB/CGETS.C
https://fossies.org/linux/TurboC/cgets.c
https://code-reference.com/c/conio.h/cgets
https://learn.microsoft.com/en-us/cpp/c-runtime-library/cgets-cgetws?view=msvc-170
https://www.ijaeast.com/C%20Logic%20Programming.pdf

The code layout you're suggesting with oddball cgets calling a saner version is what I'm implementing. I'm calling it cgetsx, +x for eXtra. If it's okay can make it public, too, at some later date, but would like to add cursor on/off, various echo settings, and CR/LF options, all would be specified as bit flags in a single unsigned char or int.

It turns out the cgets in the first draft is still too advanced; had to dumb it down even more; committed my latest. Currently trying to find Apple ][ and Atari 800 targets to test on. Works in C64 and handles multiple lines which I think is something not doable using fgets in that platform.

image

As mentioned before, half works in CX16, but leaves cursor remnants when backspacing.

@mrdudz
Copy link
Contributor
mrdudz commented Jun 20, 2025

If it's okay can make it public, too, at some later date, but would like to add cursor on/off, various echo settings, and CR/LF options, all would be specified as bit flags in a single unsigned char or int.

don't overdo it - cgets should be just that, like gets but use the conio layer. If you want to do a more advanced general input function, i suggest doing that seperately.

That said, passing parameters in the first two bytes of the buffer is just such a weird hack... please don't :) I would have never expected this in the borland api either... wth

@Russell-S-Harper
Copy link
Contributor Author

Agreed, I felt dirty writing it. But if it's not a "compliant" cgets, will there be complaints from users? I could implement cgets_s (s for "Safe") like in https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/cgets-s-cgetws-s?view=msvc-170 which uses a saner interface, and I think behaves more logically, echoing CRLF and returning error codes.

@mrdudz
Copy link
Contributor
mrdudz commented Jun 21, 2025

Agreed, I felt dirty writing it. But if it's not a "compliant" cgets, will there be complaints from users?

well, honest, conio is only losely based on the borland api. I would be very surprised if cgets() did work differentl to gets()

@Russell-S-Harper
Copy link
Contributor Author

If we're okay diverging from "standard" conio cgets, I've revised to align with the safer stdio fgets. Latest code committed. It's getting kind of messy so can rebase if needed.

@Russell-S-Harper
Copy link
Contributor Author

I wasn't able to find a documentation verification utility for SGML so hoping it's okay. Remaining is testing in Apple ][ and Atari 800 targets, in progress.

@mrdudz
Copy link
Contributor
mrdudz commented Jun 23, 2025

looks ok to me now... one thing though: is that specific handling of wraparound at the end of a line really needed? I'd think that it is not shrug

@Russell-S-Harper
Copy link
Contributor Author

It would be great if I could just use cputs("\b \b"); to backspace but unfortunately \b is not interpreted in conio as a control character in C64, and likely other platforms as well. For C64 it outputs t for \b:

image

I also tried "\e\b \e\b" in the hopes that it might interpret the backspace character differently. No luck, \e is interpreted as [:

image

Also can't do gotox(wherex() - 1); because the argument is unsigned char and -1 is interpreted as 255.

In summary, I think the line wrapping logic is required, and it's actually done more cleanly than some other implementations I've seen (excluding those where "\b \b" works).

@mrdudz
Copy link
Contributor
mrdudz commented Jun 23, 2025

You are right... if course it doesnt work. I was too much thinking in terms of stdio.

Guess i can merge then, thanks!

@mrdudz mrdudz merged commit 4863a3e into cc65:master Jun 23, 2025
2 checks passed
@Russell-S-Harper
Copy link
Contributor Author

Thank you. Much appreciated.

@Russell-S-Harper Russell-S-Harper deleted the add-conio-cgets branch June 23, 2025 14:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants
0