Question for GNU Readline expert (or at least smarter than me!)

Go To Last Post
3 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi all,

 

I have an ANSI Basic compiler that I compile from source. The original source was written by Michael Haardt (LINK). One huge shortcoming was that it had a rudimentary input handler, so typing code or editing it was a nightmare. I replaced the input code with the GUN readline library and it works absolutely wonderfully. Lines can be edited, recalled, everything. If you've used BASH, you know how great readline is.

Anyway, since the BASIC interpreter code opens up the terminal channel with ECHO turned off (for a good reason), to use readline I have to set the terminal to "standard mode", then get an input line, then reset it to "basic mode", then copy the buffer that readline got into basic's buffer. Here's a snippet of that code:

if (f->tty) {
    tcsetattr (f->infd, TCSADRAIN, &origMode); // set normal mode
}

FS_rlBuf = readline (""); // user input into rl buffer

if (f->tty) {
    tcsetattr (f->infd, TCSADRAIN, &rawMode); // go back to echo off mode
}

Now, all this works fine, except for one problem: It seems that readline doesn't know where IT'S column 1 is on stdout and hitting extra backspace keys causes existing characters to be deleted.

For example, if I have this line in BASIC:

 

10 input "Please enter a number: ";c

...and I type "333", the characters show up on the screen properly, like this (imagine the program is running):

 

Please enter a number: 333

 

Now imagine I actually wanted to type "23", so I would hit backspace 3 times, then type "2", "3". However, the final backspace which should remove the first "3" in "333" does remove it, but it also removes the whole line, like this:

 

>Ok run

Please enter a number: 333 (now, press backspace once)

Please enter a number: 33 (press backspace again)

Please enter a number: 3 (press backspace once more)

[line is blank]

(now, enter "2", "3" as was desired)

23 (now press enter)

23 (program was set to print the value of "c" upon getting a value)

>Ok

 

Note that the input statement does not re-print the prompt... I just show it like that for clarity.

 

The problem is that readline doesn't seem to know it's at the beginning of it's buffer position and continues to echo backspace chars even when there's nothing to delete. I've gone through the readline docs and can't seem to find any way to fix this. I had an idea that I could somehow "hook" into readline and examine, character by character vs buffer position and stop echoing characters when the buffer beginning it reached. I know that readline seems to know when to stop internally (if I hit a lot of backspaces, then type some valid digits, they are properly sent to the readline buffer).

 

Any ideas how to fix this problem will be appreciated, and if any more info is needed to understand the problem, please ask.

 

Thanks!

 

This topic has a solution.

Gentlemen may prefer Blondes, but Real Men prefer Redheads!

Last Edited: Sun. Jan 10, 2021 - 04:22 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've used readline() before.   My guess is that when you get to the beginning of the line and hit backspace it's returning to beginning of line and then re-issuing a prompt, which in your case is "". 

Is it possible to pass the prompt to readline as in readline("Please input a number: ")?

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 2

MattRW wrote:

I've used readline() before.   My guess is that when you get to the beginning of the line and hit backspace it's returning to beginning of line and then re-issuing a prompt, which in your case is "". 

Is it possible to pass the prompt to readline as in readline("Please input a number: ")?

 

I can't set a prompt because various functions generate different prompts. However, I was searching online again today and searched for "prevent gnu readline from backspacing beyond 0". Google said "It looks like there aren't many great matches for your search". So I deleted "prevent" and tried "gnu readline from backspacing beyond 0". Ah HA! I found a thread about someone else having the same exact problem (message) and saw that this is only a problem if the readline prompt is null. Ah, so close. But, unfortunately, the way the BASIC code is designed, there is no easy way to dynamically send different prompt strings to readline (and indeed, sometimes those could be blank, causing the same problem!).

 

I think readline does indeed try to reprint it's "prompt" when the beginning of the line is reached, but it should only print "nothing" (i.e. "") rather than erasing the entire line. It's a bug in readine, I think. Readline seems to NEED a prompt to work right.

 

Anyway, then the little halogen bulb in my head lit up. I don't want and don't need readline to print any prompt, but really this means I only don't need to SEE a prompt. So, I did this:

 

buffer = readline("\x20\x08"); <-- The Solution

 

The "prompt" is now space, backspace. Readline now knows where it's boundaries are and the problem is solved! Hurrah!

 

Anyway, it was your post that got my mind pointed in the right direction, so I send a huge THANK YOU out to you!

 

Gentlemen may prefer Blondes, but Real Men prefer Redheads!

Last Edited: Sun. Jan 10, 2021 - 04:30 PM