Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Intermediate command-line interfaces [closed]

Tags:

c

io

ncurses

I've been working with C for a while and am reasonably proficient at simple command-line interfaces. I've also had a play with the curses library, for terminal applications that do more than write text to stdout. However, I can't figure out where the half-way point is - applications like wget or make have, for example, the ability to update the text they have output (like wget's bouncing download meter and progress bar), without taking over the entire screen.

Is this sort of interface something I should be using curses for, or is there a step in between? Preferably one that is cross-platform.

like image 295
Daniel Buckmaster Avatar asked Oct 25 '11 22:10

Daniel Buckmaster


3 Answers

You can do some simple things by just printing backspace characters '\b' and raw carriage returns '\r' (without newlines). Backspaces move the cursor backwards one character, allowing you to overwrite your output, and carriage returns move the cursor back to the start of the current line, allowing you to overwrite the current line.

Here's a simple example of a progress bar:

int progress = 0;
while(progress < 100)
{
    // Note the carriage return at the start of the string and the lack of a
    // newline
    printf("\rProgress: %d%%", progress);
    fflush(stdout);

    // Do some work, and compute the new progress (0-100)
    progress = do_some_work();
}
printf("\nDone\n");

Note that you should only do this if you're writing to an actual terminal (as opposed to being redirected to a file or pipe). You can test for that with if(isatty(fileno(stdout)) { ... }. Of course, the same would be true if you were using any other library such as curses or ncurses.

like image 187
Adam Rosenfield Avatar answered Sep 17 '22 00:09

Adam Rosenfield


Between stdio and curses is the standard Unix/POSIX termios library. Trivial example program that turns character echoing off and reads a line (note, no error checking whatsoever):

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

void munch_line()
{
    int c;
    while ((c = getchar()) != EOF && c != '\n')
        ;
}

int main()
{
    int fd;
    struct termios tio;

    printf("Enter something: ");
    tcgetattr(fileno(stdin), &tio);
    tio.c_lflag &= ~ECHO;
    tcsetattr(fileno(stdin), TCSANOW, &tio);

    munch_line();
    putchar('\n');
}

Don't forget to turn echoing back on before exiting the program ;)

like image 32
Fred Foo Avatar answered Sep 17 '22 00:09

Fred Foo


If your terminal supports VT100 escape sequences, you can use them to move the cursor around:

printf("\x1b[%uD", n);  /* move cursor n steps to the left */
printf("\x1b[%uC", n);  /* move cursor n steps to the right */
printf("\x1b[K");       /* clear line from cursor to the right */
printf("\x1b[1K");      /* clear line from cursor to the left */
printf("\x1b[2K");      /* clear entire line */

A quick example (curtest.c):

#include <stdio.h>

int main(void)
{
    printf("ZZZZZZZZZZ");
    printf("\x1b[%dD", 10U);  /* move cursor 10 steps to the left */
    printf("YYYYYYYYY");
    printf("\x1b[%dD", 9U);   /* move cursor 9 steps to the left */
    printf("XXXXXXXX");
    printf("\x1b[%dD", 2U);   /* move cursor 2 steps to the left */
    printf("\x1b[1K");       /* clear line from cursor to the left */
    printf("\r\n");
    return 0;
}

If your terminal supports these escape codes, it should print

mizo@host:~/test> gcc curtest.c 
mizo@host:~/test> ./a.out
       XYZ
mizo@host:~/test>

The Windows command line does not have built-in VT100 support.

like image 37
makes Avatar answered Sep 17 '22 00:09

makes