1 /*
2 ===========================================================================
3 
4 Return to Castle Wolfenstein multiplayer GPL Source Code
5 Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
8 
9 RTCW MP Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 RTCW MP Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with RTCW MP Source Code.  If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the RTCW MP 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 RTCW MP Source Code.  If not, please request a copy in writing from id Software at the address below.
23 
24 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.
25 
26 ===========================================================================
27 */
28 
29 // q_shared.c -- stateless support routines that are included in each code dll
30 #include "q_shared.h"
31 
32 // os x game bundles have no standard library links, and the defines are not always defined!
33 
34 #ifdef __APPLE__
qmax(int x,int y)35 int qmax( int x, int y ) {
36 	return ( ( ( x ) > ( y ) ) ? ( x ) : ( y ) );
37 }
38 
qmin(int x,int y)39 int qmin( int x, int y ) {
40 	return ( ( ( x ) < ( y ) ) ? ( x ) : ( y ) );
41 }
42 #endif
43 
44 // ^[0-9a-zA-Z]
Q_IsColorString(const char * p)45 qboolean Q_IsColorString(const char *p) {
46 	if (!p)
47 		return qfalse;
48 
49 	if (p[0] != Q_COLOR_ESCAPE)
50 		return qfalse;
51 
52 	if (p[1] == 0)
53 		return qfalse;
54 
55 	// isalnum expects a signed integer in the range -1 (EOF) to 255, or it might assert on undefined behaviour
56 	// a dereferenced char pointer has the range -128 to 127, so we just need to rangecheck the negative part
57 	if (p[1] < 0)
58 		return qfalse;
59 
60 	if (isalnum(p[1]) == 0)
61 		return qfalse;
62 
63 	return qtrue;
64 }
65 
Com_Clamp(float min,float max,float value)66 float Com_Clamp( float min, float max, float value ) {
67 	if ( value < min ) {
68 		return min;
69 	}
70 	if ( value > max ) {
71 		return max;
72 	}
73 	return value;
74 }
75 
76 
77 /*
78 ============
79 COM_SkipPath
80 ============
81 */
COM_SkipPath(char * pathname)82 char *COM_SkipPath( char *pathname ) {
83 	char    *last;
84 
85 	last = pathname;
86 	while ( *pathname )
87 	{
88 		if ( *pathname == '/' ) {
89 			last = pathname + 1;
90 		}
91 		pathname++;
92 	}
93 	return last;
94 }
95 
96 /*
97 ============
98 COM_GetExtension
99 ============
100 */
COM_GetExtension(const char * name)101 const char *COM_GetExtension( const char *name )
102 {
103 	const char *dot = strrchr(name, '.'), *slash;
104 	if (dot && (!(slash = strrchr(name, '/')) || slash < dot))
105 		return dot + 1;
106 	else
107 		return "";
108 }
109 
110 /*
111 ============
112 COM_StripExtension
113 ============
114 */
COM_StripExtension(const char * in,char * out,int destsize)115 void COM_StripExtension( const char *in, char *out, int destsize )
116 {
117 	const char *dot = strrchr(in, '.'), *slash;
118 
119 	if (dot && (!(slash = strrchr(in, '/')) || slash < dot))
120 		destsize = (destsize < dot-in+1 ? destsize : dot-in+1);
121 
122 	if ( in == out && destsize > 1 )
123 		out[destsize-1] = '\0';
124 	else
125 		Q_strncpyz(out, in, destsize);
126 }
127 
128 /*
129 ============
130 COM_StripExtension2
131 a safer version
132 ============
133 */
COM_StripExtension2(const char * in,char * out,int destsize)134 void COM_StripExtension2( const char *in, char *out, int destsize ) {
135 	int len = 0;
136 	while ( len < destsize - 1 && *in && *in != '.' ) {
137 		*out++ = *in++;
138 		len++;
139 	}
140 	*out = 0;
141 }
142 
COM_StripFilename(char * in,char * out)143 void COM_StripFilename( char *in, char *out ) {
144 	char *end;
145 	Q_strncpyz( out, in, strlen( in ) );
146 	end = COM_SkipPath( out );
147 	*end = 0;
148 }
149 
150 /*
151 ============
152 COM_CompareExtension
153 
154 string compare the end of the strings and return qtrue if strings match
155 ============
156 */
COM_CompareExtension(const char * in,const char * ext)157 qboolean COM_CompareExtension(const char *in, const char *ext)
158 {
159 	int inlen, extlen;
160 
161 	inlen = strlen(in);
162 	extlen = strlen(ext);
163 
164 	if(extlen <= inlen)
165 	{
166 		in += inlen - extlen;
167 
168 		if(!Q_stricmp(in, ext))
169 			return qtrue;
170 	}
171 
172 	return qfalse;
173 }
174 
175 /*
176 ==================
177 COM_DefaultExtension
178 
179 if path doesn't have an extension, then append
180  the specified one (which should include the .)
181 ==================
182 */
COM_DefaultExtension(char * path,int maxSize,const char * extension)183 void COM_DefaultExtension( char *path, int maxSize, const char *extension )
184 {
185 	const char *dot = strrchr(path, '.'), *slash;
186 	if (dot && (!(slash = strrchr(path, '/')) || slash < dot))
187 		return;
188 	else
189 		Q_strcat(path, maxSize, extension);
190 }
191 
192 //============================================================================
193 /*
194 ==================
195 COM_BitCheck
196 
197   Allows bit-wise checks on arrays with more than one item (> 32 bits)
198 ==================
199 */
COM_BitCheck(const int array[],int bitNum)200 qboolean COM_BitCheck( const int array[], int bitNum ) {
201 	int i;
202 
203 	i = 0;
204 	while ( bitNum > 31 ) {
205 		i++;
206 		bitNum -= 32;
207 	}
208 
209 	return ( ( array[i] & ( 1 << bitNum ) ) != 0 );  // (SA) heh, whoops. :)
210 }
211 
212 /*
213 ==================
214 COM_BitSet
215 
216   Allows bit-wise SETS on arrays with more than one item (> 32 bits)
217 ==================
218 */
COM_BitSet(int array[],int bitNum)219 void COM_BitSet( int array[], int bitNum ) {
220 	int i;
221 
222 	i = 0;
223 	while ( bitNum > 31 ) {
224 		i++;
225 		bitNum -= 32;
226 	}
227 
228 	array[i] |= ( 1 << bitNum );
229 }
230 
231 /*
232 ==================
233 COM_BitClear
234 
235   Allows bit-wise CLEAR on arrays with more than one item (> 32 bits)
236 ==================
237 */
COM_BitClear(int array[],int bitNum)238 void COM_BitClear( int array[], int bitNum ) {
239 	int i;
240 
241 	i = 0;
242 	while ( bitNum > 31 ) {
243 		i++;
244 		bitNum -= 32;
245 	}
246 
247 	array[i] &= ~( 1 << bitNum );
248 }
249 //============================================================================
250 
251 /*
252 ============================================================================
253 
254 					BYTE ORDER FUNCTIONS
255 
256 ============================================================================
257 */
258 
CopyShortSwap(void * dest,void * src)259 void CopyShortSwap(void *dest, void *src)
260 {
261 	byte *to = dest, *from = src;
262 
263 	to[0] = from[1];
264 	to[1] = from[0];
265 }
266 
CopyLongSwap(void * dest,void * src)267 void CopyLongSwap(void *dest, void *src)
268 {
269 	byte *to = dest, *from = src;
270 
271 	to[0] = from[3];
272 	to[1] = from[2];
273 	to[2] = from[1];
274 	to[3] = from[0];
275 }
276 
ShortSwap(short l)277 short   ShortSwap( short l ) {
278 	byte b1,b2;
279 
280 	b1 = l & 255;
281 	b2 = ( l >> 8 ) & 255;
282 
283 	return ( b1 << 8 ) + b2;
284 }
285 
ShortNoSwap(short l)286 short   ShortNoSwap( short l ) {
287 	return l;
288 }
289 
LongSwap(int l)290 int    LongSwap( int l ) {
291 	byte b1,b2,b3,b4;
292 
293 	b1 = l & 255;
294 	b2 = ( l >> 8 ) & 255;
295 	b3 = ( l >> 16 ) & 255;
296 	b4 = ( l >> 24 ) & 255;
297 
298 	return ( (int)b1 << 24 ) + ( (int)b2 << 16 ) + ( (int)b3 << 8 ) + b4;
299 }
300 
LongNoSwap(int l)301 int LongNoSwap( int l ) {
302 	return l;
303 }
304 
Long64Swap(qint64 ll)305 qint64 Long64Swap( qint64 ll ) {
306 	qint64 result;
307 
308 	result.b0 = ll.b7;
309 	result.b1 = ll.b6;
310 	result.b2 = ll.b5;
311 	result.b3 = ll.b4;
312 	result.b4 = ll.b3;
313 	result.b5 = ll.b2;
314 	result.b6 = ll.b1;
315 	result.b7 = ll.b0;
316 
317 	return result;
318 }
319 
Long64NoSwap(qint64 ll)320 qint64 Long64NoSwap( qint64 ll ) {
321 	return ll;
322 }
323 
FloatSwap(const float * f)324 float FloatSwap (const float *f) {
325 	floatint_t out;
326 
327 	out.f = *f;
328 	out.ui = LongSwap(out.ui);
329 
330 	return out.f;
331 }
332 
FloatNoSwap(float f)333 float FloatNoSwap( float f ) {
334 	return f;
335 }
336 
337 /*
338 ============================================================================
339 
340 PARSING
341 
342 ============================================================================
343 */
344 
345 static char com_token[MAX_TOKEN_CHARS];
346 static char com_parsename[MAX_TOKEN_CHARS];
347 static int com_lines;
348 static int com_tokenline;
349 
350 static int backup_lines;
351 static char    *backup_text;
352 
COM_BeginParseSession(const char * name)353 void COM_BeginParseSession( const char *name ) {
354 	com_lines = 1;
355 	com_tokenline = 0;
356 	Com_sprintf( com_parsename, sizeof( com_parsename ), "%s", name );
357 }
358 
COM_BackupParseSession(char ** data_p)359 void COM_BackupParseSession( char **data_p ) {
360 	backup_lines = com_lines;
361 	backup_text = *data_p;
362 }
363 
COM_RestoreParseSession(char ** data_p)364 void COM_RestoreParseSession( char **data_p ) {
365 	com_lines = backup_lines;
366 	*data_p = backup_text;
367 }
368 
COM_SetCurrentParseLine(int line)369 void COM_SetCurrentParseLine( int line ) {
370 	com_lines = line;
371 }
372 
COM_GetCurrentParseLine(void)373 int COM_GetCurrentParseLine( void ) {
374 	if ( com_tokenline )
375 	{
376 		return com_tokenline;
377 	}
378 
379 	return com_lines;
380 }
381 
COM_Parse(char ** data_p)382 char *COM_Parse( char **data_p ) {
383 	return COM_ParseExt( data_p, qtrue );
384 }
385 
COM_ParseError(char * format,...)386 void COM_ParseError( char *format, ... ) {
387 	va_list argptr;
388 	static char string[4096];
389 
390 	va_start( argptr, format );
391 	Q_vsnprintf( string, sizeof( string ), format, argptr );
392 	va_end( argptr );
393 
394 	Com_Printf("ERROR: %s, line %d: %s\n", com_parsename, COM_GetCurrentParseLine(), string);
395 }
396 
COM_ParseWarning(char * format,...)397 void COM_ParseWarning( char *format, ... ) {
398 	va_list argptr;
399 	static char string[4096];
400 
401 	va_start( argptr, format );
402 	Q_vsnprintf( string, sizeof( string ), format, argptr );
403 	va_end( argptr );
404 
405 	Com_Printf("WARNING: %s, line %d: %s\n", com_parsename, COM_GetCurrentParseLine(), string);
406 }
407 
408 /*
409 ==============
410 COM_Parse
411 
412 Parse a token out of a string
413 Will never return NULL, just empty strings
414 
415 If "allowLineBreaks" is qtrue then an empty
416 string will be returned if the next token is
417 a newline.
418 ==============
419 */
SkipWhitespace(char * data,qboolean * hasNewLines)420 static char *SkipWhitespace( char *data, qboolean *hasNewLines ) {
421 	int c;
422 
423 	while ( ( c = *data ) <= ' ' ) {
424 		if ( !c ) {
425 			return NULL;
426 		}
427 		if ( c == '\n' ) {
428 			com_lines++;
429 			*hasNewLines = qtrue;
430 		}
431 		data++;
432 	}
433 
434 	return data;
435 }
436 
COM_Compress(char * data_p)437 int COM_Compress( char *data_p ) {
438 	char *in, *out;
439 	int c;
440 	qboolean newline = qfalse, whitespace = qfalse;
441 
442 	in = out = data_p;
443 	if (in) {
444 		while ((c = *in) != 0) {
445 			// skip double slash comments
446 			if ( c == '/' && in[1] == '/' ) {
447 				while (*in && *in != '\n') {
448 					in++;
449 				}
450 			// skip /* */ comments
451 			} else if ( c == '/' && in[1] == '*' ) {
452 				while ( *in && ( *in != '*' || in[1] != '/' ) )
453 					in++;
454 				if ( *in )
455 					in += 2;
456 				// record when we hit a newline
457 			} else if ( c == '\n' || c == '\r' ) {
458 				newline = qtrue;
459 				in++;
460 				// record when we hit whitespace
461 			} else if ( c == ' ' || c == '\t') {
462 				whitespace = qtrue;
463 				in++;
464 				// an actual token
465 			} else {
466 				// if we have a pending newline, emit it (and it counts as whitespace)
467 				if (newline) {
468 					*out++ = '\n';
469 					newline = qfalse;
470 					whitespace = qfalse;
471 				} if (whitespace) {
472 					*out++ = ' ';
473 					whitespace = qfalse;
474 				}
475 
476 				// copy quoted strings unmolested
477 				if (c == '"') {
478 					*out++ = c;
479 					in++;
480 					while (1) {
481 						c = *in;
482 						if (c && c != '"') {
483 							*out++ = c;
484 							in++;
485 						} else {
486 							break;
487 						}
488 					}
489 					if (c == '"') {
490 						*out++ = c;
491 						in++;
492 					}
493 				} else {
494 					*out = c;
495 					out++;
496 					in++;
497 				}
498 			}
499 		}
500 
501 		*out = 0;
502 	}
503 	return out - data_p;
504 }
505 
COM_ParseExt(char ** data_p,qboolean allowLineBreaks)506 char *COM_ParseExt( char **data_p, qboolean allowLineBreaks ) {
507 	int c = 0, len;
508 	qboolean hasNewLines = qfalse;
509 	char *data;
510 
511 	data = *data_p;
512 	len = 0;
513 	com_token[0] = 0;
514 	com_tokenline = 0;
515 
516 	// make sure incoming data is valid
517 	if ( !data ) {
518 		*data_p = NULL;
519 		return com_token;
520 	}
521 
522 	// RF, backup the session data so we can unget easily
523 	COM_BackupParseSession( data_p );
524 
525 	while ( 1 )
526 	{
527 		// skip whitespace
528 		data = SkipWhitespace( data, &hasNewLines );
529 		if ( !data ) {
530 			*data_p = NULL;
531 			return com_token;
532 		}
533 		if ( hasNewLines && !allowLineBreaks ) {
534 			*data_p = data;
535 			return com_token;
536 		}
537 
538 		c = *data;
539 
540 		// skip double slash comments
541 		if ( c == '/' && data[1] == '/' ) {
542 			data += 2;
543 			while ( *data && *data != '\n' ) {
544 				data++;
545 			}
546 		}
547 		// skip /* */ comments
548 		else if ( c == '/' && data[1] == '*' ) {
549 			data += 2;
550 			while ( *data && ( *data != '*' || data[1] != '/' ) )
551 			{
552 				if ( *data == '\n' )
553 				{
554 					com_lines++;
555 				}
556 				data++;
557 			}
558 			if ( *data ) {
559 				data += 2;
560 			}
561 		} else
562 		{
563 			break;
564 		}
565 	}
566 
567 	// token starts on this line
568 	com_tokenline = com_lines;
569 
570 	// handle quoted strings
571 	if ( c == '\"' ) {
572 		data++;
573 		while ( 1 )
574 		{
575 			c = *data++;
576 			if ( c == '\"' || !c ) {
577 				com_token[len] = 0;
578 				*data_p = ( char * ) data;
579 				return com_token;
580 			}
581 			if ( c == '\n' )
582 			{
583 				com_lines++;
584 			}
585 			if ( len < MAX_TOKEN_CHARS - 1) {
586 				com_token[len] = c;
587 				len++;
588 			}
589 		}
590 	}
591 
592 	// parse a regular word
593 	do
594 	{
595 		if ( len < MAX_TOKEN_CHARS - 1) {
596 			com_token[len] = c;
597 			len++;
598 		}
599 		data++;
600 		c = *data;
601 	} while ( c > 32 );
602 
603 	com_token[len] = 0;
604 
605 	*data_p = ( char * ) data;
606 	return com_token;
607 }
608 
609 
610 
611 
612 /*
613 ==================
614 COM_MatchToken
615 ==================
616 */
COM_MatchToken(char ** buf_p,char * match)617 void COM_MatchToken( char **buf_p, char *match ) {
618 	char    *token;
619 
620 	token = COM_Parse( buf_p );
621 	if ( strcmp( token, match ) ) {
622 		Com_Error( ERR_DROP, "MatchToken: %s != %s", token, match );
623 	}
624 }
625 
626 /*
627 =================
628 SkipBracedSection
629 
630 The next token should be an open brace or set depth to 1 if already parsed it.
631 Skips until a matching close brace is found.
632 Internal brace depths are properly skipped.
633 =================
634 */
SkipBracedSection(char ** program,int depth)635 qboolean SkipBracedSection (char **program, int depth) {
636 	char			*token;
637 
638 	do {
639 		token = COM_ParseExt( program, qtrue );
640 		if( token[1] == 0 ) {
641 			if( token[0] == '{' ) {
642 				depth++;
643 			}
644 			else if( token[0] == '}' ) {
645 				depth--;
646 			}
647 		}
648 	} while( depth && *program );
649 
650 	return ( depth == 0 );
651 }
652 
653 /*
654 =================
655 SkipRestOfLine
656 =================
657 */
SkipRestOfLine(char ** data)658 void SkipRestOfLine( char **data ) {
659 	char    *p;
660 	int c;
661 
662 	p = *data;
663 
664 	if ( !*p )
665 		return;
666 
667 	while ( ( c = *p++ ) != 0 ) {
668 		if ( c == '\n' ) {
669 			com_lines++;
670 			break;
671 		}
672 	}
673 
674 	*data = p;
675 }
676 
677 
Parse1DMatrix(char ** buf_p,int x,float * m)678 void Parse1DMatrix( char **buf_p, int x, float *m ) {
679 	char    *token;
680 	int i;
681 
682 	COM_MatchToken( buf_p, "(" );
683 
684 	for ( i = 0 ; i < x ; i++ ) {
685 		token = COM_Parse( buf_p );
686 		m[i] = atof( token );
687 	}
688 
689 	COM_MatchToken( buf_p, ")" );
690 }
691 
Parse2DMatrix(char ** buf_p,int y,int x,float * m)692 void Parse2DMatrix( char **buf_p, int y, int x, float *m ) {
693 	int i;
694 
695 	COM_MatchToken( buf_p, "(" );
696 
697 	for ( i = 0 ; i < y ; i++ ) {
698 		Parse1DMatrix( buf_p, x, m + i * x );
699 	}
700 
701 	COM_MatchToken( buf_p, ")" );
702 }
703 
Parse3DMatrix(char ** buf_p,int z,int y,int x,float * m)704 void Parse3DMatrix( char **buf_p, int z, int y, int x, float *m ) {
705 	int i;
706 
707 	COM_MatchToken( buf_p, "(" );
708 
709 	for ( i = 0 ; i < z ; i++ ) {
710 		Parse2DMatrix( buf_p, y, x, m + i * x * y );
711 	}
712 
713 	COM_MatchToken( buf_p, ")" );
714 }
715 
716 /*
717 ===================
718 Com_HexStrToInt
719 ===================
720 */
Com_HexStrToInt(const char * str)721 int Com_HexStrToInt( const char *str )
722 {
723 	if ( !str )
724 		return -1;
725 
726 	// check for hex code
727 	if( str[ 0 ] == '0' && str[ 1 ] == 'x' && str[ 2 ] != '\0' )
728 	{
729 		int i, n = 0, len = strlen( str );
730 
731 		for( i = 2; i < len; i++ )
732 		{
733 			char digit;
734 
735 			n *= 16;
736 
737 			digit = tolower( str[ i ] );
738 
739 			if( digit >= '0' && digit <= '9' )
740 				digit -= '0';
741 			else if( digit >= 'a' && digit <= 'f' )
742 				digit = digit - 'a' + 10;
743 			else
744 				return -1;
745 
746 			n += digit;
747 		}
748 
749 		return n;
750 	}
751 
752 	return -1;
753 }
754 
755 /*
756 ============================================================================
757 
758 					LIBRARY REPLACEMENT FUNCTIONS
759 
760 ============================================================================
761 */
762 
Q_isprint(int c)763 int Q_isprint( int c ) {
764 	if ( c >= 0x20 && c <= 0x7E ) {
765 		return ( 1 );
766 	}
767 	return ( 0 );
768 }
769 
Q_islower(int c)770 int Q_islower( int c ) {
771 	if ( c >= 'a' && c <= 'z' ) {
772 		return ( 1 );
773 	}
774 	return ( 0 );
775 }
776 
Q_isupper(int c)777 int Q_isupper( int c ) {
778 	if ( c >= 'A' && c <= 'Z' ) {
779 		return ( 1 );
780 	}
781 	return ( 0 );
782 }
783 
Q_isalpha(int c)784 int Q_isalpha( int c ) {
785 	if ( ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) ) {
786 		return ( 1 );
787 	}
788 	return ( 0 );
789 }
790 
Q_isanumber(const char * s)791 qboolean Q_isanumber( const char *s )
792 {
793 	char *p;
794 	double UNUSED_VAR d;
795 
796 	if( *s == '\0' )
797 		return qfalse;
798 
799 	d = strtod( s, &p );
800 
801 	return *p == '\0';
802 }
803 
Q_isintegral(float f)804 qboolean Q_isintegral( float f )
805 {
806 	return (int)f == f;
807 }
808 
809 #ifdef _WIN32
810 /*
811 =============
812 Q_vsnprintf
813 
814 Special wrapper function for Microsoft's broken _vsnprintf() function.
815 MinGW comes with its own vsnprintf() which is not broken. mingw-w64
816 however, uses Microsoft's broken _vsnprintf() function.
817 =============
818 */
819 
Q_vsnprintf(char * str,size_t size,const char * format,va_list ap)820 int Q_vsnprintf(char *str, size_t size, const char *format, va_list ap)
821 {
822 	int retval;
823 
824 	retval = _vsnprintf(str, size, format, ap);
825 
826 	if(retval < 0 || retval == size)
827 	{
828 		// Microsoft doesn't adhere to the C99 standard of vsnprintf,
829 		// which states that the return value must be the number of
830 		// bytes written if the output string had sufficient length.
831 		//
832 		// Obviously we cannot determine that value from Microsoft's
833 		// implementation, so we have no choice but to return size.
834 
835 		str[size - 1] = '\0';
836 		return size;
837 	}
838 
839 	return retval;
840 }
841 #endif
842 
843 /*
844 =============
845 Q_strncpyz
846 
847 Safe strncpy that ensures a trailing zero
848 =============
849 */
Q_strncpyz(char * dest,const char * src,int destsize)850 void Q_strncpyz( char *dest, const char *src, int destsize ) {
851   if ( !dest ) {
852     Com_Error( ERR_FATAL, "Q_strncpyz: NULL dest" );
853   }
854 	if ( !src ) {
855 		Com_Error( ERR_FATAL, "Q_strncpyz: NULL src" );
856 	}
857 	if ( destsize < 1 ) {
858 		Com_Error(ERR_FATAL,"Q_strncpyz: destsize < 1" );
859 	}
860 
861 	strncpy( dest, src, destsize-1 );
862 
863 	dest[destsize-1] = 0;
864 }
865 
Q_stricmpn(const char * s1,const char * s2,int n)866 int Q_stricmpn (const char *s1, const char *s2, int n) {
867 	int		c1, c2;
868 
869         if ( s1 == NULL ) {
870            if ( s2 == NULL )
871              return 0;
872            else
873              return -1;
874         }
875         else if ( s2==NULL )
876           return 1;
877 
878 
879 
880 	do {
881 		c1 = *s1++;
882 		c2 = *s2++;
883 
884 		if (!n--) {
885 			return 0;		// strings are equal until end point
886 		}
887 
888 		if (c1 != c2) {
889 			if (c1 >= 'a' && c1 <= 'z') {
890 				c1 -= ('a' - 'A');
891 			}
892 			if (c2 >= 'a' && c2 <= 'z') {
893 				c2 -= ('a' - 'A');
894 			}
895 			if (c1 != c2) {
896 				return c1 < c2 ? -1 : 1;
897 			}
898 		}
899 	} while (c1);
900 
901 	return 0;		// strings are equal
902 }
903 
Q_strncmp(const char * s1,const char * s2,int n)904 int Q_strncmp( const char *s1, const char *s2, int n ) {
905 	int c1, c2;
906 
907 	do {
908 		c1 = *s1++;
909 		c2 = *s2++;
910 
911 		if ( !n-- ) {
912 			return 0;       // strings are equal until end point
913 		}
914 
915 		if ( c1 != c2 ) {
916 			return c1 < c2 ? -1 : 1;
917 		}
918 	} while ( c1 );
919 
920 	return 0;       // strings are equal
921 }
922 
Q_stricmp(const char * s1,const char * s2)923 int Q_stricmp( const char *s1, const char *s2 ) {
924 	return ( s1 && s2 ) ? Q_stricmpn( s1, s2, 99999 ) : -1;
925 }
926 
927 
Q_strlwr(char * s1)928 char *Q_strlwr( char *s1 ) {
929 	char    *s;
930 
931 	s = s1;
932 	while ( *s ) {
933 		*s = tolower( *s );
934 		s++;
935 	}
936 	return s1;
937 }
938 
Q_strupr(char * s1)939 char *Q_strupr( char *s1 ) {
940 	char    *s;
941 
942 	s = s1;
943 	while ( *s ) {
944 		*s = toupper( *s );
945 		s++;
946 	}
947 	return s1;
948 }
949 
950 
951 // never goes past bounds or leaves without a terminating 0
Q_strcat(char * dest,int size,const char * src)952 void Q_strcat( char *dest, int size, const char *src ) {
953 	int l1;
954 
955 	l1 = strlen( dest );
956 	if ( l1 >= size ) {
957 		Com_Error( ERR_FATAL, "Q_strcat: already overflowed" );
958 	}
959 	Q_strncpyz( dest + l1, src, size - l1 );
960 }
961 
962 /*
963 * Find the first occurrence of find in s.
964 */
Q_stristr(const char * s,const char * find)965 const char *Q_stristr( const char *s, const char *find)
966 {
967   char c, sc;
968   size_t len;
969 
970   if ((c = *find++) != 0)
971   {
972     if (c >= 'a' && c <= 'z')
973     {
974       c -= ('a' - 'A');
975     }
976     len = strlen(find);
977     do
978     {
979       do
980       {
981         if ((sc = *s++) == 0)
982           return NULL;
983         if (sc >= 'a' && sc <= 'z')
984         {
985           sc -= ('a' - 'A');
986         }
987       } while (sc != c);
988     } while (Q_stricmpn(s, find, len) != 0);
989     s--;
990   }
991   return s;
992 }
993 
994 
Q_PrintStrlen(const char * string)995 int Q_PrintStrlen( const char *string ) {
996 	int len;
997 	const char  *p;
998 
999 	if ( !string ) {
1000 		return 0;
1001 	}
1002 
1003 	len = 0;
1004 	p = string;
1005 	while ( *p ) {
1006 		if ( Q_IsColorString( p ) ) {
1007 			p += 2;
1008 			continue;
1009 		}
1010 		p++;
1011 		len++;
1012 	}
1013 
1014 	return len;
1015 }
1016 
1017 
Q_CleanStr(char * string)1018 char *Q_CleanStr( char *string ) {
1019 	char*   d;
1020 	char*   s;
1021 	int c;
1022 
1023 	s = string;
1024 	d = string;
1025 	while ( ( c = *s ) != 0 ) {
1026 		if ( Q_IsColorString( s ) ) {
1027 			s++;
1028 		} else if ( c >= 0x20 && c <= 0x7E )   {
1029 			*d++ = c;
1030 		}
1031 		s++;
1032 	}
1033 	*d = '\0';
1034 
1035 	return string;
1036 }
1037 
Q_CountChar(const char * string,char tocount)1038 int Q_CountChar(const char *string, char tocount)
1039 {
1040 	int count;
1041 
1042 	for(count = 0; *string; string++)
1043 	{
1044 		if(*string == tocount)
1045 			count++;
1046 	}
1047 
1048 	return count;
1049 }
1050 
Com_sprintf(char * dest,int size,const char * fmt,...)1051 int QDECL Com_sprintf(char *dest, int size, const char *fmt, ...)
1052 {
1053 	int len;
1054 	va_list argptr;
1055 
1056 	/*
1057 	C99 for vsnprintf:
1058 	return the number of characters  (excluding  the  trailing  '\0')
1059 	which would have been written to the final string if enough space had been available.
1060 	*/
1061 	va_start( argptr,fmt );
1062 	len = Q_vsnprintf( dest, size, fmt, argptr );
1063 	va_end( argptr );
1064 
1065 	if ( len >= size ) {
1066 		Com_Printf("Com_sprintf: Output length %d too short, requires %d bytes.\n", size, len + 1);
1067 	}
1068 
1069 	return len;
1070 }
1071 
1072 // Ridah, ripped from l_bsp.c
Q_strncasecmp(char * s1,char * s2,int n)1073 int Q_strncasecmp( char *s1, char *s2, int n ) {
1074 	int c1, c2;
1075 
1076 	do
1077 	{
1078 		c1 = *s1++;
1079 		c2 = *s2++;
1080 
1081 		if ( !n-- ) {
1082 			return 0;       // strings are equal until end point
1083 
1084 		}
1085 		if ( c1 != c2 ) {
1086 			if ( c1 >= 'a' && c1 <= 'z' ) {
1087 				c1 -= ( 'a' - 'A' );
1088 			}
1089 			if ( c2 >= 'a' && c2 <= 'z' ) {
1090 				c2 -= ( 'a' - 'A' );
1091 			}
1092 			if ( c1 != c2 ) {
1093 				return -1;      // strings not equal
1094 			}
1095 		}
1096 	} while ( c1 );
1097 
1098 	return 0;       // strings are equal
1099 }
1100 
Q_strcasecmp(char * s1,char * s2)1101 int Q_strcasecmp( char *s1, char *s2 ) {
1102 	return Q_strncasecmp( s1, s2, 99999 );
1103 }
1104 // done.
1105 
1106 /*
1107 ============
1108 va
1109 
1110 does a varargs printf into a temp buffer, so I don't need to have
1111 varargs versions of all text functions.
1112 
1113 Ridah, modified this into a circular list, to further prevent stepping on
1114 previous strings
1115 ============
1116 */
va(char * format,...)1117 char    * QDECL va( char *format, ... ) {
1118 	va_list argptr;
1119 	#define MAX_VA_STRING   32000
1120 	static char temp_buffer[MAX_VA_STRING];
1121 	static char string[MAX_VA_STRING];      // in case va is called by nested functions
1122 	static int index = 0;
1123 	char    *buf;
1124 	int len;
1125 
1126 
1127 	va_start( argptr, format );
1128 	Q_vsnprintf (temp_buffer, sizeof(temp_buffer), format, argptr);
1129 	va_end( argptr );
1130 
1131 	if ( ( len = strlen( temp_buffer ) ) >= MAX_VA_STRING ) {
1132 		Com_Error( ERR_DROP, "Attempted to overrun string in call to va()\n" );
1133 	}
1134 
1135 	if ( len + index >= MAX_VA_STRING - 1 ) {
1136 		index = 0;
1137 	}
1138 
1139 	buf = &string[index];
1140 	memcpy( buf, temp_buffer, len + 1 );
1141 
1142 	index += len + 1;
1143 
1144 	return buf;
1145 }
1146 
1147 /*
1148 ============
1149 Com_TruncateLongString
1150 
1151 Assumes buffer is atleast TRUNCATE_LENGTH big
1152 ============
1153 */
Com_TruncateLongString(char * buffer,const char * s)1154 void Com_TruncateLongString( char *buffer, const char *s )
1155 {
1156 	int length = strlen( s );
1157 
1158 	if( length <= TRUNCATE_LENGTH )
1159 		Q_strncpyz( buffer, s, TRUNCATE_LENGTH );
1160 	else
1161 	{
1162 		Q_strncpyz( buffer, s, ( TRUNCATE_LENGTH / 2 ) - 3 );
1163 		Q_strcat( buffer, TRUNCATE_LENGTH, " ... " );
1164 		Q_strcat( buffer, TRUNCATE_LENGTH, s + length - ( TRUNCATE_LENGTH / 2 ) + 3 );
1165 	}
1166 }
1167 
1168 /*
1169 =============
1170 TempVector
1171 
1172 (SA) this is straight out of g_utils.c around line 210
1173 
1174 This is just a convenience function
1175 for making temporary vectors for function calls
1176 =============
1177 */
tv(float x,float y,float z)1178 float   *tv( float x, float y, float z ) {
1179 	static int index;
1180 	static vec3_t vecs[8];
1181 	float   *v;
1182 
1183 	// use an array so that multiple tempvectors won't collide
1184 	// for a while
1185 	v = vecs[index];
1186 	index = ( index + 1 ) & 7;
1187 
1188 	v[0] = x;
1189 	v[1] = y;
1190 	v[2] = z;
1191 
1192 	return v;
1193 }
1194 
1195 /*
1196 =====================================================================
1197 
1198   INFO STRINGS
1199 
1200 =====================================================================
1201 */
1202 
1203 /*
1204 ===============
1205 Info_ValueForKey
1206 
1207 Searches the string for the given
1208 key and returns the associated value, or an empty string.
1209 FIXME: overflow check?
1210 ===============
1211 */
Info_ValueForKey(const char * s,const char * key)1212 char *Info_ValueForKey( const char *s, const char *key ) {
1213 	char pkey[BIG_INFO_KEY];
1214 	static char value[2][BIG_INFO_VALUE];   // use two buffers so compares
1215 											// work without stomping on each other
1216 	static int valueindex = 0;
1217 	char    *o;
1218 
1219 	if ( !s || !key ) {
1220 		return "";
1221 	}
1222 
1223 	if ( strlen( s ) >= BIG_INFO_STRING ) {
1224 		Com_Error( ERR_DROP, "Info_ValueForKey: oversize infostring" );
1225 	}
1226 
1227 	valueindex ^= 1;
1228 	if ( *s == '\\' ) {
1229 		s++;
1230 	}
1231 	while ( 1 )
1232 	{
1233 		o = pkey;
1234 		while ( *s != '\\' )
1235 		{
1236 			if ( !*s ) {
1237 				return "";
1238 			}
1239 			*o++ = *s++;
1240 		}
1241 		*o = 0;
1242 		s++;
1243 
1244 		o = value[valueindex];
1245 
1246 		while ( *s != '\\' && *s )
1247 		{
1248 			*o++ = *s++;
1249 		}
1250 		*o = 0;
1251 
1252 		if ( !Q_stricmp( key, pkey ) ) {
1253 			return value[valueindex];
1254 		}
1255 
1256 		if ( !*s ) {
1257 			break;
1258 		}
1259 		s++;
1260 	}
1261 
1262 	return "";
1263 }
1264 
1265 
1266 /*
1267 ===================
1268 Info_NextPair
1269 
1270 Used to itterate through all the key/value pairs in an info string
1271 ===================
1272 */
Info_NextPair(const char ** head,char * key,char * value)1273 void Info_NextPair( const char **head, char *key, char *value ) {
1274 	char    *o;
1275 	const char  *s;
1276 
1277 	s = *head;
1278 
1279 	if ( *s == '\\' ) {
1280 		s++;
1281 	}
1282 	key[0] = 0;
1283 	value[0] = 0;
1284 
1285 	o = key;
1286 	while ( *s != '\\' ) {
1287 		if ( !*s ) {
1288 			*o = 0;
1289 			*head = s;
1290 			return;
1291 		}
1292 		*o++ = *s++;
1293 	}
1294 	*o = 0;
1295 	s++;
1296 
1297 	o = value;
1298 	while ( *s != '\\' && *s ) {
1299 		*o++ = *s++;
1300 	}
1301 	*o = 0;
1302 
1303 	*head = s;
1304 }
1305 
1306 
1307 /*
1308 ===================
1309 Info_RemoveKey
1310 ===================
1311 */
Info_RemoveKey(char * s,const char * key)1312 void Info_RemoveKey( char *s, const char *key ) {
1313 	char    *start;
1314 	char pkey[MAX_INFO_KEY];
1315 	char value[MAX_INFO_VALUE];
1316 	char    *o;
1317 
1318 	if ( strlen( s ) >= MAX_INFO_STRING ) {
1319 		Com_Error( ERR_DROP, "Info_RemoveKey: oversize infostring" );
1320 	}
1321 
1322 	if ( strchr( key, '\\' ) ) {
1323 		return;
1324 	}
1325 
1326 	while ( 1 )
1327 	{
1328 		start = s;
1329 		if ( *s == '\\' ) {
1330 			s++;
1331 		}
1332 		o = pkey;
1333 		while ( *s != '\\' )
1334 		{
1335 			if ( !*s ) {
1336 				return;
1337 			}
1338 			*o++ = *s++;
1339 		}
1340 		*o = 0;
1341 		s++;
1342 
1343 		o = value;
1344 		while ( *s != '\\' && *s )
1345 		{
1346 			if ( !*s ) {
1347 				return;
1348 			}
1349 			*o++ = *s++;
1350 		}
1351 		*o = 0;
1352 
1353 		if ( !strcmp( key, pkey ) ) {
1354 			memmove(start, s, strlen(s) + 1); // remove this part
1355 			return;
1356 		}
1357 
1358 		if ( !*s ) {
1359 			return;
1360 		}
1361 	}
1362 
1363 }
1364 
1365 /*
1366 ===================
1367 Info_RemoveKey_Big
1368 ===================
1369 */
Info_RemoveKey_Big(char * s,const char * key)1370 void Info_RemoveKey_Big( char *s, const char *key ) {
1371 	char    *start;
1372 	char pkey[BIG_INFO_KEY];
1373 	char value[BIG_INFO_VALUE];
1374 	char    *o;
1375 
1376 	if ( strlen( s ) >= BIG_INFO_STRING ) {
1377 		Com_Error( ERR_DROP, "Info_RemoveKey_Big: oversize infostring" );
1378 	}
1379 
1380 	if ( strchr( key, '\\' ) ) {
1381 		return;
1382 	}
1383 
1384 	while ( 1 )
1385 	{
1386 		start = s;
1387 		if ( *s == '\\' ) {
1388 			s++;
1389 		}
1390 		o = pkey;
1391 		while ( *s != '\\' )
1392 		{
1393 			if ( !*s ) {
1394 				return;
1395 			}
1396 			*o++ = *s++;
1397 		}
1398 		*o = 0;
1399 		s++;
1400 
1401 		o = value;
1402 		while ( *s != '\\' && *s )
1403 		{
1404 			if ( !*s ) {
1405 				return;
1406 			}
1407 			*o++ = *s++;
1408 		}
1409 		*o = 0;
1410 
1411 		if ( !strcmp( key, pkey ) ) {
1412 			memmove(start, s, strlen(s) + 1); // remove this part
1413 			return;
1414 		}
1415 
1416 		if ( !*s ) {
1417 			return;
1418 		}
1419 	}
1420 
1421 }
1422 
1423 
1424 
1425 
1426 /*
1427 ==================
1428 Info_Validate
1429 
1430 Some characters are illegal in info strings because they
1431 can mess up the server's parsing
1432 ==================
1433 */
Info_Validate(const char * s)1434 qboolean Info_Validate( const char *s ) {
1435 	if ( strchr( s, '\"' ) ) {
1436 		return qfalse;
1437 	}
1438 	if ( strchr( s, ';' ) ) {
1439 		return qfalse;
1440 	}
1441 	return qtrue;
1442 }
1443 
1444 /*
1445 ==================
1446 Info_SetValueForKey
1447 
1448 Changes or adds a key/value pair
1449 ==================
1450 */
Info_SetValueForKey(char * s,const char * key,const char * value)1451 void Info_SetValueForKey( char *s, const char *key, const char *value ) {
1452 	char newi[MAX_INFO_STRING];
1453 	const char* blacklist = "\\;\"";
1454 
1455 	if ( strlen( s ) >= MAX_INFO_STRING ) {
1456 		Com_Error( ERR_DROP, "Info_SetValueForKey: oversize infostring" );
1457 	}
1458 
1459 	for(; *blacklist; ++blacklist)
1460 	{
1461 		if (strchr (key, *blacklist) || strchr (value, *blacklist))
1462 		{
1463 			Com_Printf (S_COLOR_YELLOW "Can't use keys or values with a '%c': %s = %s\n", *blacklist, key, value);
1464 			return;
1465 		}
1466 	}
1467 
1468 	Info_RemoveKey( s, key );
1469 	if ( !value || !strlen( value ) ) {
1470 		return;
1471 	}
1472 
1473 	Com_sprintf( newi, sizeof( newi ), "\\%s\\%s", key, value );
1474 
1475 	if ( strlen( newi ) + strlen( s ) >= MAX_INFO_STRING ) {
1476 		Com_Printf( "Info string length exceeded\n" );
1477 		return;
1478 	}
1479 
1480 	strcat (newi, s);
1481 	strcpy (s, newi);
1482 }
1483 
1484 /*
1485 ==================
1486 Info_SetValueForKey_Big
1487 
1488 Changes or adds a key/value pair
1489 Includes and retains zero-length values
1490 ==================
1491 */
Info_SetValueForKey_Big(char * s,const char * key,const char * value)1492 void Info_SetValueForKey_Big( char *s, const char *key, const char *value ) {
1493 	char newi[BIG_INFO_STRING];
1494 	const char* blacklist = "\\;\"";
1495 
1496 	if ( strlen( s ) >= BIG_INFO_STRING ) {
1497 		Com_Error( ERR_DROP, "Info_SetValueForKey: oversize infostring" );
1498 	}
1499 
1500 	for(; *blacklist; ++blacklist)
1501 	{
1502 		if (strchr (key, *blacklist) || strchr (value, *blacklist))
1503 		{
1504 			Com_Printf (S_COLOR_YELLOW "Can't use keys or values with a '%c': %s = %s\n", *blacklist, key, value);
1505 			return;
1506 		}
1507 	}
1508 
1509 	Info_RemoveKey_Big( s, key );
1510 	if ( !value ) {
1511 		return;
1512 	}
1513 
1514 	Com_sprintf( newi, sizeof( newi ), "\\%s\\%s", key, value );
1515 
1516 	if ( strlen( newi ) + strlen( s ) >= BIG_INFO_STRING ) {
1517 		Com_Printf( "BIG Info string length exceeded\n" );
1518 		return;
1519 	}
1520 
1521 	strcat( s, newi );
1522 }
1523 
1524 
1525 
1526 
1527 //====================================================================
1528 
1529 /*
1530 ==================
1531 Com_CharIsOneOfCharset
1532 ==================
1533 */
Com_CharIsOneOfCharset(char c,char * set)1534 static qboolean Com_CharIsOneOfCharset( char c, char *set )
1535 {
1536 	int i;
1537 
1538 	for( i = 0; i < strlen( set ); i++ )
1539 	{
1540 		if( set[ i ] == c )
1541 			return qtrue;
1542 	}
1543 
1544 	return qfalse;
1545 }
1546 
1547 /*
1548 ==================
1549 Com_SkipCharset
1550 ==================
1551 */
Com_SkipCharset(char * s,char * sep)1552 char *Com_SkipCharset( char *s, char *sep )
1553 {
1554 	char	*p = s;
1555 
1556 	while( p )
1557 	{
1558 		if( Com_CharIsOneOfCharset( *p, sep ) )
1559 			p++;
1560 		else
1561 			break;
1562 	}
1563 
1564 	return p;
1565 }
1566 
1567 /*
1568 ==================
1569 Com_SkipTokens
1570 ==================
1571 */
Com_SkipTokens(char * s,int numTokens,char * sep)1572 char *Com_SkipTokens( char *s, int numTokens, char *sep )
1573 {
1574 	int		sepCount = 0;
1575 	char	*p = s;
1576 
1577 	while( sepCount < numTokens )
1578 	{
1579 		if( Com_CharIsOneOfCharset( *p++, sep ) )
1580 		{
1581 			sepCount++;
1582 			while( Com_CharIsOneOfCharset( *p, sep ) )
1583 				p++;
1584 		}
1585 		else if( *p == '\0' )
1586 			break;
1587 	}
1588 
1589 	if( sepCount == numTokens )
1590 		return p;
1591 	else
1592 		return s;
1593 }
1594