Prevent control-D to be echoed in terminal - c

When I use readline function and type control-D to tell my program it reached EOF, ^D is echoed in the terminal.
I would like to remove it or to replace it by another message.
I tried stty -echoctl command but it doesn't work.
I'm using ZSH with Oh My Zsh and iTerm2.
# include<stdio.h>
# include<string.h>
# include<stdlib.h>
# include<unistd.h>
# include<sys/types.h>
# include<sys/wait.h>
# include<readline/readline.h>
# include<readline/history.h>
int input(void)
{
char *buf;
buf = readline("Please write the argument:\n");
if (buf == NULL)
{
printf("Quitting the program\n");
exit(0);
}
return (0);
}
int main()
{
while (1)
{
if(!input())
continue;
}
return (0);
}
I don't know what I can try now, I checked lots of Stack Overflow threads and didn't find anything.

Although it looks like you are using the readline library, you're actually using a compatibility layer built on top of the BSD libedit library, which is what is provided by default by Mac OS. So you can expect some things to work a bit differently.
Unfortunately, libedit is not well-documented. It appears to be possible to modify the binding of the Ctrl-D key by creating a file name .editrc in your home directory, and inserting the line:
bind ^D ed-end-of-file
That will apply the change to all applications which use the libedit library, which may be a bit drastic. To make it apply only to your program, you can insert the line:
rl_readline_name = "progname";
at the beginning of your program, before the first time you call readline. Change progname to whatever you want to use as a tag for your program. Then you can change the editrc command to the following (using the same tag for progname):
progname:bind ^D ed-end-of-file
At least, that worked on an Ubuntu system.
Another option would be to just install GNU readline on your Mac. According to the GNU readline home page:
MacOS X users may obtain MacOS X packages for readline-8.0 from MacPorts, readline-7.0 from Fink, or readline-8.0 from Homebrew.
Then you'll have to make sure you build your program with GNU readline instead of the libedit shim.
Doing that will make also make the prompt work the way it reads (i.e., the prompt includes a newline). I don't know if that's what you want, though.

What you need to do is basically to have a function that reads AND manually print every character so that you can intercept characters that shouldn't be printed. Here is an idea to get started:
int ch;
char buf[SIZE] = {0};
char *p = buf;
while(1) {
ch = getchar();
if(ch == EOF) {
p[1] = 0;
break;
}
putchar(ch);
*p++ = ch;
}
You would probably like to treat backspace '\b' in a special way. Like decrementing p, but watch out for going out of bounds.

Related

How to avoid pressing enter with the c getc() function? [duplicate]

