util_str.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621
  1. /*
  2. ===========================================================================
  3. Copyright (C) 1999-2005 Id Software, Inc.
  4. This file is part of Quake III Arena source code.
  5. Quake III Arena source code is free software; you can redistribute it
  6. and/or modify it under the terms of the GNU General Public License as
  7. published by the Free Software Foundation; either version 2 of the License,
  8. or (at your option) any later version.
  9. Quake III Arena source code is distributed in the hope that it will be
  10. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with Foobar; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. ===========================================================================
  17. */
  18. //need to rewrite this
  19. #include "util_str.h"
  20. #include <stdlib.h>
  21. #include <ctype.h>
  22. #include <stdio.h>
  23. #include <stdarg.h>
  24. #ifdef _WIN32
  25. #pragma warning(disable : 4244) // 'conversion' conversion from 'type1' to 'type2', possible loss of data
  26. #pragma warning(disable : 4710) // function 'blah' not inlined
  27. #endif
  28. static const int STR_ALLOC_GRAN = 20;
  29. char *idStr::toLower
  30. (
  31. char *s1
  32. )
  33. {
  34. char *s;
  35. s = s1;
  36. while( *s )
  37. {
  38. *s = ::tolower( *s );
  39. s++;
  40. }
  41. return s1;
  42. }
  43. char *idStr::toUpper
  44. (
  45. char *s1
  46. )
  47. {
  48. char *s;
  49. s = s1;
  50. while( *s )
  51. {
  52. *s = ::toupper( *s );
  53. s++;
  54. }
  55. return s1;
  56. }
  57. int idStr::icmpn
  58. (
  59. const char *s1,
  60. const char *s2,
  61. int n
  62. )
  63. {
  64. int c1;
  65. int c2;
  66. do
  67. {
  68. c1 = *s1++;
  69. c2 = *s2++;
  70. if ( !n-- )
  71. {
  72. // idStrings are equal until end point
  73. return 0;
  74. }
  75. if ( c1 != c2 )
  76. {
  77. if ( c1 >= 'a' && c1 <= 'z' )
  78. {
  79. c1 -= ( 'a' - 'A' );
  80. }
  81. if ( c2 >= 'a' && c2 <= 'z' )
  82. {
  83. c2 -= ( 'a' - 'A' );
  84. }
  85. if ( c1 < c2 )
  86. {
  87. // strings less than
  88. return -1;
  89. }
  90. else if ( c1 > c2 )
  91. {
  92. // strings greater than
  93. return 1;
  94. }
  95. }
  96. }
  97. while( c1 );
  98. // strings are equal
  99. return 0;
  100. }
  101. int idStr::icmp
  102. (
  103. const char *s1,
  104. const char *s2
  105. )
  106. {
  107. int c1;
  108. int c2;
  109. do
  110. {
  111. c1 = *s1++;
  112. c2 = *s2++;
  113. if ( c1 != c2 )
  114. {
  115. if ( c1 >= 'a' && c1 <= 'z' )
  116. {
  117. c1 -= ( 'a' - 'A' );
  118. }
  119. if ( c2 >= 'a' && c2 <= 'z' )
  120. {
  121. c2 -= ( 'a' - 'A' );
  122. }
  123. if ( c1 < c2 )
  124. {
  125. // strings less than
  126. return -1;
  127. }
  128. else if ( c1 > c2 )
  129. {
  130. // strings greater than
  131. return 1;
  132. }
  133. }
  134. }
  135. while( c1 );
  136. // strings are equal
  137. return 0;
  138. }
  139. int idStr::cmpn
  140. (
  141. const char *s1,
  142. const char *s2,
  143. int n
  144. )
  145. {
  146. int c1;
  147. int c2;
  148. do
  149. {
  150. c1 = *s1++;
  151. c2 = *s2++;
  152. if ( !n-- )
  153. {
  154. // strings are equal until end point
  155. return 0;
  156. }
  157. if ( c1 < c2 )
  158. {
  159. // strings less than
  160. return -1;
  161. }
  162. else if ( c1 > c2 )
  163. {
  164. // strings greater than
  165. return 1;
  166. }
  167. }
  168. while( c1 );
  169. // strings are equal
  170. return 0;
  171. }
  172. int idStr::cmp
  173. (
  174. const char *s1,
  175. const char *s2
  176. )
  177. {
  178. int c1;
  179. int c2;
  180. do
  181. {
  182. c1 = *s1++;
  183. c2 = *s2++;
  184. if ( c1 < c2 )
  185. {
  186. // strings less than
  187. return -1;
  188. }
  189. else if ( c1 > c2 )
  190. {
  191. // strings greater than
  192. return 1;
  193. }
  194. }
  195. while( c1 );
  196. // strings are equal
  197. return 0;
  198. }
  199. /*
  200. ============
  201. IsNumeric
  202. Checks a string to see if it contains only numerical values.
  203. ============
  204. */
  205. bool idStr::isNumeric
  206. (
  207. const char *str
  208. )
  209. {
  210. int len;
  211. int i;
  212. bool dot;
  213. if ( *str == '-' )
  214. {
  215. str++;
  216. }
  217. dot = false;
  218. len = strlen( str );
  219. for( i = 0; i < len; i++ )
  220. {
  221. if ( !isdigit( str[ i ] ) )
  222. {
  223. if ( ( str[ i ] == '.' ) && !dot )
  224. {
  225. dot = true;
  226. continue;
  227. }
  228. return false;
  229. }
  230. }
  231. return true;
  232. }
  233. idStr operator+
  234. (
  235. const idStr& a,
  236. const float b
  237. )
  238. {
  239. char text[ 20 ];
  240. idStr result( a );
  241. sprintf( text, "%f", b );
  242. result.append( text );
  243. return result;
  244. }
  245. idStr operator+
  246. (
  247. const idStr& a,
  248. const int b
  249. )
  250. {
  251. char text[ 20 ];
  252. idStr result( a );
  253. sprintf( text, "%d", b );
  254. result.append( text );
  255. return result;
  256. }
  257. idStr operator+
  258. (
  259. const idStr& a,
  260. const unsigned b
  261. )
  262. {
  263. char text[ 20 ];
  264. idStr result( a );
  265. sprintf( text, "%u", b );
  266. result.append( text );
  267. return result;
  268. }
  269. idStr& idStr::operator+=
  270. (
  271. const float a
  272. )
  273. {
  274. char text[ 20 ];
  275. sprintf( text, "%f", a );
  276. append( text );
  277. return *this;
  278. }
  279. idStr& idStr::operator+=
  280. (
  281. const int a
  282. )
  283. {
  284. char text[ 20 ];
  285. sprintf( text, "%d", a );
  286. append( text );
  287. return *this;
  288. }
  289. idStr& idStr::operator+=
  290. (
  291. const unsigned a
  292. )
  293. {
  294. char text[ 20 ];
  295. sprintf( text, "%u", a );
  296. append( text );
  297. return *this;
  298. }
  299. void idStr::CapLength
  300. (
  301. int newlen
  302. )
  303. {
  304. assert ( m_data );
  305. if ( length() <= newlen )
  306. return;
  307. EnsureDataWritable ();
  308. m_data->data[newlen] = 0;
  309. m_data->len = newlen;
  310. }
  311. void idStr::EnsureDataWritable
  312. (
  313. void
  314. )
  315. {
  316. assert ( m_data );
  317. strdata *olddata;
  318. int len;
  319. if ( !m_data->refcount )
  320. return;
  321. olddata = m_data;
  322. len = length();
  323. m_data = new strdata;
  324. EnsureAlloced ( len + 1, false );
  325. strncpy ( m_data->data, olddata->data, len+1 );
  326. m_data->len = len;
  327. olddata->DelRef ();
  328. }
  329. void idStr::EnsureAlloced (int amount, bool keepold) {
  330. if ( !m_data ) {
  331. m_data = new strdata();
  332. }
  333. // Now, let's make sure it's writable
  334. EnsureDataWritable ();
  335. char *newbuffer;
  336. bool wasalloced = ( m_data->alloced != 0 );
  337. if ( amount < m_data->alloced ) {
  338. return;
  339. }
  340. assert ( amount );
  341. if ( amount == 1 ) {
  342. m_data->alloced = 1;
  343. } else {
  344. int newsize, mod;
  345. mod = amount % STR_ALLOC_GRAN;
  346. if ( !mod ) {
  347. newsize = amount;
  348. } else {
  349. newsize = amount + STR_ALLOC_GRAN - mod;
  350. }
  351. m_data->alloced = newsize;
  352. }
  353. newbuffer = new char[m_data->alloced];
  354. if ( wasalloced && keepold ) {
  355. strcpy ( newbuffer, m_data->data );
  356. }
  357. if ( m_data->data ) {
  358. delete [] m_data->data;
  359. }
  360. m_data->data = newbuffer;
  361. }
  362. void idStr::BackSlashesToSlashes
  363. (
  364. void
  365. )
  366. {
  367. int i;
  368. EnsureDataWritable ();
  369. for ( i=0; i < m_data->len; i++ )
  370. {
  371. if ( m_data->data[i] == '\\' )
  372. m_data->data[i] = '/';
  373. }
  374. }
  375. void idStr::snprintf
  376. (
  377. char *dst,
  378. int size,
  379. const char *fmt,
  380. ...
  381. )
  382. {
  383. char buffer[0x10000];
  384. int len;
  385. va_list argptr;
  386. va_start (argptr,fmt);
  387. len = vsprintf (buffer,fmt,argptr);
  388. va_end (argptr);
  389. assert ( len < size );
  390. strncpy (dst, buffer, size-1);
  391. }
  392. #ifdef _WIN32
  393. #pragma warning(disable : 4189) // local variable is initialized but not referenced
  394. #endif
  395. /*
  396. =================
  397. TestStringClass
  398. This is a fairly rigorous test of the idStr class's functionality.
  399. Because of the fairly global and subtle ramifications of a bug occuring
  400. in this class, it should be run after any changes to the class.
  401. Add more tests as functionality is changed. Tests should include
  402. any possible bounds violation and NULL data tests.
  403. =================
  404. */
  405. void TestStringClass
  406. (
  407. void
  408. )
  409. {
  410. char ch; // ch == ?
  411. idStr *t; // t == ?
  412. idStr a; // a.len == 0, a.data == "\0"
  413. idStr b; // b.len == 0, b.data == "\0"
  414. idStr c( "test" ); // c.len == 4, c.data == "test\0"
  415. idStr d( c ); // d.len == 4, d.data == "test\0"
  416. idStr e( reinterpret_cast<const char *>(NULL) );
  417. // e.len == 0, e.data == "\0" ASSERT!
  418. int i; // i == ?
  419. i = a.length(); // i == 0
  420. i = c.length(); // i == 4
  421. // TTimo: not used
  422. // const char *s1 = a.c_str(); // s1 == "\0"
  423. // const char *s2 = c.c_str(); // s2 == "test\0"
  424. t = new idStr(); // t->len == 0, t->data == "\0"
  425. delete t; // t == ?
  426. b = "test"; // b.len == 4, b.data == "test\0"
  427. t = new idStr( "test" ); // t->len == 4, t->data == "test\0"
  428. delete t; // t == ?
  429. a = c; // a.len == 4, a.data == "test\0"
  430. // a = "";
  431. a = NULL; // a.len == 0, a.data == "\0" ASSERT!
  432. a = c + d; // a.len == 8, a.data == "testtest\0"
  433. a = c + "wow"; // a.len == 7, a.data == "testwow\0"
  434. a = c + reinterpret_cast<const char *>(NULL);
  435. // a.len == 4, a.data == "test\0" ASSERT!
  436. a = "this" + d; // a.len == 8, a.data == "thistest\0"
  437. a = reinterpret_cast<const char *>(NULL) + d;
  438. // a.len == 4, a.data == "test\0" ASSERT!
  439. a += c; // a.len == 8, a.data == "testtest\0"
  440. a += "wow"; // a.len == 11, a.data == "testtestwow\0"
  441. a += reinterpret_cast<const char *>(NULL);
  442. // a.len == 11, a.data == "testtestwow\0" ASSERT!
  443. a = "test"; // a.len == 4, a.data == "test\0"
  444. ch = a[ 0 ]; // ch == 't'
  445. ch = a[ -1 ]; // ch == 0 ASSERT!
  446. ch = a[ 1000 ]; // ch == 0 ASSERT!
  447. ch = a[ 0 ]; // ch == 't'
  448. ch = a[ 1 ]; // ch == 'e'
  449. ch = a[ 2 ]; // ch == 's'
  450. ch = a[ 3 ]; // ch == 't'
  451. ch = a[ 4 ]; // ch == '\0' ASSERT!
  452. ch = a[ 5 ]; // ch == '\0' ASSERT!
  453. a[ 1 ] = 'b'; // a.len == 4, a.data == "tbst\0"
  454. a[ -1 ] = 'b'; // a.len == 4, a.data == "tbst\0" ASSERT!
  455. a[ 0 ] = '0'; // a.len == 4, a.data == "0bst\0"
  456. a[ 1 ] = '1'; // a.len == 4, a.data == "01st\0"
  457. a[ 2 ] = '2'; // a.len == 4, a.data == "012t\0"
  458. a[ 3 ] = '3'; // a.len == 4, a.data == "0123\0"
  459. a[ 4 ] = '4'; // a.len == 4, a.data == "0123\0" ASSERT!
  460. a[ 5 ] = '5'; // a.len == 4, a.data == "0123\0" ASSERT!
  461. a[ 7 ] = '7'; // a.len == 4, a.data == "0123\0" ASSERT!
  462. a = "test"; // a.len == 4, a.data == "test\0"
  463. b = "no"; // b.len == 2, b.data == "no\0"
  464. i = ( a == b ); // i == 0
  465. i = ( a == c ); // i == 1
  466. i = ( a == "blow" ); // i == 0
  467. i = ( a == "test" ); // i == 1
  468. i = ( a == NULL ); // i == 0 ASSERT!
  469. i = ( "test" == b ); // i == 0
  470. i = ( "test" == a ); // i == 1
  471. i = ( NULL == a ); // i == 0 ASSERT!
  472. i = ( a != b ); // i == 1
  473. i = ( a != c ); // i == 0
  474. i = ( a != "blow" ); // i == 1
  475. i = ( a != "test" ); // i == 0
  476. i = ( a != NULL ); // i == 1 ASSERT!
  477. i = ( "test" != b ); // i == 1
  478. i = ( "test" != a ); // i == 0
  479. i = ( NULL != a ); // i == 1 ASSERT!
  480. a = "test"; // a.data == "test"
  481. b = a; // b.data == "test"
  482. a = "not"; // a.data == "not", b.data == "test"
  483. a = b; // a.data == b.data == "test"
  484. a += b; // a.data == "testtest", b.data = "test"
  485. a = b;
  486. a[1] = '1'; // a.data = "t1st", b.data = "test"
  487. }
  488. #ifdef _WIN32
  489. #pragma warning(default : 4189) // local variable is initialized but not referenced
  490. #pragma warning(disable : 4514) // unreferenced inline function has been removed
  491. #endif