0

I have saved the history of the previous commands in a two-dimensional array. But I don't know how to check the up arrow.

How to use the C programming language implementing this feature (in Linux)?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • @n.m. only if you're ok with being GPL licensed, of course. – aruisdante Mar 03 '15 at 07:38
  • Termios lib can halp you (http://linux.die.net/man/3/termios). I insert example of usage in the answer below. – VolAnd Mar 03 '15 at 07:43
  • 1
    @aruisdante there is a bsd-licensed alternative called editline, but yes, i do expect people to be ok with gpl unless they specifically mention something else. they came here for free advice after all. – n. m. could be an AI Mar 03 '15 at 09:23

2 Answers2

2

Thanks to n.m. for good advice.

The following is the example of usage libreadline:

// rltest.c
#include <stdio.h>
#include <stdlib.h>
#include <readline.h>
#include <history.h>

int main(void)
{
    char* input, shell_prompt[100];
    // Configure readline to auto-complete paths when the tab key is hit.
    rl_bind_key('\t', rl_complete);
    // while work is not 0 program executes the loop
    int work = 1;
    printf("Commands to use: name, ver, exit \n");
    // loop for working with commands
    while(work) {
        // Build prompt string.
        snprintf(shell_prompt, sizeof(shell_prompt), "your command $ ");
        // Display prompt and read input
        input = readline(shell_prompt);
        // Check for EOF.
        if (!input)
            break;
        // Add input to history.
        add_history(input);
        // Command analysis and execution
        if( 0 == strcmp(input, "exit") )
        {
            printf("Bye!\n");
            work = 0;
        }
        if( 0 == strcmp(input, "name") )
        {
            printf("I'm readline example\n");
        }
        if( 0 == strcmp(input, "ver") )
        {
            printf("My version is 0.1\n");
        }
        // ...
        // Free input for future use
        free(input);
    }
    return 0;
}

to compile this example:

1) install readline library

 apt-get install libreadline-dev

2) compile program as

 gcc rltest.c -I/usr/include/readline -lreadline
VolAnd
  • 6,367
  • 3
  • 25
  • 43
0

Try the following example:

#include <stdio.h>
#include <termios.h>

// constants for sizes
#define LINES 5
#define MAX_LEN 50

// this is just for demonstration
// read more about screen cleaning http://www.cplusplus.com/articles/4z18T05o/
void ClearScreen()
{
    printf("\033[2J");
    printf("\033[0;0f");
}

// function based on termios library
// see more at http://stackoverflow.com/questions/7469139/what-is-equivalent-to-getch-getche-in-linux

static struct termios old, new;

/* Initialize new terminal i/o settings */
void initTermios(int echo)
{
  tcgetattr(0, &old); /* grab old terminal i/o settings */
  new = old; /* make new settings same as old settings */
  new.c_lflag &= ~ICANON; /* disable buffered i/o */
  new.c_lflag &= echo ? ECHO : ~ECHO; /* set echo mode */
  tcsetattr(0, TCSANOW, &new); /* use these new terminal i/o settings now */
}

/* Restore old terminal i/o settings */
void resetTermios(void)
{
  tcsetattr(0, TCSANOW, &old);
}

/* Read 1 character - echo defines echo mode */
char getch_(int echo)
{
  char ch;
  initTermios(echo);
  ch = getchar();
  resetTermios();
  return ch;
}

int main(void)
{
    char strBuff[LINES][MAX_LEN] = {"The first line",
            "This is the longest line in this buffer",
            "Just a middle line",
            "Short",
            "The last line"};
    char ch; // one character input buffer
    int cnt = 0; // number of current line to be shown
    // loop for showing lines
    ClearScreen();
    do{
        // show current line
        printf("%s", strBuff[cnt]); 
        // read input (arrows. characters, etc.
        ch = getch_(0);
        // arrows detection in input
        if(ch == 27)
        {
            ch = getch_(0);
            if( ch == 91)
            {
                ch = getch_(0);
                if(ch == 66)  // up arrow
                {
                    cnt++;
                    if(cnt >= LINES)
                        cnt = 0;
                }
                else
                    if(ch == 65)  // down arrow
                    {
                        cnt--;
                        if(cnt < 0)
                            cnt = LINES-1;
                    }
            }
        }
        // cleaning screen before next output
        ClearScreen();

    }while(ch != 'q'); // press 'q' for exit
}
VolAnd
  • 6,367
  • 3
  • 25
  • 43
  • Isn't the point of a terminal abstraction library to do away with all the hard-coded escape sequences to clear screens etc.? – Jens Mar 03 '15 at 08:06
  • Screen clearing is OS depended in any case, but conditional compilation can help in making cross-platform solution. I actually do not know such libraries. – VolAnd Mar 03 '15 at 08:27
  • Bad advice. This won't work with all terminals. Read about `terminfo` and `ncurses`. – n. m. could be an AI Mar 03 '15 at 09:25
  • For instance, I just got a bug report from someone who has to deal with 8-bit CSI (155) rather than 7-bit (27, 91). Also, even for ANSI sequences, this does not deal with non-application mode SS3 (27, 79). It is better to move that out of the hard-coded realm. – Thomas Dickey Mar 03 '15 at 09:32
  • @n.m. : It is not "Bad advice."... it is just advice with comments and references. I do not insist on such solution, and anyone can suggest other ideas and examples. – VolAnd Mar 03 '15 at 10:05
  • It is bad advice. Comments and references don't make it any better. No one should actually do what you propose in any actual code. It is just wrong. – n. m. could be an AI Mar 03 '15 at 10:29
  • I mean, it is not wrong to show and discuss code like this, but not as a practical solution for a real-life problem. It could serve as an illustration of how a real terminal library like `ncurses` could work. But in a real program one should just use `ncurses` – n. m. could be an AI Mar 03 '15 at 10:44
  • @n.m. I perviously tried to use nurses library but I never successed. So, I have many troubles about that like that initscr() will make no commands appearing on my screen even I inputting later. Could you tell me how to use ncurses to fulfill history capture up arrow? – Yiyang Zhao Mar 03 '15 at 16:02
  • For your purpose don't use ncurses directly. Use readline (it's based on ncurses internally). It does exactly what you need. – n. m. could be an AI Mar 03 '15 at 17:02
  • @n.m Thank you very much. I know I should use readline now but the core problem is how to check the up or down arrow. I mean how to make the program know when I input the up or down arrow? – Yiyang Zhao Mar 03 '15 at 17:47
  • You don't need to check anything. Use readline for input. It already processes arrows correctly as expected. – n. m. could be an AI Mar 03 '15 at 17:57
  • @n.m Thanks, one more question, how to compile it? I read from Wikipedia that the code compiled with a -lreadline compiler flag, but actually when I compile it "cannot find -lreadline" appearing on my screen? (without -lreadline also error). Lack head file or what? I use gcc to compile. how to solve this? – Yiyang Zhao Mar 03 '15 at 18:43
  • You need to install libreadline development package. Use your package manager to find libreadline-dev, readline-devel, or similar. – n. m. could be an AI Mar 03 '15 at 18:49