How to redirect assert output in C++? - c++

Is it possible to redirect assert output to a file when its parameter is false? I know its default behavior is to write a message to stderr, but the following didn't work as I expected:
#include <iostream>
#include <assert>
#include <fstream>
using namespace std;
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
ofstream ofs;
ofs.open("test.txt", ios_base::out);
ofs << "A";
cerr << "B";
cerr.rdbuf(ofs.rdbuf());
cerr << "C";
assert(1 == 2);
return 0;
}
//---------------------------------------------------------------------------
Results in test.txt:
AC
And results in stdout:
B
Assertion failed: 1 == 2, file C:\xxx\Unit1.cpp, line 14
Abnormal program termination
I was expecting that these 2 last lines printed in stdout were in test.txt file though.
I've also tried using, instead of...
cerr.rdbuf(ofs.rdbuf());
the following:
freopen("test.txt", "a", stderr);
but it hasn't worked as well.
I've also seen some posts (as C: how to redirect stderr from System-command to stdout or file?) suggesting dup2 to redirect streams such as stderr, which that is defined in unistd.h. But I'm at Windows using C++Builder and it doesn't seem available.

You can redirect all output to stderr, or any other standard file handle to a file at the start of your program.
freopen( "error.log","w",stderr);
Read about this here:
http://support.microsoft.com/kb/58667
#edit: if the output goes to stdout, then you need to do:
freopen( "error.log","w",stdout );
If you want to append and not overwrite the error.log:
freopen( "error.log","aw",stdout );

Related

Redirecting standard output - Switched from VS2013 to VS2017, exception on writing

I've recently switched a project from using the VS2013 compiler to VS2017, and now the following code appears not to be working:
#include <windows.h>
#include <Fcntl.h>
#include <io.h>
#include <iostream>
#include <exception>
if( RedirectOutput )
{
//Setup stdout
HANDLE handle_stdout = GetStdHandle( STD_OUTPUT_HANDLE );
int fileDesc_stdout = _open_osfhandle( (long)handle_stdout, _O_TEXT );
if( fileDesc_stdout == -1 )
{
throw std::exception( "fileDesc_stdout is not valid" );
}
FILE* new_stdout = _fdopen( fileDesc_stdout, "w" );
if( !new_stdout )
{
throw std::exception( "new_stdout is not valid" );
}
FILE old_stdout = *stdout;
*stdout = *new_stdout;
std::cout.clear();
std::cout << "Output Redirected!\n";
}
This code is intended to redirect standard output to a console window, either the one that kicked off the current process or a console that is created via AllocConsole. (I've added the last line for testing purposes.)
The first time writing to cout occurs, the following exception is thrown (it otherwise doesn't write output and fails silently from then on):
Debug Assertion Failed!
Program: w:\build\MyApp.exe
File: minkernel\crts\ucrt\src\appcrt\stdio_flsbuf.cpp
Line: 26
Expression: ("inconsistent IOB fields", stream->_ptr - stream->_base >= 0)
For information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts.
(Press Retry to debug the application)
I can see that stdout is coming from corecrt_wstdio.h, but when I insert a breakpoint and add a watch, it says that the stdout is undefined, so I can't check the value.
Any ideas?
So I searched around a bit and found this post on SO.
Essentially, all of the code I posted can be replaced with the following:
freopen("CONOUT$", "w", stdout);
The first parameter of freopen is a filename, so I wonder if CONOUT$/CONIN$ represent an actual file, or if the function treats that input as a special case.

Establishing via code whether console should be saved to a file (and the name of such file)

I know that when a program is executed in the console, one can specify an output file where the console can be saved. For instance, in Windows:
C:\>myprogram.exe > output.txt
However, is there a way to establish via code, i.e. programatically: 1) whether the console should be saved to a file; and 2) the name of the file to which the output should be saved, if any.
I know that I can of course use fprint or std::cout to print each string to a file the same I can do to the console. But for performance sake, I would like to know if it is possible to establish via code that the entire console should be saved to a file.
Yes, you can write code like this:
int main( int argc, char * argv[] ) {
if ( argc > 1 ) {
// there is a filename on the command line
ofstream ofs( argv[1] ); // open named file
// do something with ofs
}
else {
// do something with standard output
}
}
You can use dup2 function (in windows _dup2). It can solve the problem to log to the console exclusively or log to the file exclusively. This is not a solution to log to both.
You can use some logging library (log4cxx, log4cpp, Boost.Log, QDebug, etc.) They should have abilities you need - e.g. log to both console and file.
Solution with dup2/_dup2:
You can open new file, then call dup2 to exchange stdout with that opened file. It can work with c++ streams but I did not try it.
Relevant part of Microsoft example (all checks removed, pleas se original example. I don't have Windows so I can't verify it.)
#include <stdlib.h>
#include <stdio.h>
#include <io.h>
int main(int argc, char ** argv) {
FILE *DataFile;
fopen_s( &DataFile, "data", "w" ); // open file "data" for writing
_dup2( _fileno( DataFile ), 1 ); // exchange "standard output/console" with file "data"
printf("this goes to 'data' file'\r\n"); // print to standard output, but it will be saved to "data" file
fflush( stdout );
fclose( DataFile );
}
Complete linux verified and working C++ example
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <iostream>
int main(int argc, char ** argv) {
FILE *DataFile;
DataFile = fopen( "data", "w" ); // open file "data" for writing
dup2( fileno( DataFile ), 1 ); // exchange "standard output/console" with file "data"
std::cout << "this goes to 'data' file from c++" << std::endl;
fflush( stdout );
fclose( DataFile );
}

freopen doesn't work for C stdin

