WinUAE/archivers/chd/astring.cpp
2022-04-29 21:17:21 +03:00

485 lines
12 KiB
C++

#include "chdtypes.h"
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************
astring.c
Allocated string manipulation functions.
****************************************************************************/
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <ctype.h>
#include <new>
#include "astring.h"
#include "osdcore.h"
/***************************************************************************
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_len = uaestrlen(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;
m_len = 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;
m_len = count;
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, src.len());
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;
m_len = dstlength + count;
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, src.len());
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, len());
// move the data and NULL-terminate
if (count > 0 && start > 0)
memmove(m_text, m_text + start, count);
m_text[count] = 0;
m_len = count;
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 = len();
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;
m_len = strlength - count;
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, str2.len());
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, str2.len());
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;
m_len = strlen(m_text);
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 + len() - 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);
m_len = strlen(m_text);
return *this;
}