// SciTE - Scintilla based Text Editor /** @file SString.h ** A simple string class. **/ // Copyright 1998-2001 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef SSTRING_H #define SSTRING_H // These functions are implemented because each platform calls them something different int CompareCaseInsensitive(const char *a, const char *b); int CompareNCaseInsensitive(const char *a, const char *b, int len); bool EqualCaseInsensitive(const char *a, const char *b); // Define another string class. // While it would be 'better' to use std::string, that doubles the executable size. // An SString may contain embedded nul characters. /** * Duplicate a C string. * Allocate memory of the given size, or big enough to fit the string if length isn't given; * then copy the given string in the allocated memory. * @return the pointer to the new string */ inline char *StringDup( const char *s, ///< The string to duplicate int len=-1) ///< The length of memory to allocate. Optional. { if (!s) return 0; if (len == -1) len = strlen(s); char *sNew = new char[len + 1]; if (sNew) { strncpy(sNew, s, len); sNew[len] = '\0'; } return sNew; } /** * @brief A simple string class. * Hold the length of the string for quick operations, * can have a buffer bigger than the string to avoid too many memory allocations and copies. * May have embedded zeroes as a result of @a substitute, but rely too heavily on C string * functions to allow reliable manipulations of these strings. **/ class SString { char *s; ///< The C string int sSize; ///< The size of the buffer, less 1: ie. the maximum size of the string int sLen; ///< The size of the string in s int sizeGrowth; ///< Minimum growth size when appending strings enum { sizeGrowthDefault = 64 }; public: typedef int size_type; SString() : s(0), sSize(0), sLen(0), sizeGrowth(sizeGrowthDefault) { } SString(const SString &source) : sizeGrowth(sizeGrowthDefault) { s = StringDup(source.s); sSize = sLen = (s) ? strlen(s) : 0; } SString(const char *s_) : sizeGrowth(sizeGrowthDefault) { s = StringDup(s_); sSize = sLen = (s) ? strlen(s) : 0; } SString(const char *s_, int first, int last) : sizeGrowth(sizeGrowthDefault) { s = StringDup(s_ + first, last - first); sSize = sLen = (s) ? strlen(s) : 0; } SString(int i) : sizeGrowth(sizeGrowthDefault) { char number[32]; sprintf(number, "%0d", i); s = StringDup(number); sSize = sLen = (s) ? strlen(s) : 0; } ~SString() { delete []s; s = 0; sSize = 0; sLen = 0; } void clear(void) { if (s) { *s = '\0'; } sLen = 0; } /** Size of buffer. */ size_type size(void) const { ///< if (s) return sSize; else return 0; } /** Size of string in buffer. */ int length() const { return sLen; } SString &assign(const char* sOther, int sSize_ = -1) { if (!sOther) { sSize_ = 0; } if (sSize_ < 0) { sSize_ = strlen(sOther); } if (sSize > 0 && sSize_ <= sSize) { // Does not allocate new buffer if the current is big enough if (s && sSize_) { strncpy(s, sOther, sSize_); } s[sSize_] = '\0'; sLen = sSize_; } else { delete []s; s = StringDup(sOther, sSize_); if (s) { sSize = sSize_; // Allow buffer bigger than real string, thus providing space to grow sLen = strlen(s); } else { sSize = sLen = 0; } } return *this; } SString &assign(const SString& sOther, int sSize_ = -1) { return assign(sOther.s, sSize_); } SString &operator=(const char *source) { return assign(source); } SString &operator=(const SString &source) { if (this != &source) { assign(source.c_str()); } return *this; } bool operator==(const SString &sOther) const { if ((s == 0) && (sOther.s == 0)) return true; if ((s == 0) || (sOther.s == 0)) return false; return strcmp(s, sOther.s) == 0; } bool operator!=(const SString &sOther) const { return !operator==(sOther); } bool operator==(const char *sOther) const { if ((s == 0) && (sOther == 0)) return true; if ((s == 0) || (sOther == 0)) return false; return strcmp(s, sOther) == 0; } bool operator!=(const char *sOther) const { return !operator==(sOther); } bool contains(char ch) { if (s && *s) return strchr(s, ch) != 0; else return false; } void setsizegrowth(int sizeGrowth_) { sizeGrowth = sizeGrowth_; } const char *c_str() const { if (s) return s; else return ""; } /** Give ownership of buffer to caller which must use delete[] to free buffer. */ char *detach() { char *sRet = s; s = 0; sSize = 0; sLen = 0; return sRet; } char operator[](int i) const { if (s && i < sSize) // Or < sLen? Depends on the use, both are OK return s[i]; else return '\0'; } SString &append(const char* sOther, int sLenOther=-1, char sep=0) { if (sLenOther < 0) sLenOther = strlen(sOther); int lenSep = 0; if (sLen && sep) // Only add a separator if not empty lenSep = 1; int lenNew = sLen + sLenOther + lenSep; if (lenNew + 1 < sSize) { // Conservative about growing the buffer: don't do it, unless really needed if (lenSep) { s[sLen] = sep; sLen++; } strncpy(&s[sLen], sOther, sLenOther); s[sLen + sLenOther] = '\0'; sLen += sLenOther; } else { // Grow the buffer bigger than really needed, to have room for other appends char *sNew = new char[lenNew + sizeGrowth + 1]; if (sNew) { if (s) { memcpy(sNew, s, sLen); delete []s; } s = sNew; sSize = lenNew + sizeGrowth; if (lenSep) { s[sLen] = sep; sLen++; } strncpy(&s[sLen], sOther, sLenOther); sNew[sLen + sLenOther] = '\0'; sLen += sLenOther; } } return *this; } SString &operator +=(const char *sOther) { return append(sOther, -1); } SString &operator +=(const SString &sOther) { return append(sOther.s, sOther.sSize); } SString &operator +=(char ch) { return append(&ch, 1); } SString &appendwithseparator(const char* sOther, char sep) { return append(sOther, strlen(sOther), sep); } int value() const { if (s) return atoi(s); else return 0; } void substitute(char find, char replace) { char *t = s; while (t) { t = strchr(t, find); if (t) { *t = replace; t++; } } } }; #endif