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