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