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