q_shared.cpp 21 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214
  1. // q_shared.c -- stateless support routines that are included in each code dll
  2. // leave this at the top for PCH reasons...
  3. #include "common_headers.h"
  4. //#include "q_shared.h"
  5. float Com_Clamp( float min, float max, float value ) {
  6. if ( value < min ) {
  7. return min;
  8. }
  9. if ( value > max ) {
  10. return max;
  11. }
  12. return value;
  13. }
  14. /*
  15. ============
  16. COM_SkipPath
  17. ============
  18. */
  19. char *COM_SkipPath (char *pathname)
  20. {
  21. char *last;
  22. last = pathname;
  23. while (*pathname)
  24. {
  25. if (*pathname=='/')
  26. last = pathname+1;
  27. pathname++;
  28. }
  29. return last;
  30. }
  31. /*
  32. ============
  33. COM_StripExtension
  34. ============
  35. */
  36. void COM_StripExtension( const char *in, char *out ) {
  37. while ( *in && *in != '.' ) {
  38. *out++ = *in++;
  39. }
  40. *out = 0;
  41. }
  42. /*
  43. ==================
  44. COM_DefaultExtension
  45. ==================
  46. */
  47. void COM_DefaultExtension (char *path, int maxSize, const char *extension ) {
  48. char *src;
  49. if (path[0]) // or the strlen()-1 stuff gets a bad ptr for blank string
  50. {
  51. //
  52. // if path doesn't have a .EXT, append extension
  53. // (extension should include the .)
  54. //
  55. src = path + strlen(path) - 1;
  56. while (*src != '/' && src != path) {
  57. if ( *src == '.' ) {
  58. return; // it has an extension
  59. }
  60. src--;
  61. }
  62. }
  63. if (strlen(path)+strlen(extension) >= maxSize)
  64. {
  65. Com_Printf ("COM_DefaultExtension: overflow adding %s to %s\n", extension, path);
  66. }
  67. else
  68. {
  69. strcat(path, extension);
  70. }
  71. }
  72. /*
  73. ============================================================================
  74. BYTE ORDER FUNCTIONS
  75. ============================================================================
  76. */
  77. // can't just use function pointers, or dll linkage can
  78. // mess up when qcommon is included in multiple places
  79. static short (*_BigShort) (short l);
  80. static short (*_LittleShort) (short l);
  81. static int (*_BigLong) (int l);
  82. static int (*_LittleLong) (int l);
  83. static float (*_BigFloat) (float l);
  84. static float (*_LittleFloat) (float l);
  85. #ifdef _M_IX86
  86. //
  87. // optimised stuff for Intel, since most of our data is in that format anyway...
  88. //
  89. short BigShort(short l){return _BigShort(l);}
  90. int BigLong (int l) {return _BigLong(l);}
  91. float BigFloat (float l) {return _BigFloat(l);}
  92. //short LittleShort(short l) {return _LittleShort(l);} // these are now macros in q_shared.h
  93. //int LittleLong (int l) {return _LittleLong(l);} //
  94. //float LittleFloat (float l) {return _LittleFloat(l);} //
  95. //
  96. #else
  97. //
  98. // standard smart-swap code...
  99. //
  100. short BigShort(short l){return _BigShort(l);}
  101. short LittleShort(short l) {return _LittleShort(l);}
  102. int BigLong (int l) {return _BigLong(l);}
  103. int LittleLong (int l) {return _LittleLong(l);}
  104. float BigFloat (float l) {return _BigFloat(l);}
  105. float LittleFloat (float l) {return _LittleFloat(l);}
  106. //
  107. #endif
  108. short ShortSwap (short l)
  109. {
  110. byte b1,b2;
  111. b1 = l&255;
  112. b2 = (l>>8)&255;
  113. return (b1<<8) + b2;
  114. }
  115. short ShortNoSwap (short l)
  116. {
  117. return l;
  118. }
  119. int LongSwap (int l)
  120. {
  121. byte b1,b2,b3,b4;
  122. b1 = l&255;
  123. b2 = (l>>8)&255;
  124. b3 = (l>>16)&255;
  125. b4 = (l>>24)&255;
  126. return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
  127. }
  128. int LongNoSwap (int l)
  129. {
  130. return l;
  131. }
  132. float FloatSwap (float f)
  133. {
  134. union
  135. {
  136. float f;
  137. byte b[4];
  138. } dat1, dat2;
  139. dat1.f = f;
  140. dat2.b[0] = dat1.b[3];
  141. dat2.b[1] = dat1.b[2];
  142. dat2.b[2] = dat1.b[1];
  143. dat2.b[3] = dat1.b[0];
  144. return dat2.f;
  145. }
  146. float FloatNoSwap (float f)
  147. {
  148. return f;
  149. }
  150. /*
  151. ================
  152. Swap_Init
  153. ================
  154. */
  155. void Swap_Init (void)
  156. {
  157. byte swaptest[2] = {1,0};
  158. // set the byte swapping variables in a portable manner
  159. if ( *(short *)swaptest == 1)
  160. {
  161. _BigShort = ShortSwap;
  162. _LittleShort = ShortNoSwap;
  163. _BigLong = LongSwap;
  164. _LittleLong = LongNoSwap;
  165. _BigFloat = FloatSwap;
  166. _LittleFloat = FloatNoSwap;
  167. }
  168. else
  169. {
  170. _BigShort = ShortNoSwap;
  171. _LittleShort = ShortSwap;
  172. _BigLong = LongNoSwap;
  173. _LittleLong = LongSwap;
  174. _BigFloat = FloatNoSwap;
  175. _LittleFloat = FloatSwap;
  176. }
  177. }
  178. /*
  179. ============================================================================
  180. PARSING
  181. ============================================================================
  182. */
  183. static char com_token[MAX_TOKEN_CHARS];
  184. //JLFCALLOUT MPNOTUSED
  185. //#include functionality for files
  186. int parseDataCount = -1;
  187. parseData_t parseData[2];
  188. void COM_ParseInit( void )
  189. {
  190. memset(&(parseData[0]),0,sizeof(parseData_t));
  191. memset(&(parseData[1]),0,sizeof(parseData_t));
  192. COM_BeginParseSession();
  193. }
  194. #ifdef _XBOX
  195. void COM_BeginParseSession( bool nested )
  196. {
  197. if (nested)
  198. parseDataCount =1;
  199. else
  200. parseDataCount = 0;
  201. parseData[parseDataCount].com_lines = 1;
  202. }
  203. #else
  204. void COM_BeginParseSession( void )
  205. {
  206. parseDataCount =0;
  207. parseData[parseDataCount].com_lines = 1;
  208. }
  209. #endif
  210. int COM_GetCurrentParseLine( int index )
  211. {
  212. return parseData[parseDataCount].com_lines;
  213. }
  214. char *COM_Parse( const char **data_p )
  215. {
  216. return COM_ParseExt( data_p, qtrue );
  217. }
  218. /*
  219. ==============
  220. COM_Parse
  221. Parse a token out of a string
  222. Will never return NULL, just empty strings
  223. If "allowLineBreaks" is qtrue then an empty
  224. string will be returned if the next token is
  225. a newline.
  226. ==============
  227. */
  228. const char *SkipWhitespace( const char *data, qboolean *hasNewLines )
  229. {
  230. int c;
  231. while( (c = *data) <= ' ')
  232. {
  233. if( !c )
  234. {
  235. return NULL;
  236. }
  237. if( c == '\n' )
  238. {
  239. parseData[parseDataCount].com_lines++;
  240. *hasNewLines = qtrue;
  241. }
  242. data++;
  243. }
  244. return data;
  245. }
  246. char *COM_ParseExt( const char **data_p, qboolean allowLineBreaks )
  247. {
  248. int c = 0, len;
  249. qboolean hasNewLines = qfalse;
  250. const char *data;
  251. data = *data_p;
  252. len = 0;
  253. com_token[0] = 0;
  254. // make sure incoming data is valid
  255. if ( !data )
  256. {
  257. *data_p = NULL;
  258. return com_token;
  259. }
  260. while ( 1 )
  261. {
  262. // skip whitespace
  263. data = SkipWhitespace( data, &hasNewLines );
  264. if ( !data )
  265. {
  266. *data_p = NULL;
  267. return com_token;
  268. }
  269. if ( hasNewLines && !allowLineBreaks )
  270. {
  271. *data_p = data;
  272. return com_token;
  273. }
  274. c = *data;
  275. // skip double slash comments
  276. if ( c == '/' && data[1] == '/' )
  277. {
  278. while (*data && *data != '\n') // Advance to the end of the line
  279. {
  280. data++;
  281. }
  282. }
  283. // skip /* */ comments
  284. else if ( c=='/' && data[1] == '*' )
  285. {
  286. while ( *data && ( *data != '*' || data[1] != '/' ) ) // Advance to the */ characters
  287. {
  288. data++;
  289. }
  290. if ( *data )
  291. {
  292. data += 2;
  293. }
  294. }
  295. else
  296. {
  297. break;
  298. }
  299. }
  300. // handle quoted strings
  301. if (c == '\"')
  302. {
  303. data++;
  304. while (1)
  305. {
  306. c = *data++;
  307. if (c=='\"' || !c)
  308. {
  309. com_token[len] = 0;
  310. *data_p = ( char * ) data;
  311. return com_token;
  312. }
  313. if (len < MAX_TOKEN_CHARS)
  314. {
  315. com_token[len] = c;
  316. len++;
  317. }
  318. }
  319. }
  320. // parse a regular word
  321. do
  322. {
  323. if (len < MAX_TOKEN_CHARS)
  324. {
  325. com_token[len] = c;
  326. len++;
  327. }
  328. data++;
  329. c = *data;
  330. if ( c == '\n' )
  331. {
  332. parseData[parseDataCount].com_lines++;
  333. }
  334. } while (c>32);
  335. if (len == MAX_TOKEN_CHARS)
  336. {
  337. Com_Printf ("Token exceeded %i chars, discarded.\n", MAX_TOKEN_CHARS);
  338. len = 0;
  339. }
  340. com_token[len] = 0;
  341. *data_p = ( char * ) data;
  342. return com_token;
  343. }
  344. /*
  345. ==============
  346. COM_Compress
  347. remove blank space and comments from source
  348. ==============
  349. */
  350. int COM_Compress( char *data_p ) {
  351. char *in, *out;
  352. int c;
  353. qboolean newline = qfalse, whitespace = qfalse;
  354. in = out = data_p;
  355. if (in) {
  356. while ((c = *in) != 0) {
  357. // skip double slash comments
  358. if ( c == '/' && in[1] == '/' ) {
  359. while (*in && *in != '\n') {
  360. in++;
  361. }
  362. // skip /* */ comments
  363. } else if ( c == '/' && in[1] == '*' ) {
  364. while ( *in && ( *in != '*' || in[1] != '/' ) )
  365. in++;
  366. if ( *in )
  367. in += 2;
  368. // record when we hit a newline
  369. } else if ( c == '\n' || c == '\r' ) {
  370. newline = qtrue;
  371. in++;
  372. // record when we hit whitespace
  373. } else if ( c == ' ' || c == '\t') {
  374. whitespace = qtrue;
  375. in++;
  376. // an actual token
  377. } else {
  378. // if we have a pending newline, emit it (and it counts as whitespace)
  379. if (newline) {
  380. *out++ = '\n';
  381. newline = qfalse;
  382. whitespace = qfalse;
  383. } if (whitespace) {
  384. *out++ = ' ';
  385. whitespace = qfalse;
  386. }
  387. // copy quoted strings unmolested
  388. if (c == '"') {
  389. *out++ = c;
  390. in++;
  391. while (1) {
  392. c = *in;
  393. if (c && c != '"') {
  394. *out++ = c;
  395. in++;
  396. } else {
  397. break;
  398. }
  399. }
  400. if (c == '"') {
  401. *out++ = c;
  402. in++;
  403. }
  404. } else {
  405. *out = c;
  406. out++;
  407. in++;
  408. }
  409. }
  410. }
  411. }
  412. *out = 0;
  413. return out - data_p;
  414. }
  415. /*
  416. ==================
  417. COM_MatchToken
  418. ==================
  419. */
  420. void COM_MatchToken( const char **buf_p, const char *match ) {
  421. const char *token;
  422. token = COM_Parse( buf_p );
  423. if ( strcmp( token, match ) )
  424. {
  425. Com_Error( ERR_DROP, "MatchToken: %s != %s", token, match );
  426. }
  427. }
  428. /*
  429. =================
  430. SkipBracedSection
  431. The next token should be an open brace.
  432. Skips until a matching close brace is found.
  433. Internal brace depths are properly skipped.
  434. =================
  435. */
  436. void SkipBracedSection ( const char **program) {
  437. const char *token;
  438. int depth=0;
  439. if (com_token[0]=='{') { //for tr_shader which just ate the brace
  440. depth = 1;
  441. }
  442. do {
  443. token = COM_ParseExt( program, qtrue );
  444. if( token[1] == 0 ) {
  445. if( token[0] == '{' ) {
  446. depth++;
  447. }
  448. else if( token[0] == '}' ) {
  449. depth--;
  450. }
  451. }
  452. } while (depth && *program);
  453. }
  454. /*
  455. =================
  456. SkipRestOfLine
  457. =================
  458. */
  459. void SkipRestOfLine ( const char **data ) {
  460. const char *p;
  461. int c;
  462. p = *data;
  463. while ( (c = *p++) != 0 ) {
  464. if ( c == '\n' ) {
  465. parseData[parseDataCount].com_lines++;
  466. break;
  467. }
  468. }
  469. *data = p;
  470. }
  471. void Parse1DMatrix ( const char **buf_p, int x, float *m) {
  472. const char *token;
  473. int i;
  474. COM_MatchToken( buf_p, "(" );
  475. for (i = 0 ; i < x ; i++) {
  476. token = COM_Parse(buf_p);
  477. m[i] = atof(token);
  478. }
  479. COM_MatchToken( buf_p, ")" );
  480. }
  481. void Parse2DMatrix ( const char **buf_p, int y, int x, float *m) {
  482. int i;
  483. COM_MatchToken( buf_p, "(" );
  484. for (i = 0 ; i < y ; i++) {
  485. Parse1DMatrix (buf_p, x, m + i * x);
  486. }
  487. COM_MatchToken( buf_p, ")" );
  488. }
  489. void Parse3DMatrix ( const char **buf_p, int z, int y, int x, float *m) {
  490. int i;
  491. COM_MatchToken( buf_p, "(" );
  492. for (i = 0 ; i < z ; i++) {
  493. Parse2DMatrix (buf_p, y, x, m + i * x*y);
  494. }
  495. COM_MatchToken( buf_p, ")" );
  496. }
  497. /*
  498. ============================================================================
  499. LIBRARY REPLACEMENT FUNCTIONS
  500. ============================================================================
  501. */
  502. int Q_isprint( int c )
  503. {
  504. if ( c >= 0x20 && c <= 0x7E )
  505. return ( 1 );
  506. return ( 0 );
  507. }
  508. int Q_islower( int c )
  509. {
  510. if (c >= 'a' && c <= 'z')
  511. return ( 1 );
  512. return ( 0 );
  513. }
  514. int Q_isupper( int c )
  515. {
  516. if (c >= 'A' && c <= 'Z')
  517. return ( 1 );
  518. return ( 0 );
  519. }
  520. int Q_isalpha( int c )
  521. {
  522. if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
  523. return ( 1 );
  524. return ( 0 );
  525. }
  526. /*
  527. char* Q_strrchr( const char* string, int c )
  528. {
  529. char cc = c;
  530. char *s;
  531. char *sp=(char *)0;
  532. s = (char*)string;
  533. while (*s)
  534. {
  535. if (*s == cc)
  536. sp = s;
  537. s++;
  538. }
  539. if (cc == 0)
  540. sp = s;
  541. return sp;
  542. }
  543. */
  544. /*
  545. =============
  546. Q_strncpyz
  547. Safe strncpy that ensures a trailing zero
  548. =============
  549. */
  550. void Q_strncpyz( char *dest, const char *src, int destsize, qboolean bBarfIfTooLong/* = qfalse */ )
  551. {
  552. if ( !src ) {
  553. Com_Error( ERR_FATAL, "Q_strncpyz: NULL src" );
  554. }
  555. if ( destsize < 1 ) {
  556. Com_Error(ERR_FATAL,"Q_strncpyz: destsize < 1" );
  557. }
  558. if (bBarfIfTooLong)
  559. {
  560. if ( strlen(src)+1 > destsize)
  561. {
  562. Com_Error(ERR_FATAL,"String dest buffer too small to hold string \"%s\" %d > %d\n(source addr = %x, dest addr = %x",src, strlen(src)+1, destsize, src, dest);
  563. }
  564. }
  565. strncpy( dest, src, destsize-1 );
  566. dest[destsize-1] = 0;
  567. }
  568. /*
  569. int Q_stricmpn (const char *s1, const char *s2, int n) {
  570. int c1, c2;
  571. do {
  572. c1 = *s1++;
  573. c2 = *s2++;
  574. if (!n--) {
  575. return 0; // strings are equal until end point
  576. }
  577. if (c1 != c2) {
  578. if (c1 >= 'a' && c1 <= 'z') {
  579. c1 -= ('a' - 'A');
  580. }
  581. if (c2 >= 'a' && c2 <= 'z') {
  582. c2 -= ('a' - 'A');
  583. }
  584. if (c1 != c2) {
  585. return c1 < c2 ? -1 : 1;
  586. }
  587. }
  588. } while (c1);
  589. return 0; // strings are equal
  590. }
  591. int Q_strncmp (const char *s1, const char *s2, int n) {
  592. int c1, c2;
  593. do {
  594. c1 = *s1++;
  595. c2 = *s2++;
  596. if (!n--) {
  597. return 0; // strings are equal until end point
  598. }
  599. if (c1 != c2) {
  600. return c1 < c2 ? -1 : 1;
  601. }
  602. } while (c1);
  603. return 0; // strings are equal
  604. }
  605. char *Q_strlwr( char *s1 ) {
  606. char *s;
  607. s = s1;
  608. while ( *s ) {
  609. *s = tolower(*s);
  610. s++;
  611. }
  612. return s1;
  613. }
  614. char *Q_strupr( char *s1 ) {
  615. char *s;
  616. s = s1;
  617. while ( *s ) {
  618. *s = toupper(*s);
  619. s++;
  620. }
  621. return s1;
  622. }
  623. */
  624. // never goes past bounds or leaves without a terminating 0
  625. void Q_strcat( char *dest, int size, const char *src ) {
  626. int l1;
  627. l1 = strlen( dest );
  628. if ( l1 >= size ) {
  629. Com_Error( ERR_FATAL, "Q_strcat: already overflowed" );
  630. }
  631. if ( strlen(src)+1 > size - l1)
  632. { //do the error here instead of in Q_strncpyz to get a meaningful msg
  633. Com_Error(ERR_FATAL,"Q_strcat: cannot append \"%s\" to \"%s\"", src, dest);
  634. }
  635. Q_strncpyz( dest + l1, src, size - l1 );
  636. }
  637. int Q_PrintStrlen( const char *string ) {
  638. int len;
  639. const char *p;
  640. if( !string ) {
  641. return 0;
  642. }
  643. len = 0;
  644. p = string;
  645. while( *p ) {
  646. if( Q_IsColorString( p ) ) {
  647. p += 2;
  648. continue;
  649. }
  650. p++;
  651. len++;
  652. }
  653. return len;
  654. }
  655. char *Q_CleanStr( char *string ) {
  656. char* d;
  657. char* s;
  658. int c;
  659. s = string;
  660. d = string;
  661. while ((c = *s) != 0 ) {
  662. if ( Q_IsColorString( s ) ) {
  663. s++;
  664. }
  665. else if ( c >= 0x20 && c <= 0x7E ) {
  666. *d++ = c;
  667. }
  668. s++;
  669. }
  670. *d = '\0';
  671. return string;
  672. }
  673. void QDECL Com_sprintf( char *dest, int size, const char *fmt, ...) {
  674. int len;
  675. va_list argptr;
  676. char bigbuffer[1024];
  677. va_start (argptr,fmt);
  678. len = vsprintf (bigbuffer,fmt,argptr);
  679. va_end (argptr);
  680. if ( len >= sizeof( bigbuffer ) ) {
  681. Com_Error( ERR_FATAL, "Com_sprintf: overflowed bigbuffer" );
  682. }
  683. if (len >= size) {
  684. Com_Printf ("Com_sprintf: overflow of %i in %i\n", len, size);
  685. }
  686. Q_strncpyz (dest, bigbuffer, size );
  687. }
  688. /*
  689. ============
  690. va
  691. does a varargs printf into a temp buffer, so I don't need to have
  692. varargs versions of all text functions.
  693. FIXME: make this buffer size safe someday
  694. ============
  695. */
  696. char * QDECL va( const char *format, ... ) {
  697. int len;
  698. va_list argptr;
  699. static char buffers[4][1024]; // in case va is called by nested functions
  700. static int index = 0;
  701. char *const buf = buffers[index % 4];
  702. index++;
  703. va_start (argptr, format);
  704. len = vsprintf (buf, format,argptr);
  705. va_end (argptr);
  706. assert(len<sizeof(buffers[0]));
  707. return buf;
  708. }
  709. /*
  710. =====================================================================
  711. INFO STRINGS
  712. =====================================================================
  713. */
  714. /*
  715. ===============
  716. Info_ValueForKey
  717. Searches the string for the given
  718. key and returns the associated value, or an empty string.
  719. FIXME: overflow check?
  720. ===============
  721. */
  722. char *Info_ValueForKey( const char *s, const char *key ) {
  723. char pkey[MAX_INFO_KEY];
  724. static char value[2][MAX_INFO_VALUE]; // use two buffers so compares
  725. // work without stomping on each other
  726. static int valueindex = 0;
  727. char *o;
  728. if ( !s || !key ) {
  729. return "";
  730. }
  731. if ( strlen( s ) >= MAX_INFO_STRING ) {
  732. Com_Error( ERR_DROP, "Info_ValueForKey: oversize infostring" );
  733. }
  734. valueindex ^= 1;
  735. if (*s == '\\')
  736. s++;
  737. while (1)
  738. {
  739. o = pkey;
  740. while (*s != '\\')
  741. {
  742. if (!*s)
  743. return "";
  744. *o++ = *s++;
  745. }
  746. *o = 0;
  747. s++;
  748. o = value[valueindex];
  749. while (*s != '\\' && *s)
  750. {
  751. *o++ = *s++;
  752. }
  753. *o = 0;
  754. if (!Q_stricmp (key, pkey) )
  755. return value[valueindex];
  756. if (!*s)
  757. break;
  758. s++;
  759. }
  760. return "";
  761. }
  762. /*
  763. ===================
  764. Info_NextPair
  765. Used to itterate through all the key/value pairs in an info string
  766. ===================
  767. */
  768. void Info_NextPair( const char **head, char key[MAX_INFO_KEY], char value[MAX_INFO_VALUE] ) {
  769. char *o;
  770. const char *s;
  771. s = *head;
  772. if ( *s == '\\' ) {
  773. s++;
  774. }
  775. key[0] = 0;
  776. value[0] = 0;
  777. o = key;
  778. while ( *s != '\\' ) {
  779. if ( !*s ) {
  780. *o = 0;
  781. *head = s;
  782. return;
  783. }
  784. *o++ = *s++;
  785. }
  786. *o = 0;
  787. s++;
  788. o = value;
  789. while ( *s != '\\' && *s ) {
  790. *o++ = *s++;
  791. }
  792. *o = 0;
  793. *head = s;
  794. }
  795. /*
  796. ===================
  797. Info_RemoveKey
  798. ===================
  799. */
  800. void Info_RemoveKey( char *s, const char *key ) {
  801. char *start;
  802. char pkey[MAX_INFO_KEY];
  803. char value[MAX_INFO_VALUE];
  804. char *o;
  805. if ( strlen( s ) >= MAX_INFO_STRING ) {
  806. Com_Error( ERR_DROP, "Info_RemoveKey: oversize infostring" );
  807. }
  808. if (strchr (key, '\\')) {
  809. return;
  810. }
  811. while (1)
  812. {
  813. start = s;
  814. if (*s == '\\')
  815. s++;
  816. o = pkey;
  817. while (*s != '\\')
  818. {
  819. if (!*s)
  820. return;
  821. *o++ = *s++;
  822. }
  823. *o = 0;
  824. s++;
  825. o = value;
  826. while (*s != '\\' && *s)
  827. {
  828. if (!*s)
  829. return;
  830. *o++ = *s++;
  831. }
  832. *o = 0;
  833. if (!strcmp (key, pkey) )
  834. {
  835. strcpy (start, s); // remove this part
  836. return;
  837. }
  838. if (!*s)
  839. return;
  840. }
  841. }
  842. /*
  843. ==================
  844. Info_Validate
  845. Some characters are illegal in info strings because they
  846. can mess up the server's parsing
  847. ==================
  848. */
  849. qboolean Info_Validate( const char *s ) {
  850. if ( strchr( s, '\"' ) ) {
  851. return qfalse;
  852. }
  853. if ( strchr( s, ';' ) ) {
  854. return qfalse;
  855. }
  856. return qtrue;
  857. }
  858. /*
  859. ==================
  860. Info_SetValueForKey
  861. Changes or adds a key/value pair
  862. ==================
  863. */
  864. void Info_SetValueForKey( char *s, const char *key, const char *value ) {
  865. char newi[MAX_INFO_STRING];
  866. if ( strlen( s ) >= MAX_INFO_STRING ) {
  867. Com_Error( ERR_DROP, "Info_SetValueForKey: oversize infostring" );
  868. }
  869. if (strchr (key, '\\') || strchr (value, '\\'))
  870. {
  871. Com_Printf ("Can't use keys or values with a \\(%s, %s)\n",key,value);
  872. return;
  873. }
  874. if (strchr (key, ';') || strchr (value, ';'))
  875. {
  876. Com_Printf ("Can't use keys or values with a semicolon(%s, %s)\n",key,value);
  877. return;
  878. }
  879. if (strchr (key, '\"') || strchr (value, '\"'))
  880. {
  881. Com_Printf ("Can't use keys or values with a \"(%s, %s)\n",key,value);
  882. return;
  883. }
  884. Info_RemoveKey (s, key);
  885. if (!value || !strlen(value))
  886. return;
  887. Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value);
  888. if (strlen(newi) + strlen(s) > MAX_INFO_STRING)
  889. {
  890. Com_Printf ("Info string length exceeded\n");
  891. return;
  892. }
  893. strcat (s, newi);
  894. }
  895. /*
  896. ========================================================================
  897. String ID Tables
  898. ========================================================================
  899. */
  900. /*
  901. -------------------------
  902. GetIDForString
  903. -------------------------
  904. */
  905. #define VALIDSTRING( a ) ( ( a != NULL ) && ( a[0] != NULL ) )
  906. int GetIDForString ( const stringID_table_t *table, const char *string )
  907. {
  908. int index = 0;
  909. while ( VALIDSTRING( table[index].name ) )
  910. {
  911. if ( !Q_stricmp( table[index].name, string ) )
  912. return table[index].id;
  913. index++;
  914. }
  915. return -1;
  916. }
  917. /*
  918. -------------------------
  919. GetStringForID
  920. -------------------------
  921. */
  922. const char *GetStringForID( const stringID_table_t *table, int id )
  923. {
  924. int index = 0;
  925. while ( VALIDSTRING( table[index].name ) )
  926. {
  927. if ( table[index].id == id )
  928. return table[index].name;
  929. index++;
  930. }
  931. return NULL;
  932. }
  933. /*
  934. ===============
  935. COM_ParseString
  936. ===============
  937. */
  938. qboolean COM_ParseString( const char **data, const char **s )
  939. {
  940. // *s = COM_ParseExt( data, qtrue );
  941. *s = COM_ParseExt( data, qfalse );
  942. if ( s[0] == 0 )
  943. {
  944. Com_Printf("unexpected EOF in COM_ParseString\n");
  945. return qtrue;
  946. }
  947. return qfalse;
  948. }
  949. /*
  950. ===============
  951. COM_ParseInt
  952. ===============
  953. */
  954. qboolean COM_ParseInt( const char **data, int *i )
  955. {
  956. const char *token;
  957. token = COM_ParseExt( data, qfalse );
  958. if ( token[0] == 0 )
  959. {
  960. Com_Printf( "unexpected EOF in COM_ParseInt\n" );
  961. return qtrue;
  962. }
  963. *i = atoi( token );
  964. return qfalse;
  965. }
  966. /*
  967. ===============
  968. COM_ParseFloat
  969. ===============
  970. */
  971. qboolean COM_ParseFloat( const char **data, float *f )
  972. {
  973. const char *token;
  974. token = COM_ParseExt( data, qfalse );
  975. if ( token[0] == 0 )
  976. {
  977. Com_Printf( "unexpected EOF in COM_ParseFloat\n" );
  978. return qtrue;
  979. }
  980. *f = atof( token );
  981. return qfalse;
  982. }
  983. /*
  984. ===============
  985. COM_ParseVec4
  986. ===============
  987. */
  988. qboolean COM_ParseVec4( const char **buffer, vec4_t *c)
  989. {
  990. int i;
  991. float f;
  992. for (i = 0; i < 4; i++)
  993. {
  994. if (COM_ParseFloat(buffer, &f))
  995. {
  996. return qtrue;
  997. }
  998. (*c)[i] = f;
  999. }
  1000. return qfalse;
  1001. }
  1002. // end