I'm coding a task monitoring, which updates tasks' progress using cout. I'd like to display one task progress per line, therefore I have to rollback several lines of the console.
I insist on "several" because \b does the job for one line, but does not erase \n between lines.
I tried std::cout.seekp(std::cout.tellp() - str.length()); but tellp() returns -1 (failure).
You can do cout << '\r'; to jump to the beginning of the current line, but moving upwards is system-specific. For Unix, see man termcap and man terminfo (and search for cursor_up). On ANSI-compatible terminals (such as most modern terminals available on Unix), this works to move up: cout << "\e[A";.
Don't try seeking in cout, it's unseekable most of the time (except when redirected to a file).
As mentioned in other answers, using the ncurses (or slang) library provides a good abstraction for terminal I/O on Unix.
Instead of filling with spaces (which is error-prone, because not every terminal is 80 characters wide), you can do \r + clr_eol: std::cout << "\r\e[K" << std::flush.
Use an output formatting library such as ncurses if you can; this simplifies terminal manipulation significantly.
Neither C nor C++ define anything like that. You need explicit terminal manipulation. On Unix you can use curses. Have no idea what's there for Windows.
I know this is an old post, but the accepted doesn't cover cases where cout is piped to a program or file and this is the top of my google searches. The following will handle both piped and non-piped stdout with slightly different behavior.
#include <iostream>
#include <functional>
#include <stdio.h>
#ifdef _WIN32
#include <io.h>
#else
#include <unistd.h>
#define _isatty isatty
#define _fileno fileno
#endif
const std::function<void(const size_t&)> progress_printer(_isatty(_fileno(stdout)) == 1 ?
[](const size_t& i) {
std::cout << "\rNumber " << i << std::flush;
} :
[](const size_t& i) {
static std::ios::off_type last(-1);
if(last != -1)
std::cout.seekp(last, std::ios::beg);
last = std::cout.tellp();
std::cout << "Number " << i << std::endl;
}
);
This is untested on windows, but should work. What it does is detect if the file descriptor or is a tty. If it is then it just writes '\r' if the pos hasn't changed since last time it printed or a newline. If it isn't a newline, it seeks to the last place it was after it printed.
It behaves differently for files than for tty. For a file, if something outputs to the stream between prints then it can overwrite some or all of what was written even after newlines. For ttys it just overwrites the chars at the beginning of the current line.
You can use first system(" "); for you can use \e[A (Dev-C++) or \u001B[A (Visual Studio)
#include <iostream>
using namespace std;
int main()
{
system(" ");
string Input;
do
{
cout << "[#][\e[s";
cin >> Input;
cout << "[\e[u" << Input << "]"<<endl;
} while (2==2);
return 0;
}
enter image description here
Hope it helps ;) [It should work on Linux.]
// "\e[0K" Clear line from cursor to the end
cout << "\e[A\r\e[0K"<<what_you_want<<endl;
Related
I'm having difficulties with a particular piece of code I'm learning from "Programming Principles And Practice Using C++".
I can't get an output from a loop refering to a vector. Am using std_lib_facilities and stdafx because the book and MVS told me so.
#include "stdafx.h"
#include "../../std_lib_facilities.h"
int main()
{
vector<string>words;
for(string temp; cin>>temp; )
words.push_back(temp);
cout << "Number of words: " << words.size() << '\n';
}
This will produce nothing. I'll get the prompt, type in some words, then enter, then nothing.
Tried some variations I got here and from other websites as well, such as:
//here i tried the libraries the guy used in his code
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
cout << "Please enter a series of words followed by End-of-File: ";
vector<string> words;
string word;
string disliked = "Broccoli";
while (cin >> word)
words.push_back(word);
cout << "\nNumber of words: " << words.size() << endl;
// cycle through all strings in vector
for (int i = 0; i < words.size(); ++i)
{
if (words[i] != disliked)
cout << words[i] << endl;
else
cout << "BLEEP!\n";
}
return 0;
}
Still nothing.
After trying some things, by elimination I'm pretty certain the problem is with the loop-to-vector communication, because all of these work fine:
int main()
{
vector<string>words = { "hi" };
words.push_back("hello");
cout << words[1] << "\n"; // this will print hello
for (int i = 0; i < words.size();++i) {
cout << words[i] << "\n"; // this will print out all elements
// inside vector words, ( hi, hello)
}
cout << words.size();// this will print out number 2
for (string temp; cin >> temp;) {
words.push_back(temp);
}
cout << words.size();// this won't do anything after i type in some
// words; shouldn't it increase the size of the
// vector?
}
Neither will this alone:
int main()
{
vector<string>words = { "hi" };
for (string temp; cin >> temp;) {
words.push_back(temp);
}
cout << words.size();
}
What am I missing, please? Thank you in advance.
Input the strings and when done press Ctrl+Z (followed by Enter) if on Windows or Ctrl+D if on Linux. When you do that the cin>>temp; condition inside your for loop will evaluate to false and your program will exit the loop.
Firstly, it is not necessary to use the std_lib_facilities.h. That is just something used in the book to avoid having every example in the book regularly include a set of standard headers, or to correct for non-standard behaviours between compilers. It is also a header that that does using namespace std - you will find numerous examples (both on SO and the wider internet) explaining why it is VERY poor practice to have using namespace std in a header file.
Second, it is not necessary to use stdafx.h either. That is something generated by Microsoft IDE, and provides a means of speeding up compilation in large projects, because of how it causes the compiler to work with precompiled headers. If you only expect to use Microsoft compilers, then feel free to fill your boots and use this one. However, it is not standard C++, may (depending on IDE and project settings) include windows specific headers that will not work with non-Microsoft compilers, and in forums will probably discourage people who use other compilers from helping you - since they will have good reason to assume your code uses Microsoft-specific extensions, which will mean they probably can't help you.
The first sample of code can be rewritten, in standard C++ (without use of either header above) as
#include <vector> // for std::vector
#include <string> // for std::string
#include <iostream> // std::cout and other I/O facilities
int main()
{
std::vector<std::string> words;
for(std::string temp; std::cin >> temp; )
words.push_back(temp);
std::cout << "Number of words: " << words.size() << '\n';
}
Before you get excited, this will exhibit the same problem (not apparently finishing). The reason is actually the termination condition of the loop - std::cin >> temp will only terminate the loop if end of file or some other error is encountered in the stream.
So, if you type
The cow jumped over the moon
std::cin will continue to wait for input. It is generally necessary for the USER to trigger and end of file condition. Under windows, this requires the user to enter CTRL-Z on an empty line followed by the enter key.
An alternative would be to have some pre-agreed text that cause the loop to exit, such as
#include <vector> // for std::vector
#include <string> // for std::string
#include <iostream> // std::cout and other I/O facilities
int main()
{
std::vector<std::string> words;
for(std::string temp; std::cin >> temp && temp != "zzz"; )
words.push_back(temp);
std::cout << "Number of words: " << words.size() << '\n';
}
which will cause the program to exit when the input contains the word zzz. For example
The cow jumped over the moon zzz
There are other techniques, such as reading one character at a time, and stopping when the user enters two consecutive newlines. That requires your code to interpret every character, and decide what constitutes a word. I'll leave that as an exercise.
Note there is no means in standard C++ to directly read keystrokes - the problems above are related to how standard streams work, and interact with the host system.
The user can also use the program "as is" by placing the same text into an actual file, and (when the program is run) redirect input for your program to come from that file. For example your_executable < filename.
I'm creating a text editor and here is its code:
#include <iostream>
#include <iomanip>
#include <stdlib.h>
#include <conio.h>
int main()
{
system("cls"); system("COLOR F0");
std::string input;
static int lineNo=0;
while(true)
{
lineNo+=1;
std::cout << lineNo << "\t";
input=="{" ? std::cout << "\t" : std::cout << "";
input=="(" ? std::cout << "\t" : std::cout << "";
input=="[" ? std::cout << "\t" : std::cout << "";
std::getline(std::cin, input);
}
return 0;
}
I want to create an auto-completion tool for the brackets which enters the closing bracket instantly after the opening brace has been typed. Please help me as I am just a beginner.
You could use getch() function from conio.h library for scanning a single character only.You can declare a character variable and scan for braces like this.
char in;
in=getch();
if(in=="{")
{
//Write your code according to your uses.
}
std::cin is your program's standard input. It does not (in general) mean "the user's keyboard" or even "input to the terminal" or anything like that. How you get stuff from cin depends on how things are being written to your standard input, which typically does not happen character by character. Often your terminal only sends data to a program's standard input after a newline (after the user presses enter), in which case there's no way for you to get to that data beforehand through cin.
For what you're describing, you'll need to use (as Joachim Pileborg pointed out) platform-specific functionality, such as PeekConsoleInput on Windows. You may also find GetAsyncKeyState useful.
I've seen a couple of solutions to this question, but I'm still running into an issue. I've tried several of the solutions I've seen on this site, but I keep having the same issue. I'm not sure how to make this work, and I'm also not sure why it's not working, since I'm really new to C++.
A brief explanation of what I am attempting to do: I'm writing a simple old-school text-based story/game for a video game design club at my school, and at several points I have the user make decisions, or input things such as their name, which is then used in an output line, as it would be referenced several times. I have had no problem doing that, using something simple like this:
#include <iostream>
#include <string>
#include <limits>
#include <windows.h>
using namespace std;
int main(){
string name, place ;
cout << "???: What is your name? ";
getline (cin, name);
cout << "???: Hello, " << name << "!\n" << "\n";
}
My problem is that I'd like to have the text appear one character at a time, like dialogue, but whenever I try to use something I've seen written by others, it doesn't seem to like it very much. The only one that I tried that I can now find again is this:
#include <iostream>
#include <unistd.h> // include <windows.h> on windows
// function to output as if it was being typed
void type_text(const std::string& text)
{
// loop through each character in the text
for (std::size_t i = 0; i < text.size(); ++i)
{
// output one character
// flush to make sure the output is not delayed
std::cout << text[i] << std::flush;
// sleep 60 milliseconds
usleep(60000); // use Sleep on windows
}
}
int main()
{
type_text("Hej hej hallå!");
}
Apparently there is some sort of conflict regarding my attempt to output the name back to the user when I try to use that code with what I've written. I'm not really sure what the problem is, since I'm so new to C++, can anyone help me out?
Consider using std::this_thread::sleep_for, as it is standard C++11. Example:
#include <iostream>
#include <thread> // standard C++11
// function to output as if it was being typed
void type_text(const std::string& text)
{
// loop through each character in the text
for (std::size_t i = 0; i < text.size(); ++i)
{
// output one character
// flush to make sure the output is not delayed
std::cout << text[i] << std::flush;
// sleep 60 milliseconds
std::this_thread::sleep_for(std::chrono::milliseconds(60));
}
}
int main()
{
type_text("Hello, World!");
}
If you have access to a C++14 compiler, you can simply make use of the std::chrono user-defined literals and have a more "natural" syntax:
using namespace std::literals;
std::this_thread::sleep_for(60ms);
I have some weird issues I cannot figure out. When I run the code below which takes a file.txt reads it line by line into a vector<string> and then compares each index to string "--" it does not make it to the comparison stage.
Further more, in the convert_file() under the for loop string m, has some weird behavior: string m = "1"; m+= "--"; ('--' inside vector) m+= "2"; will print to console 2--; which makes me think something is bugging out the vector. The 2 is replacing the 1, the first character. This makes it look like the vector is bugged.
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
vector<string> get_file(const char* file){
int SIZE=256, ln=0;
char str[SIZE];
vector<string> strs;
ifstream in(file, ios::in);
if(!in){
return strs;
} else {
while(in.getline(str,SIZE)){
strs.push_back(string(str));
ln++;
}
}
in.close();
return strs;
}
void convert_file(const char* file){
vector<string> s = get_file(file);
vector<string> d;
int a, b;
bool t = false;
string comp = "--";
for(int i=0; i<s.size(); i++){
string m = "1";
m+= string(s.at(i));
m+= "2";
cout << m << endl;
if(s.at(i) == comp){
cout << "s[i] == '--'" << endl;
}
}
}
int main(){
convert_file("test.txt");
return 0;
}
now when I run a test file to check a similar program:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main(){
vector<string> s;
s.push_back("--");
s.push_back("a");
for(int i=0; i<s.size(); i++){
cout << "1" << s.at(i) << "2" << endl;
if(s.at(i) == "--"){
cout << i << "= --" << endl;
}
}
return 0;
}
prints off 1--2, 0= --, 1a2. it works, it prints properly, and does the comparison. This leads me to think something is happening when I pull the line into a string.
Windows 7, cygwin64
g++ version 4.9.3
compile: D:\projects\test>g++ -o a -std=c++11 test.cpp
Based on the behavior and the discussion the lines in the file are terminated using a "\r\n" sequence. The easiest approach for dealing with the remaining '\r' is to remove it after reading a line. For example:
for (std::string line; std::getline(file, line); ) {
if (!line.empty() && line.back() == '\r') {
line.resize(line.size() - 1u);
}
strs.push_back(line);
}
If you insist in reading into char arrays you can use file.gcount() to determine the number of characters read to find the end of the string quickly. Note, however, that the number includes the bewline character, i.e., you'd want to check str[file.gcount() - 2] and potentially set it to '\0' (if the count is bigger or equal to 2, of course).
As answered by Dietmar Kühl already, the problem is with the \r\n line endings.
However, you should not need to modify your source code. The default behaviour in C++ is supposed to be to open files in text mode. Text mode means that whenever a line ending is found, where "line ending" depends on the platform you're using, it gets translated so that your program just sees a single \n. You're supposed to explicitly request "binary mode" from your program to disable this line ending translation. This has been long-standing practise on Windows systems, is the behaviour well supported by the C++ standard, and is the expected behaviour with native Windows compilers, but for compatibility with POSIX and existing Unix programs that do not bother setting the file mode properly, Cygwin ignores this and defaults to opening files in binary mode unless a custom Cygwin-specific text mode is explicitly requested.
This is covered in the Cygwin FAQ. The first solutions provided there (using O_TEXT or "t", depending on how you open your file) are non-standard so break your code with other environments, and they are not as easy to use with C++ <fstream> file access.
However, the next solutions provided there do work even for C++ programs:
You can also avoid to change the source code at all by linking an additional object file to your executable. Cygwin provides various object files in the /usr/lib directory which, when linked to an executable, changes the default open modes of any file opened within the executed process itself. The files are
binmode.o - Open all files in binary mode.
textmode.o - Open all files in text mode.
textreadmode.o - Open all files opened for reading in text mode.
automode.o - Open all files opened for reading in text mode,
all files opened for writing in binary mode.
And indeed, changing your compiler and linker invocation from g++ -o a -std=c++11 test.cpp to g++ -o a -std=c++11 test.cpp /usr/lib/textmode.o, your program works without changes to your source code. Linking with textmode.o basically means that your I/O will work the way it already should work by default.
I want to access specific lines in of text file to display or modify that one. My text file contains lines of different lengths and i heard cannot use seekg or seekp for such files. I got a code but it doesn't works. Can someone please tell me its fault of some other helpful idea?
#include <fstream>
#include <limits>
#include <string>
#include <iostream>
std::fstream& GotoLine(std::fstream& file, unsigned int num)
{
file.seekg(std::ios::beg);
for(unsigned int i=0; i < num - 1; ++i)
{
file.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
}
return file;
}
int main()
{
using namespace std;
std::fstream& GotoLine(std::fstream& file, unsigned int num);
cout << "Starting..." << endl;
fstream file("bla.txt");
GotoLine(file, 8);
string line8;
file >> line8;
cout << "[" << line8 << "]" << endl;
// cin.get();
cout << "Finished..." << endl;
return 0;
}
string line8;
file >> line8;
will only extract until the first whitespace character is hit.
you could use something like:
string line8;
getline(file, line8);
This at least worked for me with the rest of your code on Windows 7 with VS2012
Standard C++11 (and earlier versions of the standard) dont have notion of lines contained inside files. Also POSIX (and even Windows or MacOSX) don't have it. Textual files usually contain lines of variable length (and only the line terminator is relevant, either \n or \r\n or \n\r, depending upon the operating system and perhaps the file read mode -binary or textual-).
In the 1960s or 1970s IBM mainframe OS/360 operating systems had "file" systems which did have files made of fixed-length lines, mimicking punched cards.
So, you have to read your file line by line and remember where are the line limits (or use std::istream::ignore to skip till \n).
Alternatively, read every line of your file into a std::vector<std::string> using std::getline on std::ifstream-s.
For /etc/fstab (or /proc/mounts) reading all the lines in a vector is a good idea, since it is always a tiny file. It usually have less than an few dozens of lines, often less than about a hundred char each. The pathological case could be a file with many thousand lines of comments, but that don't really happen in practice.