How can I use C++ to write to an opened terminal? - c++

I am trying to communicate with a program (xfoil) and read and write to its command line. Xfoil can take many parameters in its built in terminal.
I can open the program using system("path") but how do I input more commands to the opened xfoil terminal? Once I can do that I can do all that I need to do with the terminal commands.

Tiny Process Library is a good library for interacting with processes.
Checkout example 6 and 7 for giving commands to a process. https://gitlab.com/eidheim/tiny-process-library/blob/master/examples.cpp

How can I use C++ to write to an opened terminal
On linux, there are 7+ steps:
1) open a terminal
I find ctrl-alt t most convenient
press and hold ctrl and alt, then press t
There is also a selection LXTerminal on a mouse menu
Note - There is a way for your program to open a 'default' terminal,
and c++ can use the technique, but it is not c++, and I always seem to
need to change the defaults for my use.
2) using the terminal, you manually find the name of the terminal by:
type the command "tty" into the terminal
Typical response on my system:
hostname#username:~$ tty
/dev/pts/1
The terminal name is always of the form "/dev/pts/x" on my Linux system, where x is a number.
3) For my programs (that use a second terminal), my code accepts the x portion (of the terminal response) as command parameter 1, and uses that parameter to create a path file name (PFN) to the terminal.
std::string aTermPFN = "/dev/pts/"; // partial address
aTermPFN += argv[1]; // ouput tty identified by argv[1]
// creating /dev/pts/<argv[1]>
// thus creating PFN of "/dev/pts/1"
4) My code typically provides a confirmation of the number during creation. (recommended)
std::cout << "accessing '" << aTermPFN
<< "' with std::ofstream " << std::endl;
5) and then creates (or attempts to create) the ofstream object
std::ofstream* ansiTerm = new std::ofstream(aTermPFN);
6) and perform a few checks on it ...
if (!ansiTerm->is_open())
{
std::cerr << "Can not access '" << aTermPFN << "'" << std::endl;
assert(0); // abort
}
7) When done with term, be sure to clean up
ansiTerm->close();
delete ansiTerm;
// you can avoid the delete if you use an appropriate smart pointer.
Now all output to that 2nd terminal uses the 'ansiTerm' object, I happen to use a more generic term in that code (not a pointer, but reference) : "termRef".
Examples of use
// mostly, in the app where these sample exist, I output text at computed
// screen locations
// ansi terminals provide goto row col ansi functions
// the style is simply position the cursor,
termRef << m_ansi.gotoRC(3, col) << ss.str() << std::flush;
// then output text-----------------^^^^^^^^ (ss is stringstream)
// ansi terminals can clear
void clearScr() { termRef << m_ansi.clrscr() << std::flush; }
// ansi terminals can draw simple borders (not-fancy)
{ // across top gotoRC (int row, int col )
termRef << m_ansi.gotoRC ( tlcRow, tlcCol+1);
for ( int i=0; i<borderWidth; ++i) termRef << m_acs.HLINE;
termFlush();
}

Related

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!

In C/C++, how do you edit a certain 'coordinate' in stdout?

I've been using Vim a lot lately, and I was wondering how the program manages to change the characters at certain positions in the terminal. For example, when using :rc, it replaces the character under the cursor with c.
I have also seen similar things done with Homebrew, which prints a progress bar to the screen and updates it when necessary.
How is this done in C/C++?
There is no standard way of doing this in C++.
It is done with OS dependent lbiraries, such as curses and similar libraries (ncurses) in the Unix/Linux world. Some of these libraries have been ported on across platforms (example: PDCurses)
For very simple things such as a progress bar or a counter, and as long as you remain on a single line there is the trick of using "\r" (carriage return) in the output, to place the cursor back at the begin of the current line. Example:
for (int i = 0; i < 100; i++) {
cout << "\rProgress: " << setw(3) << i;
this_thread::sleep_for(chrono::milliseconds(100));
}
Certainly, using ncurses or similar library is a good answer. An alternative may be to use ANSI Escape Codes to control the cursor in some terminal emulators (but not Windows command shell). For example, this code prints a line in multiple colors and then moves the cursor to 2,2 (coordinates are 1-based with 1,1 being the upper left corner) and prints the word "red" in the color red.
#include <iostream>
#include <string>
const std::string CSI{"\x1b["};
const std::string BLUE{CSI + "34m"};
const std::string RED{CSI + "31m"};
const std::string RESET{CSI + "0m"};
std::ostream &curpos(int row, int col)
{
return std::cout << CSI << row << ';' << col << 'H';
}
int main()
{
std::cout << "This is " << BLUE << "blue" << RESET << " and white.\n";
curpos(2,2);
std::cout << RED << "red" << RESET << '\n';
}
As mentioned that's not a matter of any C/C++ standard operations provided with stdout or cout (besides writing the necessary control characters to the screen).
Controlling the screen cursor of an ASCII terminal totally depends on implementation of the particular terminal program used, and besides a very narrow set of control characters, there's no standard established.
There are libraries like ncurses for a broader variety of linux terminal implementations, or PDcurses for a windows CMD shell.
I'm not sure to understand you completely but with creating an array of 100 elements of type char you can modify any position of the array and loop it with a std:cout to mostrate it on the console.
Perhaps could be better define the array of 50 chars to resuce the size of the printed result.
For example, if you have to print a progessbar in the 1% process, you should print:
Char progressbar[100] = {'X','','','','','','','','',........}

How to handle the output of terminal command execution from C++, if command doesn't just printing the result, but enters some interactive mode?