While executing the following code:
#include <iostream>
using std::cout;
#include <cstdio>
/* stdin
stdout
FILE
freopen */
int main() {
for (FILE* f : {stdin, stdout})
if (nullptr == freopen(nullptr, (f == stdin) ? "rb" : "wb", f))
cout << f << '\n';
}
... I get the following output:
0x7edde180
... which means that freopen(nullptr, "rb", stdin) returned nullptr, failing.
Am I doing anything wrong?
Compiler: i586-mingw32msvc-g++ on the GNU OS
Environment: wine (x86)
http://msdn.microsoft.com/en-us/library/wk2h68td.aspx
If path, mode, or stream is a null pointer, or if filename is an empty string, these functions invoke the invalid parameter handler, as described in Parameter Validation. If execution is allowed to continue, these functions set errno to EINVAL and return NULL.
In short, it looks like the MSVC++ implementation of freopen does not allow for a NULL pathname.

how we can call a system function like pwd or ls -l without using system() or exec() function using c or c++ in linux?

I am trying to print the path of the current directory using
this
execl ("/bin/pwd", "pwd", NULL);
output: /home/user/Ubuntu
and want to print a desired text before the current path.
for example:
my name /home/user/ubntu
how this will be done?
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
using namespace std;
int main(){
string command;
while(command != "exit"){
cout<< "B-17235"<<return execl ("/bin/pwd", "pwd", NULL);
cin>> command;
}
return 0;
}
Think that the majority of Unix-Linux-Gnu commands are written in C or C++. Generally there are direct API calls either system calls (man 2) or standard C library (man 3) to get the information or do the job.
To get working directory, just use getcwd() as suggested by alk.
char buffer[256];
if (NULL == getcwd(buffer, sizeof(buffer))) {
perror("can't get current dir");
return 1;
}
If you wanted to get the output of a more complex command, the most direct way would be to use popen that encloses the fork, exec, and pipe management for you :
FILE *fd = popen("/bin/pwd", "r");
char buffer[256];
if (fgets(buffer, sizeof(buffer), fd) == NULL) {
perror("can't read command");
return 1;
}
if (buffer[strlen(buffer) - 1] != '\n') {
fprintf(stderr, "path too long";
return 1;
}
pclose(fd);
// ok the working directory is is buffer
You should not use that for a command as simple as pwd.
And don't forget : man is your friend ! man getcwd and man popen will give you plenty of information ...
I am trying to print the path of the current directory
Use the library function getcwd().
To have the function available it might be necessary to #define _XOPEN_SOURCE 500 or similar (please see the man-page linked above for details on this).

ifstream creates file if it doesn't exist

I'm having some trouble writing a Linux console app which reads apache logs.
I need to handle bash script arguments, the last one being a path to the log file.
My problem is that if the file doesn't exist, I would like to throw an exception.
But when I try to open the file in read-only mode, instead of failing it creates the file !
Here's the code :
// logreader.h
#include <string>
#include <sstream>
#include <iostream>
#include <fstream>
#include <stdexcept>
class LogReader
{
public:
LogReader(int, const char **);
virtual ~LogReader();
// ...
private:
std::ifstream log_;
};
// logreader.cpp
#include <logreader.h>
LogReader::LogReader(int argc, const char ** argv):
log_()
{
log_.exceptions(std::ifstream::failbit | std::ifstream::badbit);
for (int i = 1; i < argc; ++i)
{
std::string arg(argv[i]);
if (i == argc - 1)
{
try
{
log_.open(arg.c_str(), std::ifstream::in);
}
catch (std::ifstream::failure)
{
throw std::runtime_error("The file " + arg + " wasn't opened");
}
}
}
}
LogReader::~LogReader()
{
}
// main.cpp
#include <logreader.h>
int main(int argc, const char ** argv)
{
LogReader(argc, argv);
return 0;
}
Script call:
jmcomets $ ./test -g -l
jmcomets $ ls -l
-rw-rw-r-- 1 jmcomets jmcomets 0 Nov 14 22:41 -l
Since you are opening an std::ifstream it is necessary to add std::ios_base::in (or any other spelling of the std::ios_base::openmode) according to 27.9.1.9 [ifstream.members] paragraph 4: The flag is automatically added by the call to open(). Note that an std::ofstream or an std::fstream would automatically add std::ios_base::out (27.9.1.13 [ofstream.members] paragrpah 3) or std::ios_base::in | std::ios_base::out (27.9.1.17 [fstream.members] paragraph 3), both of which resulting in a new file being created if it doesn't exist (and there are write permissions, etc.).
If the code you posted creates a new file, the implementation of the standard C++ library is wrong: when only the flag std::ios_base::in is specified, the file is open "as if" using the open mode "r" with fopen() (27.9.1.4 [filebuf.members] paragraph 5). fopen() in turn doesn't create a new file when it gets an open mode of "r" (7.21.5.3 paragraph 3).
You can set the failbit in the exceptions flag for the ifstream:
std::ifstream log;
log.exceptions ( std::ifstream::failbit );
try {
log.open ("test.txt");
}
catch (std::ifstream::failure e) {
std::cout << "Exception opening/reading file\n";
}
Source
I've tested, and ifstream will throw a failure exception if the file cannot be opened, e.g. file not found, no read permissions. It will open read-only.
You need to specify ifstream::in as a second parameter as:
log.open(arg.c_str(), ifstream::in)
You can also do:
std::ifstream log(arg.c_str(), ifstream::in);
and skip the call to open()
Edit with something Linux compatible;
Try opening with fopen before writing. If the file DNE the FILE pointer will be null.
FILE * file;
file = fopen ("myfile.txt","r");
if (file == NULL)
//throw if fopen didn't already.
else
//do stuff with my file