X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fnetradiant.git;a=blobdiff_plain;f=tools%2Fquake3%2Fcommon%2Fcmdlib.c;h=3c01cc9923663a98c1fa282127d6755f6d7a4573;hp=17e41032e455c15df38504d1e29e33caa231f9b1;hb=943424faa1514f24b63524161d299734a8c3f8bd;hpb=80378101101ca1762bbf5638a9e3566893096d8a diff --git a/tools/quake3/common/cmdlib.c b/tools/quake3/common/cmdlib.c index 17e41032..3c01cc99 100644 --- a/tools/quake3/common/cmdlib.c +++ b/tools/quake3/common/cmdlib.c @@ -1,1153 +1,1111 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -// cmdlib.c -// TTimo 09/30/2000 -// from an intial copy of common/cmdlib.c -// stripped out the Sys_Printf Sys_Printf stuff - -// SPoG 05/27/2001 -// merging alpha branch into trunk -// replaced qprintf with Sys_Printf - -#include "cmdlib.h" -#include "mathlib.h" -#include "inout.h" -#include -#include - -#ifdef _WIN32 -#include -#include -#endif - -#if defined (__linux__) || defined (__APPLE__) -#include -#endif - -#ifdef NeXT -#include -#endif - -#define BASEDIRNAME "quake" // assumed to have a 2 or 3 following -#define PATHSEPERATOR '/' - -#ifdef SAFE_MALLOC -void *safe_malloc( size_t size ) -{ - void *p; - - p = malloc(size); - if(!p) - Error ("safe_malloc failed on allocation of %i bytes", size); - - return p; -} - -void *safe_malloc_info( size_t size, char* info ) -{ - void *p; - - p = malloc(size); - if(!p) - Error ("%s: safe_malloc failed on allocation of %i bytes", info, size); - - return p; -} -#endif - -// set these before calling CheckParm -int myargc; -char **myargv; - -char com_token[1024]; -qboolean com_eof; - -qboolean archive; -char archivedir[1024]; - - -/* -=================== -ExpandWildcards - -Mimic unix command line expansion -=================== -*/ -#define MAX_EX_ARGC 1024 -int ex_argc; -char *ex_argv[MAX_EX_ARGC]; -#ifdef _WIN32 -#include "io.h" -void ExpandWildcards( int *argc, char ***argv ) -{ - struct _finddata_t fileinfo; - int handle; - int i; - char filename[1024]; - char filebase[1024]; - char *path; - - ex_argc = 0; - for (i=0 ; i<*argc ; i++) - { - path = (*argv)[i]; - if ( path[0] == '-' - || ( !strstr(path, "*") && !strstr(path, "?") ) ) - { - ex_argv[ex_argc++] = path; - continue; - } - - handle = _findfirst (path, &fileinfo); - if (handle == -1) - return; - - ExtractFilePath (path, filebase); - - do - { - sprintf (filename, "%s%s", filebase, fileinfo.name); - ex_argv[ex_argc++] = copystring (filename); - } while (_findnext( handle, &fileinfo ) != -1); - - _findclose (handle); - } - - *argc = ex_argc; - *argv = ex_argv; -} -#else -void ExpandWildcards (int *argc, char ***argv) -{ -} -#endif - -/* - -qdir will hold the path up to the quake directory, including the slash - - f:\quake\ - /raid/quake/ - -gamedir will hold qdir + the game directory (id1, id2, etc) - -*/ - -char qdir[1024]; -char gamedir[1024]; -char writedir[1024]; - -void SetQdirFromPath( const char *path ) -{ - char temp[1024]; - const char *c; - const char *sep; - int len, count; - - if (!(path[0] == '/' || path[0] == '\\' || path[1] == ':')) - { // path is partial - Q_getwd (temp); - strcat (temp, path); - path = temp; - } - - // search for "quake2" in path - - len = strlen(BASEDIRNAME); - for (c=path+strlen(path)-1 ; c != path ; c--) - { - int i; - - if (!Q_strncasecmp (c, BASEDIRNAME, len)) - { - // - //strncpy (qdir, path, c+len+2-path); - // the +2 assumes a 2 or 3 following quake which is not the - // case with a retail install - // so we need to add up how much to the next separator - sep = c + len; - count = 1; - while (*sep && *sep != '/' && *sep != '\\') - { - sep++; - count++; - } - strncpy (qdir, path, c+len+count-path); - Sys_Printf ("qdir: %s\n", qdir); - for ( i = 0; i < strlen( qdir ); i++ ) - { - if ( qdir[i] == '\\' ) - qdir[i] = '/'; - } - - c += len+count; - while (*c) - { - if (*c == '/' || *c == '\\') - { - strncpy (gamedir, path, c+1-path); - - for ( i = 0; i < strlen( gamedir ); i++ ) - { - if ( gamedir[i] == '\\' ) - gamedir[i] = '/'; - } - - Sys_Printf ("gamedir: %s\n", gamedir); - - if ( !writedir[0] ) - strcpy( writedir, gamedir ); - else if ( writedir[strlen( writedir )-1] != '/' ) - { - writedir[strlen( writedir )] = '/'; - writedir[strlen( writedir )+1] = 0; - } - - return; - } - c++; - } - Error ("No gamedir in %s", path); - return; - } - } - Error ("SetQdirFromPath: no '%s' in %s", BASEDIRNAME, path); -} - -char *ExpandArg (const char *path) -{ - static char full[1024]; - - if (path[0] != '/' && path[0] != '\\' && path[1] != ':') - { - Q_getwd (full); - strcat (full, path); - } - else - strcpy (full, path); - return full; -} - -char *ExpandPath (const char *path) -{ - static char full[1024]; - if (!qdir) - Error ("ExpandPath called without qdir set"); - if (path[0] == '/' || path[0] == '\\' || path[1] == ':') { - strcpy( full, path ); - return full; - } - sprintf (full, "%s%s", qdir, path); - return full; -} - -char *ExpandGamePath (const char *path) -{ - static char full[1024]; - if (!qdir) - Error ("ExpandGamePath called without qdir set"); - if (path[0] == '/' || path[0] == '\\' || path[1] == ':') { - strcpy( full, path ); - return full; - } - sprintf (full, "%s%s", gamedir, path); - return full; -} - -char *ExpandPathAndArchive (const char *path) -{ - char *expanded; - char archivename[1024]; - - expanded = ExpandPath (path); - - if (archive) - { - sprintf (archivename, "%s/%s", archivedir, path); - QCopyFile (expanded, archivename); - } - return expanded; -} - - -char *copystring(const char *s) -{ - char *b; - b = safe_malloc(strlen(s)+1); - strcpy (b, s); - return b; -} - - - -/* -================ -I_FloatTime -================ -*/ -double I_FloatTime (void) -{ - time_t t; - - time (&t); - - return t; -#if 0 -// more precise, less portable - struct timeval tp; - struct timezone tzp; - static int secbase; - - gettimeofday(&tp, &tzp); - - if (!secbase) - { - secbase = tp.tv_sec; - return tp.tv_usec/1000000.0; - } - - return (tp.tv_sec - secbase) + tp.tv_usec/1000000.0; -#endif -} - -void Q_getwd (char *out) -{ - int i = 0; - -#ifdef _WIN32 - _getcwd (out, 256); - strcat (out, "\\"); -#else - // Gef: Changed from getwd() to getcwd() to avoid potential buffer overflow - getcwd (out, 256); - strcat (out, "/"); -#endif - while ( out[i] != 0 ) - { - if ( out[i] == '\\' ) - out[i] = '/'; - i++; - } -} - - -void Q_mkdir (const char *path) -{ -#ifdef _WIN32 - if (_mkdir (path) != -1) - return; -#else - if (mkdir (path, 0777) != -1) - return; -#endif - if (errno != EEXIST) - Error ("mkdir %s: %s",path, strerror(errno)); -} - -/* -============ -FileTime - -returns -1 if not present -============ -*/ -int FileTime (const char *path) -{ - struct stat buf; - - if (stat (path,&buf) == -1) - return -1; - - return buf.st_mtime; -} - - - -/* -============== -COM_Parse - -Parse a token out of a string -============== -*/ -char *COM_Parse (char *data) -{ - int c; - int len; - - len = 0; - com_token[0] = 0; - - if (!data) - return NULL; - -// skip whitespace -skipwhite: - while ( (c = *data) <= ' ') - { - if (c == 0) - { - com_eof = qtrue; - return NULL; // end of file; - } - data++; - } - -// skip // comments - if (c=='/' && data[1] == '/') - { - while (*data && *data != '\n') - data++; - goto skipwhite; - } - - -// handle quoted strings specially - if (c == '\"') - { - data++; - do - { - c = *data++; - if (c=='\"') - { - com_token[len] = 0; - return data; - } - com_token[len] = c; - len++; - } while (1); - } - -// parse single characters - if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':') - { - com_token[len] = c; - len++; - com_token[len] = 0; - return data+1; - } - -// parse a regular word - do - { - com_token[len] = c; - data++; - len++; - c = *data; - if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':') - break; - } while (c>32); - - com_token[len] = 0; - return data; -} - -int Q_strncasecmp (const char *s1, const char *s2, int n) -{ - int c1, c2; - - do - { - c1 = *s1++; - c2 = *s2++; - - if (!n--) - return 0; // strings are equal until end point - - if (c1 != c2) - { - if (c1 >= 'a' && c1 <= 'z') - c1 -= ('a' - 'A'); - if (c2 >= 'a' && c2 <= 'z') - c2 -= ('a' - 'A'); - if (c1 != c2) - return -1; // strings not equal - } - } while (c1); - - return 0; // strings are equal -} - -int Q_stricmp (const char *s1, const char *s2) -{ - return Q_strncasecmp (s1, s2, 99999); -} - -// NOTE TTimo when switching to Multithread DLL (Release/Debug) in the config -// started getting warnings about that function, prolly a duplicate with the runtime function -// maybe we still need to have it in linux builds -/* -char *strupr (char *start) -{ - char *in; - in = start; - while (*in) - { - *in = toupper(*in); - in++; - } - return start; -} -*/ - -char *strlower (char *start) -{ - char *in; - in = start; - while (*in) - { - *in = tolower(*in); - in++; - } - return start; -} - - -/* -============================================================================= - - MISC FUNCTIONS - -============================================================================= -*/ - - -/* -================= -CheckParm - -Checks for the given parameter in the program's command line arguments -Returns the argument number (1 to argc-1) or 0 if not present -================= -*/ -int CheckParm (const char *check) -{ - int i; - - for (i = 1;i 0) { - nAllocSize += MEM_BLOCKSIZE - nBlock; - } - buffer = safe_malloc (nAllocSize+1); - memset(buffer, 0, nAllocSize+1); - SafeRead (f, buffer, length); - fclose (f); - - *bufferptr = buffer; - return length; -} - - -/* -============== -TryLoadFile - -Allows failure -============== -*/ -int TryLoadFile (const char *filename, void **bufferptr) -{ - FILE *f; - int length; - void *buffer; - - *bufferptr = NULL; - - f = fopen (filename, "rb"); - if (!f) - return -1; - length = Q_filelength (f); - buffer = safe_malloc (length+1); - ((char *)buffer)[length] = 0; - SafeRead (f, buffer, length); - fclose (f); - - *bufferptr = buffer; - return length; -} - - -/* -============== -SaveFile -============== -*/ -void SaveFile (const char *filename, const void *buffer, int count) -{ - FILE *f; - - f = SafeOpenWrite (filename); - SafeWrite (f, buffer, count); - fclose (f); -} - - - -void DefaultExtension (char *path, const char *extension) -{ - char *src; -// -// if path doesnt have a .EXT, append extension -// (extension should include the .) -// - src = path + strlen(path) - 1; - - while (*src != '/' && *src != '\\' && src != path) - { - if (*src == '.') - return; // it has an extension - src--; - } - - strcat (path, extension); -} - - -void DefaultPath (char *path, const char *basepath) -{ - char temp[128]; - - if( path[ 0 ] == '/' || path[ 0 ] == '\\' ) - return; // absolute path location - strcpy (temp,path); - strcpy (path,basepath); - strcat (path,temp); -} - - -void StripFilename (char *path) -{ - int length; - - length = strlen(path)-1; - while (length > 0 && path[length] != '/' && path[ length ] != '\\' ) - length--; - path[length] = 0; -} - -void StripExtension (char *path) -{ - int length; - - length = strlen(path)-1; - while (length > 0 && path[length] != '.') - { - length--; - if (path[length] == '/' || path[ length ] == '\\' ) - return; // no extension - } - if (length) - path[length] = 0; -} - - -/* -==================== -Extract file parts -==================== -*/ -// FIXME: should include the slash, otherwise -// backing to an empty path will be wrong when appending a slash -void ExtractFilePath (const char *path, char *dest) -{ - const char *src; - - src = path + strlen(path) - 1; - -// -// back up until a \ or the start -// - while (src != path && *(src-1) != '\\' && *(src-1) != '/') - src--; - - memcpy (dest, path, src-path); - dest[src-path] = 0; -} - -void ExtractFileBase (const char *path, char *dest) -{ - const char *src; - - src = path + strlen(path) - 1; - -// -// back up until a \ or the start -// - while (src != path && *(src-1) != '/' && *(src-1) != '\\' ) - src--; - - while (*src && *src != '.') - { - *dest++ = *src++; - } - *dest = 0; -} - -void ExtractFileExtension (const char *path, char *dest) -{ - const char *src; - - src = path + strlen(path) - 1; - -// -// back up until a . or the start -// - while (src != path && *(src-1) != '.') - src--; - if (src == path) - { - *dest = 0; // no extension - return; - } - - strcpy (dest,src); -} - - -/* -============== -ParseNum / ParseHex -============== -*/ -int ParseHex (const char *hex) -{ - const char *str; - int num; - - num = 0; - str = hex; - - while (*str) - { - num <<= 4; - if (*str >= '0' && *str <= '9') - num += *str-'0'; - else if (*str >= 'a' && *str <= 'f') - num += 10 + *str-'a'; - else if (*str >= 'A' && *str <= 'F') - num += 10 + *str-'A'; - else - Error ("Bad hex number: %s",hex); - str++; - } - - return num; -} - - -int ParseNum (const char *str) -{ - if (str[0] == '$') - return ParseHex (str+1); - if (str[0] == '0' && str[1] == 'x') - return ParseHex (str+2); - return atol (str); -} - - - -/* -============================================================================ - - BYTE ORDER FUNCTIONS - -============================================================================ -*/ - -#ifdef _SGI_SOURCE -#define __BIG_ENDIAN__ -#endif - -#ifdef __BIG_ENDIAN__ - -short LittleShort (short l) -{ - byte b1,b2; - - b1 = l&255; - b2 = (l>>8)&255; - - return (b1<<8) + b2; -} - -short BigShort (short l) -{ - return l; -} - - -int LittleLong (int l) -{ - byte b1,b2,b3,b4; - - b1 = l&255; - b2 = (l>>8)&255; - b3 = (l>>16)&255; - b4 = (l>>24)&255; - - return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; -} - -int BigLong (int l) -{ - return l; -} - - -float LittleFloat (float l) -{ - union {byte b[4]; float f;} in, out; - - in.f = l; - out.b[0] = in.b[3]; - out.b[1] = in.b[2]; - out.b[2] = in.b[1]; - out.b[3] = in.b[0]; - - return out.f; -} - -float BigFloat (float l) -{ - return l; -} - - -#else - - -short BigShort (short l) -{ - byte b1,b2; - - b1 = l&255; - b2 = (l>>8)&255; - - return (b1<<8) + b2; -} - -short LittleShort (short l) -{ - return l; -} - - -int BigLong (int l) -{ - byte b1,b2,b3,b4; - - b1 = l&255; - b2 = (l>>8)&255; - b3 = (l>>16)&255; - b4 = (l>>24)&255; - - return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; -} - -int LittleLong (int l) -{ - return l; -} - -float BigFloat (float l) -{ - union {byte b[4]; float f;} in, out; - - in.f = l; - out.b[0] = in.b[3]; - out.b[1] = in.b[2]; - out.b[2] = in.b[1]; - out.b[3] = in.b[0]; - - return out.f; -} - -float LittleFloat (float l) -{ - return l; -} - - -#endif - - -//======================================================= - - -// FIXME: byte swap? - -// this is a 16 bit, non-reflected CRC using the polynomial 0x1021 -// and the initial and final xor values shown below... in other words, the -// CCITT standard CRC used by XMODEM - -#define CRC_INIT_VALUE 0xffff -#define CRC_XOR_VALUE 0x0000 - -static unsigned short crctable[256] = -{ - 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, - 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, - 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, - 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, - 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, - 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, - 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, - 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, - 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, - 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, - 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, - 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, - 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, - 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, - 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, - 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, - 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, - 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, - 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, - 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, - 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, - 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, - 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, - 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, - 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, - 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, - 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, - 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, - 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, - 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, - 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, - 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 -}; - -void CRC_Init(unsigned short *crcvalue) -{ - *crcvalue = CRC_INIT_VALUE; -} - -void CRC_ProcessByte(unsigned short *crcvalue, byte data) -{ - *crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data]; -} - -unsigned short CRC_Value(unsigned short crcvalue) -{ - return crcvalue ^ CRC_XOR_VALUE; -} -//============================================================================= - -/* -============ -CreatePath -============ -*/ -void CreatePath (const char *path) -{ - const char *ofs; - char c; - char dir[1024]; - -#ifdef _WIN32 - int olddrive = -1; - - if ( path[1] == ':' ) - { - olddrive = _getdrive(); - _chdrive( toupper( path[0] ) - 'A' + 1 ); - } -#endif - - if (path[1] == ':') - path += 2; - - for (ofs = path+1 ; *ofs ; ofs++) - { - c = *ofs; - if (c == '/' || c == '\\') - { // create the directory - memcpy( dir, path, ofs - path ); - dir[ ofs - path ] = 0; - Q_mkdir( dir ); - } - } - -#ifdef _WIN32 - if ( olddrive != -1 ) - { - _chdrive( olddrive ); - } -#endif -} - - -/* -============ -QCopyFile - - Used to archive source files -============ -*/ -void QCopyFile (const char *from, const char *to) -{ - void *buffer; - int length; - - length = LoadFile (from, &buffer); - CreatePath (to); - SaveFile (to, buffer, length); - free (buffer); -} - -void Sys_Sleep(int n) -{ -#ifdef _WIN32 - Sleep (n); -#endif -#if defined (__linux__) || defined (__APPLE__) - usleep (n * 1000); -#endif -} +/* + Copyright (C) 1999-2007 id Software, Inc. and contributors. + For a list of contributors, see the accompanying CONTRIBUTORS file. + + This file is part of GtkRadiant. + + GtkRadiant is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + GtkRadiant is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GtkRadiant; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +// cmdlib.c +// TTimo 09/30/2000 +// from an intial copy of common/cmdlib.c +// stripped out the Sys_Printf Sys_Printf stuff + +// SPoG 05/27/2001 +// merging alpha branch into trunk +// replaced qprintf with Sys_Printf + +#include "cmdlib.h" +#include "mathlib.h" +#include "inout.h" +#include +#include + +#ifdef _WIN32 +#include +#include +#endif + +#if defined ( __linux__ ) || defined ( __APPLE__ ) +#include +#endif + +#ifdef NeXT +#include +#endif + +#define BASEDIRNAME "quake" // assumed to have a 2 or 3 following +#define PATHSEPERATOR '/' + +#ifdef SAFE_MALLOC +void *safe_malloc( size_t size ){ + void *p; + + p = malloc( size ); + if ( !p ) { + Error( "safe_malloc failed on allocation of %i bytes", size ); + } + + return p; +} + +void *safe_malloc_info( size_t size, char* info ){ + void *p; + + p = malloc( size ); + if ( !p ) { + Error( "%s: safe_malloc failed on allocation of %i bytes", info, size ); + } + + return p; +} +#endif + +// set these before calling CheckParm +int myargc; +char **myargv; + +char com_token[1024]; +qboolean com_eof; + +qboolean archive; +char archivedir[1024]; + + +/* + =================== + ExpandWildcards + + Mimic unix command line expansion + =================== + */ +#define MAX_EX_ARGC 1024 +int ex_argc; +char *ex_argv[MAX_EX_ARGC]; +#ifdef _WIN32 +#include "io.h" +void ExpandWildcards( int *argc, char ***argv ){ + struct _finddata_t fileinfo; + int handle; + int i; + char filename[1024]; + char filebase[1024]; + char *path; + + ex_argc = 0; + for ( i = 0 ; i < *argc ; i++ ) + { + path = ( *argv )[i]; + if ( path[0] == '-' + || ( !strstr( path, "*" ) && !strstr( path, "?" ) ) ) { + ex_argv[ex_argc++] = path; + continue; + } + + handle = _findfirst( path, &fileinfo ); + if ( handle == -1 ) { + return; + } + + ExtractFilePath( path, filebase ); + + do + { + sprintf( filename, "%s%s", filebase, fileinfo.name ); + ex_argv[ex_argc++] = copystring( filename ); + } while ( _findnext( handle, &fileinfo ) != -1 ); + + _findclose( handle ); + } + + *argc = ex_argc; + *argv = ex_argv; +} +#else +void ExpandWildcards( int *argc, char ***argv ){ +} +#endif + +/* + + qdir will hold the path up to the quake directory, including the slash + + f:\quake\ + /raid/quake/ + + gamedir will hold qdir + the game directory (id1, id2, etc) + + */ + +char qdir[1024]; +char gamedir[1024]; +char writedir[1024]; + +void SetQdirFromPath( const char *path ){ + char temp[1024]; + const char *c; + const char *sep; + int len, count; + + if ( !( path[0] == '/' || path[0] == '\\' || path[1] == ':' ) ) { // path is partial + Q_getwd( temp ); + strcat( temp, path ); + path = temp; + } + + // search for "quake2" in path + + len = strlen( BASEDIRNAME ); + for ( c = path + strlen( path ) - 1 ; c != path ; c-- ) + { + int i; + + if ( !Q_strncasecmp( c, BASEDIRNAME, len ) ) { + // + //strncpy (qdir, path, c+len+2-path); + // the +2 assumes a 2 or 3 following quake which is not the + // case with a retail install + // so we need to add up how much to the next separator + sep = c + len; + count = 1; + while ( *sep && *sep != '/' && *sep != '\\' ) + { + sep++; + count++; + } + strncpy( qdir, path, c + len + count - path ); + Sys_Printf( "qdir: %s\n", qdir ); + for ( i = 0; i < strlen( qdir ); i++ ) + { + if ( qdir[i] == '\\' ) { + qdir[i] = '/'; + } + } + + c += len + count; + while ( *c ) + { + if ( *c == '/' || *c == '\\' ) { + strncpy( gamedir, path, c + 1 - path ); + + for ( i = 0; i < strlen( gamedir ); i++ ) + { + if ( gamedir[i] == '\\' ) { + gamedir[i] = '/'; + } + } + + Sys_Printf( "gamedir: %s\n", gamedir ); + + if ( !writedir[0] ) { + strcpy( writedir, gamedir ); + } + else if ( writedir[strlen( writedir ) - 1] != '/' ) { + writedir[strlen( writedir )] = '/'; + writedir[strlen( writedir ) + 1] = 0; + } + + return; + } + c++; + } + Error( "No gamedir in %s", path ); + return; + } + } + Error( "SetQdirFromPath: no '%s' in %s", BASEDIRNAME, path ); +} + +char *ExpandArg( const char *path ){ + static char full[1024]; + + if ( path[0] != '/' && path[0] != '\\' && path[1] != ':' ) { + Q_getwd( full ); + strcat( full, path ); + } + else{ + strcpy( full, path ); + } + return full; +} + +char *ExpandPath( const char *path ){ + static char full[1024]; + if ( path[0] == '/' || path[0] == '\\' || path[1] == ':' ) { + strcpy( full, path ); + return full; + } + sprintf( full, "%s%s", qdir, path ); + return full; +} + +char *ExpandGamePath( const char *path ){ + static char full[1024]; + if ( path[0] == '/' || path[0] == '\\' || path[1] == ':' ) { + strcpy( full, path ); + return full; + } + sprintf( full, "%s%s", gamedir, path ); + return full; +} + +char *ExpandPathAndArchive( const char *path ){ + char *expanded; + char archivename[1024]; + + expanded = ExpandPath( path ); + + if ( archive ) { + sprintf( archivename, "%s/%s", archivedir, path ); + QCopyFile( expanded, archivename ); + } + return expanded; +} + + +char *copystring( const char *s ){ + char *b; + b = safe_malloc( strlen( s ) + 1 ); + strcpy( b, s ); + return b; +} + + + +/* + ================ + I_FloatTime + ================ + */ +double I_FloatTime( void ){ + time_t t; + + time( &t ); + + return t; +#if 0 +// more precise, less portable + struct timeval tp; + struct timezone tzp; + static int secbase; + + gettimeofday( &tp, &tzp ); + + if ( !secbase ) { + secbase = tp.tv_sec; + return tp.tv_usec / 1000000.0; + } + + return ( tp.tv_sec - secbase ) + tp.tv_usec / 1000000.0; +#endif +} + +void Q_getwd( char *out ){ + int i = 0; + +#ifdef WIN32 + _getcwd( out, 256 ); + strcat( out, "\\" ); +#else + // Gef: Changed from getwd() to getcwd() to avoid potential buffer overflow + getcwd( out, 256 ); + strcat( out, "/" ); +#endif + while ( out[i] != 0 ) + { + if ( out[i] == '\\' ) { + out[i] = '/'; + } + i++; + } +} + + +void Q_mkdir( const char *path ){ +#ifdef WIN32 + if ( _mkdir( path ) != -1 ) { + return; + } +#else + if ( mkdir( path, 0777 ) != -1 ) { + return; + } +#endif + if ( errno != EEXIST ) { + Error( "mkdir %s: %s",path, strerror( errno ) ); + } +} + +/* + ============ + FileTime + + returns -1 if not present + ============ + */ +int FileTime( const char *path ){ + struct stat buf; + + if ( stat( path,&buf ) == -1 ) { + return -1; + } + + return buf.st_mtime; +} + + + +/* + ============== + COM_Parse + + Parse a token out of a string + ============== + */ +char *COM_Parse( char *data ){ + int c; + int len; + + len = 0; + com_token[0] = 0; + + if ( !data ) { + return NULL; + } + +// skip whitespace +skipwhite: + while ( ( c = *data ) <= ' ' ) + { + if ( c == 0 ) { + com_eof = qtrue; + return NULL; // end of file; + } + data++; + } + +// skip // comments + if ( c == '/' && data[1] == '/' ) { + while ( *data && *data != '\n' ) + data++; + goto skipwhite; + } + + +// handle quoted strings specially + if ( c == '\"' ) { + data++; + do + { + c = *data++; + if ( c == '\"' ) { + com_token[len] = 0; + return data; + } + com_token[len] = c; + len++; + } while ( 1 ); + } + +// parse single characters + if ( c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ':' ) { + com_token[len] = c; + len++; + com_token[len] = 0; + return data + 1; + } + +// parse a regular word + do + { + com_token[len] = c; + data++; + len++; + c = *data; + if ( c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ':' ) { + break; + } + } while ( c > 32 ); + + com_token[len] = 0; + return data; +} + +int Q_strncasecmp( const char *s1, const char *s2, int n ){ + int c1, c2; + + do + { + c1 = *s1++; + c2 = *s2++; + + if ( !n-- ) { + return 0; // strings are equal until end point + + } + if ( c1 != c2 ) { + if ( c1 >= 'a' && c1 <= 'z' ) { + c1 -= ( 'a' - 'A' ); + } + if ( c2 >= 'a' && c2 <= 'z' ) { + c2 -= ( 'a' - 'A' ); + } + if ( c1 != c2 ) { + return -1; // strings not equal + } + } + } while ( c1 ); + + return 0; // strings are equal +} + +int Q_stricmp( const char *s1, const char *s2 ){ + return Q_strncasecmp( s1, s2, 99999 ); +} + +// NOTE TTimo when switching to Multithread DLL (Release/Debug) in the config +// started getting warnings about that function, prolly a duplicate with the runtime function +// maybe we still need to have it in linux builds +/* + char *strupr (char *start) + { + char *in; + in = start; + while (*in) + { + *in = toupper(*in); + in++; + } + return start; + } + */ + +char *strlower( char *start ){ + char *in; + in = start; + while ( *in ) + { + *in = tolower( *in ); + in++; + } + return start; +} + + +/* + ============================================================================= + + MISC FUNCTIONS + + ============================================================================= + */ + + +/* + ================= + CheckParm + + Checks for the given parameter in the program's command line arguments + Returns the argument number (1 to argc-1) or 0 if not present + ================= + */ +int CheckParm( const char *check ){ + int i; + + for ( i = 1; i < myargc; i++ ) + { + if ( !Q_stricmp( check, myargv[i] ) ) { + return i; + } + } + + return 0; +} + + + +/* + ================ + Q_filelength + ================ + */ +int Q_filelength( FILE *f ){ + int pos; + int end; + + pos = ftell( f ); + fseek( f, 0, SEEK_END ); + end = ftell( f ); + fseek( f, pos, SEEK_SET ); + + return end; +} + + +FILE *SafeOpenWrite( const char *filename ){ + FILE *f; + + f = fopen( filename, "wb" ); + + if ( !f ) { + Error( "Error opening %s: %s",filename,strerror( errno ) ); + } + + return f; +} + +FILE *SafeOpenRead( const char *filename ){ + FILE *f; + + f = fopen( filename, "rb" ); + + if ( !f ) { + Error( "Error opening %s: %s",filename,strerror( errno ) ); + } + + return f; +} + + +void SafeRead( FILE *f, void *buffer, int count ){ + if ( fread( buffer, 1, count, f ) != (size_t)count ) { + Error( "File read failure" ); + } +} + + +void SafeWrite( FILE *f, const void *buffer, int count ){ + if ( fwrite( buffer, 1, count, f ) != (size_t)count ) { + Error( "File write failure" ); + } +} + + +/* + ============== + FileExists + ============== + */ +qboolean FileExists( const char *filename ){ + FILE *f; + + f = fopen( filename, "r" ); + if ( !f ) { + return qfalse; + } + fclose( f ); + return qtrue; +} + +/* + ============== + LoadFile + ============== + */ +int LoadFile( const char *filename, void **bufferptr ){ + FILE *f; + int length; + void *buffer; + + f = SafeOpenRead( filename ); + length = Q_filelength( f ); + buffer = safe_malloc( length + 1 ); + ( (char *)buffer )[length] = 0; + SafeRead( f, buffer, length ); + fclose( f ); + + *bufferptr = buffer; + return length; +} + + +/* + ============== + LoadFileBlock + - + rounds up memory allocation to 4K boundry + - + ============== + */ +int LoadFileBlock( const char *filename, void **bufferptr ){ + FILE *f; + int length, nBlock, nAllocSize; + void *buffer; + + f = SafeOpenRead( filename ); + length = Q_filelength( f ); + nAllocSize = length; + nBlock = nAllocSize % MEM_BLOCKSIZE; + if ( nBlock > 0 ) { + nAllocSize += MEM_BLOCKSIZE - nBlock; + } + buffer = safe_malloc( nAllocSize + 1 ); + memset( buffer, 0, nAllocSize + 1 ); + SafeRead( f, buffer, length ); + fclose( f ); + + *bufferptr = buffer; + return length; +} + + +/* + ============== + TryLoadFile + + Allows failure + ============== + */ +int TryLoadFile( const char *filename, void **bufferptr ){ + FILE *f; + int length; + void *buffer; + + *bufferptr = NULL; + + f = fopen( filename, "rb" ); + if ( !f ) { + return -1; + } + length = Q_filelength( f ); + buffer = safe_malloc( length + 1 ); + ( (char *)buffer )[length] = 0; + SafeRead( f, buffer, length ); + fclose( f ); + + *bufferptr = buffer; + return length; +} + + +/* + ============== + SaveFile + ============== + */ +void SaveFile( const char *filename, const void *buffer, int count ){ + FILE *f; + + f = SafeOpenWrite( filename ); + SafeWrite( f, buffer, count ); + fclose( f ); +} + + + +void DefaultExtension( char *path, const char *extension ){ + char *src; +// +// if path doesnt have a .EXT, append extension +// (extension should include the .) +// + src = path + strlen( path ) - 1; + + while ( *src != '/' && *src != '\\' && src != path ) + { + if ( *src == '.' ) { + return; // it has an extension + } + src--; + } + + strcat( path, extension ); +} + + +void DefaultPath( char *path, const char *basepath ){ + char temp[128]; + + if ( path[ 0 ] == '/' || path[ 0 ] == '\\' ) { + return; // absolute path location + } + strcpy( temp,path ); + strcpy( path,basepath ); + strcat( path,temp ); +} + + +void StripFilename( char *path ){ + int length; + + length = strlen( path ) - 1; + while ( length > 0 && path[length] != '/' && path[ length ] != '\\' ) + length--; + path[length] = 0; +} + +void StripExtension( char *path ){ + int length; + + length = strlen( path ) - 1; + while ( length > 0 && path[length] != '.' ) + { + length--; + if ( path[length] == '/' || path[ length ] == '\\' ) { + return; // no extension + } + } + if ( length ) { + path[length] = 0; + } +} + + +/* + ==================== + Extract file parts + ==================== + */ +// FIXME: should include the slash, otherwise +// backing to an empty path will be wrong when appending a slash +void ExtractFilePath( const char *path, char *dest ){ + const char *src; + + src = path + strlen( path ) - 1; + +// +// back up until a \ or the start +// + while ( src != path && *( src - 1 ) != '\\' && *( src - 1 ) != '/' ) + src--; + + memcpy( dest, path, src - path ); + dest[src - path] = 0; +} + +void ExtractFileBase( const char *path, char *dest ){ + const char *src; + + src = path + strlen( path ) - 1; + +// +// back up until a \ or the start +// + while ( src != path && *( src - 1 ) != '/' && *( src - 1 ) != '\\' ) + src--; + + while ( *src && *src != '.' ) + { + *dest++ = *src++; + } + *dest = 0; +} + +void ExtractFileExtension( const char *path, char *dest ){ + const char *src; + + src = path + strlen( path ) - 1; + +// +// back up until a . or the start +// + while ( src != path && *( src - 1 ) != '.' ) + src--; + if ( src == path ) { + *dest = 0; // no extension + return; + } + + strcpy( dest,src ); +} + + +/* + ============== + ParseNum / ParseHex + ============== + */ +int ParseHex( const char *hex ){ + const char *str; + int num; + + num = 0; + str = hex; + + while ( *str ) + { + num <<= 4; + if ( *str >= '0' && *str <= '9' ) { + num += *str - '0'; + } + else if ( *str >= 'a' && *str <= 'f' ) { + num += 10 + *str - 'a'; + } + else if ( *str >= 'A' && *str <= 'F' ) { + num += 10 + *str - 'A'; + } + else{ + Error( "Bad hex number: %s",hex ); + } + str++; + } + + return num; +} + + +int ParseNum( const char *str ){ + if ( str[0] == '$' ) { + return ParseHex( str + 1 ); + } + if ( str[0] == '0' && str[1] == 'x' ) { + return ParseHex( str + 2 ); + } + return atol( str ); +} + + + +/* + ============================================================================ + + BYTE ORDER FUNCTIONS + + ============================================================================ + */ + +#ifdef _SGI_SOURCE +#define __BIG_ENDIAN__ +#endif + +#ifdef __BIG_ENDIAN__ + +short LittleShort( short l ){ + byte b1,b2; + + b1 = l & 255; + b2 = ( l >> 8 ) & 255; + + return ( b1 << 8 ) + b2; +} + +short BigShort( short l ){ + return l; +} + + +int LittleLong( int l ){ + byte b1,b2,b3,b4; + + b1 = l & 255; + b2 = ( l >> 8 ) & 255; + b3 = ( l >> 16 ) & 255; + b4 = ( l >> 24 ) & 255; + + return ( (int)b1 << 24 ) + ( (int)b2 << 16 ) + ( (int)b3 << 8 ) + b4; +} + +int BigLong( int l ){ + return l; +} + + +float LittleFloat( float l ){ + union {byte b[4]; float f; } in, out; + + in.f = l; + out.b[0] = in.b[3]; + out.b[1] = in.b[2]; + out.b[2] = in.b[1]; + out.b[3] = in.b[0]; + + return out.f; +} + +float BigFloat( float l ){ + return l; +} + + +#else + + +short BigShort( short l ){ + byte b1,b2; + + b1 = l & 255; + b2 = ( l >> 8 ) & 255; + + return ( b1 << 8 ) + b2; +} + +short LittleShort( short l ){ + return l; +} + + +int BigLong( int l ){ + byte b1,b2,b3,b4; + + b1 = l & 255; + b2 = ( l >> 8 ) & 255; + b3 = ( l >> 16 ) & 255; + b4 = ( l >> 24 ) & 255; + + return ( (int)b1 << 24 ) + ( (int)b2 << 16 ) + ( (int)b3 << 8 ) + b4; +} + +int LittleLong( int l ){ + return l; +} + +float BigFloat( float l ){ + union {byte b[4]; float f; } in, out; + + in.f = l; + out.b[0] = in.b[3]; + out.b[1] = in.b[2]; + out.b[2] = in.b[1]; + out.b[3] = in.b[0]; + + return out.f; +} + +float LittleFloat( float l ){ + return l; +} + + +#endif + + +//======================================================= + + +// FIXME: byte swap? + +// this is a 16 bit, non-reflected CRC using the polynomial 0x1021 +// and the initial and final xor values shown below... in other words, the +// CCITT standard CRC used by XMODEM + +#define CRC_INIT_VALUE 0xffff +#define CRC_XOR_VALUE 0x0000 + +static unsigned short crctable[256] = +{ + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 +}; + +void CRC_Init( unsigned short *crcvalue ){ + *crcvalue = CRC_INIT_VALUE; +} + +void CRC_ProcessByte( unsigned short *crcvalue, byte data ){ + *crcvalue = ( *crcvalue << 8 ) ^ crctable[( *crcvalue >> 8 ) ^ data]; +} + +unsigned short CRC_Value( unsigned short crcvalue ){ + return crcvalue ^ CRC_XOR_VALUE; +} +//============================================================================= + +/* + ============ + CreatePath + ============ + */ +void CreatePath( const char *path ){ + const char *ofs; + char c; + char dir[1024]; + +#ifdef _WIN32 + int olddrive = -1; + + if ( path[1] == ':' ) { + olddrive = _getdrive(); + _chdrive( toupper( path[0] ) - 'A' + 1 ); + } +#endif + + if ( path[1] == ':' ) { + path += 2; + } + + for ( ofs = path + 1 ; *ofs ; ofs++ ) + { + c = *ofs; + if ( c == '/' || c == '\\' ) { // create the directory + memcpy( dir, path, ofs - path ); + dir[ ofs - path ] = 0; + Q_mkdir( dir ); + } + } + +#ifdef _WIN32 + if ( olddrive != -1 ) { + _chdrive( olddrive ); + } +#endif +} + + +/* + ============ + QCopyFile + + Used to archive source files + ============ + */ +void QCopyFile( const char *from, const char *to ){ + void *buffer; + int length; + + length = LoadFile( from, &buffer ); + CreatePath( to ); + SaveFile( to, buffer, length ); + free( buffer ); +} + +void Sys_Sleep( int n ){ +#ifdef WIN32 + Sleep( n ); +#endif +#if defined ( __linux__ ) || defined ( __APPLE__ ) + usleep( n * 1000 ); +#endif +}