erasing terminal output on linux - c

I was writing a command line program which will have a status bar, much like wget.
The main problem I'm facing is: how do I delete what I've already sent into stdout/stderr?
I had on idea: use the backspace char '\b' and erase the output I've sent. Is that the best way? Is it the only way? Is there a better way?
PS: I don't want to use anything like ncurses. Plain old C please.
Thanks
EDIT:
Can I also go up and/or down? Example: I have 10 lines of output, I want to change the 3rd line from Doing ABC to ABC: Done. How can I do that?
Also, can anyone post more details about what VT102 characters are? What are its capabilities? Please post good links on this if you have any.
Thanks

The basic formatting control characters are backspace (\b), tab (\t), newline (\n), and carriage return (\r). If you need more than that then you can use ANSI X3.64 / ISO/IEC 6429 / ECMA-48 escape sequences; at least the VT100 subset is recognized by most modern terminals and emulators. An advantage of using ncurses is that it will look up the capabilities of your particular terminal and so it will work even if your terminal uses a different set of escape sequences.

You have to remember that as far as the regular stdio routines are concerned, stdout is just a byte stream with no inherent display characteristics; that depends on the target device, which can be anything from a regular VT100-style terminal to a hardcopy terminal to a sheet-fed printer to a plotter to whatever.
IMO, you're far better off using a library like ncurses than trying to hack together your own display management code with VT100 escape codes, even for a relatively simple task like this. I know you want to stick with "plain old C", but this is a task that falls outside the bounds of plain old C.

Use '\r' to return to the beginning of the line and possibly rewrite the whole line.
Look for VT102 control sequences - these are character sequences ESC ... to control your terminal.

There is also the possiblity of using Ncurses, which is a library for Textual UI, where this kind of behaviour should have some support. However, it may be overkill for something like this.

A slight variation on your own solution:
You can also print a carriage return (\r), which will return you to the start of the line.

It is a progressbar for bash.
function gauge()
{
progress="$1"
total="$2"
width=`tput cols`
let gwidth=width-7
if [ "$total" == "0" ]; then
percent=100
else
set +e
let percent=progress*100/total;
set -e
fi
set +e
let fillcount=percent*gwidth/100
let nofillcount=gwidth-fillcount
set -e
fill="";
if [ "$fillcount" -gt "0" ]; then
for i in `seq $fillcount`; do
fill="$fill""|"
done
fi;
nofill=""
if [ "$nofillcount" -gt "0" ]; then
for i in `seq $nofillcount`; do
nofill="$nofill"" ";
done
fi
echo -e -n "\r[""$fill""$nofill""] ""$percent""%";
}

