I'm basically trying to derive from wfilebuf so I can both output to a file and intercept the output to print it to the console/debug window as well as illustrated here:
http://savingyoutime.wordpress.com/2009/04/21/ and/or here: http://savingyoutime.wordpress.com/2009/04/22/40/
(ancient supporting ideas here: http://www.horstmann.com/cpp/streams.txt)
I've almost got it, but I can't seem to be able to both write to the underlying file AND peek at the input.
I overrode the sync() function similar to the second example but it seems that pbase() and pptr() are always NULL unless I set a buffer with setp(...), but this seems to break the file output. The file is always empty!
My crude attempt at this is below:
class LoggerBuffer : public wfilebuf {
// Functions
public:
LoggerBuffer();
~LoggerBuffer();
void open(const wchar_t loggerFile[]);
void close();
int sync();
int_type overflow(int_type c = EOF);
void setState(int newState);
// Variables
private:
int currentState;
static const int BUFFER_SIZE = 10;
wchar_t buffer[BUFFER_SIZE];
};
class LoggerStream : public wostream {
// Functions
public:
LoggerStream();
~LoggerStream();
void open(const wchar_t loggerFile[] = 0);
void close();
void setState(int newState);
};
LoggerBuffer::LoggerBuffer() {
wfilebuf::open("NUL", wios::out); currentState = 1;
}
LoggerBuffer::~LoggerBuffer() {
wcout << "Destruction of LoggerBuffer" << endl;
}
void LoggerBuffer::open(const wchar_t loggerFile[]) {
wcout << "LoggerBuffer Opening " << loggerFile << endl;
close();
wfilebuf* temp = wfilebuf::open(loggerFile, wios::out); //ios::out | ios::app | ios::trunc
setp (buffer, buffer+(BUFFER_SIZE-1));
}
void LoggerBuffer::close() {
wfilebuf::close();
}
int LoggerBuffer::sync() {
wcout << " Syncing ";
int out_waiting = pptr() - pbase();
wcout << out_waiting << " characters!";
wcout << endl;
wcout << "pptr(): " << (unsigned int)pptr() << endl;
return wfilebuf::sync();
}
LoggerBuffer::int_type LoggerBuffer::overflow(int_type c) {
wcout << "overflow! (" << (wchar_t)c << ")" << endl;
if (c == EOF)
return EOF;
if (sync() == EOF)
return EOF;
return wfilebuf::overflow(c);
}
void LoggerBuffer::setState(int newState) {
wcout << "New buffer state = " << newState << endl;
currentState = newState;
}
LoggerStream::LoggerStream() : wostream(new LoggerBuffer), wios(0) {
}
LoggerStream::~LoggerStream() {
delete rdbuf();
}
void LoggerStream::open(const wchar_t loggerFile[]) {
wcout << "LoggerStream Opening " << loggerFile << endl;
((LoggerBuffer*)rdbuf())->open(loggerFile);
}
void LoggerStream::close() {
((LoggerBuffer*)rdbuf())->close();
}
void LoggerStream::setState(int newState) {
wcout << "New stream state = " << newState << endl;
((LoggerBuffer*)rdbuf())->setState(newState);
}
Full disclosure: I asked a question regarding something similar earlier: Simple wostream logging class (with custom stream manipulators)
I think I have solved that problem though.
Any help is greatly appreciated! Thanks!
I'd use a filtering streambuf, that does no buffering of its own, instead passing data through to a real streambuf (i.e., one that does real buffering) for each of the destinations. This should simplify your code quite a bit and let you concentrate on the parts you really care about.
Related
I am building an networking application, and being a newbie to Boost asio and networking as a whole had this doubt which might be trivial. I have this application which reads from a file and calls apis accordingly. I am reading json (example):
test.json
{
"commands":
[
{
"type":"login",
"Username": 0,
"Password": "kk"
}
]
}
My main program looks like this :
int main() {
ba::io_service ios;
tcp::socket s(ios);
s.connect({{},8080});
IO io;
io.start_read(s);
io.interact(s);
ios.run();
}
void start_read(tcp::socket& socket) {
char buffer_[MAX_LEN];
socket.async_receive(boost::asio::null_buffers(),
[&](const boost::system::error_code& ec, std::size_t bytes_read) {
(void)bytes_read;
if (likely(!ec)) {
boost::system::error_code errc;
int br = 0;
do {
br = socket.receive(boost::asio::buffer(buffer_, MAX_LEN), 0, errc);
if (unlikely(errc)) {
if (unlikely(errc != boost::asio::error::would_block)) {
if (errc != boost::asio::error::eof)
std::cerr << "asio async_receive: error " << errc.value() << " ("
<< errc.message() << ")" << std::endl;
interpret_read(socket,nullptr, -1);
//close(as);
return;
}
break; // EAGAIN
}
if (unlikely(br <= 0)) {
std::cerr << "asio async_receive: error, read " << br << " bytes" << std::endl;
interpret_read(socket,nullptr, br);
//close(as);
return;
}
interpret_read(socket,buffer_, br);
} while (br == (int)MAX_LEN);
} else {
if (socket.is_open())
std::cerr << "asio async_receive: error " << ec.value() << " (" << ec.message() << ")"
<< std::endl;
interpret_read(socket,nullptr, -1);
//close(as);
return;
}
start_read(socket);
});
}
void interpret_read(tcp::socket& s,const char* buf, int len) {
if(len<0)
{
std::cout<<"some error occured in reading"<<"\n";
}
const MessageHeaderOutComp *obj = reinterpret_cast<const MessageHeaderOutComp *>(buf);
int tempId = obj->TemplateID;
//std::cout<<tempId<<"\n";
switch(tempId)
{
case 10019: //login
{
//const UserLoginResponse *obj = reinterpret_cast<const UserLoginResponse *>(buf);
std::cout<<"*********[SERVER]: LOGIN ACKNOWLEDGEMENT RECEIVED************* "<<"\n";
break;
}
}
std::cout << "RX: " << len << " bytes\n";
if(this->input_type==2)
interact(s);
}
void interact(tcp::socket& s)
{
if(this->input_type == -1){
std::cout<<"what type of input you want ? option 1 : test.json / option 2 : manually through command line :";
int temp;
std::cin>>temp;
this->input_type = temp;
}
if(this->input_type==1)
{
//std::cout<<"reading from file\n";
std::ifstream input_file("test.json");
Json::Reader reader;
Json::Value input;
reader.parse(input_file, input);
for(auto i: input["commands"])
{
std::string str = i["type"].asString();
if(str=="login")
this->login_request(s,i);
}
std::cout<<"File read completely!! \n Do you want to continue or exit?: ";
}
}
The sending works fine, the message is sent and the server responds in a correct manner, but what I need to understand is why is the control not going to on_send_completed (which prints sent x bytes). Neither it prints the message [SERVER]: LOGIN ACKNOWLEDGEMENT RECEIVED, I know I am missing something basic or am doing something wrong, please correct me.
login_request function:
void login_request(tcp::socket& socket,Json::Value o) {
/*Some buffer being filled*/
async_write(socket, boost::asio::buffer(&info, sizeof(info)), on_send_completed);
}
Thanks in advance!!
From a cursory scan it looks like you redefined buffer_ that was already a class member (of IO, presumably).
It's hidden by the local in start_read, which is both UB (because the lifetime ends before the async read operation completes) and also makes it so the member _buffer isn't used.
I see a LOT of confusing code though. Why are you doing synchronous reads from within completion handlers?
I think you might be looking for the composed-ooperation reads (boost::asio::async_read and boost::asio::async_until)
I know, this may be a lot to ask, but can anyone help me debug this code:
#include <stdio.h>
#include <string.h>
#include <omnetpp.h>
using namespace omnetpp;
class Node : public cSimpleModule
{
private:
cMessage *out_msg;
long no_sent = 0;
long no_rcvd = 0;
cOutVector rcvdRecord;
cLongHistogram Statistics;
public:
Node();
virtual ~Node();
protected:
virtual void initialize() override;
virtual void handleMessage(cMessage *msg) override;
virtual void finish() override;
};
Define_Module(Node);
Node::Node()
{
out_msg = nullptr;
}
Node::~Node()
{
delete out_msg;
}
void Node::initialize()
{
out_msg = nullptr;
if (strcmp("sender", getName()) == 0) {
EV << "Scheduling first send to t=5.0s\n";
scheduleAt(5.0, out_msg);
out_msg = new cMessage("Sending Message");
}
}
void Node::handleMessage(cMessage *msg)
{
if (msg == out_msg) {
EV << "Sending message to receiver\n";
send(out_msg, "out");
out_msg = nullptr;
no_sent++;
simtime_t delay = par("delayTime");
scheduleAt(simTime() + delay, out_msg);
}
else {
out_msg = msg;
no_rcvd++;
rcvdRecord.record(out_msg);
Statistics.collect(out_msg); //what's going on here ?
}
}
void Node::finish()
{
EV << "Sent: " << no_sent << endl;
EV << "Received: " << no_rcvd << endl;
EV << "Messages sent, mean: " << Statistics.getMean() << endl;
EV << "Messages sent, standard deviation: " << Statistics.getStddev() << endl;
EV << "Messages sent, variance: " << Statistics.getVariance() << endl;
recordScalar("#sent", no_sent);
recordScalar("#received", no_rcvd);
Statistics.recordAs("Message Statistics");
}
I get the following error message:
Exercise2.cc:66:38: error: no matching function for call to
'omnetpp::cOutVector::record(omnetpp::cMessage*&)'
Exercise2.cc:67:39: error: no matching function for call to
'omnetpp::cLongHistogram::collect(omnetpp::cMessage*&)'
So I really don't know what this is supposed to tell me. Aren't these built-in functions, part of the cOutVector or cLongHistogram classes respectively?
Aren't these built-in functions, part of the cOutVector or
cLongHistogram classes respectively?
They aren't. Well, cOutVector does have a member function named record, it just can't take a cMessage * as an argument, so that specific function overload you wanted to use doesn't exist. Same with cLongHistogram and collect.
Just take a look at the documentation:
A cOutVector object can write doubles to the output vector file ...
And, by the way, what exactly do you expect to see as a "histogram of messages"? :D This comic comes to my mind...
To record the messages (not into a cOutVector), you can enable event logging. The resulting file can be visualized in the Sequence Chart tool of the IDE, see: https://docs.omnetpp.org/tutorials/tictoc/part2/#25-visualizing-on-a-sequence-chart
I'm writing program using Boost::Asio, I want to implement simple chat. Currently I'm struggling with problem that when I put some code inline of class function it's working, but when same code is provided by another class object is not. I think it could be connected to Boost::Asio, but I'm not sure:
void Connection::session(socket_ptr sock)
{
try{
for(;;) {
char mesg[1024];
boost::system::error_code error;
size_t length = sock->read_some(boost::asio::buffer(mesg), error);
if (error == boost::asio::error::eof){
disconnected(sock);
break;
}
else if (error)
throw boost::system::system_error(error);
message msg(mesg,length);
char *data;
data = msg.getData();
std::cout << "In session " << strlen(data) << " " << data;
/*This is working
string s_msg,s_data;
s_msg = mesg;
s_data = s_msg.substr(2,length);
std::vector<char> writable(s_data.size() + 1);
std::copy(s_data.begin(), s_data.end(), writable.begin());
std::cout << "In session " << strlen(&writable[0]) << " " << &writable[0];
send_all(sock,&writable[0],strlen(&writable[0]));
*/
send_all(sock,data,strlen(data));
}
}
catch (std::exception& e){
std::cerr << "Exception in thread: " << e.what() << "\n";
}
}
Class message that is only parsing data
message::message(char *c_msg, size_t length)
{
msg = c_msg;
id = msg.at(0);
data = msg.substr(2,length);
}
char* message::getData()
{
std::vector<char> writable(data.size() + 1);
std::copy(data.begin(), data.end(), writable.begin());
std::cout << data;
std::cout << &writable[0];
return &writable[0];
}
So when using class message this line:
std::cout << "In session " << strlen(data) << " " << data;
I get:
st String //this is cout from message getData
st String //this is cout from message getData
In session 0
With inline version:
In session 11 st String
So, in session function string is empty although message cout shows something opposite.
I don't know if it's important, but this function is invoked as new thread from main.
Regards,
Piotr
You're returning the address of a temporary:
char* message::getData()
{
std::vector<char> writable(data.size() + 1);
//...
return &writable[0];
}
This is undefined behaviour.
I'm assuming that data is just a std::string. You could do this instead:
const char* message::getData() const
{
return data.c_str();
}
I have a program in c++, during the program i use :
static ofstream s_outF(file.c_str());
if (!s_outF)
{
cerr << "ERROR : could not open file " << file << endl;
exit(EXIT_FAILURE);
}
cout.rdbuf(s_outF.rdbuf());
Meaning i redirect my cout to a file.
What would be the easiest way to return the cout back to the standard output?
thanks.
Save the old streambuf before you change cout's streambuf :
auto oldbuf = cout.rdbuf(); //save old streambuf
cout.rdbuf(s_outF.rdbuf()); //modify streambuf
cout << "Hello File"; //goes to the file!
cout.rdbuf(oldbuf); //restore old streambuf
cout << "Hello Stdout"; //goes to the stdout!
You can write a restorer to do that automatically as:
class restorer
{
std::ostream & dst;
std::ostream & src;
std::streambuf * oldbuf;
//disable copy
restorer(restorer const&);
restorer& operator=(restorer const&);
public:
restorer(std::ostream &dst,std::ostream &src): dst(dst),src(src)
{
oldbuf = dst.rdbuf(); //save
dst.rdbuf(src.rdbuf()); //modify
}
~restorer()
{
dst.rdbuf(oldbuf); //restore
}
};
Now use it based on scope as:
cout << "Hello Stdout"; //goes to the stdout!
if ( condition )
{
restorer modify(cout, s_out);
cout << "Hello File"; //goes to the file!
}
cout << "Hello Stdout"; //goes to the stdout!
The last cout would output to stdout even if condition is true and the if block is executed.
I've created an ofstream and there is a point in which I need to check if it's empty or has had things streamed into it.
Any ideas how I would go about doing this?
The std::ofstream files don't support this directly. What you can do if this is an important requirement is to create a filtering stream buffer which internally used std::filebuf but also records if there was any output being done. This could look look as simple as this:
struct statusbuf:
std::streambuf {
statusbuf(std::streambuf* buf): buf_(buf), had_output_(false) {}
bool had_output() const { return this->had_output_; }
private:
int overflow(int c) {
if (!traits_type::eq_int_type(c, traits_type::eof())) {
this->had_output_ = true;
}
return this->buf_->overflow(c);
}
std::streambuf* buf_;
bool had_output_;
};
You can initialize an std::ostream with this and query the stream buffer as needed:
std::ofstream out("some file");
statusbuf buf(out.rdbuf());
std::ostream sout(&buf);
std::cout << "had_output: " << buf.had_output() << "\n";
sout << "Hello, world!\n";
std::cout << "had_ouptut: " << buf.had_output() << "\n";
you could use ofstream.rdbuff to get the file buffer and than use streambuf::sgetn to read it. I believe that should work.