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