Redirect stdout back to console - c++

There is plenty of documentation about redirecting stdout and stderr to a file instead of the console. How do you redirect it back again? The code below shows my intention, but outputs "stdout is printed to console" only once.
I'm guessing I need to grab the console output buffer, store it somewhere, redirect stdout to file, then restore the console buffer?
#pragma warning(disable:4996)
#include <cstdio>
int main()
{
std::printf("stdout is printed to console\n");
if (std::freopen("redir.txt", "w", stdout)) {
std::printf("stdout is redirected to a file\n"); // this is written to redir.txt
std::fclose(stdout);
std::printf("stdout is printed to console\n");
}
getchar();
return 0;
}

With thanks to the articles in the comments above I found the information I needed. The dup and dup2 functions were what I needed. Note that based on info here dup and dup2 are deprecated in favour or _dup and _dup2. A working example can be found on MSDN here, but is duplicated below in case the link breaks in the future.
// crt_dup.c
// This program uses the variable old to save
// the original stdout. It then opens a new file named
// DataFile and forces stdout to refer to it. Finally, it
// restores stdout to its original state.
#include <io.h>
#include <stdlib.h>
#include <stdio.h>
int main( void )
{
int old;
FILE *DataFile;
old = _dup( 1 ); // "old" now refers to "stdout"
// Note: file descriptor 1 == "stdout"
if( old == -1 )
{
perror( "_dup( 1 ) failure" );
exit( 1 );
}
_write( old, "This goes to stdout first\n", 26 );
if( fopen_s( &DataFile, "data", "w" ) != 0 )
{
puts( "Can't open file 'data'\n" );
exit( 1 );
}
// stdout now refers to file "data"
if( -1 == _dup2( _fileno( DataFile ), 1 ) )
{
perror( "Can't _dup2 stdout" );
exit( 1 );
}
puts( "This goes to file 'data'\n" );
// Flush stdout stream buffer so it goes to correct file
fflush( stdout );
fclose( DataFile );
// Restore original stdout
_dup2( old, 1 );
puts( "This goes to stdout\n" );
puts( "The file 'data' contains:" );
_flushall();
system( "type data" );
}

Related

How to open and close files properly in C++?

