Adding a status bar to c++ console applications - c++

I am making a linux application using C++ and it will print info out to the console. Parts of the program will take a while to compute and I would like to add a status bar in the console similar to the one used in wget (I put my own depiction below).
%complete[===========> ] eta
What would be the best way to accomplish this goal? Are there any useful libraries that make it easy to add this functionality?

If your program is like wget, that is, it's basically a batch program without the need for a full-screen UI (for which I would recommend ncurses), you can use the trick to print a carriage return (but not line feed) after your line; the next thing you write will overwrite the same line.
Here's a demonstration.
#include <iostream>
#include <unistd.h>
int main(void)
{
for (int i = 0; i < 10; i++) {
std::cout << "Status: " << i << "\r" << std::flush;
sleep(1);
}
std::cout << "Completed.\n";
}

The ncurses library should be useful to you. Or you can write the progress line char by char, using backspaces, calling fflush or std::flush, etc.
A simpler way would just to output dots...

You can use debconf-apt-progress to run a command while displaying a progress line like apt does. Your command needs to report progress over a pipe fd back to debconf-apt-progress. I haven't figured out how to extract this functionality out of debconf-apt-progress yet.

Related

How do you make RPG-like scrolling text? C++ on Linux

I'm a beginner coder making a simple text 'choose your own adventure' game, but I want it to scroll out the text like an RPG instead of just spitting out the text. How can I do that?
I believe that the ncurses library is exactly what you are looking for. It allows you lower access to the terminal text, to produce things like full screen text, like this:
A tutorial for how to use it can be found here, and you can download version 6.3 here.
It is used in many applications, like GNU nano. A full list of applications using ncurses can be found here.
I'm going to assume you're just supposed to write to a console.
std::string str = "Your text";
for(char& current_char : str) {
std::cout << current_char << std::flush;
sleep(1000);
}
std::cout << std::endl;
The for loop is going to iterate over each character in the string.
It will then output it to cout. std::flush is here to force the output to be update without using std::endl which would return carriage and we don't want that.
sleep will pause for an amount of time in milliseconds, here 1000 milliseconds (1 second). Be careful though; sleep is a Windows function. On Linux, use usleep. If you need it to be cross-platform you should probably use the thread sleeping functions or make something yourself with chrono.
And finally, we use std::endl to return carriage and update the output.

C++ Console Output Manipulation [duplicate]

This question already has answers here:
C++ Update console output
(4 answers)
Closed 5 years ago.
I'm developing some application in which I want to manipulate some data comming from the embedded system. So, what do I want to do is that I want to display the values which are comming on the same position where they were before, leaving the static text on the same place and not using new line. Being more specific, I want to output my data in form of a table, and in this table on the same positions I want to update that data. There is some analogy in Linux, when in the terminal there is some update of the value(let's say some progress) while the static text remains and only the value is changing.
So, the output should look like this:
Some_data: 0xFFFF
Some_data2: 0xA1B3
Some_data3: 0x1201
So in this case, "Some_data" remains unchanged on the same place, and only the data itself is updated.
Are there maybe some libraries for doing that? What about Windows Console Functions? Also, it would be very nice if it could be made in such a way, in which the console would not flick, like when you clear the console and print something back. Any hints or suggestions? Thanks very much in advance guys!
P.S. There is no need to write the code, I just need some hints or suggestions, with very short examples if possible(but not required).
On a *nix system you have two options.
1) If you want to manipulate the entire console in table form like you ask, then ncurses is the best option. The complete reference can be found here.
As you can see, that package is quite heavyweight and can often be overkill for simple projects, so I often use . ..
2) If you can contain your changing information on a single line, use the backspace escape char \b and then rewrite the information repeatedly to that line
For example, try this . . .
#include <iostream>
#include <chrono>
#include <thread>
using namespace std;
void writeStuff(int d)
{
cout << string(100,'\b') << flush;
cout << "Thing = " << d;
}
int main()
{
cout << "AMAZING GIZMO" << "\n============" << endl;
while(1) {
writeStuff(rand());
this_thread::sleep_for(chrono::milliseconds(250));
}
}
For a real world example, the sox audio console playback command uses this technique to good effect by displaying a bar chart made of console characters to represent the audio playback level in real time.
Of course, you can get more creative with the method shown above if your console supports ANSI escape sequences.

Why does getchar work like a buffer instead of working as expected in real-time

