Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Buffer wrapping in a stream

4 views
Skip to first unread message

Philippe MESMEUR

unread,
Dec 30, 2009, 4:16:19 AM12/30/09
to
Hi,

I'm currently trying to wrap a buffer in an ostream in order to access
it as following:

void TestOutStream(ostream & a_oStream)
{
a_oStream << "HELLO" << endl << "WORLD" << endl;
a_oStream << "FOO\nBAR" << endl;
a_oStream << "\001\002\003" << endl;
cout << "=> tellp: " << a_oStream.tellp() << endl;
}

const unsigned int SIZE = 32;
char buf[SIZE];

ostream.SetBuffer(buf, SIZE); /// here is what I would like to do
TestOutStream(ostream);

cout << buf << endl;


The writting in the ostream (or an inherited class, of course) would
write in the buffer buf. The buffer overloading would also be managed.


Do such an std class exist?
What should I do?

Thank you very much for your help

Philippe

Philippe MESMEUR

unread,
Dec 30, 2009, 10:10:46 AM12/30/09
to

If I try something like:

stringbuf sbuf;
sbuf.pubsetbuf(buf, SIZE);
ostream os(&sbuf);
TestOutStream(os);

The code works under cygwin/g++ but not Visual Studio.
The problème seems to be in the function setbuf (which is called by
pubsetbuf) that is definded as follow in basic_streambuf:

virtual _Myt *__CLR_OR_THIS_CALL setbuf(_Elem *, streamsize)
{ // offer buffer to external agent (do nothing)
return (this);
}

Can anyone help me...
Philippe

I V

unread,
Dec 30, 2009, 1:04:51 PM12/30/09
to
On Wed, 30 Dec 2009 07:10:46 -0800, Philippe MESMEUR wrote:
> On 30 déc, 10:16, Philippe MESMEUR <philippe.mesm...@gmail.com> wrote:
>> The writting in the ostream (or an inherited class, of course) would
>> write in the buffer buf. The buffer overloading would also be managed.
>>
>> Do such an std class exist?

std::ostringstream sounds like it ought to do what you want (although it
works with std::string, rather than a char array)

> If I try something like:
>
> stringbuf sbuf;
> sbuf.pubsetbuf(buf, SIZE);
> ostream os(&sbuf);
> TestOutStream(os);

I think pubsetbuf is intended to set a buffer used for internal buffering
by the stream, not the characters on which the stringbuf directly
operates; the standard says the effect of calling pubsetbuf is
"implementation defined," so I guess the behavior of both G++ and VC++ is
conforming. The function to get the characters that have been written to
the stringbuf is stringbuf::str() (which returns a std::string).

Branimir Maksimovic

unread,
Dec 30, 2009, 6:42:17 PM12/30/09
to
Philippe MESMEUR wrote:
>
>
> ostream.SetBuffer(buf, SIZE); /// here is what I would like to do
> TestOutStream(ostream);
>
> cout << buf << endl;
>
>
> The writting in the ostream (or an inherited class, of course) would
> write in the buffer buf. The buffer overloading would also be managed.
>
>
> Do such an std class exist?
> What should I do?

You should write streambuf class, in this group archives and
c.l.c++.moderated you have lot of examples, how to do this, also
anu decent stl book should have it.

This is sample of two buffers to write/read strings via rpc...

