views:

298

answers:

1

I have stdin in a select() set and I want to take a string from stdin whenever the user types it and hits ENTER.

But select is triggering stdin as ready to read before ENTER is hit, and, in rare cases, before anything is typed at all. This hangs my program on getstr() until I hit ENTER.

I tried setting nocbreak() and it's perfect really except that nothing gets echoed to the screen so I can't see what I'm typing. And setting echo() doesn't change that.

I also tried using timeout(0), but the results of that was even crazier and didn't work.

A: 

What you need to do is tho check if a character is available with the getch() function. If you use it in no-delay mode the method will not block. Then you need to eat up the characters until you encounter a '\n', appending each char to the resulting string as you go.

Alternatively - and the method I use - is to use the GNU readline library. It has support for non-blocking behavior, but documentation about that section is not so excellent.

Included here is a small example that you can use. It has a select loop, and uses the GNU readline library:

#include <stdio.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <stdlib.h>
#include <stdbool.h>

int quit = false;

void rl_cb(char* line)
{
    if (NULL==line) {
        quit = true;
        return;
    }

    if(strlen(line) > 0) add_history(line);

    printf("You typed:\n%s\n", line);
    free(line);
}

int main()
{
    struct timeval to;
    const char *prompt = "# ";

    rl_callback_handler_install(prompt, (rl_vcpfunc_t*) &rl_cb);

    to.tv_sec = 0;
    to.tv_usec = 10000;

    while(1){
        if (quit) break;
        select(1, NULL, NULL, NULL, &to);
        rl_callback_read_char();
    };
    rl_callback_handler_remove();

    return 0;
}

Compile with:

gcc -Wall rl.c -lreadline
Johan
Thanks.I tried using the readline solution, it looks nice, but it still doesn't echo properly when using curses at the same time. They probably aren't mean to be used together.I decided to just use getch() and maintain an internal buffer of the line. It's surprisingly easy.
graw