2 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 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.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 // Nurail: Swiped from quake3/common
25 #include "globaldefs.h"
29 #include <sys/types.h>
37 #if GDEF_OS_LINUX || GDEF_OS_MACOS
45 #define BASEDIRNAME "quake" // assumed to have a 2 or 3 following
46 #define HERETIC2_BASEDIRNAME "h"
47 #define PATHSEPERATOR '/'
49 // qboolean verbose = false;
52 void *safe_malloc( size_t size ){
57 Error( "safe_malloc failed on allocation of %i bytes", size );
64 void *safe_malloc_info( size_t size, char* info ){
69 Error( "%s: safe_malloc failed on allocation of %i bytes", info, size );
77 // set these before calling CheckParm
85 char archivedir[1024];
92 Mimic unix command line expansion
95 #define MAX_EX_ARGC 1024
97 char *ex_argv[MAX_EX_ARGC];
100 void ExpandWildcards( int *argc, char ***argv ){
101 struct _finddata_t fileinfo;
109 for ( i = 0 ; i < *argc ; i++ )
113 || ( !strstr( path, "*" ) && !strstr( path, "?" ) ) ) {
114 ex_argv[ex_argc++] = path;
118 handle = _findfirst( path, &fileinfo );
119 if ( handle == -1 ) {
123 ExtractFilePath( path, filebase );
127 sprintf( filename, "%s%s", filebase, fileinfo.name );
128 ex_argv[ex_argc++] = copystring( filename );
129 } while ( _findnext( handle, &fileinfo ) != -1 );
131 _findclose( handle );
138 void ExpandWildcards( int *argc, char ***argv ){
144 qdir will hold the path up to the quake directory, including the slash
149 gamedir will hold qdir + the game directory (id1, id2, etc)
157 void SetQdirFromPath( const char *path ){
162 char basedirname[256];
164 if ( !( path[0] == '/' || path[0] == '\\' || path[1] == ':' ) ) { // path is partial
166 strcat( temp, path );
170 // search for "quake2" in path
172 if ( !strcmp( game, "heretic2" ) ) {
173 strncpy( basedirname, HERETIC2_BASEDIRNAME, 256 );
176 strncpy( basedirname, BASEDIRNAME, 256 );
179 len = strlen( basedirname );
180 for ( c = path + strlen( path ) - 1 ; c != path ; c-- )
184 if ( !Q_strncasecmp( c, basedirname, len ) ) {
186 //strncpy (qdir, path, c+len+2-path);
187 // the +2 assumes a 2 or 3 following quake which is not the
188 // case with a retail install
189 // so we need to add up how much to the next separator
192 while ( *sep && *sep != '/' && *sep != '\\' )
197 strncpy( qdir, path, c + len + count - path );
198 Sys_FPrintf( SYS_VRB, "qdir: %s\n", qdir );
199 for ( i = 0; i < strlen( qdir ); i++ )
201 if ( qdir[i] == '\\' ) {
209 if ( *c == '/' || *c == '\\' ) {
210 strncpy( gamedir, path, c + 1 - path );
212 for ( i = 0; i < strlen( gamedir ); i++ )
214 if ( gamedir[i] == '\\' ) {
219 Sys_FPrintf( SYS_VRB, "gamedir: %s\n", gamedir );
221 if ( !writedir[0] ) {
222 strcpy( writedir, gamedir );
224 else if ( writedir[strlen( writedir ) - 1] != '/' ) {
225 writedir[strlen( writedir )] = '/';
226 writedir[strlen( writedir ) + 1] = 0;
233 Error( "No gamedir in %s", path );
237 Error( "SetQdirFromPath: no '%s' in %s", basedirname, path );
240 char *ExpandArg( const char *path ){
241 static char full[1024];
243 if ( path[0] != '/' && path[0] != '\\' && path[1] != ':' ) {
245 strcat( full, path );
248 strcpy( full, path );
253 char *ExpandPath( const char *path ){
254 static char full[1024];
256 Error( "ExpandPath called without qdir set" );
258 if ( path[0] == '/' || path[0] == '\\' || path[1] == ':' ) {
259 strcpy( full, path );
262 sprintf( full, "%s%s", qdir, path );
266 char *ExpandGamePath( const char *path ){
267 static char full[1024];
269 Error( "ExpandGamePath called without qdir set" );
271 if ( path[0] == '/' || path[0] == '\\' || path[1] == ':' ) {
272 strcpy( full, path );
275 sprintf( full, "%s%s", gamedir, path );
279 char *ExpandPathAndArchive( const char *path ){
281 char archivename[1024];
283 expanded = ExpandPath( path );
286 sprintf( archivename, "%s/%s", archivedir, path );
287 QCopyFile( expanded, archivename );
293 char *copystring( const char *s ){
295 b = safe_malloc( strlen( s ) + 1 );
307 double I_FloatTime( void ){
314 // more precise, less portable
319 gettimeofday( &tp, &tzp );
323 return tp.tv_usec / 1000000.0;
326 return ( tp.tv_sec - secbase ) + tp.tv_usec / 1000000.0;
330 void Q_getwd( char *out ){
337 // Gef: Changed from getwd() to getcwd() to avoid potential buffer overflow
341 while ( out[i] != 0 )
343 if ( out[i] == '\\' ) {
351 void Q_mkdir( const char *path ){
353 if ( _mkdir( path ) != -1 ) {
357 if ( mkdir( path, 0777 ) != -1 ) {
361 if ( errno != EEXIST ) {
362 Error( "mkdir %s: %s",path, strerror( errno ) );
370 returns -1 if not present
373 int FileTime( const char *path ){
376 if ( stat( path,&buf ) == -1 ) {
389 Parse a token out of a string
392 char *COM_Parse( char *data ){
405 while ( ( c = *data ) <= ' ' )
409 return NULL; // end of file;
415 if ( c == '/' && data[1] == '/' ) {
416 while ( *data && *data != '\n' )
422 // handle quoted strings specially
437 // parse single characters
438 if ( c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ':' ) {
445 // parse a regular word
452 if ( c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ':' ) {
461 int Q_strncasecmp( const char *s1, const char *s2, int n ){
470 return 0; // strings are equal until end point
474 if ( c1 >= 'a' && c1 <= 'z' ) {
477 if ( c2 >= 'a' && c2 <= 'z' ) {
481 return -1; // strings not equal
486 return 0; // strings are equal
489 int Q_stricmp( const char *s1, const char *s2 ){
490 return Q_strncasecmp( s1, s2, 99999 );
493 int Q_strcasecmp( const char *s1, const char *s2 ){
494 return Q_strncasecmp( s1, s2, 99999 );
498 // NOTE TTimo when switching to Multithread DLL (Release/Debug) in the config
499 // started getting warnings about that function, prolly a duplicate with the runtime function
500 // maybe we still need to have it in linux builds
502 char *strupr (char *start)
515 char *strlower( char *start ){
520 *in = tolower( *in );
528 =============================================================================
532 =============================================================================
540 Checks for the given parameter in the program's command line arguments
541 Returns the argument number (1 to argc-1) or 0 if not present
544 int CheckParm( const char *check ){
547 for ( i = 1; i < myargc; i++ )
549 if ( !Q_stricmp( check, myargv[i] ) ) {
564 int Q_filelength( FILE *f ){
569 fseek( f, 0, SEEK_END );
571 fseek( f, pos, SEEK_SET );
577 FILE *SafeOpenWrite( const char *filename ){
580 f = fopen( filename, "wb" );
583 Error( "Error opening %s: %s",filename,strerror( errno ) );
589 FILE *SafeOpenRead( const char *filename ){
592 f = fopen( filename, "rb" );
595 Error( "Error opening %s: %s",filename,strerror( errno ) );
602 void SafeRead( FILE *f, void *buffer, int count ){
603 if ( fread( buffer, 1, count, f ) != (size_t)count ) {
604 Error( "File read failure" );
609 void SafeWrite( FILE *f, const void *buffer, int count ){
610 if ( fwrite( buffer, 1, count, f ) != (size_t)count ) {
611 Error( "File write failure" );
621 qboolean FileExists( const char *filename ){
624 f = fopen( filename, "r" );
637 int LoadFile( const char *filename, void **bufferptr ){
642 f = SafeOpenRead( filename );
643 length = Q_filelength( f );
644 buffer = safe_malloc( length + 1 );
645 ( (char *)buffer )[length] = 0;
646 SafeRead( f, buffer, length );
658 rounds up memory allocation to 4K boundry
662 int LoadFileBlock( const char *filename, void **bufferptr ){
664 int length, nBlock, nAllocSize;
667 f = SafeOpenRead( filename );
668 length = Q_filelength( f );
670 nBlock = nAllocSize % MEM_BLOCKSIZE;
672 nAllocSize += MEM_BLOCKSIZE - nBlock;
674 buffer = safe_malloc( nAllocSize + 1 );
675 memset( buffer, 0, nAllocSize + 1 );
676 SafeRead( f, buffer, length );
691 int TryLoadFile( const char *filename, void **bufferptr ){
698 f = fopen( filename, "rb" );
702 length = Q_filelength( f );
703 buffer = safe_malloc( length + 1 );
704 ( (char *)buffer )[length] = 0;
705 SafeRead( f, buffer, length );
718 void SaveFile( const char *filename, const void *buffer, int count ){
721 f = SafeOpenWrite( filename );
722 SafeWrite( f, buffer, count );
728 void DefaultExtension( char *path, const char *extension ){
731 // if path doesnt have a .EXT, append extension
732 // (extension should include the .)
734 src = path + strlen( path ) - 1;
736 while ( *src != '/' && *src != '\\' && src != path )
739 return; // it has an extension
744 strcat( path, extension );
748 void DefaultPath( char *path, const char *basepath ){
751 if ( path[ 0 ] == '/' || path[ 0 ] == '\\' ) {
752 return; // absolute path location
755 strcpy( path,basepath );
760 void StripFilename( char *path ){
763 length = strlen( path ) - 1;
764 while ( length > 0 && path[length] != '/' && path[ length ] != '\\' )
769 void StripExtension( char *path ){
772 length = strlen( path ) - 1;
773 while ( length > 0 && path[length] != '.' )
776 if ( path[length] == '/' || path[ length ] == '\\' ) {
777 return; // no extension
791 // FIXME: should include the slash, otherwise
792 // backing to an empty path will be wrong when appending a slash
793 void ExtractFilePath( const char *path, char *dest ){
796 src = path + strlen( path ) - 1;
799 // back up until a \ or the start
801 while ( src != path && *( src - 1 ) != '\\' && *( src - 1 ) != '/' )
804 memcpy( dest, path, src - path );
805 dest[src - path] = 0;
808 void ExtractFileBase( const char *path, char *dest ){
811 src = path + strlen( path ) - 1;
814 // back up until a \ or the start
816 while ( src != path && *( src - 1 ) != '/' && *( src - 1 ) != '\\' )
819 while ( *src && *src != '.' )
826 void ExtractFileExtension( const char *path, char *dest ){
829 src = path + strlen( path ) - 1;
832 // back up until a . or the start
834 while ( src != path && *( src - 1 ) != '.' )
837 *dest = 0; // no extension
850 int ParseHex( const char *hex ){
860 if ( *str >= '0' && *str <= '9' ) {
863 else if ( *str >= 'a' && *str <= 'f' ) {
864 num += 10 + *str - 'a';
866 else if ( *str >= 'A' && *str <= 'F' ) {
867 num += 10 + *str - 'A';
870 Error( "Bad hex number: %s",hex );
879 int ParseNum( const char *str ){
880 if ( str[0] == '$' ) {
881 return ParseHex( str + 1 );
883 if ( str[0] == '0' && str[1] == 'x' ) {
884 return ParseHex( str + 2 );
889 // all output ends up through here
890 void FPrintf (int flag, char *buf)
896 void Sys_FPrintf (int flag, const char *format, ...)
898 char out_buffer[4096];
901 if ((flag == SYS_VRB) && (verbose == false))
904 va_start (argptr, format);
905 vsprintf (out_buffer, format, argptr);
908 FPrintf (flag, out_buffer);
911 void Sys_Printf (const char *format, ...)
913 char out_buffer[4096];
916 va_start (argptr, format);
917 vsprintf (out_buffer, format, argptr);
920 FPrintf (SYS_STD, out_buffer);
927 //For abnormal program terminations
930 void Error( const char *error, ...)
932 char out_buffer[4096];
936 va_start (argptr,error);
937 vsprintf (tmp, error, argptr);
940 sprintf( out_buffer, "************ ERROR ************\n%s\n", tmp );
942 FPrintf( SYS_ERR, out_buffer );
950 ============================================================================
954 ============================================================================
957 #if GDEF_ARCH_ENDIAN_BIG
959 short LittleShort( short l ){
963 b2 = ( l >> 8 ) & 255;
965 return ( b1 << 8 ) + b2;
968 short BigShort( short l ){
973 int LittleLong( int l ){
977 b2 = ( l >> 8 ) & 255;
978 b3 = ( l >> 16 ) & 255;
979 b4 = ( l >> 24 ) & 255;
981 return ( (int)b1 << 24 ) + ( (int)b2 << 16 ) + ( (int)b3 << 8 ) + b4;
984 int BigLong( int l ){
989 float LittleFloat( float l ){
990 union {byte b[4]; float f; } in, out;
1001 float BigFloat( float l ){
1009 short BigShort( short l ){
1013 b2 = ( l >> 8 ) & 255;
1015 return ( b1 << 8 ) + b2;
1018 short LittleShort( short l ){
1023 int BigLong( int l ){
1027 b2 = ( l >> 8 ) & 255;
1028 b3 = ( l >> 16 ) & 255;
1029 b4 = ( l >> 24 ) & 255;
1031 return ( (int)b1 << 24 ) + ( (int)b2 << 16 ) + ( (int)b3 << 8 ) + b4;
1034 int LittleLong( int l ){
1038 float BigFloat( float l ){
1039 union {byte b[4]; float f; } in, out;
1050 float LittleFloat( float l ){
1058 //=======================================================
1061 // FIXME: byte swap?
1063 // this is a 16 bit, non-reflected CRC using the polynomial 0x1021
1064 // and the initial and final xor values shown below... in other words, the
1065 // CCITT standard CRC used by XMODEM
1067 #define CRC_INIT_VALUE 0xffff
1068 #define CRC_XOR_VALUE 0x0000
1070 static unsigned short crctable[256] =
1072 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
1073 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
1074 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
1075 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
1076 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
1077 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
1078 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
1079 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
1080 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
1081 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
1082 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
1083 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
1084 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
1085 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
1086 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
1087 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
1088 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
1089 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
1090 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
1091 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
1092 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
1093 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
1094 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
1095 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
1096 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
1097 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
1098 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
1099 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
1100 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
1101 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
1102 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
1103 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
1106 void CRC_Init( unsigned short *crcvalue ){
1107 *crcvalue = CRC_INIT_VALUE;
1110 void CRC_ProcessByte( unsigned short *crcvalue, byte data ){
1111 *crcvalue = ( *crcvalue << 8 ) ^ crctable[( *crcvalue >> 8 ) ^ data];
1114 unsigned short CRC_Value( unsigned short crcvalue ){
1115 return crcvalue ^ CRC_XOR_VALUE;
1117 //=============================================================================
1124 void CreatePath( const char *path ){
1132 if ( path[1] == ':' ) {
1133 olddrive = _getdrive();
1134 _chdrive( toupper( path[0] ) - 'A' + 1 );
1138 if ( path[1] == ':' ) {
1142 for ( ofs = path + 1 ; *ofs ; ofs++ )
1145 if ( c == '/' || c == '\\' ) { // create the directory
1146 memcpy( dir, path, ofs - path );
1147 dir[ ofs - path ] = 0;
1153 if ( olddrive != -1 ) {
1154 _chdrive( olddrive );
1164 Used to archive source files
1167 void QCopyFile( const char *from, const char *to ){
1171 length = LoadFile( from, &buffer );
1173 SaveFile( to, buffer, length );
1177 void Sys_Sleep( int n ){
1181 #if GDEF_OS_LINUX || GDEF_OS_MACOS