/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** 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 of the License, 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, see .
*/
/****************************************************************************\
* C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *
******************************************************************************
Project Name: Carpenter (The RedAlert ladder creator)
File Name : string.cpp
Author : Neal Kettler
Start Date : June 1, 1997
Last Update : June 17, 1997
A fairly typical string class. This string class always copies any input
string to it's own memory (for assignment or construction).
\***************************************************************************/
#include
#include
#include
#include
#include
#include "wstring.h"
#define PADSIZE 32 // include a little padding on alloc for future growth
Wstring::Wstring() : str(NULL), strsize(0)
{ }
Wstring::Wstring(IN char *string):str(NULL), strsize(0)
{ set(string); }
Wstring::Wstring(IN Wstring &other):str(NULL), strsize(0)
{
if (other.str!=NULL)
{
str=new char[strlen(other.str)+PADSIZE+1];
strsize=strlen(other.str)+PADSIZE+1;
strcpy(str,other.str);
}
}
Wstring::~Wstring()
{
clear();
}
bool Wstring::operator<(IN Wstring &other) RO
{
if (str == NULL && other.str == NULL)
return false;
if (str == NULL)
return true;
return ( strcmp(str, other.str) < 0 );
}
bit8 Wstring::operator==(IN char *other) RO
{
if ((str==NULL)&&(other==NULL))
return(TRUE);
if(strcmp(str, other) != 0)
return(FALSE);
else
return(TRUE);
}
bit8 Wstring::operator==(IN Wstring &other) RO
{
if((str == NULL) && (other.str == NULL))
return(TRUE);
if((str == NULL) || (other.str == NULL))
return(FALSE);
if(strcmp(str, other.str) != 0)
return(FALSE);
else
return(TRUE);
}
bit8 Wstring::operator!=(IN char *other) RO
{
if(strcmp(str, other) != 0)
return(TRUE);
else
return(FALSE);
}
bit8 Wstring::operator!=(IN Wstring &other) RO
{
if((str == NULL) && (other.str == NULL))
return(FALSE);
if((str == NULL) || (other.str == NULL))
return(TRUE);
if(strcmp(str, other.str) != 0)
return(TRUE);
else
return(FALSE);
}
Wstring &Wstring::operator=(IN char *other)
{
set(other);
return(*this);
}
Wstring &Wstring::operator=(IN Wstring &other)
{
if(*this == other)
return(*this);
set(other.get());
return(*this);
}
bit8 Wstring::cat(IN char *s)
{
uint32 len;
if (s==NULL) // it's OK to cat nothing
return(TRUE);
// Determine the length of the resultant string.
len = strlen(s) + 1;
if(str)
len += strlen(str);
// Space check
strgrow(len);
strcat(str, s);
return(TRUE);
}
bit8 Wstring::cat(uint32 size, IN char *s)
{
uint32 len;
// Determine the length of the resultant string.
len = size + 1;
if(str)
len += strlen(str);
// Allocate memory for the new string.
strgrow(len);
strncat(str, s, size);
str[len-1]=0; // make sure null term'd
return(TRUE);
}
bit8 Wstring::cat(IN Wstring &other)
{
return cat(other.get());
}
Wstring &Wstring::operator+=(IN char *string)
{
cat(string);
return(*this);
}
Wstring &Wstring::operator+=(IN Wstring &other)
{
cat(other.get());
return(*this);
}
Wstring Wstring::operator+(IN char *string)
{
Wstring temp = *this;
temp.cat(string);
return(temp);
}
Wstring Wstring::operator+(IN Wstring &s)
{
Wstring temp = *this;
temp.cat(s);
return(temp);
}
//
// This function deletes 'count' characters indexed by `pos' from the Wstring.
// If `pos'+'count' is > the length of the array, the last 'count' characters
// of the string are removed. If an error occurs, FALSE is returned.
// Otherwise, TRUE is returned. Note: count has a default value of 1.
//
//
char Wstring::remove(sint32 pos,sint32 count)
{
//char *s;
sint32 len;
len = (sint32)strlen(str);
if(pos+count > len)
pos = len - count;
if (pos < 0)
{
count+=pos; // If they remove before 0, ignore up till beginning
pos=0;
}
if (count<=0)
return(FALSE);
memmove(str+pos,str+pos+count,len-pos-count+1);
return(TRUE);
}
// Remove all instances of a char from the string
bit8 Wstring::removeChar(char c)
{
int len=0;
char *cptr=NULL;
bit8 removed=FALSE;
if (str==NULL)
return(FALSE);
len=strlen(str);
while ((cptr=strchr(str,c)) !=NULL)
{
memmove(cptr,cptr+1,len-1-((int)(cptr-str)));
len--;
str[len]=0;
removed=TRUE;
}
return(removed);
}
void Wstring::removeSpaces(void)
{
removeChar(' ');
removeChar('\t');
}
void Wstring::clear(void)
{
if(str)
delete[](str);
strsize=0;
str=NULL;
}
// This is usually used for raw storage instead of string ops...
void Wstring::setSize(sint32 size)
{
clear();
if (size<0)
return;
str=new char[size];
strsize=size;
memset(str,0,size);
}
void Wstring::cellCopy(char *dest, uint32 len)
{
uint32 i;
strncpy(dest, str, len);
for(i = (uint32)strlen(str); i < len; i++)
dest[i] = ' ';
dest[len] = 0;
}
char *Wstring::get(void) RO
{
if(!str)
return "";
return str;
}
char Wstring::get(uint32 index) RO
{
if(index < strlen(str))
return str[index];
return(0);
}
uint32 Wstring::length(void) RO
{
if(str == NULL)
return(0);
return((uint32)strlen(str));
}
// Insert at given position and shift old stuff to right
bit8 Wstring::insert(char *instring, uint32 pos)
{
if (str==NULL)
return(set(instring));
if (pos>strlen(str))
pos=strlen(str);
strgrow(strlen(str)+strlen(instring)+1);
memmove(str+pos+strlen(instring),str+pos,strlen(str)-pos+1);
memmove(str+pos,instring,strlen(instring));
return(TRUE);
}
// This function inserts the character specified by `k' into the string at the
// position indexed by `pos'. If `pos' is >= the length of the string, it is
// appended to the string. If an error occurs, FALSE is returned. Otherwise,
// TRUE is returned.
bit8 Wstring::insert(char k, uint32 pos)
{
char temp[2];
temp[0]=k;
temp[1]=0;
return(insert(temp,pos));
}
// Joe Howes (05/19/2000): This function inserts commas to nicely format a
// large number (i.e. 1234567890 -> 1,234,567,890). It doesn't really care
// if the string is really a number or not.
bit8 Wstring::beautifyNumber()
{
int len = length();
int accum = 3 - (len % 3);
int numcommas = 0;
if( accum == 3 ) accum = -1;
for(int i = 0; i < len; i++)
{
if( accum == 3 )
{
insert(',', i + numcommas);
numcommas++;
}
accum = ( accum == 3 || accum == -1 ) ? 1 : accum + 1;
}
return(TRUE);
}
// This function replaces any occurences of the string pointed to by
// `replaceThis' with the string pointed to by `withThis'. If an error
// occurs, FALSE is returned. Otherwise, TRUE is returned.
bit8 Wstring::replace(IN char *replaceThis,IN char *withThis)
{
Wstring dest;
char *foundStr, *src;
uint32 len;
src=get();
while(src && src[0])
{
foundStr = strstr(src, replaceThis);
if(foundStr)
{
len = (uint32)foundStr - (uint32)src;
if(len)
{
if(!dest.cat(len, src))
return(FALSE);
}
if(!dest.cat(withThis))
return(FALSE);
src = foundStr + strlen(replaceThis);
}
else
{
if(!dest.cat(src))
return(FALSE);
src=NULL;
}
}
return(set(dest.get()));
}
bit8 Wstring::set(IN char *s)
{
//uint32 len;
strgrow(strlen(s)+1);
strcpy(str,s);
return(TRUE);
}
bit8 Wstring::set(char c, uint32 index)
{
if(index >= (uint32)strlen(str))
return FALSE;
str[index] = c;
return TRUE;
}
char Wstring::set(uint32 size, IN char *string)
{
//uint32 len;
strgrow(size+1);
strncpy(str,string,size);
str[size]=0;
return(TRUE);
}
// Added by Joe Howes. Takes a printf formatted string and a set of args.
// The expanded string must not exceed 1k or twice the length of the format
// string, whichever is larger. It would probably be better to traverse
// the format string and properly calculate, the length so this will
// work in all cases, but this should be good enough for 99% of Wstring usage.
char Wstring::setFormatted(IN char *msg, ...)
{
if( msg == NULL || strlen(msg) <= 0 ) return FALSE;
char* string;
va_list args;
int len = (strlen(msg) < 1024) ? 1024 : (strlen(msg)*2);
string = new char[len];
va_start(args, msg);
vsprintf(string, msg, args);
va_end(args);
set(string);
delete[] string;
return(TRUE);
}
// This function converts all alphabetical characters in the string to lower
// case.
void Wstring::toLower(void)
{
uint32 i;
int strlength=length();
for(i = 0; i < (uint32)strlength; i++)
{
if((str[i] >= 'A') && (str[i] <= 'Z'))
str[i] = (sint8)tolower(str[i]);
}
}
// This function converts all alphabetical characters in the string to upper
// case.
void Wstring::toUpper(void)
{
uint32 i;
int strlength=length();
for(i = 0; i < (uint32)strlength; i++)
{
if((str[i] >= 'a') && (str[i] <= 'z'))
str[i] = (sint8)toupper(str[i]);
}
}
// This function truncates the string so its length will match the specified
// `len'. If an error occurs, FALSE is returned. Otherwise, TRUE is returned.
bit8 Wstring::truncate(uint32 len)
{
strgrow(len+1);
str[len]=0;
return(TRUE);
}
// Truncate the string after the character 'c' (gets rid of 'c' as well)
// Do nothing if 'c' isn't in the string
bit8 Wstring::truncate(char c)
{
sint32 len;
if (str==NULL)
return(FALSE);
char *cptr=strchr(str,c);
if (cptr==NULL)
return(FALSE);
len=(sint32)(cptr-str);
truncate((uint32)len);
return(TRUE);
}
// Get a token from this string that's seperated by one or more
// chars from the 'delim' string , start at offset & return offset
sint32 Wstring::getToken(int offset,char *delim,Wstring &out) RO
{
int i;
sint32 start;
sint32 stop;
if (offset<0) // check for bad input
return(-1);
for (i=offset; i<(int)length(); i++) {
if(strchr(delim,str[i])==NULL)
break;
}
if (i>=(int)length())
return(-1);
start=i;
for (; i<(int)length(); i++) {
if(strchr(delim,str[i])!=NULL)
break;
}
stop=i-1;
out.set(str+start);
out.truncate((uint32)stop-start+1);
return(stop+1);
}
// Get the first line of text after offset. Lines are terminated by '\r\n' or '\n'
sint32 Wstring::getLine(int offset, Wstring &out)
{
int i;
sint32 start;
sint32 stop;
start=i=offset;
if (start >= (sint32)length())
return(-1);
for (; i<(int)length(); i++) {
if(strchr("\r\n",str[i])!=NULL)
break;
}
stop=i;
if ((str[stop]=='\r')&&(str[stop+1]=='\n'))
stop++;
out.set(str+start);
out.truncate((uint32)stop-start+1);
return(stop+1);
}
//
// Make sure there's AT LEAST length bytes in this string object
//
void Wstring::strgrow(int length)
{
if (str==NULL)
{
str=new char[length+PADSIZE];
str[0]=0;
strsize=length+PADSIZE;
return;
}
else if (strsize >= length) // no need to alloc more data
return;
else // bah, gotta grow...
{
char *newstr=new char[length+PADSIZE];
strsize=length+PADSIZE;
strcpy(newstr,str);
delete[](str);
str=newstr;
return;
}
}