Is it possible to redirect stdout (NOT cout!) to a stream (ostream) (NOT to a file!)
Why? I am integrating a python interpreter in my application and want to capture print() calls from python code.
I am able to redirect cout this way by using rdbuf() but printf() or print() from python is not redirected since it goes to stdout and not cout
On Linux, you can simply temporarily redirect STDOUT to a temporary file for the duration of the python script.
At the end of the python call you can read the contents of the temporary file and then dump the file.
I'm pretty sure Windows will have a similar mechanism.
Here's a first go with an attempt at some RAII to clean up all the handles.
#include <unistd.h>
#include <cstdio>
#include <stdlib.h>
#include <string>
#include <iostream>
void simulate_python_script() {
std::printf("Written to STDOUT I think");
}
struct auto_fd {
auto_fd(int fd)
: fd_(fd) {}
~auto_fd() {
if (fd_ != -1)
::close(fd_);
}
auto_fd(auto_fd const&) = delete;
auto_fd& operator=(auto_fd const&) = delete;
operator int() const {
return fd_;
}
int fd_;
};
struct file_closer
{
void operator()(FILE* p) const noexcept
{
::fclose(p);
}
};
using auto_fp = std::unique_ptr<FILE, file_closer>;
auto make_auto_fp(FILE* fp)
{
return auto_fp(fp, file_closer());
}
struct push_fd {
push_fd(int target, int new_fd)
: saved_(::dup(target)), target_(target) {
::dup2(new_fd, target);
}
~push_fd() {
if (saved_ != -1) {
::dup2(saved_, target_);
::close(saved_);
}
}
int saved_, target_;
};
int main() {
using namespace std::literals;
auto tempfp = make_auto_fp(::tmpfile());
auto tempfd = auto_fd(::fileno(tempfp.get()));
// redirect STDOUT to the temp file with RAII
{
push_fd fd_save(1, tempfd);
simulate_python_script();
}
// now read the file which Python thought was STDOUT
char buf[256];
while (auto count = ::read(tempfd, buf, 256)) {
if (count < 0) break; // error condition
std::cout.write(buf, count);
}
std::cout << std::endl;
}
Related
I am trying to change multiple if-else statement in my program with either switch and enum or some other object-oriented approach. My purpose is in my code there should not be if-else or very less.
class myClass
{
void readFile();
}
void myClass :: readFile()
{
std::string lineByLine;
std::ifstream myfile;
myfile.open(file path);
if (myfile.is_open())
{
while (std::getline(myfile, lineByLine))
{
std::pair<std::string, std::string> p1 = FindFirstWord(lineByLine);
// FindFirstWord --> will break the line into 2 words, First word and remaining words
while (p1.first.compare("}")) {
if (!p1.first.compare("SCALE")) {
// calling some function
} else {
if (!p1.first.compare("symbol")) {
// calling some function
} else {
if (!p1.first.compare("set_minimum_boundary")) {
// calling some function
} else {
if (!p1.first.compare("line")) {
// calling some function
} else {
if (!p1.first.compare("circle")) {
// calling some function
} else {
if (!p1.first.compare("arc")) {
// calling some function
} else {
if (!p1.first.compare("pin")) {
// calling some function
}
}
}
}
}
}
}
I want to remove the chain of if-else statement using either by switch and enum or some other object oriented approach.
Use a mapping from keyword to handling functions, this is a quick draft of that idea. (You might want to lookup lambda functions)
#include <functional>
#include <iostream>
#include <string>
#include <sstream>
#include <unordered_map>
std::istringstream filestream
{
"SCALE\n"
"symbol\n"
};
class myClass
{
public:
myClass() :
m_handlers
{
{"SCALE", [=]() { HandleScale(); }},
{"symbol", [=]() { HandleSymbol(); }}
}
{
};
void readFile(std::istream& myfile)
{
std::string keyword;
while (myfile >> keyword)
{
// skipped line parsing, to show minimal sample
// lookup if there is a handler for read keyword
auto it = m_handlers.find(keyword);
if ( it != m_handlers.end())
{
auto& callback = it->second;
callback();
}
}
}
void HandleScale()
{
std::cout << "handling scale\n";
}
void HandleSymbol()
{
std::cout << "handling symbol\n";
}
private:
std::unordered_map<std::string, std::function<void()>> m_handlers;
};
int main()
{
myClass object;
object.readFile(filestream);
return 0;
}
If you want to use an enum with a switch, you can do it in the following way:
Define an enum for your action types:
enum class ActionType
{
Scale,
Symbol,
SetMinimumBoundary,
//...
INVALID
};
Add a function for converting a string to the action type enum:
#include <string>
ActionType StringToActionType(std::string const & actionTypeStr)
{
if (actionTypeStr == "SCALE") return ActionType::Scale;
if (actionTypeStr == "symbol") return ActionType::Symbol;
if (actionTypeStr == "set_minimum_boundary") return ActionType::SetMinimumBoundary;
// ...
return ActionType::INVALID;
}
Then use it as shown below (you can add similar logic to myClass::readFile) :
int main()
{
std::string someActionTypeStr; // Initialized to your p1.first
ActionType actionType = StringToActionType(someActionTypeStr);
switch (actionType)
{
case ActionType::Scale: // calling some function
break;
case ActionType::Symbol: // calling some function
break;
case ActionType::SetMinimumBoundary: // calling some function
break;
// ...
default:
// report error ...
break;
}
return 0;
}
here is my code, when i try running this, main does output the information placed into the LoggerComponent, but not the Logger itself. I don't know why, what could be preventing the logger from passing information into the underlying loggercomponent?
i tried using information from http://www.cplusplus.com/reference/map/map/
and from https://www.geeksforgeeks.org/map-associative-containers-the-c-standard-template-library-stl/
logger.cpp:
#include "logger.hpp"
Logger::Logger(bool verbose, bool fileoutput)
{
if(verbose)
{
LoggerComponent c1(LoggerLevel::DEBUG, &std::cout);
addLogger (LoggerType::CONSOLE, &c1);
c1.output (LoggerLevel::DEBUG, "This is the start of console output");
}
if(fileoutput)
{
}
}
void Logger::output(LoggerLevel level, std::string message)
{
for(auto& x : components)
{
x.second->output (level, message);
}
}
void Logger::addLogger(LoggerType type, LoggerComponent* component)
{
if(components.find (type) == components.end ())
components.emplace(type, component);
}
LoggerComponent* Logger::getLogger (LoggerType type)
{
if(components.find (type) != components.end ())
return components.at (type);
return nullptr;
}
void Logger::clearLoggers()
{
components.clear ();
}
void Logger::removeLogger(LoggerType type)
{
if(components.find (type) != components.end ())
components.erase (type);
}
logger.hpp
#ifndef LOGGER_HPP
#define LOGGER_HPP
#include "loggercomponent.hpp"
#include <map>
enum class LoggerType
{
CONSOLE,
FILE
};
class Logger
{
public:
explicit Logger(bool verbose, bool fileoutput);
void output(LoggerLevel level, std::string message);
void addLogger(LoggerType type, LoggerComponent* component);
void removeLogger(LoggerType type);
void clearLoggers();
LoggerComponent* getLogger(LoggerType type);
private:
std::map<LoggerType, LoggerComponent*> components;
};
#endif // LOGGER_HPP
main.cpp
#include "logger.hpp"
int main()
{
int* p;
int i = 5;
int j = 5;
p = &i;
std::cout << p << std::endl;
p = &j;
std::cout << p << std::endl;
LoggerComponent c(LoggerLevel::DEBUG, &std::cout);
c.output (LoggerLevel::INFO, "Hello World!");
c.output (LoggerLevel::CRITICAL, "Hello World!");
Logger c2(true, true);
std::cout << c.getOutputStream () << std::endl;
std::cout << c2.getLogger (LoggerType::CONSOLE)->getOutputStream () << std::endl;
c2.output (LoggerLevel::INFO, "Hello World!");
c2.output (LoggerLevel::CRITICAL, "Hello World!");
}
loggercomponent.hpp
#ifndef LOGGERCOMPONENT_HPP
#define LOGGERCOMPONENT_HPP
#include <iostream>
#include <string>
#include <ctime>
enum class LoggerLevel
{
INFO,
DEBUG,
WARNING,
ERROR,
CRITICAL
};
class LoggerComponent
{
public:
explicit LoggerComponent(LoggerLevel level, std::ostream* output);
LoggerLevel getMinimumLevel();
std::ostream* getOutputStream();
void setMinimumLevel(LoggerLevel level);
void setOutputStream(std::ostream* output);
void output(LoggerLevel level, std::string outputMessage);
private:
std::string getLevelString(LoggerLevel level);
LoggerLevel minimumLevel;
std::ostream* outputStream;
};
#endif // LOGGERCOMPONENT_HPP
loggercomponent.cpp
#include "loggercomponent.hpp"
LoggerComponent::LoggerComponent(LoggerLevel level,
std::ostream* output)
{
setMinimumLevel (level);
setOutputStream (output);
}
void LoggerComponent::setMinimumLevel(LoggerLevel level)
{
if(minimumLevel != level)
minimumLevel = level;
}
void LoggerComponent::setOutputStream(std::ostream *output)
{
if(outputStream != output)
outputStream = output;
}
LoggerLevel LoggerComponent::getMinimumLevel()
{
return minimumLevel;
}
std::ostream* LoggerComponent::getOutputStream()
{
return outputStream;
}
std::string LoggerComponent::getLevelString(LoggerLevel level)
{
switch (level) {
case LoggerLevel::INFO:
return "INFO";
case LoggerLevel::DEBUG:
return "DEBUG";
case LoggerLevel::WARNING:
return "WARNING";
case LoggerLevel::ERROR:
return "ERROR";
case LoggerLevel::CRITICAL:
return "CRITICAL";
}
return nullptr;
}
void LoggerComponent::output(LoggerLevel level, std::string outputMessage)
{
if(level >= minimumLevel)
{
time_t now = time(nullptr);
*outputStream << ctime(&now)
<< (getLevelString (level) + " >> " + outputMessage)
<< std::endl << std::endl;
}
}
output:
0x60fda8
0x60fdac
Tue Oct 01 12:29:14 2019
CRITICAL >> Hello World!
Tue Oct 01 12:29:14 2019
DEBUG >> This is the start of console output
0x6fd0cd00
0x60fdb0
You are storing a pointer to an object local to the constructor (c1) in components. It will be destroyed and the pointer invalid when you try to use it later.
Store the object itself (or a std::unique_ptr to it if you have a good reason not to store the object itself) in the map instead.
I am importing a mat file to my C++ code. After importing data, performing calculations and saving to another place I want to free the memory occupied by the original data.
Is there any specific function to perform that. Would just deleting the pointer returned by mxGetData() free the memory?
This is the class I have created to import mat file
#ifndef READMAT_H
#define READMAT_H
#include "mat.h"
#include "matrix.h"
#include "mex.h"
#include "program_exception.h"
#include "stdint.h"
class readmat
{
private:
const size_t *dimarray;
const char **dir;
MATFile *pmat;
int ndir;
mxArray *painfo,*pa;
const char *file;
int minute;
int second;
const char *name;
const char *name1;
bool isdouble;
no_mat_exception noMAT;
public:
//with default value
readmat(const char *f);
// get number of dimensions
int getnumbrofdimensions() const;
// get pointer to array
void* getarraypointer() const;
// get pointer to each dimension size
const size_t* dimensionpointer() const;
//number of elements
int numberofelements() const;
~readmat();
};
#endif
The following is the cpp implementation
#include "readmat.h"
#include <iostream>
#include "mat.h"
#include "matrix.h"
#include "mex.h"
using namespace std;
// set the file name
readmat::readmat(const char *f)
{
file = f;
pmat = matOpen(file, "r");
if (pmat == NULL) {
throw noMAT;
}
else
{
dir = (const char **)matGetDir(pmat, &ndir);
if (dir == NULL) {
printf("Error reading directory of file %s\n", file);
}
else if (ndir > 1)
{
cout << "The number of variables are larger than 1" << endl;
}
else
{
mxFree(dir);
matClose(pmat);
pmat = matOpen(file, "r");
if (pmat == NULL) {
throw noMAT;
}
else
{
painfo = matGetNextVariableInfo(pmat, &name);
matClose(pmat);
}
pmat = matOpen(file, "r");
if (pmat == NULL) {
throw noMAT;
}
else
{
pa = matGetNextVariable(pmat, &name1);
matClose(pmat);
}
}
}
}
int readmat::getnumbrofdimensions() const
{
return mxGetNumberOfDimensions(painfo);
}
void* readmat::getarraypointer() const
{
//return mxGetPr(pa);
return mxGetData(pa);
}
const size_t* readmat::dimensionpointer() const
{
return mxGetDimensions(painfo);
}
int readmat::numberofelements() const
{
return mxGetNumberOfElements(painfo);
}
readmat::~readmat()
{
mxFree(pa);
mxFree(painfo);
}
Here when I delete the object program trigger a break point in the file free.c.
The MATLAB demo on edit([matlabroot '/extern/examples/eng_mat/matdgns.c']); seems to suggest using mxDestroyArray instead of mxFree.
When calling mxGetData(). The only thing the function does, is returning a pointer to the real (in contrast to imaginary) data that is stored in the mxArray.
So there is no need to free memory, since nothing is dynamically allocated during this call.
i am using the proxygen for making a simple web server. i am restricted to use proxygen.I am using proxygen default echo server example i want to print the header values whenever a request is sent to the server. below is the code that i think i should modify.but what exactly i am unsure of.:
#include "customHandler.h"
#include <iostream>
#include <proxygen/httpserver/RequestHandler.h>
#include <proxygen/httpserver/ResponseBuilder.h>
#include <proxygen/lib/http/HTTPMessage.h>
#include <proxygen/lib/http/HTTPMethod.h>
using namespace std;
using namespace proxygen;
namespace EchoService {
EchoHandler::EchoHandler(EchoStats* stats): stats_(stats) {
}
void EchoHandler::onRequest(std::unique_ptr<HTTPMessage> headers) noexcept {
//------------------HERE TO MODIFY I THINK-------------------//
}
void EchoHandler::onBody(std::unique_ptr<folly::IOBuf> body) noexcept {
if (body_) {
body_->prependChain(std::move(body));
} else {
body_ = std::move(body);
}
}
/*
.header("Request-Number",
//this sets the request number
folly::to<std::string>(stats_->getRequestCount()),"test-b")*/
void EchoHandler::onEOM() noexcept {
ResponseBuilder(downstream_)
.status(200, "OK")
//Response is set Here...........ex-> .body(std::move("some Response object"))
.body(std::move(body_))
.sendWithEOM();
}
void EchoHandler::onUpgrade(UpgradeProtocol protocol) noexcept {
// handler doesn't support upgrades
}
void EchoHandler::requestComplete() noexcept {
delete this;
}
void EchoHandler::onError(ProxygenError err) noexcept {
delete this;
}
}
correct me if i am wrong.
Try this:
void EchoHandler::onRequest(std::unique_ptr<HTTPMessage> headers) noexcept
{
HTTPHeaders head = headers->getHeaders();
head.forEach([&] (const string& header, const string& val) {
cout << header << ": " << val<<endl;
});
}
I need to redirect an ofstream to a file and timestamp every line that's printed.
(It's part of a logging system).
I have a working class that manages to do just that but it refuses to flush the file when std::endl is emmited. I'd apreciate any help on that.
(If there is a simpler way to do this do tell).
#include <iostream>
#include <streambuf>
#include <fstream>
#include <sys/time.h>
#include <cstring>
#include <memory>
class TimeStampBuf: public std::streambuf {
public:
explicit TimeStampBuf(std::streambuf* dest) :
_dest(dest),
_isAtStartOfLine(true),
_owner( NULL) {
}
explicit TimeStampBuf(std::ostream& dest) :
_dest(dest.rdbuf()),
_isAtStartOfLine(true),
_owner(&dest) {
_owner->rdbuf(this);
}
virtual ~TimeStampBuf() {
if (_owner != NULL) {
_owner->rdbuf(_dest);
}
}
protected:
virtual int overflow(int ch) {
if (_isAtStartOfLine) {
char timebuff[30];
timeval curTime;
gettimeofday(&curTime, NULL);
strftime(timebuff, sizeof(timebuff), "%Y-%m-%d %H:%M:%S:",
localtime(&curTime.tv_sec));
sprintf(timebuff + strlen(timebuff), "%03u\t",
(unsigned int) curTime.tv_usec / 1000);
_dest->sputn(timebuff, strlen(timebuff));
}
_isAtStartOfLine = ch == '\n';
return _dest->sputc(ch);
}
private:
std::streambuf *_dest;
bool _isAtStartOfLine;
std::ostream *_owner;
};
class OutputRedirectAndStamp {
public:
OutputRedirectAndStamp(std::string file, std::ostream &s = std::cout, std::ios::openmode mode = std::ios::out){
_s=&s;
_file=file;
if(_file.size()){
_mode=mode;
_buf.open(file.c_str(),mode);
_coutBuf = s.rdbuf((std::streambuf*)&_buf);
}
_tsb.reset(new TimeStampBuf(s));
}
void reopen(void){
_tsb.reset();
if(_file.size()){
_s->rdbuf(_coutBuf); //reset to previous output
_buf.close();
_buf.open(_file.c_str(),_mode);
_coutBuf = _s->rdbuf((std::streambuf*)&_buf);
}
_tsb.reset(new TimeStampBuf(*_s));
}
~OutputRedirectAndStamp() {
_tsb.reset();
if(_file.size()){
_s->rdbuf(_coutBuf); //reset to previous output
}
}
private:
std::string _file;
std::ios::openmode _mode;
std::ostream *_s;
std::filebuf _buf;
std::streambuf *_coutBuf;
std::unique_ptr<TimeStampBuf> _tsb;
};
int main() //example main
{
std::unique_ptr<OutputRedirectAndStamp> a;
a.reset(new OutputRedirectAndStamp("test.txt",std::cout,std::ios::app | std::ios::out));
std::cout<<"this is written to file"<<2<<std::endl;
a->reopen();
std::cout<<"this is written to file also"<<std::endl;
a.reset();
std::cout<<"this is written to stdout"<<std::endl;
return 0;
}
When you flush an std::ostream, the stream buffer's pubsync() is called which in turn calls the virtual function sync(). If you don't override sync() it will just claim that it succeeded by returning 0. From your sync() override you should just call the held stream buffer's pubsync():
int TimeStampBuf::sync() {
return _dest->pubsync();
}