Read a string with ncurses in C++ - c++

I'm writing a text-based game in C++. At some point, I ask the user to input user names corresponding to the different players playing.
I'm currently reading single char from ncurses like so:
move(y,x);
printw("Enter a char");
int char = getch();
However, I'm not sure how to a string. I'm looking for something like:
move(y,x);
printw("Enter a name: ");
std::string name = getstring();
I've seen many different guides for using ncurses all using a different set of functions that the other doesn't. As far as I can tell the lines between deprecated and non-deprecated functions is not very well defined.

How about this?
std::string getstring()
{
std::string input;
// let the terminal do the line editing
nocbreak();
echo();
// this reads from buffer after <ENTER>, not "raw"
// so any backspacing etc. has already been taken care of
int ch = getch();
while ( ch != '\n' )
{
input.push_back( ch );
ch = getch();
}
// restore your cbreak / echo settings here
return input;
}
I would discourage using the alternative *scanw() function family. You would be juggling a temporary char [] buffer, the underlying *scanf() functionality with all its problems, plus the specification of *scanw() states it returns ERR or OK instead of the number of items scanned, further reducing its usefulness.
While getstr() (suggested by user indiv) looks better than *scanw() and does special handling of function keys, it would still require a temporary char [], and I try to avoid those in C++ code, if for nothing else but avoiding some arbitrary buffer size.

Related

read txt file in c++ (chinese)

I'm trying to develop function that check whether chinese word which user enters is in the txt file or not. The following is the code. But it is not working. I want to know what the problem is. Help me please.
setlocale(LC_ALL, "Chinese-simplified");
locale::global(locale("Chinese_China"));
SetConsoleOutputCP(936);
SetConsoleCP(936);
bool exist = FALSE;
cout << "\n\n <Find the keyword whether it is in that image or not> \n ";
cout << "Enter word to search for: ";
wstring search;
wcin >> search; //There is a problem to enter chinese.
wfstream file_text("./a.txt");
wstring line;
wstring::size_type pos;
while (getline(file_text, line))
{
pos = line.find(search);
if (pos != wstring::npos) // string::npos is returned if string is not found
{
cout << "Found!" << endl;
exist = true;
break;
}
}
when I use this code, The result is as follows.
const int oldMbcp = _getmbcp();
_setmbcp(936);
const std::locale locale("Chinese_China.936");
_setmbcp(oldMbcp);
If you're interested in more details, please see stod-does-not-work-correctly-with-boostlocale for a more detailed description of how locale works,
In a nutshell the more interesting part for you:
std::stream (stringstream, fstream, cin, cout) has an inner locale-object, which matches the value of the global C++ locale at the moment of the creation of the stream object. As std::in is created long before your code in main is called, it has most probably the classical C locale, no matter what you do afterwards.
you can make sure, that a std::stream object has the desirable locale by invoking std::stream::imbue(std::locale(your_favorit_locale)).
I would like to add the following:
It is almost never a good idea to set the global locale - it might break other parts of the program or third part libraries - you never know.
std::setlocale and locale::global do slightly different things, but locale::global resets not only the global c++-locale but also the c-locale (which is also set by std::setlocale, not to be confused with the classical "C" locale), so you should call it in another order if you want to have c++ locale set to Chinese_China and C locale to chinese-simplified
First
locale::global(locale("Chinese_China"));
And than
setlocale(LC_ALL, "Chinese-simplified");
Try locale::global(locale("Chinese_China.936")); or locale::global(locale(""));
And for LC_ALL "chinese-simplified" or "chs"
If using Vladislav's answer does not solve this, take a look at answer to stl - Shift-JIS decoding fails using wifstrem in Visual C++ 2013 - Stack Overflow:
const int oldMbcp = _getmbcp();
_setmbcp(936);
const std::locale locale("Chinese_China.936");
_setmbcp(oldMbcp);
There appears to be a bug in Visual Studio's implementation of locales. See also c++ - double byte character sequence conversion issue in Visual Studio 2015 - Stack Overflow.

In C++ while using cin.get(), how can I not limit the number of characters a user can enter?