In the next code:
#include <stdio.h>
int main(void) {
int c;
while ((c=getchar())!= EOF)
putchar(c);
return 0;
}
I have to press Enter to print all the letters I entered with getchar, but I don't want to do this, what I want to do is to press the letter and immediately see the the letter I introduced repeated without pressing Enter. For example, if I press the letter 'a' I want to see an other 'a' next to it, and so on:
aabbccddeeff.....
But when I press 'a' nothing happens, I can write other letters and the copy appears only when I press Enter:
abcdef
abcdef
How can I do this?
I am using the command cc -o example example.c under Ubuntu for compiling.
This depends on your OS, if you are in a UNIX like environment the ICANON flag is enabled by default, so input is buffered until the next '\n' or EOF. By disabling the canonical mode you will get the characters immediately. This is also possible on other platforms, but there is no straight forward cross-platform solution.
EDIT: I see you specified that you use Ubuntu. I just posted something similar yesterday, but be aware that this will disable many default behaviors of your terminal.
#include<stdio.h>
#include <termios.h> //termios, TCSANOW, ECHO, ICANON
#include <unistd.h> //STDIN_FILENO
int main(void){
int c;
static struct termios oldt, newt;
/*tcgetattr gets the parameters of the current terminal
STDIN_FILENO will tell tcgetattr that it should write the settings
of stdin to oldt*/
tcgetattr( STDIN_FILENO, &oldt);
/*now the settings will be copied*/
newt = oldt;
/*ICANON normally takes care that one line at a time will be processed
that means it will return if it sees a "\n" or an EOF or an EOL*/
newt.c_lflag &= ~(ICANON);
/*Those new settings will be set to STDIN
TCSANOW tells tcsetattr to change attributes immediately. */
tcsetattr( STDIN_FILENO, TCSANOW, &newt);
/*This is your part:
I choose 'e' to end input. Notice that EOF is also turned off
in the non-canonical mode*/
while((c=getchar())!= 'e')
putchar(c);
/*restore the old settings*/
tcsetattr( STDIN_FILENO, TCSANOW, &oldt);
return 0;
}
You will notice, that every character appears twice. This is because the input is immediately echoed back to the terminal and then your program puts it back with putchar() too. If you want to disassociate the input from the output, you also have to turn of the ECHO flag. You can do this by simply changing the appropriate line to:
newt.c_lflag &= ~(ICANON | ECHO);
On a linux system, you can modify terminal behaviour using the stty command. By default, the terminal will buffer all information until Enter is pressed, before even sending it to the C program.
A quick, dirty, and not-particularly-portable example to change the behaviour from within the program itself:
#include<stdio.h>
#include<stdlib.h>
int main(void){
int c;
/* use system call to make terminal send all keystrokes directly to stdin */
system ("/bin/stty raw");
while((c=getchar())!= '.') {
/* type a period to break out of the loop, since CTRL-D won't work raw */
putchar(c);
}
/* use system call to set terminal behaviour to more normal behaviour */
system ("/bin/stty cooked");
return 0;
}
Please note that this isn't really optimal, since it just sort of assumes that stty cooked is the behaviour you want when the program exits, rather than checking what the original terminal settings were. Also, since all special processing is skipped in raw mode, many key sequences (such as CTRL-C or CTRL-D) won't actually work as you expect them to without explicitly processing them in the program.
You can man stty for more control over the terminal behaviour, depending exactly on what you want to achieve.
getchar() is a standard function that on many platforms requires you to press ENTER to get the input, because the platform buffers input until that key is pressed. Many compilers/platforms support the non-standard getch() that does not care about ENTER (bypasses platform buffering, treats ENTER like just another key).
I/O is an operating system function. In many cases, the operating system won't pass typed character to a program until ENTER is pressed. This allows the user to modify the input (such as backspacing and retyping) before sending it to the program. For most purposes, this works well, presents a consistent interface to the user, and relieves the program from having to deal with this. In some cases, it's desirable for a program to get characters from keys as they are pressed.
The C library itself deals with files, and doesn't concern itself with how data gets into the input file. Therefore, there's no way in the language itself to get keys as they are pressed; instead, this is platform-specific. Since you haven't specified OS or compiler, we can't look it up for you.
Also, the standard output is normally buffered for efficiency. This is done by the C libraries, and so there is a C solution, which is to fflush(stdout); after each character written. After that, whether the characters are displayed immediately is up to the operating system, but all the OSes I'm familiar with will display the output immediately, so that's not normally a problem.
I like Lucas answer, but I would like to elaborate it a bit. There is a built-in function in termios.h named cfmakeraw() which man describes as:
cfmakeraw() sets the terminal to something like the "raw" mode of the
old Version 7 terminal driver: input is available character by
character, echoing is disabled, and all special processing of
terminal input and output characters is disabled. [...]
This basically does the same as what Lucas suggested and more, you can see the exact flags it sets in the man pages: termios(3).
Use case
int c = 0;
static struct termios oldTermios, newTermios;
tcgetattr(STDIN_FILENO, &oldTermios);
newTermios = oldTermios;
cfmakeraw(&newTermios);
tcsetattr(STDIN_FILENO, TCSANOW, &newTermios);
c = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldTermios);
switch (c) {
case 113: // q
printf("\n\n");
exit(0);
break;
case 105: // i
printf("insert\n");
break;
default:
break;
Since you are working on a Unix derivative (Ubuntu), here is one way to do it - not recommended, but it will work (as long as you can type commands accurately):
echo "stty -g $(stty -g)" > restore-sanity
stty cbreak
./your_program
Use interrupt to stop the program when you are bored with it.
sh restore-sanity
The 'echo' line saves the current terminal settings as a shell script that will restore them.
The 'stty' line turns off most of the special processing (so Control-D has no effect, for example) and sends characters to the program as soon as they are available. It means you cannot edit your typing any more.
The 'sh' line reinstates your original terminal settings.
You can economize if 'stty sane' restores your settings sufficiently accurately for your purposes. The format of '-g' is not portable across versions of 'stty' (so what is generated on Solaris 10 won't work on Linux, or vice versa), but the concept works everywhere. The 'stty sane' option is not universally available, AFAIK (but is on Linux).
You could include the 'ncurses' library, and use getch() instead of getchar().
"How to avoid pressing Enter with getchar()?"
First of all, terminal input is commonly either line or fully buffered. This means that the operating system stores the actual input from the terminal in a buffer. Usually, this buffer is flushed to the program when e.g. \n was signalized/provided in stdin. This is f.e. made by a press to Enter.
getchar() is just at the end of the chain. It has no ability to actually influence the buffering process.
"How can I do this?"
Ditch getchar() in the first place, if you don´t want to use specific system calls to change the behavior of the terminal explicitly like well explained in the other answers.
There is unfortunately no standard library function and with that no portable way to flush the buffer at single character input. However, there are implementation-based and non-portable solutions.
In Windows/MS-DOS, there are the getch() and getche() functions in the conio.h header file, which do exactly the thing you want - read a single character without the need to wait for the newline to flush the buffer.
The main difference between getch() and getche() is that getch() does not immediately output the actual input character in the console, while getche() does. The additional "e" stands for echo.
Example:
#include <stdio.h>
#include <conio.h>
int main (void)
{
int c;
while ((c = getche()) != EOF)
{
if (c == '\n')
{
break;
}
printf("\n");
}
return 0;
}
In Linux, a way to obtain direct character processing and output is to use the cbreak() and echo() options and the getch() and refresh() routines in the ncurses-library.
Note, that you need to initialize the so called standard screen with the initscr() and close the same with the endwin() routines.
Example:
#include <stdio.h>
#include <ncurses.h>
int main (void)
{
int c;
cbreak();
echo();
initscr();
while ((c = getch()) != ERR)
{
if (c == '\n')
{
break;
}
printf("\n");
refresh();
}
endwin();
return 0;
}
Note: You need to invoke the compiler with the -lncurses option, so that the linker can search and find the ncurses-library.
yes you can do this on windows too, here's the code below, using the conio.h library
#include <iostream> //basic input/output
#include <conio.h> //provides non standard getch() function
using namespace std;
int main()
{
cout << "Password: ";
string pass;
while(true)
{
char ch = getch();
if(ch=='\r'){ //when a carriage return is found [enter] key
cout << endl << "Your password is: " << pass <<endl;
break;
}
pass+=ch;
cout << "*";
}
getch();
return 0;
}
I've had this problem/question come up in an assignment that I'm currently working on.
It also depends on which input you are grabbing from.
I am using
/dev/tty
to get input while the program is running, so that needs to be the filestream associated with the command.
On the ubuntu machine I have to test/target, it required more than just
system( "stty -raw" );
or
system( "stty -icanon" );
I had to add the --file flag, as well as path to the command, like so:
system( "/bin/stty --file=/dev/tty -icanon" );
Everything is copacetic now.
This code worked for me. Attention : this is not part of the standard library, even if most compilers (I use GCC) supports it.
#include <stdio.h>
#include <conio.h>
int main(int argc, char const *argv[]) {
char a = getch();
printf("You typed a char with an ASCII value of %d, printable as '%c'\n", a, a);
return 0;
}
This code detects the first key press.
Can create a new function that checks for Enter:
#include <stdio.h>
char getChar()
{
printf("Please enter a char:\n");
char c = getchar();
if (c == '\n')
{
c = getchar();
}
return c;
}
int main(int argc, char *argv[])
{
char ch;
while ((ch = getChar()) != '.')
{
printf("Your char: %c\n", ch);
}
return 0;
}
By default, the C library buffers the output until it sees a return. To print out the results immediately, use fflush:
while((c=getchar())!= EOF)
{
putchar(c);
fflush(stdout);
}
you can use _getch() instead of getch() from <conio.h>

putchar ends only on pressing enter (C) [duplicate]

In the next code:
#include <stdio.h>
int main(void) {
int c;
while ((c=getchar())!= EOF)
putchar(c);
return 0;
}
I have to press Enter to print all the letters I entered with getchar, but I don't want to do this, what I want to do is to press the letter and immediately see the the letter I introduced repeated without pressing Enter. For example, if I press the letter 'a' I want to see an other 'a' next to it, and so on:
aabbccddeeff.....
But when I press 'a' nothing happens, I can write other letters and the copy appears only when I press Enter:
abcdef
abcdef
How can I do this?
I am using the command cc -o example example.c under Ubuntu for compiling.
This depends on your OS, if you are in a UNIX like environment the ICANON flag is enabled by default, so input is buffered until the next '\n' or EOF. By disabling the canonical mode you will get the characters immediately. This is also possible on other platforms, but there is no straight forward cross-platform solution.
EDIT: I see you specified that you use Ubuntu. I just posted something similar yesterday, but be aware that this will disable many default behaviors of your terminal.
#include<stdio.h>
#include <termios.h> //termios, TCSANOW, ECHO, ICANON
#include <unistd.h> //STDIN_FILENO
int main(void){
int c;
static struct termios oldt, newt;
/*tcgetattr gets the parameters of the current terminal
STDIN_FILENO will tell tcgetattr that it should write the settings
of stdin to oldt*/
tcgetattr( STDIN_FILENO, &oldt);
/*now the settings will be copied*/
newt = oldt;
/*ICANON normally takes care that one line at a time will be processed
that means it will return if it sees a "\n" or an EOF or an EOL*/
newt.c_lflag &= ~(ICANON);
/*Those new settings will be set to STDIN
TCSANOW tells tcsetattr to change attributes immediately. */
tcsetattr( STDIN_FILENO, TCSANOW, &newt);
/*This is your part:
I choose 'e' to end input. Notice that EOF is also turned off
in the non-canonical mode*/
while((c=getchar())!= 'e')
putchar(c);
/*restore the old settings*/
tcsetattr( STDIN_FILENO, TCSANOW, &oldt);
return 0;
}
You will notice, that every character appears twice. This is because the input is immediately echoed back to the terminal and then your program puts it back with putchar() too. If you want to disassociate the input from the output, you also have to turn of the ECHO flag. You can do this by simply changing the appropriate line to:
newt.c_lflag &= ~(ICANON | ECHO);
On a linux system, you can modify terminal behaviour using the stty command. By default, the terminal will buffer all information until Enter is pressed, before even sending it to the C program.
A quick, dirty, and not-particularly-portable example to change the behaviour from within the program itself:
#include<stdio.h>
#include<stdlib.h>
int main(void){
int c;
/* use system call to make terminal send all keystrokes directly to stdin */
system ("/bin/stty raw");
while((c=getchar())!= '.') {
/* type a period to break out of the loop, since CTRL-D won't work raw */
putchar(c);
}
/* use system call to set terminal behaviour to more normal behaviour */
system ("/bin/stty cooked");
return 0;
}
Please note that this isn't really optimal, since it just sort of assumes that stty cooked is the behaviour you want when the program exits, rather than checking what the original terminal settings were. Also, since all special processing is skipped in raw mode, many key sequences (such as CTRL-C or CTRL-D) won't actually work as you expect them to without explicitly processing them in the program.
You can man stty for more control over the terminal behaviour, depending exactly on what you want to achieve.
getchar() is a standard function that on many platforms requires you to press ENTER to get the input, because the platform buffers input until that key is pressed. Many compilers/platforms support the non-standard getch() that does not care about ENTER (bypasses platform buffering, treats ENTER like just another key).
I/O is an operating system function. In many cases, the operating system won't pass typed character to a program until ENTER is pressed. This allows the user to modify the input (such as backspacing and retyping) before sending it to the program. For most purposes, this works well, presents a consistent interface to the user, and relieves the program from having to deal with this. In some cases, it's desirable for a program to get characters from keys as they are pressed.
The C library itself deals with files, and doesn't concern itself with how data gets into the input file. Therefore, there's no way in the language itself to get keys as they are pressed; instead, this is platform-specific. Since you haven't specified OS or compiler, we can't look it up for you.
Also, the standard output is normally buffered for efficiency. This is done by the C libraries, and so there is a C solution, which is to fflush(stdout); after each character written. After that, whether the characters are displayed immediately is up to the operating system, but all the OSes I'm familiar with will display the output immediately, so that's not normally a problem.
I like Lucas answer, but I would like to elaborate it a bit. There is a built-in function in termios.h named cfmakeraw() which man describes as:
cfmakeraw() sets the terminal to something like the "raw" mode of the
old Version 7 terminal driver: input is available character by
character, echoing is disabled, and all special processing of
terminal input and output characters is disabled. [...]
This basically does the same as what Lucas suggested and more, you can see the exact flags it sets in the man pages: termios(3).
Use case
int c = 0;
static struct termios oldTermios, newTermios;
tcgetattr(STDIN_FILENO, &oldTermios);
newTermios = oldTermios;
cfmakeraw(&newTermios);
tcsetattr(STDIN_FILENO, TCSANOW, &newTermios);
c = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldTermios);
switch (c) {
case 113: // q
printf("\n\n");
exit(0);
break;
case 105: // i
printf("insert\n");
break;
default:
break;
Since you are working on a Unix derivative (Ubuntu), here is one way to do it - not recommended, but it will work (as long as you can type commands accurately):
echo "stty -g $(stty -g)" > restore-sanity
stty cbreak
./your_program
Use interrupt to stop the program when you are bored with it.
sh restore-sanity
The 'echo' line saves the current terminal settings as a shell script that will restore them.
The 'stty' line turns off most of the special processing (so Control-D has no effect, for example) and sends characters to the program as soon as they are available. It means you cannot edit your typing any more.
The 'sh' line reinstates your original terminal settings.
You can economize if 'stty sane' restores your settings sufficiently accurately for your purposes. The format of '-g' is not portable across versions of 'stty' (so what is generated on Solaris 10 won't work on Linux, or vice versa), but the concept works everywhere. The 'stty sane' option is not universally available, AFAIK (but is on Linux).
You could include the 'ncurses' library, and use getch() instead of getchar().
"How to avoid pressing Enter with getchar()?"
First of all, terminal input is commonly either line or fully buffered. This means that the operating system stores the actual input from the terminal in a buffer. Usually, this buffer is flushed to the program when e.g. \n was signalized/provided in stdin. This is f.e. made by a press to Enter.
getchar() is just at the end of the chain. It has no ability to actually influence the buffering process.
"How can I do this?"
Ditch getchar() in the first place, if you don´t want to use specific system calls to change the behavior of the terminal explicitly like well explained in the other answers.
There is unfortunately no standard library function and with that no portable way to flush the buffer at single character input. However, there are implementation-based and non-portable solutions.
In Windows/MS-DOS, there are the getch() and getche() functions in the conio.h header file, which do exactly the thing you want - read a single character without the need to wait for the newline to flush the buffer.
The main difference between getch() and getche() is that getch() does not immediately output the actual input character in the console, while getche() does. The additional "e" stands for echo.
Example:
#include <stdio.h>
#include <conio.h>
int main (void)
{
int c;
while ((c = getche()) != EOF)
{
if (c == '\n')
{
break;
}
printf("\n");
}
return 0;
}
In Linux, a way to obtain direct character processing and output is to use the cbreak() and echo() options and the getch() and refresh() routines in the ncurses-library.
Note, that you need to initialize the so called standard screen with the initscr() and close the same with the endwin() routines.
Example:
#include <stdio.h>
#include <ncurses.h>
int main (void)
{
int c;
cbreak();
echo();
initscr();
while ((c = getch()) != ERR)
{
if (c == '\n')
{
break;
}
printf("\n");
refresh();
}
endwin();
return 0;
}
Note: You need to invoke the compiler with the -lncurses option, so that the linker can search and find the ncurses-library.
yes you can do this on windows too, here's the code below, using the conio.h library
#include <iostream> //basic input/output
#include <conio.h> //provides non standard getch() function
using namespace std;
int main()
{
cout << "Password: ";
string pass;
while(true)
{
char ch = getch();
if(ch=='\r'){ //when a carriage return is found [enter] key
cout << endl << "Your password is: " << pass <<endl;
break;
}
pass+=ch;
cout << "*";
}
getch();
return 0;
}
I've had this problem/question come up in an assignment that I'm currently working on.
It also depends on which input you are grabbing from.
I am using
/dev/tty
to get input while the program is running, so that needs to be the filestream associated with the command.
On the ubuntu machine I have to test/target, it required more than just
system( "stty -raw" );
or
system( "stty -icanon" );
I had to add the --file flag, as well as path to the command, like so:
system( "/bin/stty --file=/dev/tty -icanon" );
Everything is copacetic now.
This code worked for me. Attention : this is not part of the standard library, even if most compilers (I use GCC) supports it.
#include <stdio.h>
#include <conio.h>
int main(int argc, char const *argv[]) {
char a = getch();
printf("You typed a char with an ASCII value of %d, printable as '%c'\n", a, a);
return 0;
}
This code detects the first key press.
Can create a new function that checks for Enter:
#include <stdio.h>
char getChar()
{
printf("Please enter a char:\n");
char c = getchar();
if (c == '\n')
{
c = getchar();
}
return c;
}
int main(int argc, char *argv[])
{
char ch;
while ((ch = getChar()) != '.')
{
printf("Your char: %c\n", ch);
}
return 0;
}
By default, the C library buffers the output until it sees a return. To print out the results immediately, use fflush:
while((c=getchar())!= EOF)
{
putchar(c);
fflush(stdout);
}
you can use _getch() instead of getch() from <conio.h>

pre-fill stdin in C

My program is supposed to let the user edit a line of a file. The user edits the line and sends it back by pressing enter. Therefore I would like to print the current line which is about to be edited, but kind of print it on stdin instead of stdout.
The only problem I don't know how to solve is how I can prefill the stdin. I've already tried this:
char cprefill[] = {"You may edit this line"};
char cbuffer[100];
fprintf(stdin, cprefill);
fgets(cbuffer, 100, stdin);
This seems to be the simplest solution, but is probably too simple to work. The fprintf doesn't print anything to stdin. What is the correct way?
Edit:
This is how it is supposed to look like. Please mind the cursor which can be moved.
The C language has no notion of terminal nor of line edition, so it cannot be done in a portable way. You can either rely on a library like [n]curses to get an almost portable solution, or if you only need that on one single OS use low level OS primitives.
For exemple on Windows, you could feed the input buffer by simulating key strokes into the appropriate window (for example by sending WM_CHAR messages) just before reading, but that would be highly non portable - and in the end is no longer a C but a Windows solution...
First you need the libreadline developer package. (You might also need the libreadline if it's not already available on your system)
On Debian / Ubuntu that's apt install libreadline-dev (plus libreadline6 if you need the binaries also - 6 might be different on your platform)
Then you can add an history to readline, like this
#include <stdio.h>
#include <readline/readline.h>
#include <readline/history.h>
...
char cprefill[] = {"You may edit this line"};
add_history(cprefill);
char *buf = readline("Line: ");
printf("Edited line is %s\n", buf);
// free the line allocated by readline
free(buf);
User is prompted "Line: ", and has to do UP ARROW to get and edit the history, i.e. the cprefill line.
Note that you have to compile/link with -lreadline
readline prints the prompt given as argument, then waits for user interaction, allowing line edition, and arrows to load lines stored in the history.
The char * returned by readline has then to be freed (since that function allocates a buffer with malloc()).
You could use GNU Readline. It calls the function that rl_startup_hook points to when starting, where we use rl_insert_text to put our text in the line buffer.
#include <stdio.h>
#include <stdlib.h>
#include <readline/readline.h>
int prefill(void)
{
rl_insert_text("You may edit this line");
return 0;
}
int main(void)
{
char *cbuffer;
puts("Please edit the following line");
rl_startup_hook = prefill;
if ((cbuffer = readline(NULL)) == NULL) /* if the user sends EOF, readline will return NULL */
return 1;
printf("You entered: %s\n", cbuffer);
free(cbuffer);
return 0;
}
For more information, see the GNU Readline manual.

Printf number of character in C [duplicate]

In the next code:
#include <stdio.h>
int main(void) {
int c;
while ((c=getchar())!= EOF)
putchar(c);
return 0;
}
I have to press Enter to print all the letters I entered with getchar, but I don't want to do this, what I want to do is to press the letter and immediately see the the letter I introduced repeated without pressing Enter. For example, if I press the letter 'a' I want to see an other 'a' next to it, and so on:
aabbccddeeff.....
But when I press 'a' nothing happens, I can write other letters and the copy appears only when I press Enter:
abcdef
abcdef
How can I do this?
I am using the command cc -o example example.c under Ubuntu for compiling.
This depends on your OS, if you are in a UNIX like environment the ICANON flag is enabled by default, so input is buffered until the next '\n' or EOF. By disabling the canonical mode you will get the characters immediately. This is also possible on other platforms, but there is no straight forward cross-platform solution.
EDIT: I see you specified that you use Ubuntu. I just posted something similar yesterday, but be aware that this will disable many default behaviors of your terminal.
#include<stdio.h>
#include <termios.h> //termios, TCSANOW, ECHO, ICANON
#include <unistd.h> //STDIN_FILENO
int main(void){
int c;
static struct termios oldt, newt;
/*tcgetattr gets the parameters of the current terminal
STDIN_FILENO will tell tcgetattr that it should write the settings
of stdin to oldt*/
tcgetattr( STDIN_FILENO, &oldt);
/*now the settings will be copied*/
newt = oldt;
/*ICANON normally takes care that one line at a time will be processed
that means it will return if it sees a "\n" or an EOF or an EOL*/
newt.c_lflag &= ~(ICANON);
/*Those new settings will be set to STDIN
TCSANOW tells tcsetattr to change attributes immediately. */
tcsetattr( STDIN_FILENO, TCSANOW, &newt);
/*This is your part:
I choose 'e' to end input. Notice that EOF is also turned off
in the non-canonical mode*/
while((c=getchar())!= 'e')
putchar(c);
/*restore the old settings*/
tcsetattr( STDIN_FILENO, TCSANOW, &oldt);
return 0;
}
You will notice, that every character appears twice. This is because the input is immediately echoed back to the terminal and then your program puts it back with putchar() too. If you want to disassociate the input from the output, you also have to turn of the ECHO flag. You can do this by simply changing the appropriate line to:
newt.c_lflag &= ~(ICANON | ECHO);
On a linux system, you can modify terminal behaviour using the stty command. By default, the terminal will buffer all information until Enter is pressed, before even sending it to the C program.
A quick, dirty, and not-particularly-portable example to change the behaviour from within the program itself:
#include<stdio.h>
#include<stdlib.h>
int main(void){
int c;
/* use system call to make terminal send all keystrokes directly to stdin */
system ("/bin/stty raw");
while((c=getchar())!= '.') {
/* type a period to break out of the loop, since CTRL-D won't work raw */
putchar(c);
}
/* use system call to set terminal behaviour to more normal behaviour */
system ("/bin/stty cooked");
return 0;
}
Please note that this isn't really optimal, since it just sort of assumes that stty cooked is the behaviour you want when the program exits, rather than checking what the original terminal settings were. Also, since all special processing is skipped in raw mode, many key sequences (such as CTRL-C or CTRL-D) won't actually work as you expect them to without explicitly processing them in the program.
You can man stty for more control over the terminal behaviour, depending exactly on what you want to achieve.
getchar() is a standard function that on many platforms requires you to press ENTER to get the input, because the platform buffers input until that key is pressed. Many compilers/platforms support the non-standard getch() that does not care about ENTER (bypasses platform buffering, treats ENTER like just another key).
I/O is an operating system function. In many cases, the operating system won't pass typed character to a program until ENTER is pressed. This allows the user to modify the input (such as backspacing and retyping) before sending it to the program. For most purposes, this works well, presents a consistent interface to the user, and relieves the program from having to deal with this. In some cases, it's desirable for a program to get characters from keys as they are pressed.
The C library itself deals with files, and doesn't concern itself with how data gets into the input file. Therefore, there's no way in the language itself to get keys as they are pressed; instead, this is platform-specific. Since you haven't specified OS or compiler, we can't look it up for you.
Also, the standard output is normally buffered for efficiency. This is done by the C libraries, and so there is a C solution, which is to fflush(stdout); after each character written. After that, whether the characters are displayed immediately is up to the operating system, but all the OSes I'm familiar with will display the output immediately, so that's not normally a problem.
I like Lucas answer, but I would like to elaborate it a bit. There is a built-in function in termios.h named cfmakeraw() which man describes as:
cfmakeraw() sets the terminal to something like the "raw" mode of the
old Version 7 terminal driver: input is available character by
character, echoing is disabled, and all special processing of
terminal input and output characters is disabled. [...]
This basically does the same as what Lucas suggested and more, you can see the exact flags it sets in the man pages: termios(3).
Use case
int c = 0;
static struct termios oldTermios, newTermios;
tcgetattr(STDIN_FILENO, &oldTermios);
newTermios = oldTermios;
cfmakeraw(&newTermios);
tcsetattr(STDIN_FILENO, TCSANOW, &newTermios);
c = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldTermios);
switch (c) {
case 113: // q
printf("\n\n");
exit(0);
break;
case 105: // i
printf("insert\n");
break;
default:
break;
Since you are working on a Unix derivative (Ubuntu), here is one way to do it - not recommended, but it will work (as long as you can type commands accurately):
echo "stty -g $(stty -g)" > restore-sanity
stty cbreak
./your_program
Use interrupt to stop the program when you are bored with it.
sh restore-sanity
The 'echo' line saves the current terminal settings as a shell script that will restore them.
The 'stty' line turns off most of the special processing (so Control-D has no effect, for example) and sends characters to the program as soon as they are available. It means you cannot edit your typing any more.
The 'sh' line reinstates your original terminal settings.
You can economize if 'stty sane' restores your settings sufficiently accurately for your purposes. The format of '-g' is not portable across versions of 'stty' (so what is generated on Solaris 10 won't work on Linux, or vice versa), but the concept works everywhere. The 'stty sane' option is not universally available, AFAIK (but is on Linux).
You could include the 'ncurses' library, and use getch() instead of getchar().
"How to avoid pressing Enter with getchar()?"
First of all, terminal input is commonly either line or fully buffered. This means that the operating system stores the actual input from the terminal in a buffer. Usually, this buffer is flushed to the program when e.g. \n was signalized/provided in stdin. This is f.e. made by a press to Enter.
getchar() is just at the end of the chain. It has no ability to actually influence the buffering process.
"How can I do this?"
Ditch getchar() in the first place, if you don´t want to use specific system calls to change the behavior of the terminal explicitly like well explained in the other answers.
There is unfortunately no standard library function and with that no portable way to flush the buffer at single character input. However, there are implementation-based and non-portable solutions.
In Windows/MS-DOS, there are the getch() and getche() functions in the conio.h header file, which do exactly the thing you want - read a single character without the need to wait for the newline to flush the buffer.
The main difference between getch() and getche() is that getch() does not immediately output the actual input character in the console, while getche() does. The additional "e" stands for echo.
Example:
#include <stdio.h>
#include <conio.h>
int main (void)
{
int c;
while ((c = getche()) != EOF)
{
if (c == '\n')
{
break;
}
printf("\n");
}
return 0;
}
In Linux, a way to obtain direct character processing and output is to use the cbreak() and echo() options and the getch() and refresh() routines in the ncurses-library.
Note, that you need to initialize the so called standard screen with the initscr() and close the same with the endwin() routines.
Example:
#include <stdio.h>
#include <ncurses.h>
int main (void)
{
int c;
cbreak();
echo();
initscr();
while ((c = getch()) != ERR)
{
if (c == '\n')
{
break;
}
printf("\n");
refresh();
}
endwin();
return 0;
}
Note: You need to invoke the compiler with the -lncurses option, so that the linker can search and find the ncurses-library.
yes you can do this on windows too, here's the code below, using the conio.h library
#include <iostream> //basic input/output
#include <conio.h> //provides non standard getch() function
using namespace std;
int main()
{
cout << "Password: ";
string pass;
while(true)
{
char ch = getch();
if(ch=='\r'){ //when a carriage return is found [enter] key
cout << endl << "Your password is: " << pass <<endl;
break;
}
pass+=ch;
cout << "*";
}
getch();
return 0;
}
I've had this problem/question come up in an assignment that I'm currently working on.
It also depends on which input you are grabbing from.
I am using
/dev/tty
to get input while the program is running, so that needs to be the filestream associated with the command.
On the ubuntu machine I have to test/target, it required more than just
system( "stty -raw" );
or
system( "stty -icanon" );
I had to add the --file flag, as well as path to the command, like so:
system( "/bin/stty --file=/dev/tty -icanon" );
Everything is copacetic now.
This code worked for me. Attention : this is not part of the standard library, even if most compilers (I use GCC) supports it.
#include <stdio.h>
#include <conio.h>
int main(int argc, char const *argv[]) {
char a = getch();
printf("You typed a char with an ASCII value of %d, printable as '%c'\n", a, a);
return 0;
}
This code detects the first key press.
Can create a new function that checks for Enter:
#include <stdio.h>
char getChar()
{
printf("Please enter a char:\n");
char c = getchar();
if (c == '\n')
{
c = getchar();
}
return c;
}
int main(int argc, char *argv[])
{
char ch;
while ((ch = getChar()) != '.')
{
printf("Your char: %c\n", ch);
}
return 0;
}
By default, the C library buffers the output until it sees a return. To print out the results immediately, use fflush:
while((c=getchar())!= EOF)
{
putchar(c);
fflush(stdout);
}
you can use _getch() instead of getch() from <conio.h>

C - Flush stdin input buffer without 'enter' [duplicate]

In the next code:
#include <stdio.h>
int main(void) {
int c;
while ((c=getchar())!= EOF)
putchar(c);
return 0;
}
I have to press Enter to print all the letters I entered with getchar, but I don't want to do this, what I want to do is to press the letter and immediately see the the letter I introduced repeated without pressing Enter. For example, if I press the letter 'a' I want to see an other 'a' next to it, and so on:
aabbccddeeff.....
But when I press 'a' nothing happens, I can write other letters and the copy appears only when I press Enter:
abcdef
abcdef
How can I do this?
I am using the command cc -o example example.c under Ubuntu for compiling.
This depends on your OS, if you are in a UNIX like environment the ICANON flag is enabled by default, so input is buffered until the next '\n' or EOF. By disabling the canonical mode you will get the characters immediately. This is also possible on other platforms, but there is no straight forward cross-platform solution.
EDIT: I see you specified that you use Ubuntu. I just posted something similar yesterday, but be aware that this will disable many default behaviors of your terminal.
#include<stdio.h>
#include <termios.h> //termios, TCSANOW, ECHO, ICANON
#include <unistd.h> //STDIN_FILENO
int main(void){
int c;
static struct termios oldt, newt;
/*tcgetattr gets the parameters of the current terminal
STDIN_FILENO will tell tcgetattr that it should write the settings
of stdin to oldt*/
tcgetattr( STDIN_FILENO, &oldt);
/*now the settings will be copied*/
newt = oldt;
/*ICANON normally takes care that one line at a time will be processed
that means it will return if it sees a "\n" or an EOF or an EOL*/
newt.c_lflag &= ~(ICANON);
/*Those new settings will be set to STDIN
TCSANOW tells tcsetattr to change attributes immediately. */
tcsetattr( STDIN_FILENO, TCSANOW, &newt);
/*This is your part:
I choose 'e' to end input. Notice that EOF is also turned off
in the non-canonical mode*/
while((c=getchar())!= 'e')
putchar(c);
/*restore the old settings*/
tcsetattr( STDIN_FILENO, TCSANOW, &oldt);
return 0;
}
You will notice, that every character appears twice. This is because the input is immediately echoed back to the terminal and then your program puts it back with putchar() too. If you want to disassociate the input from the output, you also have to turn of the ECHO flag. You can do this by simply changing the appropriate line to:
newt.c_lflag &= ~(ICANON | ECHO);
On a linux system, you can modify terminal behaviour using the stty command. By default, the terminal will buffer all information until Enter is pressed, before even sending it to the C program.
A quick, dirty, and not-particularly-portable example to change the behaviour from within the program itself:
#include<stdio.h>
#include<stdlib.h>
int main(void){
int c;
/* use system call to make terminal send all keystrokes directly to stdin */
system ("/bin/stty raw");
while((c=getchar())!= '.') {
/* type a period to break out of the loop, since CTRL-D won't work raw */
putchar(c);
}
/* use system call to set terminal behaviour to more normal behaviour */
system ("/bin/stty cooked");
return 0;
}
Please note that this isn't really optimal, since it just sort of assumes that stty cooked is the behaviour you want when the program exits, rather than checking what the original terminal settings were. Also, since all special processing is skipped in raw mode, many key sequences (such as CTRL-C or CTRL-D) won't actually work as you expect them to without explicitly processing them in the program.
You can man stty for more control over the terminal behaviour, depending exactly on what you want to achieve.
getchar() is a standard function that on many platforms requires you to press ENTER to get the input, because the platform buffers input until that key is pressed. Many compilers/platforms support the non-standard getch() that does not care about ENTER (bypasses platform buffering, treats ENTER like just another key).
I/O is an operating system function. In many cases, the operating system won't pass typed character to a program until ENTER is pressed. This allows the user to modify the input (such as backspacing and retyping) before sending it to the program. For most purposes, this works well, presents a consistent interface to the user, and relieves the program from having to deal with this. In some cases, it's desirable for a program to get characters from keys as they are pressed.
The C library itself deals with files, and doesn't concern itself with how data gets into the input file. Therefore, there's no way in the language itself to get keys as they are pressed; instead, this is platform-specific. Since you haven't specified OS or compiler, we can't look it up for you.
Also, the standard output is normally buffered for efficiency. This is done by the C libraries, and so there is a C solution, which is to fflush(stdout); after each character written. After that, whether the characters are displayed immediately is up to the operating system, but all the OSes I'm familiar with will display the output immediately, so that's not normally a problem.
I like Lucas answer, but I would like to elaborate it a bit. There is a built-in function in termios.h named cfmakeraw() which man describes as:
cfmakeraw() sets the terminal to something like the "raw" mode of the
old Version 7 terminal driver: input is available character by
character, echoing is disabled, and all special processing of
terminal input and output characters is disabled. [...]
This basically does the same as what Lucas suggested and more, you can see the exact flags it sets in the man pages: termios(3).
Use case
int c = 0;
static struct termios oldTermios, newTermios;
tcgetattr(STDIN_FILENO, &oldTermios);
newTermios = oldTermios;
cfmakeraw(&newTermios);
tcsetattr(STDIN_FILENO, TCSANOW, &newTermios);
c = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldTermios);
switch (c) {
case 113: // q
printf("\n\n");
exit(0);
break;
case 105: // i
printf("insert\n");
break;
default:
break;
Since you are working on a Unix derivative (Ubuntu), here is one way to do it - not recommended, but it will work (as long as you can type commands accurately):
echo "stty -g $(stty -g)" > restore-sanity
stty cbreak
./your_program
Use interrupt to stop the program when you are bored with it.
sh restore-sanity
The 'echo' line saves the current terminal settings as a shell script that will restore them.
The 'stty' line turns off most of the special processing (so Control-D has no effect, for example) and sends characters to the program as soon as they are available. It means you cannot edit your typing any more.
The 'sh' line reinstates your original terminal settings.
You can economize if 'stty sane' restores your settings sufficiently accurately for your purposes. The format of '-g' is not portable across versions of 'stty' (so what is generated on Solaris 10 won't work on Linux, or vice versa), but the concept works everywhere. The 'stty sane' option is not universally available, AFAIK (but is on Linux).
You could include the 'ncurses' library, and use getch() instead of getchar().
"How to avoid pressing Enter with getchar()?"
First of all, terminal input is commonly either line or fully buffered. This means that the operating system stores the actual input from the terminal in a buffer. Usually, this buffer is flushed to the program when e.g. \n was signalized/provided in stdin. This is f.e. made by a press to Enter.
getchar() is just at the end of the chain. It has no ability to actually influence the buffering process.
"How can I do this?"
Ditch getchar() in the first place, if you don´t want to use specific system calls to change the behavior of the terminal explicitly like well explained in the other answers.
There is unfortunately no standard library function and with that no portable way to flush the buffer at single character input. However, there are implementation-based and non-portable solutions.
In Windows/MS-DOS, there are the getch() and getche() functions in the conio.h header file, which do exactly the thing you want - read a single character without the need to wait for the newline to flush the buffer.
The main difference between getch() and getche() is that getch() does not immediately output the actual input character in the console, while getche() does. The additional "e" stands for echo.
Example:
#include <stdio.h>
#include <conio.h>
int main (void)
{
int c;
while ((c = getche()) != EOF)
{
if (c == '\n')
{
break;
}
printf("\n");
}
return 0;
}
In Linux, a way to obtain direct character processing and output is to use the cbreak() and echo() options and the getch() and refresh() routines in the ncurses-library.
Note, that you need to initialize the so called standard screen with the initscr() and close the same with the endwin() routines.
Example:
#include <stdio.h>
#include <ncurses.h>
int main (void)
{
int c;
cbreak();
echo();
initscr();
while ((c = getch()) != ERR)
{
if (c == '\n')
{
break;
}
printf("\n");
refresh();
}
endwin();
return 0;
}
Note: You need to invoke the compiler with the -lncurses option, so that the linker can search and find the ncurses-library.
yes you can do this on windows too, here's the code below, using the conio.h library
#include <iostream> //basic input/output
#include <conio.h> //provides non standard getch() function
using namespace std;
int main()
{
cout << "Password: ";
string pass;
while(true)
{
char ch = getch();
if(ch=='\r'){ //when a carriage return is found [enter] key
cout << endl << "Your password is: " << pass <<endl;
break;
}
pass+=ch;
cout << "*";
}
getch();
return 0;
}
I've had this problem/question come up in an assignment that I'm currently working on.
It also depends on which input you are grabbing from.
I am using
/dev/tty
to get input while the program is running, so that needs to be the filestream associated with the command.
On the ubuntu machine I have to test/target, it required more than just
system( "stty -raw" );
or
system( "stty -icanon" );
I had to add the --file flag, as well as path to the command, like so:
system( "/bin/stty --file=/dev/tty -icanon" );
Everything is copacetic now.
This code worked for me. Attention : this is not part of the standard library, even if most compilers (I use GCC) supports it.
#include <stdio.h>
#include <conio.h>
int main(int argc, char const *argv[]) {
char a = getch();
printf("You typed a char with an ASCII value of %d, printable as '%c'\n", a, a);
return 0;
}
This code detects the first key press.
Can create a new function that checks for Enter:
#include <stdio.h>
char getChar()
{
printf("Please enter a char:\n");
char c = getchar();
if (c == '\n')
{
c = getchar();
}
return c;
}
int main(int argc, char *argv[])
{
char ch;
while ((ch = getChar()) != '.')
{
printf("Your char: %c\n", ch);
}
return 0;
}
By default, the C library buffers the output until it sees a return. To print out the results immediately, use fflush:
while((c=getchar())!= EOF)
{
putchar(c);
fflush(stdout);
}
you can use _getch() instead of getch() from <conio.h>

Resources