This question was inspired by that one.
I've understood how to execute utils from C or C++ code. But how can we get result from some command, that doesn't just printing the result, but enters some interactive mode and works until we press Ctrl+zor something like this? The example of such a command is top.
Usually you don't. You launch the command with options that makes them non interactive.
Technically you could get information from an interactive terminal interface, but you will have a hard time doing it, because in order for the interface to be human like, terminal capabilities are often used (termcaps, ncurses..) which basically works by outputting special characters, so you 'll have to dodge these characters by knowing what is expected when, so except if the interface is quite simple and static (actually even in this case) it's gonna be a pain.
Some applications (such as "dialog") can work interactively and write their final result to a different output stream. In the case of dialog, that is done using stderr (by default). If you have control over the application, you can provide for doing something like that, for passing back information to the calling application.
You simply can access stdin, stdout and stderr. Before you fork create the pipes as needed and fork and after that call execv or any other variant.
An example can be found here:
https://jineshkj.wordpress.com/2006/12/22/how-to-capture-stdin-stdout-and-stderr-of-child-program/
There is also a common used library to capture the output of a child program and react with some new actions on found items. This library was first written for tcl but can also be used for c and c++.
http://expect.sourceforge.net/
With some glue code around the expect lib your source can look like this:
int main()
{
Tcl_Interp *interp = Tcl_CreateInterp();
Expect_Init(interp);
// read from file
int lfd = open( "test.txt", O_RDONLY );
int fd = exp_spawnfd(lfd);
// or read from application
int fd ? exp_spawn("top","top", (char*)0)));
bool cont= true;
Expections set1 =
{
{ exp_glob, "YYY", []( Expection& exp)->void { cout << "found: YYY" << endl; }},
{ exp_regexp, "XXX ([0-9]+)", []( Expection& exp)->void { cout << "found: XXX" << exp.GetResult(1) << endl;}},
{ exp_glob, "END", [&cont]( Expection& exp)->void { cout << "EOF" << endl; cont = false; }}
};
int cnt = 0;
do
{
cout << "Run " << cnt << endl;
cnt++;
Expect ( fd, set1, 2 );
} while ( cont );
cout << "Finish" << endl;
return 0;
}

Reading .vtk file

I'm working on VTK (Qt on ubuntu 10.04).
I'm trying to read a .vtk file having 3D image. As I could understand, this
http://www.vtk.org/Wiki/VTK/Examples/Cxx/IO/GenericDataObjectReader
makes it possible to read any vtk file. However, it does not work. All I get is :
Starting /home/taha/Downloads/VTK/Examples/qtcreator-build/GenericDataObjectReader...
Usage: /home/taha/Downloads/VTK/Examples/qtcreator-build/GenericDataObjectReader InputFilename
/home/taha/Downloads/VTK/Examples/qtcreator-build/GenericDataObjectReader exited with code 1
1) Does the code I'm using work properly? Should I change something?
Even though I know that I need to pass the filename as arguments, I may not know how to do it from command prompt. I searched on internet in detail for this but the ways I'm following might be wrong.
2) How could one pass filename as arguments to program in C++?
If you desire to call the compiled programm from the example given from vtk-wiki simply open up a shell/dos window and type:
yourExecutable.exe path-to-file.vtk
As the output stated above, you did not match the requirements for the example to run (2 parameters).
One parameter (the first) is the usage (to what program you call) and the second one containing the path to the vtk-file you want to read.
If you don't want to call it with parameters you could change the given example to this:
int main ( int argc, char *argv[] )
{
// simply set filename here (oh static joy)
std::string inputFilename = "setYourPathToVtkFileHere";
// Get all data from the file
vtkSmartPointer<vtkGenericDataObjectReader> reader =
vtkSmartPointer<vtkGenericDataObjectReader>::New();
reader->SetFileName(inputFilename.c_str());
reader->Update();
// All of the standard data types can be checked and obtained like this:
if(reader->IsFilePolyData())
{
std::cout << "output is a polydata" << std::endl;
vtkPolyData* output = reader->GetPolyDataOutput();
std::cout << "output has " << output->GetNumberOfPoints() << " points." << std::endl;
}
return EXIT_SUCCESS;
}
and simply replace setYourPathToVtkFileHere with the (preferably absolute) your path.

Why does my output go to cout rather than to file?

I am doing some scientific work on a system with a queue. The cout gets output to a log file with name specified with command line options when submitting to the queue. However, I also want a separate output to a file, which I implement like this:
ofstream vout("potential.txt"); ...
vout<<printf("%.3f %.5f\n",Rf*BohrToA,eval(0)*hatocm);
However it gets mixed in with the output going to cout and I only get some cryptic repeating numbers in my potential.txt. Is this a buffer problem? Other instances of outputting to other files work... maybe I should move this one away from an area that is cout heavy?
You are sending the value returned by printf in vout, not the string.
You should simply do:
vout << Rf*BohrToA << " " << eval(0)*hatocm << "\n";
You are getting your C and C++ mixed together.
printf is a function from the c library which prints a formatted string to standard output. ofstream and its << operator are how you print to a file in C++ style.
You have two options here, you can either print it out the C way or the C++ way.
C style:
FILE* vout = fopen("potential.txt", "w");
fprintf(vout, "%.3f %.5f\n",Rf*BohrToA,eval(0)*hatocm);
C++ style:
#include <iomanip>
//...
ofstream vout("potential.txt");
vout << fixed << setprecision(3) << (Rf*BohrToA) << " ";
vout << setprecision(5) << (eval(0)*hatocm) << endl;
If this is on a *nix system, you can simply write your program to send its output to stdout and then use a pipe and the tee command to direct the output to one or more files as well. e.g.
$ command parameters | tee outfile
will cause the output of command to be written to outfile as well as the console.
You can also do this on Windows if you have the appropriate tools installed (such as GnuWin32).