vfspk3 in q3map2: also support -fs_forbiddenpath
[divverent/netradiant.git] / tools / quake3 / q3map2 / path_init.c
1 /* -------------------------------------------------------------------------------
2
3 Copyright (C) 1999-2007 id Software, Inc. and contributors.
4 For a list of contributors, see the accompanying CONTRIBUTORS file.
5
6 This file is part of GtkRadiant.
7
8 GtkRadiant is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 GtkRadiant is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GtkRadiant; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21
22 ----------------------------------------------------------------------------------
23
24 This code has been altered significantly from its original form, to support
25 several games based on the Quake III Arena engine, in the form of "Q3Map2."
26
27 ------------------------------------------------------------------------------- */
28
29
30
31 /* marker */
32 #define PATH_INIT_C
33
34
35
36 /* dependencies */
37 #include "q3map2.h"
38
39
40
41 /* path support */
42 #define MAX_BASE_PATHS  10
43 #define MAX_GAME_PATHS  10
44
45 char                                    *homePath;
46 char                                    installPath[ MAX_OS_PATH ];
47
48 int                                             numBasePaths;
49 char                                    *basePaths[ MAX_BASE_PATHS ];
50 int                                             numGamePaths;
51 char                                    *gamePaths[ MAX_GAME_PATHS ];
52 char                                    *homeBasePath = NULL;
53
54
55 /*
56 some of this code is based off the original q3map port from loki
57 and finds various paths. moved here from bsp.c for clarity.
58 */
59
60 /*
61 PathLokiGetHomeDir()
62 gets the user's home dir (for ~/.q3a)
63 */
64
65 char *LokiGetHomeDir( void )
66 {
67         #ifndef Q_UNIX
68                 return NULL;
69         #else
70                 char                    *home;
71                 uid_t                   id;
72                 struct passwd   *pwd;
73                 
74                 
75                 /* get the home environment variable */
76                 home = getenv( "HOME" );
77                 if( home == NULL )
78                 {
79                         /* do some more digging */
80                         id = getuid();
81                         setpwent();
82                         while( (pwd = getpwent()) != NULL )
83                         {
84                                 if( pwd->pw_uid == id )
85                                 {
86                                         home = pwd->pw_dir;
87                                         break;
88                                 }
89                         }
90                         endpwent();
91                 }
92                 
93                 /* return it */
94                 return home;
95         #endif
96 }
97
98
99
100 /*
101 PathLokiInitPaths()
102 initializes some paths on linux/os x
103 */
104
105 void LokiInitPaths( char *argv0 )
106 {
107         #ifndef Q_UNIX
108                 /* this is kinda crap, but hey */
109                 strcpy( installPath, "../" );
110         #else
111                 char            temp[ MAX_OS_PATH ];
112                 char            *home;
113                 char            *path;
114                 char            *last;
115                 qboolean        found;
116                 
117                 
118                 /* get home dir */
119                 home = LokiGetHomeDir();
120                 if( home == NULL )
121                         home = ".";
122                 
123                 /* do some path divining */
124                 strcpy( temp, argv0 );
125                 if( strrchr( temp, '/' ) )
126                         argv0 = strrchr( argv0, '/' ) + 1;
127                 else
128                 {
129                         /* get path environment variable */
130                         path = getenv( "PATH" );
131                         
132                         /* minor setup */
133                         last[ 0 ] = path[ 0 ];
134                         last[ 1 ] = '\0';
135                         found = qfalse;
136                         
137                         /* go through each : segment of path */
138                         while( last[ 0 ] != '\0' && found == qfalse )
139                         {
140                                 /* null out temp */
141                                 temp[ 0 ] = '\0';
142                                 
143                                 /* find next chunk */
144                                 last = strchr( path, ':' );
145                                 if( last == NULL )
146                                         last = path + strlen( path );
147                                 
148                                 /* found home dir candidate */
149                                 if( *path == '~' )
150                                 {
151                                         strcpy( temp, home );
152                                         path++;
153                                 }
154                                 
155                                 /* concatenate */
156                                 if( last > (path + 1) )
157                                 {
158                                         strncat( temp, path, (last - path) );
159                                         strcat( temp, "/" );
160                                 }
161                                 strcat( temp, "./" );
162                                 strcat( temp, argv0 );
163                                 
164                                 /* verify the path */
165                                 if( access( temp, X_OK ) == 0 )
166                                         found++;
167                                 path = last + 1;
168                         }
169                 }
170                 
171                 /* flake */
172                 if( realpath( temp, installPath ) )
173                 {
174                         /* q3map is in "tools/" */
175                         *(strrchr( installPath, '/' )) = '\0';
176                         *(strrchr( installPath, '/' ) + 1) = '\0';
177                 }
178                 
179                 /* set home path */
180                 homePath = home;
181         #endif
182 }
183
184
185
186 /*
187 CleanPath() - ydnar
188 cleans a dos path \ -> /
189 */
190
191 void CleanPath( char *path )
192 {
193         while( *path )
194         {
195                 if( *path == '\\' )
196                         *path = '/';
197                 path++;
198         }
199 }
200
201
202
203 /*
204 GetGame() - ydnar
205 gets the game_t based on a -game argument
206 returns NULL if no match found
207 */
208
209 game_t *GetGame( char *arg )
210 {
211         int     i;
212         
213         
214         /* dummy check */
215         if( arg == NULL || arg[ 0 ] == '\0' )
216                 return NULL;
217         
218         /* joke */
219         if( !Q_stricmp( arg, "quake1" ) ||
220                 !Q_stricmp( arg, "quake2" ) ||
221                 !Q_stricmp( arg, "unreal" ) ||
222                 !Q_stricmp( arg, "ut2k3" ) ||
223                 !Q_stricmp( arg, "dn3d" ) ||
224                 !Q_stricmp( arg, "dnf" ) ||
225                 !Q_stricmp( arg, "hl" ) )
226         {
227                 Sys_Printf( "April fools, silly rabbit!\n" );
228                 exit( 0 );
229         }
230         
231         /* test it */
232         i = 0;
233         while( games[ i ].arg != NULL )
234         {
235                 if( Q_stricmp( arg, games[ i ].arg ) == 0 )
236                         return &games[ i ];
237                 i++;
238         }
239         
240         /* no matching game */
241         return NULL;
242 }
243
244
245
246 /*
247 AddBasePath() - ydnar
248 adds a base path to the list
249 */
250
251 void AddBasePath( char *path )
252 {
253         /* dummy check */
254         if( path == NULL || path[ 0 ] == '\0' || numBasePaths >= MAX_BASE_PATHS )
255                 return;
256         
257         /* add it to the list */
258         basePaths[ numBasePaths ] = safe_malloc( strlen( path ) + 1 );
259         strcpy( basePaths[ numBasePaths ], path );
260         CleanPath( basePaths[ numBasePaths ] );
261         numBasePaths++;
262 }
263
264
265
266 /*
267 AddHomeBasePath() - ydnar
268 adds a base path to the beginning of the list, prefixed by ~/
269 */
270
271 void AddHomeBasePath( char *path )
272 {
273         #ifdef Q_UNIX
274                 int             i;
275                 char    temp[ MAX_OS_PATH ];
276                 
277                 
278                 /* dummy check */
279                 if( path == NULL || path[ 0 ] == '\0' )
280                         return;
281
282                 /* make a hole */
283                 for( i = (MAX_BASE_PATHS - 2); i >= 0; i-- )
284                         basePaths[ i + 1 ] = basePaths[ i ];
285                 
286                 /* concatenate home dir and path */
287                 sprintf( temp, "%s/%s", homePath, path );
288                 
289                 /* add it to the list */
290                 basePaths[ 0 ] = safe_malloc( strlen( temp ) + 1 );
291                 strcpy( basePaths[ 0 ], temp );
292                 CleanPath( basePaths[ 0 ] );
293                 numBasePaths++;
294         #endif
295 }
296
297
298
299 /*
300 AddGamePath() - ydnar
301 adds a game path to the list
302 */
303
304 void AddGamePath( char *path )
305 {
306         /* dummy check */
307         if( path == NULL || path[ 0 ] == '\0' || numGamePaths >= MAX_GAME_PATHS )
308                 return;
309         
310         /* add it to the list */
311         gamePaths[ numGamePaths ] = safe_malloc( strlen( path ) + 1 );
312         strcpy( gamePaths[ numGamePaths ], path );
313         CleanPath( gamePaths[ numGamePaths ] );
314         numGamePaths++;
315 }
316
317
318
319
320 /*
321 InitPaths() - ydnar
322 cleaned up some of the path initialization code from bsp.c
323 will remove any arguments it uses
324 */
325
326 void InitPaths( int *argc, char **argv )
327 {
328         int             i, j, k, len, len2;
329         char    temp[ MAX_OS_PATH ];
330         
331         
332         /* note it */
333         Sys_FPrintf( SYS_VRB, "--- InitPaths ---\n" );
334         
335         /* get the install path for backup */
336         LokiInitPaths( argv[ 0 ] );
337         
338         /* set game to default (q3a) */
339         game = &games[ 0 ];
340         numBasePaths = 0;
341         numGamePaths = 0;
342         
343         /* parse through the arguments and extract those relevant to paths */
344         for( i = 0; i < *argc; i++ )
345         {
346                 /* check for null */
347                 if( argv[ i ] == NULL )
348                         continue;
349                 
350                 /* -game */
351                 if( strcmp( argv[ i ], "-game" ) == 0 )
352                 {
353                         if( ++i >= *argc )
354                                 Error( "Out of arguments: No game specified after %s", argv[ i - 1 ] );
355                         argv[ i - 1 ] = NULL;
356                         game = GetGame( argv[ i ] );
357                         if( game == NULL )
358                                 game = &games[ 0 ];
359                         argv[ i ] = NULL;
360                 }
361
362                 /* -fs_forbiddenpath */
363                 else if( strcmp( argv[ i ], "-fs_forbiddenpath" ) == 0 )
364                 {
365                         if( ++i >= *argc )
366                                 Error( "Out of arguments: No path specified after %s.", argv[ i - 1 ] );
367                         argv[ i - 1 ] = NULL;
368                         if(g_numForbiddenDirs < VFS_MAXDIRS)
369                         {
370                                 strncpy(g_strForbiddenDirs[g_numForbiddenDirs], argv[i], PATH_MAX);
371                                 g_strForbiddenDirs[g_numForbiddenDirs][PATH_MAX] = 0;
372                                 ++g_numForbiddenDirs;
373                         }
374                         argv[ i ] = NULL;
375                 }
376
377                 /* -fs_basepath */
378                 else if( strcmp( argv[ i ], "-fs_basepath" ) == 0 )
379                 {
380                         if( ++i >= *argc )
381                                 Error( "Out of arguments: No path specified after %s.", argv[ i - 1 ] );
382                         argv[ i - 1 ] = NULL;
383                         AddBasePath( argv[ i ] );
384                         argv[ i ] = NULL;
385                 }
386                 
387                 /* -fs_game */
388                 else if( strcmp( argv[ i ], "-fs_game" ) == 0 )
389                 {
390                         if( ++i >= *argc )
391                                 Error( "Out of arguments: No path specified after %s.", argv[ i - 1 ] );
392                         argv[ i - 1 ] = NULL;
393                         AddGamePath( argv[ i ] );
394                         argv[ i ] = NULL;
395                 }
396                 
397                 /* -fs_nohomebase */
398                 else if( strcmp( argv[ i ], "-fs_homebase" ) == 0 )
399                 {
400                         if( ++i >= *argc )
401                                 Error( "Out of arguments: No path specified after %s.", argv[ i - 1 ] );
402                         argv[ i - 1 ] = NULL;
403                         homeBasePath = argv[i];
404                         argv[ i ] = NULL;
405                 }
406         }
407         
408         /* remove processed arguments */
409         for( i = 0, j = 0, k = 0; i < *argc && j < *argc; i++, j++ )
410         {
411                 for( ; j < *argc && argv[ j ] == NULL; j++ );
412                 argv[ i ] = argv[ j ];
413                 if( argv[ i ] != NULL )
414                         k++;
415         }
416         *argc = k;
417         
418         /* add standard game path */
419         AddGamePath( game->gamePath );
420         
421         /* if there is no base path set, figure it out */
422         if( numBasePaths == 0 )
423         {
424                 /* this is another crappy replacement for SetQdirFromPath() */
425                 len2 = strlen( game->magic );
426                 for( i = 0; i < *argc && numBasePaths == 0; i++ )
427                 {
428                         /* extract the arg */
429                         strcpy( temp, argv[ i ] );
430                         CleanPath( temp );
431                         len = strlen( temp );
432                         Sys_FPrintf( SYS_VRB, "Searching for \"%s\" in \"%s\" (%d)...\n", game->magic, temp, i );
433                         
434                         /* this is slow, but only done once */
435                         for( j = 0; j < (len - len2); j++ )
436                         {
437                                 /* check for the game's magic word */
438                                 if( Q_strncasecmp( &temp[ j ], game->magic, len2 ) == 0 )
439                                 {
440                                         /* now find the next slash and nuke everything after it */
441                                         while( temp[ ++j ] != '/' && temp[ j ] != '\0' );
442                                         temp[ j ] = '\0';
443                                         
444                                         /* add this as a base path */
445                                         AddBasePath( temp );
446                                         break;
447                                 }
448                         }
449                 }
450                 
451                 /* add install path */
452                 if( numBasePaths == 0 )
453                         AddBasePath( installPath );
454                 
455                 /* check again */
456                 if( numBasePaths == 0 )
457                         Error( "Failed to find a valid base path." );
458         }
459         
460         /* this only affects unix */
461         if(homeBasePath)
462                 AddHomeBasePath( homeBasePath );
463         else
464                 AddHomeBasePath( game->homeBasePath );
465         
466         /* initialize vfs paths */
467         if( numBasePaths > MAX_BASE_PATHS )
468                 numBasePaths = MAX_BASE_PATHS;
469         if( numGamePaths > MAX_GAME_PATHS )
470                 numGamePaths = MAX_GAME_PATHS;
471         
472         /* walk the list of game paths */
473         for( j = 0; j < numGamePaths; j++ )
474         {
475                 /* walk the list of base paths */
476                 for( i = 0; i < numBasePaths; i++ )
477                 {
478                         /* create a full path and initialize it */
479                         sprintf( temp, "%s/%s/", basePaths[ i ], gamePaths[ j ] );
480                         vfsInitDirectory( temp );
481                 }
482         }
483         
484         /* done */
485         Sys_Printf( "\n" );
486 }
487
488
489
490