diff options
Diffstat (limited to 'trunk/src/lib/util/astring.c')
-rw-r--r-- | trunk/src/lib/util/astring.c | 504 |
1 files changed, 504 insertions, 0 deletions
diff --git a/trunk/src/lib/util/astring.c b/trunk/src/lib/util/astring.c new file mode 100644 index 00000000000..2c001f3db62 --- /dev/null +++ b/trunk/src/lib/util/astring.c @@ -0,0 +1,504 @@ +/*************************************************************************** + + astring.c + + Allocated string manipulation functions. + +**************************************************************************** + + Copyright Aaron Giles + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name 'MAME' nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +****************************************************************************/ + +#include "astring.h" +#include "osdcore.h" + +#include <string.h> +#include <stdarg.h> +#include <stdlib.h> +#include <ctype.h> +#include <new> + + +/*************************************************************************** + GLOBAL VARIABLES +***************************************************************************/ + +static const astring dummy_astring; + + + +//************************************************************************** +// INLINE FUNCTIONS +//************************************************************************** + +//------------------------------------------------- +// ensure_room - ensure we have room for a +// given string, or else reallocate our buffer +//------------------------------------------------- + +bool astring::ensure_room(int length) +{ + // always fail to expand the dummy + if (this == &dummy_astring) + return false; + + // if we have the room, do nothing + if (m_alloclen >= length + 1) + return true; + + // allocate a new buffer with some slop + int alloclen = length + 256; + char *newbuf = new char[alloclen]; + + // swap in the new buffer and free the old one + char *oldbuf = (m_text == m_smallbuf) ? NULL : m_text; + m_text = strcpy(newbuf, m_text); + m_alloclen = alloclen; + delete[] oldbuf; + + return true; +} + + +//------------------------------------------------- +// safe_string_base - return a "safe" string +// base for a given start index +//------------------------------------------------- + +inline char *astring::safe_string_base(int start) const +{ + int max = len(); + return (start >= 0 && start < max) ? m_text + start : m_text + max; +} + + +//------------------------------------------------- +// normalize_substr - normalize substr parameters +//------------------------------------------------- + +inline void astring::normalize_substr(int &start, int &count, int length) const +{ + // limit start + if (start < 0) + start = 0; + else if (start > length) + start = length; + + // update count + if (count == -1 || start + count > length) + count = length - start; +} + + + +//************************************************************************** +// ASTRING ALLOCATION +//************************************************************************** + +//------------------------------------------------- +// init - constructor helper +//------------------------------------------------- + +astring &astring::init() +{ + // initialize ourselves to point to the internal buffer + m_text = m_smallbuf; + m_alloclen = ARRAY_LENGTH(m_smallbuf); + m_smallbuf[0] = 0; + return *this; +} + + +//------------------------------------------------- +// ~astring - destructor +//------------------------------------------------- + +astring::~astring() +{ + if (m_text != m_smallbuf) + delete[] m_text; +} + + + +/*************************************************************************** + INLINE ASTRING CHANGES +***************************************************************************/ + +//------------------------------------------------- +// cpy - copy a character array into an astring +//------------------------------------------------- + +astring &astring::cpy(const char *src, int count) +{ + // make room; if we fail or if we are the dummy, do nothing + if (!ensure_room(count)) + return *this; + + // copy the raw data and NULL-terminate + if (count > 0 && m_text != src) + memcpy(m_text, src, count); + m_text[count] = 0; + return *this; +} + + +//------------------------------------------------- +// cpysubstr - copy a substring of one string to +// another +//------------------------------------------------- + +astring &astring::cpysubstr(const astring &src, int start, int count) +{ + normalize_substr(start, count, strlen(src.m_text)); + return cpy(src.m_text + start, count); +} + + +//------------------------------------------------- +// ins - insert a character array into an astring +//------------------------------------------------- + +astring &astring::ins(int insbefore, const char *src, int count) +{ + // make room; if we fail or if we are the dummy, do nothing + int dstlength = len(); + if (!ensure_room(dstlength + count)) + return *this; + + // adjust insbefore to be logical + if (insbefore < 0 || insbefore > dstlength) + insbefore = dstlength; + + // copy the data an NULL-terminate + if (insbefore < dstlength) + memmove(m_text + insbefore + count, m_text + insbefore, dstlength - insbefore); + memcpy(m_text + insbefore, src, count); + m_text[dstlength + count] = 0; + return *this; +} + + +//------------------------------------------------- +// inssubstr - insert a substring of one string +// into another +//------------------------------------------------- + +astring &astring::inssubstr(int insbefore, const astring &src, int start, int count) +{ + normalize_substr(start, count, strlen(src.m_text)); + return ins(insbefore, src.m_text + start, count); +} + + +//------------------------------------------------- +// substr - extract a substring of ourself, +// removing everything else +//------------------------------------------------- + +astring &astring::substr(int start, int count) +{ + // ignore attempts to do this on the dummy + if (this == &dummy_astring) + return *this; + + // normalize parameters + normalize_substr(start, count, strlen(m_text)); + + // move the data and NULL-terminate + if (count > 0 && start > 0) + memmove(m_text, m_text + start, count); + m_text[count] = 0; + return *this; +} + + +//------------------------------------------------- +// del - delete a substring of ourself, keeping +// everything else +//------------------------------------------------- + +astring &astring::del(int start, int count) +{ + // ignore attempts to do this on the dummy + if (this == &dummy_astring) + return *this; + + // normalize parameters + int strlength = strlen(m_text); + normalize_substr(start, count, strlength); + + // move the data and NULL-terminate + if (count > 0) + memmove(m_text + start, m_text + start + count, strlength - (start + count)); + m_text[strlength - count] = 0; + return *this; +} + + +//------------------------------------------------- +// vprintf - vprintf text into an astring +//-------------------------------------------------*/ + +int astring::vprintf(const char *format, va_list args) +{ + // sprintf into the temporary buffer + char tempbuf[4096]; + int result = vsprintf(tempbuf, format, args); + + // set the result + cpy(tempbuf); + return result; +} + + +//------------------------------------------------- +// catprintf - formatted vprintf to the end of +// an astring +//------------------------------------------------- + +int astring::catvprintf(const char *format, va_list args) +{ + // sprintf into the temporary buffer + char tempbuf[4096]; + int result = vsprintf(tempbuf, format, args); + + // append the result + cat(tempbuf); + return result; +} + + + +/*************************************************************************** + ASTRING QUERIES +***************************************************************************/ + +//------------------------------------------------- +// cmp - compare a character array to an astring +//------------------------------------------------- + +int astring::cmp(const char *str2, int count) const +{ + // loop while equal until we hit the end of strings + int index; + for (index = 0; index < count; index++) + if (m_text[index] == 0 || m_text[index] != str2[index]) + break; + + // determine the final result + if (index < count) + return m_text[index] - str2[index]; + if (m_text[index] == 0) + return 0; + return 1; +} + + +//------------------------------------------------- +// cmpsubstr - compare a substring to an astring +//------------------------------------------------- + +int astring::cmpsubstr(const astring &str2, int start, int count) const +{ + normalize_substr(start, count, strlen(str2.m_text)); + return cmp(str2.m_text + start, count); +} + + +//------------------------------------------------- +// icmp - compare a character array to an astring +//------------------------------------------------- + +int astring::icmp(const char *str2, int count) const +{ + // loop while equal until we hit the end of strings + int index; + for (index = 0; index < count; index++) + if (m_text[index] == 0 || tolower(m_text[index]) != tolower(str2[index])) + break; + + // determine the final result + if (index < count) + return tolower(m_text[index]) - tolower(str2[index]); + if (m_text[index] == 0) + return 0; + return 1; +} + + +//------------------------------------------------- +// icmpsubstr - compare a substring to an astring +//------------------------------------------------- + +int astring::icmpsubstr(const astring &str2, int start, int count) const +{ + normalize_substr(start, count, strlen(str2.m_text)); + return icmp(str2.m_text + start, count); +} + + +//------------------------------------------------- +// chr - return the index of a character in an +// astring +//------------------------------------------------- + +int astring::chr(int start, int ch) const +{ + char *result = strchr(safe_string_base(start), ch); + return (result != NULL) ? (result - m_text) : -1; +} + + +//------------------------------------------------- +// rchr - return the index of a character in an +// astring, searching from the end +//------------------------------------------------- + +int astring::rchr(int start, int ch) const +{ + char *result = strrchr(safe_string_base(start), ch); + return (result != NULL) ? (result - m_text) : -1; +} + + +//------------------------------------------------- +// find - find a C string in an astring +//-------------------------------------------------*/ + +int astring::find(int start, const char *search) const +{ + char *result = strstr(safe_string_base(start), search); + return (result != NULL) ? (result - m_text) : -1; +} + + +//------------------------------------------------- +// replacec - search in an astring for a C string, +// replacing all instances with another C string +// and returning the number of matches +//------------------------------------------------- + +int astring::replace(int start, const char *search, const char *replace) +{ + int searchlen = strlen(search); + int replacelen = strlen(replace); + int matches = 0; + + for (int curindex = find(start, search); curindex != -1; curindex = find(curindex + replacelen, search)) + { + matches++; + del(curindex, searchlen).ins(curindex, replace); + } + return matches; +} + + + +//************************************************************************** +// ASTRING UTILITIES +//************************************************************************** + +//------------------------------------------------- +// delchr - delete all instances of 'ch' +//------------------------------------------------- + +astring &astring::delchr(int ch) +{ + // simple deletion + char *dst = m_text; + for (char *src = m_text; *src != 0; src++) + if (*src != ch) + *dst++ = *src; + *dst = 0; + return *this; +} + + +//------------------------------------------------- +// replacechr - replace all instances of 'ch' +// with 'newch' +//------------------------------------------------- + +astring &astring::replacechr(int ch, int newch) +{ + // simple replacement + for (char *text = m_text; *text != 0; text++) + if (*text == ch) + *text = newch; + return *this; +} + + +//------------------------------------------------- +// makeupper - convert string to all upper-case +//------------------------------------------------- + +astring &astring::makeupper() +{ + // just makeupper() on all characters + for (char *text = m_text; *text != 0; text++) + *text = toupper((UINT8)*text); + return *this; +} + + +//------------------------------------------------- +// makelower - convert string to all lower-case +//------------------------------------------------- + +astring &astring::makelower() +{ + // just tolower() on all characters + for (char *text = m_text; *text != 0; text++) + *text = tolower((UINT8)*text); + return *this; +} + + +//------------------------------------------------- +// trimspace - remove all space characters from +// beginning/end +//------------------------------------------------- + +astring &astring::trimspace() +{ + // first remove stuff from the end + for (char *ptr = m_text + strlen(m_text) - 1; ptr >= m_text && (!(*ptr & 0x80) && isspace(UINT8(*ptr))); ptr--) + *ptr = 0; + + // then count how much to remove from the beginning + char *ptr; + for (ptr = m_text; *ptr != 0 && (!(*ptr & 0x80) && isspace(UINT8(*ptr))); ptr++) ; + if (ptr > m_text) + substr(ptr - m_text); + return *this; +} |