I am using Boost Program Options to parse command line arguments (and I don't want to miss it since it works great). However, I have one problem: Boost program options offer the possibility to assign a description to each option. Boost then offers the possibility to
cout << program_options_description << endl
to nicely display help explaining the options. However, it seems to be the case that these error messages are adjusted to a terminal width of 80 (I conclude this from the fact that for a width of 80, the line breaks are nicely set).
If my current terminal has another width (in particular one that has less than 80 columns), the displayed help looks very unnatural due to automatic line breaks done by the terminal.
So: Is there a possibility that Boost automatically adjusts the option descriptions to the current terminal width?
The options_description accepts the column width as a parameter.
options_description(const std::string &, unsigned = m_default_line_length,
unsigned = m_default_line_length/2);
I believe the default is 80 for m_default_line_length. Also, see this SO question to get the terminal width on linux and then pass that to the constructor. Or if you are windows, you would want to call GetConsoleScreenBufferInfo.
Related
I'm currently designing a CLI interface for linux, and for various reasons I am not able to use ncurses. I am using exclusively C++ and the Qt framework.
Therefore, in order to have a user-friendly interface, I have to run this getch loop in a separate thread:
https://stackoverflow.com/a/912796/3605689
Which basically means I have to implement all basic functionalities (such as backspace) by myself. I have already implemented command completion and command history(like when you press tab or uparrow/downarrow in linux), but I can't figure out how to implement leftarrow/rightarrow (aka seeking through the typeahead).
Normally, I implement it like this: upon every gech which is not equal to -1, I check whether the user has pressed a special key (one that modifies the typeahead somehow). I then clear the stdout using the following function:
void inputobject::clear_line(int nletters)
{
QTextStream(stdout) << "\033[2K";
for(int i = 0; i < nletters;i++){
QTextStream(stdout) << "\b";
}
rewind(stdout);
}
And replace it with something else, effectively simulating the typeahead. For example, in the case of backspace, I would save the command call clear_line, and print the command out again, just with one less letter, behaving exactly as a normal console application would.
My real problem is with the cursor, in the case of left/rightarrow, I need to move the cursor visual in order to be able to indicate where in the text is the user seeking:
Because of the nature of how I rewrite the given stdout line to simulate the typeahead, it does not really matter where the cursor REALLY is, as long as it stays on the same line - it is just the visual that matters. How can I achieve moving the cursor visual on linux?
The answer was provided in the comment by Evilruff:
Cursor Movement
ANSI escape sequences allow you to move the cursor around the screen at will. This is more useful for full screen user interfaces generated by shell scripts, but can also be used in prompts. The movement escape sequences are as follows:
Position the Cursor:
\033[;H
Or
\033[L;Cf
puts the cursor at line L and column C.
Move the cursor up N lines:
\033[NA
Move the cursor down N lines:
\033[NB
Move the cursor forward N columns:
\033[NC
Move the cursor backward N columns:
\033[ND
Clear the screen, move to (0,0):
\033[2J
Erase to end of line:
\033[K
Save cursor position:
\033[s
Restore cursor position:
\033[u
Not using ncurses and co is a serious limitation.
It is hell to make correct input/output on shell for displaying anything.
The only others real solutions (I can't think as a solution to reimplement a ncurse-like library) I think of are:
making call to dialog (for some example www.linuxjournal.com/article/2807 and for the doc: http://linux.die.net/man/1/dialog)
using the framebuffer mecanism with Qt4 (here)
In my output there are certain lines that are refreshed every few seconds. If I resize the terminal by clicking F11, then output is just as I wanted. If terminal isn't big enough some long lines that are refreshed are splitted in two, and because of that, only one part of line is refreshed, and every time line is refreshed I also get new line.
This could be easily avoided if I could specify default size of terminal (resize terminal from my program). Also it would be great if I could forbid user to change terminal size while program is running.
while(1)
{
cout<<"Long line that is refreshed every 5s... \r";
//if line is splited in two lines, \r will return to beginning of that new line
//and the first part of original line would stay as it is(won't be rewrited)
sleep(5);
}
How do I specify a terminal size or stop terminal resizing?
Some terminal emulators (including the default macOS Terminal.app) support being resized/moved/etc in response to printed control sequences. The sequences are fairly standard but not all terminal emulators implement all of them.
For example:
# set terminal width to 50, height to 100
cout << "\e[8;50;100t";
This answer includes an overview of some other available control sequences.
I don't think you can forbid the user to change the terminal size. A better way would be to catch the SIGWINCH signal that is sent to the process everytime the window size is changed, and use the TIOCGWINSZ / TIOCGSIZE ioctl() to get the dimensions.
I'm currently designing a CLI interface for linux, and for various reasons I am not able to use ncurses. I am using exclusively C++ and the Qt framework.
Therefore, in order to have a user-friendly interface, I have to run this getch loop in a separate thread:
https://stackoverflow.com/a/912796/3605689
Which basically means I have to implement all basic functionalities (such as backspace) by myself. I have already implemented command completion and command history(like when you press tab or uparrow/downarrow in linux), but I can't figure out how to implement leftarrow/rightarrow (aka seeking through the typeahead).
Normally, I implement it like this: upon every gech which is not equal to -1, I check whether the user has pressed a special key (one that modifies the typeahead somehow). I then clear the stdout using the following function:
void inputobject::clear_line(int nletters)
{
QTextStream(stdout) << "\033[2K";
for(int i = 0; i < nletters;i++){
QTextStream(stdout) << "\b";
}
rewind(stdout);
}
And replace it with something else, effectively simulating the typeahead. For example, in the case of backspace, I would save the command call clear_line, and print the command out again, just with one less letter, behaving exactly as a normal console application would.
My real problem is with the cursor, in the case of left/rightarrow, I need to move the cursor visual in order to be able to indicate where in the text is the user seeking:
Because of the nature of how I rewrite the given stdout line to simulate the typeahead, it does not really matter where the cursor REALLY is, as long as it stays on the same line - it is just the visual that matters. How can I achieve moving the cursor visual on linux?
The answer was provided in the comment by Evilruff:
Cursor Movement
ANSI escape sequences allow you to move the cursor around the screen at will. This is more useful for full screen user interfaces generated by shell scripts, but can also be used in prompts. The movement escape sequences are as follows:
Position the Cursor:
\033[;H
Or
\033[L;Cf
puts the cursor at line L and column C.
Move the cursor up N lines:
\033[NA
Move the cursor down N lines:
\033[NB
Move the cursor forward N columns:
\033[NC
Move the cursor backward N columns:
\033[ND
Clear the screen, move to (0,0):
\033[2J
Erase to end of line:
\033[K
Save cursor position:
\033[s
Restore cursor position:
\033[u
Not using ncurses and co is a serious limitation.
It is hell to make correct input/output on shell for displaying anything.
The only others real solutions (I can't think as a solution to reimplement a ncurse-like library) I think of are:
making call to dialog (for some example www.linuxjournal.com/article/2807 and for the doc: http://linux.die.net/man/1/dialog)
using the framebuffer mecanism with Qt4 (here)
I am writing a program for Windows that eventually has to launch a different pre-existing .exe that sits on the same computer. It passes multiple parameters to this .exe file. I am reading the actual command and parameters and constructing the command but I also tried hard coding it with the same results. Here's the hard coded version (I picked this out of an older C program that uses the same.exe):
system("c://IQapture//dmon2_6_IHD -p2 c://IQapture//mon_table_101_Tx8.txt 11 0 0");
So in the original program inside int _cdecl main(int argc, char**argv) this use of system works. In my C++ program inside a C++ class method when I issue the command the correct program launches but it immediately puts up an error dialog stating that an error has occurred. I echo'd the system string used to launch the exe out to the console. Right after it fails, I copy and paste the same line that was echo'd and this time the exe runs without error. This is repeatable. In case it was timing related I tried adding a 10 second delay before issuing the system command but it didn't matter. Plus the original older program doesn't require a delay. This implies to me that the string is correct and the target program works. Somehow the system() invocation is different from a direct command line invocation. The program compiles and builds fine. I'm using Visual Studio 2010.
Does anyone have ideas on how to make the system() invocation work like the command line invocation?
That really doesn't look like the kind of thing that Windows would be happy with... Try it with backslashes instead:
system("c:\\IQapture\\dmon2_6_IHD -p2 c:\\IQapture\\mon_table_101_Tx8.txt 11 0 0");
If that still doesn't work, you quite likely have one of the following issues:
Your current working directory is wrong;
An environment variable is missing;
Your program is running with the wrong user permissions;
Your program is tying up a resource that the spawned process requires (eg you have not closed a file that it requires as input).
There are a lot of things to consider - the environment, the user running the program, the parent process and what's inherited... Take a look at the parameters to the CreateProcess function. Chances are your system call's invocation isn't matching the command line's (though that may not be the issue, simpler things are more likely.)
I'd advise working backwards from the error to rule out simple causes such as the environment, current directory, etc. before delving into such things as creation flags and security attributes.
You have your slashes backwards. Try:
system("c:/IQapture/dmon2_6_IHD -p2 c:/IQapture/mon_table_101_Tx8.txt 11 0 0");
You can use the backslash \ but because that is an escape sequence starter in a string (for C/C++) that is why you use two in a row. As the compiler will convert \\ into a single slahs in the string:
Thus:
system("c:\\IQapture\\dmon2_6_IHD -p2 c:\\IQapture\\mon_table_101_Tx8.txt 11 0 0");
// Is equivelent to the command line string:
> c:\IQapture\dmon2_6_IHD -p2 c:\IQapture\mon_table_101_Tx8.txt 11 0 0
But Windows has supported both types of slashes for longer than I can remember. So the following command line is equivalent.
> c:/IQapture/dmon2_6_IHD -p2 c:/IQapture/mon_table_101_Tx8.txt 11 0 0
Using '/' in a string (in C/C++) does not require escaping. So you just need to use it as is:
system("c:/IQapture/dmon2_6_IHD -p2 c:/IQapture/mon_table_101_Tx8.txt 11 0 0");
I'm writing a piece of code which deals with math variables and indices, and I'd need to print subscripts and superscripts on a CLI, is there a (possibly cross-platform) way to do that? I'm working in vanilla C++.
Note: I'd like this to be cross-platform, but since from the first answers this doesn't seem to be possible I'm working under MacOS and Ubuntu Linux (so bash).
Thank you
Since most CLIs are really only terminals (pretty dumb ones mostly but sometimes with color), the only cross-platform way I've ever done this is by allocating muliple physical lines per virtual line, such as:
2
f(x) = x + log x
2
It's not ideal but it's probably the best you're going to get without a GUI.
Following you extra information as to what platforms you're mainly interested in:
With Ubuntu at least, gnome-terminal runs in UTF-8 mode by default so the following code shows how to generate the superscripts and subscripts:
#include <stdio.h>
static char *super[] = {"\xe2\x81\xb0", "\xc2\xb9", "\xc2\xb2",
"\xc2\xb3", "\xe2\x81\xb4", "\xe2\x81\xb5", "\xe2\x81\xb6",
"\xe2\x81\xb7", "\xe2\x81\xb8", "\xe2\x81\xb9"};
static char *sub[] = {"\xe2\x82\x80", "\xe2\x82\x81", "\xe2\x82\x82",
"\xe2\x82\x83", "\xe2\x82\x84", "\xe2\x82\x85", "\xe2\x82\x86",
"\xe2\x82\x87", "\xe2\x82\x88", "\xe2\x82\x89"};
int main(void) {
int i;
printf ("f(x) = x%s + log%sx\n",super[2],sub[2]);
for (i = 0; i < 10; i++) {
printf ("x%s x%s ", super[i], sub[i]);
}
printf ("y%s%s%s z%s%s\n", super[9], super[9], super[9], sub[7], sub[5]);
return 0;
}
The super and sub char* arrays are the UTF-8 encodings for the Unicode code points for numeric superscripts and subscripts (see here). The given program will output my formula from above (on one line instead of three), then another test line for all the choices and a y-super-999 and z-sub-75 so you can see what they look like.
MacOS doesn't appear to use gnome-terminal as a terminal program but references here and here seem to indicate the standard terminal understands UTF-8 (or you could download and install gnome-terminal as a last resort).
I'd need to print subscripts and superscripts on a CLI, is there a cross-platform way to do that?
Only if you have a Unicode-capable terminal, which is far from guaranteed. Unicode defines a limited number of sub- and superscript ‘compatibility characters’, you certainly can't use it on any old letter:
₀₁₂₃₄₅₆₇₈₉₊₋₌₍₎ₐₑₒₓ
⁰¹²³⁴⁵⁶⁷⁸⁹⁺⁻⁼⁽⁾ⁿⁱ
Even then you're reliant on there being a glyph for it in the console font, which is also far from guaranteed. Superscript 2 and 3 are likely to exist as they're present in ISO-8859-1; the others may well not work.