среда, 16 мая 2007 г.

Для перенаправления stdout в область памяти или файл

Для перенаправления stdout в область памяти (или файл) необходимо написать небольшую конструкцию.


Редирект в память или строку (std::string)

// make stdout buffer
char buf[16384]={0};
int fdpipe[2];
// make pipe
_pipe( fdpipe, sizeof(buf), O_BINARY );
// backup stdout handle
int old=_dup(_fileno(stdout));
// replace stdout handle with write-pipe
_dup2(fdpipe[1], _fileno(stdout));

// test output
fprint(stdout,"test");

// get collected buffer
int r = read(fdpipe[0],buf,sizeof(buf));
buf[r]=0;
// restore original stdout
_dup2(old, _fileno(stdout));
// make string
std::string str(buf);


Пример для работы с STL std::cout.


std:stringstream oss;
std::cout.rdbuf( oss.rdbuf() );
std::cout << "here's some text";


Пример редиректа в файл:

stream = freopen( "freopen.out", "w", stderr );
fprintf( stdout, "successfully reassignedn" );
fclose( stream );

C#

  class StdOutCapture
{
char buf[32768];
int fdpipe[2];
int old;

public:
class Error:public std::exception
{
std::string er;
public:
Error(const char*p):er(p)
{
}
const char* what() const throw()
{
return er.c_str();
}
};

StdOutCapture()
{
if(_pipe( fdpipe, sizeof(buf), _O_TEXT | _O_NOINHERIT)!=0)
throw Error(_sys_errlist[errno]);
old=_dup(_fileno(stdout));
if(old==-1)
throw Error(_sys_errlist[errno]);
if(_dup2(fdpipe[1], _fileno(stdout))!=0)
throw Error(_sys_errlist[errno]);
if(_close(fdpipe[1])!=0)
throw Error(_sys_errlist[errno]);
}
~StdOutCapture()
{
}
operator std::string()
{
int r = read(fdpipe[0],buf,sizeof(buf));
if(_dup2(old, _fileno(stdout))!=0)
throw Error(_sys_errlist[errno]);
if(_close(old)!=0)
throw Error(_sys_errlist[errno]);
return std::string(buf);
}
};

В Visual C++ 2005 есть ограничение на использоание стандартных потоков. Проблема заключается в том, что при запуске из под отладчика и без него stdout, stderr ведут себя по разному. При работе из под отладчика данные потоки создаются их использование производится стандартным классом StdOutCapture. Однако при запуске того же приложения без отладчика потоки отстутствуют. Пока я не нашел решения позволяющее корректно обходить указанную проблему, предлогаю вашему вниманию заглушку.


/// In Visual C++ 2005, there is a behavior change. If stdout or stderr is not
/// associated with an output stream (for example, in a Windows application
/// without a console window), the file descriptor returned is -2. In previous
/// versions, the file descriptor returned was -1. This change allows applications
/// to distinguish this condition from an error.
class FakeStreams
{
int outpipe[2];
int errpipe[2];
char buf[32768];
public:

class Error:public std::exception
{
std::string er;
public:
Error(const char*p):er(p)
{
}
const char* what() const throw()
{
return er.c_str();
}
};

FakeStreams()
{
if(_fileno(stdout)==-2)
{
if(_pipe( outpipe, sizeof(buf), _O_TEXT | _O_NOINHERIT)!=0)
throw Error(_sys_errlist[errno]);
*stdout=*_fdopen(outpipe[1],"w");
}
if(_fileno(stderr)==-2)
{
if(_pipe( errpipe, sizeof(buf), _O_TEXT | _O_NOINHERIT)!=0)
throw Error(_sys_errlist[errno]);
*stderr=*_fdopen(errpipe[1],"w");
}
}
};

0 коммент.:

Отправить комментарий