C++ interactive command line prompt without waiting for a newline character - c++

Is there a way to process command line input before seeing the newline character? I'm thinking of making a program that supports autocomplete (like the ones found in search engines or iOS keyboard).
To be more specific, my program will prompt for user input when started, and for each character input, I would like to output something BEFORE the newline character(or EOF) is input.
The following code snippet is what I have tried:
int main(){
char ch;
while ( (ch = cin.get()) != cin.eof() )
{
cout << ch << flush;
}
}
expected: for each character input, output that character.
actual: does not output anything UNTIL the program sees an eof.

In a Unix-like system, you can achieve this by changing the terminal to non-canonical input mode. Terminal supports canonical input which gathers the entire line for editing until the end of line character or Ctrl-D is pressed. As a result, the application often sees whole line on the read() system calls. On the other hand, non-canonical input does no line buffering; the input characters are made available to the program as soon as they are typed.
Here is a Linux C/C++ example of how to set -icanon flag (non-canonical) programmatically.
#include <iostream>
#include <termios.h>
#include <unistd.h>
int main() {
struct termios old_tio, new_tio;
tcgetattr(STDIN_FILENO, &old_tio);
new_tio = old_tio;
new_tio.c_lflag &= (~ICANON);
tcsetattr(STDIN_FILENO, TCSANOW, &new_tio);
char c;
while (fread(&c, 1, 1, stdin))
std::cout << c << std::endl;
return 0;
}

Related

How to read data from stdin without waiting for a newline character [duplicate]

Is there a way to process command line input before seeing the newline character? I'm thinking of making a program that supports autocomplete (like the ones found in search engines or iOS keyboard).
To be more specific, my program will prompt for user input when started, and for each character input, I would like to output something BEFORE the newline character(or EOF) is input.
The following code snippet is what I have tried:
int main(){
char ch;
while ( (ch = cin.get()) != cin.eof() )
{
cout << ch << flush;
}
}
expected: for each character input, output that character.
actual: does not output anything UNTIL the program sees an eof.
In a Unix-like system, you can achieve this by changing the terminal to non-canonical input mode. Terminal supports canonical input which gathers the entire line for editing until the end of line character or Ctrl-D is pressed. As a result, the application often sees whole line on the read() system calls. On the other hand, non-canonical input does no line buffering; the input characters are made available to the program as soon as they are typed.
Here is a Linux C/C++ example of how to set -icanon flag (non-canonical) programmatically.
#include <iostream>
#include <termios.h>
#include <unistd.h>
int main() {
struct termios old_tio, new_tio;
tcgetattr(STDIN_FILENO, &old_tio);
new_tio = old_tio;
new_tio.c_lflag &= (~ICANON);
tcsetattr(STDIN_FILENO, TCSANOW, &new_tio);
char c;
while (fread(&c, 1, 1, stdin))
std::cout << c << std::endl;
return 0;
}

Reading large strings in c++ [duplicate]

I am trying to read in a string of length in 10^5 order. I get incorrect string if the size of string grows beyond 4096.
I am using the following code
string a;
cin>>a;
This didn't work then I tried reading character by character by following code
unsigned char c;
vector<unsigned char> a;
while(count>0){
c = getchar();
a.push_back(c);
count--;
}
I have done necessary escaping for using getchar this also had the 4096 bytes problem. Can someone suggest a workaround or point to correct way of reading it.
It is because your terminal inputs are buffered in the I/O queue of the kernel.
Input and output queues of a terminal device implement a form of buffering within the kernel independent of the buffering implemented by I/O streams.
The terminal input queue is also sometimes referred to as its typeahead buffer. It holds the characters that have been received from the terminal but not yet read by any process.
The size of the input queue is described by the MAX_INPUT and _POSIX_MAX_INPUT parameters;
By default, your terminal is in Canonical mode.
In canonical mode, all input stays in the queue until a newline character is received, so the terminal input queue can fill up when you type a very long line.
We can change the input mode of terminal from canonical mode to non-canonical mode.
You can do it from terminal:
$ stty -icanon (change the input mode to non-canonical)
$ ./a.out (run your program)
$ stty icanon (change it back to canonical)
Or you can also do it programatically,
To change the input mode programatically we have to use low level terminal interface.
So you can do something like:
#include <iostream>
#include <string>
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
int clear_icanon(void)
{
struct termios settings;
int result;
result = tcgetattr (STDIN_FILENO, &settings);
if (result < 0)
{
perror ("error in tcgetattr");
return 0;
}
settings.c_lflag &= ~ICANON;
result = tcsetattr (STDIN_FILENO, TCSANOW, &settings);
if (result < 0)
{
perror ("error in tcsetattr");
return 0;
}
return 1;
}
int main()
{
clear_icanon(); // Changes terminal from canonical mode to non canonical mode.
std::string a;
std::cin >> a;
std::cout << a.length() << std::endl;
}
Using this test-program based on what you posted:
#include <iostream>
#include <string>
int main()
{
std::string a;
std::cin >> a;
std::cout << a.length() << std::endl;
}
I can do:
./a.out < fact100000.txt
and get the output:
456574
However, if I copy'n'paste from an editor to the console, it stops at 4095. I expect that's a limit somewhere in the consoles copy'n'paste handling. The easy solution to that is of course to not use copy'n'paste, but redirect from a file. On some other systems, the restruction to 4KB of input may of course reside somewhere else. (Note that, at least on my system, I can happily copy and paste the 450KB of factorial result to another editor window, so in my system it's simply the console buffer that is the problem).
This is much more likely to be a platform/OS problem than a C++ problem. What OS are you using, and what method are you using to get the string fed to stdin? It's pretty common for command-line arguments to be capped at a certain size.
In particular, given that you've tried reading one character at a time, and it still didn't work, this seems like a problem with getting the string to the program, rather than a C++ issue.