This is my first question on stackoverflow. Pardon me if I haven't searched properly but I do not seem to find an explanation for this. Was just attempting an example from Bjourne Stroustroup's papers. Added my bits to see the array get re-sized as I type the text.
But it doesn't seem to work that way! getchar() simply waits till I am done with entering all the characters and then it will execute the loop. As per the logic, it doesn't actually go into the loop, get a character, perform its actions and then iterate. I am wondering if this is implementation specific, or intended to be like this?
I am on Ubuntu 14.04 LTS using Codeblocks with gcc 4.8.2. The source was in cpp files if that matters.
while(true)
{
int c = getchar();
if(c=='\n' || c==EOF)
{
text[i] = 0;
break;
}
text[i] = c;
if(i == maxsize-1)
{
maxsize = maxsize+maxsize;
text = (char*)realloc(text,maxsize);
if(text == 0) exit(1);
cout << "\n Increasing array size to " << maxsize << endl;
}
i++;
}
The output is as follows:
Array Size is now: 10
Please enter some text: this is some sample text. I would have liked to see the memory being realloced right here, but apparently that's not how it works!
Increasing array size to 20
Increasing array size to 40
Increasing array size to 80
Increasing array size to 160
You have entered: this is some sample text. I would have liked to see the memory being realloced right here, but apparently that's not how it works!
Array Size is now: 160
This has nothing to do with getchar directly. The "problem" is the underlying terminal, which will buffer your Input. The Input is sent to the program after you press enter. In Linux (dunno if there is a way in Windows) you can workaround this by calling
/bin/stty raw
in terminal or by calling
system ("/bin/stty raw");
in your program. This will cause getchar to immediately return the input character to you.
Dont forget to reset the tty behaviour by calling
/bin/stty cooked
when done!
Here is an example (for Linux):
#include <stdio.h>
#include <stdlib.h>
using namespace std;
int main() {
system ("/bin/stty raw");
char c = getchar();
system ("/bin/stty cooked");
return 0;
}
Also have a look at this SO Post: How to avoid press enter with any getchar()
Also, as suggested in the comments, have a look here: http://linux.die.net/man/3/termios especially on the command tcsetattr, which should work cross-platform.
Actually, tcsetattr does not apply to Windows (which is what is commonly referred to in this site as "cross-platform"). However, the question is tagged for Linux, so "cross-platform" is a moot point.
By default the standard input, output and error streams are set to
line-buffered (input)
block-buffered (output)
line-buffered (error)
You can change that using setbuf, but of course will not solve the problem (the answer calls for single-character input). POSIX terminal I/O (termios) lets you change via a system call any of the flags shown using stty. As a rule, you might call stty directly from a script, rarely from a C program.
Reading a single character is a frequently asked question, e.g.,
How can I read single characters from the terminal? (unix-faq)
How can I read a single character from the keyboard without waiting for the RETURN key? How can I stop characters from being echoed on the screen as they're typed? (comp.lang.c FAQ)
You could also use ncurses: the filter function is useful for programs that process a command-line (rather than a full-screen application). There is a sample program in ncurses-examples (filter.c) which does this.

Piping output from one program to another not working for this particular program

I expect this is a basic question, but I haven't been able to find an answer.
I'm building a web server in C++, and in order to help me visualise the system as it's running I'm building a separate program to do the visualisation. The web server will inform the visualiser of its current state by printing statements to stdout that are piped into the visualiser, which will parse the input and render a nice schematic view of the whole system along with various stats. The visualiser will be written in Python.
To check that I understand how piping works I created two simple programs:
#include <iostream>
using namespace std;
int main() {
cout << "Hello world!\n";
return 0;
}
, and
#include <iostream>
using namespace std;
int main() {
char buf[128];
while (!cin.eof()) {
cin.getline(buf, 128, '\n');
cout << "Received line: " << buf << "\n";
}
return 0;
}
This works as expected when I execute the command
./one | ./two
However, when I run my web server like so:
./aril | ./two
I get no output at all.
Running the server on its own produces output like the following:
Spawning handlers
Waiting for HTTP clients
Server: got connection from 127.0.0.1, port 52168
Connection timed out
(Obviously that isn't actually the kind of output I'll be passing to the visualiser -- it will need a more easily parse-able syntax).
Possibly relevant info:
The web server is divided into two processes: aril and arild. aril runs with root privileges, whereas arild doesn't. Both processes print to stdout using std::cout.
I can't think of any reason why this isn't working.
EDIT:
The solution, it turns out, is simply to explicitly flush the output. Should have been the first thing I tried really..
Your web server is printing in STDERR while in two you are reading from STDIN. So it'll not work.
Change ./aril | ./two to
./aril 2>&1 | ./two
This will redirect all the STDERR and STOUT of aril to STDOUT and thus two will be able to read it.
It is possible that aril detects if its output is piped (see fstat() and this thread http://cboard.cprogramming.com/cplusplus-programming/73909-prevent-piping.html for details) and switches to silent mode, i.e does not produce any output. Try piping to something else, cat maybe, and see if it produces an output.
I think your programs are designed to work as pairs, but not interchangeably. ./one | ./two are an example of piping, but ./aril is expecting to communicate with ./arild via sockets. It probably doesn't make sense to mix ./aril | ./two.

Custom interactive shell

I've run into the following problem: My console utility should be running as a process (hope it's the right term) so every command goes to it directly. Like gnuplot, interactive shells (irb, etc.).
This shows what I'm talking about:
Mikulas-Dites-Mac-2:Web rullaf$ command
Mikulas-Dites-Mac-2:Web rullaf$ irb
>> command
NameError: undefined local variable or method `command' for main:Object
from (irb):1
>> exit
Mikulas-Dites-Mac-2:Web rullaf$
first command is executed as shell command, but after I enter irb, it's not. You get the point.
irb puts console into some special mode, or it simply parses the given input itself in some loop?
Is here any proper way to create such a behavior in c++? Thanks
You have to parse the input yourself. Depending on the complexity of the input, this might be accomplished by some simple string matching for trivial cases. A very simple example:
#include <iostream>
#include <string>
int main()
{
std::string input;
for(;;)
{
std::cout << ">>";
std::cin >> input;
if(input=="exit")
return 0;
else if(input=="test")
std::cout << "Test!\n";
else
std::cout << "Unknown command.\n";
}
}
Obviously, this little program will print a prompt (>>) and understand the commands exit and test and will print Unknown command. on all other commands.
For everything else, you probably want to learn some more about pattern matching or parsing; Google is your friend (take a look at bison for example and a good tutorial).
To parse your command line, you can use Boost.Program_options.