Im trying to get a users input using cin.get() but I dont want to limit the amount of characters that they can enter. How can I do this?
EDIT: I guess a better way to phrase this would be: How can I dynamicaly change the character array to fit the length of the users input?
This is a strange requirement for a C++ program. You can of course go the C way and simply keep on getting more memory whenever your input outgrows the currently available memory. It goes something like this (warning: code fragments ahead):
while(cin.get(c)) {
if (cur_pos == cur_len) {
cur_len = grow_charbuf(buffer, cur_len);
}
buffer[cur_pos++] = c;
}
Here, the grow function is where it gets ugly. It needs to allocate a larger piece of memory, copy the contents of the current buffer to the beginning of that, dealocate the memory occupied by the current buffer, and return the new size. For example, something along these lines:
char* new_charbuf(size_t len) {
return new char [len];
}
size_t grow_charbuf(char* buf, size_t cur_len) {
size_t new_len = cur_len * 2;
char* new_buf = new char [new_len];
// copy old buffer contents to new buffer
delete[] buf;
buf = new_buf;
return new_len;
}
And you can then use it as follows:
cur_len = 1000; // or whatever
char* buffer = new_charbur(cur_len);
// write into the buffer, calling grow_charbuf() when necessary
// and don't forget to free the memory once you are done...
// or don't free it, if the program eventually exits anyway
This is terrible code. It might work, but you should never ever do this in C++ if you can avoid it. Apart from this, I have avoided handling any error conditions or exceptions that this code might cause. It is meant just to illustrate the idea.
Managing your memory manually is a bad idea because it requires a lot of code and is not easy to get right. You can get away with less if your program has a known, limited life-span.
Don't use characters array at all. Use std::string or other standard containers.
And of cause learn to use streams.
Here an example. It reads as many characters as the user inputs until the user presses enter. As you cna see, there is no explicite buffer-size required:
/////TEST PUT ANYWHERE IN GLOBAL SCOPE
#include <string>
#include <sstream>
#include <iostream>
using namespace std;
int test()
{
//SET BP HERE AND STEP THROUGH
string line;
getline(cin,line);
std::stringstream user_input( line );
while(!user_input.eof())
{
string word;
user_input >> word;
cout << word << endl;
}
return 0;
}
static int _test = test();
/////END TEST
You need a cin.getline(). In other words you need to have a specified size of char array and use it like so:
Using cin.get()
char str[100];
char sayHello[100];
cin.get(str, 100);
// make sure to add cin.ignore() or program will terminate right before next cin().
cin.ignore();
cout << str << endl;
cin.get(sayHello, 100);
cout << sayHello;
or for cin.getline()
char input[100];
cin.ignore(); // stops the sentence from truncating.
cin.getline(input,sizeof(input));
You could also use getline() for strings like so:
string name;
getline(cin, name);
The problem is that in c++ when receiving input your cin looks for the 0 aka the space in your sentence. It then ends thinking that was the end.

File Handling:What is the use of peek() function in c++?