About the progress bar: something like this?
#include <stdio.h>
#include <unistd.h>
typedef enum
{
false=0,
true=!false
} bool;
typedef struct
{
/* Start delimiter (e.g. [ )*/
char StartDelimiter;
/* End Delimiter (e.g. ] )*/
char EndDelimiter;
/* Central block (e.g. = )*/
char Block;
/* Last block (e.g. > ) */
char CurBlock;
/* Width of the progress bar (in characters) */
unsigned int Width;
/* Maximum value of the progress bar */
double Max;
/* True if we have to print also the percentage of the operation */
bool PrintPercentage;
/* True if the bar must be redrawn;
note that this must be just set to false before the first call, the function then will change it by itself. */
bool Update;
} ProgressBarSettings;
/* Prints/updates the progress bar */
void PrintProgressBar(double Pos, ProgressBarSettings * Settings);
/* Inits the settings of the progress bar to the default values */
void DefaultProgressBar(ProgressBarSettings * Settings);
int main()
{
int i;
/* Init the bar settings */
ProgressBarSettings pbs;
DefaultProgressBar(&pbs);
pbs.Max=200;
pbs.Width=60;
printf("Progress: ");
/* Show the empty bar */
PrintProgressBar(0,&pbs);
for(i=0;i<=pbs.Max;i++)
{
/* Wait 50 msec */
usleep(50000);
/* Update the progress bar */
PrintProgressBar(i,&pbs);
}
puts(" Done");
return 0;
}
/* Inits the settings of the progress bar to the default values */
void DefaultProgressBar(ProgressBarSettings * Settings)
{
Settings->StartDelimiter='[';
Settings->EndDelimiter=']';
Settings->Block='=';
Settings->CurBlock='>';
Settings->PrintPercentage=true;
Settings->Update=false;
Settings->Max=100;
Settings->Width=40;
}
/* Prints/updates the progress bar */
void PrintProgressBar(double Pos, ProgressBarSettings * Settings)
{
/* Blocks to print */
unsigned int printBlocks=(unsigned int)(Settings->Width*Pos/Settings->Max);
/* Counter */
unsigned int counter;
/* If we are updating an existing bar...*/
if(Settings->Update)
{
/* ... we get back to its first character to rewrite it... */
for(counter=Settings->Width+2+(Settings->PrintPercentage?5:0);counter;counter--)
putchar('\b');
}
else
Settings->Update=true; /* next time we'll be updating it */
/* Print the first delimiter */
putchar(Settings->StartDelimiter);
/* Reset the counter */
counter=Settings->Width;
/* Print all the blocks except the last; in the meantime, we decrement the counter, so in the end we'll have
the number of spaces to fill the bar */
for(;printBlocks>1;printBlocks--,counter--)
putchar(Settings->Block);
/* Print the last block; if the operation ended, use the normal block, otherwise the one for the last block */
putchar((Settings->Max==Pos)?Settings->Block:Settings->CurBlock);
/* Another block was printed, decrement the counter */
counter--;
/* Fill the rest of the bar with spaces */
for(;counter;counter--)
putchar(' ');
/* Print the end delimiter */
putchar(Settings->EndDelimiter);
/* If asked, print also the percentage */
if(Settings->PrintPercentage)
printf(" %3d%%",(int)(100*Pos/Settings->Max));
/* Flush the output buffer */
fflush(stdout);
};
Note: the unistd.h and usleep thing is just to fake the progress of an operation, the progress bar code itself just uses the standard library. Its only assumptions about the output stream are that \b actually gets to the previous written character. I tried it successfully on Windows and Linux (with gnome-terminal), don't know if it doesn't work correctly with some terminal emulators.
Sorry for the excessive amount of comments, I wrote it for another forum where I needed to explain pratically every line of the code to a C newbie.

Related

ncurses forms: Show editing cursor / highlight active field

