123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884 |
- #include <bfc/wasabi_std.h>
- #include "string.h"
- #include <bfc/nsguid.h>
- String::String(const char *initial_val)
- : val(NULL)
- {
- setValue(initial_val);
- }
- String::String(const String &s)
- : val(NULL)
- {
- if (s == NULL) setValue(NULL);
- else setValue(s.getValue());
- }
- String::String(const String *s)
- : val(NULL)
- {
- if (s == NULL) setValue(NULL);
- else setValue(s->getValue());
- }
- String::~String()
- {
- FREE(val);
- }
- const char *String::getValueSafe(const char *def_val) const
- {
- if (val == NULL)
- return def_val;
- else
- return val;
- }
- int String::getChar(int pos, int bounds_check)
- {
- if (pos < 0 || val == NULL) return -1;
- if (bounds_check && pos >= len()) return -1;
- return val[pos];
- }
- int String::setChar(int pos, int value)
- {
- if (pos < 0 || val == NULL) return -1;
- return val[pos] = value;
- }
- const char *String::setValue(const char *newval)
- {
- if (newval != val)
- {
- if (newval == NULL)
- {
- FREE(val);
- val = NULL;
- }
- else
- {
- int len = STRLEN(newval);
- if (val != NULL)
- #ifdef STRING_REALLOC_OPTIMS
- {
- int oldlen = STRLEN(val);
- // if smaller but greater than half previous size, don't realloc
- if (len > oldlen || len < oldlen / 2)
- val = (char *)REALLOC(val, len + 1);
- }
- #else
- val = (char *)REALLOC(val, len + 1);
- #endif
- else
- val = (char *)MALLOC(len + 1);
- ASSERT(newval != NULL);
- MEMCPY_(val, newval, len + 1);
- }
- }
- return getValue();
- }
- int String::len() const
- {
- return (val == NULL) ? 0 : STRLEN(val);
- }
- int String::isempty() const
- {
- return (!val || !*val);
- }
- void String::toupper()
- {
- if (!isempty())
- STRTOUPPER(val);
- }
- void String::tolower()
- {
- if (!isempty())
- STRTOLOWER(val);
- }
- int String::isequal(const char *otherval) const
- {
- return !STRCMPSAFE(getValue(), otherval);
- }
- int String::iscaseequal(const char *otherval) const
- {
- return !STRICMPSAFE(getValue(), otherval);
- }
- int String::islessthan(const char *otherval) const
- {
- return STRCMPSAFE(getValue(), otherval) < 0;
- }
- void String::changeChar(int from, int to)
- {
- if (val == NULL) return ;
- int length = len();
- for (int i = 0; i < length; i++)
- if (val[i] == from) val[i] = to;
- }
- void String::truncateOnChar(int which, int fromright)
- {
- if (fromright)
- {
- if (val == NULL) return ;
- int length = len();
- for (int i = length - 1; i >= 0; i--)
- {
- if (val[i] == which)
- {
- val[i] = '\0';
- return ;
- }
- }
- }
- else
- {
- changeChar(which, '\0');
- }
- }
- int String::lastChar()
- {
- if (isempty()) return -1;
- return val[len() - 1];
- }
- const char *String::printf(const char *format, ...)
- {
- va_list args;
- va_start (args, format);
- va_sprintf(format, args);
- va_end(args);
- return getValue();
- }
- const char *String::cat(const char *value)
- {
- if (value == NULL || *value == 0) return getValue();
- if (val == NULL) return setValue(value);
- return catn(value, STRLEN(value));
- }
- const char *String::catn(const char *value, int len)
- {
- if (len == 0) return val;
- if (value == NULL || *value == 0) return getValue();
- if (val == NULL) return ncpy(value, len);
- int ol = STRLEN(val);
- val = (char *)REALLOC(val, ol + len + 1);
- val[ol + len] = 0;
- STRNCPY(val + ol, value, len);
- return val;
- }
- const char *String::prepend(const char *value)
- {
- if (value == NULL || *value == 0) return getValue();
- if (val == NULL) return setValue(value);
- StringPrintf temp("%s%s", value, getValue());
- swap(&temp);
- return getValue();
- }
- // replaces string with n chars of val or length of val, whichever is less.
- const char *String::ncpy(const char *newstr, int numchars)
- {
- val = (char *)REALLOC(val, numchars + 1);
- val[numchars] = 0;
- STRNCPY(val, newstr, numchars);
- return getValue();
- }
- void String::strncpyTo(char *dest, int maxlen)
- {
- ASSERT(dest != NULL);
- ASSERT(maxlen >= 0);
- if (maxlen == 0) return ;
- else if (maxlen == 1)
- {
- *dest = '\0';
- return ;
- }
- const char *src = val;
- if (src == NULL) src = "";
- int copylen = MIN(STRLEN(src), maxlen);
- if (maxlen == copylen) copylen--; // make room for 0-termination
- MEMCPY(dest, src, copylen);
- dest[copylen] = 0;
- }
- // -----------------------------------------
- // Character based find-n-splice methods --
- // "l" and "r" prefixes specify to begin at
- // front or back of string:
- #ifdef FAST_METHODS
- #undef FAST_METHODS
- #endif//FAST_METHODS
- #ifdef SAFE_METHODS
- #undef SAFE_METHODS
- #endif//SAFE_METHODS
- #ifdef USE
- #undef USE
- #endif//USE
- #define FAST_METHODS 1
- #define SAFE_METHODS 0
- #define USE FAST_METHODS
- // Returns index of first found, -1 if not found.
- int String::lFindChar(char findval)
- {
- int length = len();
- for (int i = 0; i < length; i++)
- {
- if (val[i] == findval)
- {
- return i;
- }
- }
- return -1;
- }
- // Same as above, save the "findval" is a string where it searches
- // for any of the characters in the string.
- int String::lFindChar(const char *findval)
- {
- int length = len();
- int numchars = STRLEN(findval);
- for (int i = 0; i < length; i++)
- {
- for (int j = 0; j < numchars; j++)
- {
- if (val[i] == findval[j])
- {
- return i;
- }
- }
- }
- return -1;
- }
- int String::rFindChar(char findval)
- {
- int length = len();
- for (int i = length - 1; i > 0; i--)
- {
- if (val[i] == findval)
- {
- return i;
- }
- }
- return -1;
- }
- // Same as above, save the "findval" is a string where it searches
- // for any of the characters in the string.
- int String::rFindChar(const char *findval)
- {
- int length = len();
- int numchars = STRLEN(findval);
- for (int i = length - 1; i > 0; i--)
- {
- for (int j = 0; j < numchars; j++)
- {
- if (val[i] == findval[j])
- {
- return i;
- }
- }
- }
- return -1;
- }
- // Splits string at findval. Characters passed by search, including the
- // found character, are MOVED to the returned string. If there is no char
- // to be found, the entire string is returnef and the called instance is
- // left empty. (Makes looped splits very easy).
- String String::lSplit(int idxval)
- {
- if (val == NULL) return String();
- if (idxval == -1)
- { // Not Found
- // Copy our contents to return on the stack
- String retval(val);
- // And zero the string.
- if (val)
- {
- val[0] = 0;
- }
- return retval;
- }
- else
- {
- String retval;
- // Copy into retval the number of characters to the found char index.
- retval.ncpy(val, idxval + 1);
- {
- String testscope;
- // Copy into retval the number of characters to the found char index.
- testscope.ncpy(val, idxval + 1);
- }
- #if USE == FAST_METHODS
- size_t len = strlen(val + idxval + 1);
- MEMCPY(val, val + idxval + 1, len + 1);
- #elif USE == SAFE_METHODS
- // Copy from the found index downwards to save for this object
- String temp(val + idxval + 1);
- // And then copy into ourselves the tempspace.
- *this = temp;
- #endif
- return retval;
- }
- // this will never be hit. many compilers are too stupid to realize this.
- return String();
- }
- String String::lSplitChar(char findval)
- {
- if (val == NULL) return String();
- // The index of the found character
- int idxval = lFindChar(findval);
- return lSplit(idxval);
- }
- String String::lSplitChar(const char *findval)
- {
- if (val == NULL) return String();
- // The index of the found character
- int idxval = lFindChar(findval);
- return lSplit(idxval);
- }
- String String::rSplit(int idxval)
- {
- if (val == NULL) return String();
- if (idxval == -1)
- { // Not Found
- // Copy our contents to return on the stack
- String retval(val);
- // And zero the string.
- val[0] = 0;
- return retval;
- }
- else
- {
- // Copy from the found index downwards to the retval
- String retval(val + idxval);
- // Terminate the found char index
- val[idxval] = 0;
- // That was easier, wasn't it?
- return retval;
- }
- // this will never be hit. many compilers are too stupid to realize this.
- return String();
- }
- String String::rSplitChar(char findval)
- {
- if (val == NULL) return String();
- // The index of the found character
- int idxval = rFindChar(findval);
- return rSplit(idxval);
- }
- String String::rSplitChar(const char *findval)
- {
- if (val == NULL) return String();
- // The index of the found character
- int idxval = rFindChar(findval);
- return rSplit(idxval);
- }
- // Same as split, except the find char is cut completely.
- String String::lSpliceChar(char findval)
- {
- if (val == NULL) return String();
- //CUT // Auto-scope reference allows us to avoid a copy.
- //CUT String & retval = lSplitChar(findval);
- //BU gcc doesn't agree with you and neither do I :/
- String retval = lSplitChar(findval);
- // We need to strip the findval char, which is the end char.
- int end = retval.len();
- if (end)
- {
- if (retval.val[end - 1] == findval)
- {
- retval.val[end - 1] = 0;
- }
- }
- return retval;
- }
- // Same as split, except the find char is cut completely.
- String String::lSpliceChar(const char *findval)
- {
- if (val == NULL) return String();
- //CUT // Auto-scope reference allows us to avoid a copy.
- //CUT String & retval = lSplitChar(findval);
- //BU gcc doesn't agree with you and neither do I :/
- String retval = lSplitChar(findval);
- // We need to strip the findval char, which is the end char.
- int end = retval.len();
- int num = STRLEN(findval);
- if (end)
- {
- for (int i = 0; i < num; i++)
- {
- if (retval.val[end - 1] == findval[i])
- {
- retval.val[end - 1] = 0;
- }
- }
- }
- return retval;
- }
- String String::rSpliceChar(char findval)
- {
- if (val == NULL) return String();
- //CUT // Auto-scope reference allows us to avoid a copy.
- //CUT String & retval = rSplitChar(findval);
- //BU gcc doesn't agree with you and neither do I :/
- String retval = rSplitChar(findval);
- // We need to strip the findval char, which is the first char.
- // (But we still check for empty string:)
- size_t end = retval.len();
- if (end)
- {
- if (retval.val[0] == findval)
- {
- #if USE == FAST_METHODS
- size_t len = strlen(retval.val + 1);
- MEMCPY(retval.val, retval.val + 1, len + 1);
- #elif USE == SAFE_METHODS
- String temp(retval.val + 1);
- retval = temp;
- #endif
- return retval;
- }
- }
- return retval;
- }
- String String::rSpliceChar(const char *findval)
- {
- if (val == NULL) return String();
- //CUT // Auto-scope reference allows us to avoid a copy.
- //CUT String & retval = rSplitChar(findval);
- //BU gcc doesn't agree with you and neither do I :/
- String retval = rSplitChar(findval);
- // We need to strip the findval char, which is the first char.
- // (But we still check for empty string:)
- size_t end = retval.len();
- size_t num = STRLEN(findval);
- if (end)
- {
- for (size_t i = 0; i < num; i++)
- {
- if (retval.val[0] == findval[i])
- {
- #if USE == FAST_METHODS
- size_t len = strlen(retval.val + 1);
- MEMCPY(retval.val, retval.val + 1, len + 1);
- #elif USE == SAFE_METHODS
- String temp(retval.val + 1);
- retval = temp;
- #endif
- return retval;
- }
- }
- }
- return retval;
- }
- int String::replace(const char *find, const char *replace)
- {
- if (len() == 0 || find == NULL || replace == NULL) return 0;
- int find_count = 0;
- char *p, *p2;
- int rep_len = STRLEN( replace );
- int find_len = STRLEN( find );
- int size_diff = rep_len - find_len;
- if ( size_diff == 0 )
- {
- p = val;
- while ( p = STRSTR( p, find ) )
- {
- STRNCPY( p, replace, rep_len );
- p += find_len;
- find_count++;
- }
- }
- else
- {
- char *new_buf, *in;
- p = val;
- while ( p = STRSTR( p, find ) )
- {
- find_count++;
- p += find_len;
- }
- new_buf = (char *)MALLOC( len() + find_count * size_diff + 1 );
- p = val;
- in = new_buf;
- while ( p2 = STRSTR( p, find ) )
- {
- STRNCPY( in, p, (int)(p2 - p) );
- in += p2 - p;
- STRNCPY( in, replace, rep_len );
- in += rep_len;
- p = p2 + find_len;
- }
- STRCPY( in, p );
- new_buf[ len() + find_count * size_diff ] = 0;
- // just swap buffers
- FREE(val);
- val = new_buf;
- }
- return find_count;
- }
- int String::replaceNumericField(int value, int fieldchar)
- {
- if (val == NULL || *val == '\0') return 0;
- int nrep = 0;
- for (const char *p = val; *p; p++)
- {
- if (*p == fieldchar) nrep++;
- else if (nrep) break;
- }
- if (nrep == 0) return 0; // no field found
- String rc;
- char fc[2] = { 0, 0 };
- fc[0] = fieldchar;
- for (int i = 0; i < nrep; i++) rc.cat(fc);
- StringPrintf fmt("%%0%0dd", nrep);
- StringPrintf replacement(fmt.getValue(), value);
- return replace(rc, replacement);
- }
- #undef USE
- #undef SAFE_METHODS
- #undef FAST_METHODS
- int String::numCharacters()
- {
- // count newsize characters over how many bytes?
- int count, bytes;
- for (bytes = 0, count = 0; val[bytes]; count++, bytes++)
- {
- // If we encounter a lead byte, skip over the trail bytes.
- switch (val[bytes] & 0xC0)
- {
- case 0x80: // trail bytes
- // THIS SHOULD NEVER EVER EVER EVER HAPPEN!
- // but we'll fall through anyhow, just in case someone
- // sends us non-UTF8.
- case 0xC0: // lead bytes
- do
- {
- bytes++;
- if (val[bytes] == 0)
- {
- // if people are giving us lame encodings, break here.
- break;
- }
- }
- while ((val[bytes + 1] & 0xC0) == 0x80);
- break;
- }
- }
- return count;
- }
- void String::trunc(int newlen)
- {
- if (val == NULL) return ;
- int oldlen = numCharacters();
- if (newlen < 0) newlen = MAX(oldlen + newlen, 0);
- if (newlen >= oldlen) return ;
- // count newsize characters over how many bytes?
- int count, bytes;
- for (bytes = 0, count = 0; count < newlen; count++, bytes++)
- {
- // If we encounter a lead byte, skip over the trail bytes.
- switch (val[bytes] & 0xC0)
- {
- case 0x80: // trail bytes
- // THIS SHOULD NEVER EVER EVER EVER HAPPEN!
- // but we'll fall through anyhow, just in case someone
- // sends us non-UTF8.
- case 0xC0: // lead bytes
- do
- {
- bytes++;
- }
- while ((val[bytes + 1] & 0xC0) == 0x80);
- break;
- }
- }
- val[bytes] = 0;
- }
- void String::trim(const char *whitespace, int left, int right)
- {
- if (val == NULL) return ;
- if (left)
- { // trim left
- for (;;)
- {
- int restart = 0;
- const char *p;
- for (p = whitespace; *p; p++)
- {
- if (*p == val[0])
- {
- STRCPY(val, val + 1);
- restart = 1;
- break;
- }
- }
- if (!restart) break;
- }
- } //left
- if (right)
- {
- char *ptr = val;
- while (ptr && *ptr) ptr++;
- ptr--;
- if (ptr <= val) return ;
- for (; ptr > val; ptr--)
- {
- const char *p;
- for (p = whitespace; *p; p++)
- {
- if (*p == *ptr)
- {
- *ptr = '\0';
- break;
- }
- }
- if (!*p) break;
- }
- } //right
- }
- int String::va_sprintf(const char *format, va_list args)
- {
- if (!format) return 0;
- va_list saveargs = args;
- // roughly evaluate size of dest string
- const char *p = format;
- int length = 0;
- while (p && *p)
- {
- if (*(p++) != '%') length++;
- else
- {
- void *arg = va_arg(args, void *);
- for (;;)
- {
- const char f = *p++;
- if (f == 'c') length++;
- else if (f == 'i') length += 16;
- else if (f == 'u') length += 16;
- else if (f == 'f') length += 64;
- else if (f == 'd' || f == 'f') length += 64;
- else if (f == 'x') length += 32; // Hex with LC Alphas: 0x0009a64c
- else if (f == 'X') length += 32; // Hex with UC Alphas: 0x0009A64C
- else if (f == 's')
- { // ::vsrintf can properly handle null.
- if (arg == NULL)
- {
- length += STRLEN("(null)"); // Just to be explicit.
- }
- else
- {
- length += STRLEN((const char *)arg);
- }
- }
- else if (f == 'S')
- { // ::vsrintf can properly handle null.
- if (arg == NULL)
- {
- length += (int)wcslen(L"(null)"); // Just to be explicit.
- }
- else
- {
- length += (int)wcslen((const wchar_t *)arg);
- }
- }
- else if (ISDIGIT(f)) continue;
- else if (f == '.') continue;
- else if (f == '%') length++;
- else ASSERTPR(0, "undefined format passed to stringprintf!");
- break;
- }
- }
- }
- if (val)
- {
- if (len() < length)
- val = (char *)REALLOC(val, length + 1);
- }
- else val = (char *)MALLOC(length + 1);
- // now write the string in val
- int real_len = ::vsprintf_s(val, length + 1, format, saveargs);
- ASSERTPR(real_len <= length, "String.printf overflow");
- return real_len;
- }
- void String::purge()
- {
- FREE(val);
- val = NULL;
- }
- // swaps buffers with another string
- void String::swap(String *swapper)
- {
- char *tempChar = swapper->val;
- swapper->val = val;
- val = tempChar;
- }
- void String::swap(String &swapper) // swaps buffers with another string
- {
- char *tempChar = swapper.val;
- swapper.val = val;
- val = tempChar;
- }
- // take ownership of a buffer
- void String::own(char *swapper)
- {
- if (val)
- FREE(val);
- val = swapper;
- }
- const char *String::catPostSeparator(const char *value, const char separator)
- {
- if (value == NULL || *value == 0 || separator == 0) return getValue();
- int oldLen = val ? STRLEN(val) : 0;
- int newLen = STRLEN(value);
- val = (char *)REALLOC(val, oldLen + newLen + 1 + 1); // +1 for separator, +1 for null character
- STRCPY(val + oldLen, value);
- val[oldLen + newLen] = separator; // add the separator
- val[oldLen + newLen + 1] = 0; // null terminate
- return val;
- }
- const char *String::catPreSeparator(const char separator, const char *value)
- {
- if (value == NULL || *value == 0 || separator == 0) return getValue();
- int oldLen = val ? STRLEN(val) : 0;
- int newLen = STRLEN(value);
- val = (char *)REALLOC(val, oldLen + newLen + 1 + 1); // +1 for separator, +1 for null character
- val[oldLen] = separator; // add the separator
- STRCPY(val + oldLen + 1, value); // +1 for separator (goes first)
- val[oldLen + newLen + 1] = 0; // null terminate
- return val;
- }
- void String::AppendPath(const char *path)
- {
- catPreSeparator('/', path);
- }
- StringPrintf::StringPrintf(const char *format, ...)
- {
- va_list args;
- va_start (args, format);
- va_sprintf(format, args);
- va_end(args);
- }
- StringPrintf::StringPrintf(int value)
- {
- *this += value;
- }
- StringPrintf::StringPrintf(double value)
- {
- // TODO: review to use locale variant...
- char* locale = _strdup(setlocale(LC_NUMERIC, NULL));
- setlocale(LC_NUMERIC, "C");
- *this += StringPrintf("%f", value);
- if (locale)
- {
- setlocale(LC_NUMERIC, locale);
- free(locale);
- }
- }
- StringPrintf::StringPrintf(GUID g)
- {
- char splab[nsGUID::GUID_STRLEN + 1] = {0};
- nsGUID::toChar(g, splab);
- cat(splab);
- }
- _DebugString::_DebugString(const char *format, ...)
- {
- va_list args;
- va_start (args, format);
- va_sprintf(format, args);
- va_end(args);
- debugPrint();
- }
- _DebugString::_DebugString(const String &s) : String(s)
- {
- debugPrint();
- }
- _DebugString::_DebugString(const String *s) : String(s)
- {
- debugPrint();
- }
- void _DebugString::debugPrint()
- {
- #ifdef _WIN32
- OutputDebugStringA(getValue());
- if (lastChar() != '\n') OutputDebugStringA("\n");
- #else
- #warning port me
- #endif
- }
- int StringComparator::compareItem(String *p1, String* p2)
- {
- return STRCMP(p1->getValue(), p2->getValue());
- }
- int StringComparator::compareAttrib(const wchar_t *attrib, String *item)
- {
- return STRCMP((const char *)attrib, item->getValue());
- }
|