ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

str.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "common/hash-str.h"
00024 #include "common/list.h"
00025 #include "common/memorypool.h"
00026 #include "common/str.h"
00027 #include "common/util.h"
00028 #include "common/mutex.h"
00029 
00030 namespace Common {
00031 
00032 MemoryPool *g_refCountPool = nullptr; // FIXME: This is never freed right now
00033 MutexRef g_refCountPoolMutex = nullptr;
00034 
00035 void lockMemoryPoolMutex() {
00036     // The Mutex class can only be used once g_system is set and initialized,
00037     // but we may use the String class earlier than that (it is for example
00038     // used in the OSystem_POSIX constructor). However in those early stages
00039     // we can hope we don't have multiple threads either.
00040     if (!g_system || !g_system->backendInitialized())
00041         return;
00042     if (!g_refCountPoolMutex)
00043         g_refCountPoolMutex = g_system->createMutex();
00044     g_system->lockMutex(g_refCountPoolMutex);
00045 }
00046 
00047 void unlockMemoryPoolMutex() {
00048     if (g_refCountPoolMutex)
00049         g_system->unlockMutex(g_refCountPoolMutex);
00050 }
00051 
00052 void String::releaseMemoryPoolMutex() {
00053     if (g_refCountPoolMutex){
00054         g_system->deleteMutex(g_refCountPoolMutex);
00055         g_refCountPoolMutex = nullptr;
00056     }
00057 }
00058 
00059 static uint32 computeCapacity(uint32 len) {
00060     // By default, for the capacity we use the next multiple of 32
00061     return ((len + 32 - 1) & ~0x1F);
00062 }
00063 
00064 String::String(const char *str) : _size(0), _str(_storage) {
00065     if (str == nullptr) {
00066         _storage[0] = 0;
00067         _size = 0;
00068     } else
00069         initWithCStr(str, strlen(str));
00070 }
00071 
00072 String::String(const char *str, uint32 len) : _size(0), _str(_storage) {
00073     initWithCStr(str, len);
00074 }
00075 
00076 String::String(const char *beginP, const char *endP) : _size(0), _str(_storage) {
00077     assert(endP >= beginP);
00078     initWithCStr(beginP, endP - beginP);
00079 }
00080 
00081 void String::initWithCStr(const char *str, uint32 len) {
00082     assert(str);
00083 
00084     // Init _storage member explicitly (ie. without calling its constructor)
00085     // for GCC 2.95.x compatibility (see also tracker item #1602879).
00086     _storage[0] = 0;
00087 
00088     _size = len;
00089 
00090     if (len >= _builtinCapacity) {
00091         // Not enough internal storage, so allocate more
00092         _extern._capacity = computeCapacity(len + 1);
00093         _extern._refCount = nullptr;
00094         _str = new char[_extern._capacity];
00095         assert(_str != nullptr);
00096     }
00097 
00098     // Copy the string into the storage area
00099     memmove(_str, str, len);
00100     _str[len] = 0;
00101 }
00102 
00103 String::String(const String &str)
00104     : _size(str._size) {
00105     if (str.isStorageIntern()) {
00106         // String in internal storage: just copy it
00107         memcpy(_storage, str._storage, _builtinCapacity);
00108         _str = _storage;
00109     } else {
00110         // String in external storage: use refcount mechanism
00111         str.incRefCount();
00112         _extern._refCount = str._extern._refCount;
00113         _extern._capacity = str._extern._capacity;
00114         _str = str._str;
00115     }
00116     assert(_str != nullptr);
00117 }
00118 
00119 String::String(char c)
00120     : _size(0), _str(_storage) {
00121 
00122     _storage[0] = c;
00123     _storage[1] = 0;
00124 
00125     _size = (c == 0) ? 0 : 1;
00126 }
00127 
00128 String::~String() {
00129     decRefCount(_extern._refCount);
00130 }
00131 
00132 void String::makeUnique() {
00133     ensureCapacity(_size, true);
00134 }
00135 
00142 void String::ensureCapacity(uint32 new_size, bool keep_old) {
00143     bool isShared;
00144     uint32 curCapacity, newCapacity;
00145     char *newStorage;
00146     int *oldRefCount = _extern._refCount;
00147 
00148     if (isStorageIntern()) {
00149         isShared = false;
00150         curCapacity = _builtinCapacity;
00151     } else {
00152         isShared = (oldRefCount && *oldRefCount > 1);
00153         curCapacity = _extern._capacity;
00154     }
00155 
00156     // Special case: If there is enough space, and we do not share
00157     // the storage, then there is nothing to do.
00158     if (!isShared && new_size < curCapacity)
00159         return;
00160 
00161     // We need to allocate storage on the heap!
00162 
00163     // Compute a suitable new capacity limit
00164     // If the current capacity is sufficient we use the same capacity
00165     if (new_size < curCapacity)
00166         newCapacity = curCapacity;
00167     else
00168         newCapacity = MAX(curCapacity * 2, computeCapacity(new_size+1));
00169 
00170     // Allocate new storage
00171     newStorage = new char[newCapacity];
00172     assert(newStorage);
00173 
00174 
00175     // Copy old data if needed, elsewise reset the new storage.
00176     if (keep_old) {
00177         assert(_size < newCapacity);
00178         memcpy(newStorage, _str, _size + 1);
00179     } else {
00180         _size = 0;
00181         newStorage[0] = 0;
00182     }
00183 
00184     // Release hold on the old storage ...
00185     decRefCount(oldRefCount);
00186 
00187     // ... in favor of the new storage
00188     _str = newStorage;
00189 
00190     if (!isStorageIntern()) {
00191         // Set the ref count & capacity if we use an external storage.
00192         // It is important to do this *after* copying any old content,
00193         // else we would override data that has not yet been copied!
00194         _extern._refCount = nullptr;
00195         _extern._capacity = newCapacity;
00196     }
00197 }
00198 
00199 void String::incRefCount() const {
00200     assert(!isStorageIntern());
00201     if (_extern._refCount == nullptr) {
00202         lockMemoryPoolMutex();
00203         if (g_refCountPool == nullptr) {
00204             g_refCountPool = new MemoryPool(sizeof(int));
00205             assert(g_refCountPool);
00206         }
00207 
00208         _extern._refCount = (int *)g_refCountPool->allocChunk();
00209         unlockMemoryPoolMutex();
00210         *_extern._refCount = 2;
00211     } else {
00212         ++(*_extern._refCount);
00213     }
00214 }
00215 
00216 void String::decRefCount(int *oldRefCount) {
00217     if (isStorageIntern())
00218         return;
00219 
00220     if (oldRefCount) {
00221         --(*oldRefCount);
00222     }
00223     if (!oldRefCount || *oldRefCount <= 0) {
00224         // The ref count reached zero, so we free the string storage
00225         // and the ref count storage.
00226         if (oldRefCount) {
00227             lockMemoryPoolMutex();
00228             assert(g_refCountPool);
00229             g_refCountPool->freeChunk(oldRefCount);
00230             unlockMemoryPoolMutex();
00231         }
00232         delete[] _str;
00233 
00234         // Even though _str points to a freed memory block now,
00235         // we do not change its value, because any code that calls
00236         // decRefCount will have to do this afterwards anyway.
00237     }
00238 }
00239 
00240 String &String::operator=(const char *str) {
00241     uint32 len = strlen(str);
00242     ensureCapacity(len, false);
00243     _size = len;
00244     memmove(_str, str, len + 1);
00245     return *this;
00246 }
00247 
00248 String &String::operator=(const String &str) {
00249     if (&str == this)
00250         return *this;
00251 
00252     if (str.isStorageIntern()) {
00253         decRefCount(_extern._refCount);
00254         _size = str._size;
00255         _str = _storage;
00256         memcpy(_str, str._str, _size + 1);
00257     } else {
00258         str.incRefCount();
00259         decRefCount(_extern._refCount);
00260 
00261         _extern._refCount = str._extern._refCount;
00262         _extern._capacity = str._extern._capacity;
00263         _size = str._size;
00264         _str = str._str;
00265     }
00266 
00267     return *this;
00268 }
00269 
00270 String &String::operator=(char c) {
00271     decRefCount(_extern._refCount);
00272     _str = _storage;
00273 
00274     _str[0] = c;
00275     _str[1] = 0;
00276 
00277     _size = (c == 0) ? 0 : 1;
00278     return *this;
00279 }
00280 
00281 String &String::operator+=(const char *str) {
00282     if (_str <= str && str <= _str + _size)
00283         return operator+=(String(str));
00284 
00285     int len = strlen(str);
00286     if (len > 0) {
00287         ensureCapacity(_size + len, true);
00288 
00289         memcpy(_str + _size, str, len + 1);
00290         _size += len;
00291     }
00292     return *this;
00293 }
00294 
00295 String &String::operator+=(const String &str) {
00296     if (&str == this)
00297         return operator+=(String(str));
00298 
00299     int len = str._size;
00300     if (len > 0) {
00301         ensureCapacity(_size + len, true);
00302 
00303         memcpy(_str + _size, str._str, len + 1);
00304         _size += len;
00305     }
00306     return *this;
00307 }
00308 
00309 String &String::operator+=(char c) {
00310     ensureCapacity(_size + 1, true);
00311 
00312     _str[_size++] = c;
00313     _str[_size] = 0;
00314 
00315     return *this;
00316 }
00317 
00318 bool String::hasPrefix(const String &x) const {
00319     return hasPrefix(x.c_str());
00320 }
00321 
00322 bool String::hasPrefix(const char *x) const {
00323     assert(x != nullptr);
00324     // Compare x with the start of _str.
00325     const char *y = c_str();
00326     while (*x && *x == *y) {
00327         ++x;
00328         ++y;
00329     }
00330     // It's a prefix, if and only if all letters in x are 'used up' before
00331     // _str ends.
00332     return *x == 0;
00333 }
00334 
00335 bool String::hasPrefixIgnoreCase(const String &x) const {
00336     return hasPrefixIgnoreCase(x.c_str());
00337 }
00338 
00339 bool String::hasPrefixIgnoreCase(const char *x) const {
00340     assert(x != nullptr);
00341     // Compare x with the start of _str.
00342     const char *y = c_str();
00343     while (*x && tolower(*x) == tolower(*y)) {
00344         ++x;
00345         ++y;
00346     }
00347     // It's a prefix, if and only if all letters in x are 'used up' before
00348     // _str ends.
00349     return *x == 0;
00350 }
00351 
00352 bool String::hasSuffix(const String &x) const {
00353     return hasSuffix(x.c_str());
00354 }
00355 
00356 bool String::hasSuffix(const char *x) const {
00357     assert(x != nullptr);
00358     // Compare x with the end of _str.
00359     const uint32 x_size = strlen(x);
00360     if (x_size > _size)
00361         return false;
00362     const char *y = c_str() + _size - x_size;
00363     while (*x && *x == *y) {
00364         ++x;
00365         ++y;
00366     }
00367     // It's a suffix, if and only if all letters in x are 'used up' before
00368     // _str ends.
00369     return *x == 0;
00370 }
00371 
00372 bool String::hasSuffixIgnoreCase(const String &x) const {
00373     return hasSuffixIgnoreCase(x.c_str());
00374 }
00375 
00376 bool String::hasSuffixIgnoreCase(const char *x) const {
00377     assert(x != nullptr);
00378     // Compare x with the end of _str.
00379     const uint32 x_size = strlen(x);
00380     if (x_size > _size)
00381         return false;
00382     const char *y = c_str() + _size - x_size;
00383     while (*x && tolower(*x) == tolower(*y)) {
00384         ++x;
00385         ++y;
00386     }
00387     // It's a suffix, if and only if all letters in x are 'used up' before
00388     // _str ends.
00389     return *x == 0;
00390 }
00391 
00392 bool String::contains(const String &x) const {
00393     return strstr(c_str(), x.c_str()) != nullptr;
00394 }
00395 
00396 bool String::contains(const char *x) const {
00397     assert(x != nullptr);
00398     return strstr(c_str(), x) != nullptr;
00399 }
00400 
00401 bool String::contains(char x) const {
00402     return strchr(c_str(), x) != nullptr;
00403 }
00404 
00405 uint64 String::asUint64() const {
00406     uint64 result = 0;
00407     for (uint32 i = 0; i < _size; ++i) {
00408         if (_str[i] < '0' || _str[i] > '9') break;
00409         result = result * 10L + (_str[i] - '0');
00410     }
00411     return result;
00412 }
00413 
00414 bool String::matchString(const char *pat, bool ignoreCase, bool pathMode) const {
00415     return Common::matchString(c_str(), pat, ignoreCase, pathMode);
00416 }
00417 
00418 bool String::matchString(const String &pat, bool ignoreCase, bool pathMode) const {
00419     return Common::matchString(c_str(), pat.c_str(), ignoreCase, pathMode);
00420 }
00421 
00422 void String::deleteLastChar() {
00423     if (_size > 0)
00424         deleteChar(_size - 1);
00425 }
00426 
00427 void String::deleteChar(uint32 p) {
00428     assert(p < _size);
00429 
00430     makeUnique();
00431     while (p++ < _size)
00432         _str[p - 1] = _str[p];
00433     _size--;
00434 }
00435 
00436 void String::erase(uint32 p, uint32 len) {
00437     assert(p < _size);
00438 
00439     makeUnique();
00440     // If len == npos or p + len is over the end, remove all the way to the end
00441     if (len == npos || p + len >= _size) {
00442         // Delete char at p as well. So _size = (p - 1) + 1
00443         _size = p;
00444         // Null terminate
00445         _str[_size] = 0;
00446         return;
00447     }
00448 
00449     for ( ; p + len <= _size; p++) {
00450         _str[p] = _str[p + len];
00451     }
00452     _size -= len;
00453 }
00454 
00455 void String::clear() {
00456     decRefCount(_extern._refCount);
00457 
00458     _size = 0;
00459     _str = _storage;
00460     _storage[0] = 0;
00461 }
00462 
00463 void String::setChar(char c, uint32 p) {
00464     assert(p < _size);
00465 
00466     makeUnique();
00467     _str[p] = c;
00468 }
00469 
00470 void String::insertChar(char c, uint32 p) {
00471     assert(p <= _size);
00472 
00473     ensureCapacity(_size + 1, true);
00474     _size++;
00475     for (uint32 i = _size; i > p; --i)
00476         _str[i] = _str[i - 1];
00477     _str[p] = c;
00478 }
00479 
00480 void String::toLowercase() {
00481     makeUnique();
00482     for (uint32 i = 0; i < _size; ++i)
00483         _str[i] = tolower(_str[i]);
00484 }
00485 
00486 void String::toUppercase() {
00487     makeUnique();
00488     for (uint32 i = 0; i < _size; ++i)
00489         _str[i] = toupper(_str[i]);
00490 }
00491 
00492 void String::trim() {
00493     if (_size == 0)
00494         return;
00495 
00496     makeUnique();
00497 
00498     // Trim trailing whitespace
00499     while (_size >= 1 && isSpace(_str[_size - 1]))
00500         --_size;
00501     _str[_size] = 0;
00502 
00503     // Trim leading whitespace
00504     char *t = _str;
00505     while (isSpace(*t))
00506         t++;
00507 
00508     if (t != _str) {
00509         _size -= t - _str;
00510         memmove(_str, t, _size + 1);
00511     }
00512 }
00513 
00514 void String::wordWrap(const uint32 maxLength) {
00515     if (_size < maxLength) {
00516         return;
00517     }
00518 
00519     makeUnique();
00520 
00521     enum { kNoSpace = 0xFFFFFFFF };
00522 
00523     uint32 i = 0;
00524     while (i < _size) {
00525         uint32 lastSpace = kNoSpace;
00526         uint32 x = 0;
00527         while (i < _size && x <= maxLength) {
00528             const char c = _str[i];
00529             if (c == '\n') {
00530                 lastSpace = kNoSpace;
00531                 x = 0;
00532             } else {
00533                 if (Common::isSpace(c)) {
00534                     lastSpace = i;
00535                 }
00536                 ++x;
00537             }
00538             ++i;
00539         }
00540 
00541         if (x > maxLength) {
00542             if (lastSpace == kNoSpace) {
00543                 insertChar('\n', i - 1);
00544             } else {
00545                 setChar('\n', lastSpace);
00546                 i = lastSpace + 1;
00547             }
00548         }
00549     }
00550 }
00551 
00552 uint String::hash() const {
00553     return hashit(c_str());
00554 }
00555 
00556 void String::replace(uint32 pos, uint32 count, const String &str) {
00557     replace(pos, count, str, 0, str._size);
00558 }
00559 
00560 void String::replace(uint32 pos, uint32 count, const char *str) {
00561     replace(pos, count, str, 0, strlen(str));
00562 }
00563 
00564 void String::replace(iterator begin_, iterator end_, const String &str) {
00565     replace(begin_ - _str, end_ - begin_, str._str, 0, str._size);
00566 }
00567 
00568 void String::replace(iterator begin_, iterator end_, const char *str) {
00569     replace(begin_ - _str, end_ - begin_, str, 0, strlen(str));
00570 }
00571 
00572 void String::replace(uint32 posOri, uint32 countOri, const String &str,
00573                      uint32 posDest, uint32 countDest) {
00574     replace(posOri, countOri, str._str, posDest, countDest);
00575 }
00576 
00577 void String::replace(uint32 posOri, uint32 countOri, const char *str,
00578                      uint32 posDest, uint32 countDest) {
00579 
00580     ensureCapacity(_size + countDest - countOri, true);
00581 
00582     // Prepare string for the replaced text.
00583     if (countOri < countDest) {
00584         uint32 offset = countDest - countOri; 
00585         uint32 newSize = _size + offset;
00586         _size = newSize;
00587 
00588         // Push the old characters to the end of the string
00589         for (uint32 i = _size; i >= posOri + countDest; i--)
00590             _str[i] = _str[i - offset];
00591 
00592     } else if (countOri > countDest){
00593         uint32 offset = countOri - countDest; 
00594 
00595         // Pull the remainder string back
00596         for (uint32 i = posOri + countDest; i < _size; i++)
00597             _str[i] = _str[i + offset];
00598 
00599         _size -= offset;
00600     }
00601 
00602     // Copy the replaced part of the string
00603     for (uint32 i = 0; i < countDest; i++)
00604         _str[posOri + i] = str[posDest + i];
00605 
00606 }
00607 
00608 // static
00609 String String::format(const char *fmt, ...) {
00610     String output;
00611 
00612     va_list va;
00613     va_start(va, fmt);
00614     output = String::vformat(fmt, va);
00615     va_end(va);
00616 
00617     return output;
00618 }
00619 
00620 // static
00621 String String::vformat(const char *fmt, va_list args) {
00622     String output;
00623     assert(output.isStorageIntern());
00624 
00625     va_list va;
00626     scumm_va_copy(va, args);
00627     int len = vsnprintf(output._str, _builtinCapacity, fmt, va);
00628     va_end(va);
00629 
00630     if (len == -1 || len == _builtinCapacity - 1) {
00631         // MSVC and IRIX don't return the size the full string would take up.
00632         // MSVC returns -1, IRIX returns the number of characters actually written,
00633         // which is at the most the size of the buffer minus one, as the string is
00634         // truncated to fit.
00635 
00636         // We assume MSVC failed to output the correct, null-terminated string
00637         // if the return value is either -1 or size.
00638         // For IRIX, because we lack a better mechanism, we assume failure
00639         // if the return value equals size - 1.
00640         // The downside to this is that whenever we try to format a string where the
00641         // size is 1 below the built-in capacity, the size is needlessly increased.
00642 
00643         // Try increasing the size of the string until it fits.
00644         int size = _builtinCapacity;
00645         do {
00646             size *= 2;
00647             output.ensureCapacity(size - 1, false);
00648             assert(!output.isStorageIntern());
00649             size = output._extern._capacity;
00650 
00651             scumm_va_copy(va, args);
00652             len = vsnprintf(output._str, size, fmt, va);
00653             va_end(va);
00654         } while (len == -1 || len >= size - 1);
00655         output._size = len;
00656     } else if (len < (int)_builtinCapacity) {
00657         // vsnprintf succeeded
00658         output._size = len;
00659     } else {
00660         // vsnprintf didn't have enough space, so grow buffer
00661         output.ensureCapacity(len, false);
00662         scumm_va_copy(va, args);
00663         int len2 = vsnprintf(output._str, len + 1, fmt, va);
00664         va_end(va);
00665         assert(len == len2);
00666         output._size = len2;
00667     }
00668 
00669     return output;
00670 }
00671 
00672 
00673 #pragma mark -
00674 
00675 bool String::operator==(const String &x) const {
00676     return equals(x);
00677 }
00678 
00679 bool String::operator==(const char *x) const {
00680     assert(x != nullptr);
00681     return equals(x);
00682 }
00683 
00684 bool String::operator!=(const String &x) const {
00685     return !equals(x);
00686 }
00687 
00688 bool String::operator !=(const char *x) const {
00689     assert(x != nullptr);
00690     return !equals(x);
00691 }
00692 
00693 bool String::operator<(const String &x) const {
00694     return compareTo(x) < 0;
00695 }
00696 
00697 bool String::operator<=(const String &x) const {
00698     return compareTo(x) <= 0;
00699 }
00700 
00701 bool String::operator>(const String &x) const {
00702     return compareTo(x) > 0;
00703 }
00704 
00705 bool String::operator>=(const String &x) const {
00706     return compareTo(x) >= 0;
00707 }
00708 
00709 #pragma mark -
00710 
00711 bool operator==(const char* y, const String &x) {
00712     return (x == y);
00713 }
00714 
00715 bool operator!=(const char* y, const String &x) {
00716     return x != y;
00717 }
00718 
00719 #pragma mark -
00720 
00721 bool String::equals(const String &x) const {
00722     return (0 == compareTo(x));
00723 }
00724 
00725 bool String::equals(const char *x) const {
00726     assert(x != nullptr);
00727     return (0 == compareTo(x));
00728 }
00729 
00730 bool String::equalsIgnoreCase(const String &x) const {
00731     return (0 == compareToIgnoreCase(x));
00732 }
00733 
00734 bool String::equalsIgnoreCase(const char *x) const {
00735     assert(x != nullptr);
00736     return (0 == compareToIgnoreCase(x));
00737 }
00738 
00739 int String::compareTo(const String &x) const {
00740     return compareTo(x.c_str());
00741 }
00742 
00743 int String::compareTo(const char *x) const {
00744     assert(x != nullptr);
00745     return strcmp(c_str(), x);
00746 }
00747 
00748 int String::compareToIgnoreCase(const String &x) const {
00749     return compareToIgnoreCase(x.c_str());
00750 }
00751 
00752 int String::compareToIgnoreCase(const char *x) const {
00753     assert(x != nullptr);
00754     return scumm_stricmp(c_str(), x);
00755 }
00756 
00757 #pragma mark -
00758 
00759 String operator+(const String &x, const String &y) {
00760     String temp(x);
00761     temp += y;
00762     return temp;
00763 }
00764 
00765 String operator+(const char *x, const String &y) {
00766     String temp(x);
00767     temp += y;
00768     return temp;
00769 }
00770 
00771 String operator+(const String &x, const char *y) {
00772     String temp(x);
00773     temp += y;
00774     return temp;
00775 }
00776 
00777 String operator+(char x, const String &y) {
00778     String temp(x);
00779     temp += y;
00780     return temp;
00781 }
00782 
00783 String operator+(const String &x, char y) {
00784     String temp(x);
00785     temp += y;
00786     return temp;
00787 }
00788 
00789 char *ltrim(char *t) {
00790     while (isSpace(*t))
00791         t++;
00792     return t;
00793 }
00794 
00795 char *rtrim(char *t) {
00796     int l = strlen(t) - 1;
00797     while (l >= 0 && isSpace(t[l]))
00798         t[l--] = 0;
00799     return t;
00800 }
00801 
00802 char *trim(char *t) {
00803     return rtrim(ltrim(t));
00804 }
00805 
00806 String lastPathComponent(const String &path, const char sep) {
00807     const char *str = path.c_str();
00808     const char *last = str + path.size();
00809 
00810     // Skip over trailing slashes
00811     while (last > str && *(last - 1) == sep)
00812         --last;
00813 
00814     // Path consisted of only slashes -> return empty string
00815     if (last == str)
00816         return String();
00817 
00818     // Now scan the whole component
00819     const char *first = last - 1;
00820     while (first > str && *first != sep)
00821         --first;
00822 
00823     if (*first == sep)
00824         first++;
00825 
00826     return String(first, last);
00827 }
00828 
00829 String normalizePath(const String &path, const char sep) {
00830     if (path.empty())
00831         return path;
00832 
00833     const char *cur = path.c_str();
00834     String result;
00835 
00836     // If there is a leading slash, preserve that:
00837     if (*cur == sep) {
00838         result += sep;
00839         // Skip over multiple leading slashes, so "//" equals "/"
00840         while (*cur == sep)
00841             ++cur;
00842     }
00843 
00844     // Scan for path components till the end of the String
00845     List<String> comps;
00846     while (*cur != 0) {
00847         const char *start = cur;
00848 
00849         // Scan till the next path separator resp. the end of the string
00850         while (*cur != sep && *cur != 0)
00851             cur++;
00852 
00853         const String component(start, cur);
00854 
00855         if (component.empty() || component == ".") {
00856             // Skip empty components and dot components
00857         } else if (!comps.empty() && component == ".." && comps.back() != "..") {
00858             // If stack is non-empty and top is not "..", remove top
00859             comps.pop_back();
00860         } else {
00861             // Add the component to the stack
00862             comps.push_back(component);
00863         }
00864 
00865         // Skip over separator chars
00866         while (*cur == sep)
00867             cur++;
00868     }
00869 
00870     // Finally, assemble all components back into a path
00871     while (!comps.empty()) {
00872         result += comps.front();
00873         comps.pop_front();
00874         if (!comps.empty())
00875             result += sep;
00876     }
00877 
00878     return result;
00879 }
00880 
00881 bool matchString(const char *str, const char *pat, bool ignoreCase, bool pathMode) {
00882     assert(str);
00883     assert(pat);
00884 
00885     const char *p = nullptr;
00886     const char *q = nullptr;
00887 
00888     for (;;) {
00889         if (pathMode && *str == '/') {
00890             p = nullptr;
00891             q = nullptr;
00892             if (*pat == '?')
00893                 return false;
00894         }
00895 
00896         switch (*pat) {
00897         case '*':
00898             if (*str) {
00899                 // Record pattern / string position for backtracking
00900                 p = ++pat;
00901                 q = str;
00902             } else {
00903                 // If we've reached the end of str, we can't backtrack further
00904                 // NB: We can't simply check if pat also ended here, because
00905                 // the pattern might end with any number of *s.
00906                 ++pat;
00907                 p = nullptr;
00908                 q = nullptr;
00909             }
00910             // If pattern ended with * -> match
00911             if (!*pat)
00912                 return true;
00913             break;
00914 
00915         case '#':
00916             if (!isDigit(*str))
00917                 return false;
00918             pat++;
00919             str++;
00920             break;
00921 
00922         default:
00923             if ((!ignoreCase && *pat != *str) ||
00924                 (ignoreCase && tolower(*pat) != tolower(*str))) {
00925                 if (p) {
00926                     // No match, oops -> try to backtrack
00927                     pat = p;
00928                     str = ++q;
00929                     if (!*str)
00930                         return !*pat;
00931                     break;
00932                 }
00933                 else
00934                     return false;
00935             }
00936             // fallthrough
00937         case '?':
00938             if (!*str)
00939                 return !*pat;
00940             pat++;
00941             str++;
00942         }
00943     }
00944 }
00945 
00946 void replace(Common::String &source, const Common::String &what, const Common::String &with) {
00947     const char *cstr = source.c_str();
00948     const char *position = strstr(cstr, what.c_str());
00949     if (position) {
00950         uint32 index = position - cstr;
00951         source.replace(index, what.size(), with);
00952     }
00953 }
00954 
00955 String tag2string(uint32 tag) {
00956     char str[5];
00957     str[0] = (char)(tag >> 24);
00958     str[1] = (char)(tag >> 16);
00959     str[2] = (char)(tag >> 8);
00960     str[3] = (char)tag;
00961     str[4] = '\0';
00962     // Replace non-printable chars by dot
00963     for (int i = 0; i < 4; ++i) {
00964         if (!Common::isPrint(str[i]))
00965             str[i] = '.';
00966     }
00967     return String(str);
00968 }
00969 
00970 size_t strlcpy(char *dst, const char *src, size_t size) {
00971     // Our backup of the source's start, we need this
00972     // to calculate the source's length.
00973     const char * const srcStart = src;
00974 
00975     // In case a non-empty size was specified we
00976     // copy over (size - 1) bytes at max.
00977     if (size != 0) {
00978         // Copy over (size - 1) bytes at max.
00979         while (--size != 0) {
00980             if ((*dst++ = *src) == 0)
00981                 break;
00982             ++src;
00983         }
00984 
00985         // In case the source string was longer than the
00986         // destination, we need to add a terminating
00987         // zero.
00988         if (size == 0)
00989             *dst = 0;
00990     }
00991 
00992     // Move to the terminating zero of the source
00993     // string, we need this to determine the length
00994     // of the source string.
00995     while (*src)
00996         ++src;
00997 
00998     // Return the source string's length.
00999     return src - srcStart;
01000 }
01001 
01002 size_t strlcat(char *dst, const char *src, size_t size) {
01003     // In case the destination buffer does not contain
01004     // space for at least 1 character, we will just
01005     // return the source string's length.
01006     if (size == 0)
01007         return strlen(src);
01008 
01009     // Our backup of the source's start, we need this
01010     // to calculate the source's length.
01011     const char * const srcStart = src;
01012 
01013     // Our backup of the destination's start, we need
01014     // this to calculate the destination's length.
01015     const char * const dstStart = dst;
01016 
01017     // Search the end of the destination, but do not
01018     // move past the terminating zero.
01019     while (size-- != 0 && *dst != 0)
01020         ++dst;
01021 
01022     // Calculate the destination's length;
01023     const size_t dstLength = dst - dstStart;
01024 
01025     // In case we reached the end of the destination
01026     // buffer before we had a chance to append any
01027     // characters we will just return the destination
01028     // length plus the source string's length.
01029     if (size == 0)
01030         return dstLength + strlen(srcStart);
01031 
01032     // Copy over all of the source that fits
01033     // the destination buffer. We also need
01034     // to take the terminating zero we will
01035     // add into consideration.
01036     while (size-- != 0 && *src != 0)
01037         *dst++ = *src++;
01038     *dst = 0;
01039 
01040     // Move to the terminating zero of the source
01041     // string, we need this to determine the length
01042     // of the source string.
01043     while (*src)
01044         ++src;
01045 
01046     // Return the total length of the result string
01047     return dstLength + (src - srcStart);
01048 }
01049 
01050 size_t strnlen(const char *src, size_t maxSize) {
01051     size_t counter = 0;
01052     while (counter != maxSize && *src++)
01053         ++counter;
01054     return counter;
01055 }
01056 
01057 } // End of namespace Common
01058 
01059 // Portable implementation of stricmp / strcasecmp / strcmpi.
01060 // TODO: Rename this to Common::strcasecmp
01061 int scumm_stricmp(const char *s1, const char *s2) {
01062     byte l1, l2;
01063     do {
01064         // Don't use ++ inside tolower, in case the macro uses its
01065         // arguments more than once.
01066         l1 = (byte)*s1++;
01067         l1 = tolower(l1);
01068         l2 = (byte)*s2++;
01069         l2 = tolower(l2);
01070     } while (l1 == l2 && l1 != 0);
01071     return l1 - l2;
01072 }
01073 
01074 // Portable implementation of strnicmp / strncasecmp / strncmpi.
01075 // TODO: Rename this to Common::strncasecmp
01076 int scumm_strnicmp(const char *s1, const char *s2, uint n) {
01077     byte l1, l2;
01078     do {
01079         if (n-- == 0)
01080             return 0; // no difference found so far -> signal equality
01081 
01082         // Don't use ++ inside tolower, in case the macro uses its
01083         // arguments more than once.
01084         l1 = (byte)*s1++;
01085         l1 = tolower(l1);
01086         l2 = (byte)*s2++;
01087         l2 = tolower(l2);
01088     } while (l1 == l2 && l1 != 0);
01089     return l1 - l2;
01090 }
01091 
01092 //  Portable implementation of strdup.
01093 char *scumm_strdup(const char *in) {
01094     const size_t len = strlen(in) + 1;
01095     char *out = new char[len];
01096     if (out) {
01097         strcpy(out, in);
01098     }
01099     return out;
01100 }


Generated on Sat Mar 16 2019 05:01:55 for ResidualVM by doxygen 1.7.1
curved edge   curved edge