Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

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