I want to open some files, redirect the output of them and then go back to previous situation, so I wrote:
int fd = open("test.txt", O_WRONLY | O_CREAT, 0666);
dup(1);
dup2(3, 1);
close(3);
//call my func() to print in std::cout which will write to test.txt
dup2(4, 1);//Close file
I know that the default input channel is in index 0, output channel (screen) in index 1 and stderr in index 2 so fd will get 3, dup 1 will create another pointer to output channel in index 4, then I replace screen with my file and close that isn't needed.
My code is correct, but did I forget anything else or can it be made shorter/ more clear?
Most importantly, in case one line fails I want to return false but this will be a lot of checks and in every advance step we need to close more. How can I solve this problem?
What if I wanted in case of failure to make everything go back to default situation?
Please Note, I only know and want to use open,close,dup,dup2
Most importantly it is the duty of a programmer to write reliable, faultless code, and this includes thorough error checking. Error checking often makes for large parts of the code, especially when user interaction is part of the program. But, there is no way around it, if you want to be/become a good programmer.
That said, it is easy (in a first step) to change your code so that it does not depend on specific file descriptor numbers (not tested).
int fileFd;
int redirectFd1;
int redirectFd2;
fileFd = open( "test.txt", O_WRONLY | O_CREAT, 0666 );
redirectFd1 = dup( 1 );
redirectFd2 = dup2( fileFd, 1 );
close( fileFd );
//call my func() to print in std::cout which will write to test.txt
dup2( redirectFd1, 1 );//Close file
Next step is to add error checking.
int fileFd;
int redirectFd1;
int redirectFd2;
if ( ( fileFd = open( "test.txt", O_WRONLY | O_CREAT, 0666 ) ) == -1 ) {
// open() failed. Do appropriate error handling here...
exit( 1 );
}
if ( ( redirectFd1 = dup( 1 ) ) == -1 ) {
// dup() failed. Do appropriate error handling here...
// Since we arrvied here, fileFd *is* open. So we need to close it.
// But redirectFd1 is *not* open
close( fileFd );
exit(1);
}
if ( ( redirectFd2 = dup2( fileFD, 1 ) ) == -1 ) {
// dup() failed. Do appropriate error handling here...
// Since we arrvied here, fileFd *and* redirectFd1 *are* open.
// So we need to close them.
// But redirectFd2 is *not* open
close( fileFd );
close( redirectFd1 );
exit(1);
}
close( fileFd );
//call my func() to print in std::cout which will write to test.txt
if ( dup2( redirectFD1, 1 ) == -1 ) {
// dup2() failed. Do appropriate error handling here...
close( redirectFd1 );
}
close( redirectFd1 );
One can argue whether checking for errors on the close( fileFd ) statement is needed or nor. Fact is that open() succeeded, so it would be very unsusual for close() to fail here. One can also argue whether checking for errors on the last dup2() is needed or not.
In general, I keep track of open files, and take care of closing in case of errros in a clean-up routine. The code might look like this:
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
int fileFd;
bool fileFdIsOpen = false;
int redirectFd1;
bool redirectFd1IsOpen = false;
int redirectFd2;
bool redirectFd2IsOpen = false;
void cleanup();
int main( int argc, char* argv[] ) {
int stdoutFd = fileno( stdout );
if ( ( fileFd = open( "test.txt", O_WRONLY | O_CREAT, 0666 ) ) == -1 ) {
// open() failed. Do appropriate error handling here...
exit( 1 );
}
fileFdIsOpen = true;
if ( ( redirectFd1 = dup( stdoutFd ) ) == -1 ) {
// dup() failed. Do appropriate error handling here...
cleanup();
exit(1);
}
redirectFd1IsOpen = true;
if ( ( redirectFd2 = dup2( fileFd, stdoutFd ) ) == -1 ) {
// dup() failed. Do appropriate error handling here...
cleanup();
exit(1);
}
redirectFd2IsOpen = true;
close( fileFd );
fileFdIsOpen = false;
//call my func() to print in std::cout which will write to test.txt
if ( dup2( redirectFd1, stdoutFd ) == -1 ) {
// dup2() failed. Do appropriate error handling here...
cleanup();
}
cleanup();
exit (0);
}
void cleanup() {
if ( fileFdIsOpen ) {
close( fileFd );
fileFdIsOpen = false;
}
if ( redirectFd1IsOpen ) {
close( redirectFd1 );
redirectFd1IsOpen = false;
}
if ( redirectFd2IsOpen ) {
close( redirectFd2 );
redirectFd2IsOpen = false;
}
}
I know that default input channel is in index 0, output channel
(screen) in index 1 and stderr in index 2 so fd will get 3
That's undetermined, process can be run in away those ids would be altered and starting descriptor also might be different from stderr+1. Theremore, on Linux there are situation where process can be created with none open, but that's different.
In C header <stdio.h> defines those variables that are supposed to be initialized by runtime library.
extern FILE *stdin;
extern FILE *stdout;
extern FILE *stderr;
Code you had shown is pretty much C code, not C++, but you can use <cstdio> and fileno function to obtain descriptor
int fileno(FILE *stream);
You have to check returned results of fileno, dup and open to be sure that you program didn't run into some limitations imposed on it, and errno variable would tell you a reason. On some other platforms, like Windows, more appropriate error reporting functions do exist.

load xml values and pass it into string in vc++

Am working in vc++ and trying to load an xml file and load the entire data into a string but am not getting the results
char text[700] = {""};
TiXmlDocument doc( "'demotest.xml" );
bool loadOkay = doc.LoadFile();
if ( !loadOkay )
{
printf( "Could not load test file 'demotest.xml'. Error='%s'. Exiting.\n", doc.ErrorDesc() );
system("PAUSE");
exit( 1 );
}
printf( "** Demo doc read from disk: ** \n\n" );
printf( "** Printing via doc.Print **\n" );
//doc.Print( stdout );
{
printf( "** Printing via TiXmlPrinter **\n" );
TiXmlPrinter printer;
doc.Accept( &printer );
fprintf( stdout, "%s", printer.CStr() );
//upto this line its working fine in console. but when I convert this string am getting struck
wsprintf(text, "%s", (char*)printer.CStr());
AddLOG_message(text, 0, true);
}
Last two lines I should get the entire content of the xml including header, elements and values.
Please help.
I'd do it like this, with less C code, more C++ code and deprecating the risky char array of length magic number 700:
TiXmlPrinter printer;
doc.Accept( &printer );
doc.Print(); // simpler for stdout output
std::string text = printer.CStr(); // easier, safer this way
AddLOG_message( text.c_str(), 0, true );

Opening a console from app

