summaryrefslogtreecommitdiff
path: root/include/swbuf.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/swbuf.h')
-rw-r--r--include/swbuf.h430
1 files changed, 430 insertions, 0 deletions
diff --git a/include/swbuf.h b/include/swbuf.h
new file mode 100644
index 0000000..6ae6958
--- /dev/null
+++ b/include/swbuf.h
@@ -0,0 +1,430 @@
+/******************************************************************************
+* swbuf.h - code for SWBuf used as a transport and utility for data buffers
+*
+* $Id: swbuf.h 2116 2007-10-17 00:12:27Z scribe $
+*
+* Copyright 2003 CrossWire Bible Society (http://www.crosswire.org)
+* CrossWire Bible Society
+* P. O. Box 2528
+* Tempe, AZ 85280-2528
+*
+* 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 version 2.
+*
+* 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.
+*
+*/
+
+#ifndef SWBUF_H
+#define SWBUF_H
+
+#include <defs.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef __BORLANDC__
+#include <mem.h>
+#endif
+
+SWORD_NAMESPACE_START
+
+
+#define JUNKBUFSIZE 65534
+
+/**
+* This class is used as a transport and utility for data buffers.
+*
+* @warning This class does not perform pointer validity checks (for speed reasons).
+* Therefore, never try to pass an invalid string (const char* 0) as an argument-
+* it will crash your program. You need to perform the checks yourself!
+*/
+class SWDLLEXPORT SWBuf {
+ char *buf;
+ char *end;
+ char *endAlloc;
+ char fillByte;
+ unsigned long allocSize;
+ static char *nullStr;
+ static char junkBuf[JUNKBUFSIZE];
+
+ inline void assureMore(size_t pastEnd) {
+ if (size_t(endAlloc-end) < pastEnd) {
+ assureSize(allocSize + pastEnd);
+ }
+ }
+
+ inline void assureSize(size_t checkSize) {
+ if (checkSize > allocSize) {
+ long size = (end - buf);
+ checkSize += 128;
+ buf = (char *)((allocSize) ? realloc(buf, checkSize) : malloc(checkSize));
+ allocSize = checkSize;
+ end = (buf + size);
+ *end = 0;
+ endAlloc = buf + allocSize - 1;
+ }
+ }
+
+ inline void init(size_t initSize) {
+ fillByte = ' ';
+ allocSize = 0;
+ buf = nullStr;
+ end = buf;
+ endAlloc = buf;
+ if (initSize)
+ assureSize(initSize);
+ }
+
+
+public:
+
+ /******************************************************************************
+ * SWBuf Constructor - Creates an empty SWBuf object
+ *
+ */
+ inline SWBuf() {
+ init(0);
+ }
+
+ /**
+ * SWBuf Constructor - Creates an SWBuf initialized
+ * to a value from a const char *
+ *
+ */
+ SWBuf(const char *initVal, unsigned long initSize = 0);
+// SWBuf(unsigned long initSize);
+
+ /**
+ * SWBuf Constructor - Creates an SWBuf initialized
+ * to a value from a char
+ *
+ */
+ SWBuf(char initVal, unsigned long initSize = 0);
+
+ /**
+ * SWBuf Constructor - Creates an SWBuf initialized
+ * to a value from another SWBuf
+ *
+ */
+ SWBuf(const SWBuf &other, unsigned long initSize = 0);
+
+ /******************************************************************************
+ * SWBuf Destructor - Cleans up instance of SWBuf
+ */
+ inline ~SWBuf() {
+ if ((buf) && (buf != nullStr))
+ free(buf);
+ }
+
+ /**
+ * SWBuf::setFillByte - Set the fillByte character
+ *
+ * @param ch This character is used when the SWBuf is (re)sized.
+ * The memory will be filled with this character. \see setSize() \see resize()
+ */
+ inline void setFillByte(char ch) { fillByte = ch; }
+
+ /**
+ * SWBuf::getFillByte - Get the fillByte character
+ *
+ * @return The character used for filling memory. \see setFillByte.
+ */
+ inline char getFillByte() { return fillByte; }
+
+ /**
+ * @return a pointer to the buffer content (null-terminated string)
+ */
+ inline const char *c_str() const{ return buf; }
+
+ /**
+ * @param pos The position of the requested character.
+ * @return The character at the specified position
+ */
+ inline char &charAt(unsigned long pos) { return ((pos <= (unsigned long)(end - buf)) ? buf[pos] : ((*junkBuf=0),*junkBuf)); }
+
+ /**
+ * @return size() and length() return only the number of characters of the string.
+ * Add one for the following null and one for each char to be appended!
+ */
+ inline unsigned long size() const { return length(); }
+
+ /**
+ * set's the size of the buffer. This is a quick inline method which checks
+ * for changes before actually calling setSize().
+ * @param newSize new size of the buffer
+ */
+ inline void size(unsigned long newSize) { if (end - buf - newSize) setSize(newSize); }
+
+ /**
+ * @return size() and length() return only the number of characters of the string.
+ */
+ inline unsigned long length() const { return end - buf; }
+
+ /**
+ * SWBuf::set - sets this buf to a new value
+ * If the allocated memory is bigger than the new string, it will NOT be resized.
+ * @param newVal the value to set this buffer to.
+ */
+ inline void set(const SWBuf &newVal) {
+ unsigned long len = newVal.length() + 1;
+ assureSize(len);
+// const char *n = newVal.c_str();
+// for (end = buf;len;len--) *end++ = *n++;
+ memcpy(buf, newVal.c_str(), len);
+ end = buf + (len - 1);
+ }
+
+ /**
+ * SWBuf::set - sets this buf to a new value.
+ * If the allocated memory is bigger than the new string, it will NOT be resized.
+ * @param newVal the value to set this buffer to.
+ */
+ inline void set(const char *newVal) {
+ if (newVal) {
+ unsigned long len = strlen(newVal) + 1;
+ assureSize(len);
+ memcpy(buf, newVal, len);
+ end = buf + (len - 1);
+ }
+ else {
+ assureSize(1);
+ end = buf;
+ *end = 0;
+ }
+ }
+
+ /**
+ * SWBuf::setFormatted - sets this buf to a formatted string.
+ * If the allocated memory is bigger than the new string, it will NOT be resized.
+ *
+ * @warning This function can only write at most JUNKBUFSIZE to the string per call.
+ *
+ * @warning This function is not very fast. For loops with many iterations you might
+ * consider replacing it by other calls.
+ * Example:
+ * \code SWBuf buf.setFormatted("<%s>", stringVal); \endcode
+ * should be replaced by:
+ * \code buf.set("<"); buf.append(stringVal); buf.append(">"); \endcode
+ * This will produce much faster results.
+ *
+ * @param format The format string. Same syntax as printf, for example.
+ * @param ... Add all arguments here.
+ */
+ void setFormatted(const char *format, ...);
+
+ /**
+ * SWBuf::setSize - Size this buffer to a specific length.
+ * @param len The new size of the buffer. One byte for the null will be added.
+ */
+ void setSize(unsigned long len);
+ /**
+ * SWBuf::resize - Resize this buffer to a specific length.
+ * @param len The new size of the buffer. One byte for the null will be added.
+ */
+ inline void resize(unsigned long len) { setSize(len); }
+
+ /**
+ * SWBuf::append - appends a value to the current value of this SWBuf.
+ * If the allocated memory is not enough, it will be resized accordingly.
+ * @param str Append this.
+ * @param max Append only max chars.
+ */
+ void append(const char *str, long max = -1);
+
+ /**
+ * SWBuf::append - appends a value to the current value of this SWBuf
+ * If the allocated memory is not enough, it will be resized accordingly.
+ * @param str Append this.
+ * @param max Append only max chars.
+ */
+ inline void append(const SWBuf &str, long max = -1) { append(str.c_str(), max); }
+
+ /**
+ * SWBuf::append - appends a value to the current value of this SWBuf
+ * If the allocated memory is not enough, it will be resized accordingly.
+ * @param ch Append this.
+ */
+ inline void append(char ch) {
+ assureMore(1);
+ *end++ = ch;
+ *end = 0;
+ }
+
+ /**
+ * SWBuf::appendFormatted - appends formatted strings to the current value of this SWBuf.
+ *
+ * @warning This function can only write at most JUNKBUFSIZE to the string per call.
+ *
+ * @warning This function is not very fast. For loops with many iterations you might
+ * consider replacing it by other calls.
+ * Example:
+ * \code SWBuf buf.appendFormatted("<%s>", stringVal); \endcode
+ * should be replaced by:
+ * \code buf.append("<"); buf.append(stringVal); buf.append(">"); \endcode
+ * This will produce much faster results.
+ *
+ * @param format The format string. Same syntax as printf, for example.
+ * @param ... Add all arguments here.
+ */
+ void appendFormatted(const char *format, ...);
+
+ /**
+ * SWBuf::insert - inserts the given string at position into this string
+ * @param pos The position where to insert. pos=0 inserts at the beginning, pos=1 after the first char, etc. Using pos=length() is the same as calling append(s)
+ * @param str string to be inserted
+ * @param start start from this position in the string to be inserted
+ * @param max Insert only max chars.
+ */
+ void insert(unsigned long pos, const char* str, unsigned long start = 0, signed long max = -1);
+
+ /**
+ * SWBuf::insert - inserts the given string at position into this string
+ * @param pos The position where to insert. pos=0 inserts at the beginning, pos=1 after the first char, etc. Using pos=length() is the same as calling append(s)
+ * @param str string to be inserted
+ * @param start start from this position in the string to be inserted
+ * @param max Insert only max chars.
+ */
+ inline void insert(unsigned long pos, const SWBuf &str, unsigned long start = 0, signed long max = -1) {
+ insert(pos, str.c_str(), start, max);
+ };
+
+ /**
+ * SWBuf::insert - inserts the given character at position into this string
+ * @param pos The position where to insert. pos=0 inserts at the beginning, pos=1 after the first char, etc. Using pos=length() is the same as calling append(s)
+ * @param c Insert this.
+ */
+ inline void insert(unsigned long pos, char c) {
+ insert(pos, SWBuf(c));
+ }
+
+ /** SWBuf::getRawData
+ *
+ * @warning be careful! Probably setSize needs to be called in conjunction before and maybe after
+ *
+ * @return Pointer to the allocated memory of the SWBuf.
+ */
+ inline char *getRawData() { return buf; }
+
+ inline operator const char *() const { return c_str(); }
+ inline char &operator[](unsigned long pos) { return charAt(pos); }
+ inline char &operator[](long pos) { return charAt((unsigned long)pos); }
+ inline char &operator[](unsigned int pos) { return charAt((unsigned long)pos); }
+ inline char &operator[](int pos) { return charAt((unsigned long)pos); }
+ inline SWBuf &operator =(const char *newVal) { set(newVal); return *this; }
+ inline SWBuf &operator =(const SWBuf &other) { set(other); return *this; }
+ inline SWBuf &operator +=(const char *str) { append(str); return *this; }
+ inline SWBuf &operator +=(char ch) { append(ch); return *this; }
+
+ /**
+ * Decrease the buffer size, discarding the last characters
+ * @param len how many bytes to decrease the buffer size
+ */
+ inline SWBuf &operator -=(unsigned long len) { setSize(length()-len); return *this; }
+
+ /**
+ * Decrease the buffer size, discarding the last character
+ */
+ inline SWBuf &operator --(int) { operator -=(1); return *this; }
+
+ /**
+ * Shift the buffer to the left, discarding the first bytes, decreasing the buffer size
+ */
+ inline SWBuf &operator <<(unsigned long n) { if (n && length()) { n = (n<=length())?n:(length()-1); memmove(buf, buf+n, length()-n); (*this)-=n; } return *this; }
+
+ /**
+ * Shift the buffer to the right, increasing the buffer size
+ */
+ inline SWBuf &operator >>(unsigned long n) { setSize(length()+n); memmove(buf+n, buf, length()-n); return *this; }
+
+ /**
+ * Concatenate another buffer to the end of this buffer
+ */
+ inline SWBuf operator +(const SWBuf &other) const {
+ SWBuf retVal = buf;
+ retVal += other;
+ return retVal;
+ }
+
+ /**
+ * Concatenate a byte to the end of this buffer
+ */
+ inline SWBuf operator +(char ch) const { return (*this) + SWBuf(ch); }
+
+ /**
+ * Trim whitespace from the start of this buffer, shifting the buffer left as necessary
+ */
+ inline SWBuf &trimStart() { while (size() && (strchr("\t\r\n ", *(buf)))) *this << 1; return *this; }
+
+ /**
+ * Trim whitespace from the end of this buffer, decreasing the size as necessary
+ */
+ inline SWBuf &trimEnd() { while (size() && (strchr("\t\r\n ", *(end-1)))) setSize(size()-1); return *this; }
+
+ /**
+ * Trim whitespace from the start and end of this buffer, shifting left and decreasing size as necessary
+ */
+ inline SWBuf &trim() { trimStart(); return trimEnd(); }
+
+
+ /**
+ * Strip a prefix from this buffer up to a separator byte.
+ * Returns the prefix and modifies this buffer, shifting left to remove prefix
+ * @param separator to use (e.g. ':')
+ * @return prefix if separator character found; otherwise, null and leaves buffer unmodified
+ */
+ inline const char *stripPrefix(char separator) { const char *m = strchr(buf, separator); if (m) { int len = m-buf; char *hold = new char[len]; memcpy(hold, buf, len); *this << (len+1); memcpy(end+1, hold, len); delete [] hold; end[len+1] = 0; } return (m) ? end+1 : 0; } // safe. we know we don't actually realloc and shrink buffer when shifting, so we can place our return val at end.
+
+ // this could be nicer, like replacing a contiguous series of target bytes with single replacement; offering replacement const char *
+ /**
+ * Replace with a new byte value all occurances in this buffer of any byte value specified in a set
+ * @param targets a set of bytes, any of which will be replaced
+ * @param newByte value to use as replacement.
+ *
+ * Example: replaceBytes("abc", 'z'); // replaces all occurances of 'a', 'b', and 'c' with 'z'
+ */
+ inline SWBuf &replaceBytes(const char *targets, char newByte) { for (unsigned int i = 0; (i < size()); i++) { if (strchr(targets, buf[i])) buf[i] = newByte; } return *this; }
+
+ /**
+ * @return returns true if this buffer starts with the specified prefix
+ */
+ inline bool startsWith(const SWBuf &prefix) const { return !strncmp(c_str(), prefix.c_str(), prefix.size()); }
+
+ /**
+ * @return returns true if this buffer ends with the specified postfix
+ */
+ inline bool endsWith(const SWBuf &postfix) const { return (size() >= postfix.size())?!strncmp(end-postfix.size(), postfix.c_str(), postfix.size()):false; }
+
+ inline int compare(const SWBuf &other) const { return strcmp(c_str(), other.c_str()); }
+ inline bool operator ==(const SWBuf &other) const { return compare(other) == 0; }
+ inline bool operator !=(const SWBuf &other) const { return compare(other) != 0; }
+ inline bool operator > (const SWBuf &other) const { return compare(other) > 0; }
+ inline bool operator < (const SWBuf &other) const { return compare(other) < 0; }
+ inline bool operator <=(const SWBuf &other) const { return compare(other) <= 0; }
+ inline bool operator >=(const SWBuf &other) const { return compare(other) >= 0; }
+
+ /**
+ * @return returns true if this buffer starts with the specified prefix
+ */
+ inline bool startsWith(const char *prefix) const { return !strncmp(c_str(), prefix, strlen(prefix)); }
+
+ /**
+ * @return returns true if this buffer ends with the specified postfix
+ */
+ inline bool endsWith(const char *postfix) const { unsigned int psize = strlen(postfix); return (size() >= psize)?!strncmp(end-psize, postfix, psize):false; }
+
+ inline int compare(const char *other) const { return strcmp(c_str(), other); }
+ inline bool operator ==(const char *other) const { return compare(other) == 0; }
+ inline bool operator !=(const char *other) const { return compare(other) != 0; }
+ inline bool operator > (const char *other) const { return compare(other) > 0; }
+ inline bool operator < (const char *other) const { return compare(other) < 0; }
+ inline bool operator <=(const char *other) const { return compare(other) <= 0; }
+ inline bool operator >=(const char *other) const { return compare(other) >= 0; }
+};
+
+
+
+SWORD_NAMESPACE_END
+#endif