Author: rambetter
[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            last0[ 2 ];
113                 char            *home;
114                 char            *path;
115                 char            *last;
116                 qboolean        found;
117                 
118                 
119                 /* get home dir */
120                 home = LokiGetHomeDir();
121                 if( home == NULL )
122                         home = ".";
123                 
124                 /* do some path divining */
125                 strcpy( temp, argv0 );
126                 if( strrchr( argv0, '/' ) )
127                         argv0 = strrchr( argv0, '/' ) + 1;
128                 else
129                 {
130                         /* get path environment variable */
131                         path = getenv( "PATH" );
132                         
133                         /* minor setup */
134                         last = last0;
135                         last[ 0 ] = path[ 0 ];
136                         last[ 1 ] = '\0';
137                         found = qfalse;
138                         
139                         /* go through each : segment of path */
140                         while( last[ 0 ] != '\0' && found == qfalse )
141                         {
142                                 /* null out temp */
143                                 temp[ 0 ] = '\0';
144                                 
145                                 /* find next chunk */
146                                 last = strchr( path, ':' );
147                                 if( last == NULL )
148                                         last = path + strlen( path );
149                                 
150                                 /* found home dir candidate */
151                                 if( *path == '~' )
152                                 {
153                                         strcpy( temp, home );
154                                         path++;
155                                 }
156                                 
157                                 /* concatenate */
158                                 if( last > (path + 1) )
159                                 {
160                                         strncat( temp, path, (last - path) );
161                                         strcat( temp, "/" );
162                                 }
163                                 strcat( temp, "./" );
164                                 strcat( temp, argv0 );
165                                 
166                                 /* verify the path */
167                                 if( access( temp, X_OK ) == 0 )
168                                         found++;
169                                 path = last + 1;
170                         }
171                 }
172                 
173                 /* flake */
174                 if( realpath( temp, installPath ) )
175                 {
176                         /* q3map is in "tools/" */
177                         *(strrchr( installPath, '/' )) = '\0';
178                         *(strrchr( installPath, '/' ) + 1) = '\0';
179                 }
180                 
181                 /* set home path */
182                 homePath = home;
183         #endif
184 }
185
186
187
188 /*
189 CleanPath() - ydnar
190 cleans a dos path \ -> /
191 */
192
193 void CleanPath( char *path )
194 {
195         while( *path )
196         {
197                 if( *path == '\\' )
198                         *path = '/';
199                 path++;
200         }
201 }
202
203
204
205 /*
206 GetGame() - ydnar
207 gets the game_t based on a -game argument
208 returns NULL if no match found
209 */
210
211 game_t *GetGame( char *arg )
212 {
213         int     i;
214         
215         
216         /* dummy check */
217         if( arg == NULL || arg[ 0 ] == '\0' )
218                 return NULL;
219         
220         /* joke */
221         if( !Q_stricmp( arg, "quake1" ) ||
222                 !Q_stricmp( arg, "quake2" ) ||
223                 !Q_stricmp( arg, "unreal" ) ||
224                 !Q_stricmp( arg, "ut2k3" ) ||
225                 !Q_stricmp( arg, "dn3d" ) ||
226                 !Q_stricmp( arg, "dnf" ) ||
227                 !Q_stricmp( arg, "hl" ) )
228         {
229                 Sys_Printf( "April fools, silly rabbit!\n" );
230                 exit( 0 );
231         }
232         
233         /* test it */
234         i = 0;
235         while( games[ i ].arg != NULL )
236         {
237                 if( Q_stricmp( arg, games[ i ].arg ) == 0 )
238                         return &games[ i ];
239                 i++;
240         }
241         
242         /* no matching game */
243         return NULL;
244 }
245
246
247
248 /*
249 AddBasePath() - ydnar
250 adds a base path to the list
251 */
252
253 void AddBasePath( char *path )
254 {
255         /* dummy check */
256         if( path == NULL || path[ 0 ] == '\0' || numBasePaths >= MAX_BASE_PATHS )
257                 return;
258         
259         /* add it to the list */
260         basePaths[ numBasePaths ] = safe_malloc( strlen( path ) + 1 );
261         strcpy( basePaths[ numBasePaths ], path );
262         CleanPath( basePaths[ numBasePaths ] );
263         numBasePaths++;
264 }
265
266
267
268 /*
269 AddHomeBasePath() - ydnar
270 adds a base path to the beginning of the list, prefixed by ~/
271 */
272
273 void AddHomeBasePath( char *path )
274 {
275         #ifdef Q_UNIX
276                 int             i;
277                 char    temp[ MAX_OS_PATH ];
278                 
279                 
280                 /* dummy check */
281                 if( path == NULL || path[ 0 ] == '\0' )
282                         return;
283
284                 /* make a hole */
285                 for( i = (MAX_BASE_PATHS - 2); i >= 0; i-- )
286                         basePaths[ i + 1 ] = basePaths[ i ];
287                 
288                 /* concatenate home dir and path */
289                 sprintf( temp, "%s/%s", homePath, path );
290                 
291                 /* add it to the list */
292                 basePaths[ 0 ] = safe_malloc( strlen( temp ) + 1 );
293                 strcpy( basePaths[ 0 ], temp );
294                 CleanPath( basePaths[ 0 ] );
295                 numBasePaths++;
296         #endif
297 }
298
299
300
301 /*
302 AddGamePath() - ydnar
303 adds a game path to the list
304 */
305
306 void AddGamePath( char *path )
307 {
308         /* dummy check */
309         if( path == NULL || path[ 0 ] == '\0' || numGamePaths >= MAX_GAME_PATHS )
310                 return;
311         
312         /* add it to the list */
313         gamePaths[ numGamePaths ] = safe_malloc( strlen( path ) + 1 );
314         strcpy( gamePaths[ numGamePaths ], path );
315         CleanPath( gamePaths[ numGamePaths ] );
316         numGamePaths++;
317 }
318
319
320
321
322 /*
323 InitPaths() - ydnar
324 cleaned up some of the path initialization code from bsp.c
325 will remove any arguments it uses
326 */
327
328 void InitPaths( int *argc, char **argv )
329 {
330         int             i, j, k, len, len2;
331         char    temp[ MAX_OS_PATH ];
332         
333         
334         /* note it */
335         Sys_FPrintf( SYS_VRB, "--- InitPaths ---\n" );
336         
337         /* get the install path for backup */
338         LokiInitPaths( argv[ 0 ] );
339         
340         /* set game to default (q3a) */
341         game = &games[ 0 ];
342         numBasePaths = 0;
343         numGamePaths = 0;
344         
345         /* parse through the arguments and extract those relevant to paths */
346         for( i = 0; i < *argc; i++ )
347         {
348                 /* check for null */
349                 if( argv[ i ] == NULL )
350                         continue;
351                 
352                 /* -game */
353                 if( strcmp( argv[ i ], "-game" ) == 0 )
354                 {
355                         if( ++i >= *argc )
356                                 Error( "Out of arguments: No game specified after %s", argv[ i - 1 ] );
357                         argv[ i - 1 ] = NULL;
358                         game = GetGame( argv[ i ] );
359                         if( game == NULL )
360                                 game = &games[ 0 ];
361                         argv[ i ] = NULL;
362                 }
363
364                 /* -fs_forbiddenpath */
365                 else if( strcmp( argv[ i ], "-fs_forbiddenpath" ) == 0 )
366                 {
367                         if( ++i >= *argc )
368                                 Error( "Out of arguments: No path specified after %s.", argv[ i - 1 ] );
369                         argv[ i - 1 ] = NULL;
370                         if(g_numForbiddenDirs < VFS_MAXDIRS)
371                         {
372                                 strncpy(g_strForbiddenDirs[g_numForbiddenDirs], argv[i], PATH_MAX);
373                                 g_strForbiddenDirs[g_numForbiddenDirs][PATH_MAX] = 0;
374                                 ++g_numForbiddenDirs;
375                         }
376                         argv[ i ] = NULL;
377                 }
378
379                 /* -fs_basepath */
380                 else if( strcmp( argv[ i ], "-fs_basepath" ) == 0 )
381                 {
382                         if( ++i >= *argc )
383                                 Error( "Out of arguments: No path specified after %s.", argv[ i - 1 ] );
384                         argv[ i - 1 ] = NULL;
385                         AddBasePath( argv[ i ] );
386                         argv[ i ] = NULL;
387                 }
388                 
389                 /* -fs_game */
390                 else if( strcmp( argv[ i ], "-fs_game" ) == 0 )
391                 {
392                         if( ++i >= *argc )
393                                 Error( "Out of arguments: No path specified after %s.", argv[ i - 1 ] );
394                         argv[ i - 1 ] = NULL;
395                         AddGamePath( argv[ i ] );
396                         argv[ i ] = NULL;
397                 }
398                 
399                 /* -fs_nohomebase */
400                 else if( strcmp( argv[ i ], "-fs_homebase" ) == 0 )
401                 {
402                         if( ++i >= *argc )
403                                 Error( "Out of arguments: No path specified after %s.", argv[ i - 1 ] );
404                         argv[ i - 1 ] = NULL;
405                         homeBasePath = argv[i];
406                         argv[ i ] = NULL;
407                 }
408         }
409         
410         /* remove processed arguments */
411         for( i = 0, j = 0, k = 0; i < *argc && j < *argc; i++, j++ )
412         {
413                 for( ; j < *argc && argv[ j ] == NULL; j++ );
414                 argv[ i ] = argv[ j ];
415                 if( argv[ i ] != NULL )
416                         k++;
417         }
418         *argc = k;
419         
420         /* add standard game path */
421         AddGamePath( game->gamePath );
422         
423         /* if there is no base path set, figure it out */
424         if( numBasePaths == 0 )
425         {
426                 /* this is another crappy replacement for SetQdirFromPath() */
427                 len2 = strlen( game->magic );
428                 for( i = 0; i < *argc && numBasePaths == 0; i++ )
429                 {
430                         /* extract the arg */
431                         strcpy( temp, argv[ i ] );
432                         CleanPath( temp );
433                         len = strlen( temp );
434                         Sys_FPrintf( SYS_VRB, "Searching for \"%s\" in \"%s\" (%d)...\n", game->magic, temp, i );
435                         
436                         /* this is slow, but only done once */
437                         for( j = 0; j < (len - len2); j++ )
438                         {
439                                 /* check for the game's magic word */
440                                 if( Q_strncasecmp( &temp[ j ], game->magic, len2 ) == 0 )
441                                 {
442                                         /* now find the next slash and nuke everything after it */
443                                         while( temp[ ++j ] != '/' && temp[ j ] != '\0' );
444                                         temp[ j ] = '\0';
445                                         
446                                         /* add this as a base path */
447                                         AddBasePath( temp );
448                                         break;
449                                 }
450                         }
451                 }
452                 
453                 /* add install path */
454                 if( numBasePaths == 0 )
455                         AddBasePath( installPath );
456                 
457                 /* check again */
458                 if( numBasePaths == 0 )
459                         Error( "Failed to find a valid base path." );
460         }
461         
462         /* this only affects unix */
463         if(homeBasePath)
464                 AddHomeBasePath( homeBasePath );
465         else
466                 AddHomeBasePath( game->homeBasePath );
467         
468         /* initialize vfs paths */
469         if( numBasePaths > MAX_BASE_PATHS )
470                 numBasePaths = MAX_BASE_PATHS;
471         if( numGamePaths > MAX_GAME_PATHS )
472                 numGamePaths = MAX_GAME_PATHS;
473         
474         /* walk the list of game paths */
475         for( j = 0; j < numGamePaths; j++ )
476         {
477                 /* walk the list of base paths */
478                 for( i = 0; i < numBasePaths; i++ )
479                 {
480                         /* create a full path and initialize it */
481                         sprintf( temp, "%s/%s/", basePaths[ i ], gamePaths[ j ] );
482                         vfsInitDirectory( temp );
483                 }
484         }
485         
486         /* done */
487         Sys_Printf( "\n" );
488 }
489
490
491
492