|  | /* Copyright (C) 2021-2025 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 <unistd.h> | 
|  |  | 
|  | #include "libiberty.h" | 
|  | #include "gp-defs.h" | 
|  | #include "StringBuilder.h" | 
|  | #include "i18n.h" | 
|  |  | 
|  | StringBuilder::StringBuilder () | 
|  | { | 
|  | count = 0; | 
|  | maxCapacity = 16; | 
|  | value = (char *) xmalloc (maxCapacity); | 
|  | memset (value, 0, maxCapacity); | 
|  | } | 
|  |  | 
|  | StringBuilder::StringBuilder (int capacity) | 
|  | { | 
|  | count = 0; | 
|  | maxCapacity = capacity; | 
|  | value = (char *) xmalloc (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 *) xmalloc (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 *) xmalloc (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 *) xmalloc (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); | 
|  | } | 
|  |  | 
|  | void | 
|  | StringBuilder::write (int fd) | 
|  | { | 
|  | if (count > 0) | 
|  | ::write (fd, value, count); | 
|  | } | 
|  |  | 
|  | 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; | 
|  | } | 
|  | } | 
|  |  |