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