I am working on a C and C++ app that uses some graphical engine to handle gtk windows (Opencv/highgui). This app does some minor output to stdout/cout.
On Windows, starting this kind of app from the desktop automatically opens a console, showing the user what is been written on standard output, either with "printf()" or "std::cout".
On Linux, if I start it from a previously opened console, no trouble. But if I start it through the desktop (double-click), then linux doesn't open an associated console, and data written on stdout/cout is lost.
Seems that this is the normal behaviour on Linux (?).
I would like to automatically open a console from my app, when compiled on a linux platform.
This seems like a dupe of this one, the point is, it doesn't work! I have at present the following code:
#ifndef __WIN32
filebuf* console = new filebuf();
console->open( "/dev/tty", ios::out );
if( !console->is_open() )
cerr << "Can't open console" << endl;
else
cout.ios::rdbuf(console);
#endif
(cerr is redirected in a file using freopen() )
I keep getting "Can't open console". I tried replacing the console name:
console->open( "/dev/console", ios::out );
but that didn't change.
Am I in the right direction? What can I try next? Should I try to open specifically the terminal application (xterm)? But then, how could I "connect" that console with my app?
Solution 1
Very simple solution you might not like: have a script that runs your application in a terminal using gnome-terminal -x <your_program> <your_args>. Double-clicking the script will open the terminal.
Solution 2
A bit more involved solution add a '--noconsole' argument to your application. If the argument is present, just run your application. If '--noconsole' is not present:
if( fork() == 0 ) {
execlp("gnome-terminal", "gnome-terminal", "-x", argv[0], "--noconsole", NULL );
} else {
exit( 0 );
}
This creates a child process in which it runs the application in gnome-terminal using the --noconsole arugment. Makes sense? A bit hacky, but hey, it works.
Solution 3
This one is the trickiest solution, but in some ways more elegant. The idea is to redirect our stdout to a file and create a terminal running tail -f <file_name> --pid=<parent_pid>. This prints the output of the parent process and terminates when the parent dies.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
// Create terminal and redirect output to it, returns 0 on success,
// -1 otherwise.
int make_terminal() {
char pidarg[256]; // the '--pid=' argument of tail
pid_t child; // the pid of the child proc
pid_t parent; // the pid of the parent proc
FILE* fp; // file to which output is redirected
int fn; // file no of fp
// Open file for redirection
fp = fopen("/tmp/asdf.log","w");
fn = fileno(fp);
// Get pid of current process and create string with argument for tail
parent = getpid();
sprintf( pidarg, "--pid=%d", parent );
// Create child process
child = fork();
if( child == 0 ) {
// CHILD PROCESS
// Replace child process with a gnome-terminal running:
// tail -f /tmp/asdf.log --pid=<parent_pid>
// This prints the lines outputed in asdf.log and exits when
// the parent process dies.
execlp( "gnome-terminal", "gnome-terminal", "-x", "tail","-f","/tmp/asdf.log", pidarg, NULL );
// if there's an error, print out the message and exit
perror("execlp()");
exit( -1 );
} else {
// PARENT PROCESS
close(1); // close stdout
int ok = dup2( fn, 1 ); // replace stdout with the file
if( ok != 1 ) {
perror("dup2()");
return -1;
}
// Make stdout flush on newline, doesn't happen by default
// since stdout is actually a file at this point.
setvbuf( stdout, NULL, _IONBF, BUFSIZ );
}
return 0;
}
int main( int argc, char *argv[]) {
// Attempt to create terminal.
if( make_terminal() != 0 ) {
fprintf( stderr, "Could not create terminal!\n" );
return -1;
}
// Stuff is now printed to terminal, let's print a message every
// second for 10 seconds.
int i = 0;
while( i < 10 ) {
printf( "iteration %d\n", ++ i );
sleep( 1 );
}
return 0;
}
Your examples all "open" a console - in the sense that one opens a file. This doesn't do anything to a gui. If you want to do that you will have to open a gtk window and direct the output to it.

Read() from file descriptor hangs

