2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
\r
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
\r
5 This file is part of GtkRadiant.
\r
7 GtkRadiant is free software; you can redistribute it and/or modify
\r
8 it under the terms of the GNU General Public License as published by
\r
9 the Free Software Foundation; either version 2 of the License, or
\r
10 (at your option) any later version.
\r
12 GtkRadiant is distributed in the hope that it will be useful,
\r
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
15 GNU General Public License for more details.
\r
17 You should have received a copy of the GNU General Public License
\r
18 along with GtkRadiant; if not, write to the Free Software
\r
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
\r
22 // Nurail: Swiped from quake3/common
\r
25 #include "mathlib.h"
\r
27 #include <sys/types.h>
\r
28 #include <sys/stat.h>
\r
32 #include <windows.h>
\r
35 #if defined (__linux__) || defined (__APPLE__)
\r
43 #define BASEDIRNAME "h"
\r
44 #define PATHSEPERATOR '/'
\r
46 extern qboolean verbose;
\r
48 qboolean g_dokeypress = false;
\r
50 qboolean g_nomkdir = false;
\r
54 void *safe_malloc( size_t size )
\r
60 Error ("safe_malloc failed on allocation of %i bytes", size);
\r
65 void *safe_malloc_info( size_t size, char* info )
\r
71 Error ("%s: safe_malloc failed on allocation of %i bytes", info, size);
\r
77 void *SafeMalloc(size_t n, char *desc)
\r
81 if((p = malloc(n)) == NULL)
\r
83 Error("Failed to allocate %d bytes for '%s'.\n", n, desc);
\r
89 #if defined (__linux__) || defined (__APPLE__)
\r
90 void strlwr(char *conv_str)
\r
94 for(i=0; i<strlen(conv_str); i++)
\r
95 conv_str[i]=tolower(conv_str[i]);
\r
100 // set these before calling CheckParm
\r
104 char com_token[1024];
\r
108 char archivedir[1024];
\r
112 ===================
\r
115 Mimic unix command line expansion
\r
116 ===================
\r
118 #define MAX_EX_ARGC 1024
\r
120 char *ex_argv[MAX_EX_ARGC];
\r
123 void ExpandWildcards( int *argc, char ***argv )
\r
125 struct _finddata_t fileinfo;
\r
128 char filename[1024];
\r
129 char filebase[1024];
\r
133 for (i=0 ; i<*argc ; i++)
\r
136 if ( path[0] == '-'
\r
137 || ( !strstr(path, "*") && !strstr(path, "?") ) )
\r
139 ex_argv[ex_argc++] = path;
\r
143 handle = _findfirst (path, &fileinfo);
\r
147 ExtractFilePath (path, filebase);
\r
151 sprintf (filename, "%s%s", filebase, fileinfo.name);
\r
152 ex_argv[ex_argc++] = copystring (filename);
\r
153 } while (_findnext( handle, &fileinfo ) != -1);
\r
155 _findclose (handle);
\r
162 void ExpandWildcards (int *argc, char ***argv)
\r
169 qdir will hold the path up to the quake directory, including the slash
\r
174 gamedir will hold qdir + the game directory (id1, id2, etc)
\r
179 char gamedir[1024];
\r
180 char writedir[1024];
\r
182 void SetQdirFromPath( const char *path )
\r
189 if (!(path[0] == '/' || path[0] == '\\' || path[1] == ':'))
\r
190 { // path is partial
\r
192 strcat (temp, path);
\r
196 // search for "quake2" in path
\r
198 len = strlen(BASEDIRNAME);
\r
199 for (c=path+strlen(path)-1 ; c != path ; c--)
\r
203 if (!Q_strncasecmp (c, BASEDIRNAME, len))
\r
206 //strncpy (qdir, path, c+len+2-path);
\r
207 // the +2 assumes a 2 or 3 following quake which is not the
\r
208 // case with a retail install
\r
209 // so we need to add up how much to the next separator
\r
212 while (*sep && *sep != '/' && *sep != '\\')
\r
217 strncpy (qdir, path, c+len+count-path);
\r
218 Sys_Printf ("qdir: %s\n", qdir);
\r
219 for ( i = 0; i < strlen( qdir ); i++ )
\r
221 if ( qdir[i] == '\\' )
\r
228 if (*c == '/' || *c == '\\')
\r
230 strncpy (gamedir, path, c+1-path);
\r
232 for ( i = 0; i < strlen( gamedir ); i++ )
\r
234 if ( gamedir[i] == '\\' )
\r
238 Sys_Printf ("gamedir: %s\n", gamedir);
\r
240 if ( !writedir[0] )
\r
241 strcpy( writedir, gamedir );
\r
242 else if ( writedir[strlen( writedir )-1] != '/' )
\r
244 writedir[strlen( writedir )] = '/';
\r
245 writedir[strlen( writedir )+1] = 0;
\r
252 Error ("No gamedir in %s", path);
\r
256 Error ("SetQdirFromPath: no '%s' in %s", BASEDIRNAME, path);
\r
259 char *ExpandArg (const char *path)
\r
261 static char full[1024];
\r
263 if (path[0] != '/' && path[0] != '\\' && path[1] != ':')
\r
266 strcat (full, path);
\r
269 strcpy (full, path);
\r
273 char *ExpandPath (const char *path)
\r
275 static char full[1024];
\r
277 Error ("ExpandPath called without qdir set");
\r
278 if (path[0] == '/' || path[0] == '\\' || path[1] == ':') {
\r
279 strcpy( full, path );
\r
282 sprintf (full, "%s%s", qdir, path);
\r
286 char *ExpandGamePath (const char *path)
\r
288 static char full[1024];
\r
290 Error ("ExpandGamePath called without qdir set");
\r
291 if (path[0] == '/' || path[0] == '\\' || path[1] == ':') {
\r
292 strcpy( full, path );
\r
295 sprintf (full, "%s%s", gamedir, path);
\r
299 char *ExpandPathAndArchive (const char *path)
\r
302 char archivename[1024];
\r
304 expanded = ExpandPath (path);
\r
308 sprintf (archivename, "%s/%s", archivedir, path);
\r
309 QCopyFile (expanded, archivename);
\r
315 char *copystring(const char *s)
\r
318 b = safe_malloc(strlen(s)+1);
\r
330 double I_FloatTime (void)
\r
338 // more precise, less portable
\r
340 struct timezone tzp;
\r
341 static int secbase;
\r
343 gettimeofday(&tp, &tzp);
\r
347 secbase = tp.tv_sec;
\r
348 return tp.tv_usec/1000000.0;
\r
351 return (tp.tv_sec - secbase) + tp.tv_usec/1000000.0;
\r
355 void Q_getwd (char *out)
\r
360 _getcwd (out, 256);
\r
361 strcat (out, "\\");
\r
363 // Gef: Changed from getwd() to getcwd() to avoid potential buffer overflow
\r
367 while ( out[i] != 0 )
\r
369 if ( out[i] == '\\' )
\r
376 void Q_mkdir (const char *path)
\r
379 if (_mkdir (path) != -1)
\r
382 if (mkdir (path, 0777) != -1)
\r
385 if (errno != EEXIST)
\r
386 Error ("mkdir %s: %s",path, strerror(errno));
\r
393 returns -1 if not present
\r
396 int FileTime (const char *path)
\r
400 if (stat (path,&buf) == -1)
\r
403 return buf.st_mtime;
\r
412 Parse a token out of a string
\r
415 char *COM_Parse (char *data)
\r
428 while ( (c = *data) <= ' ')
\r
433 return NULL; // end of file;
\r
438 // skip // comments
\r
439 if (c=='/' && data[1] == '/')
\r
441 while (*data && *data != '\n')
\r
447 // handle quoted strings specially
\r
456 com_token[len] = 0;
\r
459 com_token[len] = c;
\r
464 // parse single characters
\r
465 if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
\r
467 com_token[len] = c;
\r
469 com_token[len] = 0;
\r
473 // parse a regular word
\r
476 com_token[len] = c;
\r
480 if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
\r
484 com_token[len] = 0;
\r
488 int Q_strncasecmp (const char *s1, const char *s2, int n)
\r
498 return 0; // strings are equal until end point
\r
502 if (c1 >= 'a' && c1 <= 'z')
\r
504 if (c2 >= 'a' && c2 <= 'z')
\r
507 return -1; // strings not equal
\r
511 return 0; // strings are equal
\r
514 int Q_stricmp (const char *s1, const char *s2)
\r
516 return Q_strncasecmp (s1, s2, 99999);
\r
519 int Q_strcasecmp (const char *s1, const char *s2)
\r
521 return Q_strncasecmp (s1, s2, 99999);
\r
524 // NOTE TTimo when switching to Multithread DLL (Release/Debug) in the config
\r
525 // started getting warnings about that function, prolly a duplicate with the runtime function
\r
526 // maybe we still need to have it in linux builds
\r
528 char *strupr (char *start)
\r
534 *in = toupper(*in);
\r
541 char *strlower (char *start)
\r
547 *in = tolower(*in);
\r
555 =============================================================================
\r
559 =============================================================================
\r
567 Checks for the given parameter in the program's command line arguments
\r
568 Returns the argument number (1 to argc-1) or 0 if not present
\r
571 int CheckParm (const char *check)
\r
575 for (i = 1;i<myargc;i++)
\r
577 if ( !Q_stricmp(check, myargv[i]) )
\r
591 int Q_filelength (FILE *f)
\r
597 fseek (f, 0, SEEK_END);
\r
599 fseek (f, pos, SEEK_SET);
\r
605 FILE *SafeOpenWrite (const char *filename)
\r
609 f = fopen(filename, "wb");
\r
612 Error ("Error opening %s: %s",filename,strerror(errno));
\r
617 FILE *SafeOpenRead (const char *filename)
\r
621 f = fopen(filename, "rb");
\r
624 Error ("Error opening %s: %s",filename,strerror(errno));
\r
630 void SafeRead (FILE *f, void *buffer, int count)
\r
632 if ( fread (buffer, 1, count, f) != (size_t)count)
\r
633 Error ("File read failure");
\r
637 void SafeWrite (FILE *f, const void *buffer, int count)
\r
639 if (fwrite (buffer, 1, count, f) != (size_t)count)
\r
640 Error ("File write failure");
\r
649 qboolean FileExists (const char *filename)
\r
653 f = fopen (filename, "r");
\r
665 int LoadFile( const char *filename, void **bufferptr )
\r
671 f = SafeOpenRead (filename);
\r
672 length = Q_filelength (f);
\r
673 buffer = safe_malloc (length+1);
\r
674 ((char *)buffer)[length] = 0;
\r
675 SafeRead (f, buffer, length);
\r
678 *bufferptr = buffer;
\r
687 rounds up memory allocation to 4K boundry
\r
691 int LoadFileBlock( const char *filename, void **bufferptr )
\r
694 int length, nBlock, nAllocSize;
\r
697 f = SafeOpenRead (filename);
\r
698 length = Q_filelength (f);
\r
699 nAllocSize = length;
\r
700 nBlock = nAllocSize % MEM_BLOCKSIZE;
\r
702 nAllocSize += MEM_BLOCKSIZE - nBlock;
\r
704 buffer = safe_malloc (nAllocSize+1);
\r
705 memset(buffer, 0, nAllocSize+1);
\r
706 SafeRead (f, buffer, length);
\r
709 *bufferptr = buffer;
\r
721 int TryLoadFile (const char *filename, void **bufferptr)
\r
729 f = fopen (filename, "rb");
\r
732 length = Q_filelength (f);
\r
733 buffer = safe_malloc (length+1);
\r
734 ((char *)buffer)[length] = 0;
\r
735 SafeRead (f, buffer, length);
\r
738 *bufferptr = buffer;
\r
748 void SaveFile (const char *filename, const void *buffer, int count)
\r
752 f = SafeOpenWrite (filename);
\r
753 SafeWrite (f, buffer, count);
\r
759 void DefaultExtension (char *path, const char *extension)
\r
763 // if path doesnt have a .EXT, append extension
\r
764 // (extension should include the .)
\r
766 src = path + strlen(path) - 1;
\r
768 while (*src != '/' && *src != '\\' && src != path)
\r
771 return; // it has an extension
\r
775 strcat (path, extension);
\r
779 void DefaultPath (char *path, const char *basepath)
\r
783 if( path[ 0 ] == '/' || path[ 0 ] == '\\' )
\r
784 return; // absolute path location
\r
785 strcpy (temp,path);
\r
786 strcpy (path,basepath);
\r
787 strcat (path,temp);
\r
791 void StripFilename (char *path)
\r
795 length = strlen(path)-1;
\r
796 while (length > 0 && path[length] != '/' && path[ length ] != '\\' )
\r
801 void StripExtension (char *path)
\r
805 length = strlen(path)-1;
\r
806 while (length > 0 && path[length] != '.')
\r
809 if (path[length] == '/' || path[ length ] == '\\' )
\r
810 return; // no extension
\r
818 ====================
\r
820 ====================
\r
822 // FIXME: should include the slash, otherwise
\r
823 // backing to an empty path will be wrong when appending a slash
\r
824 void ExtractFilePath (const char *path, char *dest)
\r
828 src = path + strlen(path) - 1;
\r
831 // back up until a \ or the start
\r
833 while (src != path && *(src-1) != '\\' && *(src-1) != '/')
\r
836 memcpy (dest, path, src-path);
\r
837 dest[src-path] = 0;
\r
840 void ExtractFileBase (const char *path, char *dest)
\r
844 src = path + strlen(path) - 1;
\r
847 // back up until a \ or the start
\r
849 while (src != path && *(src-1) != '/' && *(src-1) != '\\' )
\r
852 while (*src && *src != '.')
\r
859 void ExtractFileExtension (const char *path, char *dest)
\r
863 src = path + strlen(path) - 1;
\r
866 // back up until a . or the start
\r
868 while (src != path && *(src-1) != '.')
\r
872 *dest = 0; // no extension
\r
882 ParseNum / ParseHex
\r
885 int ParseHex (const char *hex)
\r
896 if (*str >= '0' && *str <= '9')
\r
898 else if (*str >= 'a' && *str <= 'f')
\r
899 num += 10 + *str-'a';
\r
900 else if (*str >= 'A' && *str <= 'F')
\r
901 num += 10 + *str-'A';
\r
903 Error ("Bad hex number: %s",hex);
\r
911 int ParseNum (const char *str)
\r
914 return ParseHex (str+1);
\r
915 if (str[0] == '0' && str[1] == 'x')
\r
916 return ParseHex (str+2);
\r
920 // all output ends up through here
\r
921 void FPrintf (int flag, char *buf)
\r
927 void Sys_FPrintf (int flag, const char *format, ...)
\r
929 char out_buffer[4096];
\r
932 if ((flag == SYS_VRB) && (verbose == false))
\r
935 va_start (argptr, format);
\r
936 vsprintf (out_buffer, format, argptr);
\r
939 FPrintf (flag, out_buffer);
\r
942 void Sys_Printf (const char *format, ...)
\r
944 char out_buffer[4096];
\r
947 va_start (argptr, format);
\r
948 vsprintf (out_buffer, format, argptr);
\r
951 FPrintf (SYS_STD, out_buffer);
\r
954 //=================
\r
957 //For abnormal program terminations
\r
958 //=================
\r
960 void Error( const char *error, ...)
\r
962 char out_buffer[4096];
\r
966 va_start (argptr,error);
\r
967 vsprintf (tmp, error, argptr);
\r
970 sprintf( out_buffer, "************ ERROR ************\n%s\n", tmp );
\r
972 FPrintf( SYS_ERR, out_buffer );
\r
980 ============================================================================
\r
982 BYTE ORDER FUNCTIONS
\r
984 ============================================================================
\r
988 #define __BIG_ENDIAN__
\r
991 #ifdef __BIG_ENDIAN__
\r
993 short LittleShort (short l)
\r
1000 return (b1<<8) + b2;
\r
1003 short BigShort (short l)
\r
1009 int LittleLong (int l)
\r
1018 return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
\r
1021 int BigLong (int l)
\r
1027 float LittleFloat (float l)
\r
1029 union {byte b[4]; float f;} in, out;
\r
1032 out.b[0] = in.b[3];
\r
1033 out.b[1] = in.b[2];
\r
1034 out.b[2] = in.b[1];
\r
1035 out.b[3] = in.b[0];
\r
1040 float BigFloat (float l)
\r
1049 short BigShort (short l)
\r
1056 return (b1<<8) + b2;
\r
1059 short LittleShort (short l)
\r
1065 int BigLong (int l)
\r
1074 return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
\r
1077 int LittleLong (int l)
\r
1082 float BigFloat (float l)
\r
1084 union {byte b[4]; float f;} in, out;
\r
1087 out.b[0] = in.b[3];
\r
1088 out.b[1] = in.b[2];
\r
1089 out.b[2] = in.b[1];
\r
1090 out.b[3] = in.b[0];
\r
1095 float LittleFloat (float l)
\r
1104 //=======================================================
\r
1107 // FIXME: byte swap?
\r
1109 // this is a 16 bit, non-reflected CRC using the polynomial 0x1021
\r
1110 // and the initial and final xor values shown below... in other words, the
\r
1111 // CCITT standard CRC used by XMODEM
\r
1113 #define CRC_INIT_VALUE 0xffff
\r
1114 #define CRC_XOR_VALUE 0x0000
\r
1116 static unsigned short crctable[256] =
\r
1118 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
\r
1119 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
\r
1120 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
\r
1121 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
\r
1122 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
\r
1123 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
\r
1124 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
\r
1125 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
\r
1126 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
\r
1127 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
\r
1128 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
\r
1129 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
\r
1130 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
\r
1131 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
\r
1132 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
\r
1133 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
\r
1134 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
\r
1135 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
\r
1136 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
\r
1137 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
\r
1138 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
\r
1139 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
\r
1140 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
\r
1141 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
\r
1142 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
\r
1143 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
\r
1144 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
\r
1145 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
\r
1146 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
\r
1147 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
\r
1148 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
\r
1149 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
\r
1152 void CRC_Init(unsigned short *crcvalue)
\r
1154 *crcvalue = CRC_INIT_VALUE;
\r
1157 void CRC_ProcessByte(unsigned short *crcvalue, byte data)
\r
1159 *crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data];
\r
1162 unsigned short CRC_Value(unsigned short crcvalue)
\r
1164 return crcvalue ^ CRC_XOR_VALUE;
\r
1166 //=============================================================================
\r
1173 void CreatePath (const char *path)
\r
1180 int olddrive = -1;
\r
1182 if ( path[1] == ':' )
\r
1184 olddrive = _getdrive();
\r
1185 _chdrive( toupper( path[0] ) - 'A' + 1 );
\r
1189 if (path[1] == ':')
\r
1192 for (ofs = path+1 ; *ofs ; ofs++)
\r
1195 if (c == '/' || c == '\\')
\r
1196 { // create the directory
\r
1197 memcpy( dir, path, ofs - path );
\r
1198 dir[ ofs - path ] = 0;
\r
1204 if ( olddrive != -1 )
\r
1206 _chdrive( olddrive );
\r
1216 Used to archive source files
\r
1219 void QCopyFile (const char *from, const char *to)
\r
1224 length = LoadFile (from, &buffer);
\r
1226 SaveFile (to, buffer, length);
\r
1230 void Sys_Sleep(int n)
\r
1235 #if defined (__linux__) || defined (__APPLE__)
\r
1236 usleep (n * 1000);
\r