class RpcOutBuf: public std::streambuf {
public:

RpcOutBuf(const std::string& sName, const std::string& sHost, unsigned
long ulP
virtual ~RpcOutBuf();

protected:

/**
Flushes buffer
*/

int flushBuffer();

/**
when buffer is full this function is called;
@param current character c
function will write current c, and all previous characters
*/
int overflow(int c);

/**
Synchronizes data with server
*/
int sync();

private:
/**
Service number on Rpc Server
*/
unsigned long ulSvcNum_;
/**
Constant which limits buffers size;
*/
static const int sizeOf = 2048;
/**
Internal buffer
*/
char szBuffer_[sizeOf+1];
/**
Rpc Client used for connection
*/
RpcClient rpcOutBufClient_;

};

class RpcInBuf: public std::streambuf {
public:

RpcInBuf(const std::string& sName, const std::string& sHost, unsigned
long ulPr

protected:

/**
Reads characters via RPC into buffer
*/

virtual int underflow();

private:
/**
Service number on Rpc server
*/
unsigned long ulSvcNum_;
/**
Constant which limits buffers size;
*/
static const int sizeOf = 2048;
/**
Internal buffer
*/
char szBuffer_[sizeOf+1];
/**
Rpc Client used for connection
*/
RpcClient rpcInBufClient_;

};

RpcOutBuf::RpcOutBuf(const std::string& sName, const std::string& sHost,
unsign
: ulSvcNum_(ulSvcNum),
rpcOutBufClient_(sName, sHost, ulProg, ulVer)
{
rpcOutBufClient_.regProc("outbuf", ulSvcNum_,
(xdrproc_t)xdr_wrapstring, (xdrproc_t)xdr_int);

setp(szBuffer_, szBuffer_+(sizeOf-1));
}

RpcOutBuf::~RpcOutBuf()
{
sync();
}

int RpcOutBuf::flushBuffer()
{
int num = pptr()-pbase();
try{
if ( num ) {
szBuffer_[num]=0;
int status;timeval t={5,0};
#ifdef DEBUG
std::clog<<"\nbuffer to send: \n"<<szBuffer_<<'\n';
#endif
char*ptr=szBuffer_;
if(rpcOutBufClient_.call("outbuf",(char*)&ptr, (char*)&status,
t) != R
{
rpcOutBufClient_.throwRpcClientError();
}
}
}catch(const std::exception& e)
{
std::cerr<<e.what()<<'\n';
return EOF;
}
pbump(-num);
return num;
}

/**
when buffer is full this function is called;
function will write current c, and all previous characters
*/
int RpcOutBuf::overflow(int c)
{
if(c!=EOF){
*pptr() = c;
pbump(1);
}
if(flushBuffer() == EOF){ /// this is transmit error
return EOF;
}
return c;
}

/**
Synchronizes data with server
*/
int RpcOutBuf::sync(){
if(flushBuffer() == EOF){ /// this is transmit error
return -1;
}
return 0;
}

RpcInBuf::RpcInBuf(const std::string& sName, const std::string& sHost,
unsigned
:ulSvcNum_(ulSvcNum),
rpcInBufClient_(sName, sHost, ulProg, ulVer)
{
rpcInBufClient_.regProc("inbuf", ulSvcNum_,
(xdrproc_t)xdr_int, (xdrproc_t)xdr_wrapstring);
setg(szBuffer_, szBuffer_, szBuffer_); /// this is the place to init
ungetc ar
/// perhaps to put some chars in
buffer,
/// unused for now....
}


/**
Insert new characters into buffer
*/

int RpcInBuf::underflow()
{
if(gptr() < egptr())
{
return *gptr();
}
try {
int request=1;timeval t={5,0};
char*ptr=szBuffer_;
if(rpcInBufClient_.call("inbuf",
(char*)&request,
(char*)&ptr,
t
)!= RPC_SUCCESS
)
{
rpcInBufClient_.throwRpcClientError();
}
#ifdef DEBUF
std::clog<<"\nbuffer contains: \n"<<szBuffer_<<'\n';
#endif
} catch(const std::exception& e)
{
std::cerr<<e.what()<<'\n';
}
if(!strlen(szBuffer_))
{
std::cerr<<"End of file...\n";
return EOF;
}
setg(szBuffer_, szBuffer_, szBuffer_+strlen(szBuffer_));
return *gptr();
}

I wrote this some 10 years ago, don;t ask for explanations ;)


Greets

--
http://maxa.homedns.org/

Dietmar Kuehl

unread,
Jan 1, 2010, 5:30:43 PM1/1/10
to
On Dec 30 2009, 10:16 am, Philippe MESMEUR

<philippe.mesm...@gmail.com> wrote:
> ostream.SetBuffer(buf, SIZE);  /// here is what I would like to do
> TestOutStream(ostream);

I don't know what "ostream.SetBuffer()" is supposed to be. If you are
referring to std::streambuf::pubsetbuf() you'll find that this
operation is only really useful to turn a file stream into being
unbuffered. All other uses are non-portable and in most cases don't do
anything.

From the looks of it you want to set up a stream to write into a
memory area. The way to do this is to create a simple stream buffer
which only sets up a put area which is never resized. The stream
buffer is then used to initialize an std::ostream. Here is how this
would roughly look like:

#include <streambuf>
#include <iostream>

struct membuf:
std::streambuf
{
membuf(char* buffer, size_t size) { this->setp(buffer, buffer +
size); }
char* end() const { return this->pptr(); }
};

int main()
{
char buffer[1024];
membuf sbuf(buffer, sizeof(buffer));
std::ostream out(&sbuf);

out << "hello, world\n";

// the sequence [buffer, sbuf.end()) now contains the written
string
}

The code is untested and most likely contains a few typos but should
essentially work...

0 new messages