CMD Prompt C++: Limiting literals entered on screen

I hope the question isn't to ambiguous.
when I ask:
int main()
{
string name = {""};
cout << "Please enter a name: " << endl;
getline(cin, name);
//user enters 12 characters stop displaying next literal keypresses.
enter code here
}
I would like to be able to limit the amount of times the user can enter a char on screen. Example, the screen stops displaying characters after length 12?
If so what would be the library and command line for doing something like this?
Wanting to this as, I have a ascii art drawn on the CMD, and when I cout the statement at x,y anything over 12 characters long inputed draws over the ascii art.
I hope this makes sense :'{ Thank you!
By default the console is in cooked mode (canonical mode, line mode, ...). This means
that the console driver is buffering data before it hands it to your application
characters will be automatically echoed back to the console by the console driver
Normally, this means that your program only ever gets hold of the input after a line ends, i.e. when enter is pressed. Because of the auto-echo, those character are then already on screen.
Both settings can be changed independently, however the mechanism is --unfortunately-- an OS-specific call:
For Window it's SetConsoleMode():
HANDLE h_stdin = GetStdHandle(STD_INPUT_HANDLE);
DWORD mode = 0;
// get chars immediately
GetConsoleMode(hStdin, &mode);
SetConsoleMode(hStdin, mode & ~ENABLE_LINE_INPUT));
// display input echo, set after 12th char.
GetConsoleMode(hStdin, &mode);
SetConsoleMode(hStdin, mode & ~ENABLE_ECHO_INPUT));
As noted by yourself, Windows still provides conio.h including a non-echoing _getch() (with underscore, nowadays). You can always use that and manually echo the characters. _getch() simply wraps the console line mode on/off, echo on/off switch into a function.
Edit: There is meant to be an example on the use of _getch(), here. I'm a little to busy to get it done properly, I refrained from posting potentially buggy code.
Under *nix you will most likely want to use curses/termcap/terminfo. If you want a leaner approach, the low level routines are documented in termios/tty_ioctl:
#include <sys/types.h>
#include <termios.h>
struct termios tcattr;
// enable non-canonical mode, get raw chars as they are generated
tcgetattr(STDIN_FILENO, &tcattr);
tcattr.c_lflag &= ~ICANON;
tcsetattr(STDIN_FILENO, TCSAFLUSH, &tcattr);
// disable echo
tcgetattr(STDIN_FILENO, &tcattr);
tcattr.c_lflag &= ~ECHO;
tcsetattr(STDIN_FILENO, TCSAFLUSH, &tcattr);
You can use scanf("%c",&character) on a loop from 1 to 12 and append them to a pre-allocated buffer.
As in my comments, I mentioned a method I figured out using _getch(); and
displaying each char manually.
simplified version:
#include <iostream>
#include <string>
#include <conio.h>
using namespace std;
string name = "";
int main()
{
char temp;
cout << "Enter a string: ";
for (int i = 0; i < 12; i++) { //Replace 12 with character limit you want
temp = _getch();
name += temp;
cout << temp;
}
system("PAUSE");
}
This lets you cout each key-press as its pressed,
while concatenating each character pressed to a string called name.
Then later on in what ever program you use this in, you can display the full name as a single string type.

How to check if std::cin is associated with a terminal or a pipe

