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