#include <cstdarg>
#include <cstdio>
#include <string>
#include <unistd.h>
#include <cassert>
class aprintf_class
{
public:
~aprintf_class()
{
if(audit_length)
flush();
}
void flush()
{
write(1,"[debug, calling write():]\n",26);
write(1,buffer.c_str(),buffer.size());
buffer.clear();
audit_length=0;
}
aprintf_class &operator()(const char* format, ...)
{
assert((buffer.size() == audit_length)
&& "don't have multiple PrintContext active in same thread");
va_list args4len, args;
va_start(args, format);
va_copy(args4len, args); // each va_list can only be used once, so make a copy
// calculate length of what we want to add to the buffer
int len = vsnprintf(NULL, 0, format, args4len);
va_end(args4len);
// create room for it in the buffer
int pos = buffer.size();
buffer.resize(pos + len);
audit_length += len;
// add the new data to the buffer
vsnprintf(buffer.data()+pos,buffer.size()-pos+1,format, args); // +1 because std::string makes room for null terminator
va_end(args);
return *this;
}
private:
int audit_length = 0;
inline static thread_local std::string buffer;
};
#define aprintf aprintf_class()
int main()
{
// simple usage:
aprintf("Hello, %s! The answer is %d\n", "John", 42);
// loop usage with scope
{
aprintf_class pc;
pc("First line (blah %g)\n", 47.89);
for(int i=0;i<2;i++)
pc("%d\n",i);
pc("This line should always go with the first one\n");
} // pc goes out of scope here, which is when it is written
// or this way w/out loop, but it all could have been one printf() anyway...
aprintf("one line\n")("and another\n");
// ok not to wrap with scope as long as you flush()
aprintf_class pc;
pc("something new\n");
pc.flush();
pc("reuse\n");
pc.flush();
aprintf_class pc2;
pc2("from pc2\n"); // won't see this because we didn't flush() before the crash!
// demonstrate abuse of the API, which abort()s
{
aprintf_class p1, p2;
p1("to first context\n");
p2("to second context\n"); // should abort
}
return 0;
}
To embed this project on your website, copy the following code and paste it into your website's HTML: