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