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