1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 */
20 // common.c -- misc functions used in client and server
21 #include "qcommon.h"
22 #include "version.h"
23 #include <setjmp.h>
24 #include <zlib.h>
25 
26 #define COM_LOGFILE_NAME	"qconsole.log"
27 #define COM_CONFIG_NAME		"q2config.cfg"
28 #define COM_DEFAULTCFG_NAME		"default.cfg"
29 #define COM_AUTOEXECCFG_NAME		"autoexec.cfg"
30 
31 commonAPI_t	com;
32 
33 static jmp_buf abortframe;		// an ERR_DROP occured, exit the entire frame
34 
35 static char		com_errorMsg[MAXPRINTMSG];
36 
37 cvar_t	*host_speeds;
38 cvar_t	*developer;
39 cvar_t	*timescale;
40 cvar_t	*fixedtime;
41 cvar_t	*dedicated;
42 
43 cvar_t	*logfile_active;	// 1 = create new, 2 = append to existing
44 cvar_t	*logfile_flush;		// 1 = flush after each print
45 cvar_t	*logfile_name;
46 
47 cvar_t	*sv_running;
48 cvar_t	*sv_paused;
49 cvar_t	*cl_running;
50 cvar_t	*cl_paused;
51 cvar_t	*com_timedemo;
52 cvar_t	*com_sleep;
53 cvar_t	*com_date_format;
54 cvar_t	*com_time_format;
55 cvar_t	*com_debug_break;
56 
57 //
58 // userinfo
59 //
60 cvar_t	*info_password;
61 cvar_t	*info_spectator;
62 cvar_t	*info_name;
63 cvar_t	*info_skin;
64 cvar_t	*info_rate;
65 cvar_t	*info_fov;
66 cvar_t	*info_msg;
67 cvar_t	*info_hand;
68 cvar_t	*info_gender;
69 
70 fileHandle_t	com_logFile;
71 uint32		com_framenum;
72 uint32		com_eventTime;
73 
74 // host_speeds times
75 int		time_before_game;
76 int		time_after_game;
77 int		time_before_ref;
78 int		time_after_ref;
79 
80 void Con_Init( void );
81 void Prompt_Init( void );
82 void SCR_EndLoadingPlaque( void );
83 
84 /*
85 ============================================================================
86 
87 CLIENT / SERVER interactions
88 
89 ============================================================================
90 */
91 
92 static int	rd_target;
93 static char	*rd_buffer;
94 static int	rd_buffersize;
95 static void	(*rd_flush)(int target, char *buffer);
96 
Com_BeginRedirect(int target,char * buffer,int buffersize,void (* flush))97 void Com_BeginRedirect (int target, char *buffer, int buffersize, void (*flush))
98 {
99 	if (!target || !buffer || !buffersize || !flush)
100 		return;
101 	rd_target = target;
102 	rd_buffer = buffer;
103 	rd_buffersize = buffersize;
104 	rd_flush = flush;
105 
106 	*rd_buffer = 0;
107 }
108 
Com_EndRedirect(void)109 void Com_EndRedirect (void)
110 {
111 	rd_flush(rd_target, rd_buffer);
112 
113 	rd_target = 0;
114 	rd_buffer = NULL;
115 	rd_buffersize = 0;
116 	rd_flush = NULL;
117 }
118 
LogFile_Close(void)119 static void LogFile_Close( void ) {
120 	if( !com_logFile ) {
121 		return;
122 	}
123 
124 	Com_Printf( "Closing %s\n", FS_GetFileName( com_logFile ) );
125 
126 	FS_FCloseFile( com_logFile );
127 	com_logFile = 0;
128 }
129 
LogFile_Open(void)130 static void LogFile_Open( void ) {
131 	uint32		mode;
132 
133 	mode = logfile_active->integer > 1 ? FS_MODE_APPEND : FS_MODE_WRITE;
134 
135 	if( logfile_flush->integer ) {
136 		mode |= FS_FLUSH_SYNC;
137 	}
138 
139 	FS_FOpenFile( logfile_name->string, &com_logFile, mode );
140 
141 	if( !com_logFile ) {
142 		Com_WPrintf( "Couldn't open %s\n", logfile_name->string );
143 		Cvar_SetInteger( "logfile", 0 );
144 		return;
145 	}
146 
147 	Com_Printf( "Logging console to %s\n", logfile_name->string );
148 }
149 
LogFileActive_OnChange(cvar_t * self,void * arg)150 static void LogFileActive_OnChange( cvar_t *self, void *arg ) {
151 	if( !self->integer ) {
152 		LogFile_Close();
153 	} else {
154 		LogFile_Open();
155 	}
156 }
157 
LogFileParam_OnChange(cvar_t * self,void * arg)158 static void LogFileParam_OnChange( cvar_t *self, void *arg ) {
159 	if( logfile_active->integer ) {
160 		LogFile_Close();
161 		LogFile_Open();
162 	}
163 }
164 
LogFile_Output(const char * string)165 static void LogFile_Output( const char *string ) {
166 	char text[MAXPRINTMSG];
167 	char *p;
168 	int length;
169 
170 	/* not checking for overflow - buffer size is
171 	 * large enough, and length may only decrease.
172 	 */
173 	p = text;
174 	while( *string ) {
175 		if( Q_IsColorString( string ) ) {
176 			string += 2;
177 			continue;
178 		}
179 
180 		*p++ = *string++;
181 	}
182 	*p = 0;
183 
184 	length = p - text;
185 	FS_Write( text, length, com_logFile );
186 }
187 
188 /*
189 =============
190 Com_Printf
191 
192 Both client and server can use this, and it will output
193 to the apropriate place.
194 =============
195 */
Com_Printf(const char * fmt,...)196 void Com_Printf( const char *fmt, ... ) {
197 	va_list		argptr;
198 	char		msg[MAXPRINTMSG];
199 	static int	recursive;
200 	int			length;
201 
202 	if( recursive == 2 ) {
203 		return;
204 	}
205 
206 	recursive++;
207 
208 	va_start( argptr, fmt );
209 	length = Q_vsnprintf( msg, sizeof( msg ), fmt, argptr );
210 	va_end( argptr );
211 
212 	if( rd_target ) {
213 		if( length + strlen( rd_buffer ) > rd_buffersize - 1 ) {
214 			rd_flush( rd_target, rd_buffer );
215 			*rd_buffer = 0;
216 		}
217 		Q_strcat( rd_buffer, rd_buffersize, msg );
218 	} else {
219 		Con_Print( msg );
220 
221 		// also echo to debugging console
222 		Sys_ConsoleOutput( msg );
223 
224 		// logfile
225 		if( com_logFile ) {
226 			LogFile_Output( msg );
227 		}
228 	}
229 
230 	recursive--;
231 
232 }
233 
234 
235 /*
236 ================
237 Com_DPrintf
238 
239 A Com_Printf that only shows up if the "developer" cvar is set
240 ================
241 */
Com_DPrintf(const char * fmt,...)242 void Com_DPrintf( const char *fmt, ... ) {
243 	va_list		argptr;
244 	char		msg[MAXPRINTMSG];
245 
246 	if( !developer || !developer->integer )
247 		return;			// don't confuse non-developers with techie stuff...
248 
249 	va_start( argptr, fmt );
250 	Q_vsnprintf( msg, sizeof( msg ), fmt, argptr );
251 	va_end( argptr );
252 
253 	Com_Printf( S_COLOR_BLUE"%s", msg );
254 }
255 
256 /*
257 ================
258 Com_WPrintf
259 
260 ================
261 */
Com_WPrintf(const char * fmt,...)262 void Com_WPrintf( const char *fmt, ... ) {
263 	va_list		argptr;
264 	char		msg[MAXPRINTMSG];
265 
266 	va_start( argptr, fmt );
267 	Q_vsnprintf( msg, sizeof( msg ), fmt, argptr );
268 	va_end( argptr );
269 
270 	Com_Printf( S_COLOR_YELLOW"WARNING: %s", msg );
271 }
272 
273 /*
274 ================
275 Com_EPrintf
276 
277 ================
278 */
Com_EPrintf(const char * fmt,...)279 void Com_EPrintf( const char *fmt, ... ) {
280 	va_list		argptr;
281 	char		msg[MAXPRINTMSG];
282 
283 	va_start( argptr, fmt );
284 	Q_vsnprintf( msg, sizeof( msg ), fmt, argptr );
285 	va_end( argptr );
286 
287 	Com_Printf( S_COLOR_RED"ERROR: %s", msg );
288 }
289 
290 
291 /*
292 =============
293 Com_Error
294 
295 Both client and server can use this, and it will
296 do the apropriate things.
297 =============
298 */
Com_Error(comErrorType_t code,const char * fmt,...)299 void Com_Error( comErrorType_t code, const char *fmt, ... ) {
300 	va_list		argptr;
301 	static	qboolean	recursive;
302 
303 	if( recursive ) {
304 #ifndef NDEBUG
305 		Sys_DebugBreak();
306 #endif
307 		Sys_Error( "recursive error after: %s", com_errorMsg );
308 	}
309 	recursive = qtrue;
310 
311 	va_start( argptr, fmt );
312 	Q_vsnprintf( com_errorMsg, sizeof( com_errorMsg ), fmt, argptr );
313 	va_end( argptr );
314 
315     /* fix up drity message buffers */
316     MSG_Init();
317 
318 	if( code == ERR_DISCONNECT || code == ERR_SILENT ) {
319 		SV_Shutdown( va( "Server was killed: %s", com_errorMsg ),
320                 KILL_DISCONNECT );
321 		CL_Disconnect( code, com_errorMsg );
322 		Com_Printf( S_COLOR_YELLOW "%s\n", com_errorMsg );
323 		recursive = qfalse;
324 		longjmp( abortframe, -1 );
325 	}
326 
327 	if( com_debug_break && com_debug_break->integer ) {
328 		Sys_DebugBreak();
329 	}
330 
331 	if( code == ERR_DROP ) {
332 		Com_Printf( S_COLOR_RED "********************\n"
333                                 "ERROR: %s\n"
334                                 "********************\n", com_errorMsg );
335 		SV_Shutdown( va( "Server crashed: %s\n", com_errorMsg ), KILL_DROP );
336 		CL_Disconnect( ERR_DROP, com_errorMsg );
337 		recursive = qfalse;
338 		longjmp( abortframe, -1 );
339 	}
340 
341 	if( com_logFile ) {
342 		FS_FPrintf( com_logFile, "FATAL: %s\n", com_errorMsg );
343 	}
344 
345 	SV_Shutdown( va( "Server fatal crashed: %s\n", com_errorMsg ), KILL_DROP );
346 	CL_Shutdown();
347 	Qcommon_Shutdown( qtrue );
348 
349 	Sys_Error( "%s", com_errorMsg );
350 }
351 
352 /*
353 ===================
354 Com_LevelPrint
355 ===================
356 */
Com_LevelPrint(comPrintType_t type,const char * str)357 void Com_LevelPrint( comPrintType_t type, const char *str ) {
358 	switch( type ) {
359 	case PRINT_DEVELOPER:
360 		Com_DPrintf( "%s", str );
361 		break;
362 	case PRINT_WARNING:
363 		Com_WPrintf( "%s", str );
364 		break;
365 	case PRINT_ERROR:
366 		Com_EPrintf( "%s", str );
367 		break;
368 	default:
369 		Com_Printf( "%s", str );
370 		break;
371 	}
372 }
373 
374 /*
375 ===================
376 Com_LevelError
377 ===================
378 */
Com_LevelError(comErrorType_t code,const char * str)379 void Com_LevelError( comErrorType_t code, const char *str ) {
380 	Com_Error( code, "%s", str );
381 }
382 
383 /*
384 =============
385 Com_Quit
386 
387 Both client and server can use this, and it will
388 do the apropriate things.
389 =============
390 */
Com_Quit(void)391 void Com_Quit( void ) {
392 	SV_Shutdown( "Server quit\n", KILL_DROP );
393 	CL_Shutdown();
394 	Qcommon_Shutdown( qfalse );
395 
396 	Sys_Quit();
397 }
398 
399 
400 // ============================================================================
401 
402 #ifndef DEDICATED_ONLY
403 
404 /*
405 ===============
406 Com_WriteConfiguration
407 
408 Writes key bindings and archived cvars to config.cfg
409 ===============
410 */
Com_WriteConfiguration(const char * path)411 static qboolean Com_WriteConfiguration( const char *path ) {
412 	fileHandle_t f;
413 
414 	FS_FOpenFile( path, &f, FS_MODE_WRITE );
415 	if( !f ) {
416 		Com_WPrintf( "Couldn't write %s\n", path );
417 		return qfalse;
418 	}
419 
420 	FS_FPrintf( f, "// generated by q2pro, do not modify\n" );
421 
422 	Key_WriteBindings( f );
423 	Cvar_WriteVariables( f );
424 
425 	FS_FCloseFile( f );
426 
427 	return qtrue;
428 }
429 
430 /*
431 ===============
432 Com_WriteConfig_f
433 ===============
434 */
Com_WriteConfig_f(void)435 static void Com_WriteConfig_f( void ) {
436 	char buffer[MAX_QPATH];
437 
438 	if( Cmd_Argc() > 2 ) {
439 		Com_Printf( "Usage: %s [cfgfile]\n", Cmd_Argv( 0 ) );
440 		return;
441 	}
442 
443 	if( Cmd_Argc() < 2 ) {
444 		strcpy( buffer, COM_CONFIG_NAME );
445 	} else {
446 		Cmd_ArgvBuffer( 1, buffer, sizeof( buffer ) );
447 		COM_DefaultExtension( buffer, ".cfg", sizeof( buffer ) );
448 	}
449 
450 	if( Com_WriteConfiguration( buffer ) ) {
451 		Com_Printf( "Wrote %s\n", buffer );
452 	}
453 }
454 
455 #endif
456 
457 /*
458 ==============================================================================
459 
460 						ZONE MEMORY ALLOCATION
461 
462 just cleared malloc with counters now...
463 
464 ==============================================================================
465 */
466 
467 #define	Z_MAGIC		0x1d0d
468 #define	Z_TAIL		0x5b7b
469 
470 typedef struct zhead_s {
471 	uint16	magic;
472 	uint16	tag;			// for group free
473 	size_t	size;
474 	struct zhead_s	*prev, *next;
475 } zhead_t;
476 
477 static zhead_t		z_chain;
478 
479 typedef struct zstatic_s {
480 	zhead_t	z;
481 	char	data[2]; /* !!make sure 'tail' field is aligned properly */
482 	uint16	tail;
483 } zstatic_t;
484 
485 static zstatic_t		z_static[] = {
486 	{ { Z_MAGIC, TAG_STATIC, sizeof( zstatic_t ) }, { '0', '\0' }, Z_TAIL },
487 	{ { Z_MAGIC, TAG_STATIC, sizeof( zstatic_t ) }, { '1', '\0' }, Z_TAIL },
488 	{ { Z_MAGIC, TAG_STATIC, sizeof( zstatic_t ) }, { '2', '\0' }, Z_TAIL },
489 	{ { Z_MAGIC, TAG_STATIC, sizeof( zstatic_t ) }, { '3', '\0' }, Z_TAIL },
490 	{ { Z_MAGIC, TAG_STATIC, sizeof( zstatic_t ) }, { '4', '\0' }, Z_TAIL },
491 	{ { Z_MAGIC, TAG_STATIC, sizeof( zstatic_t ) }, { '5', '\0' }, Z_TAIL },
492 	{ { Z_MAGIC, TAG_STATIC, sizeof( zstatic_t ) }, { '6', '\0' }, Z_TAIL },
493 	{ { Z_MAGIC, TAG_STATIC, sizeof( zstatic_t ) }, { '7', '\0' }, Z_TAIL },
494 	{ { Z_MAGIC, TAG_STATIC, sizeof( zstatic_t ) }, { '8', '\0' }, Z_TAIL },
495 	{ { Z_MAGIC, TAG_STATIC, sizeof( zstatic_t ) }, { '9', '\0' }, Z_TAIL },
496 	{ { Z_MAGIC, TAG_STATIC, sizeof( zstatic_t ) }, { '\0'		}, Z_TAIL },
497 };
498 
499 typedef struct zstats_s {
500 	size_t  count;
501 	size_t	bytes;
502 	char	*name;
503 } zstats_t;
504 
505 static zstats_t		z_stats[TAG_MAX];
506 
Z_Check(void)507 void Z_Check( void ) {
508 	zhead_t	*z;
509 
510 	for( z = z_chain.next; z != &z_chain; z = z->next ) {
511 		if( z->magic != Z_MAGIC ) {
512 			Com_Error( ERR_FATAL, "Z_Check: bad magic" );
513         }
514 
515 		if( *( uint16 * )( ( byte * )z + z->size - sizeof( uint16 ) ) !=
516                 Z_TAIL )
517         {
518 			Com_Error( ERR_FATAL, "Z_Check: bad tail" );
519         }
520 
521 		if( z->tag == TAG_FREE ) {
522 			Com_Error( ERR_FATAL, "Z_Check: bad tag" );
523         }
524 	}
525 }
526 
Z_LeakTest(memtag_t tag)527 void Z_LeakTest( memtag_t tag ) {
528 	zhead_t	*z;
529 	zstats_t *s;
530 	size_t numLeaks, numBytes;
531 
532 	numLeaks = numBytes = 0;
533 	for( z = z_chain.next; z != &z_chain; z = z->next ) {
534 		if( z->magic != Z_MAGIC )
535 			Com_Error( ERR_FATAL, "Z_LeakTest: bad magic" );
536 
537 		if( *( uint16 * )( ( byte * )z + z->size - sizeof( uint16 ) ) !=
538                 Z_TAIL )
539         {
540 			Com_Error( ERR_FATAL, "Z_LeakTest: bad tail" );
541         }
542 
543 		if( z->tag == TAG_FREE ) {
544 			Com_Error( ERR_FATAL, "Z_LeakTest: bad tag" );
545         }
546 
547 		if( z->tag == tag ) {
548 			numLeaks++;
549 			numBytes += z->size;
550 		}
551 	}
552 
553 	if( numLeaks ) {
554 		s = &z_stats[tag < TAG_MAX ? tag : TAG_FREE];
555 		Com_Printf( S_COLOR_YELLOW "************* Z_LeakTest *************\n"
556 						           "%s leaked %u bytes of memory (%u object%s)\n"
557 						           "**************************************\n",
558 								   s->name, numBytes, numLeaks,
559 								   ( numLeaks % 10 ) == 1 ? "" : "s" );
560 	}
561 }
562 
563 /*
564 ========================
565 Z_Free
566 ========================
567 */
Z_Free(void * ptr)568 void Z_Free( void *ptr ) {
569 	zhead_t	*z;
570 	zstats_t *s;
571 
572 	if( !ptr ) {
573         return;
574 	}
575 
576 	z = ( ( zhead_t * )ptr ) - 1;
577 
578 	if( z->magic != Z_MAGIC ) {
579 		Com_Error( ERR_FATAL, "Z_Free: bad magic" );
580     }
581 
582 	if( *( uint16 * )( ( byte * )z + z->size - sizeof( uint16 ) ) != Z_TAIL ) {
583 		Com_Error( ERR_FATAL, "Z_Free: bad tail" );
584     }
585 
586 	if( z->tag == TAG_FREE ) {
587 		Com_Error( ERR_FATAL, "Z_Free: bad tag" );
588     }
589 
590 	s = &z_stats[z->tag < TAG_MAX ? z->tag : TAG_FREE];
591 	s->count--;
592 	s->bytes -= z->size;
593 
594 	if( z->tag != TAG_STATIC ) {
595     	z->prev->next = z->next;
596 	    z->next->prev = z->prev;
597 
598 	    free( z );
599     }
600 }
601 
602 /*
603 ========================
604 Z_Realloc
605 ========================
606 */
Z_Realloc(void * ptr,size_t size)607 void *Z_Realloc( void *ptr, size_t size ) {
608 	zhead_t	*z;
609 	zstats_t *s;
610 
611 	if( !ptr ) {
612         return Z_Malloc( size );
613 	}
614 
615     if( !size ) {
616         Z_Free( ptr );
617         return NULL;
618     }
619 
620 	z = ( ( zhead_t * )ptr ) - 1;
621 
622 	if( z->magic != Z_MAGIC ) {
623 		Com_Error( ERR_FATAL, "Z_Realloc: bad magic" );
624     }
625 
626 	if( *( uint16 * )( ( byte * )z + z->size - sizeof( uint16 ) ) != Z_TAIL ) {
627 		Com_Error( ERR_FATAL, "Z_Realloc: bad tail" );
628     }
629 
630 	if( z->tag == TAG_FREE ) {
631 		Com_Error( ERR_FATAL, "Z_Realloc: bad tag" );
632     }
633 
634 	if( z->tag == TAG_STATIC ) {
635         Z_Free( ptr );
636         return Z_Malloc( size );
637     }
638 
639 	s = &z_stats[z->tag < TAG_MAX ? z->tag : TAG_FREE];
640 	s->bytes -= z->size;
641 
642 	size += sizeof( zhead_t ) + sizeof( uint16 );
643 	size = ( size + 3 ) & ~3;
644 
645     z = realloc( z, size );
646     if( !z ) {
647 		Com_Error( ERR_FATAL, "Z_Realloc: couldn't reallocate %u bytes", size );
648     }
649 
650 	z->size = size;
651     z->prev->next = z;
652     z->next->prev = z;
653 
654 	s->bytes += size;
655 
656 	*( uint16 * )( ( byte * )z + size - sizeof( uint16 ) ) = Z_TAIL;
657 
658 	return ( void * )( z + 1 );
659 }
660 
661 /*
662 ========================
663 Z_Stats_f
664 ========================
665 */
Z_Stats_f(void)666 void Z_Stats_f( void ) {
667 	size_t z_bytes, z_count;
668 	zstats_t *s;
669 	int i;
670 
671 	Com_Printf( "-----------------\n" );
672 	Com_Printf( "    bytes  blocks\n\n" );
673 
674 	z_bytes = 0;
675 	z_count = 0;
676 	for( i = 0, s = z_stats; i < TAG_MAX; i++, s++ ) {
677         if( !s->count ) {
678             continue;
679         }
680 
681 		Com_Printf( "%9u  %6u  %s\n", s->bytes, s->count, s->name );
682 		z_bytes += s->bytes;
683 		z_count += s->count;
684 	}
685 
686 	Com_Printf( "-----------------\n" );
687 	Com_Printf( "%9u  %6u  %s\n", z_bytes, z_count, "total" );
688 }
689 
690 /*
691 ========================
692 Z_FreeTags
693 ========================
694 */
Z_FreeTags(memtag_t tag)695 void Z_FreeTags( memtag_t tag ) {
696 	zhead_t	*z, *next;
697 
698 	for( z = z_chain.next; z != &z_chain; z = next ) {
699 		if( z->magic != Z_MAGIC ) {
700 			Com_Error( ERR_FATAL, "Z_FreeTags: bad magic" );
701         }
702 
703 		if( *( uint16 * )( ( byte * )z + z->size - sizeof( uint16 ) ) !=
704                 Z_TAIL )
705         {
706 			Com_Error( ERR_FATAL, "Z_FreeTags: bad tail" );
707         }
708 
709 		if( z->tag == TAG_FREE ) {
710 			Com_Error( ERR_FATAL, "Z_FreeTags: bad tag" );
711         }
712 		next = z->next;
713 		if( z->tag == tag ) {
714 			Z_Free( ( void * )( z + 1 ) );
715 		}
716 	}
717 }
718 
719 /*
720 ========================
721 Z_TagMalloc
722 ========================
723 */
Z_TagMalloc(size_t size,memtag_t tag)724 void *Z_TagMalloc( size_t size, memtag_t tag ) {
725 	zhead_t	*z;
726 	zstats_t *s;
727 
728 	if( !size ) {
729 		return NULL;
730 	}
731 
732 	if( tag == TAG_FREE )
733 		Com_Error( ERR_FATAL, "Z_TagMalloc: bad tag" );
734 
735 	size += sizeof( zhead_t ) + sizeof( uint16 );
736 	size = ( size + 3 ) & ~3;
737 	z = malloc( size );
738 	if( !z ) {
739 		Com_Error( ERR_FATAL, "Z_TagMalloc: couldn't allocate %u bytes", size );
740     }
741 	z->magic = Z_MAGIC;
742 	z->tag = tag;
743 	z->size = size;
744 
745 	z->next = z_chain.next;
746 	z->prev = &z_chain;
747 	z_chain.next->prev = z;
748 	z_chain.next = z;
749 
750 	*( uint16 * )( ( byte * )z + size - sizeof( uint16 ) ) = Z_TAIL;
751 
752 	s = &z_stats[tag < TAG_MAX ? tag : TAG_FREE];
753 	s->count++;
754 	s->bytes += size;
755 
756 	return ( void * )( z + 1 );
757 }
758 
Z_TagMallocz(size_t size,memtag_t tag)759 void *Z_TagMallocz( size_t size, memtag_t tag ) {
760     void *ptr;
761 
762     if( !size ) {
763         return NULL;
764     }
765 
766     ptr = Z_TagMalloc( size, tag );
767     memset( ptr, 0, size );
768 
769     return ptr;
770 }
771 
772 static byte *z_reserved;
773 static size_t z_reservedUnuse;
774 static size_t z_reservedTotal;
775 
Z_TagReserve(size_t size,memtag_t tag)776 void Z_TagReserve( size_t size, memtag_t tag ) {
777 	z_reserved = Z_TagMalloc( size, tag );
778 	z_reservedTotal = size;
779 	z_reservedUnuse = 0;
780 }
781 
Z_ReservedAlloc(size_t size)782 void *Z_ReservedAlloc( size_t size ) {
783 	byte *ptr;
784 
785 	if( z_reservedUnuse + size > z_reservedTotal ) {
786 		Com_Error( ERR_FATAL, "Z_ReservedAlloc: out of space" );
787 	}
788 
789 	ptr = z_reserved + z_reservedUnuse;
790 	z_reservedUnuse += size;
791 
792 	return ( void * )ptr;
793 
794 }
795 
Z_ReservedCopyString(const char * in)796 char *Z_ReservedCopyString( const char *in ) {
797 	char	*out;
798 	int length;
799 
800 	if( !in ) {
801 		return NULL;
802 	}
803 
804 	length = strlen( in ) + 1;
805 
806 	out = Z_ReservedAlloc( length );
807 	strcpy( out, in );
808 
809 	return out;
810 }
811 
812 /*
813 ========================
814 Z_Init
815 ========================
816 */
Z_Init(void)817 void Z_Init( void ) {
818 	zstats_t *s;
819 	int i;
820 	static char *names[TAG_MAX] = {
821 		"game",
822 		"static",
823 		"generic",
824 		"cmd",
825 		"cvar",
826 		"filesystem",
827 		"renderer",
828 		"ui",
829 		"cgame",
830         "server",
831 		"mvd",
832         "sound",
833 		"cmodel",
834         "lua"
835 	};
836 
837 	z_chain.next = z_chain.prev = &z_chain;
838 
839 	for( i = 0, s = z_stats; i < TAG_MAX; i++, s++ ) {
840 		s->name = names[i] ? names[i] : "unknown";
841 	}
842 }
843 
844 /*
845 ================
846 Z_TagCopyString
847 ================
848 */
Z_TagCopyString(const char * in,memtag_t tag)849 char *Z_TagCopyString( const char *in, memtag_t tag ) {
850 	char	*out;
851 	int length;
852 
853 	if( !in ) {
854 		return NULL;
855 	}
856 
857 	length = strlen( in ) + 1;
858 
859 	out = Z_TagMalloc( length, tag );
860 	strcpy( out, in );
861 
862 	return out;
863 }
864 
865 /*
866 ================
867 Cvar_CopyString
868 ================
869 */
Cvar_CopyString(const char * in)870 char *Cvar_CopyString( const char *in ) {
871 	char	*out;
872 	int length;
873     zstatic_t *z;
874 
875 	if( !in ) {
876 		return NULL;
877 	}
878 
879 	if( !in[0] ) {
880         z = &z_static[10];
881         z_stats[TAG_STATIC].count++;
882         z_stats[TAG_STATIC].bytes += z->z.size;
883 		return z->data;
884 	}
885 
886 	if( !in[1] && Q_isdigit( in[0] ) ) {
887         z = &z_static[ in[0] - '0' ];
888         z_stats[TAG_STATIC].count++;
889         z_stats[TAG_STATIC].bytes += z->z.size;
890 		return z->data;
891 	}
892 
893 	length = strlen( in ) + 1;
894 
895 	out = Z_TagMalloc( length, TAG_CVAR );
896 	strcpy( out, in );
897 
898 	return out;
899 }
900 
901 /*
902 ==============================================================================
903 
904 						INTERFACE TO ZLIB
905 
906 ==============================================================================
907 */
908 
909 static z_stream		com_zStream;
910 static sizebuf_t	*com_zOutputBuf;
911 
912 #define ZLIB_WINDOW_BITS	( -15 )
913 
914 /*
915 =============
916 Com_ZLibDeflateStart
917 =============
918 */
Com_ZLibDeflateStart(sizebuf_t * outputBuf)919 qboolean Com_ZLibDeflateStart( sizebuf_t *outputBuf ) {
920 	memset( &com_zStream, 0, sizeof( com_zStream ) );
921 	com_zStream.next_out = outputBuf->data;
922 	com_zStream.avail_out = outputBuf->maxsize;
923 
924 	if( deflateInit2( &com_zStream, Z_BEST_COMPRESSION, Z_DEFLATED,
925                 ZLIB_WINDOW_BITS, 9, Z_DEFAULT_STRATEGY ) != Z_OK )
926     {
927 		return qfalse;
928 	}
929 
930 	SZ_Clear( outputBuf );
931 	com_zOutputBuf = outputBuf;
932 
933 	return qtrue;
934 }
935 
936 /*
937 =============
938 Com_ZLibDeflateChunk
939 =============
940 */
Com_ZLibDeflateChunk(sizebuf_t * inputBuf)941 qboolean Com_ZLibDeflateChunk( sizebuf_t *inputBuf ) {
942 	com_zStream.next_in = inputBuf->data;
943 	com_zStream.avail_in = inputBuf->cursize;
944 
945 	if( deflate( &com_zStream, Z_SYNC_FLUSH ) != Z_OK ) {
946 		return qfalse;
947 	}
948 
949 	if( !com_zStream.avail_out ) {
950 		return qfalse;
951 	}
952 
953 	com_zOutputBuf->cursize = com_zStream.total_out;
954 
955 	return qtrue;
956 }
957 
958 /*
959 =============
960 Com_ZLibDeflateAbort
961 =============
962 */
Com_ZLibDeflateAbort(void)963 void Com_ZLibDeflateAbort( void ) {
964 	deflateEnd( &com_zStream );
965 	com_zOutputBuf = NULL;
966 }
967 
968 /*
969 =============
970 Com_ZLibDeflateFinish
971 =============
972 */
Com_ZLibDeflateFinish(void)973 qboolean Com_ZLibDeflateFinish( void ) {
974 	if( deflate( &com_zStream, Z_FINISH ) != Z_STREAM_END ) {
975 		Com_ZLibDeflateAbort();
976 		return qfalse;
977 	}
978 
979 	com_zOutputBuf->cursize = com_zStream.total_out;
980 	com_zOutputBuf = NULL;
981 
982 	if( deflateEnd( &com_zStream ) != Z_OK ) {
983 		return qfalse;
984 	}
985 
986 	return qtrue;
987 }
988 
989 /*
990 =============
991 Com_ZLibDeflateBuffer
992 =============
993 */
Com_ZLibDeflateBuffer(sizebuf_t * inputBuf,sizebuf_t * outputBuf)994 qboolean Com_ZLibDeflateBuffer( sizebuf_t *inputBuf, sizebuf_t *outputBuf ) {
995 	z_stream	z;
996 
997 	memset( &z, 0, sizeof( z ) );
998 
999 	z.next_in = inputBuf->data;
1000 	z.avail_in = inputBuf->cursize;
1001 
1002 	SZ_Clear( outputBuf );
1003 	z.next_out = outputBuf->data;
1004 	z.avail_out = outputBuf->maxsize;
1005 
1006 	if( deflateInit2( &z, Z_BEST_COMPRESSION, Z_DEFLATED, ZLIB_WINDOW_BITS, 9,
1007                 Z_DEFAULT_STRATEGY ) != Z_OK )
1008     {
1009 		return qfalse;
1010 	}
1011 
1012 	if( deflate( &z, Z_FINISH ) != Z_STREAM_END ) {
1013 		deflateEnd( &z );
1014 		return qfalse;
1015 	}
1016 
1017 	if( deflateEnd( &z ) != Z_OK ) {
1018 		return qfalse;
1019 	}
1020 
1021 	outputBuf->cursize = z.total_out;
1022 
1023 	return qtrue;
1024 }
1025 
1026 /*
1027 =============
1028 Com_ZLibInflateBuffer
1029 =============
1030 */
Com_ZLibInflateBuffer(sizebuf_t * inputBuf,sizebuf_t * outputBuf,int length)1031 qboolean Com_ZLibInflateBuffer( sizebuf_t *inputBuf, sizebuf_t *outputBuf,
1032         int length )
1033 {
1034 	z_stream	z;
1035 
1036 	memset( &z, 0, sizeof( z ) );
1037 
1038 	z.next_in = inputBuf->data + inputBuf->readcount;
1039 	if( length ) {
1040 		if( length < 0 || inputBuf->readcount + length > inputBuf->cursize ) {
1041 			return qfalse;
1042 		}
1043 		z.avail_in = length;
1044 	} else {
1045 		z.avail_in = inputBuf->cursize - inputBuf->readcount;
1046 	}
1047 
1048 	SZ_Clear( outputBuf );
1049 	z.next_out = outputBuf->data;
1050 	z.avail_out = outputBuf->maxsize;
1051 
1052 	if( inflateInit2( &z, ZLIB_WINDOW_BITS ) != Z_OK ) {
1053 		return qfalse;
1054 	}
1055 
1056 	if( inflate( &z, Z_FINISH ) != Z_STREAM_END ) {
1057 		inflateEnd( &z );
1058 		return qfalse;
1059 	}
1060 
1061 	if( inflateEnd( &z ) != Z_OK ) {
1062 		return qfalse;
1063 	}
1064 
1065 	outputBuf->cursize = z.total_out;
1066 
1067 	return qtrue;
1068 }
1069 
MSG_ParseZPacket(void (* parsefunc)(void))1070 void MSG_ParseZPacket( void (*parsefunc)( void ) ) {
1071 	sizebuf_t	decompressed, temp;
1072 	byte		decompressed_data[MAX_MSGLEN];
1073 	int			compressedLength, decompressedLength;
1074 
1075 	if( msg_read.data != msg_read_buffer ) {
1076 		Com_Error( ERR_DROP, "MSG_ParseZPacket: recursively entered" );
1077 	}
1078 
1079 	compressedLength = MSG_ReadShort();
1080 	decompressedLength = MSG_ReadShort();
1081 
1082 	SZ_Init( &decompressed, decompressed_data, sizeof( decompressed_data ) );
1083 	if( !Com_ZLibInflateBuffer( &msg_read, &decompressed, compressedLength ) ||
1084 		decompressed.cursize != decompressedLength )
1085 	{
1086 		Com_Error( ERR_DROP,
1087                 "MSG_ParseZPacket: decompression of %d bytes into %d failed",
1088 			        compressedLength, decompressedLength );
1089 	}
1090 
1091 	temp = msg_read;
1092 	msg_read = decompressed;
1093 
1094 	(*parsefunc)();
1095 
1096 	msg_read = temp;
1097 	msg_read.readcount += compressedLength;
1098 }
1099 
1100 #ifndef NDEBUG
1101 /*
1102 =============
1103 Com_ZLibTest_f
1104 =============
1105 */
Com_ZLibTest_f(void)1106 static void Com_ZLibTest_f( void ) {
1107 	sizebuf_t in, out;
1108 	byte in_buf[1024], out_buf[1200];
1109 	int i;
1110 	int checksum;
1111 	int time = Sys_Milliseconds();
1112 
1113 	Com_Printf( "Testing ZLib on 1024 bytes of data...\n" );
1114 
1115 	SZ_Init( &in, in_buf, sizeof( in_buf ) );
1116 	SZ_Init( &out, out_buf, sizeof( out_buf ) );
1117 
1118 	for( i = 0; i < sizeof( in_buf ); i++ ) {
1119 		in_buf[i] = 'a' + ( rand() % ( 'z' - 'a' ) );
1120 	}
1121 
1122 	checksum = Com_BlockChecksum( in_buf, sizeof( in_buf ) );
1123 
1124 	if( !Com_ZLibDeflateStart( &out ) ) {
1125 		Com_Printf( "Com_ZLibDeflateStart() failed\n" );
1126 		return;
1127 	}
1128 
1129 	in.cursize = 256;
1130 	for( i = 0; i < sizeof( in_buf ) / 256; i++ ) {
1131 		if( !Com_ZLibDeflateChunk( &in ) ) {
1132 			Com_ZLibDeflateAbort();
1133 			Com_Printf( "Com_ZLibDeflateChunk() failed\n" );
1134 			return;
1135 		}
1136 		in.data += 256;
1137 	}
1138 
1139 	if( !Com_ZLibDeflateFinish() ) {
1140 		Com_Printf( "Com_ZLibDeflateFinish() failed\n" );
1141 		return;
1142 	}
1143 
1144 	Com_Printf( "Compressed to %i bytes\n", out.cursize );
1145 
1146 	SZ_Init( &in, in_buf, sizeof( in_buf ) );
1147 	memset( in_buf, 0, sizeof( in_buf ) );
1148 
1149 	if( !Com_ZLibInflateBuffer( &out, &in, 0 ) ) {
1150 		Com_Printf( "Com_ZLibInflateBuffer() failed\n" );
1151 		return;
1152 	}
1153 
1154 	Com_Printf( "Decompressed to %i bytes\n", in.cursize );
1155 
1156 	if( checksum != Com_BlockChecksum( in_buf, sizeof( in_buf ) ) ) {
1157 		Com_Printf( "Checksum mismatch!\n" );
1158 		return;
1159 	}
1160 
1161 	Com_Printf( "ZLib tested successfully (%i msec)\n",
1162             Sys_Milliseconds() - time );
1163 }
1164 
1165 #endif
1166 
1167 
1168 /*
1169 ==============================================================================
1170 
1171 						INIT / SHUTDOWN
1172 
1173 ==============================================================================
1174 */
1175 
1176 /*
1177 =============
1178 Com_FillAPI
1179 =============
1180 */
Com_FillAPI(commonAPI_t * api)1181 void Com_FillAPI( commonAPI_t *api ) {
1182 	api->Print = Com_LevelPrint;
1183 	api->Error = Com_LevelError;
1184 	api->TagMalloc = Z_TagMalloc;
1185     api->Realloc = Z_Realloc;
1186 	api->Free = Z_Free;
1187 }
1188 
1189 /*
1190 =============
1191 Com_Time_m
1192 =============
1193 */
Com_Time_m(char * buffer,int bufferSize)1194 void Com_Time_m( char *buffer, int bufferSize ) {
1195 #ifdef _WIN32_WCE
1196 	buffer[0] = 0;
1197 #else
1198 	time_t	clock;
1199 	struct tm	*localTime;
1200 
1201 	time( &clock );
1202 	localTime = localtime( &clock );
1203 
1204 	strftime( buffer, bufferSize, com_time_format->string, localTime );
1205 #endif
1206 }
1207 
1208 /*
1209 =============
1210 Com_Date_m
1211 =============
1212 */
Com_Date_m(char * buffer,int bufferSize)1213 static void Com_Date_m( char *buffer, int bufferSize ) {
1214 #ifdef _WIN32_WCE
1215 	buffer[0] = 0;
1216 #else
1217 	time_t	clock;
1218 	struct tm	*localTime;
1219 
1220 	time( &clock );
1221 	localTime = localtime( &clock );
1222 
1223 	strftime( buffer, bufferSize, com_date_format->string, localTime );
1224 #endif
1225 }
1226 
Com_LastError_f(void)1227 static void Com_LastError_f( void ) {
1228 	if( com_errorMsg[0] ) {
1229 		Com_Printf( "%s\n", com_errorMsg );
1230 	} else {
1231 		Com_Printf( "No error.\n" );
1232 	}
1233 }
1234 
1235 #ifndef NDEBUG
1236 
1237 /*
1238 =============
1239 Com_Error_f
1240 
1241 Just throw a fatal error to
1242 test error shutdown procedures
1243 =============
1244 */
Com_Error_f(void)1245 void Com_Error_f( void ) {
1246 	Com_Error( ERR_FATAL, "%s", Cmd_Argv( 1 ) );
1247 }
1248 
Com_ErrorDrop_f(void)1249 void Com_ErrorDrop_f( void ) {
1250 	Com_Error( ERR_DROP, "%s", Cmd_Argv( 1 ) );
1251 }
1252 
Com_Freeze_f(void)1253 void Com_Freeze_f( void ) {
1254 	int seconds, time;
1255 
1256 	if( Cmd_Argc() < 2 ) {
1257 		Com_Printf( "Usage: %s <seconds>\n", Cmd_Argv( 0 ) );
1258 		return;
1259 	}
1260 
1261 	seconds = atoi( Cmd_Argv( 1 ) );
1262 	if( seconds < 1 ) {
1263 		return;
1264 	}
1265 
1266 	time = Sys_Milliseconds() + seconds * 1000;
1267 	while( Sys_Milliseconds() < time )
1268 		;
1269 
1270 }
1271 
Com_Crash_f(void)1272 void Com_Crash_f( void ) {
1273 	*( uint32 * )0 = 0x123456;
1274 }
1275 
Com_VsnprintfTest_f(void)1276 static void Com_VsnprintfTest_f( void ) {
1277 	char buffer[32];
1278 	int ret;
1279 	qboolean fail;
1280 
1281 	/* test if returned length is valid, no overflow, large buffer */
1282 	Com_Printf( "test 1\n" );
1283 	fail = qfalse;
1284 	memset( buffer, '@', sizeof( buffer ) );
1285 	ret = Com_sprintf( buffer, sizeof( buffer ), "%s", "abcd" );
1286 	if( ret != 4 ) {
1287 		Com_Printf( "returned %d instead of %d\n", ret, 4 );
1288 		fail = qtrue;
1289 	}
1290 	if( buffer[4] != 0 ) {
1291 		Com_Printf( "buffer left unterminated\n" );
1292 		fail = qtrue;
1293 	}
1294 	if( buffer[5] != '@' ) {
1295 		Com_Printf( "buffer overflowed\n" );
1296 		fail = qtrue;
1297 	}
1298 	if( !fail ) {
1299 		Com_Printf( "succeeded\n" );
1300 	} else {
1301 		Com_Printf( "failed\n" );
1302 	}
1303 
1304 	/* test if returned length is valid, no overflow, small buffer */
1305 	Com_Printf( "test 2\n" );
1306 	fail = qfalse;
1307 	memset( buffer, '@', sizeof( buffer ) );
1308 	ret = Com_sprintf( buffer, 5, "%s", "abcd" );
1309 	if( ret != 4 ) {
1310 		Com_Printf( "returned %d instead of %d\n", ret, 4 );
1311 	}
1312 	if( buffer[4] != 0 ) {
1313 		Com_Printf( "buffer left unterminated\n" );
1314 		fail = qtrue;
1315 	}
1316 	if( buffer[5] != '@' ) {
1317 		Com_Printf( "buffer overflowed\n" );
1318 		fail = qtrue;
1319 	}
1320 	if( !fail ) {
1321 		Com_Printf( "succeeded\n" );
1322 	} else {
1323 		Com_Printf( "failed\n" );
1324 	}
1325 
1326 	/* test if returned length is valid, with overflow */
1327 	Com_Printf( "test 3\n" );
1328 	fail = qfalse;
1329 	memset( buffer, '@', sizeof( buffer ) );
1330 	ret = Com_sprintf( buffer, 5, "%s", "abcdefgh" );
1331 	if( ret != 4 ) {
1332 		Com_Printf( "returned %d instead of %d\n", ret, 4 );
1333 		fail = qtrue;
1334 	}
1335 	if( buffer[4] != 0 ) {
1336 		Com_Printf( "buffer left unterminated\n" );
1337 		fail = qtrue;
1338 	}
1339 	if( buffer[5] != '@' ) {
1340 		Com_Printf( "buffer overflowed\n" );
1341 		fail = qtrue;
1342 	}
1343 
1344 	if( !fail ) {
1345 		Com_Printf( "succeeded\n" );
1346 	} else {
1347 		Com_Printf( "failed\n" );
1348 	}
1349 }
1350 
1351 #endif
1352 
Com_FileNameGenerator(const char * path,const char * ext,const char * partial,qboolean stripExtension,int state)1353 const char *Com_FileNameGenerator( const char *path, const char *ext,
1354         const char *partial, qboolean stripExtension, int state ) {
1355     static int length, numFiles;
1356     static char **list;
1357     static int curpos;
1358     char *s, *p;
1359 
1360 	if( state == 2 ) {
1361 		goto finish;
1362 	}
1363 
1364     if( !state ) {
1365         length = strlen( partial );
1366         list = FS_ListFiles( path, ext, 0, &numFiles );
1367         curpos = 0;
1368     }
1369 
1370     while( curpos < numFiles ) {
1371         s = list[curpos++];
1372 		if( stripExtension ) {
1373 			p = COM_FileExtension( s );
1374 			*p = 0;
1375 		}
1376         if( !strncmp( s, partial, length ) ) {
1377             return s;
1378         }
1379     }
1380 
1381 finish:
1382     if( list ) {
1383         FS_FreeFileList( list );
1384         list = NULL;
1385     }
1386     return NULL;
1387 }
1388 
Com_FileNameGeneratorByFilter(const char * path,const char * filter,const char * partial,qboolean stripExtension,int state)1389 const char *Com_FileNameGeneratorByFilter( const char *path, const char *filter,
1390         const char *partial, qboolean stripExtension, int state ) {
1391     static int length, numFiles;
1392     static char **list;
1393     static int curpos;
1394     char *s, *p;
1395 
1396 	if( state == 2 ) {
1397 		goto finish;
1398 	}
1399 
1400     if( !state ) {
1401         length = strlen( partial );
1402         list = FS_ListFiles( path, filter, FS_SEARCH_SAVEPATH |
1403                 FS_SEARCH_BYFILTER, &numFiles );
1404         curpos = 0;
1405     }
1406 
1407     while( curpos < numFiles ) {
1408         s = list[curpos++];
1409 		if( stripExtension ) {
1410 			p = COM_FileExtension( s );
1411 			*p = 0;
1412 		}
1413         if( !strncmp( s, partial, length ) ) {
1414             return s;
1415         }
1416     }
1417 
1418 finish:
1419     if( list ) {
1420         FS_FreeFileList( list );
1421         list = NULL;
1422     }
1423     return NULL;
1424 }
1425 
1426 #define MAX_LINE_COMMANDS	128
1427 
1428 static char	*com_commands[MAX_LINE_COMMANDS];
1429 static int		com_numCommands;
1430 
1431 /*
1432 ===============
1433 Com_ParseCommandLine
1434 
1435 ===============
1436 */
Com_ParseCommandLine(char * commandLine)1437 static void Com_ParseCommandLine( char *commandLine ) {
1438 	qboolean inquote = qfalse;
1439 
1440     if( !commandLine ) {
1441         return;
1442     }
1443 
1444 	com_numCommands = 0;
1445 	while( *commandLine ) {
1446 		if( *commandLine == '\"' ) {
1447 			inquote ^= 1;
1448 		} else if( *commandLine == '+' && !inquote ) {
1449 			com_commands[com_numCommands] = commandLine + 1;
1450 			com_numCommands++;
1451 
1452 			*commandLine = 0;
1453 
1454 			if( com_numCommands == MAX_LINE_COMMANDS ) {
1455 				break;
1456 			}
1457 		}
1458 
1459 		commandLine++;
1460 
1461 	}
1462 }
1463 
1464 /*
1465 ===============
1466 Com_AddEarlyCommands
1467 
1468 Adds command line parameters as script statements.
1469 Commands lead with a +, and continue until another +
1470 
1471 Set commands are added early, so they are guaranteed to be set before
1472 the client and server initialize for the first time.
1473 
1474 Other commands are added late, after all initialization is complete.
1475 ===============
1476 */
Com_AddEarlyCommands(qboolean clear)1477 static void Com_AddEarlyCommands( qboolean clear ) {
1478 	int		i;
1479 	char	*s, *name;
1480 
1481 	for( i = 0; i < com_numCommands; i++ ) {
1482 		s = com_commands[i];
1483 		if( !*s ) {
1484 			continue;
1485 		}
1486 		Cmd_TokenizeString( s, qfalse );
1487 		if( strcmp( Cmd_Argv( 0 ), "set" ) ) {
1488 			continue;
1489 		}
1490         if( Cmd_Argc() != 3 ) {
1491             Com_Printf( "Usage: +set <variable> <value>\n" );
1492         } else {
1493 			name = Cmd_Argv( 1 );
1494 			if( !strcmp( name, "port" ) ) {
1495 				Com_WPrintf( "'port' variable is deprecated. Please use 'net_port' instead.\n" );
1496 				name = "net_port";
1497 			}
1498     		Cvar_SetEx( name, Cmd_Argv( 2 ), CVAR_SET_COMMAND_LINE );
1499         }
1500 		if( clear ) {
1501 			*s = 0;
1502 		}
1503 	}
1504 }
1505 
1506 /*
1507 =================
1508 Com_AddLateCommands
1509 
1510 Adds command line parameters as script statements
1511 Commands lead with a + and continue until another +
1512 
1513 Returns qtrue if any late commands were added, which
1514 will keep the demoloop from immediately starting
1515 
1516 Assumes +set commands are already filtered out
1517 =================
1518 */
Com_AddLateCommands(void)1519 static qboolean Com_AddLateCommands( void ) {
1520 	int		i;
1521 	char	*s;
1522 	qboolean ret = qfalse;
1523 
1524 	for( i = 0; i < com_numCommands; i++ ) {
1525 		s = com_commands[i];
1526 		if( !*s ) {
1527 			continue;
1528 		}
1529 		Cbuf_AddText( s );
1530 		Cbuf_AddText( "\n" );
1531 		ret = qtrue;
1532 	}
1533 
1534 	if( ret ) {
1535 		Cbuf_Execute();
1536 	}
1537 
1538 	return ret;
1539 }
1540 
1541 /*
1542 =================
1543 Qcommon_Init
1544 =================
1545 */
Qcommon_Init(char * commandLine)1546 void Qcommon_Init( char *commandLine ) {
1547 	static const char *version = APPLICATION " " VERSION " " __DATE__ " " BUILDSTRING "-" CPUSTRING;
1548 
1549 	if( _setjmp( abortframe ) )
1550 		Sys_Error( "Error during initialization: %s", com_errorMsg );
1551 
1552 	Com_Printf( S_COLOR_CYAN "%s\n", version );
1553 
1554 	Com_ParseCommandLine( commandLine );
1555 
1556 	// prepare enough of the subsystems to handle
1557 	// cvar and command buffer management
1558 	Z_Init();
1559 	MSG_Init();
1560 	Cbuf_Init();
1561 	Cmd_Init();
1562 	Cvar_Init();
1563 	Key_Init();
1564 	Prompt_Init();
1565 	Con_Init();
1566 
1567 	Com_FillAPI( &com );
1568 
1569 	//
1570 	// init commands and vars
1571 	//
1572 	host_speeds = Cvar_Get ("host_speeds", "0", 0);
1573 	developer = Cvar_Get ("developer", "0", 0);
1574 	timescale = Cvar_Get ("timescale", "1", CVAR_CHEAT );
1575 	fixedtime = Cvar_Get ("fixedtime", "0", CVAR_CHEAT );
1576 	logfile_active = Cvar_Get( "logfile", "0", 0 );
1577 	logfile_flush = Cvar_Get( "logfile_flush", "0", 0 );
1578 	logfile_name = Cvar_Get( "logfile_name", COM_LOGFILE_NAME, 0 );
1579 #ifdef DEDICATED_ONLY
1580 	dedicated = Cvar_Get ("dedicated", "1", CVAR_ROM);
1581 #else
1582 	dedicated = Cvar_Get ("dedicated", "0", CVAR_NOSET);
1583 #endif
1584 	sv_running = Cvar_Get( "sv_running", "0", CVAR_ROM );
1585 	sv_paused = Cvar_Get( "sv_paused", "0", CVAR_ROM );
1586 	cl_running = Cvar_Get( "cl_running", "0", CVAR_ROM );
1587 	cl_paused = Cvar_Get( "cl_paused", "0", CVAR_ROM );
1588 	com_timedemo = Cvar_Get( "timedemo", "0", CVAR_CHEAT );
1589 	com_sleep = Cvar_Get( "com_sleep", "1", 0 );
1590 	com_date_format = Cvar_Get( "com_date_format", "%Y-%m-%d", 0 );
1591 	com_time_format = Cvar_Get( "com_time_format", "%H.%M.%S", 0 );
1592 	com_debug_break = Cvar_Get( "com_debug_break", "0", 0 );
1593 
1594     //
1595     // userinfo - shared by regular client and MVD client
1596     //
1597     info_password = Cvar_Get( "password", "", CVAR_USERINFO );
1598 	info_spectator = Cvar_Get( "spectator", dedicated->integer ? "1" : "0",
1599 		CVAR_USERINFO );
1600     info_name = Cvar_Get( "name", "unnamed", CVAR_USERINFO | CVAR_ARCHIVE );
1601     info_skin = Cvar_Get( "skin", "male/grunt", CVAR_USERINFO | CVAR_ARCHIVE );
1602 	info_rate = Cvar_Get( "rate", dedicated->integer ? "15000" : "5000",
1603 		CVAR_USERINFO | CVAR_ARCHIVE );
1604     info_msg = Cvar_Get( "msg", "1", CVAR_USERINFO | CVAR_ARCHIVE );
1605     info_hand = Cvar_Get( "hand", "0", CVAR_USERINFO | CVAR_ARCHIVE );
1606     info_fov = Cvar_Get( "fov", "90", CVAR_USERINFO | CVAR_ARCHIVE );
1607     info_gender = Cvar_Get( "gender", "male", CVAR_USERINFO | CVAR_ARCHIVE );
1608 
1609 #ifdef NDEBUG
1610 	Cvar_Get( "version", version, CVAR_SERVERINFO|CVAR_ROM );
1611 #else
1612 	Cvar_Get( "version", version, CVAR_SERVERINFO );
1613 #endif
1614 
1615 	Cmd_AddCommand ("z_stats", Z_Stats_f);
1616 
1617 #ifndef DEDICATED_ONLY
1618 	if( !dedicated->integer ) {
1619 		Cmd_AddCommand( "writeconfig", Com_WriteConfig_f );
1620 	}
1621 #endif
1622 
1623 
1624 	Cmd_AddMacro( "com_date", Com_Date_m );
1625 	Cmd_AddMacro( "com_time", Com_Time_m );
1626 
1627 	// we need to add the early commands twice, because
1628 	// a basedir or cddir needs to be set before execing
1629 	// config files, but we want other parms to override
1630 	// the settings of the config files
1631 	Com_AddEarlyCommands( qfalse );
1632 
1633 	Sys_Init();
1634 	FS_Init();
1635 
1636 	/* after FS is initialized, open logfile */
1637 	logfile_active->changedFunc = LogFileActive_OnChange;
1638 	logfile_flush->changedFunc = LogFileParam_OnChange;
1639 	logfile_name->changedFunc = LogFileParam_OnChange;
1640 	LogFileActive_OnChange( logfile_active, NULL );
1641 
1642 	Cbuf_AddText( "exec "COM_DEFAULTCFG_NAME"\n" );
1643 	Cbuf_Execute();
1644 
1645 	Cbuf_AddText( "exec "COM_CONFIG_NAME"\n" );
1646 	Cbuf_Execute();
1647 
1648 	Cbuf_AddText( "exec "COM_AUTOEXECCFG_NAME"\n" );
1649 	Cbuf_Execute();
1650 
1651 	Com_AddEarlyCommands( qtrue );
1652 
1653 #ifndef NDEBUG
1654 	Cmd_AddCommand( "error", Com_Error_f );
1655 	Cmd_AddCommand( "errordrop", Com_ErrorDrop_f );
1656 	Cmd_AddCommand( "freeze", Com_Freeze_f );
1657 	Cmd_AddCommand( "crash", Com_Crash_f );
1658 	Cmd_AddCommand( "vstest", Com_VsnprintfTest_f );
1659 	Cmd_AddCommand( "zlibtest", Com_ZLibTest_f );
1660 #endif
1661 
1662 	Cmd_AddCommand( "lasterror", Com_LastError_f );
1663 
1664 	Cmd_AddCommand( "quit", Com_Quit );
1665 
1666 	srand( Sys_Milliseconds() );
1667 
1668 	Netchan_Init();
1669 	CM_Init();
1670 	SV_Init();
1671 	CL_Init();
1672 	NET_Init();
1673 
1674 	if( dedicated->integer ) {
1675 		NET_Config( NET_SERVER );
1676 	}
1677 
1678 	// add + commands from command line
1679 	if( !Com_AddLateCommands() ) {
1680 		// if the user didn't give any commands, run default action
1681 		if( dedicated->integer ) {
1682 			Cbuf_AddText( "dedicated_start\n" );
1683 		} else {
1684 			// TODO
1685 			//Cbuf_AddText( "d1\n" );
1686 		}
1687 		Cbuf_Execute();
1688 	} else {
1689 		// the user asked for something explicit
1690 		// so drop the loading plaque
1691 		SCR_EndLoadingPlaque();
1692 	}
1693 
1694 
1695 	Com_Printf( "====== " APPLICATION " initialized ======\n\n" );
1696 	Com_Printf( S_COLOR_CYAN APPLICATION " " VERSION ", " __DATE__ "\n"
1697                 S_COLOR_RESET   "w/ zlib " ZLIB_VERSION "\n" );
1698 	Com_Printf( "http://q2pro.sf.net\n\n" );
1699 
1700 	Com_DPrintf( "Working directory: %s\n", Sys_GetCurrentDirectory() );
1701 
1702 	com_numCommands = 0;
1703 
1704 	com_eventTime = Sys_Realtime();
1705 }
1706 
1707 /*
1708 ==============
1709 Com_ProcessEvents
1710 ==============
1711 */
Com_ProcessEvents(void)1712 void Com_ProcessEvents( void ) {
1713 	int ret;
1714 
1715 	while( ( ret = NET_GetPacket( NS_SERVER, &net_from ) ) != 0 ) {
1716 		SV_PacketEvent( ret );
1717 	}
1718 
1719 #ifdef DEDICATED_ONLY
1720 	while( ( ret = NET_GetPacket( NS_CLIENT, &net_from ) ) != 0 ) {
1721 		MVD_PacketEvent( ret );
1722 	}
1723 #else
1724 	while( ( ret = NET_GetPacket( NS_CLIENT, &net_from ) ) != 0 ) {
1725 		if( mvd_running->integer ) {
1726 			MVD_PacketEvent( ret );
1727 		} else {
1728 			CL_PacketEvent( ret );
1729 		}
1730 	}
1731 	CL_PumpEvents();
1732 	CL_InputFrame();
1733 #endif
1734 }
1735 
1736 #ifndef DEDICATED_ONLY
1737 /*
1738 ==============
1739 Com_ProcessLoopback
1740 ==============
1741 */
Com_ProcessLoopback(void)1742 static void Com_ProcessLoopback( void ) {
1743 	int i;
1744 
1745 	memset( &net_from, 0, sizeof( net_from ) );
1746 	net_from.type = NA_LOOPBACK;
1747 
1748 	// Process loopback packets
1749 	for( i = 0; i < 2; i++ ) {
1750 		while( NET_GetLoopPacket( NS_SERVER ) ) {
1751 			if( sv_running->integer ) {
1752 				SV_PacketEvent( 1 );
1753 			}
1754 		}
1755 
1756 		while( NET_GetLoopPacket( NS_CLIENT ) ) {
1757 			if( cl_running->integer ) {
1758 				CL_PacketEvent( 1 );
1759 			}
1760 		}
1761 	}
1762 }
1763 #endif
1764 
1765 /*
1766 =================
1767 Qcommon_Frame
1768 =================
1769 */
Qcommon_Frame(void)1770 void Qcommon_Frame( void ) {
1771 	int		time_before, time_event, time_between, time_after;
1772 	uint32	realTime;
1773     char	*s;
1774 	int		msec;
1775 
1776 	if( _setjmp( abortframe ) ) {
1777 		return;			// an ERR_DROP was thrown
1778 	}
1779 
1780 	time_before = time_event = time_between = time_after = 0;
1781 
1782 	if( host_speeds->integer )
1783 		time_before = Sys_Milliseconds();
1784 
1785 	do {
1786 		Com_ProcessEvents();
1787 		realTime = Sys_Realtime();
1788         if( com_eventTime > realTime ) {
1789             com_eventTime = realTime;
1790         }
1791 		msec = realTime - com_eventTime;
1792 	} while( msec < 1 );
1793 	com_eventTime = realTime;
1794 
1795 	if( fixedtime->integer ) {
1796 		Cvar_ClampInteger( fixedtime, 1, 1000 );
1797 		msec = fixedtime->integer;
1798 	} else if( timescale->value > 0 ) {
1799 		msec *= timescale->value;
1800 		if( msec < 1 )
1801 			msec = 1;
1802 	}
1803 
1804     if( ( s = Sys_ConsoleInput() ) != NULL ) {
1805         do {
1806             Cbuf_AddText( s );
1807             Cbuf_AddText( "\n" );
1808         } while( ( s = Sys_ConsoleInput() ) != NULL );
1809 
1810         Cbuf_Execute();
1811     }
1812 
1813 	if( host_speeds->integer )
1814 		time_event = Sys_Milliseconds();
1815 
1816 	SV_Frame( msec );
1817 
1818 	if( host_speeds->integer )
1819 		time_between = Sys_Milliseconds();
1820 
1821 #ifndef DEDICATED_ONLY
1822 	Com_ProcessLoopback();
1823 #endif
1824 
1825 	CL_Frame( msec );
1826 
1827 	if( host_speeds->integer )
1828 		time_after = Sys_Milliseconds();
1829 
1830 	if( host_speeds->integer ) {
1831 		int			all, ev, sv, gm, cl, rf;
1832 
1833 		all = time_after - time_before;
1834 		ev = time_event - time_before;
1835 		sv = time_between - time_event;
1836 		cl = time_after - time_between;
1837 		gm = time_after_game - time_before_game;
1838 		rf = time_after_ref - time_before_ref;
1839 		sv -= gm;
1840 		cl -= rf;
1841 
1842 		Com_Printf( "all:%3i ev:%3i sv:%3i gm:%3i cl:%3i rf:%3i\n",
1843 			all, ev, sv, gm, cl, rf );
1844 	}
1845 
1846 	cvar_infoModified = 0;
1847 
1848 	com_framenum++;
1849 }
1850 
1851 /*
1852 =================
1853 Qcommon_Shutdown
1854 =================
1855 */
Qcommon_Shutdown(qboolean fatalError)1856 void Qcommon_Shutdown( qboolean fatalError ) {
1857 #ifndef DEDICATED_ONLY
1858 	if( !fatalError && dedicated && !dedicated->integer ) {
1859 		Com_WriteConfiguration( COM_CONFIG_NAME );
1860 	}
1861 #endif
1862 	LogFile_Close();
1863 	FS_Shutdown( qtrue );
1864 }
1865 
1866