As I have so much problem while dealing with the eof of a file, whenever I code with fstream and the eof appears I have to clear the stream in order to work with that stream. Although I have searched a lot about the eof and I got the result that I should start using:
fstream file("Filename.txt",ios::in|ios::ate|ios::out);
char str[80];
while(file>>str)
{
//do the required stuff
}
//clear the stream and reuse it
file.clear();
file.seekp(0);
But I have also read about a function called peek() which is also used for such purposes but I am a little confused in its working and I am not able to apply it in the code. So if anyone could guide me through this.
And I have also heard about a function called putback() what's that??
Edit-1
fstream file("Filename.txt",ios::in|ios::ate|ios::out);
char str[80];
while(file>>str)
{
//do the required stuff
}
//clear the stream and reuse it
file.clear();
file.seekp(0);
//Now do the required writing operation after reading the whole file wherever is required
//I also want to perform writing operations and if this pattern seems most suitable for me
Say you want to write a parser for C or C++ and your code does something like this:
char c = source.get();
switch(c)
{
...
case '<':
// May be < or <=
if (source.peek() == '=')
{
source.get();
return less_or_equal;
}
// Ok, not <= so:
return less;
...
}
[I ignored that it may be part of a template, a shift, or something else like that]
The need for putback() is very little when you have peek(), but it does allow code that "normally consumes" the character to put it back "if it got it wrong". Say you know that <= is more common than <, then you could do:
char c = source.get();
switch(c)
{
...
case '<':
// May be < or <=
c = source.get();
if (c == '=')
{
source.get();
return less_or_equal;
}
source.putback(c);
// Ok, not <= so:
return less;
...
}
because it only does putback on the rare case [as per the assumed statistics above].
One can imagine cases where the common case is to get and the rare case is mismatch, e.g. if we want to read a number:
int number = 0;
do
{
char c = input.get();
if (isdigit(c))
{
number *= 10;
number += c - '0';
}
else
{
input.putback(c);
}
while( isdgit(c) );
Since, most numbers have more than one digit in them, the more common case is that the first and the subsequent character is a digit, and the unusual case is that we need to call putback(). [Of course, reading numbers "properly" will require a bit more stuff...]
But I have also read about a function called peek() which is also used for such purposes
peek() was created for a different purpose - it's there to let your program process two characters at a time - essentially emulating ungetc() functionality from the portion of the library based on the C standard library.
Using peek to see if you are about to hit eof is valid, but the approach that you show in the code, i.e. while(file>>str), is more idiomatic to C++ than the one based on peek.
I have also heard about a function called putback() what's that?
The std::putback() function lets you do the same thing as ungetc() does for FILE* streams.

How to put UTF-8 text into std::string through linux sockets

I made a simple C++ server program, which works just fine as long as I use it with simple tools like telnet, however when I use for example .Net (C#) that would connect to it and send it some strings, the text is somewhat corrupted. I tried multiple encodings on C# side, and only result was that it was corrupted in a different way.
I belive that main problem is in this function that is meant to read a line of text from socket:
std::string Client::ReadLine()
{
std::string line;
while (true)
{
char buffer[10];
read(this->Socket, buffer, 9);
int i = 0;
while (i < 10)
{
if (buffer[i] == '\r')
{
i++;
continue;
}
if (buffer[i] == '\0')
{
// end of string reached
break;
}
if (buffer[i] == '\n')
{
return line;
}
line += buffer[i];
i++;
}
}
return line;
}
This is a simple output of program into terminal, when I send it string "en.wikipedia.org" using telnet I see:
Subscribed to en.wikipedia.org
When I use C# that open a stream writer using this code
streamWriter = new StreamWriter(networkStream, Encoding.UTF8);
I see:
Subscribed to en.wiki,pedia.org,
When I use it without UTF-8 (so that default .net encoding is used, IDK what it is)
streamWriter = new StreamWriter(networkStream);
I see:
Subscribed to en.wiki�pedia.org�
However, in both cases it's wrong. What's a most simple way to achieve this, using just standard C++ and linux libraries? (no boost etc - I can do this using some framework, like Qt, boost etc, but I would like to understand this). Full code #http://github.com/huggle/XMLRCS
A UTF-8 string is just a series of single bytes, basically just wnat std::string is supposed to handle. You have two other problems:
The first is that you don't actually check ho many characters was actually read, you always loop over ten characters. Since you don't loop over the actual number of characters read (and don't check for error or end of connection) you might read data in the buffer beyond what was written by read and you have undefined behavior.
The second problem is kind of related to the first, and that is that you have a buffer of ten characters, you read up to nine characters into the buffer, and then loop over all ten characters in the buffer. The problem with this is that since you only read up to nine characters, the tenth character will always be uninitialized. Because the tenth entry in the buffer is always uninitialized, its value will be indeterminate and reading it will again lead to undefined behavior.

Adding char to string in C++

I work with Eclipse and Arduino.
I want to add a char to a string. I tried to use append,insert ( but these can not be resolved)
I tried to use += but when i print the string it always have one char.Basically i deletes the string and writes only the new char i want to add in.
I tried also concat and it does the same thing.Also strcat gives me headache with the operands cause it needs a const char pointer and i want to add a char that changes.
while (theSettings.available()) {
character = theSettings.read();
if(character == '/') {
// Comment - ignore this line
while(character != '\n'){
character = theSettings.read();
}
} else if(isalnum(character)){ // Add a character to the description
Serial.println(character);
description +=character;
//description.concat(character);
Serial.println(description);
}
It sounds like what you want (for convenience) is the String object class available with the Arduino library.
http://arduino.cc/en/Reference/StringObject
If description is of the Ardunio-specific String type, you should be able to use the += operator to append.
You can do a very simple thing;
Serial.print(character);
Serial.print("");
Serial.println(description);
alternatively you can use "dtostrf" if you need to concatenate float and strings