1 /* -------------------------------------------------------------------------------
3 Copyright (C) 1999-2007 id Software, Inc. and contributors.
4 For a list of contributors, see the accompanying CONTRIBUTORS file.
6 This file is part of GtkRadiant.
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.
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.
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
22 ----------------------------------------------------------------------------------
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."
27 ------------------------------------------------------------------------------- */
42 #define MAX_BASE_PATHS 10
43 #define MAX_GAME_PATHS 10
44 #define MAX_PAK_PATHS 200
47 char installPath[ MAX_OS_PATH ];
50 char *basePaths[ MAX_BASE_PATHS ];
52 char *gamePaths[ MAX_GAME_PATHS ];
54 char *pakPaths[ MAX_PAK_PATHS ];
55 char *homeBasePath = NULL;
59 some of this code is based off the original q3map port from loki
60 and finds various paths. moved here from bsp.c for clarity.
65 gets the user's home dir (for ~/.q3a)
68 char *LokiGetHomeDir( void ){
72 static char buf[ 4096 ];
73 struct passwd pw, *pwp;
75 static char homeBuf[MAX_OS_PATH];
78 /* get the home environment variable */
79 home = getenv( "HOME" );
81 /* look up home dir in password database */
84 if ( getpwuid_r( getuid(), &pw, buf, sizeof( buf ), &pwp ) == 0 ) {
89 snprintf( homeBuf, sizeof( homeBuf ), "%s/.", home );
100 initializes some paths on linux/os x
103 void LokiInitPaths( char *argv0 ){
108 home = LokiGetHomeDir();
109 if ( home == NULL ) {
121 /* this is kinda crap, but hey */
122 strcpy( installPath, "../" );
124 char temp[ MAX_OS_PATH ];
131 path = getenv( "PATH" );
133 /* do some path divining */
134 Q_strncpyz( temp, argv0, sizeof( temp ) );
135 if ( strrchr( temp, '/' ) ) {
136 argv0 = strrchr( argv0, '/' ) + 1;
142 /* go through each : segment of path */
143 while ( last[ 0 ] != '\0' && found == qfalse )
148 /* find next chunk */
149 last = strchr( path, ':' );
150 if ( last == NULL ) {
151 last = path + strlen( path );
154 /* found home dir candidate */
155 if ( *path == '~' ) {
156 Q_strncpyz( temp, home, sizeof( temp ) );
161 if ( last > ( path + 1 ) ) {
162 Q_strncat( temp, sizeof( temp ), path, ( last - path ) );
163 Q_strcat( temp, sizeof( temp ), "/" );
165 Q_strcat( temp, sizeof( temp ), "./" );
166 Q_strcat( temp, sizeof( temp ), argv0 );
168 /* verify the path */
169 if ( access( temp, X_OK ) == 0 ) {
177 if ( realpath( temp, installPath ) ) {
178 /* q3map is in "tools/" */
179 *( strrchr( installPath, '/' ) ) = '\0';
180 *( strrchr( installPath, '/' ) + 1 ) = '\0';
189 cleans a dos path \ -> /
192 void CleanPath( char *path ){
195 if ( *path == '\\' ) {
206 gets the game_t based on a -game argument
207 returns NULL if no match found
210 game_t *GetGame( char *arg ){
215 if ( arg == NULL || arg[ 0 ] == '\0' ) {
220 if ( !Q_stricmp( arg, "quake1" ) ||
221 !Q_stricmp( arg, "quake2" ) ||
222 !Q_stricmp( arg, "unreal" ) ||
223 !Q_stricmp( arg, "ut2k3" ) ||
224 !Q_stricmp( arg, "dn3d" ) ||
225 !Q_stricmp( arg, "dnf" ) ||
226 !Q_stricmp( arg, "hl" ) ) {
227 Sys_Printf( "April fools, silly rabbit!\n" );
233 while ( games[ i ].arg != NULL )
235 if ( Q_stricmp( arg, games[ i ].arg ) == 0 ) {
241 /* no matching game */
248 AddBasePath() - ydnar
249 adds a base path to the list
252 void AddBasePath( char *path ){
254 if ( path == NULL || path[ 0 ] == '\0' || numBasePaths >= MAX_BASE_PATHS ) {
258 /* add it to the list */
259 basePaths[ numBasePaths ] = safe_malloc( strlen( path ) + 1 );
260 strcpy( basePaths[ numBasePaths ], path );
261 CleanPath( basePaths[ numBasePaths ] );
268 AddHomeBasePath() - ydnar
269 adds a base path to the beginning of the list, prefixed by ~/
272 void AddHomeBasePath( char *path ){
274 char temp[ MAX_OS_PATH ];
282 if ( path == NULL || path[ 0 ] == '\0' ) {
286 /* strip leading dot, if homePath does not end in /. */
287 homePathLen = strlen( homePath );
288 if ( !strcmp( path, "." ) ) {
289 /* -fs_homebase . means that -fs_home is to be used as is */
290 strcpy( temp, homePath );
292 else if ( homePathLen >= 2 && !strcmp( homePath + homePathLen - 2, "/." ) ) {
293 /* remove trailing /. of homePath */
296 /* concatenate home dir and path */
297 sprintf( temp, "%.*s/%s", homePathLen, homePath, path );
301 /* remove leading . of path */
302 if ( path[0] == '.' ) {
306 /* concatenate home dir and path */
307 sprintf( temp, "%s/%s", homePath, path );
311 for ( i = ( MAX_BASE_PATHS - 2 ); i >= 0; i-- )
312 basePaths[ i + 1 ] = basePaths[ i ];
314 /* add it to the list */
315 basePaths[ 0 ] = safe_malloc( strlen( temp ) + 1 );
316 strcpy( basePaths[ 0 ], temp );
317 CleanPath( basePaths[ 0 ] );
324 AddGamePath() - ydnar
325 adds a game path to the list
328 void AddGamePath( char *path ){
332 if ( path == NULL || path[ 0 ] == '\0' || numGamePaths >= MAX_GAME_PATHS ) {
336 /* add it to the list */
337 gamePaths[ numGamePaths ] = safe_malloc( strlen( path ) + 1 );
338 strcpy( gamePaths[ numGamePaths ], path );
339 CleanPath( gamePaths[ numGamePaths ] );
342 /* don't add it if it's already there */
343 for ( i = 0; i < numGamePaths - 1; i++ )
345 if ( strcmp( gamePaths[i], gamePaths[numGamePaths - 1] ) == 0 ) {
346 free( gamePaths[numGamePaths - 1] );
347 gamePaths[numGamePaths - 1] = NULL;
358 adds a pak path to the list
361 void AddPakPath( char *path ){
363 if ( path == NULL || path[ 0 ] == '\0' || numPakPaths >= MAX_PAK_PATHS ) {
367 /* add it to the list */
368 pakPaths[ numPakPaths ] = safe_malloc( strlen( path ) + 1 );
369 strcpy( pakPaths[ numPakPaths ], path );
370 CleanPath( pakPaths[ numPakPaths ] );
378 cleaned up some of the path initialization code from bsp.c
379 will remove any arguments it uses
382 void InitPaths( int *argc, char **argv ){
383 int i, j, k, len, len2;
384 char temp[ MAX_OS_PATH ];
388 Sys_FPrintf( SYS_VRB, "--- InitPaths ---\n" );
390 /* get the install path for backup */
391 LokiInitPaths( argv[ 0 ] );
393 /* set game to default (q3a) */
398 /* parse through the arguments and extract those relevant to paths */
399 for ( i = 0; i < *argc; i++ )
402 if ( argv[ i ] == NULL ) {
407 if ( strcmp( argv[ i ], "-game" ) == 0 ) {
408 if ( ++i >= *argc ) {
409 Error( "Out of arguments: No game specified after %s", argv[ i - 1 ] );
411 argv[ i - 1 ] = NULL;
412 game = GetGame( argv[ i ] );
413 if ( game == NULL ) {
419 /* -fs_forbiddenpath */
420 else if ( strcmp( argv[ i ], "-fs_forbiddenpath" ) == 0 ) {
421 if ( ++i >= *argc ) {
422 Error( "Out of arguments: No path specified after %s.", argv[ i - 1 ] );
424 argv[ i - 1 ] = NULL;
425 if ( g_numForbiddenDirs < VFS_MAXDIRS ) {
426 strncpy( g_strForbiddenDirs[g_numForbiddenDirs], argv[i], PATH_MAX );
427 g_strForbiddenDirs[g_numForbiddenDirs][PATH_MAX] = 0;
428 ++g_numForbiddenDirs;
434 else if ( strcmp( argv[ i ], "-fs_basepath" ) == 0 ) {
435 if ( ++i >= *argc ) {
436 Error( "Out of arguments: No path specified after %s.", argv[ i - 1 ] );
438 argv[ i - 1 ] = NULL;
439 AddBasePath( argv[ i ] );
444 else if ( strcmp( argv[ i ], "-fs_game" ) == 0 ) {
445 if ( ++i >= *argc ) {
446 Error( "Out of arguments: No path specified after %s.", argv[ i - 1 ] );
448 argv[ i - 1 ] = NULL;
449 AddGamePath( argv[ i ] );
454 else if ( strcmp( argv[ i ], "-fs_home" ) == 0 ) {
455 if ( ++i >= *argc ) {
456 Error( "Out of arguments: No path specified after %s.", argv[ i - 1 ] );
458 argv[ i - 1 ] = NULL;
464 else if ( strcmp( argv[ i ], "-fs_homebase" ) == 0 ) {
465 if ( ++i >= *argc ) {
466 Error( "Out of arguments: No path specified after %s.", argv[ i - 1 ] );
468 argv[ i - 1 ] = NULL;
469 homeBasePath = argv[i];
473 /* -fs_homepath - sets both of them */
474 else if ( strcmp( argv[ i ], "-fs_homepath" ) == 0 ) {
475 if ( ++i >= *argc ) {
476 Error( "Out of arguments: No path specified after %s.", argv[ i - 1 ] );
478 argv[ i - 1 ] = NULL;
485 else if ( strcmp( argv[ i ], "-fs_pakpath" ) == 0 ) {
486 if ( ++i >= *argc ) {
487 Error( "Out of arguments: No path specified after %s.", argv[ i - 1 ] );
489 argv[ i - 1 ] = NULL;
490 AddPakPath( argv[ i ] );
496 /* remove processed arguments */
497 for ( i = 0, j = 0, k = 0; i < *argc && j < *argc; i++, j++ )
499 for ( ; j < *argc && argv[ j ] == NULL; j++ ) ;
500 argv[ i ] = argv[ j ];
501 if ( argv[ i ] != NULL ) {
507 /* add standard game path */
508 AddGamePath( game->gamePath );
510 /* if there is no base path set, figure it out */
511 if ( numBasePaths == 0 ) {
512 /* this is another crappy replacement for SetQdirFromPath() */
513 len2 = strlen( game->magic );
514 for ( i = 0; i < *argc && numBasePaths == 0; i++ )
516 /* extract the arg */
517 strcpy( temp, argv[ i ] );
519 len = strlen( temp );
520 Sys_FPrintf( SYS_VRB, "Searching for \"%s\" in \"%s\" (%d)...\n", game->magic, temp, i );
522 /* this is slow, but only done once */
523 for ( j = 0; j < ( len - len2 ); j++ )
525 /* check for the game's magic word */
526 if ( Q_strncasecmp( &temp[ j ], game->magic, len2 ) == 0 ) {
527 /* now find the next slash and nuke everything after it */
528 while ( temp[ ++j ] != '/' && temp[ j ] != '\0' ) ;
531 /* add this as a base path */
538 /* add install path */
539 if ( numBasePaths == 0 ) {
540 AddBasePath( installPath );
544 if ( numBasePaths == 0 ) {
545 Error( "Failed to find a valid base path." );
549 /* this only affects unix */
550 if ( homeBasePath ) {
551 AddHomeBasePath( homeBasePath );
554 AddHomeBasePath( game->homeBasePath );
557 /* initialize vfs paths */
558 if ( numBasePaths > MAX_BASE_PATHS ) {
559 numBasePaths = MAX_BASE_PATHS;
561 if ( numGamePaths > MAX_GAME_PATHS ) {
562 numGamePaths = MAX_GAME_PATHS;
565 /* walk the list of game paths */
566 for ( j = 0; j < numGamePaths; j++ )
568 /* walk the list of base paths */
569 for ( i = 0; i < numBasePaths; i++ )
571 /* create a full path and initialize it */
572 sprintf( temp, "%s/%s/", basePaths[ i ], gamePaths[ j ] );
573 vfsInitDirectory( temp );
577 /* initialize vfs paths */
578 if ( numPakPaths > MAX_PAK_PATHS ) {
579 numPakPaths = MAX_PAK_PATHS;
582 /* walk the list of pak paths */
583 for ( i = 0; i < numPakPaths; i++ )
585 /* initialize this pak path */
586 vfsInitDirectory( pakPaths[ i ] );