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