Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

cmdlib.c (20686B)


      1 /*
      2 ===========================================================================
      3 Copyright (C) 1999-2005 Id Software, Inc.
      4 
      5 This file is part of Quake III Arena source code.
      6 
      7 Quake III Arena source code is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 2 of the License,
     10 or (at your option) any later version.
     11 
     12 Quake III Arena source code is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 // cmdlib.c
     23 
     24 #include "cmdlib.h"
     25 #include <sys/types.h>
     26 #include <sys/stat.h>
     27 
     28 #ifdef WIN32
     29 #include <direct.h>
     30 #include <windows.h>
     31 #endif
     32 
     33 #ifdef NeXT
     34 #include <libc.h>
     35 #endif
     36 
     37 #define	BASEDIRNAME	"quake"		// assumed to have a 2 or 3 following
     38 #define PATHSEPERATOR   '/'
     39 
     40 // set these before calling CheckParm
     41 int myargc;
     42 char **myargv;
     43 
     44 char		com_token[1024];
     45 qboolean	com_eof;
     46 
     47 qboolean		archive;
     48 char			archivedir[1024];
     49 
     50 
     51 /*
     52 ===================
     53 ExpandWildcards
     54 
     55 Mimic unix command line expansion
     56 ===================
     57 */
     58 #define	MAX_EX_ARGC	1024
     59 int		ex_argc;
     60 char	*ex_argv[MAX_EX_ARGC];
     61 #ifdef _WIN32
     62 #include "io.h"
     63 void ExpandWildcards( int *argc, char ***argv )
     64 {
     65 	struct _finddata_t fileinfo;
     66 	int		handle;
     67 	int		i;
     68 	char	filename[1024];
     69 	char	filebase[1024];
     70 	char	*path;
     71 
     72 	ex_argc = 0;
     73 	for (i=0 ; i<*argc ; i++)
     74 	{
     75 		path = (*argv)[i];
     76 		if ( path[0] == '-'
     77 			|| ( !strstr(path, "*") && !strstr(path, "?") ) )
     78 		{
     79 			ex_argv[ex_argc++] = path;
     80 			continue;
     81 		}
     82 
     83 		handle = _findfirst (path, &fileinfo);
     84 		if (handle == -1)
     85 			return;
     86 
     87 		ExtractFilePath (path, filebase);
     88 
     89 		do
     90 		{
     91 			sprintf (filename, "%s%s", filebase, fileinfo.name);
     92 			ex_argv[ex_argc++] = copystring (filename);
     93 		} while (_findnext( handle, &fileinfo ) != -1);
     94 
     95 		_findclose (handle);
     96 	}
     97 
     98 	*argc = ex_argc;
     99 	*argv = ex_argv;
    100 }
    101 #else
    102 void ExpandWildcards (int *argc, char ***argv)
    103 {
    104 }
    105 #endif
    106 
    107 #ifdef WIN_ERROR
    108 #include <windows.h>
    109 /*
    110 =================
    111 Error
    112 
    113 For abnormal program terminations in windowed apps
    114 =================
    115 */
    116 void Error( const char *error, ... )
    117 {
    118 	va_list argptr;
    119 	char	text[1024];
    120 	char	text2[1024];
    121 	int		err;
    122 
    123 	err = GetLastError ();
    124 
    125 	va_start (argptr,error);
    126 	vsprintf (text, error,argptr);
    127 	va_end (argptr);
    128 
    129 	sprintf (text2, "%s\nGetLastError() = %i", text, err);
    130     MessageBox(NULL, text2, "Error", 0 /* MB_OK */ );
    131 
    132 	exit (1);
    133 }
    134 
    135 #else
    136 /*
    137 =================
    138 Error
    139 
    140 For abnormal program terminations in console apps
    141 =================
    142 */
    143 void Error( const char *error, ...)
    144 {
    145 	va_list argptr;
    146 
    147 	_printf ("\n************ ERROR ************\n");
    148 
    149 	va_start (argptr,error);
    150 	vprintf (error,argptr);
    151 	va_end (argptr);
    152 	_printf ("\r\n");
    153 
    154 	exit (1);
    155 }
    156 #endif
    157 
    158 // only printf if in verbose mode
    159 qboolean verbose = qfalse;
    160 void qprintf( const char *format, ... ) {
    161 	va_list argptr;
    162 
    163 	if (!verbose)
    164 		return;
    165 
    166 	va_start (argptr,format);
    167 	vprintf (format,argptr);
    168 	va_end (argptr);
    169 
    170 }
    171 
    172 #ifdef WIN32
    173 HWND hwndOut = NULL;
    174 qboolean lookedForServer = qfalse;
    175 UINT wm_BroadcastCommand = -1;
    176 #endif
    177 
    178 void _printf( const char *format, ... ) {
    179 	va_list argptr;
    180   char text[4096];
    181   ATOM a;
    182 
    183 	va_start (argptr,format);
    184 	vsprintf (text, format, argptr);
    185 	va_end (argptr);
    186 
    187   printf(text);
    188 
    189 #ifdef WIN32
    190   if (!lookedForServer) {
    191     lookedForServer = qtrue;
    192     hwndOut = FindWindow(NULL, "Q3Map Process Server");
    193     if (hwndOut) {
    194       wm_BroadcastCommand = RegisterWindowMessage( "Q3MPS_BroadcastCommand" );
    195     }
    196   }
    197   if (hwndOut) {
    198     a = GlobalAddAtom(text);
    199     PostMessage(hwndOut, wm_BroadcastCommand, 0, (LPARAM)a);
    200   }
    201 #endif
    202 }
    203 
    204 
    205 /*
    206 
    207 qdir will hold the path up to the quake directory, including the slash
    208 
    209   f:\quake\
    210   /raid/quake/
    211 
    212 gamedir will hold qdir + the game directory (id1, id2, etc)
    213 
    214   */
    215 
    216 char		qdir[1024];
    217 char		gamedir[1024];
    218 char		writedir[1024];
    219 
    220 void SetQdirFromPath( const char *path )
    221 {
    222 	char	temp[1024];
    223 	const char	*c;
    224   const char *sep;
    225 	int		len, count;
    226 
    227 	if (!(path[0] == '/' || path[0] == '\\' || path[1] == ':'))
    228 	{	// path is partial
    229 		Q_getwd (temp);
    230 		strcat (temp, path);
    231 		path = temp;
    232 	}
    233 
    234 	// search for "quake2" in path
    235 
    236 	len = strlen(BASEDIRNAME);
    237 	for (c=path+strlen(path)-1 ; c != path ; c--)
    238 	{
    239 		int i;
    240 
    241 		if (!Q_strncasecmp (c, BASEDIRNAME, len))
    242 		{
    243       //
    244 			//strncpy (qdir, path, c+len+2-path);
    245       // the +2 assumes a 2 or 3 following quake which is not the
    246       // case with a retail install
    247       // so we need to add up how much to the next separator
    248       sep = c + len;
    249       count = 1;
    250       while (*sep && *sep != '/' && *sep != '\\')
    251       {
    252         sep++;
    253         count++;
    254       }
    255 			strncpy (qdir, path, c+len+count-path);
    256 			qprintf ("qdir: %s\n", qdir);
    257 			for ( i = 0; i < strlen( qdir ); i++ )
    258 			{
    259 				if ( qdir[i] == '\\' ) 
    260 					qdir[i] = '/';
    261 			}
    262 
    263 			c += len+count;
    264 			while (*c)
    265 			{
    266 				if (*c == '/' || *c == '\\')
    267 				{
    268 					strncpy (gamedir, path, c+1-path);
    269 
    270 					for ( i = 0; i < strlen( gamedir ); i++ )
    271 					{
    272 						if ( gamedir[i] == '\\' ) 
    273 							gamedir[i] = '/';
    274 					}
    275 
    276 					qprintf ("gamedir: %s\n", gamedir);
    277 
    278 					if ( !writedir[0] )
    279 						strcpy( writedir, gamedir );
    280 					else if ( writedir[strlen( writedir )-1] != '/' )
    281 					{
    282 						writedir[strlen( writedir )] = '/';
    283 						writedir[strlen( writedir )+1] = 0;
    284 					}
    285 
    286 					return;
    287 				}
    288 				c++;
    289 			}
    290 			Error ("No gamedir in %s", path);
    291 			return;
    292 		}
    293 	}
    294 	Error ("SetQdirFromPath: no '%s' in %s", BASEDIRNAME, path);
    295 }
    296 
    297 char *ExpandArg (const char *path)
    298 {
    299 	static char full[1024];
    300 
    301 	if (path[0] != '/' && path[0] != '\\' && path[1] != ':')
    302 	{
    303 		Q_getwd (full);
    304 		strcat (full, path);
    305 	}
    306 	else
    307 		strcpy (full, path);
    308 	return full;
    309 }
    310 
    311 char *ExpandPath (const char *path)
    312 {
    313 	static char full[1024];
    314 	if (!qdir)
    315 		Error ("ExpandPath called without qdir set");
    316 	if (path[0] == '/' || path[0] == '\\' || path[1] == ':') {
    317 		strcpy( full, path );
    318 		return full;
    319 	}
    320 	sprintf (full, "%s%s", qdir, path);
    321 	return full;
    322 }
    323 
    324 char *ExpandGamePath (const char *path)
    325 {
    326 	static char full[1024];
    327 	if (!qdir)
    328 		Error ("ExpandGamePath called without qdir set");
    329 	if (path[0] == '/' || path[0] == '\\' || path[1] == ':') {
    330 		strcpy( full, path );
    331 		return full;
    332 	}
    333 	sprintf (full, "%s%s", gamedir, path);
    334 	return full;
    335 }
    336 
    337 char *ExpandPathAndArchive (const char *path)
    338 {
    339 	char	*expanded;
    340 	char	archivename[1024];
    341 
    342 	expanded = ExpandPath (path);
    343 
    344 	if (archive)
    345 	{
    346 		sprintf (archivename, "%s/%s", archivedir, path);
    347 		QCopyFile (expanded, archivename);
    348 	}
    349 	return expanded;
    350 }
    351 
    352 
    353 char *copystring(const char *s)
    354 {
    355 	char	*b;
    356 	b = malloc(strlen(s)+1);
    357 	strcpy (b, s);
    358 	return b;
    359 }
    360 
    361 
    362 
    363 /*
    364 ================
    365 I_FloatTime
    366 ================
    367 */
    368 double I_FloatTime (void)
    369 {
    370 	time_t	t;
    371 	
    372 	time (&t);
    373 	
    374 	return t;
    375 #if 0
    376 // more precise, less portable
    377 	struct timeval tp;
    378 	struct timezone tzp;
    379 	static int		secbase;
    380 
    381 	gettimeofday(&tp, &tzp);
    382 	
    383 	if (!secbase)
    384 	{
    385 		secbase = tp.tv_sec;
    386 		return tp.tv_usec/1000000.0;
    387 	}
    388 	
    389 	return (tp.tv_sec - secbase) + tp.tv_usec/1000000.0;
    390 #endif
    391 }
    392 
    393 void Q_getwd (char *out)
    394 {
    395 	int i = 0;
    396 
    397 #ifdef WIN32
    398    _getcwd (out, 256);
    399    strcat (out, "\\");
    400 #else
    401    getwd (out);
    402    strcat (out, "/");
    403 #endif
    404 
    405    while ( out[i] != 0 )
    406    {
    407 	   if ( out[i] == '\\' )
    408 		   out[i] = '/';
    409 	   i++;
    410    }
    411 }
    412 
    413 
    414 void Q_mkdir (const char *path)
    415 {
    416 #ifdef WIN32
    417 	if (_mkdir (path) != -1)
    418 		return;
    419 #else
    420 	if (mkdir (path, 0777) != -1)
    421 		return;
    422 #endif
    423 	if (errno != EEXIST)
    424 		Error ("mkdir %s: %s",path, strerror(errno));
    425 }
    426 
    427 /*
    428 ============
    429 FileTime
    430 
    431 returns -1 if not present
    432 ============
    433 */
    434 int	FileTime (const char *path)
    435 {
    436 	struct	stat	buf;
    437 	
    438 	if (stat (path,&buf) == -1)
    439 		return -1;
    440 	
    441 	return buf.st_mtime;
    442 }
    443 
    444 
    445 
    446 /*
    447 ==============
    448 COM_Parse
    449 
    450 Parse a token out of a string
    451 ==============
    452 */
    453 char *COM_Parse (char *data)
    454 {
    455 	int		c;
    456 	int		len;
    457 	
    458 	len = 0;
    459 	com_token[0] = 0;
    460 	
    461 	if (!data)
    462 		return NULL;
    463 		
    464 // skip whitespace
    465 skipwhite:
    466 	while ( (c = *data) <= ' ')
    467 	{
    468 		if (c == 0)
    469 		{
    470 			com_eof = qtrue;
    471 			return NULL;			// end of file;
    472 		}
    473 		data++;
    474 	}
    475 	
    476 // skip // comments
    477 	if (c=='/' && data[1] == '/')
    478 	{
    479 		while (*data && *data != '\n')
    480 			data++;
    481 		goto skipwhite;
    482 	}
    483 	
    484 
    485 // handle quoted strings specially
    486 	if (c == '\"')
    487 	{
    488 		data++;
    489 		do
    490 		{
    491 			c = *data++;
    492 			if (c=='\"')
    493 			{
    494 				com_token[len] = 0;
    495 				return data;
    496 			}
    497 			com_token[len] = c;
    498 			len++;
    499 		} while (1);
    500 	}
    501 
    502 // parse single characters
    503 	if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
    504 	{
    505 		com_token[len] = c;
    506 		len++;
    507 		com_token[len] = 0;
    508 		return data+1;
    509 	}
    510 
    511 // parse a regular word
    512 	do
    513 	{
    514 		com_token[len] = c;
    515 		data++;
    516 		len++;
    517 		c = *data;
    518 	if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
    519 			break;
    520 	} while (c>32);
    521 	
    522 	com_token[len] = 0;
    523 	return data;
    524 }
    525 
    526 
    527 int Q_strncasecmp (const char *s1, const char *s2, int n)
    528 {
    529 	int		c1, c2;
    530 	
    531 	do
    532 	{
    533 		c1 = *s1++;
    534 		c2 = *s2++;
    535 
    536 		if (!n--)
    537 			return 0;		// strings are equal until end point
    538 		
    539 		if (c1 != c2)
    540 		{
    541 			if (c1 >= 'a' && c1 <= 'z')
    542 				c1 -= ('a' - 'A');
    543 			if (c2 >= 'a' && c2 <= 'z')
    544 				c2 -= ('a' - 'A');
    545 			if (c1 != c2)
    546 				return -1;		// strings not equal
    547 		}
    548 	} while (c1);
    549 	
    550 	return 0;		// strings are equal
    551 }
    552 
    553 int Q_stricmp (const char *s1, const char *s2)
    554 {
    555 	return Q_strncasecmp (s1, s2, 99999);
    556 }
    557 
    558 
    559 char *strupr (char *start)
    560 {
    561 	char	*in;
    562 	in = start;
    563 	while (*in)
    564 	{
    565 		*in = toupper(*in);
    566 		in++;
    567 	}
    568 	return start;
    569 }
    570 
    571 char *strlower (char *start)
    572 {
    573 	char	*in;
    574 	in = start;
    575 	while (*in)
    576 	{
    577 		*in = tolower(*in); 
    578 		in++;
    579 	}
    580 	return start;
    581 }
    582 
    583 
    584 /*
    585 =============================================================================
    586 
    587 						MISC FUNCTIONS
    588 
    589 =============================================================================
    590 */
    591 
    592 
    593 /*
    594 =================
    595 CheckParm
    596 
    597 Checks for the given parameter in the program's command line arguments
    598 Returns the argument number (1 to argc-1) or 0 if not present
    599 =================
    600 */
    601 int CheckParm (const char *check)
    602 {
    603 	int             i;
    604 
    605 	for (i = 1;i<myargc;i++)
    606 	{
    607 		if ( !Q_stricmp(check, myargv[i]) )
    608 			return i;
    609 	}
    610 
    611 	return 0;
    612 }
    613 
    614 
    615 
    616 /*
    617 ================
    618 Q_filelength
    619 ================
    620 */
    621 int Q_filelength (FILE *f)
    622 {
    623 	int		pos;
    624 	int		end;
    625 
    626 	pos = ftell (f);
    627 	fseek (f, 0, SEEK_END);
    628 	end = ftell (f);
    629 	fseek (f, pos, SEEK_SET);
    630 
    631 	return end;
    632 }
    633 
    634 
    635 FILE *SafeOpenWrite (const char *filename)
    636 {
    637 	FILE	*f;
    638 
    639 	f = fopen(filename, "wb");
    640 
    641 	if (!f)
    642 		Error ("Error opening %s: %s",filename,strerror(errno));
    643 
    644 	return f;
    645 }
    646 
    647 FILE *SafeOpenRead (const char *filename)
    648 {
    649 	FILE	*f;
    650 
    651 	f = fopen(filename, "rb");
    652 
    653 	if (!f)
    654 		Error ("Error opening %s: %s",filename,strerror(errno));
    655 
    656 	return f;
    657 }
    658 
    659 
    660 void SafeRead (FILE *f, void *buffer, int count)
    661 {
    662 	if ( fread (buffer, 1, count, f) != (size_t)count)
    663 		Error ("File read failure");
    664 }
    665 
    666 
    667 void SafeWrite (FILE *f, const void *buffer, int count)
    668 {
    669 	if (fwrite (buffer, 1, count, f) != (size_t)count)
    670 		Error ("File write failure");
    671 }
    672 
    673 
    674 /*
    675 ==============
    676 FileExists
    677 ==============
    678 */
    679 qboolean	FileExists (const char *filename)
    680 {
    681 	FILE	*f;
    682 
    683 	f = fopen (filename, "r");
    684 	if (!f)
    685 		return qfalse;
    686 	fclose (f);
    687 	return qtrue;
    688 }
    689 
    690 /*
    691 ==============
    692 LoadFile
    693 ==============
    694 */
    695 int    LoadFile( const char *filename, void **bufferptr )
    696 {
    697 	FILE	*f;
    698 	int    length;
    699 	void    *buffer;
    700 
    701 	f = SafeOpenRead (filename);
    702 	length = Q_filelength (f);
    703 	buffer = malloc (length+1);
    704 	((char *)buffer)[length] = 0;
    705 	SafeRead (f, buffer, length);
    706 	fclose (f);
    707 
    708 	*bufferptr = buffer;
    709 	return length;
    710 }
    711 
    712 
    713 /*
    714 ==============
    715 LoadFileBlock
    716 -
    717 rounds up memory allocation to 4K boundry
    718 -
    719 ==============
    720 */
    721 int    LoadFileBlock( const char *filename, void **bufferptr )
    722 {
    723 	FILE	*f;
    724 	int    length, nBlock, nAllocSize;
    725 	void    *buffer;
    726 
    727 	f = SafeOpenRead (filename);
    728 	length = Q_filelength (f);
    729   nAllocSize = length;
    730   nBlock = nAllocSize % MEM_BLOCKSIZE;
    731   if ( nBlock > 0) {
    732     nAllocSize += MEM_BLOCKSIZE - nBlock;
    733   }
    734 	buffer = malloc (nAllocSize+1);
    735   memset(buffer, 0, nAllocSize+1);
    736 	SafeRead (f, buffer, length);
    737 	fclose (f);
    738 
    739 	*bufferptr = buffer;
    740 	return length;
    741 }
    742 
    743 
    744 /*
    745 ==============
    746 TryLoadFile
    747 
    748 Allows failure
    749 ==============
    750 */
    751 int    TryLoadFile (const char *filename, void **bufferptr)
    752 {
    753 	FILE	*f;
    754 	int    length;
    755 	void    *buffer;
    756 
    757 	*bufferptr = NULL;
    758 
    759 	f = fopen (filename, "rb");
    760 	if (!f)
    761 		return -1;
    762 	length = Q_filelength (f);
    763 	buffer = malloc (length+1);
    764 	((char *)buffer)[length] = 0;
    765 	SafeRead (f, buffer, length);
    766 	fclose (f);
    767 
    768 	*bufferptr = buffer;
    769 	return length;
    770 }
    771 
    772 
    773 /*
    774 ==============
    775 SaveFile
    776 ==============
    777 */
    778 void    SaveFile (const char *filename, const void *buffer, int count)
    779 {
    780 	FILE	*f;
    781 
    782 	f = SafeOpenWrite (filename);
    783 	SafeWrite (f, buffer, count);
    784 	fclose (f);
    785 }
    786 
    787 
    788 
    789 void DefaultExtension (char *path, const char *extension)
    790 {
    791 	char    *src;
    792 //
    793 // if path doesnt have a .EXT, append extension
    794 // (extension should include the .)
    795 //
    796 	src = path + strlen(path) - 1;
    797 
    798 	while (*src != '/' && *src != '\\' && src != path)
    799 	{
    800 		if (*src == '.')
    801 			return;                 // it has an extension
    802 		src--;
    803 	}
    804 
    805 	strcat (path, extension);
    806 }
    807 
    808 
    809 void DefaultPath (char *path, const char *basepath)
    810 {
    811 	char    temp[128];
    812 
    813 	if (path[0] == PATHSEPERATOR)
    814 		return;                   // absolute path location
    815 	strcpy (temp,path);
    816 	strcpy (path,basepath);
    817 	strcat (path,temp);
    818 }
    819 
    820 
    821 void    StripFilename (char *path)
    822 {
    823 	int             length;
    824 
    825 	length = strlen(path)-1;
    826 	while (length > 0 && path[length] != PATHSEPERATOR)
    827 		length--;
    828 	path[length] = 0;
    829 }
    830 
    831 void    StripExtension (char *path)
    832 {
    833 	int             length;
    834 
    835 	length = strlen(path)-1;
    836 	while (length > 0 && path[length] != '.')
    837 	{
    838 		length--;
    839 		if (path[length] == '/')
    840 			return;		// no extension
    841 	}
    842 	if (length)
    843 		path[length] = 0;
    844 }
    845 
    846 
    847 /*
    848 ====================
    849 Extract file parts
    850 ====================
    851 */
    852 // FIXME: should include the slash, otherwise
    853 // backing to an empty path will be wrong when appending a slash
    854 void ExtractFilePath (const char *path, char *dest)
    855 {
    856 	const char    *src;
    857 
    858 	src = path + strlen(path) - 1;
    859 
    860 //
    861 // back up until a \ or the start
    862 //
    863 	while (src != path && *(src-1) != '\\' && *(src-1) != '/')
    864 		src--;
    865 
    866 	memcpy (dest, path, src-path);
    867 	dest[src-path] = 0;
    868 }
    869 
    870 void ExtractFileBase (const char *path, char *dest)
    871 {
    872 	const char    *src;
    873 
    874 	src = path + strlen(path) - 1;
    875 
    876 //
    877 // back up until a \ or the start
    878 //
    879 	while (src != path && *(src-1) != PATHSEPERATOR)
    880 		src--;
    881 
    882 	while (*src && *src != '.')
    883 	{
    884 		*dest++ = *src++;
    885 	}
    886 	*dest = 0;
    887 }
    888 
    889 void ExtractFileExtension (const char *path, char *dest)
    890 {
    891 	const char    *src;
    892 
    893 	src = path + strlen(path) - 1;
    894 
    895 //
    896 // back up until a . or the start
    897 //
    898 	while (src != path && *(src-1) != '.')
    899 		src--;
    900 	if (src == path)
    901 	{
    902 		*dest = 0;	// no extension
    903 		return;
    904 	}
    905 
    906 	strcpy (dest,src);
    907 }
    908 
    909 
    910 /*
    911 ==============
    912 ParseNum / ParseHex
    913 ==============
    914 */
    915 int ParseHex (const char *hex)
    916 {
    917 	const char    *str;
    918 	int    num;
    919 
    920 	num = 0;
    921 	str = hex;
    922 
    923 	while (*str)
    924 	{
    925 		num <<= 4;
    926 		if (*str >= '0' && *str <= '9')
    927 			num += *str-'0';
    928 		else if (*str >= 'a' && *str <= 'f')
    929 			num += 10 + *str-'a';
    930 		else if (*str >= 'A' && *str <= 'F')
    931 			num += 10 + *str-'A';
    932 		else
    933 			Error ("Bad hex number: %s",hex);
    934 		str++;
    935 	}
    936 
    937 	return num;
    938 }
    939 
    940 
    941 int ParseNum (const char *str)
    942 {
    943 	if (str[0] == '$')
    944 		return ParseHex (str+1);
    945 	if (str[0] == '0' && str[1] == 'x')
    946 		return ParseHex (str+2);
    947 	return atol (str);
    948 }
    949 
    950 
    951 
    952 /*
    953 ============================================================================
    954 
    955 					BYTE ORDER FUNCTIONS
    956 
    957 ============================================================================
    958 */
    959 
    960 #ifdef _SGI_SOURCE
    961 #define	__BIG_ENDIAN__
    962 #endif
    963 
    964 #ifdef __BIG_ENDIAN__
    965 
    966 short   LittleShort (short l)
    967 {
    968 	byte    b1,b2;
    969 
    970 	b1 = l&255;
    971 	b2 = (l>>8)&255;
    972 
    973 	return (b1<<8) + b2;
    974 }
    975 
    976 short   BigShort (short l)
    977 {
    978 	return l;
    979 }
    980 
    981 
    982 int    LittleLong (int l)
    983 {
    984 	byte    b1,b2,b3,b4;
    985 
    986 	b1 = l&255;
    987 	b2 = (l>>8)&255;
    988 	b3 = (l>>16)&255;
    989 	b4 = (l>>24)&255;
    990 
    991 	return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
    992 }
    993 
    994 int    BigLong (int l)
    995 {
    996 	return l;
    997 }
    998 
    999 
   1000 float	LittleFloat (float l)
   1001 {
   1002 	union {byte b[4]; float f;} in, out;
   1003 	
   1004 	in.f = l;
   1005 	out.b[0] = in.b[3];
   1006 	out.b[1] = in.b[2];
   1007 	out.b[2] = in.b[1];
   1008 	out.b[3] = in.b[0];
   1009 	
   1010 	return out.f;
   1011 }
   1012 
   1013 float	BigFloat (float l)
   1014 {
   1015 	return l;
   1016 }
   1017 
   1018 
   1019 #else
   1020 
   1021 
   1022 short   BigShort (short l)
   1023 {
   1024 	byte    b1,b2;
   1025 
   1026 	b1 = l&255;
   1027 	b2 = (l>>8)&255;
   1028 
   1029 	return (b1<<8) + b2;
   1030 }
   1031 
   1032 short   LittleShort (short l)
   1033 {
   1034 	return l;
   1035 }
   1036 
   1037 
   1038 int    BigLong (int l)
   1039 {
   1040 	byte    b1,b2,b3,b4;
   1041 
   1042 	b1 = l&255;
   1043 	b2 = (l>>8)&255;
   1044 	b3 = (l>>16)&255;
   1045 	b4 = (l>>24)&255;
   1046 
   1047 	return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
   1048 }
   1049 
   1050 int    LittleLong (int l)
   1051 {
   1052 	return l;
   1053 }
   1054 
   1055 float	BigFloat (float l)
   1056 {
   1057 	union {byte b[4]; float f;} in, out;
   1058 	
   1059 	in.f = l;
   1060 	out.b[0] = in.b[3];
   1061 	out.b[1] = in.b[2];
   1062 	out.b[2] = in.b[1];
   1063 	out.b[3] = in.b[0];
   1064 	
   1065 	return out.f;
   1066 }
   1067 
   1068 float	LittleFloat (float l)
   1069 {
   1070 	return l;
   1071 }
   1072 
   1073 
   1074 #endif
   1075 
   1076 
   1077 //=======================================================
   1078 
   1079 
   1080 // FIXME: byte swap?
   1081 
   1082 // this is a 16 bit, non-reflected CRC using the polynomial 0x1021
   1083 // and the initial and final xor values shown below...  in other words, the
   1084 // CCITT standard CRC used by XMODEM
   1085 
   1086 #define CRC_INIT_VALUE	0xffff
   1087 #define CRC_XOR_VALUE	0x0000
   1088 
   1089 static unsigned short crctable[256] =
   1090 {
   1091 	0x0000,	0x1021,	0x2042,	0x3063,	0x4084,	0x50a5,	0x60c6,	0x70e7,
   1092 	0x8108,	0x9129,	0xa14a,	0xb16b,	0xc18c,	0xd1ad,	0xe1ce,	0xf1ef,
   1093 	0x1231,	0x0210,	0x3273,	0x2252,	0x52b5,	0x4294,	0x72f7,	0x62d6,
   1094 	0x9339,	0x8318,	0xb37b,	0xa35a,	0xd3bd,	0xc39c,	0xf3ff,	0xe3de,
   1095 	0x2462,	0x3443,	0x0420,	0x1401,	0x64e6,	0x74c7,	0x44a4,	0x5485,
   1096 	0xa56a,	0xb54b,	0x8528,	0x9509,	0xe5ee,	0xf5cf,	0xc5ac,	0xd58d,
   1097 	0x3653,	0x2672,	0x1611,	0x0630,	0x76d7,	0x66f6,	0x5695,	0x46b4,
   1098 	0xb75b,	0xa77a,	0x9719,	0x8738,	0xf7df,	0xe7fe,	0xd79d,	0xc7bc,
   1099 	0x48c4,	0x58e5,	0x6886,	0x78a7,	0x0840,	0x1861,	0x2802,	0x3823,
   1100 	0xc9cc,	0xd9ed,	0xe98e,	0xf9af,	0x8948,	0x9969,	0xa90a,	0xb92b,
   1101 	0x5af5,	0x4ad4,	0x7ab7,	0x6a96,	0x1a71,	0x0a50,	0x3a33,	0x2a12,
   1102 	0xdbfd,	0xcbdc,	0xfbbf,	0xeb9e,	0x9b79,	0x8b58,	0xbb3b,	0xab1a,
   1103 	0x6ca6,	0x7c87,	0x4ce4,	0x5cc5,	0x2c22,	0x3c03,	0x0c60,	0x1c41,
   1104 	0xedae,	0xfd8f,	0xcdec,	0xddcd,	0xad2a,	0xbd0b,	0x8d68,	0x9d49,
   1105 	0x7e97,	0x6eb6,	0x5ed5,	0x4ef4,	0x3e13,	0x2e32,	0x1e51,	0x0e70,
   1106 	0xff9f,	0xefbe,	0xdfdd,	0xcffc,	0xbf1b,	0xaf3a,	0x9f59,	0x8f78,
   1107 	0x9188,	0x81a9,	0xb1ca,	0xa1eb,	0xd10c,	0xc12d,	0xf14e,	0xe16f,
   1108 	0x1080,	0x00a1,	0x30c2,	0x20e3,	0x5004,	0x4025,	0x7046,	0x6067,
   1109 	0x83b9,	0x9398,	0xa3fb,	0xb3da,	0xc33d,	0xd31c,	0xe37f,	0xf35e,
   1110 	0x02b1,	0x1290,	0x22f3,	0x32d2,	0x4235,	0x5214,	0x6277,	0x7256,
   1111 	0xb5ea,	0xa5cb,	0x95a8,	0x8589,	0xf56e,	0xe54f,	0xd52c,	0xc50d,
   1112 	0x34e2,	0x24c3,	0x14a0,	0x0481,	0x7466,	0x6447,	0x5424,	0x4405,
   1113 	0xa7db,	0xb7fa,	0x8799,	0x97b8,	0xe75f,	0xf77e,	0xc71d,	0xd73c,
   1114 	0x26d3,	0x36f2,	0x0691,	0x16b0,	0x6657,	0x7676,	0x4615,	0x5634,
   1115 	0xd94c,	0xc96d,	0xf90e,	0xe92f,	0x99c8,	0x89e9,	0xb98a,	0xa9ab,
   1116 	0x5844,	0x4865,	0x7806,	0x6827,	0x18c0,	0x08e1,	0x3882,	0x28a3,
   1117 	0xcb7d,	0xdb5c,	0xeb3f,	0xfb1e,	0x8bf9,	0x9bd8,	0xabbb,	0xbb9a,
   1118 	0x4a75,	0x5a54,	0x6a37,	0x7a16,	0x0af1,	0x1ad0,	0x2ab3,	0x3a92,
   1119 	0xfd2e,	0xed0f,	0xdd6c,	0xcd4d,	0xbdaa,	0xad8b,	0x9de8,	0x8dc9,
   1120 	0x7c26,	0x6c07,	0x5c64,	0x4c45,	0x3ca2,	0x2c83,	0x1ce0,	0x0cc1,
   1121 	0xef1f,	0xff3e,	0xcf5d,	0xdf7c,	0xaf9b,	0xbfba,	0x8fd9,	0x9ff8,
   1122 	0x6e17,	0x7e36,	0x4e55,	0x5e74,	0x2e93,	0x3eb2,	0x0ed1,	0x1ef0
   1123 };
   1124 
   1125 void CRC_Init(unsigned short *crcvalue)
   1126 {
   1127 	*crcvalue = CRC_INIT_VALUE;
   1128 }
   1129 
   1130 void CRC_ProcessByte(unsigned short *crcvalue, byte data)
   1131 {
   1132 	*crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data];
   1133 }
   1134 
   1135 unsigned short CRC_Value(unsigned short crcvalue)
   1136 {
   1137 	return crcvalue ^ CRC_XOR_VALUE;
   1138 }
   1139 //=============================================================================
   1140 
   1141 /*
   1142 ============
   1143 CreatePath
   1144 ============
   1145 */
   1146 void	CreatePath (const char *path)
   1147 {
   1148 	const char	*ofs;
   1149 	char		c;
   1150 	char		dir[1024];
   1151 
   1152 #ifdef _WIN32
   1153 	int		olddrive = -1;
   1154 
   1155 	if ( path[1] == ':' )
   1156 	{
   1157 		olddrive = _getdrive();
   1158 		_chdrive( toupper( path[0] ) - 'A' + 1 );
   1159 	}
   1160 #endif
   1161 
   1162 	if (path[1] == ':')
   1163 		path += 2;
   1164 
   1165 	for (ofs = path+1 ; *ofs ; ofs++)
   1166 	{
   1167 		c = *ofs;
   1168 		if (c == '/' || c == '\\')
   1169 		{	// create the directory
   1170 			memcpy( dir, path, ofs - path );
   1171 			dir[ ofs - path ] = 0;
   1172 			Q_mkdir( dir );
   1173 		}
   1174 	}
   1175 
   1176 #ifdef _WIN32
   1177 	if ( olddrive != -1 )
   1178 	{
   1179 		_chdrive( olddrive );
   1180 	}
   1181 #endif
   1182 }
   1183 
   1184 
   1185 /*
   1186 ============
   1187 QCopyFile
   1188 
   1189   Used to archive source files
   1190 ============
   1191 */
   1192 void QCopyFile (const char *from, const char *to)
   1193 {
   1194 	void	*buffer;
   1195 	int		length;
   1196 
   1197 	length = LoadFile (from, &buffer);
   1198 	CreatePath (to);
   1199 	SaveFile (to, buffer, length);
   1200 	free (buffer);
   1201 }