How is it possible to check if std::cin buffer is associated with a terminal or a pipe?
Command line which shows that std::cin is associated with a file:
Application.exe < C:\output.txt > C:\result.txt
Command line which shows std::cin associated with a terminal:
Application.exe
I tried to analyze in_avail() for this purpose. But it hasn't helped.
std::cin.rdbuf()->in_avail()
I found an answer to my question.
First of all I have to ask my question in a correct way.
Question I want to ask: How to figure out if std::cin is associated with a terminal or a pipe.
On Windows:
_isatty( _fileno(stdin) );
On POSIX:
isatty( fileno(stdin) );
On Windows:
_isatty call retursn non zero value if stdin is associated with a char device.
On POSIX:
isatty call returns 1 if stdin is referring to a terminal.
isatty man for Linux: http://man7.org/linux/man-pages/man3/isatty.3.html
_isatty man on MSDN: http://msdn.microsoft.com/en-us/library/f4s0ddew.aspx
From the reference of std::istream::peek:
If good() == true, returns the next character as obtained by rdbuf()->sgetc() Otherwise, returns Traits::eof().
This means that it will either return the next available character, or an eof flag.
And if will, if needed, cause the underlying buffers underflow function to be called which fills the buffer if there's anything to read from the operating system.
This will work for file input (and user input):
#include <iostream>
#include <sstream>
int main(int argc, const char * argv[])
{
typedef std::istream::traits_type Traits;
std::stringstream buffer;
Traits::int_type ch;
while((ch = std::cin.get()) != Traits::eof()) {
buffer << Traits::to_char_type(ch);
}
std::cout << buffer.str();
}
Having user input in a (linux) terminal a < ctrl-d > is needed to stop reading.
There is no other way (basically), to detect if cin has (will get) a character available (Although some protocol could handle the user input).

End of File(EOF) of Standard input stream (stdin)

Does stdin have any EOF? For example, if I start reading from stdin using fread or read, then will the following loop end?
while ((c = read(0, buffer, BUFSIZ)) > 0) {
.
.
.
}
If the answer to this question is no, then is there any way to add EOF to stdin?
Speaking about EOF in stdin: when you redirect input from file, e.g.:
program <input.txt
the file already has an EOF, so this is not a problem. In console you can simulate EOF flag. In UNIX systems it is Ctrl+D, in Windows Ctrl+Z. When you type this in the console, program will behave like it has just reached end of input file.
Edit
According to a question asked by OP:
So does it means that stdin don't have EOF and we have to insert them manually using Ctrl+Z or Ctrl+D?
Actually -- yes. One may consider stdin (not redirected, but taken from the console) as infinite file -- no one can tell where does it end. The end of input file, where input ist stdin, must be told literally by Ctrl+D or Ctrl+Z.
I have never programmed C in windows so I can't tell you but in bash, the program will get an EOF when you type end of data (Ctrl+D)
while ((c = read(0, buffer, BUFSIZ)) > 0) {
You don't say the type of c but using that name implies that it's a char. Note that the EOF value for iosteams is an (int) -1. Storing that into an unsigned char will get you a value of 255 which will not match EOF.
The way to test for EOF is to check the return value of fread, and then use feof:
while( fread( ... ) ) { // loop so long as fread does not return zero
// do something
}
if ( feof( stdin ) ) {
// read failed because of EOF
}
else {
// some other error
}
Your solution is tagged C++, so here's some C++.
std::string lols;
while(!(std::cin >> lols).eof()) { // This loop will end when EOF is reached
// Process string
}
First getchar() is really getc(stdin) so getc(FILE) you can read more from that. getchar() gets you last unprocessed character from input stream or stdin pressing enter is '\n'. if the stdin is empty getchar forces a pause to get input.
Say in a program I call getchar() at first the stdin is empty so it pauses for input. If I enter ab'\n' the first getchar() will get 97 the ascii of 'a'. the next time i call getchar() i will get b , then again getchar() will have '\n'.
To prove this write this code.
int choice;
do
{
cout << "Enter input:" ;
choice = getchar();
cout << "Last getchar(): " << choice << ":" << (char) choice ;
if( choice == '0' || choice == EOF)
{
cout << "Exited loop" << endl; // EOF is ctrl+z in windows
break;
}
}while(true);
I do believe stdin is a global so until getchar() or similar function gets called it to clear the stream the characters remain there which can cause bugs later if you use getchar() elsewhere. As people have mentioned you can use gets(char[]) which puts all characters until newline into the character array. The problem with this is you need a char[] larger than input or you will get errors. The nice thing is gets(char[]) does clear stdin so you can make a dumby buffer to clear stdin or process it.
I hope this is informative.