q_shared.c (22536B)
1 /* 2 =========================================================================== 3 Copyright (C) 1999-2005 Id Software, Inc. 4 5 This file is part of Quake III Arena source code. 6 7 Quake III Arena source code is free software; you can redistribute it 8 and/or modify it under the terms of the GNU General Public License as 9 published by the Free Software Foundation; either version 2 of the License, 10 or (at your option) any later version. 11 12 Quake III Arena source code is distributed in the hope that it will be 13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with Foobar; if not, write to the Free Software 19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 =========================================================================== 21 */ 22 // 23 // q_shared.c -- stateless support routines that are included in each code dll 24 #include "q_shared.h" 25 26 float Com_Clamp( float min, float max, float value ) { 27 if ( value < min ) { 28 return min; 29 } 30 if ( value > max ) { 31 return max; 32 } 33 return value; 34 } 35 36 37 /* 38 ============ 39 COM_SkipPath 40 ============ 41 */ 42 char *COM_SkipPath (char *pathname) 43 { 44 char *last; 45 46 last = pathname; 47 while (*pathname) 48 { 49 if (*pathname=='/') 50 last = pathname+1; 51 pathname++; 52 } 53 return last; 54 } 55 56 /* 57 ============ 58 COM_StripExtension 59 ============ 60 */ 61 void COM_StripExtension( const char *in, char *out ) { 62 while ( *in && *in != '.' ) { 63 *out++ = *in++; 64 } 65 *out = 0; 66 } 67 68 69 /* 70 ================== 71 COM_DefaultExtension 72 ================== 73 */ 74 void COM_DefaultExtension (char *path, int maxSize, const char *extension ) { 75 char oldPath[MAX_QPATH]; 76 char *src; 77 78 // 79 // if path doesn't have a .EXT, append extension 80 // (extension should include the .) 81 // 82 src = path + strlen(path) - 1; 83 84 while (*src != '/' && src != path) { 85 if ( *src == '.' ) { 86 return; // it has an extension 87 } 88 src--; 89 } 90 91 Q_strncpyz( oldPath, path, sizeof( oldPath ) ); 92 Com_sprintf( path, maxSize, "%s%s", oldPath, extension ); 93 } 94 95 /* 96 ============================================================================ 97 98 BYTE ORDER FUNCTIONS 99 100 ============================================================================ 101 */ 102 /* 103 // can't just use function pointers, or dll linkage can 104 // mess up when qcommon is included in multiple places 105 static short (*_BigShort) (short l); 106 static short (*_LittleShort) (short l); 107 static int (*_BigLong) (int l); 108 static int (*_LittleLong) (int l); 109 static qint64 (*_BigLong64) (qint64 l); 110 static qint64 (*_LittleLong64) (qint64 l); 111 static float (*_BigFloat) (const float *l); 112 static float (*_LittleFloat) (const float *l); 113 114 short BigShort(short l){return _BigShort(l);} 115 short LittleShort(short l) {return _LittleShort(l);} 116 int BigLong (int l) {return _BigLong(l);} 117 int LittleLong (int l) {return _LittleLong(l);} 118 qint64 BigLong64 (qint64 l) {return _BigLong64(l);} 119 qint64 LittleLong64 (qint64 l) {return _LittleLong64(l);} 120 float BigFloat (const float *l) {return _BigFloat(l);} 121 float LittleFloat (const float *l) {return _LittleFloat(l);} 122 */ 123 124 short ShortSwap (short l) 125 { 126 byte b1,b2; 127 128 b1 = l&255; 129 b2 = (l>>8)&255; 130 131 return (b1<<8) + b2; 132 } 133 134 short ShortNoSwap (short l) 135 { 136 return l; 137 } 138 139 int LongSwap (int l) 140 { 141 byte b1,b2,b3,b4; 142 143 b1 = l&255; 144 b2 = (l>>8)&255; 145 b3 = (l>>16)&255; 146 b4 = (l>>24)&255; 147 148 return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; 149 } 150 151 int LongNoSwap (int l) 152 { 153 return l; 154 } 155 156 qint64 Long64Swap (qint64 ll) 157 { 158 qint64 result; 159 160 result.b0 = ll.b7; 161 result.b1 = ll.b6; 162 result.b2 = ll.b5; 163 result.b3 = ll.b4; 164 result.b4 = ll.b3; 165 result.b5 = ll.b2; 166 result.b6 = ll.b1; 167 result.b7 = ll.b0; 168 169 return result; 170 } 171 172 qint64 Long64NoSwap (qint64 ll) 173 { 174 return ll; 175 } 176 177 typedef union { 178 float f; 179 unsigned int i; 180 } _FloatByteUnion; 181 182 float FloatSwap (const float *f) { 183 const _FloatByteUnion *in; 184 _FloatByteUnion out; 185 186 in = (_FloatByteUnion *)f; 187 out.i = LongSwap(in->i); 188 189 return out.f; 190 } 191 192 float FloatNoSwap (const float *f) 193 { 194 return *f; 195 } 196 197 /* 198 ================ 199 Swap_Init 200 ================ 201 */ 202 /* 203 void Swap_Init (void) 204 { 205 byte swaptest[2] = {1,0}; 206 207 // set the byte swapping variables in a portable manner 208 if ( *(short *)swaptest == 1) 209 { 210 _BigShort = ShortSwap; 211 _LittleShort = ShortNoSwap; 212 _BigLong = LongSwap; 213 _LittleLong = LongNoSwap; 214 _BigLong64 = Long64Swap; 215 _LittleLong64 = Long64NoSwap; 216 _BigFloat = FloatSwap; 217 _LittleFloat = FloatNoSwap; 218 } 219 else 220 { 221 _BigShort = ShortNoSwap; 222 _LittleShort = ShortSwap; 223 _BigLong = LongNoSwap; 224 _LittleLong = LongSwap; 225 _BigLong64 = Long64NoSwap; 226 _LittleLong64 = Long64Swap; 227 _BigFloat = FloatNoSwap; 228 _LittleFloat = FloatSwap; 229 } 230 231 } 232 */ 233 234 /* 235 ============================================================================ 236 237 PARSING 238 239 ============================================================================ 240 */ 241 242 static char com_token[MAX_TOKEN_CHARS]; 243 static char com_parsename[MAX_TOKEN_CHARS]; 244 static int com_lines; 245 246 void COM_BeginParseSession( const char *name ) 247 { 248 com_lines = 0; 249 Com_sprintf(com_parsename, sizeof(com_parsename), "%s", name); 250 } 251 252 int COM_GetCurrentParseLine( void ) 253 { 254 return com_lines; 255 } 256 257 char *COM_Parse( char **data_p ) 258 { 259 return COM_ParseExt( data_p, qtrue ); 260 } 261 262 void COM_ParseError( char *format, ... ) 263 { 264 va_list argptr; 265 static char string[4096]; 266 267 va_start (argptr, format); 268 vsprintf (string, format, argptr); 269 va_end (argptr); 270 271 Com_Printf("ERROR: %s, line %d: %s\n", com_parsename, com_lines, string); 272 } 273 274 void COM_ParseWarning( char *format, ... ) 275 { 276 va_list argptr; 277 static char string[4096]; 278 279 va_start (argptr, format); 280 vsprintf (string, format, argptr); 281 va_end (argptr); 282 283 Com_Printf("WARNING: %s, line %d: %s\n", com_parsename, com_lines, string); 284 } 285 286 /* 287 ============== 288 COM_Parse 289 290 Parse a token out of a string 291 Will never return NULL, just empty strings 292 293 If "allowLineBreaks" is qtrue then an empty 294 string will be returned if the next token is 295 a newline. 296 ============== 297 */ 298 static char *SkipWhitespace( char *data, qboolean *hasNewLines ) { 299 int c; 300 301 while( (c = *data) <= ' ') { 302 if( !c ) { 303 return NULL; 304 } 305 if( c == '\n' ) { 306 com_lines++; 307 *hasNewLines = qtrue; 308 } 309 data++; 310 } 311 312 return data; 313 } 314 315 int COM_Compress( char *data_p ) { 316 char *in, *out; 317 int c; 318 qboolean newline = qfalse, whitespace = qfalse; 319 320 in = out = data_p; 321 if (in) { 322 while ((c = *in) != 0) { 323 // skip double slash comments 324 if ( c == '/' && in[1] == '/' ) { 325 while (*in && *in != '\n') { 326 in++; 327 } 328 // skip /* */ comments 329 } else if ( c == '/' && in[1] == '*' ) { 330 while ( *in && ( *in != '*' || in[1] != '/' ) ) 331 in++; 332 if ( *in ) 333 in += 2; 334 // record when we hit a newline 335 } else if ( c == '\n' || c == '\r' ) { 336 newline = qtrue; 337 in++; 338 // record when we hit whitespace 339 } else if ( c == ' ' || c == '\t') { 340 whitespace = qtrue; 341 in++; 342 // an actual token 343 } else { 344 // if we have a pending newline, emit it (and it counts as whitespace) 345 if (newline) { 346 *out++ = '\n'; 347 newline = qfalse; 348 whitespace = qfalse; 349 } if (whitespace) { 350 *out++ = ' '; 351 whitespace = qfalse; 352 } 353 354 // copy quoted strings unmolested 355 if (c == '"') { 356 *out++ = c; 357 in++; 358 while (1) { 359 c = *in; 360 if (c && c != '"') { 361 *out++ = c; 362 in++; 363 } else { 364 break; 365 } 366 } 367 if (c == '"') { 368 *out++ = c; 369 in++; 370 } 371 } else { 372 *out = c; 373 out++; 374 in++; 375 } 376 } 377 } 378 } 379 *out = 0; 380 return out - data_p; 381 } 382 383 char *COM_ParseExt( char **data_p, qboolean allowLineBreaks ) 384 { 385 int c = 0, len; 386 qboolean hasNewLines = qfalse; 387 char *data; 388 389 data = *data_p; 390 len = 0; 391 com_token[0] = 0; 392 393 // make sure incoming data is valid 394 if ( !data ) 395 { 396 *data_p = NULL; 397 return com_token; 398 } 399 400 while ( 1 ) 401 { 402 // skip whitespace 403 data = SkipWhitespace( data, &hasNewLines ); 404 if ( !data ) 405 { 406 *data_p = NULL; 407 return com_token; 408 } 409 if ( hasNewLines && !allowLineBreaks ) 410 { 411 *data_p = data; 412 return com_token; 413 } 414 415 c = *data; 416 417 // skip double slash comments 418 if ( c == '/' && data[1] == '/' ) 419 { 420 data += 2; 421 while (*data && *data != '\n') { 422 data++; 423 } 424 } 425 // skip /* */ comments 426 else if ( c=='/' && data[1] == '*' ) 427 { 428 data += 2; 429 while ( *data && ( *data != '*' || data[1] != '/' ) ) 430 { 431 data++; 432 } 433 if ( *data ) 434 { 435 data += 2; 436 } 437 } 438 else 439 { 440 break; 441 } 442 } 443 444 // handle quoted strings 445 if (c == '\"') 446 { 447 data++; 448 while (1) 449 { 450 c = *data++; 451 if (c=='\"' || !c) 452 { 453 com_token[len] = 0; 454 *data_p = ( char * ) data; 455 return com_token; 456 } 457 if (len < MAX_TOKEN_CHARS) 458 { 459 com_token[len] = c; 460 len++; 461 } 462 } 463 } 464 465 // parse a regular word 466 do 467 { 468 if (len < MAX_TOKEN_CHARS) 469 { 470 com_token[len] = c; 471 len++; 472 } 473 data++; 474 c = *data; 475 if ( c == '\n' ) 476 com_lines++; 477 } while (c>32); 478 479 if (len == MAX_TOKEN_CHARS) 480 { 481 // Com_Printf ("Token exceeded %i chars, discarded.\n", MAX_TOKEN_CHARS); 482 len = 0; 483 } 484 com_token[len] = 0; 485 486 *data_p = ( char * ) data; 487 return com_token; 488 } 489 490 491 #if 0 492 // no longer used 493 /* 494 =============== 495 COM_ParseInfos 496 =============== 497 */ 498 int COM_ParseInfos( char *buf, int max, char infos[][MAX_INFO_STRING] ) { 499 char *token; 500 int count; 501 char key[MAX_TOKEN_CHARS]; 502 503 count = 0; 504 505 while ( 1 ) { 506 token = COM_Parse( &buf ); 507 if ( !token[0] ) { 508 break; 509 } 510 if ( strcmp( token, "{" ) ) { 511 Com_Printf( "Missing { in info file\n" ); 512 break; 513 } 514 515 if ( count == max ) { 516 Com_Printf( "Max infos exceeded\n" ); 517 break; 518 } 519 520 infos[count][0] = 0; 521 while ( 1 ) { 522 token = COM_ParseExt( &buf, qtrue ); 523 if ( !token[0] ) { 524 Com_Printf( "Unexpected end of info file\n" ); 525 break; 526 } 527 if ( !strcmp( token, "}" ) ) { 528 break; 529 } 530 Q_strncpyz( key, token, sizeof( key ) ); 531 532 token = COM_ParseExt( &buf, qfalse ); 533 if ( !token[0] ) { 534 strcpy( token, "<NULL>" ); 535 } 536 Info_SetValueForKey( infos[count], key, token ); 537 } 538 count++; 539 } 540 541 return count; 542 } 543 #endif 544 545 546 /* 547 ================== 548 COM_MatchToken 549 ================== 550 */ 551 void COM_MatchToken( char **buf_p, char *match ) { 552 char *token; 553 554 token = COM_Parse( buf_p ); 555 if ( strcmp( token, match ) ) { 556 Com_Error( ERR_DROP, "MatchToken: %s != %s", token, match ); 557 } 558 } 559 560 561 /* 562 ================= 563 SkipBracedSection 564 565 The next token should be an open brace. 566 Skips until a matching close brace is found. 567 Internal brace depths are properly skipped. 568 ================= 569 */ 570 void SkipBracedSection (char **program) { 571 char *token; 572 int depth; 573 574 depth = 0; 575 do { 576 token = COM_ParseExt( program, qtrue ); 577 if( token[1] == 0 ) { 578 if( token[0] == '{' ) { 579 depth++; 580 } 581 else if( token[0] == '}' ) { 582 depth--; 583 } 584 } 585 } while( depth && *program ); 586 } 587 588 /* 589 ================= 590 SkipRestOfLine 591 ================= 592 */ 593 void SkipRestOfLine ( char **data ) { 594 char *p; 595 int c; 596 597 p = *data; 598 while ( (c = *p++) != 0 ) { 599 if ( c == '\n' ) { 600 com_lines++; 601 break; 602 } 603 } 604 605 *data = p; 606 } 607 608 609 void Parse1DMatrix (char **buf_p, int x, float *m) { 610 char *token; 611 int i; 612 613 COM_MatchToken( buf_p, "(" ); 614 615 for (i = 0 ; i < x ; i++) { 616 token = COM_Parse(buf_p); 617 m[i] = atof(token); 618 } 619 620 COM_MatchToken( buf_p, ")" ); 621 } 622 623 void Parse2DMatrix (char **buf_p, int y, int x, float *m) { 624 int i; 625 626 COM_MatchToken( buf_p, "(" ); 627 628 for (i = 0 ; i < y ; i++) { 629 Parse1DMatrix (buf_p, x, m + i * x); 630 } 631 632 COM_MatchToken( buf_p, ")" ); 633 } 634 635 void Parse3DMatrix (char **buf_p, int z, int y, int x, float *m) { 636 int i; 637 638 COM_MatchToken( buf_p, "(" ); 639 640 for (i = 0 ; i < z ; i++) { 641 Parse2DMatrix (buf_p, y, x, m + i * x*y); 642 } 643 644 COM_MatchToken( buf_p, ")" ); 645 } 646 647 648 /* 649 ============================================================================ 650 651 LIBRARY REPLACEMENT FUNCTIONS 652 653 ============================================================================ 654 */ 655 656 int Q_isprint( int c ) 657 { 658 if ( c >= 0x20 && c <= 0x7E ) 659 return ( 1 ); 660 return ( 0 ); 661 } 662 663 int Q_islower( int c ) 664 { 665 if (c >= 'a' && c <= 'z') 666 return ( 1 ); 667 return ( 0 ); 668 } 669 670 int Q_isupper( int c ) 671 { 672 if (c >= 'A' && c <= 'Z') 673 return ( 1 ); 674 return ( 0 ); 675 } 676 677 int Q_isalpha( int c ) 678 { 679 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) 680 return ( 1 ); 681 return ( 0 ); 682 } 683 684 char* Q_strrchr( const char* string, int c ) 685 { 686 char cc = c; 687 char *s; 688 char *sp=(char *)0; 689 690 s = (char*)string; 691 692 while (*s) 693 { 694 if (*s == cc) 695 sp = s; 696 s++; 697 } 698 if (cc == 0) 699 sp = s; 700 701 return sp; 702 } 703 704 /* 705 ============= 706 Q_strncpyz 707 708 Safe strncpy that ensures a trailing zero 709 ============= 710 */ 711 void Q_strncpyz( char *dest, const char *src, int destsize ) { 712 // bk001129 - also NULL dest 713 if ( !dest ) { 714 Com_Error( ERR_FATAL, "Q_strncpyz: NULL dest" ); 715 } 716 if ( !src ) { 717 Com_Error( ERR_FATAL, "Q_strncpyz: NULL src" ); 718 } 719 if ( destsize < 1 ) { 720 Com_Error(ERR_FATAL,"Q_strncpyz: destsize < 1" ); 721 } 722 723 strncpy( dest, src, destsize-1 ); 724 dest[destsize-1] = 0; 725 } 726 727 int Q_stricmpn (const char *s1, const char *s2, int n) { 728 int c1, c2; 729 730 // bk001129 - moved in 1.17 fix not in id codebase 731 if ( s1 == NULL ) { 732 if ( s2 == NULL ) 733 return 0; 734 else 735 return -1; 736 } 737 else if ( s2==NULL ) 738 return 1; 739 740 741 742 do { 743 c1 = *s1++; 744 c2 = *s2++; 745 746 if (!n--) { 747 return 0; // strings are equal until end point 748 } 749 750 if (c1 != c2) { 751 if (c1 >= 'a' && c1 <= 'z') { 752 c1 -= ('a' - 'A'); 753 } 754 if (c2 >= 'a' && c2 <= 'z') { 755 c2 -= ('a' - 'A'); 756 } 757 if (c1 != c2) { 758 return c1 < c2 ? -1 : 1; 759 } 760 } 761 } while (c1); 762 763 return 0; // strings are equal 764 } 765 766 int Q_strncmp (const char *s1, const char *s2, int n) { 767 int c1, c2; 768 769 do { 770 c1 = *s1++; 771 c2 = *s2++; 772 773 if (!n--) { 774 return 0; // strings are equal until end point 775 } 776 777 if (c1 != c2) { 778 return c1 < c2 ? -1 : 1; 779 } 780 } while (c1); 781 782 return 0; // strings are equal 783 } 784 785 int Q_stricmp (const char *s1, const char *s2) { 786 return (s1 && s2) ? Q_stricmpn (s1, s2, 99999) : -1; 787 } 788 789 790 char *Q_strlwr( char *s1 ) { 791 char *s; 792 793 s = s1; 794 while ( *s ) { 795 *s = tolower(*s); 796 s++; 797 } 798 return s1; 799 } 800 801 char *Q_strupr( char *s1 ) { 802 char *s; 803 804 s = s1; 805 while ( *s ) { 806 *s = toupper(*s); 807 s++; 808 } 809 return s1; 810 } 811 812 813 // never goes past bounds or leaves without a terminating 0 814 void Q_strcat( char *dest, int size, const char *src ) { 815 int l1; 816 817 l1 = strlen( dest ); 818 if ( l1 >= size ) { 819 Com_Error( ERR_FATAL, "Q_strcat: already overflowed" ); 820 } 821 Q_strncpyz( dest + l1, src, size - l1 ); 822 } 823 824 825 int Q_PrintStrlen( const char *string ) { 826 int len; 827 const char *p; 828 829 if( !string ) { 830 return 0; 831 } 832 833 len = 0; 834 p = string; 835 while( *p ) { 836 if( Q_IsColorString( p ) ) { 837 p += 2; 838 continue; 839 } 840 p++; 841 len++; 842 } 843 844 return len; 845 } 846 847 848 char *Q_CleanStr( char *string ) { 849 char* d; 850 char* s; 851 int c; 852 853 s = string; 854 d = string; 855 while ((c = *s) != 0 ) { 856 if ( Q_IsColorString( s ) ) { 857 s++; 858 } 859 else if ( c >= 0x20 && c <= 0x7E ) { 860 *d++ = c; 861 } 862 s++; 863 } 864 *d = '\0'; 865 866 return string; 867 } 868 869 870 void QDECL Com_sprintf( char *dest, int size, const char *fmt, ...) { 871 int len; 872 va_list argptr; 873 char bigbuffer[32000]; // big, but small enough to fit in PPC stack 874 875 va_start (argptr,fmt); 876 len = vsprintf (bigbuffer,fmt,argptr); 877 va_end (argptr); 878 if ( len >= sizeof( bigbuffer ) ) { 879 Com_Error( ERR_FATAL, "Com_sprintf: overflowed bigbuffer" ); 880 } 881 if (len >= size) { 882 Com_Printf ("Com_sprintf: overflow of %i in %i\n", len, size); 883 #ifdef _DEBUG 884 __asm { 885 int 3; 886 } 887 #endif 888 } 889 Q_strncpyz (dest, bigbuffer, size ); 890 } 891 892 893 /* 894 ============ 895 va 896 897 does a varargs printf into a temp buffer, so I don't need to have 898 varargs versions of all text functions. 899 FIXME: make this buffer size safe someday 900 ============ 901 */ 902 char * QDECL va( char *format, ... ) { 903 va_list argptr; 904 static char string[2][32000]; // in case va is called by nested functions 905 static int index = 0; 906 char *buf; 907 908 buf = string[index & 1]; 909 index++; 910 911 va_start (argptr, format); 912 vsprintf (buf, format,argptr); 913 va_end (argptr); 914 915 return buf; 916 } 917 918 919 /* 920 ===================================================================== 921 922 INFO STRINGS 923 924 ===================================================================== 925 */ 926 927 /* 928 =============== 929 Info_ValueForKey 930 931 Searches the string for the given 932 key and returns the associated value, or an empty string. 933 FIXME: overflow check? 934 =============== 935 */ 936 char *Info_ValueForKey( const char *s, const char *key ) { 937 char pkey[BIG_INFO_KEY]; 938 static char value[2][BIG_INFO_VALUE]; // use two buffers so compares 939 // work without stomping on each other 940 static int valueindex = 0; 941 char *o; 942 943 if ( !s || !key ) { 944 return ""; 945 } 946 947 if ( strlen( s ) >= BIG_INFO_STRING ) { 948 Com_Error( ERR_DROP, "Info_ValueForKey: oversize infostring" ); 949 } 950 951 valueindex ^= 1; 952 if (*s == '\\') 953 s++; 954 while (1) 955 { 956 o = pkey; 957 while (*s != '\\') 958 { 959 if (!*s) 960 return ""; 961 *o++ = *s++; 962 } 963 *o = 0; 964 s++; 965 966 o = value[valueindex]; 967 968 while (*s != '\\' && *s) 969 { 970 *o++ = *s++; 971 } 972 *o = 0; 973 974 if (!Q_stricmp (key, pkey) ) 975 return value[valueindex]; 976 977 if (!*s) 978 break; 979 s++; 980 } 981 982 return ""; 983 } 984 985 986 /* 987 =================== 988 Info_NextPair 989 990 Used to itterate through all the key/value pairs in an info string 991 =================== 992 */ 993 void Info_NextPair( const char **head, char *key, char *value ) { 994 char *o; 995 const char *s; 996 997 s = *head; 998 999 if ( *s == '\\' ) { 1000 s++; 1001 } 1002 key[0] = 0; 1003 value[0] = 0; 1004 1005 o = key; 1006 while ( *s != '\\' ) { 1007 if ( !*s ) { 1008 *o = 0; 1009 *head = s; 1010 return; 1011 } 1012 *o++ = *s++; 1013 } 1014 *o = 0; 1015 s++; 1016 1017 o = value; 1018 while ( *s != '\\' && *s ) { 1019 *o++ = *s++; 1020 } 1021 *o = 0; 1022 1023 *head = s; 1024 } 1025 1026 1027 /* 1028 =================== 1029 Info_RemoveKey 1030 =================== 1031 */ 1032 void Info_RemoveKey( char *s, const char *key ) { 1033 char *start; 1034 char pkey[MAX_INFO_KEY]; 1035 char value[MAX_INFO_VALUE]; 1036 char *o; 1037 1038 if ( strlen( s ) >= MAX_INFO_STRING ) { 1039 Com_Error( ERR_DROP, "Info_RemoveKey: oversize infostring" ); 1040 } 1041 1042 if (strchr (key, '\\')) { 1043 return; 1044 } 1045 1046 while (1) 1047 { 1048 start = s; 1049 if (*s == '\\') 1050 s++; 1051 o = pkey; 1052 while (*s != '\\') 1053 { 1054 if (!*s) 1055 return; 1056 *o++ = *s++; 1057 } 1058 *o = 0; 1059 s++; 1060 1061 o = value; 1062 while (*s != '\\' && *s) 1063 { 1064 if (!*s) 1065 return; 1066 *o++ = *s++; 1067 } 1068 *o = 0; 1069 1070 if (!strcmp (key, pkey) ) 1071 { 1072 strcpy (start, s); // remove this part 1073 return; 1074 } 1075 1076 if (!*s) 1077 return; 1078 } 1079 1080 } 1081 1082 /* 1083 =================== 1084 Info_RemoveKey_Big 1085 =================== 1086 */ 1087 void Info_RemoveKey_Big( char *s, const char *key ) { 1088 char *start; 1089 char pkey[BIG_INFO_KEY]; 1090 char value[BIG_INFO_VALUE]; 1091 char *o; 1092 1093 if ( strlen( s ) >= BIG_INFO_STRING ) { 1094 Com_Error( ERR_DROP, "Info_RemoveKey_Big: oversize infostring" ); 1095 } 1096 1097 if (strchr (key, '\\')) { 1098 return; 1099 } 1100 1101 while (1) 1102 { 1103 start = s; 1104 if (*s == '\\') 1105 s++; 1106 o = pkey; 1107 while (*s != '\\') 1108 { 1109 if (!*s) 1110 return; 1111 *o++ = *s++; 1112 } 1113 *o = 0; 1114 s++; 1115 1116 o = value; 1117 while (*s != '\\' && *s) 1118 { 1119 if (!*s) 1120 return; 1121 *o++ = *s++; 1122 } 1123 *o = 0; 1124 1125 if (!strcmp (key, pkey) ) 1126 { 1127 strcpy (start, s); // remove this part 1128 return; 1129 } 1130 1131 if (!*s) 1132 return; 1133 } 1134 1135 } 1136 1137 1138 1139 1140 /* 1141 ================== 1142 Info_Validate 1143 1144 Some characters are illegal in info strings because they 1145 can mess up the server's parsing 1146 ================== 1147 */ 1148 qboolean Info_Validate( const char *s ) { 1149 if ( strchr( s, '\"' ) ) { 1150 return qfalse; 1151 } 1152 if ( strchr( s, ';' ) ) { 1153 return qfalse; 1154 } 1155 return qtrue; 1156 } 1157 1158 /* 1159 ================== 1160 Info_SetValueForKey 1161 1162 Changes or adds a key/value pair 1163 ================== 1164 */ 1165 void Info_SetValueForKey( char *s, const char *key, const char *value ) { 1166 char newi[MAX_INFO_STRING]; 1167 1168 if ( strlen( s ) >= MAX_INFO_STRING ) { 1169 Com_Error( ERR_DROP, "Info_SetValueForKey: oversize infostring" ); 1170 } 1171 1172 if (strchr (key, '\\') || strchr (value, '\\')) 1173 { 1174 Com_Printf ("Can't use keys or values with a \\\n"); 1175 return; 1176 } 1177 1178 if (strchr (key, ';') || strchr (value, ';')) 1179 { 1180 Com_Printf ("Can't use keys or values with a semicolon\n"); 1181 return; 1182 } 1183 1184 if (strchr (key, '\"') || strchr (value, '\"')) 1185 { 1186 Com_Printf ("Can't use keys or values with a \"\n"); 1187 return; 1188 } 1189 1190 Info_RemoveKey (s, key); 1191 if (!value || !strlen(value)) 1192 return; 1193 1194 Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value); 1195 1196 if (strlen(newi) + strlen(s) > MAX_INFO_STRING) 1197 { 1198 Com_Printf ("Info string length exceeded\n"); 1199 return; 1200 } 1201 1202 strcat (newi, s); 1203 strcpy (s, newi); 1204 } 1205 1206 /* 1207 ================== 1208 Info_SetValueForKey_Big 1209 1210 Changes or adds a key/value pair 1211 ================== 1212 */ 1213 void Info_SetValueForKey_Big( char *s, const char *key, const char *value ) { 1214 char newi[BIG_INFO_STRING]; 1215 1216 if ( strlen( s ) >= BIG_INFO_STRING ) { 1217 Com_Error( ERR_DROP, "Info_SetValueForKey: oversize infostring" ); 1218 } 1219 1220 if (strchr (key, '\\') || strchr (value, '\\')) 1221 { 1222 Com_Printf ("Can't use keys or values with a \\\n"); 1223 return; 1224 } 1225 1226 if (strchr (key, ';') || strchr (value, ';')) 1227 { 1228 Com_Printf ("Can't use keys or values with a semicolon\n"); 1229 return; 1230 } 1231 1232 if (strchr (key, '\"') || strchr (value, '\"')) 1233 { 1234 Com_Printf ("Can't use keys or values with a \"\n"); 1235 return; 1236 } 1237 1238 Info_RemoveKey_Big (s, key); 1239 if (!value || !strlen(value)) 1240 return; 1241 1242 Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value); 1243 1244 if (strlen(newi) + strlen(s) > BIG_INFO_STRING) 1245 { 1246 Com_Printf ("BIG Info string length exceeded\n"); 1247 return; 1248 } 1249 1250 strcat (s, newi); 1251 } 1252 1253 1254 1255 1256 //==================================================================== 1257 1258