Hey, hopefully this should be my last PTY-related question and I can move onto more exciting issues. (c;
Here's a set of small functions I have written for creating and reading/writing to a pty: http://pastebin.com/m4fcee34d The only problem is that they don't work! After I run the initializer and writeToPty( "ls -l" ) , 'output' from readFromPty is still empty.
Ubuntu, QT C++
EDITED: Ok, I can confirm all this stuff works except for the read loop. In the debuggers' locals/watchers tab it shows that the QString 'output' actually does get the right data put in it, but after it ( the read() ) runs out of characters from the output it runs and then hangs. What is going on and how can I fix it?
Thanks! (c:
#include <iostream>
#include <unistd.h>
#include <utmp.h>
#include <pty.h>
#include <QString>
#include <QThread>
// You also need libutil in your .pro file for this to compile.
class CMkPty
{
public:
CMkPty( int *writeChannel, int *readChannel );
~CMkPty();
int runInPty( char *command );
int writeToPty( char *input );
int readFromPty( QString output );
int m_nPid;
private:
int m_nMaster, m_nSlave, m_nPosition, m_nBytes;
char *m_chName;
void safe_print( char *s );
char m_output;
};
CMkPty::CMkPty( int *masterFD, int *slaveFD )
{
openpty( &m_nMaster, &m_nSlave, (char*)0, __null, __null );
m_nPid = fork();
*masterFD = m_nMaster;
*slaveFD = m_nSlave;
if( m_nPid == 0 )
{
login_tty( m_nSlave );
execl( "/bin/bash", "-l", (char*)0 );
return;
}
else if( m_nPid > 0 )
{
return;
}
else if( m_nPid < 0 )
{
std::cout << "Failed to fork." ;
return;
}
}
CMkPty::~CMkPty()
{
close( m_nMaster );
close( m_nSlave );
}
int CMkPty::writeToPty( char *szInput )
{
int nWriteTest;
write( m_nMaster, szInput, sizeof( szInput ) );
nWriteTest = write( m_nMaster, "\n", 1 );
if( nWriteTest < 0 )
{
std::cout << "Write to PTY failed" ;
return -1;
}
return 0;
}
int CMkPty::readFromPty( QString output )
{
char buffer[ 160 ];
m_nBytes = sizeof( buffer );
while ( ( m_nPosition = read( m_nMaster, buffer, m_nBytes ) ) > 0 )
{
buffer[ m_nPosition ] = 0;
output += buffer;
}
return 0;
}
EDIT: Here's a link to the question with the code that finally worked for me.
I'm note entirely familiar with posix, but after reading this page http://pwet.fr/man/linux/fonctions_bibliotheques/posix/read I had some insight. What's more, I don't see you adjusting your M_nBytes value if you haven't read as much as you were expecting on the first pass of the loop.
edit: from that link, perhaps this will be of some help:
If some process has the pipe open for writing and O_NONBLOCK is clear, read() shall block the calling thread until some data is written or the pipe is closed by all processes that had the pipe open for writing.
When attempting to read a file (other than a pipe or FIFO) that supports non-blocking reads and has no data currently available:
*
If O_NONBLOCK is clear, read() shall block the calling thread until some data becomes available.
so essentially, if you're not in an error state, and you tell it to keep reading, it will block until it finds something to read.

How can I execute external commands in C++/Linux?

I just want to know which is the best way to execute an external command in C++ and how can I grab the output if there is any?
Edit: I Guess I had to tell that I'm a newbie here in this world, so I think I'm gonna need a working example. For example I want to execute a command like:
ls -la
how do I do that?
Use the popen function.
Example (not complete, production quality code, no error handling):
FILE* file = popen("ls", "r");
// use fscanf to read:
char buffer[100];
fscanf(file, "%100s", buffer);
pclose(file);
An example:
#include <stdio.h>
int main() {
FILE * f = popen( "ls -al", "r" );
if ( f == 0 ) {
fprintf( stderr, "Could not execute\n" );
return 1;
}
const int BUFSIZE = 1000;
char buf[ BUFSIZE ];
while( fgets( buf, BUFSIZE, f ) ) {
fprintf( stdout, "%s", buf );
}
pclose( f );
}
popen definitely does the job that you're looking for, but it has a few drawbacks:
It invokes a shell on the command you're executing (which means that you need to untaint any user provided command strings)
It only works in one direction, either you can provide input to the subprocess or you can read its output.
If you want invoke a subprocess and provide input and capture output then you'll have to do something like this:
int Input[2], Output[2];
pipe( Input );
pipe( Output );
if( fork() )
{
// We're in the parent here.
// Close the reading end of the input pipe.
close( Input[ 0 ] );
// Close the writing end of the output pipe
close( Output[ 1 ] );
// Here we can interact with the subprocess. Write to the subprocesses stdin via Input[ 1 ], and read from the subprocesses stdout via Output[ 0 ].
...
}
else
{ // We're in the child here.
close( Input[ 1 ] );
dup2( Input[ 0 ], STDIN_FILENO );
close( Output[ 0 ] );
dup2( Output[ 1 ], STDOUT_FILENO );
execlp( "ls", "-la", NULL );
}
Of course, you can replace the execlp with any of the other exec functions as appropriate.