/*-*-mode:c++-*-*/
/* --------------------------------------------------------------------
* Filename:
* src/iodevice.cc
*
* Description:
* Implementation of the IODevice class.
* --------------------------------------------------------------------
* Copyright 2002, 2003 Andreas Aardal Hanssen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
* --------------------------------------------------------------------
*/
#include "iodevice.h"
#include "convert.h" // BincStream
//#include "session.h" // getEnv/hasEnv
#include <stdlib.h>
#include <unistd.h>
using namespace ::std;
using namespace ::Binc;
//------------------------------------------------------------------------
IODevice::IODevice(int f) : flags(f | IsEnabled),
maxInputBufferSize(0),
maxOutputBufferSize(0),
timeout(0),
readCount(0), writeCount(0),
outputLevel(0), outputLevelLimit(0),
error(Unknown), errorString("Unknown error"),
dumpfd(0)
{
}
//------------------------------------------------------------------------
IODevice::~IODevice(void)
{
}
//------------------------------------------------------------------------
IODevice &IODevice::operator <<(ostream &(*source)(ostream &))
{
if (!(flags & IsEnabled) || outputLevel > outputLevelLimit)
return *this;
static std::ostream &(*endl_funcptr)(ostream &) = endl;
if (source != endl_funcptr)
return *this;
outputBuffer << "\r\n";
if (dumpfd)
::write(dumpfd, "\r\n", 2);
if (flags & FlushesOnEndl)
flush();
else if (flags & HasOutputLimit)
if (outputBuffer.getSize() > maxOutputBufferSize)
flush();
return *this;
}
//------------------------------------------------------------------------
bool IODevice::canRead(void) const
{
return false;
}
//------------------------------------------------------------------------
void IODevice::clear()
{
if (!(flags & IsEnabled))
return;
inputBuffer.clear();
outputBuffer.clear();
}
//------------------------------------------------------------------------
bool IODevice::flush()
{
if (!(flags & IsEnabled))
return true;
WriteResult writeResult = WriteWait;
do {
unsigned int s = outputBuffer.getSize();
if (s == 0)
break;
if (!waitForWrite())
return false;
writeResult = write();
if (writeResult == WriteError)
return false;
writeCount += s - outputBuffer.getSize();
} while (outputBuffer.getSize() > 0 && writeResult == WriteWait);
outputBuffer.clear();
return true;
}
//------------------------------------------------------------------------
void IODevice::setFlags(unsigned int f)
{
flags |= f;
}
//------------------------------------------------------------------------
void IODevice::clearFlags(unsigned int f)
{
flags &= ~f;
}
//------------------------------------------------------------------------
void IODevice::setMaxInputBufferSize(unsigned int max)
{
maxInputBufferSize = max;
}
//------------------------------------------------------------------------
void IODevice::setMaxOutputBufferSize(unsigned int max)
{
maxOutputBufferSize = max;
}
//------------------------------------------------------------------------
void IODevice::setTimeout(unsigned int t)
{
timeout = t;
if (t)
flags |= HasTimeout;
else
flags &= ~HasTimeout;
}
//------------------------------------------------------------------------
unsigned int IODevice::getTimeout(void) const
{
return timeout;
}
//------------------------------------------------------------------------
void IODevice::setOutputLevel(unsigned int level)
{
outputLevel = level;
}
//------------------------------------------------------------------------
unsigned int IODevice::getOutputLevel(void) const
{
return outputLevel;
}
//------------------------------------------------------------------------
void IODevice::setOutputLevelLimit(unsigned int level)
{
outputLevelLimit = level;
}
//------------------------------------------------------------------------
unsigned int IODevice::getOutputLevelLimit(void) const
{
return outputLevelLimit;
}
//------------------------------------------------------------------------
bool IODevice::readStr(string *dest, unsigned int max)
{
// If max is 0, fill the input buffer once only if it's empty.
if (!max && inputBuffer.getSize() == 0 && !fillInputBuffer())
return false;
// If max is != 0, wait until we have max.
while (max && inputBuffer.getSize() < max) {
if (!fillInputBuffer())
return false;
}
unsigned int bytesToRead = max ? max : inputBuffer.getSize();
*dest += inputBuffer.str().substr(0, bytesToRead);
if (dumpfd) {
::write(dumpfd, inputBuffer.str().substr(0, bytesToRead).c_str(),
bytesToRead);
}
inputBuffer.popString(bytesToRead);
readCount += bytesToRead;
return true;
}
//------------------------------------------------------------------------
bool IODevice::readChar(char *dest)
{
if (inputBuffer.getSize() == 0 && !fillInputBuffer())
return false;
char c = inputBuffer.popChar();
if (dest)
*dest = c;
if (dumpfd)
::write(dumpfd, &c, 1);
++readCount;
return true;
}
//------------------------------------------------------------------------
void IODevice::unreadChar(char c)
{
inputBuffer.unpopChar(c);
}
//------------------------------------------------------------------------
void IODevice::unreadStr(const string &s)
{
inputBuffer.unpopStr(s);
}
//------------------------------------------------------------------------
bool IODevice::skipTo(char c)
{
char dest = '\0';
do {
if (!readChar(&dest))
return false;
if (dumpfd)
::write(dumpfd, &dest, 1);
} while (c != dest);
return true;
}
//------------------------------------------------------------------------
string IODevice::service(void) const
{
return "nul";
}
//------------------------------------------------------------------------
bool IODevice::waitForWrite(void) const
{
return false;
}
//------------------------------------------------------------------------
bool IODevice::waitForRead(void) const
{
return false;
}
//------------------------------------------------------------------------
IODevice::WriteResult IODevice::write(void)
{
return WriteError;
}
//------------------------------------------------------------------------
bool IODevice::fillInputBuffer(void)
{
return false;
}
//------------------------------------------------------------------------
IODevice::Error IODevice::getLastError(void) const
{
return error;
}
//------------------------------------------------------------------------
string IODevice::getLastErrorString(void) const
{
return errorString;
}
//------------------------------------------------------------------------
unsigned int IODevice::getReadCount(void) const
{
return readCount;
}
//------------------------------------------------------------------------
unsigned int IODevice::getWriteCount(void) const
{
return writeCount;
}
//------------------------------------------------------------------------
void IODevice::enableProtocolDumping(void)
{
#if 0
BincStream ss;
ss << "/tmp/bincimap-dump-" << (int) time(0) << "-"
<< Session::getInstance().getIP() << "-XXXXXX";
char *safename = strdup(ss.str().c_str());
dumpfd = mkstemp(safename);
if (dumpfd == -1)
dumpfd = 0;
delete safename;
#endif
}