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"
28 #include <sys/types.h>
36 #if GDEF_OS_LINUX || GDEF_OS_MACOS
44 #define BASEDIRNAME "h"
45 #define PATHSEPERATOR '/'
47 extern qboolean verbose;
49 qboolean g_dokeypress = false;
51 qboolean g_nomkdir = false;
55 void *safe_malloc( size_t size ){
60 Error( "safe_malloc failed on allocation of %i bytes", size );
66 void *safe_malloc_info( size_t size, char* info ){
71 Error( "%s: safe_malloc failed on allocation of %i bytes", info, size );
78 void *SafeMalloc( size_t n, char *desc ){
81 if ( ( p = malloc( n ) ) == NULL ) {
82 Error( "Failed to allocate %d bytes for '%s'.\n", n, desc );
88 #if GDEF_OS_LINUX || GDEF_OS_MACOS
89 void strlwr( char *conv_str ){
92 for ( i = 0; i < strlen( conv_str ); i++ )
93 conv_str[i] = tolower( conv_str[i] );
98 // set these before calling CheckParm
102 char com_token[1024];
106 char archivedir[1024];
113 Mimic unix command line expansion
116 #define MAX_EX_ARGC 1024
118 char *ex_argv[MAX_EX_ARGC];
121 void ExpandWildcards( int *argc, char ***argv ){
122 struct _finddata_t fileinfo;
130 for ( i = 0 ; i < *argc ; i++ )
134 || ( !strstr( path, "*" ) && !strstr( path, "?" ) ) ) {
135 ex_argv[ex_argc++] = path;
139 handle = _findfirst( path, &fileinfo );
140 if ( handle == -1 ) {
144 ExtractFilePath( path, filebase );
148 sprintf( filename, "%s%s", filebase, fileinfo.name );
149 ex_argv[ex_argc++] = copystring( filename );
150 } while ( _findnext( handle, &fileinfo ) != -1 );
152 _findclose( handle );
159 void ExpandWildcards( int *argc, char ***argv ){
165 qdir will hold the path up to the quake directory, including the slash
170 gamedir will hold qdir + the game directory (id1, id2, etc)
178 void SetQdirFromPath( const char *path ){
184 if ( !( path[0] == '/' || path[0] == '\\' || path[1] == ':' ) ) { // path is partial
186 strcat( temp, path );
190 // search for "quake2" in path
192 len = strlen( BASEDIRNAME );
193 for ( c = path + strlen( path ) - 1 ; c != path ; c-- )
197 if ( !Q_strncasecmp( c, BASEDIRNAME, len ) ) {
199 //strncpy (qdir, path, c+len+2-path);
200 // the +2 assumes a 2 or 3 following quake which is not the
201 // case with a retail install
202 // so we need to add up how much to the next separator
205 while ( *sep && *sep != '/' && *sep != '\\' )
210 strncpy( qdir, path, c + len + count - path );
211 Sys_Printf( "qdir: %s\n", qdir );
212 for ( i = 0; i < strlen( qdir ); i++ )
214 if ( qdir[i] == '\\' ) {
222 if ( *c == '/' || *c == '\\' ) {
223 strncpy( gamedir, path, c + 1 - path );
225 for ( i = 0; i < strlen( gamedir ); i++ )
227 if ( gamedir[i] == '\\' ) {
232 Sys_Printf( "gamedir: %s\n", gamedir );
234 if ( !writedir[0] ) {
235 strcpy( writedir, gamedir );
237 else if ( writedir[strlen( writedir ) - 1] != '/' ) {
238 writedir[strlen( writedir )] = '/';
239 writedir[strlen( writedir ) + 1] = 0;
246 Error( "No gamedir in %s", path );
250 Error( "SetQdirFromPath: no '%s' in %s", BASEDIRNAME, path );
253 char *ExpandArg( const char *path ){
254 static char full[1024];
256 if ( path[0] != '/' && path[0] != '\\' && path[1] != ':' ) {
258 strcat( full, path );
261 strcpy( full, path );
266 char *ExpandPath( const char *path ){
267 static char full[1024];
269 Error( "ExpandPath called without qdir set" );
271 if ( path[0] == '/' || path[0] == '\\' || path[1] == ':' ) {
272 strcpy( full, path );
275 sprintf( full, "%s%s", qdir, path );
279 char *ExpandGamePath( const char *path ){
280 static char full[1024];
282 Error( "ExpandGamePath called without qdir set" );
284 if ( path[0] == '/' || path[0] == '\\' || path[1] == ':' ) {
285 strcpy( full, path );
288 sprintf( full, "%s%s", gamedir, path );
292 char *ExpandPathAndArchive( const char *path ){
294 char archivename[1024];
296 expanded = ExpandPath( path );
299 sprintf( archivename, "%s/%s", archivedir, path );
300 QCopyFile( expanded, archivename );
306 char *copystring( const char *s ){
308 b = safe_malloc( strlen( s ) + 1 );
320 double I_FloatTime( void ){
327 // more precise, less portable
332 gettimeofday( &tp, &tzp );
336 return tp.tv_usec / 1000000.0;
339 return ( tp.tv_sec - secbase ) + tp.tv_usec / 1000000.0;
343 void Q_getwd( char *out ){
350 // Gef: Changed from getwd() to getcwd() to avoid potential buffer overflow
354 while ( out[i] != 0 )
356 if ( out[i] == '\\' ) {
364 void Q_mkdir( const char *path ){
366 if ( _mkdir( path ) != -1 ) {
370 if ( mkdir( path, 0777 ) != -1 ) {
374 if ( errno != EEXIST ) {
375 Error( "mkdir %s: %s",path, strerror( errno ) );
383 returns -1 if not present
386 int FileTime( const char *path ){
389 if ( stat( path,&buf ) == -1 ) {
402 Parse a token out of a string
405 char *COM_Parse( char *data ){
418 while ( ( c = *data ) <= ' ' )
422 return NULL; // end of file;
428 if ( c == '/' && data[1] == '/' ) {
429 while ( *data && *data != '\n' )
435 // handle quoted strings specially
450 // parse single characters
451 if ( c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ':' ) {
458 // parse a regular word
465 if ( c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ':' ) {
474 int Q_strncasecmp( const char *s1, const char *s2, int n ){
483 return 0; // strings are equal until end point
487 if ( c1 >= 'a' && c1 <= 'z' ) {
490 if ( c2 >= 'a' && c2 <= 'z' ) {
494 return -1; // strings not equal
499 return 0; // strings are equal
502 int Q_stricmp( const char *s1, const char *s2 ){
503 return Q_strncasecmp( s1, s2, 99999 );
506 int Q_strcasecmp( const char *s1, const char *s2 ){
507 return Q_strncasecmp( s1, s2, 99999 );
510 // NOTE TTimo when switching to Multithread DLL (Release/Debug) in the config
511 // started getting warnings about that function, prolly a duplicate with the runtime function
512 // maybe we still need to have it in linux builds
514 char *strupr (char *start)
527 char *strlower( char *start ){
532 *in = tolower( *in );
540 =============================================================================
544 =============================================================================
552 Checks for the given parameter in the program's command line arguments
553 Returns the argument number (1 to argc-1) or 0 if not present
556 int CheckParm( const char *check ){
559 for ( i = 1; i < myargc; i++ )
561 if ( !Q_stricmp( check, myargv[i] ) ) {
576 int Q_filelength( FILE *f ){
581 fseek( f, 0, SEEK_END );
583 fseek( f, pos, SEEK_SET );
589 FILE *SafeOpenWrite( const char *filename ){
592 f = fopen( filename, "wb" );
595 Error( "Error opening %s: %s",filename,strerror( errno ) );
601 FILE *SafeOpenRead( const char *filename ){
604 f = fopen( filename, "rb" );
607 Error( "Error opening %s: %s",filename,strerror( errno ) );
614 void SafeRead( FILE *f, void *buffer, int count ){
615 if ( fread( buffer, 1, count, f ) != (size_t)count ) {
616 Error( "File read failure" );
621 void SafeWrite( FILE *f, const void *buffer, int count ){
622 if ( fwrite( buffer, 1, count, f ) != (size_t)count ) {
623 Error( "File write failure" );
633 qboolean FileExists( const char *filename ){
636 f = fopen( filename, "r" );
649 int LoadFile( const char *filename, void **bufferptr ){
654 f = SafeOpenRead( filename );
655 length = Q_filelength( f );
656 buffer = safe_malloc( length + 1 );
657 ( (char *)buffer )[length] = 0;
658 SafeRead( f, buffer, length );
670 rounds up memory allocation to 4K boundry
674 int LoadFileBlock( const char *filename, void **bufferptr ){
676 int length, nBlock, nAllocSize;
679 f = SafeOpenRead( filename );
680 length = Q_filelength( f );
682 nBlock = nAllocSize % MEM_BLOCKSIZE;
684 nAllocSize += MEM_BLOCKSIZE - nBlock;
686 buffer = safe_malloc( nAllocSize + 1 );
687 memset( buffer, 0, nAllocSize + 1 );
688 SafeRead( f, buffer, length );
703 int TryLoadFile( const char *filename, void **bufferptr ){
710 f = fopen( filename, "rb" );
714 length = Q_filelength( f );
715 buffer = safe_malloc( length + 1 );
716 ( (char *)buffer )[length] = 0;
717 SafeRead( f, buffer, length );
730 void SaveFile( const char *filename, const void *buffer, int count ){
733 f = SafeOpenWrite( filename );
734 SafeWrite( f, buffer, count );
740 void DefaultExtension( char *path, const char *extension ){
743 // if path doesnt have a .EXT, append extension
744 // (extension should include the .)
746 src = path + strlen( path ) - 1;
748 while ( *src != '/' && *src != '\\' && src != path )
751 return; // it has an extension
756 strcat( path, extension );
760 void DefaultPath( char *path, const char *basepath ){
763 if ( path[ 0 ] == '/' || path[ 0 ] == '\\' ) {
764 return; // absolute path location
767 strcpy( path,basepath );
772 void StripFilename( char *path ){
775 length = strlen( path ) - 1;
776 while ( length > 0 && path[length] != '/' && path[ length ] != '\\' )
781 void StripExtension( char *path ){
784 length = strlen( path ) - 1;
785 while ( length > 0 && path[length] != '.' )
788 if ( path[length] == '/' || path[ length ] == '\\' ) {
789 return; // no extension
803 // FIXME: should include the slash, otherwise
804 // backing to an empty path will be wrong when appending a slash
805 void ExtractFilePath( const char *path, char *dest ){
808 src = path + strlen( path ) - 1;
811 // back up until a \ or the start
813 while ( src != path && *( src - 1 ) != '\\' && *( src - 1 ) != '/' )
816 memcpy( dest, path, src - path );
817 dest[src - path] = 0;
820 void ExtractFileBase( const char *path, char *dest ){
823 src = path + strlen( path ) - 1;
826 // back up until a \ or the start
828 while ( src != path && *( src - 1 ) != '/' && *( src - 1 ) != '\\' )
831 while ( *src && *src != '.' )
838 void ExtractFileExtension( const char *path, char *dest ){
841 src = path + strlen( path ) - 1;
844 // back up until a . or the start
846 while ( src != path && *( src - 1 ) != '.' )
849 *dest = 0; // no extension
862 int ParseHex( const char *hex ){
872 if ( *str >= '0' && *str <= '9' ) {
875 else if ( *str >= 'a' && *str <= 'f' ) {
876 num += 10 + *str - 'a';
878 else if ( *str >= 'A' && *str <= 'F' ) {
879 num += 10 + *str - 'A';
882 Error( "Bad hex number: %s",hex );
891 int ParseNum( const char *str ){
892 if ( str[0] == '$' ) {
893 return ParseHex( str + 1 );
895 if ( str[0] == '0' && str[1] == 'x' ) {
896 return ParseHex( str + 2 );
901 // all output ends up through here
902 void FPrintf (int flag, char *buf)
908 void Sys_FPrintf (int flag, const char *format, ...)
910 char out_buffer[4096];
913 if ((flag == SYS_VRB) && (verbose == false))
916 va_start (argptr, format);
917 vsprintf (out_buffer, format, argptr);
920 FPrintf (flag, out_buffer);
923 void Sys_Printf (const char *format, ...)
925 char out_buffer[4096];
928 va_start (argptr, format);
929 vsprintf (out_buffer, format, argptr);
932 FPrintf (SYS_STD, out_buffer);
938 //For abnormal program terminations
941 void Error( const char *error, ...)
943 char out_buffer[4096];
947 va_start (argptr,error);
948 vsprintf (tmp, error, argptr);
951 sprintf( out_buffer, "************ ERROR ************\n%s\n", tmp );
953 FPrintf( SYS_ERR, out_buffer );
961 ============================================================================
965 ============================================================================
968 #if GDEF_ARCH_ENDIAN_BIG
970 short LittleShort( short l ){
974 b2 = ( l >> 8 ) & 255;
976 return ( b1 << 8 ) + b2;
979 short BigShort( short l ){
984 int LittleLong( int l ){
988 b2 = ( l >> 8 ) & 255;
989 b3 = ( l >> 16 ) & 255;
990 b4 = ( l >> 24 ) & 255;
992 return ( (int)b1 << 24 ) + ( (int)b2 << 16 ) + ( (int)b3 << 8 ) + b4;
995 int BigLong( int l ){
1000 float LittleFloat( float l ){
1001 union {byte b[4]; float f; } in, out;
1012 float BigFloat( float l ){
1020 short BigShort( short l ){
1024 b2 = ( l >> 8 ) & 255;
1026 return ( b1 << 8 ) + b2;
1029 short LittleShort( short l ){
1034 int BigLong( int l ){
1038 b2 = ( l >> 8 ) & 255;
1039 b3 = ( l >> 16 ) & 255;
1040 b4 = ( l >> 24 ) & 255;
1042 return ( (int)b1 << 24 ) + ( (int)b2 << 16 ) + ( (int)b3 << 8 ) + b4;
1045 int LittleLong( int l ){
1049 float BigFloat( float l ){
1050 union {byte b[4]; float f; } in, out;
1061 float LittleFloat( float l ){
1069 //=======================================================
1072 // FIXME: byte swap?
1074 // this is a 16 bit, non-reflected CRC using the polynomial 0x1021
1075 // and the initial and final xor values shown below... in other words, the
1076 // CCITT standard CRC used by XMODEM
1078 #define CRC_INIT_VALUE 0xffff
1079 #define CRC_XOR_VALUE 0x0000
1081 static unsigned short crctable[256] =
1083 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
1084 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
1085 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
1086 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
1087 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
1088 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
1089 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
1090 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
1091 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
1092 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
1093 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
1094 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
1095 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
1096 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
1097 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
1098 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
1099 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
1100 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
1101 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
1102 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
1103 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
1104 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
1105 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
1106 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
1107 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
1108 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
1109 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
1110 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
1111 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
1112 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
1113 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
1114 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
1117 void CRC_Init( unsigned short *crcvalue ){
1118 *crcvalue = CRC_INIT_VALUE;
1121 void CRC_ProcessByte( unsigned short *crcvalue, byte data ){
1122 *crcvalue = ( *crcvalue << 8 ) ^ crctable[( *crcvalue >> 8 ) ^ data];
1125 unsigned short CRC_Value( unsigned short crcvalue ){
1126 return crcvalue ^ CRC_XOR_VALUE;
1128 //=============================================================================
1135 void CreatePath( const char *path ){
1143 if ( path[1] == ':' ) {
1144 olddrive = _getdrive();
1145 _chdrive( toupper( path[0] ) - 'A' + 1 );
1149 if ( path[1] == ':' ) {
1153 for ( ofs = path + 1 ; *ofs ; ofs++ )
1156 if ( c == '/' || c == '\\' ) { // create the directory
1157 memcpy( dir, path, ofs - path );
1158 dir[ ofs - path ] = 0;
1164 if ( olddrive != -1 ) {
1165 _chdrive( olddrive );
1175 Used to archive source files
1178 void QCopyFile( const char *from, const char *to ){
1182 length = LoadFile( from, &buffer );
1184 SaveFile( to, buffer, length );
1188 void Sys_Sleep( int n ){
1192 #if GDEF_OS_LINUX || GDEF_OS_MACOS