mirror of
https://github.com/autc04/Retro68.git
synced 2024-06-15 07:29:41 +00:00
586 lines
11 KiB
C++
586 lines
11 KiB
C++
/* Copyright (C) 2021 Free Software Foundation, Inc.
|
|
Contributed by Oracle.
|
|
|
|
This file is part of GNU Binutils.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3, or (at your option)
|
|
any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, 51 Franklin Street - Fifth Floor, Boston,
|
|
MA 02110-1301, USA. */
|
|
|
|
#include "config.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <values.h>
|
|
#include <stdarg.h>
|
|
|
|
#include "gp-defs.h"
|
|
#include "StringBuilder.h"
|
|
#include "i18n.h"
|
|
|
|
StringBuilder::StringBuilder ()
|
|
{
|
|
count = 0;
|
|
maxCapacity = 16;
|
|
value = (char *) malloc (maxCapacity);
|
|
memset (value, 0, maxCapacity);
|
|
}
|
|
|
|
StringBuilder::StringBuilder (int capacity)
|
|
{
|
|
count = 0;
|
|
maxCapacity = capacity;
|
|
value = (char *) malloc (maxCapacity);
|
|
memset (value, 0, maxCapacity);
|
|
}
|
|
|
|
StringBuilder::~StringBuilder ()
|
|
{
|
|
free (value);
|
|
}
|
|
|
|
void
|
|
StringBuilder::ensureCapacity (int minimumCapacity)
|
|
{
|
|
if (minimumCapacity > maxCapacity)
|
|
expandCapacity (minimumCapacity);
|
|
}
|
|
|
|
void
|
|
StringBuilder::expandCapacity (int minimumCapacity)
|
|
{
|
|
int newCapacity = (maxCapacity + 1) * 2;
|
|
if (newCapacity < 0)
|
|
newCapacity = MAXINT;
|
|
else if (minimumCapacity > newCapacity)
|
|
newCapacity = minimumCapacity;
|
|
char *newValue = (char *) malloc (newCapacity);
|
|
maxCapacity = newCapacity;
|
|
memcpy (newValue, value, count);
|
|
memset (newValue + count, 0, maxCapacity - count);
|
|
free (value);
|
|
value = newValue;
|
|
}
|
|
|
|
void
|
|
StringBuilder::trimToSize ()
|
|
{
|
|
if (count < maxCapacity)
|
|
{
|
|
char *newValue = (char *) malloc (count);
|
|
maxCapacity = count;
|
|
memcpy (newValue, value, count);
|
|
free (value);
|
|
value = newValue;
|
|
}
|
|
}
|
|
|
|
void
|
|
StringBuilder::trim ()
|
|
{
|
|
while (count > 0)
|
|
{
|
|
if (value[count - 1] != ' ')
|
|
break;
|
|
count--;
|
|
}
|
|
}
|
|
|
|
void
|
|
StringBuilder::setLength (int newLength)
|
|
{
|
|
if (newLength < 0)
|
|
return;
|
|
if (newLength > maxCapacity)
|
|
expandCapacity (newLength);
|
|
if (count < newLength)
|
|
{
|
|
for (; count < newLength; count++)
|
|
value[count] = '\0';
|
|
}
|
|
else
|
|
count = newLength;
|
|
}
|
|
|
|
char
|
|
StringBuilder::charAt (int index)
|
|
{
|
|
if (index < 0 || index >= count)
|
|
return 0;
|
|
return value[index];
|
|
}
|
|
|
|
void
|
|
StringBuilder::getChars (int srcBegin, int srcEnd, char dst[], int dstBegin)
|
|
{
|
|
if (srcBegin < 0)
|
|
return;
|
|
if (srcEnd < 0 || srcEnd > count)
|
|
return;
|
|
if (srcBegin > srcEnd)
|
|
return;
|
|
memcpy (dst + dstBegin, value + srcBegin, srcEnd - srcBegin);
|
|
}
|
|
|
|
void
|
|
StringBuilder::setCharAt (int index, char ch)
|
|
{
|
|
if (index < 0 || index >= count)
|
|
return;
|
|
value[index] = ch;
|
|
}
|
|
|
|
StringBuilder *
|
|
StringBuilder::append (StringBuilder *sb)
|
|
{
|
|
if (sb == NULL)
|
|
return append (NTXT ("null"));
|
|
int len = sb->count;
|
|
int newcount = count + len;
|
|
if (newcount > maxCapacity)
|
|
expandCapacity (newcount);
|
|
sb->getChars (0, len, value, count);
|
|
count = newcount;
|
|
return this;
|
|
}
|
|
|
|
StringBuilder *
|
|
StringBuilder::append (const char str[])
|
|
{
|
|
int len = (int) strlen (str);
|
|
int newCount = count + len;
|
|
if (newCount > maxCapacity)
|
|
expandCapacity (newCount);
|
|
memcpy (value + count, str, len);
|
|
count = newCount;
|
|
return this;
|
|
}
|
|
|
|
StringBuilder *
|
|
StringBuilder::append (const char str[], int offset, int len)
|
|
{
|
|
int newCount = count + len;
|
|
if (newCount > maxCapacity)
|
|
expandCapacity (newCount);
|
|
memcpy (value + count, str + offset, len);
|
|
count = newCount;
|
|
return this;
|
|
}
|
|
|
|
StringBuilder *
|
|
StringBuilder::append (bool b)
|
|
{
|
|
if (b)
|
|
append (NTXT ("true"));
|
|
else
|
|
append (NTXT ("false"));
|
|
return this;
|
|
}
|
|
|
|
StringBuilder *
|
|
StringBuilder::append (char c)
|
|
{
|
|
int newCount = count + 1;
|
|
if (newCount > maxCapacity)
|
|
{
|
|
expandCapacity (newCount);
|
|
}
|
|
value[count++] = c;
|
|
return this;
|
|
}
|
|
|
|
StringBuilder *
|
|
StringBuilder::append (int i)
|
|
{
|
|
char buf[16];
|
|
snprintf (buf, sizeof (buf), NTXT ("%d"), i);
|
|
append (buf);
|
|
return this;
|
|
}
|
|
|
|
StringBuilder *
|
|
StringBuilder::append (unsigned int i)
|
|
{
|
|
char buf[16];
|
|
snprintf (buf, sizeof (buf), NTXT ("%u"), i);
|
|
append (buf);
|
|
return this;
|
|
}
|
|
|
|
StringBuilder *
|
|
StringBuilder::append (long lng)
|
|
{
|
|
char buf[32];
|
|
snprintf (buf, sizeof (buf), NTXT ("%ld"), lng);
|
|
append (buf);
|
|
return this;
|
|
}
|
|
|
|
StringBuilder *
|
|
StringBuilder::append (unsigned long lng)
|
|
{
|
|
char buf[32];
|
|
snprintf (buf, sizeof (buf), NTXT ("%lu"), lng);
|
|
append (buf);
|
|
return this;
|
|
}
|
|
|
|
StringBuilder *
|
|
StringBuilder::append (long long lng)
|
|
{
|
|
char buf[32];
|
|
snprintf (buf, sizeof (buf), NTXT ("%lld"), lng);
|
|
append (buf);
|
|
return this;
|
|
}
|
|
|
|
StringBuilder *
|
|
StringBuilder::append (unsigned long long lng)
|
|
{
|
|
char buf[32];
|
|
snprintf (buf, sizeof (buf), NTXT ("%llu"), lng);
|
|
append (buf);
|
|
return this;
|
|
}
|
|
|
|
StringBuilder *
|
|
StringBuilder::append (float f)
|
|
{
|
|
char buf[32];
|
|
snprintf (buf, sizeof (buf), NTXT ("%f"), (double) f);
|
|
append (buf);
|
|
return this;
|
|
}
|
|
|
|
StringBuilder *
|
|
StringBuilder::append (double d)
|
|
{
|
|
char buf[32];
|
|
snprintf (buf, sizeof (buf), NTXT ("%f"), d);
|
|
append (buf);
|
|
return this;
|
|
}
|
|
|
|
StringBuilder *
|
|
StringBuilder::_delete (int start, int end)
|
|
{
|
|
if (start < 0)
|
|
return this;
|
|
if (end > count)
|
|
end = count;
|
|
if (start > end)
|
|
return this;
|
|
int len = end - start;
|
|
if (len > 0)
|
|
{
|
|
memcpy (value + start, value + start + len, count - end);
|
|
count -= len;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
StringBuilder *
|
|
StringBuilder::deleteCharAt (int index)
|
|
{
|
|
if (index < 0 || index >= count)
|
|
return this;
|
|
memcpy (value + index, value + index + 1, count - index - 1);
|
|
count--;
|
|
return this;
|
|
}
|
|
|
|
bool
|
|
StringBuilder::endsWith (const char str[])
|
|
{
|
|
if (str == NULL)
|
|
{
|
|
if (count == 0)
|
|
return true;
|
|
return false;
|
|
}
|
|
int len = (int) strlen (str);
|
|
if (len == 0)
|
|
return true;
|
|
int start = count - len;
|
|
if (start < 0)
|
|
return false;
|
|
int res = strncmp ((const char *) (value + start), str, len);
|
|
if (res != 0)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
StringBuilder *
|
|
StringBuilder::insert (int index, const char str[], int offset, int len)
|
|
{
|
|
if (index < 0 || index > count)
|
|
return this;
|
|
if (offset < 0 || len < 0 || offset > ((int) strlen (str)) - len)
|
|
return this;
|
|
int newCount = count + len;
|
|
if (newCount > maxCapacity)
|
|
expandCapacity (newCount);
|
|
memcpy (value + index + len, value + index, count - index);
|
|
memcpy (value + index, str + offset, len);
|
|
count = newCount;
|
|
return this;
|
|
}
|
|
|
|
StringBuilder *
|
|
StringBuilder::insert (int offset, const char str[])
|
|
{
|
|
if (offset < 0 || offset > count)
|
|
return this;
|
|
int len = (int) strlen (str);
|
|
int newCount = count + len;
|
|
if (newCount > maxCapacity)
|
|
expandCapacity (newCount);
|
|
memcpy (value + offset + len, value + offset, count - offset);
|
|
memcpy (value + offset, str, len);
|
|
count = newCount;
|
|
return this;
|
|
}
|
|
|
|
StringBuilder *
|
|
StringBuilder::insert (int offset, bool b)
|
|
{
|
|
return insert (offset, b ? NTXT ("true") : NTXT ("false"));
|
|
}
|
|
|
|
StringBuilder *
|
|
StringBuilder::insert (int offset, char c)
|
|
{
|
|
int newCount = count + 1;
|
|
if (newCount > maxCapacity)
|
|
expandCapacity (newCount);
|
|
memcpy (value + offset + 1, value + offset, count - offset);
|
|
value[offset] = c;
|
|
count = newCount;
|
|
return this;
|
|
}
|
|
|
|
StringBuilder *
|
|
StringBuilder::insert (int offset, int i)
|
|
{
|
|
char buf[16];
|
|
snprintf (buf, sizeof (buf), NTXT ("%d"), i);
|
|
insert (offset, buf);
|
|
return this;
|
|
}
|
|
|
|
StringBuilder *
|
|
StringBuilder::insert (int offset, long l)
|
|
{
|
|
char buf[32];
|
|
snprintf (buf, sizeof (buf), NTXT ("%ld"), l);
|
|
insert (offset, buf);
|
|
return this;
|
|
}
|
|
|
|
StringBuilder *
|
|
StringBuilder::insert (int offset, float f)
|
|
{
|
|
char buf[32];
|
|
snprintf (buf, sizeof (buf), NTXT ("%f"), (double) f);
|
|
insert (offset, buf);
|
|
return this;
|
|
}
|
|
|
|
StringBuilder *
|
|
StringBuilder::insert (int offset, double d)
|
|
{
|
|
char buf[32];
|
|
snprintf (buf, sizeof (buf), NTXT ("%f"), d);
|
|
insert (offset, buf);
|
|
return this;
|
|
}
|
|
|
|
StringBuilder *
|
|
StringBuilder::reverse ()
|
|
{
|
|
int n = count - 1;
|
|
for (int j = (n - 1) >> 1; j >= 0; --j)
|
|
{
|
|
char temp = value[j];
|
|
char temp2 = value[n - j];
|
|
value[j] = temp2;
|
|
value[n - j] = temp;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
//String *StringBuilder::toString();
|
|
char *
|
|
StringBuilder::toString ()
|
|
{
|
|
char *str = (char *) malloc (count + 1);
|
|
memcpy (str, value, count);
|
|
str[count] = '\0';
|
|
return str;
|
|
}
|
|
|
|
void
|
|
StringBuilder::toFile (FILE *fp)
|
|
{
|
|
append ('\0');
|
|
count--;
|
|
fprintf (fp, NTXT ("%s"), value);
|
|
}
|
|
|
|
void
|
|
StringBuilder::toFileLn (FILE *fp)
|
|
{
|
|
trim ();
|
|
append ('\0');
|
|
count--;
|
|
fprintf (fp, NTXT ("%s\n"), value);
|
|
}
|
|
|
|
StringBuilder *
|
|
StringBuilder::sprintf (const char *fmt, ...)
|
|
{
|
|
int cnt;
|
|
setLength (0);
|
|
|
|
va_list vp;
|
|
va_start (vp, fmt);
|
|
cnt = vsnprintf (value, maxCapacity, fmt, vp);
|
|
va_end (vp);
|
|
if (cnt < maxCapacity)
|
|
{
|
|
count = cnt;
|
|
return this;
|
|
}
|
|
|
|
// Have to count the trailing zero
|
|
ensureCapacity (cnt + 1);
|
|
va_start (vp, fmt);
|
|
count = vsnprintf (value, maxCapacity, fmt, vp);
|
|
va_end (vp);
|
|
return this;
|
|
}
|
|
|
|
StringBuilder *
|
|
StringBuilder::appendf (const char *fmt, ...)
|
|
{
|
|
va_list vp;
|
|
va_start (vp, fmt);
|
|
int cnt = vsnprintf (value + count, maxCapacity - count, fmt, vp);
|
|
va_end (vp);
|
|
if (cnt + count < maxCapacity)
|
|
{
|
|
count += cnt;
|
|
return this;
|
|
}
|
|
|
|
// Have to count the trailing zero
|
|
ensureCapacity (count + cnt + 1);
|
|
va_start (vp, fmt);
|
|
count += vsnprintf (value + count, maxCapacity - count, fmt, vp);
|
|
va_end (vp);
|
|
return this;
|
|
}
|
|
|
|
int
|
|
StringBuilder::indexOf (const char str[])
|
|
{
|
|
return indexOf (str, 0);
|
|
}
|
|
|
|
int
|
|
StringBuilder::indexOf (const char str[], int fromIndex)
|
|
{
|
|
int len = (int) strlen (str);
|
|
if (fromIndex >= count)
|
|
return len == 0 ? count : -1;
|
|
if (fromIndex < 0)
|
|
fromIndex = 0;
|
|
if (len == 0)
|
|
return fromIndex;
|
|
|
|
char first = str[0];
|
|
int max = (count - len);
|
|
|
|
for (int i = fromIndex; i <= max; i++)
|
|
{
|
|
/* Look for first character. */
|
|
if (value[i] != first)
|
|
while (++i <= max && value[i] != first)
|
|
;
|
|
/* Found first character, now look at the rest of v2 */
|
|
if (i <= max)
|
|
{
|
|
int j = i + 1;
|
|
int end = j + len - 1;
|
|
for (int k = 1; j < end && value[j] == str[k]; j++, k++)
|
|
;
|
|
if (j == end) /* Found whole string. */
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int
|
|
StringBuilder::lastIndexOf (const char str[])
|
|
{
|
|
return lastIndexOf (str, count);
|
|
}
|
|
|
|
int
|
|
StringBuilder::lastIndexOf (const char str[], int fromIndex)
|
|
{
|
|
/*
|
|
* Check arguments; return immediately where possible. For
|
|
* consistency, don't check for null str.
|
|
*/
|
|
int len = (int) strlen (str);
|
|
int rightIndex = count - len;
|
|
if (fromIndex < 0)
|
|
return -1;
|
|
if (fromIndex > rightIndex)
|
|
fromIndex = rightIndex;
|
|
/* Empty string always matches. */
|
|
if (len == 0)
|
|
return fromIndex;
|
|
|
|
int strLastIndex = len - 1;
|
|
char strLastChar = str[strLastIndex];
|
|
int min = len - 1;
|
|
int i = min + fromIndex;
|
|
|
|
while (true)
|
|
{
|
|
while (i >= min && value[i] != strLastChar)
|
|
i--;
|
|
if (i < min)
|
|
return -1;
|
|
|
|
int j = i - 1;
|
|
int start = j - (len - 1);
|
|
int k = strLastIndex - 1;
|
|
while (j > start)
|
|
{
|
|
if (value[j--] != str[k--])
|
|
{
|
|
i--;
|
|
break;
|
|
}
|
|
}
|
|
if (j == start)
|
|
return start + 1;
|
|
}
|
|
}
|
|
|