How to overwrite stdout in C - c

In most modern shells, you can hit the up and down arrows and it will put, at the prompt, previous commands that you have executed. My question is, how does this work?!
It seems to me that the shell is somehow manipulating stdout to overwrite what it has already written?
I notice that programs like wget do this as well. Does anybody have any idea how they do it?

It's not manipulating stdout -- it's overwriting the characters which have already been displayed by the terminal.
Try this:
#include <stdio.h>
#include <unistd.h>
static char bar[] = "======================================="
"======================================>";
int main() {
int i;
for (i = 77; i >= 0; i--) {
printf("[%s]\r", &bar[i]);
fflush(stdout);
sleep(1);
}
printf("\n");
return 0;
}
That's pretty close to wget's output, right? \r is a carriage-return, which the terminal interprets as "move the cursor back to the start of the current line".
Your shell, if it's bash, uses the GNU Readline library, which provides much more general functionality, including detecting terminal types, history management, programmable key bindings, etc.
One more thing -- when in doubt, the source for your wget, your shell, etc. are all available.

To overwrite the current standard output line (or parts of it) use \r (or \b.) The special character \r (carriage return) will return the caret to the beginning of the line, allowing you to overwrite it. The special character \b will bring the caret back one position only, allowing you to overwrite the last character, e.g.
#include <stdio.h>
#include <unistd.h>
int i;
const char progress[] = "|/-\\";
for (i = 0; i < 100; i += 10) {
printf("Processing: %3d%%\r",i); /* \r returns the caret to the line start */
fflush(stdout);
sleep(1);
}
printf("\n"); /* goes to the next line */
fflush(stdout);
printf("Processing: ");
for (i = 0; i < 100; i += 10) {
printf("%c\b", progress[(i/10)%sizeof(progress)]); /* \b goes one back */
fflush(stdout);
sleep(1);
}
printf("\n"); /* goes to the next line */
fflush(stdout);
Use fflush(stdout); because standard output is usually buffered and the information may not otherwise be immediately printed on the output or terminal

In addition to \r and \b, take a look at ncurses for some advanced control over what's on the console screen. (Including columns, moving around arbitrarily, etc).

A program running in a text terminal / console can manipulate the text displayed in its console in various ways (make text bold, move cursor, clear screen etc.). This is accomplished by printing special character sequences, called "escape sequences" (because they usually start with Escape, ASCII 27).
If stdout goes to a terminal which understands these escape sequences, the display of the terminal will change accordingly.
If you redirect stdout to a file, the escape sequences will appear in the file (which is usually not what you want).
There is no complete standard for escape sequences, but most terminals use the sequences introduced by VT100, with many extensions. This is what most terminals under Unix/Linux (xterm, rxvt, konsole) and others like PuTTY understand.
In practice, you would not directly hardcode escape sequences into your software (though you could), but use a library to print them, such as ncurses or GNU readline mentioned above. This allows compatibility with different terminal types.

