Thread: Pre-Populating Input Prompt Using Libedit

  1. #1
    Registered User
    Join Date
    Jun 2008
    Posts
    93

    Pre-Populating Input Prompt Using Libedit

    I am currently using libedit in a custom shell I am designing. Is there a way to use libedit to pre-populate the user input at the prompt? For example, i am using:

    el_set(el, EL_PROMPT, ntp_prompt);
    and
    el_gets(el, input_len);

    to generate something like:

    [Prompt]:

    but what I am looking for is something like:

    [Prompt]: 2

    as opposed to the user having to enter the 2 themselves. I am doing this because I would like parameters that have already been set by the shell/user to be pre-populated the next time the visit the prompt without any interaction on their part.

    If libedit doesn't have this capability, are there any other ways of doing this?

    Would it be possible to use history() to add the pre-populated data to the next history item and then pre-populate the prompt using history?
    Last edited by fguy817817; 07-28-2011 at 10:10 AM.

  2. #2
    Registered User
    Join Date
    Oct 2008
    Location
    TX
    Posts
    2,059
    There's some material on this site that maybe of help.

  3. #3
    Registered User
    Join Date
    Jun 2008
    Posts
    93
    I actually read this page previously. Unfortunately, they only go over the very basics of using libedit to create a prompt and accept input.

  4. #4
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    I don't really know anything about libedit, including where to find good docs. You can check your system for man pages (man libedit_function_name). If it's allowed for your project, look into using GLib. They have an automatic string completion component: Automatic String Completion, and lots of other useful stuff like ADTs, config file parsing, etc. If nothing else, it's open source, so you can peruse the string completion code to see how it works so you can implement your own version. It's not a terribly complicated thing to implement, but tried and true, existing functionality is usually preferred in software development.

  5. #5
    Registered User
    Join Date
    Jun 2008
    Posts
    93
    I have never used glib before. I wasn't aware that its functionality was that extensive. This will be a good reference in the future for me. I am going to look at the code for the string completion stuff now.

    It was probably a bad idea to use libedit in my example. I will make this much less intricate.

    Suppose I was only going to use scanf() or fgets(). Would there be any way possible to insert text at the prompt prior to a user entering data? I suppose the answer to this may also be buried in the glib code for the string completion because it probably uses the same technique to autocomplete at a prompt that I would need.

  6. #6
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    If you're designing the shell as you say, then I guess that means you're in control of the keyboard buffer? (As in, you're receiving raw keystrokes?) If so, then just stick the material in the front of the keyboard buffer.

    If you're using scanf/fgets, then there is such a thing as ungetc(), but you should check your man pages on its limits (e.g., the system doesn't have to let you put more than one character back in the keyboard buffer, as I recall).

  7. #7
    Registered User
    Join Date
    Jun 2008
    Posts
    93
    I'm not receiving the raw keystrokes. Currently I have written my own version of scanf() that uses fgets() to accept keyboard input. I have never used the keyboard buffer before. Considering the number of shells that contain an autocomplete feature, I was thinking there was a standard way of doing this type of manipulation.

  8. #8
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    A big problem you'll have (which tabstop hinted at) is the line buffering of stdin. Nothing gets transmitted to your program until the user presses enter, thus scanf wont be able to pick up partial lines to be completed until the user hits enter, e.g. "cd foo<tab>" wont get transmitted for your programs auto-complete code unless you set up your terminal to send/receive raw keystrokes. Try "man termios" for starters.

  9. #9
    Registered User
    Join Date
    Jun 2008
    Posts
    93
    I have seen some mention of using ioctl() and TIOCSTI to simulate keyboard stokes to TTY. However, as you mentioned, scanf is a blocking call. Would I have to do this on a separate thread?

  10. #10
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by fguy817817 View Post
    I'm not receiving the raw keystrokes. Currently I have written my own version of scanf() that uses fgets() to accept keyboard input. I have never used the keyboard buffer before. Considering the number of shells that contain an autocomplete feature, I was thinking there was a standard way of doing this type of manipulation.
    I don't know what the shells are using, but I imagine at the least they have to change the buffering of stdin. One thing to be aware of with my previous suggestion:
    Code:
    tabstop@ubuntu:~/helping$ cat chars.c
    #include <stdio.h>
    #include <stdlib.h>
    
    int main(void) {
    
        printf("Prompt: ");
        ungetc('2', stdin);
        ungetc('1', stdin);
        char answer[80];
        fgets(answer, sizeof(answer), stdin);
        printf("%s\n", answer);
        return 0;
    }
    
    tabstop@ubuntu:~/helping$ ./chars
    Prompt: 3
    123

  11. #11
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    No, you don't need a new thread. Changing the terminal settings should allow raw input. You should probably read that into a buffer, because there may be control characters that will cause problems with scanf. When you get a special character (say <tab> for completion), look at your buffer and decide what to do. E.g. if your buffer contains "cd foo", and you receive <tab>, you need to get a list of all the directories in the current directory, and see which ones start with foo. If there's only 1, complete it. If there's more than 1, either give a list of them all, or cycle through them. Note that the completion code itself is not complicated (some simple string prefix matching and maybe getting a list of commands, files or directories), but the unbuffered IO you need can be a real pain.

    EDIT: To clarify, a new thread wont fix your problem. It will simply allow you to collect line buffered input and do other stuff in the mean time, instead of having a scanf call that blocks the rest of your program waiting for a new line, it will only block your input thread. But that input thread wont see anything until it gets the newline, so it cant put anything in your program's input buffer for the other thread to process.
    Last edited by anduril462; 07-28-2011 at 12:36 PM.

  12. #12
    Registered User
    Join Date
    Jun 2008
    Posts
    93
    I tried a sample and ran into the same problem

  13. #13
    Registered User
    Join Date
    Jun 2008
    Posts
    93
    Quote Originally Posted by anduril462 View Post
    No, you don't need a new thread. Changing the terminal settings should allow raw input. You should probably read that into a buffer, because there may be control characters that will cause problems with scanf. When you get a special character (say <tab> for completion), look at your buffer and decide what to do. E.g. if your buffer contains "cd foo", and you receive <tab>, you need to get a list of all the directories in the current directory, and see which ones start with foo. If there's only 1, complete it. If there's more than 1, either give a list of them all, or cycle through them. Note that the completion code itself is not complicated (some simple string prefix matching and maybe getting a list of commands, files or directories), but the unbuffered IO you need can be a real pain.

    EDIT: To clarify, a new thread wont fix your problem. It will simply allow you to collect line buffered input and do other stuff in the mean time, instead of having a scanf call that blocks the rest of your program waiting for a new line, it will only block your input thread. But that input thread wont see anything until it gets the newline, so it cant put anything in your program's input buffer for the other thread to process.
    Ok so let me try to step through this. I need to:

    1. Call togetattr() to retrieve the current terminal settings
    2. Modify the settings returned by togetattr() to allow raw input
    3. Call tosetattr() to apply the new settings
    4. Write my desired text to the terminal (where the user will be entering their text)
    5. Revert back to the original terminal settings
    6. Use fgets to parse the user input

    The user doesnt need the capability to autocomplete. I just need to prepopulate the input field with data they used when entering a response previously so they can just press enter to continue without having to enter the same informatoin over and over again each time they are prompted with the same question. I used automcomplete as an example because it seems as though it would require similar capabilities. My case is much less complex.

  14. #14
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    Steps 1-3 and 5 seem fine. You'll want to leave the terminal in raw mode the whole time though. I think step 4 is worded poorly. Basically, step 4 should be your actual shell code running. It should print a prompt, take user input, handling any tab completion (or whatever completion char you pick), change directories, executing commands, etc. You are done with step 4 when the user exits your shell.

    As for step 6, fgets wont parse the user input. You will be using getchar or the like to read each char individually. You will more likely store those in a buffer, and when you hit a special char like <tab> or <enter>, instead of storing it in the buffer, you will handle it specially. Really, this belongs in your shell, as part of step 4.

  15. #15
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    Doh! I totally misread your post. Don't know what I was thinking. Maybe I should step out for a bit.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Populating 2-D arrays
    By fgg in forum C Programming
    Replies: 4
    Last Post: 10-13-2010, 12:39 PM
  2. command prompt input, write into file
    By angela in forum C Programming
    Replies: 3
    Last Post: 03-17-2010, 09:00 AM
  3. populating 2-D array
    By edster in forum C Programming
    Replies: 4
    Last Post: 10-22-2009, 02:42 PM
  4. Program hangs up at first input prompt.
    By MikeR in forum C Programming
    Replies: 3
    Last Post: 10-14-2007, 07:45 PM
  5. Replies: 5
    Last Post: 05-06-2004, 09:14 AM