wstring.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /****************************************************************************\
  19. * 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 *
  20. ******************************************************************************
  21. Project Name: Carpenter (The RedAlert ladder creator)
  22. File Name : string.cpp
  23. Author : Neal Kettler
  24. Start Date : June 1, 1997
  25. Last Update : June 17, 1997
  26. A fairly typical string class. This string class always copies any input
  27. string to it's own memory (for assignment or construction).
  28. \***************************************************************************/
  29. #include <ctype.h>
  30. #include <stdlib.h>
  31. #include <stdio.h>
  32. #include <string.h>
  33. #include <stdarg.h>
  34. #include "wstring.h"
  35. #define PADSIZE 32 // include a little padding on alloc for future growth
  36. Wstring::Wstring() : str(NULL), strsize(0)
  37. { }
  38. Wstring::Wstring(IN char *string):str(NULL), strsize(0)
  39. { set(string); }
  40. Wstring::Wstring(IN Wstring &other):str(NULL), strsize(0)
  41. {
  42. if (other.str!=NULL)
  43. {
  44. str=new char[strlen(other.str)+PADSIZE+1];
  45. strsize=strlen(other.str)+PADSIZE+1;
  46. strcpy(str,other.str);
  47. }
  48. }
  49. Wstring::~Wstring()
  50. {
  51. clear();
  52. }
  53. bool Wstring::operator<(IN Wstring &other) RO
  54. {
  55. if (str == NULL && other.str == NULL)
  56. return false;
  57. if (str == NULL)
  58. return true;
  59. return ( strcmp(str, other.str) < 0 );
  60. }
  61. bit8 Wstring::operator==(IN char *other) RO
  62. {
  63. if ((str==NULL)&&(other==NULL))
  64. return(TRUE);
  65. if(strcmp(str, other) != 0)
  66. return(FALSE);
  67. else
  68. return(TRUE);
  69. }
  70. bit8 Wstring::operator==(IN Wstring &other) RO
  71. {
  72. if((str == NULL) && (other.str == NULL))
  73. return(TRUE);
  74. if((str == NULL) || (other.str == NULL))
  75. return(FALSE);
  76. if(strcmp(str, other.str) != 0)
  77. return(FALSE);
  78. else
  79. return(TRUE);
  80. }
  81. bit8 Wstring::operator!=(IN char *other) RO
  82. {
  83. if(strcmp(str, other) != 0)
  84. return(TRUE);
  85. else
  86. return(FALSE);
  87. }
  88. bit8 Wstring::operator!=(IN Wstring &other) RO
  89. {
  90. if((str == NULL) && (other.str == NULL))
  91. return(FALSE);
  92. if((str == NULL) || (other.str == NULL))
  93. return(TRUE);
  94. if(strcmp(str, other.str) != 0)
  95. return(TRUE);
  96. else
  97. return(FALSE);
  98. }
  99. Wstring &Wstring::operator=(IN char *other)
  100. {
  101. set(other);
  102. return(*this);
  103. }
  104. Wstring &Wstring::operator=(IN Wstring &other)
  105. {
  106. if(*this == other)
  107. return(*this);
  108. set(other.get());
  109. return(*this);
  110. }
  111. bit8 Wstring::cat(IN char *s)
  112. {
  113. uint32 len;
  114. if (s==NULL) // it's OK to cat nothing
  115. return(TRUE);
  116. // Determine the length of the resultant string.
  117. len = strlen(s) + 1;
  118. if(str)
  119. len += strlen(str);
  120. // Space check
  121. strgrow(len);
  122. strcat(str, s);
  123. return(TRUE);
  124. }
  125. bit8 Wstring::cat(uint32 size, IN char *s)
  126. {
  127. uint32 len;
  128. // Determine the length of the resultant string.
  129. len = size + 1;
  130. if(str)
  131. len += strlen(str);
  132. // Allocate memory for the new string.
  133. strgrow(len);
  134. strncat(str, s, size);
  135. str[len-1]=0; // make sure null term'd
  136. return(TRUE);
  137. }
  138. bit8 Wstring::cat(IN Wstring &other)
  139. {
  140. return cat(other.get());
  141. }
  142. Wstring &Wstring::operator+=(IN char *string)
  143. {
  144. cat(string);
  145. return(*this);
  146. }
  147. Wstring &Wstring::operator+=(IN Wstring &other)
  148. {
  149. cat(other.get());
  150. return(*this);
  151. }
  152. Wstring Wstring::operator+(IN char *string)
  153. {
  154. Wstring temp = *this;
  155. temp.cat(string);
  156. return(temp);
  157. }
  158. Wstring Wstring::operator+(IN Wstring &s)
  159. {
  160. Wstring temp = *this;
  161. temp.cat(s);
  162. return(temp);
  163. }
  164. //
  165. // This function deletes 'count' characters indexed by `pos' from the Wstring.
  166. // If `pos'+'count' is > the length of the array, the last 'count' characters
  167. // of the string are removed. If an error occurs, FALSE is returned.
  168. // Otherwise, TRUE is returned. Note: count has a default value of 1.
  169. //
  170. //
  171. char Wstring::remove(sint32 pos,sint32 count)
  172. {
  173. //char *s;
  174. sint32 len;
  175. len = (sint32)strlen(str);
  176. if(pos+count > len)
  177. pos = len - count;
  178. if (pos < 0)
  179. {
  180. count+=pos; // If they remove before 0, ignore up till beginning
  181. pos=0;
  182. }
  183. if (count<=0)
  184. return(FALSE);
  185. memmove(str+pos,str+pos+count,len-pos-count+1);
  186. return(TRUE);
  187. }
  188. // Remove all instances of a char from the string
  189. bit8 Wstring::removeChar(char c)
  190. {
  191. int len=0;
  192. char *cptr=NULL;
  193. bit8 removed=FALSE;
  194. if (str==NULL)
  195. return(FALSE);
  196. len=strlen(str);
  197. while ((cptr=strchr(str,c)) !=NULL)
  198. {
  199. memmove(cptr,cptr+1,len-1-((int)(cptr-str)));
  200. len--;
  201. str[len]=0;
  202. removed=TRUE;
  203. }
  204. return(removed);
  205. }
  206. void Wstring::removeSpaces(void)
  207. {
  208. removeChar(' ');
  209. removeChar('\t');
  210. }
  211. void Wstring::clear(void)
  212. {
  213. if(str)
  214. delete[](str);
  215. strsize=0;
  216. str=NULL;
  217. }
  218. // This is usually used for raw storage instead of string ops...
  219. void Wstring::setSize(sint32 size)
  220. {
  221. clear();
  222. if (size<0)
  223. return;
  224. str=new char[size];
  225. strsize=size;
  226. memset(str,0,size);
  227. }
  228. void Wstring::cellCopy(char *dest, uint32 len)
  229. {
  230. uint32 i;
  231. strncpy(dest, str, len);
  232. for(i = (uint32)strlen(str); i < len; i++)
  233. dest[i] = ' ';
  234. dest[len] = 0;
  235. }
  236. char *Wstring::get(void) RO
  237. {
  238. if(!str)
  239. return "";
  240. return str;
  241. }
  242. char Wstring::get(uint32 index) RO
  243. {
  244. if(index < strlen(str))
  245. return str[index];
  246. return(0);
  247. }
  248. uint32 Wstring::length(void) RO
  249. {
  250. if(str == NULL)
  251. return(0);
  252. return((uint32)strlen(str));
  253. }
  254. // Insert at given position and shift old stuff to right
  255. bit8 Wstring::insert(char *instring, uint32 pos)
  256. {
  257. if (str==NULL)
  258. return(set(instring));
  259. if (pos>strlen(str))
  260. pos=strlen(str);
  261. strgrow(strlen(str)+strlen(instring)+1);
  262. memmove(str+pos+strlen(instring),str+pos,strlen(str)-pos+1);
  263. memmove(str+pos,instring,strlen(instring));
  264. return(TRUE);
  265. }
  266. // This function inserts the character specified by `k' into the string at the
  267. // position indexed by `pos'. If `pos' is >= the length of the string, it is
  268. // appended to the string. If an error occurs, FALSE is returned. Otherwise,
  269. // TRUE is returned.
  270. bit8 Wstring::insert(char k, uint32 pos)
  271. {
  272. char temp[2];
  273. temp[0]=k;
  274. temp[1]=0;
  275. return(insert(temp,pos));
  276. }
  277. // Joe Howes (05/19/2000): This function inserts commas to nicely format a
  278. // large number (i.e. 1234567890 -> 1,234,567,890). It doesn't really care
  279. // if the string is really a number or not.
  280. bit8 Wstring::beautifyNumber()
  281. {
  282. int len = length();
  283. int accum = 3 - (len % 3);
  284. int numcommas = 0;
  285. if( accum == 3 ) accum = -1;
  286. for(int i = 0; i < len; i++)
  287. {
  288. if( accum == 3 )
  289. {
  290. insert(',', i + numcommas);
  291. numcommas++;
  292. }
  293. accum = ( accum == 3 || accum == -1 ) ? 1 : accum + 1;
  294. }
  295. return(TRUE);
  296. }
  297. // This function replaces any occurences of the string pointed to by
  298. // `replaceThis' with the string pointed to by `withThis'. If an error
  299. // occurs, FALSE is returned. Otherwise, TRUE is returned.
  300. bit8 Wstring::replace(IN char *replaceThis,IN char *withThis)
  301. {
  302. Wstring dest;
  303. char *foundStr, *src;
  304. uint32 len;
  305. src=get();
  306. while(src && src[0])
  307. {
  308. foundStr = strstr(src, replaceThis);
  309. if(foundStr)
  310. {
  311. len = (uint32)foundStr - (uint32)src;
  312. if(len)
  313. {
  314. if(!dest.cat(len, src))
  315. return(FALSE);
  316. }
  317. if(!dest.cat(withThis))
  318. return(FALSE);
  319. src = foundStr + strlen(replaceThis);
  320. }
  321. else
  322. {
  323. if(!dest.cat(src))
  324. return(FALSE);
  325. src=NULL;
  326. }
  327. }
  328. return(set(dest.get()));
  329. }
  330. bit8 Wstring::set(IN char *s)
  331. {
  332. //uint32 len;
  333. strgrow(strlen(s)+1);
  334. strcpy(str,s);
  335. return(TRUE);
  336. }
  337. bit8 Wstring::set(char c, uint32 index)
  338. {
  339. if(index >= (uint32)strlen(str))
  340. return FALSE;
  341. str[index] = c;
  342. return TRUE;
  343. }
  344. char Wstring::set(uint32 size, IN char *string)
  345. {
  346. //uint32 len;
  347. strgrow(size+1);
  348. strncpy(str,string,size);
  349. str[size]=0;
  350. return(TRUE);
  351. }
  352. // Added by Joe Howes. Takes a printf formatted string and a set of args.
  353. // The expanded string must not exceed 1k or twice the length of the format
  354. // string, whichever is larger. It would probably be better to traverse
  355. // the format string and properly calculate, the length so this will
  356. // work in all cases, but this should be good enough for 99% of Wstring usage.
  357. char Wstring::setFormatted(IN char *msg, ...)
  358. {
  359. if( msg == NULL || strlen(msg) <= 0 ) return FALSE;
  360. char* string;
  361. va_list args;
  362. int len = (strlen(msg) < 1024) ? 1024 : (strlen(msg)*2);
  363. string = new char[len];
  364. va_start(args, msg);
  365. vsprintf(string, msg, args);
  366. va_end(args);
  367. set(string);
  368. delete[] string;
  369. return(TRUE);
  370. }
  371. // This function converts all alphabetical characters in the string to lower
  372. // case.
  373. void Wstring::toLower(void)
  374. {
  375. uint32 i;
  376. int strlength=length();
  377. for(i = 0; i < (uint32)strlength; i++)
  378. {
  379. if((str[i] >= 'A') && (str[i] <= 'Z'))
  380. str[i] = (sint8)tolower(str[i]);
  381. }
  382. }
  383. // This function converts all alphabetical characters in the string to upper
  384. // case.
  385. void Wstring::toUpper(void)
  386. {
  387. uint32 i;
  388. int strlength=length();
  389. for(i = 0; i < (uint32)strlength; i++)
  390. {
  391. if((str[i] >= 'a') && (str[i] <= 'z'))
  392. str[i] = (sint8)toupper(str[i]);
  393. }
  394. }
  395. // This function truncates the string so its length will match the specified
  396. // `len'. If an error occurs, FALSE is returned. Otherwise, TRUE is returned.
  397. bit8 Wstring::truncate(uint32 len)
  398. {
  399. strgrow(len+1);
  400. str[len]=0;
  401. return(TRUE);
  402. }
  403. // Truncate the string after the character 'c' (gets rid of 'c' as well)
  404. // Do nothing if 'c' isn't in the string
  405. bit8 Wstring::truncate(char c)
  406. {
  407. sint32 len;
  408. if (str==NULL)
  409. return(FALSE);
  410. char *cptr=strchr(str,c);
  411. if (cptr==NULL)
  412. return(FALSE);
  413. len=(sint32)(cptr-str);
  414. truncate((uint32)len);
  415. return(TRUE);
  416. }
  417. // Get a token from this string that's seperated by one or more
  418. // chars from the 'delim' string , start at offset & return offset
  419. sint32 Wstring::getToken(int offset,char *delim,Wstring &out) RO
  420. {
  421. int i;
  422. sint32 start;
  423. sint32 stop;
  424. if (offset<0) // check for bad input
  425. return(-1);
  426. for (i=offset; i<(int)length(); i++) {
  427. if(strchr(delim,str[i])==NULL)
  428. break;
  429. }
  430. if (i>=(int)length())
  431. return(-1);
  432. start=i;
  433. for (; i<(int)length(); i++) {
  434. if(strchr(delim,str[i])!=NULL)
  435. break;
  436. }
  437. stop=i-1;
  438. out.set(str+start);
  439. out.truncate((uint32)stop-start+1);
  440. return(stop+1);
  441. }
  442. // Get the first line of text after offset. Lines are terminated by '\r\n' or '\n'
  443. sint32 Wstring::getLine(int offset, Wstring &out)
  444. {
  445. int i;
  446. sint32 start;
  447. sint32 stop;
  448. start=i=offset;
  449. if (start >= (sint32)length())
  450. return(-1);
  451. for (; i<(int)length(); i++) {
  452. if(strchr("\r\n",str[i])!=NULL)
  453. break;
  454. }
  455. stop=i;
  456. if ((str[stop]=='\r')&&(str[stop+1]=='\n'))
  457. stop++;
  458. out.set(str+start);
  459. out.truncate((uint32)stop-start+1);
  460. return(stop+1);
  461. }
  462. //
  463. // Make sure there's AT LEAST length bytes in this string object
  464. //
  465. void Wstring::strgrow(int length)
  466. {
  467. if (str==NULL)
  468. {
  469. str=new char[length+PADSIZE];
  470. str[0]=0;
  471. strsize=length+PADSIZE;
  472. return;
  473. }
  474. else if (strsize >= length) // no need to alloc more data
  475. return;
  476. else // bah, gotta grow...
  477. {
  478. char *newstr=new char[length+PADSIZE];
  479. strsize=length+PADSIZE;
  480. strcpy(newstr,str);
  481. delete[](str);
  482. str=newstr;
  483. return;
  484. }
  485. }