/**
* ======================== legal notice ======================
*
* File: StringBuilder.cc
* Created: 6. Juli 2012, 10
* Author: Geronimo
* Project: libutil - base classes used by other libraries
*
* CMP - compound media player
*
* is a client/server mediaplayer intended to play any media from any workstation
* without the need to export or mount shares. cmps is an easy to use backend
* with a (ready to use) HTML-interface. Additionally the backend supports
* authentication via HTTP-digest authorization.
* cmpc is a client with vdr-like osd-menues.
*
* Copyright (c) 2012 Reinhard Mantey, some rights reserved!
* published under Creative Commons by-sa
* For details see http://creativecommons.org/licenses/by-sa/3.0/
*
* The cmp project's homepage is at http://projects.vdr-developer.org/projects/cmp
*
* --------------------------------------------------------------
*/
#include
#include
#include
#include
#include
static void freeStringCallback(void *elem)
{
free(elem);
}
cStringBuilder::cStringBuilder(const char *First)
: chunkSize(127)
, readOffset(0)
, writeOffset(0)
, firstChunk(NULL)
, pool(freeStringCallback)
{
init();
if (First) Append(First);
}
cStringBuilder::cStringBuilder(int ChunkSize)
: chunkSize(ChunkSize)
, readOffset(0)
, writeOffset(0)
, firstChunk(NULL)
, pool(freeStringCallback)
{
init();
}
cStringBuilder::~cStringBuilder()
{
}
void cStringBuilder::init(void)
{
char *first = (char *) malloc(chunkSize);
pool.push_back(first);
firstChunk = first;
}
void cStringBuilder::Write(const char *Text)
{
if (!Text) {
esyslog("ERROR: text to add is a NULL-pointer!");
return;
}
uint chunkFree = chunkSize - writeOffset;
char *curChunk = (char *) pool[pool.size() - 1];
const char *p = Text;
while (strlen(p) >= chunkFree) {
strncpy(curChunk + writeOffset, p, chunkFree);
p += chunkFree;
curChunk = (char *) malloc(chunkSize);
pool.push_back(curChunk);
writeOffset = 0;
chunkFree = chunkSize;
}
if (strlen(p)) {
strcpy(curChunk + writeOffset, p);
writeOffset += strlen(p);
}
}
size_t cStringBuilder::Size()
{
return (pool.size() - 1) * chunkSize + writeOffset;
}
size_t cStringBuilder::Size() const
{
return (pool.size() - 1) * chunkSize + writeOffset;
}
size_t cStringBuilder::Copy(char* Buf, size_t BufSize)
{
uint chunkNo = readOffset / chunkSize;
uint chunkOff = readOffset % chunkSize;
uint bytes2Write = chunkSize;
char *curChunk = (char *) pool[chunkNo];
size_t bytesWritten = 0;
if (chunkNo == (pool.size() - 1)) bytes2Write = writeOffset;
while ((BufSize - bytesWritten) > (bytes2Write - chunkOff)) {
strncpy(Buf + bytesWritten, curChunk + chunkOff, bytes2Write - chunkOff);
bytesWritten += bytes2Write - chunkOff;
chunkOff = 0;
if (++chunkNo < (pool.size() - 1)) bytes2Write = chunkSize;
else bytes2Write = writeOffset;
if (chunkNo == pool.size()) break;
curChunk = (char *) pool[chunkNo];
}
readOffset += bytesWritten;
return bytesWritten;
}
cStringBuilder &cStringBuilder::Append(const char* Text)
{
if (!Text) Write("(null)");
Write(Text);
return *this;
}
cStringBuilder &cStringBuilder::Append(char c)
{
char buf[2];
*buf = c;
buf[1] = 0;
Write(buf);
return *this;
}
cStringBuilder &cStringBuilder::Append(bool v, const char *TrueValue, const char *FalseValue)
{
if (v) Write(TrueValue);
else Write(FalseValue);
return *this;
}
cStringBuilder &cStringBuilder::Append(double v)
{
char *elem = NULL;
asprintf(&elem, "%lg", v);
if (elem) {
Write(elem);
free(elem);
}
return *this;
}
cStringBuilder &cStringBuilder::Append(int v)
{
char buf[12];
if (snprintf(buf, sizeof(buf), "%d", v)) Write(buf);
return *this;
}
cStringBuilder &cStringBuilder::Append(long v)
{
char buf[24];
if (snprintf(buf, sizeof(buf), "%ld", v)) Write(buf);
return *this;
}
cStringBuilder &cStringBuilder::Append(size_t v)
{
char buf[24];
if (snprintf(buf, sizeof(buf), "%lu", v)) Write(buf);
return *this;
}
char *cStringBuilder::toString(void)
{
char *rv = (char *) malloc(Size() + 1);
if (rv) {
readOffset = 0;
Copy(rv, Size() + 1);
*(rv + Size()) = 0;
}
return rv;
}