I’m new to programming and I’d like to realise the following with ncurses in C:
A form with fields to fill out and underneath this form, there is a continuously changing sensor value to be observed by the user during filling out the form, which results in the desired actions.
I’m glad I made it that far, that I can put the field buffer into my variables now, by pressing return, but now I’m facing a problem which seems to be not googleable.
My program started off from the example, which I posted underneath. In the original example I just added two lines and it already demonstrates my problem very well.
I set timeout(1); so the getch() function won’t wait for user input in the form before it prints the fresh sensor values.
Into the while-loop I put in the sennsor value with mvprint.
Now the sensor values are always up-to-date and it is still possible to move from one field to the other with the arrow keys and type into the fields.
But the visible Cursor always stays at the sensor value, which makes sense to me, because it is continuously moved there for printing. The forms driver seems to remember the position which was edited lastly, so that editing the fields will still function, but without any optical hint at which position the typing will be. The documentation refers to this position as the “editing-cursor” at one point.
Am I doing something completely wrong? Or is there a way to highlight the field, or even make the editing-cursor visible?
Thank you!
/* gcc -Wall -pthread -g -o formncurses formncurses.c -lform -lncurses */
#include <form.h>
int main()
{ FIELD *field[3];
FORM *my_form;
int ch;
/* Initialize curses */
initscr();
cbreak();
noecho();
keypad(stdscr, TRUE);
timeout(1);
/* Initialize the fields */
field[0] = new_field(1, 10, 4, 18, 0, 0);
field[1] = new_field(1, 10, 6, 18, 0, 0);
field[2] = NULL;
/* Set field options */
set_field_back(field[0], A_UNDERLINE); /* Print a line for the option */
field_opts_off(field[0], O_AUTOSKIP); /* Don't go to next field when this */
/* Field is filled up */
set_field_back(field[1], A_UNDERLINE);
field_opts_off(field[1], O_AUTOSKIP);
/* Create the form and post it */
my_form = new_form(field);
post_form(my_form);
refresh();
mvprintw(4, 10, "Value 1:");
mvprintw(6, 10, "Value 2:");
refresh();
/* Loop through to get user requests */
while((ch = getch()) != KEY_F(1))
{ switch(ch)
{ case KEY_DOWN:
/* Go to next field */
form_driver(my_form, REQ_NEXT_FIELD);
/* Go to the end of the present buffer */
/* Leaves nicely at the last character */
form_driver(my_form, REQ_END_LINE);
break;
case KEY_UP:
/* Go to previous field */
form_driver(my_form, REQ_PREV_FIELD);
form_driver(my_form, REQ_END_LINE);
break;
default:
/* If this is a normal character, it gets */
/* Printed */
form_driver(my_form, ch);
break;
}
mvprintw(12, 10, "Here stands the changing sensor value");
}
/* Un post form and free the memory */
unpost_form(my_form);
free_form(my_form);
free_field(field[0]);
free_field(field[1]);
endwin();
return 0;
}
The getch call essentially tells ncurses to leave the cursor where your mvprintw has left it — on the standard screen. To get it to move to your form, you would have to tell it to use wgetch, passing the WINDOW* pointer for the current form (which in turn holds a window's position for the field).
Further reading:
FIELD *current_field(const FORM *);
WINDOW *form_win(const FORM *form);
One thing that #Thomas's answer does not provide is how to highlight the active field (as indicated by the title of the question). For completion's sake, I am going to add a function here that will allow you to do just that:
void highlight_current_field(FORM *form, FIELD *fields[])
{
FIELD *cfield = current_field(form);
FIELD *currfield;
int i = 0;
while ((currfield = fields[i]) != NULL)
{
if (currfield == cfield)
set_field_back(currfield, A_STANDOUT);
else if (i >= 4)
set_field_back(currfield, A_UNDERLINE);
++i;
}
}
I hope this helps fellow travelers. For more information on the attributes provide, check out this site.

Eclipse printing symbols instead of 'chars' on console for C

new to C. Trying to get it to work with Eclipse since it seems a lot easier to use then vi (formatting, syntax warnings before compiling etc).
Now my program works fine in a terminal but in Eclipse console it does not seem to work well.
I have found the source of error but I need some assistance fixing it.
For some reason Eclipse console does not like to re-locate the cursor to print over existing text (or so it seems). Because when I print regularly using printf(...) it prints fine.
I am using these functions to re-print and Eclipse console does not like it. I first re-locate the cursor with set_cur_pos(..) and then in a for loop reprint my characters on top of existing text by calling put(..)
//
// Name: put
// Description: calls putchar to place a character, then flushes stdout
// #param character - character to print onto console
void put(char character) {
putchar(character);
fflush( stdout);
} // clear
//
// Name: set_cur_pos
// Description - sets cursor at a specific location on console
// #param rCursor - row location to place cursor
// #param cCursor - col location to place cursor
//
void set_cur_pos(int rCursor, int cCursor) {
printf("\033[%d;%dH", rCursor, cCursor);
} // set_cur_pos
EG: I'd use it like this
/**
* Description: Function prints a grid using cursor control.
*/
static void printOver(char grid[40][40]) {
int i, j;
for ( i = 0; i < size; i++ ) {
for ( j = 0; j < size; j++ ) {
set_cur_pos(i, j);
put(grid[i][j]);
}
}
Any ideas why Eclipse prints this out?
[2J[0;0H [0;1H*[0;2H [0;3H [0;4H [0;5HY[0;6H*[0;7H [0;8H [0;9H [1;0H [1;1H [1;2H [1;3H [1;4H [1;5HY[1;6H [1;7H [1;8H [1;9H*[2;0H [2;1H [2;2H*[2;3H [2;4H*[2;5HY[2;6H [2;7HY[2;8H [2;9H [3;0H [3;1H [3;2H [3;3H [3;4HY[3;5HY[3;6H [3;7H [3;8H [3;9H [4;0H*[4;1H [4;2H [4;3H [4;4HY[4;5H [4;6H [4;7H [4;8H [4;9H [5;0H*[5;1HY[5;2H [5;3H [5;4H [5;5H [5;6H [5;7H [5;8H*[5;9H [6;0HY[6;1HY[6;2H [6;3H [6;4H [6;5HY[6;6HY[6;7H*[6;8H [6;9H [7;0H [7;1HY[7;2H [7;3HY[7;4H [7;5H [7;6HY[7;7H [7;8H [7;9H*[8;0HY[8;1HY[8;2H [8;3H [8;4H [8;5H [8;6H [8;7H*[8;8H [8;9H [9;0H [9;1H [9;2H [9;3HY[9;4H [9;5H*[9;6H [9;7H [9;8H [9;9H [10;0H
[0;0H [0;1H_[0;2H [0;3H [0;4H [0;5HY[0;6H_[0;7H [0;8H [0;9H [1;0H [1;1H [1;2H [1;3H [1;4H [1;5HY[1;6H [1;7H [1;8H [1;9H*[2;0H [2;1H [2;2H*[2;3H [2;4H*[2;5HY[2;6H [2;7H*[2;8H [2;9H [3;0H [3;1H [3;2H [3;3H [3;4HY[3;5H*[3;6H [3;7H [3;8H [3;9H [4;0H*[4;1H [4;2H [4;3H [4;4HY[4;5H [4;6H [4;7H [4;8H [4;9H [5;0H*[5;1HY[5;2H [5;3H [5;4H [5;5H [5;6H [5;7H [5;8H*[5;9H [6;0HY[6;1H*[6;2H [6;3H [6;4H [6;5HY[6;6H*[6;7H_[6;8H [6;9H [7;0H [7;1HY[7;2H [7;3HY[7;4H [7;5H [7;6HY[7;7H [7;8H [7;9H_[8;0HY[8;1HY[8;2H [8;3H [8;4H [8;5H [8;6H [8;7H_[8;8H [8;9H [9;0H [9;1H [9;2H [9;3HY[9;4H [9;5H*[9;6H [9;7H [9;8H [9;9H [10;0H
These \033[... escape sequences are not terminal portable, eg. between bash and cmd.
So I think the eclipse IDE console does not interpret them as a cursor set command.
The single one portable cursor command without using PALs is '\r', wich will set
the cursor to the beginning of the line.

How do I scroll a message across the terminal?

I'm trying to write a program to that acts as a marquee that uses the curses.h library to create a side-scrolling display.
What should happen is that my message "Hello" should appear to scroll from the right side of the terminal to the left, character by character.
"hello" should appear to scroll across the terminal like so:
| H| // fist frame of animation
| He| //2nd
| Hel| //3rd
...
| Hello | // some time in the middle of animation
|Hello | // finished.
Instead of appearing to scroll across the terminal my program simply outputs the "Hello" message on the left side of the terminal as if it is finished.
I thought that printing the appropriate number of spaces then the appropriate number of characters of the string each frame would work.
What am I doing wrong?
Below is my code so far:
#include <curses.h>
#include <string.h>
main()
{
char message[] = "Hello";
int max_y, max_x; // max dimensions of terminal window
int text_length;
int i,row=0,col=0,spaces=0;
// Get text length
text_length = strlen(message);
// Get terminal dimensions
getmaxyx(stdscr, max_y, max_x);
// num of spaces needed to print
spaces = max_x -1;
initscr(); // initialize curses
clear(); // clear screen to begin
while(1)
{
clear(); // clear last drawn iteration
move(5,col);
// print spaces as necessary
for(i=0;i<spaces;i++)
{
addch(' ');
}
refresh();
// print appropriate number of characters of the message
for(i=0;i<text_length || i<max_x; i++)
{
addch(message[i]);
}
refresh();
usleep(50000); // wait some time
spaces = spaces-1; //adjust spaces need for next iteration
}
}
The first problem is that you call getmaxyx() before initscr(). In this situation, stdscr has not been initialized, so the values returned by getmaxyx() are meaningless. (I get -1 for each value, aka ERR.)
That fixed, the program basically works, but prints junk after the "Hello" string. You can solve that by changing the for loop test, text_length || i<max_x, to text_length && i<max_x, although the result is still probably not quite what you want. But I'll leave it to you to figure that one out.
Finally, as a stylistic matter, I'd suggest using curses' own napms() function instead of usleep() (i.e., napms(50) instead of usleep(50000)). But if you do stick with usleep(), you should add #include <unistd.h> at the top.

Input text in graphics in C programming

I am making a project in C. Its simple, just a Hangman Game.
Got the logic already cause I've done that only in console.
Now, I'm trying to do it in C again with GRAPHICS. I am using Turbo C.
I've read some of the functions of graphics.h: so far I've seen outtext() / outtextxy() something like that. It can print a string.
Can you input a char or string in graphics? Searched a lot but seen nothing.
Seen only drawing shapes examples.
How do you input characters, integers etc. in the graphics mode?
From memory, while you can use regular stdio functions printf, scanf, and gets, the graphics driver will paint them over your screen onto a "virtual cursor" position and scroll the screen when it reaches the bottom. You can use the nonstandard conio.h functions such as gotoxy and attempt to position the cursor, but it's still a mediocre way of inputting text, messing up the graphics stuff. You also cannot use the fancy fonts!
So use getch to read characters without showing them; update a string buffer (manually handling special keys such as Backspace and Return), and draw that on the screen using a font of your choice.
A short sample snippet of code to get you started:
#define MAX_INPUT_LEN 80
char inputbuf[MAX_INPUT_LEN];
int input_pos = 0;
then, in your main loop
int the_end = 0;
do
{
outtextxy (0,0, inputbuf);
c = getch();
switch (c)
{
case 8: /* backspace */
if (input_pos)
{
input_pos--;
inputbuf[input_pos] = 0;
}
break;
case 13: /* return */
the_end = 1;
break;
case 27: /* Escape = Abort */
inputbuf[0] = 0;
the_end = 1;
break;
default:
if (input_pos < MAX_INPUT_LEN-1 && c >= ' ' && c <= '~')
{
inputbuf[input_pos] = c;
input_pos++;
inputbuf[input_pos] = 0;
}
}
} while (!the_end);
Before you draw the text, make sure to erase the previous line! I left that out because it's been too long ago I used Turbo-C.
For taking input from used.. you can use scanf function similar to how we take input in any non-graphics c program.
You can do this by using normal scanf function. And by using sprintf copy a integer/whatever variable into a string. Now you can use outtextxy to set the string in specified location using x,y axis. Check geeksforgeeks to learn sprintf syntax.
I know it is too late. Hope it helps someone else.!

REPL for interpreter using Flex/Bison

I've written an interpreter for a C-like language, using Flex and Bison for the scanner/parser. It's working fine when executing full program files.
Now I'm trying implement a REPL in the interpreter for interactive use. I want it to work like the command line interpreters in Ruby or ML:
Show a prompt
Accept one or more statements on the line
If the expression is incomplete
display a continuation prompt
allow the user to continue entering lines
When the line ends with a complete expression
echo the result of evaluating the last expression
show the main prompt
My grammar starts with a top_level production, which represents a single statement in the language. The lexer is configured for interactive mode on stdin. I am using the same scanner and grammar in both full-file and REPL modes, because there's no semantic difference in the two interfaces.
My main evaluation loop is structured like this.
while (!interpreter.done) {
if (interpreter.repl)
printf(prompt);
int status = yyparse(interpreter);
if (status) {
if (interpreter.error)
report_error(interpreter);
}
else {
if (interpreter.repl)
puts(interpreter.result);
}
}
This works fine except for the prompt and echo logic. If the user enters multiple statements on a line, this loop prints out superfluous prompts and expressions. And if the expression continues on multiple lines, this code doesn't print out continuation prompts. These problems occur because the granularity of the prompt/echo logic is a top_level statement in the grammar, but the line-reading logic is deep in the lexer.
What's the best way to restructure the evaluation loop to handle the REPL prompting and echoing? That is:
how can I display one prompt per line
how can I display the continuation prompt at the right time
how can I tell when a complete expression is the last one on a line
(I'd rather not change the scanner language to pass newline tokens, since that will severely alter the grammar. Modifying YY_INPUT and adding a few actions to the Bison grammar would be fine. Also, I'm using the stock Flex 2.5.35 and Bison 2.3 that ship with Xcode.)
After looking at how languages like Python and SML/NJ handle their REPLs, I got a nice one working in my interpreter. Instead of having the prompt/echo logic in the outermost parser driver loop, I put it in the innermost lexer input routine. Actions in the parser and lexer set flags that control the prompting by input routine.
I'm using a reentrant scanner, so yyextra contains the state passed between the layers of the interpreter. It looks roughly like this:
typedef struct Interpreter {
char* ps1; // prompt to start statement
char* ps2; // prompt to continue statement
char* echo; // result of last statement to display
BOOL eof; // set by the EOF action in the parser
char* error; // set by the error action in the parser
BOOL completeLine // managed by yyread
BOOL atStart; // true before scanner sees printable chars on line
// ... and various other fields needed by the interpreter
} Interpreter;
The lexer input routine:
size_t yyread(FILE* file, char* buf, size_t max, Interpreter* interpreter)
{
// Interactive input is signaled by yyin==NULL.
if (file == NULL) {
if (interpreter->completeLine) {
if (interpreter->atStart && interpreter->echo != NULL) {
fputs(interpreter->echo, stdout);
fputs("\n", stdout);
free(interpreter->echo);
interpreter->echo = NULL;
}
fputs(interpreter->atStart ? interpreter->ps1 : interpreter->ps2, stdout);
fflush(stdout);
}
char ibuf[max+1]; // fgets needs an extra byte for \0
size_t len = 0;
if (fgets(ibuf, max+1, stdin)) {
len = strlen(ibuf);
memcpy(buf, ibuf, len);
// Show the prompt next time if we've read a full line.
interpreter->completeLine = (ibuf[len-1] == '\n');
}
else if (ferror(stdin)) {
// TODO: propagate error value
}
return len;
}
else { // not interactive
size_t len = fread(buf, 1, max, file);
if (len == 0 && ferror(file)) {
// TODO: propagate error value
}
return len;
}
}
The top level interpreter loop becomes:
while (!interpreter->eof) {
interpreter->atStart = YES;
int status = yyparse(interpreter);
if (status) {
if (interpreter->error)
report_error(interpreter);
}
else {
exec_statement(interpreter);
if (interactive)
interpreter->echo = result_string(interpreter);
}
}
The Flex file gets these new definitions:
%option extra-type="Interpreter*"
#define YY_INPUT(buf, result, max_size) result = yyread(yyin, buf, max_size, yyextra)
#define YY_USER_ACTION if (!isspace(*yytext)) { yyextra->atStart = NO; }
The YY_USER_ACTION handles the tricky interplay between tokens in the language grammar and lines of input. My language is like C and ML in that a special character (';') is required to end a statement. In the input stream, that character can either be followed by a newline character to signal end-of-line, or it can be followed by characters that are part of a new statement. The input routine needs to show the main prompt if the only characters scanned since the last end-of-statement are newlines or other whitespace; otherwise it should show the continuation prompt.
I too am working on such an interpreter, I haven't gotten to the point of making a REPL yet, so my discussion might be somewhat vague.
Is it acceptable if given a sequence of statements on a single line, only the result of the last expression is printed? Because you can re-factor your top level grammar rule like so:
top_level = top_level statement | statement ;
The output of your top_level then could be a linked list of statements, and interpreter.result would be the evaluation of the tail of this list.

Resources