Is there a way to either;
(1) Clear any input from the terminal
(2) take input without the input being saved to the terminal
For example, in this program I enter a string and it checks if any of the letters are the same. Ideally I would want the input string to be cleared so that the hashtags form a rectangle by the 5th guess. I am aware that clearing the entire terminal and reprinting all the rows is an option but I would much rather just clear the line of input after every guess (if this is possible).
You can use VT100 escape codes. Most terminals, including xterm, are VT100 aware. For erasing a line, this is ^[[2K. In C this gives:
printf("\33[2K\r");
Some worthwhile subtleties...
\33[2K erases the entire line your cursor is currently on
\033[A moves your cursor up one line, but in the same column i.e. not to the start of the line
\r brings your cursor to the beginning of the line (r is for carriage return N.B. carriage returns do not include a newline so cursor remains on the same line) but does not erase anything
Related
I am using the readline (version 6.3, default [non-vi] mode, Ubuntu 14.04) library from within my own program, running in a Terminal window (on a PC). There is a problem when there is previous output not terminated by newline when readline() is called.
#include <stdio.h>
#include <readline/readline.h>
void main(void)
{
// Previous output from some other part of application
// which *may* have output stuff *not* terminated with a '\n'
printf("Hello ");
fflush(stdout);
char *in = readline("OK> ");
}
So the line looks like:
Hello OK> <caret here>
If you type a small number of characters (up to 5?) and then, say, Ctrl+U (may be others) to delete your input so far it all seems well --- readline() moves the caret back to just after its own prompt, i.e. deleting 5 characters. However, try typing, say:
123456 <Ctrl+U>
Now it deletes back into the Hello, leaving just Hell on the line, followed by the caret, i.e. deleting 6+6==12. So you see:
Hello OK> 123456 <Ctrl+U>
Hell<caret here>
I need one of two possible solutions:
I have realised it depends on how many characters are typed on the line where it goes wrong. Any fix/workaround?
Alternatively, is there a readline library call I could make which would tell me what position/column the caret is at before I invoke readline()? Then at least I could recognise the fact that that I am at the end of an existing line and output a \n so as to position myself at the start of a new line first.
I think I can sort of guess that for up to 5 characters typed it does up to 5 backspaces, but over that it chooses to do something else which messes up if it did not start at beginning of line?
I see GNU Readline: how to clear the input line?. Is this the same situation? The solutions seem pretty complex. Is it not possible to ask what column you are at when starting readline(), or to tell it not to try to be so clever at deleting and stick to only deleting as many characters as have actually been typed into it?
It turns out that readline cannot recognise if it is not starting at column #1, and thereby stop itself from messing up the previous output on the line.
The only way to deal with this is to recognise the starting column ourselves, and move to the start of the next line down if the current position is not column #1. Then it will always starts from the left-most column, without outputting an unnecessary newline when it is already at column #1.
We can do this for the standard "Terminal" because it understands an ANSI escape sequence to query the current row & column of the terminal. The query is sent via characters to stdout and the response is read via characters the terminal inserts into stdin. We must put the terminal into "raw" input mode so that the response characters can be read immediately and will not be echoed.
So here is the code:
rl_prep_terminal(1); // put the terminal into "raw" mode
fputs("\033[6n", stdout); // <ESC>[6n is ANSI sequence to query terminal position
int row, col; // terminal will reply with <ESC>[<row>;<col>R
fscanf(stdin, "\033[%d;%dR", &row, &col);
rl_deprep_terminal(); // restore terminal "cooked" mode
if (col > 1) // if beyond the first column...
fputc('\n', stdout); // output '\n' to move to start of next line
in = readline(prompt); // now we can invoke readline() with our prompt
Some applications running in terminal can erase their outputs. e.g.
when it tells you to wait, it will show a sequence of dots alternating between different lengths.
How is erasing output in terminal implemented in C? Is it done by reverse line feed?
Can a program only erase the previous characters in the current line, not the characters in the previous line in stdout?
Thanks.
It depends on the terminal.
The COMSPEC shell on Windows (often called the DOS prompt or command.com) exposes an API in C to control the cursor. I haven't done any Windows programming so I can't tell you much about it.
Most other terminals (especially on unixen) emulate protocols that resemble the VT100 serial terminal (the VT100 terminal was a physical device, a monitor and keyboard, that you attached to a modem or serial port to communicate with a server).
On VT100 terminals, carriage return and line feed are separate commands, both one byte. The carriage return command sets the cursor to the beginning of the line. The line feed command moves the cursor down a line (but doesn't bring the cursor to the beginning of the line by itself). Most shells on unixen automatically insert a carriage return after a line feed but almost none inserts a line feed after a carriage return.
With this knowledge, the simplest implementation is to simply output a carriage return and reprint the entire line:
printf("\rprogress: %d percent ", x);
Note the extra spaces at the end of the line. Printing "\r" doesn't erase the line so reprinting over the old line may end up leaving some of the old string on screen. The extra spaces is used to try and erase the remainder of the old line.
If you googled "VT100 escape secquence", you'll find commands that will allow you to do things like erase the current line, change color of text, goto a specific row/column on screen etc. The most popular use of VT100 sequences is to output coloured text. But you can also do other things with them.
The next simplest implementation is to cleanly delete the line and reprint it:
printf("\033[2K\rprogress: %d percent", x);
The \033[2K is the escape sequence to delete the current line (ESC[2K).
From here you can get more creative if you want. You can use the cursor save/restore command with the erase until end of line command to only erase the part you want to update (instead of the entire line). You can use the goto commands to put the cursor in a specific location on screen to update text there etc.
It should be noted that the more advanced stuff such as VT102 sequences or some of the full ANSI escape sequences are generally not portable accross terminals (by terminals I don't mean the shell, I mean the terminals: rxvt, xterm, linux terminal, hyperterminal(on windows) etc).
If you want portability (and/or sane API) you should use the curses or ncurses libraries.
If you wanted to know how it's done, then that's how it's done. It's just printing specially formatted strings to screen (except for the COMSPEC shell). Kind of like HTML but old-school.
#include <stdio.h>
int main()
{
int countch=0;
int countwd=1;
printf("Enter your sentence in lowercase: ");
char ch='a';
while(ch!='\r')
{
ch=getche();
if(ch==' ')
countwd++;
else
countch++;
}
printf("\n Words =%d ",countwd);
printf("Characters = %d",countch-1);
getch();
}
This is the program where I came across \r. What exactly is its role here? I am beginner in C and I appreciate a clear explanation on this.
'\r' is the carriage return character. The main times it would be useful are:
When reading text in binary mode, or which may come from a foreign OS, you'll find (and probably want to discard) it due to CR/LF line-endings from Windows-format text files.
When writing to an interactive terminal on stdout or stderr, '\r' can be used to move the cursor back to the beginning of the line, to overwrite it with new contents. This makes a nice primitive progress indicator.
The example code in your post is definitely a wrong way to use '\r'. It assumes a carriage return will precede the newline character at the end of a line entered, which is non-portable and only true on Windows. Instead the code should look for '\n' (newline), and discard any carriage return it finds before the newline. Or, it could use text mode and have the C library handle the translation (but text mode is ugly and probably should not be used).
It's Carriage Return. Source: http://msdn.microsoft.com/en-us/library/6aw8xdf2(v=vs.80).aspx
The following repeats the loop until the user has pressed the Return key.
while(ch!='\r')
{
ch=getche();
}
Once upon a time, people had terminals like typewriters (with only upper-case letters, but that's another story). Search for 'Teletype', and how do you think tty got used for 'terminal device'?
Those devices had two separate motions. The carriage return moved the print head back to the start of the line without scrolling the paper; the line feed character moved the paper up a line without moving the print head back to the beginning of the line. So, on those devices, you needed two control characters to get the print head back to the start of the next line: a carriage return and a line feed. Because this was mechanical, it took time, so you had to pause for long enough before sending more characters to the terminal after sending the CR and LF characters. One use for CR without LF was to do 'bold' by overstriking the characters on the line. You'd write the line out once, then use CR to start over and print twice over the characters that needed to be bold. You could also, of course, type X's over stuff that you wanted partially hidden, or create very dense ASCII art pictures with judicious overstriking.
On Unix, all the logic for this stuff was hidden in a terminal driver. You could use the stty command and the underlying functions (in those days, ioctl() calls; they were sanitized into the termios interface by POSIX.1 in 1988) to tweak all sorts of ways that the terminal behaved.
Eventually, you got 'glass terminals' where the speeds were greater and and there were new idiosyncrasies to deal with - Hazeltine glitches and so on and so forth. These got enshrined in the termcap and later terminfo libraries, and then further encapsulated behind the curses library.
However, some other (non-Unix) systems did not hide things as well, and you had to deal with CRLF in your text files - and no, this is not just Windows and DOS that were in the 'CRLF' camp.
Anyway, on some systems, the C library has to deal with text files that contain CRLF line endings and presents those to you as if there were only a newline at the end of the line. However, if you choose to treat the text file as a binary file, you will see the CR characters as well as the LF.
Systems like the old Mac OS (version 9 or earlier) used just CR (aka \r) for the line ending. Systems like DOS and Windows (and, I believe, many of the DEC systems such as VMS and RSTS) used CRLF for the line ending. Many of the Internet standards (such as mail) mandate CRLF line endings. And Unix has always used just LF (aka NL or newline, hence \n) for its line endings. And most people, most of the time, manage to ignore CR.
Your code is rather funky in looking for \r. On a system compliant with the C standard, you won't see the CR unless the file is opened in binary mode; the CRLF or CR will be mapped to NL by the C runtime library.
There are a few characters which can indicate a new line. The usual ones are these two:
'\n' or '0x0A' (10 in decimal) -> This character is called "Line Feed" (LF).
'\r' or '0x0D' (13 in decimal) -> This one is called "Carriage return" (CR).
Different Operating Systems handle newlines in a different way. Here is a short list of the most common ones:
DOS and Windows
They expect a newline to be the combination of two characters, namely '\r\n' (or 13 followed by 10).
Unix (and hence Linux as well)
Unix uses a single '\n' to indicate a new line.
Mac
Macs use a single '\r'.
That is not always true; it only works in Windows.
For interacting with terminal in putty, Linux shell,... it will be used for returning the cursor to the beginning of line.
following picture shows the usage of that:
Without '\r':
Data comes without '\r' to the putty terminal, it has just '\n'.
it means that data will be printed just in next line.
With '\r':
Data comes with '\r', i.e. string ends with '\r\n'. So the cursor in putty terminal not only will go to the next line but also at the beginning of line
It depends upon which platform you're on as to how it will be translated and whether it will be there at all: Wikipedia entry on newline
\r is an escape sequence character or void character. It is used to bring the cursor to the beginning of the line (it maybe of same or new line) to overwrite with new content (content written ahead of \r like: \rhello);
int main ()
{
printf("Hello \rworld");
return 0;
}
The output of the program will be world not Hello world
because \r has put the cursor at the beginning of the line and Hello has been overwritten with world.
I expect this simple line of code
printf("foo\b\tbar\n");
to replace "o" with "\t" and to produce the following output
fo bar
(assuming that tab stop occurs every 8 characters).
On the contrary I get
foo bar
It seems that my shell interprets \b as "move the cursors one position back" and \t as "move cursor to the next tab stop". Is this behaviour specific to the shell in which I'm running the code? Should I expect different behaviour on different systems?
No, that's more or less what they're meant to do.
In C (and many other languages), you can insert hard-to-see/type characters using \ notation:
\a is alert/bell
\b is backspace/rubout
\n is newline
\r is carriage return (return to left margin)
\t is tab
You can also specify the octal value of any character using \0nnn, or the hexadecimal value of any character with \xnn.
EG: the ASCII value of _ is octal 137, hex 5f, so it can also be typed \0137 or \x5f, if your keyboard didn't have a _ key or something. This is more useful for control characters like NUL (\0) and ESC (\033)
As someone posted (then deleted their answer before I could +1 it), there are also some less-frequently-used ones:
\f is a form feed/new page (eject page from printer)
\v is a vertical tab (move down one line, on the same column)
On screens, \f usually works the same as \v, but on some printers/teletypes, it will
go all the way to the next form/sheet of paper.
Backspace and tab both move the cursor position. Neither is truly a 'printable' character.
Your code says:
print "foo"
move the cursor back one space
move the cursor forward to the next tabstop
output "bar".
To get the output you expect, you need printf("foo\b \tbar"). Note the extra 'space'. That says:
output "foo"
move the cursor back one space
output a ' ' (this replaces the second 'o').
move the cursor forward to the next tabstop
output "bar".
Most of the time it is inappropriate to use tabs and backspace for formatting your program output. Learn to use printf() formatting specifiers. Rendering of tabs can vary drastically depending on how the output is viewed.
This little script shows one way to alter your terminal's tab rendering. Tested on Ubuntu + gnome-terminal:
#!/bin/bash
tabs -8
echo -e "\tnormal tabstop"
for x in `seq 2 10`; do
tabs $x
echo -e "\ttabstop=$x"
done
tabs -8
echo -e "\tnormal tabstop"
Also see man setterm and regtabs.
And if you redirect your output or just write to a file, tabs will quite commonly be displayed as fewer than the standard 8 chars, especially in "programming" editors and IDEs.
So in otherwords:
printf("%-8s%s", "foo", "bar"); /* this will ALWAYS output "foo bar" */
printf("foo\tbar"); /* who knows how this will be rendered */
IMHO, tabs in general are rarely appropriate for anything. An exception might be generating output for a program that requires tab-separated-value input files (similar to comma separated value).
Backspace '\b' is a different story... it should never be used to create a text file since it will just make a text editor spit out garbage. But it does have many applications in writing interactive command line programs that cannot be accomplished with format strings alone. If you find yourself needing it a lot, check out "ncurses", which gives you much better control over where your output goes on the terminal screen. And typically, since it's 2011 and not 1995, a GUI is usually easier to deal with for highly interactive programs. But again, there are exceptions. Like writing a telnet server or console for a new scripting language.
The C standard (actually C99, I'm not up to date) says:
Alphabetic escape sequences representing nongraphic characters in the execution character set are intended to produce actions on display devices as follows:
\b (backspace) Moves the active position to the previous position on the current line. [...]
\t (horizontal tab) Moves the active position to the next horizontal tabulation position on the current line. [...]
Both just move the active position, neither are supposed to write any character on or over another character. To overwrite with a space you could try: puts("foo\b \tbar"); but note that on some display devices - say a daisy wheel printer - the o will show the transparent space.
This behaviour is terminal-specific and specified by the terminal emulator you use (e.g. xterm) and the semantics of terminal that it provides. The terminal behaviour has been very stable for the last 20 years, and you can reasonably rely on the semantics of \b.
\t is the tab character, and is doing exactly what you're anticipating based on the action of \b - it goes to the next tab stop, then gets decremented, and then goes to the next tab stop (which is in this case the same tab stop, because of the \b.
If for the following code:
printf("HEllo\n"); // do not change this line.
printf("\b\bworld");
I need an output: Helloworld (In a single line). But this does not work fine. Could anyone please explain the reason? And other escape sequence if any.
There is no platform-independent control character to move back up a line. This harkens back to the days of line printers, where printf actually would print a line of text onto a sheet of paper and there was no way of retracting the paper to overwrite what had already been printed.
That said, there are libraries like ncurses that let you move the cursor around the console. They're just not part of the standard libraries.
How about simply:
printf("Helloworld");
\n is an escape sequence for a new line. Since you want everything to appear on the same line, there's no reason to specify \n.
The problem is you can't reliably move back up a line (using \b) after you've printed a new line. But if you require that there be two lines of code in your source, you can simply omit both escape sequences:
printf("HEllo");
printf("world");
If you're writing a Win32 console application, you can take advantage of the Console Screen Buffer API. The following code will move 1 line up:
printf("HEllo\n");
CONSOLE_SCREEN_BUFFER_INFO coninfo;
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo(hConsole, &coninfo);
coninfo.dwCursorPosition.Y -= 1; // move up one line
coninfo.dwCursorPosition.X += 5; // move to the right the length of the word
SetConsoleCursorPosition(hConsole, coninfo.dwCursorPosition);
printf("world");
Output:
HElloworld
Remove "\n" from your first printf. It moves the cursor to a new line.
Here is the list of escape sequences.
If you can't remove "\n", then you can do make a copy of a substring without these charaters. See the following example:
const char* from = "12345678";
char *to = (char*) malloc(6);
strncpy(to, from+2, 5);
All you need is to determine the index of "\n" characters.
The backspace character, when sent to a stream (such as through the printf() family of functions), does not seek backward in the file, it is sent as-is. If you run your example, the backspace character will be output as "garbage".
If you don't want a new line, don't post a newline character.
It is because '\b' is a terminal escape code... (sans the 'escape' of course ;-)
so it only modifies what you see on the terminal. That is, the terminal adjusts its display to respond to the backspace code, even though it received everything prior to it. A file also receives everything, including the backspace code, but it is not a tty device so the file's content is not modified; it keeps everything you send to it.
If printing an extra blank is a problem, then you should code some extra logic to print the trailing blank on every output except the last.
Reference This is in reference to files but maybe same idea applies. You might want to check out this link there is a very detailed explanation that most probably answers your question.
In a console, you can't go up a line. You can clear the screen and redraw it (which simulate going up a line.) Or you can rewrite on the same line. \r will take you to the beginning of the line you just printed.
You can do it actually in a platform-independent* way, assuming that you can somehow calculate the x offset of the previous line.
int x = printf("Hello, World!\n");
gotoxy(x-1-1,gety()-1); // One for the length-offset difference and the other to skip \n
printf("\b \b");
You can avoid using that variable by directly replacing it with x.
Note: printf() returns an int (the length of the passed String (of characters)). Use it wisely :)