4

I'm writing a linux shell for a custom scripting language, and I want to print a "... " before each follow-up line a user enters for a single statement, with the first line having a ">>> " printed, then waiting for input. Following is an example:

>>> void f() {
...  "this is a test"
... }
>>> 

I'm reading the line with fgets, and after I read it completely, I print the "... ", and repeat using another call to fgets. This works fine for moderately fast interactive input. But if I paste code containing newlines into the terminal, what I get is the following

>>> void f() {
 "this is a test"
}
... ... >>> 

The "... "'es are printed too late, even though I emit a fflush call after I print them to stdout. Does anyone know whether there is anything special to do to make this work?

3
  • I suspect you need terminal control for that, not just streams. You're trying to interfere with the terminal's own process of echoing keypresses - generally characters appear on screen "when they're typed", not "when the program is ready to read them", and it looks as though paste is dumping a lot of characters at once. You need to be able to disable echoing for e.g. password input, so the facility is there in e.g. ncurses. Commented Mar 17, 2011 at 23:22
  • @Steve ah i see now. I will want to disable echo and then just printf the text I read? That sounds good. Commented Mar 17, 2011 at 23:25
  • Yes, either printf it, or once you've started with ncurses you can use other ncurses stuff to place the text. Commented Mar 17, 2011 at 23:27

2 Answers 2

1

If you turn off echo (see stty(1) -echo) for the terminal, then you are in complete control over when the input is printed to the screen.

My assumption is the paste is causing all lines to be written to the terminal at once, and your program will never get an opportunity to send output to the terminal when necessary. So, if you turn off echo and print the user's input as they enter it, you can perform your special handling when you see the newline chars.

You can see that the irb program does something very similar by running strace on it:

ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
...
ioctl(0, SNDCTL_TMR_STOP or TCSETSW, {B38400 opost isig -icanon -echo ...}) = 0
Sign up to request clarification or add additional context in comments.

Comments

0

There's not really a simple way to do it using stdio -- you'll need to use something like ncurses to control the terminal. The issue is that when you copy and paste multiple lines like that, they all get pulled into stdin's read buffer in a single call to read(2), so stdout has no chance to intervene and print the intervening prompts.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.