It's done with the readline library... I'm not sure how it works behind the scenes but I don't think it has anything to do with stdout or streams. I suspect readline uses some sort of cryptic (to me, at least) terminal commands - that is, it cooperates with the terminal program that actually displays your shell session. I don't know that you can get readline-like behavior just by printing output.
(Think about this: stdout can be redirected to a file, but the up/down-arrow keys trick doesn't work on files.)

You can use carriage return to simulate this.
#include <stdio.h>
int main(int argc, char* argv[])
{
while(1)
{
printf("***********");
fflush(stdout);
sleep(1);
printf("\r");
printf("...........");
sleep(1);
}
return 0;
}

The program does this by printing special characters that the terminal interprets in a special way. The most simple version of this is (on most linux/unix terminals) to print '\r' (carriage return) to the normal stdout which resets the cursor position to the first character in the current line. So the thing you write next will overwrite the line you wrote previously. This can be used for simple progress indicators, for example.
int i = 0;
while (something) {
i++;
printf("\rprocessing line %i...", i);
...
}
But there are more complicated escape characters sequences that are interpreted in various ways. All kinds of things can be done with this, like positioning the cursor at a specific position on the screen or setting the text color. If or how these character sequences are interpreted depends on your terminal, but a common class supported by most terminals are ansi escape sequences. So if you want red text, try:
printf("Text in \033[1;31mred\033[0m\n");

The simplest way is to print to stdout the carriage return character ('\r').
The cursor will be moved to the start of the line, allowing you to overwrite its contents.

Related

Count down for quiz game in C

I want to make a quizgame with a countdown. The problem is; when I use system cls all the prints are going. I tried using printf("/ b"). In that case, I can't get data from the user because the system is in the loop.
Can I keep the question output and count down and get input from the user?
Here this is my countdown code:
int v=30;
while(v!=0) {
printf("\n\t%d",v);
v--;
sleep(1);
system("cls");
}
If I understand your question, and you just want to display a countdown in the same location on the screen, then for terminals that support VT100 emulation (and some earlier VTXX versions), you can just use ANSI escapes to control the cursor visibility and a carriage-return ('\r') to return cursor position to the original starting point. If you use the field-width modifier for your integer output, you don't even need the ANSI escape to clear to end-of-line. If you have variable number of characters that are part of your countdown, you can use the ANSI escape to clear to end-of-line to ensure all text is erased each iteration.
For example you could do:
#include <stdio.h>
#include <unistd.h>
int main (void) {
int v = 30;
printf ("\033[?25l"); /* hide cursor */
while (v--) {
printf (" countdown: %2d\r", v); /* print, CR */
fflush (stdout); /* flush stdout */
sleep (1);
}
printf ("\033[?25h\n"); /* restore cursor, \n */
}
If you did have additional text after the countdown number that varied in length with each iteration, you could use:
printf (" countdown: %2d\033[0k\r", v); /* print, clear to end, CR */
which includes the clear to end-of-line escape \033[0k.
The two additional ANSI escapes used above are \033[?25l (hide cursor) and \033[?25h (restore cursor).
The fflush(stdout); is necessary because output in C is line-buffered by default. Without fflush(stdout);, all output would be buffered until a '\n' was encountered -- making all text appear at once.
Give it a try. If you have a VT compatible terminal, it will work fine. But note, the reason ANSI escapes are discouraged is they are not portable. Not all terminals support VT emulation (but a lot do...) See ANSI Escape sequences - VT100 / VT52 for additional escape sequences.
If you are developing a full fledged terminal app with numerous inputs and outputs formatted on the screen, you are better served using a library that provides that capability, such as ncursees etc..
The possible soulution:
I won't put the sleep.
I would ask the user inside the loop and after every answer i would v-- .
#include <stdio.h>
int main (void) {
int v=10;
char *name;
while(v!=0){
printf("Whats your name? ");
scanf("%s", &name);
printf("\nyour name is %s", &name);
printf("\n");
printf("\n\t%d",v);
printf("\n");
v--;
}
return 0;
}

What Is the Use Of ( \r ) carriage return in c program

Can You Explain Me This Code ....
What Is The Use Of \r In This Program
#include<stdio.h>
void main()
{
printf("This Is \r Amarendra Deo");
}
The \r has no inherit meaning for the C language, but terminals (aka console) can react to this character in different ways. The most common way for terminal is that carriage return sets the cursor at the start of the current line. So when you execute this line, you'll get
Amarendra Deo
Because printf will print This Is and the \r will set the cursor back to the beginning of the line and Amarendra Deo will overwrite whatever has been printed on that line. And since Amarendra Deo is longer than This Is, all you see is
Amarendra Deo
This is for example a very useful trick for when you want to print something
repeatedly on the same line, for example a status message:
for(size_t i = 0; i < 5; ++i)
{
printf("Processing task %d...\r", i+1);
fflush(stdout);
execute_task(i); // can take several seconds to finish
}
In that case you'll see the the Processing task ... text on the same line and it's a nice visual feature for the user. Try executing that for yourself (change the execute_task(i) with sleep(1) or something to make a delay).

Ending a Loop with EOF (without enter)

i am currently trying to end a while loop with something like this:
#include <stdio.h>
int main()
{
while(getchar() != EOF)
{
if( getchar() == EOF )
break;
}
return 0;
}
When i press CTRL+D on my Ubuntu, it ends the loop immediately. But on Windows i have to press CTRL+Z and then press ENTER to close the loop. Can i get rid of the ENTER on Windows?
The getchar behavior
For linux the EOF char is written with ctrl + d, while on Windows it is written by the console when you press enter after changing an internal status of the CRT library through ctrl + z (this behaviour is kept for retrocompatibility with very old systems). If I'm not wrong it is called soft end of file. I don't think you can bypass it, since the EOF char is actually consumed by your getchar when you press enter, not when you press ctrl + z.
As reported here:
In Microsoft's DOS and Windows (and in CP/M and many DEC operating systems), reading from the terminal will never produce an EOF. Instead, programs recognize that the source is a terminal (or other "character device") and interpret a given reserved character or sequence as an end-of-file indicator; most commonly this is an ASCII Control-Z, code 26. Some MS-DOS programs, including parts of the Microsoft MS-DOS shell (COMMAND.COM) and operating-system utility programs (such as EDLIN), treat a Control-Z in a text file as marking the end of meaningful data, and/or append a Control-Z to the end when writing a text file. This was done for two reasons:
Backward compatibility with CP/M. The CP/M file system only recorded the lengths of files in multiples of 128-byte "records", so by convention a Control-Z character was used to mark the end of meaningful data if it ended in the middle of a record. The MS-DOS filesystem has always recorded the exact byte-length of files, so this was never necessary on MS-DOS.
It allows programs to use the same code to read input from both a terminal and a text file.
Other information are also reported here:
Some modern text file formats (e.g. CSV-1203[6]) still recommend a trailing EOF character to be appended as the last character in the file. However, typing Control+Z does not embed an EOF character into a file in either MS-DOS or Microsoft Windows, nor do the APIs of those systems use the character to denote the actual end of a file.
Some programming languages (e.g. Visual Basic) will not read past a "soft" EOF when using the built-in text file reading primitives (INPUT, LINE INPUT etc.), and alternate methods must be adopted, e.g. opening the file in binary mode or using the File System Object to progress beyond it.
Character 26 was used to mark "End of file" even if the ASCII calls it Substitute, and has other characters for this.
If you modify your code like that:
#include <stdio.h>
int main() {
while(1) {
char c = getchar();
printf("%d\n", c);
if (c == EOF) // tried with also -1 and 26
break;
}
return 0;
}
and you test it, on Windows you will see that the EOF (-1) it is not written in console until you press enter. Beore of that a ^Z is printed by the terminal emulator (I suspect). From my test, this behavior is repeated if:
you compile using the Microsoft Compiler
you compile using GCC
you run the compiled code in CMD window
you run the compiled code in bash emulator in windows
Update using Windows Console API
Following the suggestion of #eryksun, I successfully written a (ridiculously complex for what it can do) code for Windows that changes the behavior of conhost to actually get the "exit when pressing ctrl + d". It does not handle everything, it is only an example. IMHO, this is something to avoid as much as possible, since the portability is less than 0. Also, to actually handle correctly other input cases a lot more code should be written, since this stuff detaches the stdin from the console and you have to handle it by yourself.
The methods works more or less as follows:
get the current handler for the standard input
create an array of input records, a structure that contains information about what happens in the conhost window (keyboard, mouse, resize, etc.)
read what happens in the window (it can handle the number of events)
iterate over the event vector to handle the keyboard event and intercept the required EOF (that is a 4, from what I've tested) for exiting, or prints any other ascii character.
This is the code:
#include <windows.h>
#include <stdio.h>
#define Kev input_buffer[i].Event.KeyEvent // a shortcut
int main(void) {
HANDLE h_std_in; // Handler for the stdin
DWORD read_count, // number of events intercepted by ReadConsoleInput
i; // iterator
INPUT_RECORD input_buffer[128]; // Vector of events
h_std_in = GetStdHandle( // Get the stdin handler
STD_INPUT_HANDLE // enumerator for stdin. Others exist for stdout and stderr
);
while(1) {
ReadConsoleInput( // Read the input from the handler
h_std_in, // our handler
input_buffer, // the vector in which events will be saved
128, // the dimension of the vector
&read_count); // the number of events captured and saved (always < 128 in this case)
for (i = 0; i < read_count; i++) { // and here we iterate from 0 to read_count
switch(input_buffer[i].EventType) { // let's check the type of event
case KEY_EVENT: // to intercept the keyboard ones
if (Kev.bKeyDown) { // and refine only on key pressed (avoid a second event for key released)
// Intercepts CTRL + D
if (Kev.uChar.AsciiChar != 4)
printf("%c", Kev.uChar.AsciiChar);
else
return 0;
}
break;
default:
break;
}
}
}
return 0;
}
while(getchar() != EOF)
{
if( getchar() == EOF )
break;
}
return 0;
Here it is inconsistent.
If getchar() != EOF it will enter the loop, otherwise (if getchar() == EOF) it will not enter the loop. So, there is no reason to check getchar() == EOF inside the loop.
On the other hand, you call getchar() 2 times, you wait to enter 2 characters instead of only 1.
What did you try to do ?

How to print "\r" to a file

I want to show a progress bar in my program so I add this
#include <stdio.h>
#include <unistd.h>
int main() {
puts("begin");
for (int i = 0; i < 100; i++) {
printf("%d%% finished.\r", i);
fflush(stdout);
usleep(100000);
}
puts("end");
}
when it outputs to stdout it shows nicely a line indicating the current progress.
However if I direct its output to a file, then all the lines with printf("%d%% finished.\r", i); are missing.
Is it possible to keep all the lines in a file?
You can't really use formatting like that when output is redirected to a file, because output to the file only writes forward, it never writes backwards.
If you're on a POSIX system (like Linux or macOS) then you can use isatty to detect if your writing to an actual terminal or not, and change your output formatting accordingly.
It is unlikely that the lines be missing in your output file, but it is possible that copying the file to the terminal occurs so quickly that each line overwrites the previous one without a chance for you to see it. Unlike your program, cat will not pause between the lines. Only the last line will be visible at the end, if it is at least as long as the previous ones.
Dump the file in hexadecimal with od -x to check the actual file contents.

Why does printf() not print anything before sleep()?

I'm just learning C with Kernighan and Ritchie's book; I'm in the basics of the fourth chapter ("Functions and Program Structure"). The other day I became curious about the sleep() function, so tried to use it like this:
#include <stdio.h>
#include <unistd.h>
int main(void)
{
printf(" I like cows.");
sleep(5);
return 0;
}
The problem is the output of the program, it looks like it does the sleep() first and then the printf(), in other words, it waits five seconds and then prints the string. So I thought, maybe the program gets to sleep() so fast that it doesn't let printf() have his work done like I want, that is print the string and then sleep.
How can I show the string and then put the program to sleep?
The compiler is GCC 3.3.5 (propolice) in OpenBSD 4.3.
printf() writes to stdout (the default output stream) which is usually line buffered. The buffer isn't flushed by the time sleep is called so nothing is displayed, when the program exits all streams are automatically flushed which is why it prints right before exiting. Printing a newline will usually cause the stream to be flushed, alternatively you could use the fflush function:
int main(void)
{
printf(" I like cows.\n");
sleep(5);
return 0;
}
or:
int main(void)
{
printf(" I like cows.");
fflush(stdout);
sleep(5);
return 0;
}
If you are printing to a stream that is not line buffered, as may be the case if stdout is redirected or you are writing to a file, simply printing a newline probably won't work. In such cases you should use fflush if you want the data written immediately.
Your problem is that printf (and anything else that uses the stdio library to write to stdout (standard output)) is buffered - line buffered if it goes to the console, and size buffered if it goes to a file. If you do a fflush(stdout); after the printf, it will do what you want. You could try just adding a newline ('\n') to your string, and that would do the right thing as long as you don't redirect standard output to a file.
I'm not 100% sure, but I think stderr isn't buffered, which can cause confusion because you might see output you made to stderr before output you previously made to stdout.
Buffering means that all the output is stored in a place (called buffer) and is output after a certain amount of data is present in it. This is done for efficiency reasons.
Some (most?) implementations clear the buffer after a newline when writing to the console, so you can also try
printf(" I like cows.\n");
instead of the call to fflush()
I implemented time encounter as following;
for (int i = 1; i <= 60; i++) {
printf("%02d", i);
fflush(stdout);
sleep(1);
printf("\b\b");
}

Resources