CMD Prompt C++: Limiting literals entered on screen - c++

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.

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.

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

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;
}

Let user type in the middle of string (c/c++)?

Normally c/cpp string displayed in console only allows user to type after it.
Is there any simple way to let user to type in the middle of the output string, e.g fill in the blank:
Mr ____ is the teacher.
std::cout can print it easily, but how to let user type directly in the blank with simple code and read it? And e.g. if the name is long the move the printed character to the right?
You're looking for controlling a console/terminal. Neither of the languages you ask about has any notion of that -- they both only know streams of input and output. This is a simple abstraction, input and output are done character by character, in sequence. Input doesn't have to come from a keyboard, output doesn't have to be a screen or terminal ...
Controlling the contents of a screen is very platform-dependent. If you are on windows, the windows API provides a bunch of functions for controlling a console.
If you want to do something cross-platform, have a look at curses. There are implementations for many platforms, like ncurses (often used on *nix systems) and pdcurses (which is quite good for windows) and they all provide the same interface.
To learn about curses programming, the NCURSES Programming HOWTO is a good start. Just replace #include <ncurses.h> with #include <curses.h> so your code isn't tied specifically to ncurses but works with any curses implementation.
Yes, you can absolutely do this (I mean, ever played snake? All games were on terminals back then, and your problem is much simpler than writing a game).
A trick is using \r, which is a carriage return. That character will slide you back to the start of the line, allowing you to overwrite the previous string. This is commonly used for loading animations like
[---]
[=---]
[==-]
[===]
To prevent forcing the user to hit enter before sending data, I'll show a Linux/Mac solution.
system("/bin/stty raw"); // Get keystrokes immediately, #include <stdlib.h>
string s;
char c;
cout << "Mr _ is the teacher." << flush;
while( c = getchar() ) { // #include <stdio.h>
if( c == 3 ) // CTRL+C
exit(1);
if( c == 13 ) { // Newline
cout << endl;
break;
}
if( c == 127 ) { // Backspace
if( s.size() > 0 )
s.pop_back();
} else {
s += c;
}
cout << "\r"; // Reset the cursor
cout << "Mr " << s << "_ is the teacher. " << flush; // Spaces to cover invalid backspace character
cout << "\r"; // Reset the cursor
cout << "Mr " << s << "_ is the teacher." << flush;
}
system("/bin/stty cooked"); // Go back to buffered input
This can be done in Windows by importing #include<conio.h>, and then using getch() instead of getchar(). (You don't need any stty system commands)
Make sure to use your platform-specific #ifdef's to make your code portable!

Reading a huge text

I am trying to read a file like I use option more in Linux. I am just trying to make almost the same realization of more.
My problem is when I read file in order like:
aaaaaaaaaaaaaaaaaaaa
bbbbbbbbbbbbbbbbbbbbb
.....................
ccccccccccccccccccccc
For, example: I have 100 strings in txt.file, in order which I showed you. So every string does not exceed the horizontal size of the console and goes after ENTER.
The program works excellent. I mean, if my information of a txt.file does not show fully, I just press SPACE and see another screen of my information from a file.
But if I put a huge text with long strings, It just read a file fully and shows me the end of the file.
What do I do wrong with this? Might I not considered the horizontal size of a console? But I think, Linux thinks for me in this case.. Can you help me with this?
My arguments are:./more 0 1.txt
./more - make file, 0- I beging on this string, 1.txt -file name.
My code :
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <sys/ioctl.h>
#include <unistd.h>
#include <termios.h>
int getch();
void printRecord(int& numStr,struct winsize w, std::vector<std::string>& lines);
int main(int argc, char *argv[]) {
struct winsize w;
char ch;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
std::ifstream readRecord;
std::vector<std::string> lines;
std::string str;
readRecord.open(argv[2]);
int numStr= atoi(argv[1]);
while (!readRecord.eof())
{
getline(readRecord, str);
str.size();
lines.push_back(str);
}
printRecord(numStr,w, lines);
ch=getch();
while(ch!='q'){
if (ch==32)
{
numStr--;
printRecord(numStr,w,lines);
}
if (numStr>=lines.size()){
break;}
ch=getch();
}
return 0;
}
void printRecord(int& numStr,struct winsize w,std::vector<std::string>& lines)
{
for (int i = numStr; i < numStr + w.winsize::ws_row-1; i++)
{
if (i>=lines.size())
break;
else
std::cout << lines[i] << std::endl;
}
numStr += w.winsize::ws_row;
}
int getch()
{
int ch;
struct termios oldt, newt;
tcgetattr( STDIN_FILENO, &oldt );
newt = oldt;
newt.c_lflag &= ~( ICANON | ECHO );
tcsetattr( STDIN_FILENO, TCSANOW, &newt );
ch = getchar();
tcsetattr( STDIN_FILENO, TCSANOW, &oldt );
return ch;
}
No, Linux doesn't "thinks for me in this case." If your code prints out the contents of the file, as is, then the contents of the file get printed to standard output. If the terminal is not big enough to show the contents of the file, only whatever fits on the screen will remain at the end. As the contents of the file get printed, the initial parts of the file will briefly appear, before the display scrolls off.
The terminal is not going to automatically paginate your program's output for you. That's the real more's job. If you want to replicate more's functionality, you must do it yourself.
Your program can obtain the size of the terminal display by making the TIOCGWINSZ ioctl, as explained in the tty_ioctl(4) manual page, that you should read. After obtaining the terminal's size, it is going to be up to your program to calculate how much of the file's contents will fit on the screen, and to paginate it properly.
Things get complicated rather quickly, if you have to deal with multibyte UTF-8-encoded content, not to mention double-wide characters if your output contains certain Asian character sets. Computing the actual size of printed text, in the age of internationalization and localization, is surprisingly difficult. But, for plain Latin text, this should be sufficient. You should also set up a signal handler for SIGWINCH, as explained in that manual page, to detect changes to the terminal size, so that you can repaginate the contents of the file accordingly.
You can also consider using a higher-level library, like curses, which might be useful in this case.