Str.cpp 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 Source Code 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. You should have received a copy of the GNU General Public License
  15. along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #include "precompiled.h"
  21. #pragma hdrstop
  22. #if !defined( ID_REDIRECT_NEWDELETE ) && !defined( MACOS_X )
  23. #define USE_STRING_DATA_ALLOCATOR
  24. #endif
  25. #ifdef USE_STRING_DATA_ALLOCATOR
  26. static idDynamicBlockAlloc<char, 1<<18, 128> stringDataAllocator;
  27. #endif
  28. idVec4 g_color_table[16] =
  29. {
  30. idVec4(0.0f, 0.0f, 0.0f, 1.0f),
  31. idVec4(1.0f, 0.0f, 0.0f, 1.0f), // S_COLOR_RED
  32. idVec4(0.0f, 1.0f, 0.0f, 1.0f), // S_COLOR_GREEN
  33. idVec4(1.0f, 1.0f, 0.0f, 1.0f), // S_COLOR_YELLOW
  34. idVec4(0.0f, 0.0f, 1.0f, 1.0f), // S_COLOR_BLUE
  35. idVec4(0.0f, 1.0f, 1.0f, 1.0f), // S_COLOR_CYAN
  36. idVec4(1.0f, 0.0f, 1.0f, 1.0f), // S_COLOR_MAGENTA
  37. idVec4(1.0f, 1.0f, 1.0f, 1.0f), // S_COLOR_WHITE
  38. idVec4(0.5f, 0.5f, 0.5f, 1.0f), // S_COLOR_GRAY
  39. idVec4(0.0f, 0.0f, 0.0f, 1.0f), // S_COLOR_BLACK
  40. idVec4(0.0f, 0.0f, 0.0f, 1.0f),
  41. idVec4(0.0f, 0.0f, 0.0f, 1.0f),
  42. idVec4(0.0f, 0.0f, 0.0f, 1.0f),
  43. idVec4(0.0f, 0.0f, 0.0f, 1.0f),
  44. idVec4(0.0f, 0.0f, 0.0f, 1.0f),
  45. idVec4(0.0f, 0.0f, 0.0f, 1.0f),
  46. };
  47. const char *units[2][4] =
  48. {
  49. { "B", "KB", "MB", "GB" },
  50. { "B/s", "KB/s", "MB/s", "GB/s" }
  51. };
  52. /*
  53. ============
  54. idStr::ColorForIndex
  55. ============
  56. */
  57. idVec4 & idStr::ColorForIndex( int i ) {
  58. return g_color_table[ i & 15 ];
  59. }
  60. /*
  61. ============
  62. idStr::ReAllocate
  63. ============
  64. */
  65. void idStr::ReAllocate( int amount, bool keepold ) {
  66. char *newbuffer;
  67. int newsize;
  68. int mod;
  69. //assert( data );
  70. assert( amount > 0 );
  71. mod = amount % STR_ALLOC_GRAN;
  72. if ( !mod ) {
  73. newsize = amount;
  74. }
  75. else {
  76. newsize = amount + STR_ALLOC_GRAN - mod;
  77. }
  78. alloced = newsize;
  79. #ifdef USE_STRING_DATA_ALLOCATOR
  80. newbuffer = stringDataAllocator.Alloc( alloced );
  81. #else
  82. newbuffer = new char[ alloced ];
  83. #endif
  84. if ( keepold && data ) {
  85. data[ len ] = '\0';
  86. strcpy( newbuffer, data );
  87. }
  88. if ( data && data != baseBuffer ) {
  89. #ifdef USE_STRING_DATA_ALLOCATOR
  90. stringDataAllocator.Free( data );
  91. #else
  92. delete [] data;
  93. #endif
  94. }
  95. data = newbuffer;
  96. }
  97. /*
  98. ============
  99. idStr::FreeData
  100. ============
  101. */
  102. void idStr::FreeData( void ) {
  103. if ( data && data != baseBuffer ) {
  104. #ifdef USE_STRING_DATA_ALLOCATOR
  105. stringDataAllocator.Free( data );
  106. #else
  107. delete[] data;
  108. #endif
  109. data = baseBuffer;
  110. }
  111. }
  112. /*
  113. ============
  114. idStr::operator=
  115. ============
  116. */
  117. void idStr::operator=( const char *text ) {
  118. int l;
  119. int diff;
  120. int i;
  121. if ( !text ) {
  122. // safe behaviour if NULL
  123. EnsureAlloced( 1, false );
  124. data[ 0 ] = '\0';
  125. len = 0;
  126. return;
  127. }
  128. if ( text == data ) {
  129. return; // copying same thing
  130. }
  131. // check if we're aliasing
  132. if ( text >= data && text <= data + len ) {
  133. diff = text - data;
  134. assert( strlen( text ) < (unsigned)len );
  135. for ( i = 0; text[ i ]; i++ ) {
  136. data[ i ] = text[ i ];
  137. }
  138. data[ i ] = '\0';
  139. len -= diff;
  140. return;
  141. }
  142. l = strlen( text );
  143. EnsureAlloced( l + 1, false );
  144. strcpy( data, text );
  145. len = l;
  146. }
  147. /*
  148. ============
  149. idStr::FindChar
  150. returns -1 if not found otherwise the index of the char
  151. ============
  152. */
  153. int idStr::FindChar( const char *str, const char c, int start, int end ) {
  154. int i;
  155. if ( end == -1 ) {
  156. end = strlen( str ) - 1;
  157. }
  158. for ( i = start; i <= end; i++ ) {
  159. if ( str[i] == c ) {
  160. return i;
  161. }
  162. }
  163. return -1;
  164. }
  165. /*
  166. ============
  167. idStr::FindText
  168. returns -1 if not found otherwise the index of the text
  169. ============
  170. */
  171. int idStr::FindText( const char *str, const char *text, bool casesensitive, int start, int end ) {
  172. int l, i, j;
  173. if ( end == -1 ) {
  174. end = strlen( str );
  175. }
  176. l = end - strlen( text );
  177. for ( i = start; i <= l; i++ ) {
  178. if ( casesensitive ) {
  179. for ( j = 0; text[j]; j++ ) {
  180. if ( str[i+j] != text[j] ) {
  181. break;
  182. }
  183. }
  184. } else {
  185. for ( j = 0; text[j]; j++ ) {
  186. if ( ::toupper( str[i+j] ) != ::toupper( text[j] ) ) {
  187. break;
  188. }
  189. }
  190. }
  191. if ( !text[j] ) {
  192. return i;
  193. }
  194. }
  195. return -1;
  196. }
  197. /*
  198. ============
  199. idStr::Filter
  200. Returns true if the string conforms the given filter.
  201. Several metacharacter may be used in the filter.
  202. * match any string of zero or more characters
  203. ? match any single character
  204. [abc...] match any of the enclosed characters; a hyphen can
  205. be used to specify a range (e.g. a-z, A-Z, 0-9)
  206. ============
  207. */
  208. bool idStr::Filter( const char *filter, const char *name, bool casesensitive ) {
  209. idStr buf;
  210. int i, found, index;
  211. while(*filter) {
  212. if (*filter == '*') {
  213. filter++;
  214. buf.Empty();
  215. for (i = 0; *filter; i++) {
  216. if ( *filter == '*' || *filter == '?' || (*filter == '[' && *(filter+1) != '[') ) {
  217. break;
  218. }
  219. buf += *filter;
  220. if ( *filter == '[' ) {
  221. filter++;
  222. }
  223. filter++;
  224. }
  225. if ( buf.Length() ) {
  226. index = idStr(name).Find( buf.c_str(), casesensitive );
  227. if ( index == -1 ) {
  228. return false;
  229. }
  230. name += index + strlen(buf);
  231. }
  232. }
  233. else if (*filter == '?') {
  234. filter++;
  235. name++;
  236. }
  237. else if (*filter == '[') {
  238. if ( *(filter+1) == '[' ) {
  239. if ( *name != '[' ) {
  240. return false;
  241. }
  242. filter += 2;
  243. name++;
  244. }
  245. else {
  246. filter++;
  247. found = false;
  248. while(*filter && !found) {
  249. if (*filter == ']' && *(filter+1) != ']') {
  250. break;
  251. }
  252. if (*(filter+1) == '-' && *(filter+2) && (*(filter+2) != ']' || *(filter+3) == ']')) {
  253. if (casesensitive) {
  254. if (*name >= *filter && *name <= *(filter+2)) {
  255. found = true;
  256. }
  257. }
  258. else {
  259. if ( ::toupper(*name) >= ::toupper(*filter) && ::toupper(*name) <= ::toupper(*(filter+2)) ) {
  260. found = true;
  261. }
  262. }
  263. filter += 3;
  264. }
  265. else {
  266. if (casesensitive) {
  267. if (*filter == *name) {
  268. found = true;
  269. }
  270. }
  271. else {
  272. if ( ::toupper(*filter) == ::toupper(*name) ) {
  273. found = true;
  274. }
  275. }
  276. filter++;
  277. }
  278. }
  279. if (!found) {
  280. return false;
  281. }
  282. while(*filter) {
  283. if ( *filter == ']' && *(filter+1) != ']' ) {
  284. break;
  285. }
  286. filter++;
  287. }
  288. filter++;
  289. name++;
  290. }
  291. }
  292. else {
  293. if (casesensitive) {
  294. if (*filter != *name) {
  295. return false;
  296. }
  297. }
  298. else {
  299. if ( ::toupper(*filter) != ::toupper(*name) ) {
  300. return false;
  301. }
  302. }
  303. filter++;
  304. name++;
  305. }
  306. }
  307. return true;
  308. }
  309. /*
  310. =============
  311. idStr::StripMediaName
  312. makes the string lower case, replaces backslashes with forward slashes, and removes extension
  313. =============
  314. */
  315. void idStr::StripMediaName( const char *name, idStr &mediaName ) {
  316. char c;
  317. mediaName.Empty();
  318. for ( c = *name; c; c = *(++name) ) {
  319. // truncate at an extension
  320. if ( c == '.' ) {
  321. break;
  322. }
  323. // convert backslashes to forward slashes
  324. if ( c == '\\' ) {
  325. mediaName.Append( '/' );
  326. } else {
  327. mediaName.Append( idStr::ToLower( c ) );
  328. }
  329. }
  330. }
  331. /*
  332. =============
  333. idStr::CheckExtension
  334. =============
  335. */
  336. bool idStr::CheckExtension( const char *name, const char *ext ) {
  337. const char *s1 = name + Length( name ) - 1;
  338. const char *s2 = ext + Length( ext ) - 1;
  339. int c1, c2, d;
  340. do {
  341. c1 = *s1--;
  342. c2 = *s2--;
  343. d = c1 - c2;
  344. while( d ) {
  345. if ( c1 <= 'Z' && c1 >= 'A' ) {
  346. d += ('a' - 'A');
  347. if ( !d ) {
  348. break;
  349. }
  350. }
  351. if ( c2 <= 'Z' && c2 >= 'A' ) {
  352. d -= ('a' - 'A');
  353. if ( !d ) {
  354. break;
  355. }
  356. }
  357. return false;
  358. }
  359. } while( s1 > name && s2 > ext );
  360. return ( s1 >= name );
  361. }
  362. /*
  363. =============
  364. idStr::FloatArrayToString
  365. =============
  366. */
  367. const char *idStr::FloatArrayToString( const float *array, const int length, const int precision ) {
  368. static int index = 0;
  369. static char str[4][16384]; // in case called by nested functions
  370. int i, n;
  371. char format[16], *s;
  372. // use an array of string so that multiple calls won't collide
  373. s = str[ index ];
  374. index = (index + 1) & 3;
  375. idStr::snPrintf( format, sizeof( format ), "%%.%df", precision );
  376. n = idStr::snPrintf( s, sizeof( str[0] ), format, array[0] );
  377. if ( precision > 0 ) {
  378. while( n > 0 && s[n-1] == '0' ) s[--n] = '\0';
  379. while( n > 0 && s[n-1] == '.' ) s[--n] = '\0';
  380. }
  381. idStr::snPrintf( format, sizeof( format ), " %%.%df", precision );
  382. for ( i = 1; i < length; i++ ) {
  383. n += idStr::snPrintf( s + n, sizeof( str[0] ) - n, format, array[i] );
  384. if ( precision > 0 ) {
  385. while( n > 0 && s[n-1] == '0' ) s[--n] = '\0';
  386. while( n > 0 && s[n-1] == '.' ) s[--n] = '\0';
  387. }
  388. }
  389. return s;
  390. }
  391. /*
  392. ============
  393. idStr::Last
  394. returns -1 if not found otherwise the index of the char
  395. ============
  396. */
  397. int idStr::Last( const char c ) const {
  398. int i;
  399. for( i = Length(); i > 0; i-- ) {
  400. if ( data[ i - 1 ] == c ) {
  401. return i - 1;
  402. }
  403. }
  404. return -1;
  405. }
  406. /*
  407. ============
  408. idStr::StripLeading
  409. ============
  410. */
  411. void idStr::StripLeading( const char c ) {
  412. while( data[ 0 ] == c ) {
  413. memmove( &data[ 0 ], &data[ 1 ], len );
  414. len--;
  415. }
  416. }
  417. /*
  418. ============
  419. idStr::StripLeading
  420. ============
  421. */
  422. void idStr::StripLeading( const char *string ) {
  423. int l;
  424. l = strlen( string );
  425. if ( l > 0 ) {
  426. while ( !Cmpn( string, l ) ) {
  427. memmove( data, data + l, len - l + 1 );
  428. len -= l;
  429. }
  430. }
  431. }
  432. /*
  433. ============
  434. idStr::StripLeadingOnce
  435. ============
  436. */
  437. bool idStr::StripLeadingOnce( const char *string ) {
  438. int l;
  439. l = strlen( string );
  440. if ( ( l > 0 ) && !Cmpn( string, l ) ) {
  441. memmove( data, data + l, len - l + 1 );
  442. len -= l;
  443. return true;
  444. }
  445. return false;
  446. }
  447. /*
  448. ============
  449. idStr::StripTrailing
  450. ============
  451. */
  452. void idStr::StripTrailing( const char c ) {
  453. int i;
  454. for( i = Length(); i > 0 && data[ i - 1 ] == c; i-- ) {
  455. data[ i - 1 ] = '\0';
  456. len--;
  457. }
  458. }
  459. /*
  460. ============
  461. idStr::StripLeading
  462. ============
  463. */
  464. void idStr::StripTrailing( const char *string ) {
  465. int l;
  466. l = strlen( string );
  467. if ( l > 0 ) {
  468. while ( ( len >= l ) && !Cmpn( string, data + len - l, l ) ) {
  469. len -= l;
  470. data[len] = '\0';
  471. }
  472. }
  473. }
  474. /*
  475. ============
  476. idStr::StripTrailingOnce
  477. ============
  478. */
  479. bool idStr::StripTrailingOnce( const char *string ) {
  480. int l;
  481. l = strlen( string );
  482. if ( ( l > 0 ) && ( len >= l ) && !Cmpn( string, data + len - l, l ) ) {
  483. len -= l;
  484. data[len] = '\0';
  485. return true;
  486. }
  487. return false;
  488. }
  489. /*
  490. ============
  491. idStr::Replace
  492. ============
  493. */
  494. void idStr::Replace( const char *old, const char *nw ) {
  495. int oldLen, newLen, i, j, count;
  496. idStr oldString( data );
  497. oldLen = strlen( old );
  498. newLen = strlen( nw );
  499. // Work out how big the new string will be
  500. count = 0;
  501. for( i = 0; i < oldString.Length(); i++ ) {
  502. if( !idStr::Cmpn( &oldString[i], old, oldLen ) ) {
  503. count++;
  504. i += oldLen - 1;
  505. }
  506. }
  507. if( count ) {
  508. EnsureAlloced( len + ( ( newLen - oldLen ) * count ) + 2, false );
  509. // Replace the old data with the new data
  510. for( i = 0, j = 0; i < oldString.Length(); i++ ) {
  511. if( !idStr::Cmpn( &oldString[i], old, oldLen ) ) {
  512. memcpy( data + j, nw, newLen );
  513. i += oldLen - 1;
  514. j += newLen;
  515. } else {
  516. data[j] = oldString[i];
  517. j++;
  518. }
  519. }
  520. data[j] = 0;
  521. len = strlen( data );
  522. }
  523. }
  524. /*
  525. ============
  526. idStr::Mid
  527. ============
  528. */
  529. const char *idStr::Mid( int start, int len, idStr &result ) const {
  530. int i;
  531. result.Empty();
  532. i = Length();
  533. if ( i == 0 || len <= 0 || start >= i ) {
  534. return NULL;
  535. }
  536. if ( start + len >= i ) {
  537. len = i - start;
  538. }
  539. result.Append( &data[ start ], len );
  540. return result;
  541. }
  542. /*
  543. ============
  544. idStr::Mid
  545. ============
  546. */
  547. idStr idStr::Mid( int start, int len ) const {
  548. int i;
  549. idStr result;
  550. i = Length();
  551. if ( i == 0 || len <= 0 || start >= i ) {
  552. return result;
  553. }
  554. if ( start + len >= i ) {
  555. len = i - start;
  556. }
  557. result.Append( &data[ start ], len );
  558. return result;
  559. }
  560. /*
  561. ============
  562. idStr::StripTrailingWhitespace
  563. ============
  564. */
  565. void idStr::StripTrailingWhitespace( void ) {
  566. int i;
  567. // cast to unsigned char to prevent stripping off high-ASCII characters
  568. for( i = Length(); i > 0 && (unsigned char)(data[ i - 1 ]) <= ' '; i-- ) {
  569. data[ i - 1 ] = '\0';
  570. len--;
  571. }
  572. }
  573. /*
  574. ============
  575. idStr::StripQuotes
  576. Removes the quotes from the beginning and end of the string
  577. ============
  578. */
  579. idStr& idStr::StripQuotes ( void )
  580. {
  581. if ( data[0] != '\"' )
  582. {
  583. return *this;
  584. }
  585. // Remove the trailing quote first
  586. if ( data[len-1] == '\"' )
  587. {
  588. data[len-1] = '\0';
  589. len--;
  590. }
  591. // Strip the leading quote now
  592. len--;
  593. memmove( &data[ 0 ], &data[ 1 ], len );
  594. data[len] = '\0';
  595. return *this;
  596. }
  597. /*
  598. =====================================================================
  599. filename methods
  600. =====================================================================
  601. */
  602. /*
  603. ============
  604. idStr::FileNameHash
  605. ============
  606. */
  607. int idStr::FileNameHash( void ) const {
  608. int i;
  609. long hash;
  610. char letter;
  611. hash = 0;
  612. i = 0;
  613. while( data[i] != '\0' ) {
  614. letter = idStr::ToLower( data[i] );
  615. if ( letter == '.' ) {
  616. break; // don't include extension
  617. }
  618. if ( letter =='\\' ) {
  619. letter = '/';
  620. }
  621. hash += (long)(letter)*(i+119);
  622. i++;
  623. }
  624. hash &= (FILE_HASH_SIZE-1);
  625. return hash;
  626. }
  627. /*
  628. ============
  629. idStr::BackSlashesToSlashes
  630. ============
  631. */
  632. idStr &idStr::BackSlashesToSlashes( void ) {
  633. int i;
  634. for ( i = 0; i < len; i++ ) {
  635. if ( data[ i ] == '\\' ) {
  636. data[ i ] = '/';
  637. }
  638. }
  639. return *this;
  640. }
  641. /*
  642. ============
  643. idStr::SetFileExtension
  644. ============
  645. */
  646. idStr &idStr::SetFileExtension( const char *extension ) {
  647. StripFileExtension();
  648. if ( *extension != '.' ) {
  649. Append( '.' );
  650. }
  651. Append( extension );
  652. return *this;
  653. }
  654. /*
  655. ============
  656. idStr::StripFileExtension
  657. ============
  658. */
  659. idStr &idStr::StripFileExtension( void ) {
  660. int i;
  661. for ( i = len-1; i >= 0; i-- ) {
  662. if ( data[i] == '.' ) {
  663. data[i] = '\0';
  664. len = i;
  665. break;
  666. }
  667. }
  668. return *this;
  669. }
  670. /*
  671. ============
  672. idStr::StripAbsoluteFileExtension
  673. ============
  674. */
  675. idStr &idStr::StripAbsoluteFileExtension( void ) {
  676. int i;
  677. for ( i = 0; i < len; i++ ) {
  678. if ( data[i] == '.' ) {
  679. data[i] = '\0';
  680. len = i;
  681. break;
  682. }
  683. }
  684. return *this;
  685. }
  686. /*
  687. ==================
  688. idStr::DefaultFileExtension
  689. ==================
  690. */
  691. idStr &idStr::DefaultFileExtension( const char *extension ) {
  692. int i;
  693. // do nothing if the string already has an extension
  694. for ( i = len-1; i >= 0; i-- ) {
  695. if ( data[i] == '.' ) {
  696. return *this;
  697. }
  698. }
  699. if ( *extension != '.' ) {
  700. Append( '.' );
  701. }
  702. Append( extension );
  703. return *this;
  704. }
  705. /*
  706. ==================
  707. idStr::DefaultPath
  708. ==================
  709. */
  710. idStr &idStr::DefaultPath( const char *basepath ) {
  711. if ( ( ( *this )[ 0 ] == '/' ) || ( ( *this )[ 0 ] == '\\' ) ) {
  712. // absolute path location
  713. return *this;
  714. }
  715. *this = basepath + *this;
  716. return *this;
  717. }
  718. /*
  719. ====================
  720. idStr::AppendPath
  721. ====================
  722. */
  723. void idStr::AppendPath( const char *text ) {
  724. int pos;
  725. int i = 0;
  726. if ( text && text[i] ) {
  727. pos = len;
  728. EnsureAlloced( len + strlen( text ) + 2 );
  729. if ( pos ) {
  730. if ( data[ pos-1 ] != '/' ) {
  731. data[ pos++ ] = '/';
  732. }
  733. }
  734. if ( text[i] == '/' ) {
  735. i++;
  736. }
  737. for ( ; text[ i ]; i++ ) {
  738. if ( text[ i ] == '\\' ) {
  739. data[ pos++ ] = '/';
  740. } else {
  741. data[ pos++ ] = text[ i ];
  742. }
  743. }
  744. len = pos;
  745. data[ pos ] = '\0';
  746. }
  747. }
  748. /*
  749. ==================
  750. idStr::StripFilename
  751. ==================
  752. */
  753. idStr &idStr::StripFilename( void ) {
  754. int pos;
  755. pos = Length() - 1;
  756. while( ( pos > 0 ) && ( ( *this )[ pos ] != '/' ) && ( ( *this )[ pos ] != '\\' ) ) {
  757. pos--;
  758. }
  759. if ( pos < 0 ) {
  760. pos = 0;
  761. }
  762. CapLength( pos );
  763. return *this;
  764. }
  765. /*
  766. ==================
  767. idStr::StripPath
  768. ==================
  769. */
  770. idStr &idStr::StripPath( void ) {
  771. int pos;
  772. pos = Length();
  773. while( ( pos > 0 ) && ( ( *this )[ pos - 1 ] != '/' ) && ( ( *this )[ pos - 1 ] != '\\' ) ) {
  774. pos--;
  775. }
  776. *this = Right( Length() - pos );
  777. return *this;
  778. }
  779. /*
  780. ====================
  781. idStr::ExtractFilePath
  782. ====================
  783. */
  784. void idStr::ExtractFilePath( idStr &dest ) const {
  785. int pos;
  786. //
  787. // back up until a \ or the start
  788. //
  789. pos = Length();
  790. while( ( pos > 0 ) && ( ( *this )[ pos - 1 ] != '/' ) && ( ( *this )[ pos - 1 ] != '\\' ) ) {
  791. pos--;
  792. }
  793. Left( pos, dest );
  794. }
  795. /*
  796. ====================
  797. idStr::ExtractFileName
  798. ====================
  799. */
  800. void idStr::ExtractFileName( idStr &dest ) const {
  801. int pos;
  802. //
  803. // back up until a \ or the start
  804. //
  805. pos = Length() - 1;
  806. while( ( pos > 0 ) && ( ( *this )[ pos - 1 ] != '/' ) && ( ( *this )[ pos - 1 ] != '\\' ) ) {
  807. pos--;
  808. }
  809. Right( Length() - pos, dest );
  810. }
  811. /*
  812. ====================
  813. idStr::ExtractFileBase
  814. ====================
  815. */
  816. void idStr::ExtractFileBase( idStr &dest ) const {
  817. int pos;
  818. int start;
  819. //
  820. // back up until a \ or the start
  821. //
  822. pos = Length() - 1;
  823. while( ( pos > 0 ) && ( ( *this )[ pos - 1 ] != '/' ) && ( ( *this )[ pos - 1 ] != '\\' ) ) {
  824. pos--;
  825. }
  826. start = pos;
  827. while( ( pos < Length() ) && ( ( *this )[ pos ] != '.' ) ) {
  828. pos++;
  829. }
  830. Mid( start, pos - start, dest );
  831. }
  832. /*
  833. ====================
  834. idStr::ExtractFileExtension
  835. ====================
  836. */
  837. void idStr::ExtractFileExtension( idStr &dest ) const {
  838. int pos;
  839. //
  840. // back up until a . or the start
  841. //
  842. pos = Length() - 1;
  843. while( ( pos > 0 ) && ( ( *this )[ pos - 1 ] != '.' ) ) {
  844. pos--;
  845. }
  846. if ( !pos ) {
  847. // no extension
  848. dest.Empty();
  849. } else {
  850. Right( Length() - pos, dest );
  851. }
  852. }
  853. /*
  854. =====================================================================
  855. char * methods to replace library functions
  856. =====================================================================
  857. */
  858. /*
  859. ============
  860. idStr::IsNumeric
  861. Checks a string to see if it contains only numerical values.
  862. ============
  863. */
  864. bool idStr::IsNumeric( const char *s ) {
  865. int i;
  866. bool dot;
  867. if ( *s == '-' ) {
  868. s++;
  869. }
  870. dot = false;
  871. for ( i = 0; s[i]; i++ ) {
  872. if ( !isdigit( s[i] ) ) {
  873. if ( ( s[ i ] == '.' ) && !dot ) {
  874. dot = true;
  875. continue;
  876. }
  877. return false;
  878. }
  879. }
  880. return true;
  881. }
  882. /*
  883. ============
  884. idStr::HasLower
  885. Checks if a string has any lowercase chars
  886. ============
  887. */
  888. bool idStr::HasLower( const char *s ) {
  889. if ( !s ) {
  890. return false;
  891. }
  892. while ( *s ) {
  893. if ( CharIsLower( *s ) ) {
  894. return true;
  895. }
  896. s++;
  897. }
  898. return false;
  899. }
  900. /*
  901. ============
  902. idStr::HasUpper
  903. Checks if a string has any uppercase chars
  904. ============
  905. */
  906. bool idStr::HasUpper( const char *s ) {
  907. if ( !s ) {
  908. return false;
  909. }
  910. while ( *s ) {
  911. if ( CharIsUpper( *s ) ) {
  912. return true;
  913. }
  914. s++;
  915. }
  916. return false;
  917. }
  918. /*
  919. ================
  920. idStr::Cmp
  921. ================
  922. */
  923. int idStr::Cmp( const char *s1, const char *s2 ) {
  924. int c1, c2, d;
  925. do {
  926. c1 = *s1++;
  927. c2 = *s2++;
  928. d = c1 - c2;
  929. if ( d ) {
  930. return ( INTSIGNBITNOTSET( d ) << 1 ) - 1;
  931. }
  932. } while( c1 );
  933. return 0; // strings are equal
  934. }
  935. /*
  936. ================
  937. idStr::Cmpn
  938. ================
  939. */
  940. int idStr::Cmpn( const char *s1, const char *s2, int n ) {
  941. int c1, c2, d;
  942. assert( n >= 0 );
  943. do {
  944. c1 = *s1++;
  945. c2 = *s2++;
  946. if ( !n-- ) {
  947. return 0; // strings are equal until end point
  948. }
  949. d = c1 - c2;
  950. if ( d ) {
  951. return ( INTSIGNBITNOTSET( d ) << 1 ) - 1;
  952. }
  953. } while( c1 );
  954. return 0; // strings are equal
  955. }
  956. /*
  957. ================
  958. idStr::Icmp
  959. ================
  960. */
  961. int idStr::Icmp( const char *s1, const char *s2 ) {
  962. int c1, c2, d;
  963. do {
  964. c1 = *s1++;
  965. c2 = *s2++;
  966. d = c1 - c2;
  967. while( d ) {
  968. if ( c1 <= 'Z' && c1 >= 'A' ) {
  969. d += ('a' - 'A');
  970. if ( !d ) {
  971. break;
  972. }
  973. }
  974. if ( c2 <= 'Z' && c2 >= 'A' ) {
  975. d -= ('a' - 'A');
  976. if ( !d ) {
  977. break;
  978. }
  979. }
  980. return ( INTSIGNBITNOTSET( d ) << 1 ) - 1;
  981. }
  982. } while( c1 );
  983. return 0; // strings are equal
  984. }
  985. /*
  986. ================
  987. idStr::Icmpn
  988. ================
  989. */
  990. int idStr::Icmpn( const char *s1, const char *s2, int n ) {
  991. int c1, c2, d;
  992. assert( n >= 0 );
  993. do {
  994. c1 = *s1++;
  995. c2 = *s2++;
  996. if ( !n-- ) {
  997. return 0; // strings are equal until end point
  998. }
  999. d = c1 - c2;
  1000. while( d ) {
  1001. if ( c1 <= 'Z' && c1 >= 'A' ) {
  1002. d += ('a' - 'A');
  1003. if ( !d ) {
  1004. break;
  1005. }
  1006. }
  1007. if ( c2 <= 'Z' && c2 >= 'A' ) {
  1008. d -= ('a' - 'A');
  1009. if ( !d ) {
  1010. break;
  1011. }
  1012. }
  1013. return ( INTSIGNBITNOTSET( d ) << 1 ) - 1;
  1014. }
  1015. } while( c1 );
  1016. return 0; // strings are equal
  1017. }
  1018. /*
  1019. ================
  1020. idStr::Icmp
  1021. ================
  1022. */
  1023. int idStr::IcmpNoColor( const char *s1, const char *s2 ) {
  1024. int c1, c2, d;
  1025. do {
  1026. while ( idStr::IsColor( s1 ) ) {
  1027. s1 += 2;
  1028. }
  1029. while ( idStr::IsColor( s2 ) ) {
  1030. s2 += 2;
  1031. }
  1032. c1 = *s1++;
  1033. c2 = *s2++;
  1034. d = c1 - c2;
  1035. while( d ) {
  1036. if ( c1 <= 'Z' && c1 >= 'A' ) {
  1037. d += ('a' - 'A');
  1038. if ( !d ) {
  1039. break;
  1040. }
  1041. }
  1042. if ( c2 <= 'Z' && c2 >= 'A' ) {
  1043. d -= ('a' - 'A');
  1044. if ( !d ) {
  1045. break;
  1046. }
  1047. }
  1048. return ( INTSIGNBITNOTSET( d ) << 1 ) - 1;
  1049. }
  1050. } while( c1 );
  1051. return 0; // strings are equal
  1052. }
  1053. /*
  1054. ================
  1055. idStr::IcmpPath
  1056. ================
  1057. */
  1058. int idStr::IcmpPath( const char *s1, const char *s2 ) {
  1059. int c1, c2, d;
  1060. #if 0
  1061. //#if !defined( _WIN32 )
  1062. idLib::common->Printf( "WARNING: IcmpPath used on a case-sensitive filesystem?\n" );
  1063. #endif
  1064. do {
  1065. c1 = *s1++;
  1066. c2 = *s2++;
  1067. d = c1 - c2;
  1068. while( d ) {
  1069. if ( c1 <= 'Z' && c1 >= 'A' ) {
  1070. d += ('a' - 'A');
  1071. if ( !d ) {
  1072. break;
  1073. }
  1074. }
  1075. if ( c1 == '\\' ) {
  1076. d += ('/' - '\\');
  1077. if ( !d ) {
  1078. break;
  1079. }
  1080. }
  1081. if ( c2 <= 'Z' && c2 >= 'A' ) {
  1082. d -= ('a' - 'A');
  1083. if ( !d ) {
  1084. break;
  1085. }
  1086. }
  1087. if ( c2 == '\\' ) {
  1088. d -= ('/' - '\\');
  1089. if ( !d ) {
  1090. break;
  1091. }
  1092. }
  1093. // make sure folders come first
  1094. while( c1 ) {
  1095. if ( c1 == '/' || c1 == '\\' ) {
  1096. break;
  1097. }
  1098. c1 = *s1++;
  1099. }
  1100. while( c2 ) {
  1101. if ( c2 == '/' || c2 == '\\' ) {
  1102. break;
  1103. }
  1104. c2 = *s2++;
  1105. }
  1106. if ( c1 && !c2 ) {
  1107. return -1;
  1108. } else if ( !c1 && c2 ) {
  1109. return 1;
  1110. }
  1111. // same folder depth so use the regular compare
  1112. return ( INTSIGNBITNOTSET( d ) << 1 ) - 1;
  1113. }
  1114. } while( c1 );
  1115. return 0;
  1116. }
  1117. /*
  1118. ================
  1119. idStr::IcmpnPath
  1120. ================
  1121. */
  1122. int idStr::IcmpnPath( const char *s1, const char *s2, int n ) {
  1123. int c1, c2, d;
  1124. #if 0
  1125. //#if !defined( _WIN32 )
  1126. idLib::common->Printf( "WARNING: IcmpPath used on a case-sensitive filesystem?\n" );
  1127. #endif
  1128. assert( n >= 0 );
  1129. do {
  1130. c1 = *s1++;
  1131. c2 = *s2++;
  1132. if ( !n-- ) {
  1133. return 0; // strings are equal until end point
  1134. }
  1135. d = c1 - c2;
  1136. while( d ) {
  1137. if ( c1 <= 'Z' && c1 >= 'A' ) {
  1138. d += ('a' - 'A');
  1139. if ( !d ) {
  1140. break;
  1141. }
  1142. }
  1143. if ( c1 == '\\' ) {
  1144. d += ('/' - '\\');
  1145. if ( !d ) {
  1146. break;
  1147. }
  1148. }
  1149. if ( c2 <= 'Z' && c2 >= 'A' ) {
  1150. d -= ('a' - 'A');
  1151. if ( !d ) {
  1152. break;
  1153. }
  1154. }
  1155. if ( c2 == '\\' ) {
  1156. d -= ('/' - '\\');
  1157. if ( !d ) {
  1158. break;
  1159. }
  1160. }
  1161. // make sure folders come first
  1162. while( c1 ) {
  1163. if ( c1 == '/' || c1 == '\\' ) {
  1164. break;
  1165. }
  1166. c1 = *s1++;
  1167. }
  1168. while( c2 ) {
  1169. if ( c2 == '/' || c2 == '\\' ) {
  1170. break;
  1171. }
  1172. c2 = *s2++;
  1173. }
  1174. if ( c1 && !c2 ) {
  1175. return -1;
  1176. } else if ( !c1 && c2 ) {
  1177. return 1;
  1178. }
  1179. // same folder depth so use the regular compare
  1180. return ( INTSIGNBITNOTSET( d ) << 1 ) - 1;
  1181. }
  1182. } while( c1 );
  1183. return 0;
  1184. }
  1185. /*
  1186. =============
  1187. idStr::Copynz
  1188. Safe strncpy that ensures a trailing zero
  1189. =============
  1190. */
  1191. void idStr::Copynz( char *dest, const char *src, int destsize ) {
  1192. if ( !src ) {
  1193. idLib::common->Warning( "idStr::Copynz: NULL src" );
  1194. return;
  1195. }
  1196. if ( destsize < 1 ) {
  1197. idLib::common->Warning( "idStr::Copynz: destsize < 1" );
  1198. return;
  1199. }
  1200. strncpy( dest, src, destsize-1 );
  1201. dest[destsize-1] = 0;
  1202. }
  1203. /*
  1204. ================
  1205. idStr::Append
  1206. never goes past bounds or leaves without a terminating 0
  1207. ================
  1208. */
  1209. void idStr::Append( char *dest, int size, const char *src ) {
  1210. int l1;
  1211. l1 = strlen( dest );
  1212. if ( l1 >= size ) {
  1213. idLib::common->Error( "idStr::Append: already overflowed" );
  1214. }
  1215. idStr::Copynz( dest + l1, src, size - l1 );
  1216. }
  1217. /*
  1218. ================
  1219. idStr::LengthWithoutColors
  1220. ================
  1221. */
  1222. int idStr::LengthWithoutColors( const char *s ) {
  1223. int len;
  1224. const char *p;
  1225. if ( !s ) {
  1226. return 0;
  1227. }
  1228. len = 0;
  1229. p = s;
  1230. while( *p ) {
  1231. if ( idStr::IsColor( p ) ) {
  1232. p += 2;
  1233. continue;
  1234. }
  1235. p++;
  1236. len++;
  1237. }
  1238. return len;
  1239. }
  1240. /*
  1241. ================
  1242. idStr::RemoveColors
  1243. ================
  1244. */
  1245. char *idStr::RemoveColors( char *string ) {
  1246. char *d;
  1247. char *s;
  1248. int c;
  1249. s = string;
  1250. d = string;
  1251. while( (c = *s) != 0 ) {
  1252. if ( idStr::IsColor( s ) ) {
  1253. s++;
  1254. }
  1255. else {
  1256. *d++ = c;
  1257. }
  1258. s++;
  1259. }
  1260. *d = '\0';
  1261. return string;
  1262. }
  1263. /*
  1264. ================
  1265. idStr::snPrintf
  1266. ================
  1267. */
  1268. int idStr::snPrintf( char *dest, int size, const char *fmt, ...) {
  1269. int len;
  1270. va_list argptr;
  1271. char buffer[32000]; // big, but small enough to fit in PPC stack
  1272. va_start( argptr, fmt );
  1273. len = vsprintf( buffer, fmt, argptr );
  1274. va_end( argptr );
  1275. if ( len >= sizeof( buffer ) ) {
  1276. idLib::common->Error( "idStr::snPrintf: overflowed buffer" );
  1277. }
  1278. if ( len >= size ) {
  1279. idLib::common->Warning( "idStr::snPrintf: overflow of %i in %i\n", len, size );
  1280. len = size;
  1281. }
  1282. idStr::Copynz( dest, buffer, size );
  1283. return len;
  1284. }
  1285. /*
  1286. ============
  1287. idStr::vsnPrintf
  1288. vsnprintf portability:
  1289. C99 standard: vsnprintf returns the number of characters (excluding the trailing
  1290. '\0') which would have been written to the final string if enough space had been available
  1291. snprintf and vsnprintf do not write more than size bytes (including the trailing '\0')
  1292. win32: _vsnprintf returns the number of characters written, not including the terminating null character,
  1293. or a negative value if an output error occurs. If the number of characters to write exceeds count, then count
  1294. characters are written and -1 is returned and no trailing '\0' is added.
  1295. idStr::vsnPrintf: always appends a trailing '\0', returns number of characters written (not including terminal \0)
  1296. or returns -1 on failure or if the buffer would be overflowed.
  1297. ============
  1298. */
  1299. int idStr::vsnPrintf( char *dest, int size, const char *fmt, va_list argptr ) {
  1300. int ret;
  1301. #ifdef _WIN32
  1302. #undef _vsnprintf
  1303. ret = _vsnprintf( dest, size-1, fmt, argptr );
  1304. #define _vsnprintf use_idStr_vsnPrintf
  1305. #else
  1306. #undef vsnprintf
  1307. ret = vsnprintf( dest, size, fmt, argptr );
  1308. #define vsnprintf use_idStr_vsnPrintf
  1309. #endif
  1310. dest[size-1] = '\0';
  1311. if ( ret < 0 || ret >= size ) {
  1312. return -1;
  1313. }
  1314. return ret;
  1315. }
  1316. /*
  1317. ============
  1318. sprintf
  1319. Sets the value of the string using a printf interface.
  1320. ============
  1321. */
  1322. int sprintf( idStr &string, const char *fmt, ... ) {
  1323. int l;
  1324. va_list argptr;
  1325. char buffer[32000];
  1326. va_start( argptr, fmt );
  1327. l = idStr::vsnPrintf( buffer, sizeof(buffer)-1, fmt, argptr );
  1328. va_end( argptr );
  1329. buffer[sizeof(buffer)-1] = '\0';
  1330. string = buffer;
  1331. return l;
  1332. }
  1333. /*
  1334. ============
  1335. vsprintf
  1336. Sets the value of the string using a vprintf interface.
  1337. ============
  1338. */
  1339. int vsprintf( idStr &string, const char *fmt, va_list argptr ) {
  1340. int l;
  1341. char buffer[32000];
  1342. l = idStr::vsnPrintf( buffer, sizeof(buffer)-1, fmt, argptr );
  1343. buffer[sizeof(buffer)-1] = '\0';
  1344. string = buffer;
  1345. return l;
  1346. }
  1347. /*
  1348. ============
  1349. va
  1350. does a varargs printf into a temp buffer
  1351. NOTE: not thread safe
  1352. ============
  1353. */
  1354. char *va( const char *fmt, ... ) {
  1355. va_list argptr;
  1356. static int index = 0;
  1357. static char string[4][16384]; // in case called by nested functions
  1358. char *buf;
  1359. buf = string[index];
  1360. index = (index + 1) & 3;
  1361. va_start( argptr, fmt );
  1362. vsprintf( buf, fmt, argptr );
  1363. va_end( argptr );
  1364. return buf;
  1365. }
  1366. /*
  1367. ============
  1368. idStr::BestUnit
  1369. ============
  1370. */
  1371. int idStr::BestUnit( const char *format, float value, Measure_t measure ) {
  1372. int unit = 1;
  1373. while ( unit <= 3 && ( 1 << ( unit * 10 ) < value ) ) {
  1374. unit++;
  1375. }
  1376. unit--;
  1377. value /= 1 << ( unit * 10 );
  1378. sprintf( *this, format, value );
  1379. *this += " ";
  1380. *this += units[ measure ][ unit ];
  1381. return unit;
  1382. }
  1383. /*
  1384. ============
  1385. idStr::SetUnit
  1386. ============
  1387. */
  1388. void idStr::SetUnit( const char *format, float value, int unit, Measure_t measure ) {
  1389. value /= 1 << ( unit * 10 );
  1390. sprintf( *this, format, value );
  1391. *this += " ";
  1392. *this += units[ measure ][ unit ];
  1393. }
  1394. /*
  1395. ================
  1396. idStr::InitMemory
  1397. ================
  1398. */
  1399. void idStr::InitMemory( void ) {
  1400. #ifdef USE_STRING_DATA_ALLOCATOR
  1401. stringDataAllocator.Init();
  1402. #endif
  1403. }
  1404. /*
  1405. ================
  1406. idStr::ShutdownMemory
  1407. ================
  1408. */
  1409. void idStr::ShutdownMemory( void ) {
  1410. #ifdef USE_STRING_DATA_ALLOCATOR
  1411. stringDataAllocator.Shutdown();
  1412. #endif
  1413. }
  1414. /*
  1415. ================
  1416. idStr::PurgeMemory
  1417. ================
  1418. */
  1419. void idStr::PurgeMemory( void ) {
  1420. #ifdef USE_STRING_DATA_ALLOCATOR
  1421. stringDataAllocator.FreeEmptyBaseBlocks();
  1422. #endif
  1423. }
  1424. /*
  1425. ================
  1426. idStr::ShowMemoryUsage_f
  1427. ================
  1428. */
  1429. void idStr::ShowMemoryUsage_f( const idCmdArgs &args ) {
  1430. #ifdef USE_STRING_DATA_ALLOCATOR
  1431. idLib::common->Printf( "%6d KB string memory (%d KB free in %d blocks, %d empty base blocks)\n",
  1432. stringDataAllocator.GetBaseBlockMemory() >> 10, stringDataAllocator.GetFreeBlockMemory() >> 10,
  1433. stringDataAllocator.GetNumFreeBlocks(), stringDataAllocator.GetNumEmptyBaseBlocks() );
  1434. #endif
  1435. }
  1436. /*
  1437. ================
  1438. idStr::FormatNumber
  1439. ================
  1440. */
  1441. struct formatList_t {
  1442. int gran;
  1443. int count;
  1444. };
  1445. // elements of list need to decend in size
  1446. formatList_t formatList[] = {
  1447. { 1000000000, 0 },
  1448. { 1000000, 0 },
  1449. { 1000, 0 }
  1450. };
  1451. int numFormatList = sizeof(formatList) / sizeof( formatList[0] );
  1452. idStr idStr::FormatNumber( int number ) {
  1453. idStr string;
  1454. bool hit;
  1455. // reset
  1456. for ( int i = 0; i < numFormatList; i++ ) {
  1457. formatList_t *li = formatList + i;
  1458. li->count = 0;
  1459. }
  1460. // main loop
  1461. do {
  1462. hit = false;
  1463. for ( int i = 0; i < numFormatList; i++ ) {
  1464. formatList_t *li = formatList + i;
  1465. if ( number >= li->gran ) {
  1466. li->count++;
  1467. number -= li->gran;
  1468. hit = true;
  1469. break;
  1470. }
  1471. }
  1472. } while ( hit );
  1473. // print out
  1474. bool found = false;
  1475. for ( int i = 0; i < numFormatList; i++ ) {
  1476. formatList_t *li = formatList + i;
  1477. if ( li->count ) {
  1478. if ( !found ) {
  1479. string += va( "%i,", li->count );
  1480. } else {
  1481. string += va( "%3.3i,", li->count );
  1482. }
  1483. found = true;
  1484. }
  1485. else if ( found ) {
  1486. string += va( "%3.3i,", li->count );
  1487. }
  1488. }
  1489. if ( found ) {
  1490. string += va( "%3.3i", number );
  1491. }
  1492. else {
  1493. string += va( "%i", number );
  1494. }
  1495. // pad to proper size
  1496. int count = 11 - string.Length();
  1497. for ( int i = 0; i < count; i++ ) {
  1498. string.Insert( " ", 0 );
  1499. }
  1500. return string;
  1501. }