transfer from internal tree r5311 branches/1.4-gpl
[xonotic/netradiant.git] / tools / quake3 / q3map2 / path_init.c
1 /*\r
2 Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
3 For a list of contributors, see the accompanying CONTRIBUTORS file.\r
4 \r
5 This file is part of GtkRadiant.\r
6 \r
7 GtkRadiant is free software; you can redistribute it and/or modify\r
8 it under the terms of the GNU General Public License as published by\r
9 the Free Software Foundation; either version 2 of the License, or\r
10 (at your option) any later version.\r
11 \r
12 GtkRadiant is distributed in the hope that it will be useful,\r
13 but WITHOUT ANY WARRANTY; without even the implied warranty of\r
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
15 GNU General Public License for more details.\r
16 \r
17 You should have received a copy of the GNU General Public License\r
18 along with GtkRadiant; if not, write to the Free Software\r
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
20 \r
21 ----------------------------------------------------------------------------------\r
22 \r
23 This code has been altered significantly from its original form, to support\r
24 several games based on the Quake III Arena engine, in the form of "Q3Map2."\r
25 \r
26 ------------------------------------------------------------------------------- */\r
27 \r
28 \r
29 \r
30 /* marker */\r
31 #define PATH_INIT_C\r
32 \r
33 \r
34 \r
35 /* dependencies */\r
36 #include "q3map2.h"\r
37 \r
38 \r
39 \r
40 /* path support */\r
41 #define MAX_BASE_PATHS  10\r
42 #define MAX_GAME_PATHS  10\r
43 \r
44 char                                    *homePath;\r
45 char                                    installPath[ MAX_OS_PATH ];\r
46 \r
47 int                                             numBasePaths;\r
48 char                                    *basePaths[ MAX_BASE_PATHS ];\r
49 int                                             numGamePaths;\r
50 char                                    *gamePaths[ MAX_GAME_PATHS ];\r
51 \r
52 \r
53 \r
54 /*\r
55 some of this code is based off the original q3map port from loki\r
56 and finds various paths. moved here from bsp.c for clarity.\r
57 */\r
58 \r
59 /*\r
60 PathLokiGetHomeDir()\r
61 gets the user's home dir (for ~/.q3a)\r
62 */\r
63 \r
64 char *LokiGetHomeDir( void )\r
65 {\r
66         #ifndef Q_UNIX\r
67                 return NULL;\r
68         #else\r
69                 char                    *home;\r
70                 uid_t                   id;\r
71                 struct passwd   *pwd;\r
72                 \r
73                 \r
74                 /* get the home environment variable */\r
75                 home = getenv( "HOME" );\r
76                 if( home == NULL )\r
77                 {\r
78                         /* do some more digging */\r
79                         id = getuid();\r
80                         setpwent();\r
81                         while( (pwd = getpwent()) != NULL )\r
82                         {\r
83                                 if( pwd->pw_uid == id )\r
84                                 {\r
85                                         home = pwd->pw_dir;\r
86                                         break;\r
87                                 }\r
88                         }\r
89                         endpwent();\r
90                 }\r
91                 \r
92                 /* return it */\r
93                 return home;\r
94         #endif\r
95 }\r
96 \r
97 \r
98 \r
99 /*\r
100 PathLokiInitPaths()\r
101 initializes some paths on linux/os x\r
102 */\r
103 \r
104 void LokiInitPaths( char *argv0 )\r
105 {\r
106         #ifndef Q_UNIX\r
107                 /* this is kinda crap, but hey */\r
108                 strcpy( installPath, "../" );\r
109         #else\r
110                 char            temp[ MAX_OS_PATH ];\r
111                 char            *home;\r
112                 char            *path;\r
113                 char            *last;\r
114                 qboolean        found;\r
115                 \r
116                 \r
117                 /* get home dir */\r
118                 home = LokiGetHomeDir();\r
119                 if( home == NULL )\r
120                         home = ".";\r
121                 \r
122                 /* do some path divining */\r
123                 strcpy( temp, argv0 );\r
124                 if( strrchr( temp, '/' ) )\r
125                         argv0 = strrchr( argv0, '/' ) + 1;\r
126                 else\r
127                 {\r
128                         /* get path environment variable */\r
129                         path = getenv( "PATH" );\r
130                         \r
131                         /* minor setup */\r
132                         last[ 0 ] = path[ 0 ];\r
133                         last[ 1 ] = '\0';\r
134                         found = qfalse;\r
135                         \r
136                         /* go through each : segment of path */\r
137                         while( last[ 0 ] != '\0' && found == qfalse )\r
138                         {\r
139                                 /* null out temp */\r
140                                 temp[ 0 ] = '\0';\r
141                                 \r
142                                 /* find next chunk */\r
143                                 last = strchr( path, ':' );\r
144                                 if( last == NULL )\r
145                                         last = path + strlen( path );\r
146                                 \r
147                                 /* found home dir candidate */\r
148                                 if( *path == '~' )\r
149                                 {\r
150                                         strcpy( temp, home );\r
151                                         path++;\r
152                                 }\r
153                                 \r
154                                 /* concatenate */\r
155                                 if( last > (path + 1) )\r
156                                 {\r
157                                         strncat( temp, path, (last - path) );\r
158                                         strcat( temp, "/" );\r
159                                 }\r
160                                 strcat( temp, "./" );\r
161                                 strcat( temp, argv0 );\r
162                                 \r
163                                 /* verify the path */\r
164                                 if( access( temp, X_OK ) == 0 )\r
165                                         found++;\r
166                                 path = last + 1;\r
167                         }\r
168                 }\r
169                 \r
170                 /* flake */\r
171                 if( realpath( temp, installPath ) )\r
172                 {\r
173                         /* q3map is in "tools/" */\r
174                         *(strrchr( installPath, '/' )) = '\0';\r
175                         *(strrchr( installPath, '/' ) + 1) = '\0';\r
176                 }\r
177                 \r
178                 /* set home path */\r
179                 homePath = home;\r
180         #endif\r
181 }\r
182 \r
183 \r
184 \r
185 /*\r
186 CleanPath() - ydnar\r
187 cleans a dos path \ -> /\r
188 */\r
189 \r
190 void CleanPath( char *path )\r
191 {\r
192         while( *path )\r
193         {\r
194                 if( *path == '\\' )\r
195                         *path = '/';\r
196                 path++;\r
197         }\r
198 }\r
199 \r
200 \r
201 \r
202 /*\r
203 SetGame() - ydnar\r
204 sets the game based on a -game argument\r
205 doesn't set it if the game doesn't match any known games\r
206 */\r
207 \r
208 void SetGame( char *arg )\r
209 {\r
210         int     i;\r
211         \r
212         \r
213         /* dummy check */\r
214         if( arg == NULL || arg[ 0 ] == '\0' )\r
215                 return;\r
216         \r
217         /* joke */\r
218         if( !Q_stricmp( arg, "quake1" ) ||\r
219                 !Q_stricmp( arg, "quake2" ) ||\r
220                 !Q_stricmp( arg, "unreal" ) ||\r
221                 !Q_stricmp( arg, "ut2k3" ) ||\r
222                 !Q_stricmp( arg, "dn3d" ) ||\r
223                 !Q_stricmp( arg, "dnf" ) ||\r
224                 !Q_stricmp( arg, "hl" ) )\r
225         {\r
226                 Sys_Printf( "April fools, silly rabbit!\n" );\r
227                 exit( 0 );\r
228         }\r
229         \r
230         /* test it */\r
231         i = 0;\r
232         while( games[ i ].arg != NULL )\r
233         {\r
234                 if( Q_stricmp( arg, games[ i ].arg ) == 0 )\r
235                         game = &games[ i ];\r
236                 i++;\r
237         }\r
238 }\r
239 \r
240 \r
241 \r
242 /*\r
243 AddBasePath() - ydnar\r
244 adds a base path to the list\r
245 */\r
246 \r
247 void AddBasePath( char *path )\r
248 {\r
249         /* dummy check */\r
250         if( path == NULL || path[ 0 ] == '\0' || numBasePaths >= MAX_BASE_PATHS )\r
251                 return;\r
252         \r
253         /* add it to the list */\r
254         basePaths[ numBasePaths ] = safe_malloc( strlen( path ) + 1 );\r
255         strcpy( basePaths[ numBasePaths ], path );\r
256         CleanPath( basePaths[ numBasePaths ] );\r
257         numBasePaths++;\r
258 }\r
259 \r
260 \r
261 \r
262 /*\r
263 AddHomeBasePath() - ydnar\r
264 adds a base path to the beginning of the list, prefixed by ~/\r
265 */\r
266 \r
267 void AddHomeBasePath( char *path )\r
268 {\r
269         #ifdef Q_UNIX\r
270                 int             i;\r
271                 char    temp[ MAX_OS_PATH ];\r
272                 \r
273                 \r
274                 /* dummy check */\r
275                 if( path == NULL || path[ 0 ] == '\0' )\r
276                         return;\r
277 \r
278                 /* make a hole */\r
279                 for( i = 0; i < (MAX_BASE_PATHS - 1); i++ )\r
280                         basePaths[ i + 1 ] = basePaths[ i ];\r
281                 \r
282                 /* concatenate home dir and path */\r
283                 sprintf( temp, "%s/%s", homePath, path );\r
284                 \r
285                 /* add it to the list */\r
286                 basePaths[ 0 ] = safe_malloc( strlen( temp ) + 1 );\r
287                 strcpy( basePaths[ 0 ], temp );\r
288                 CleanPath( basePaths[ 0 ] );\r
289                 numBasePaths++;\r
290         #endif\r
291 }\r
292 \r
293 \r
294 \r
295 /*\r
296 AddGamePath() - ydnar\r
297 adds a game path to the list\r
298 */\r
299 \r
300 void AddGamePath( char *path )\r
301 {\r
302         /* dummy check */\r
303         if( path == NULL || path[ 0 ] == '\0' || numGamePaths >= MAX_GAME_PATHS )\r
304                 return;\r
305         \r
306         /* add it to the list */\r
307         gamePaths[ numGamePaths ] = safe_malloc( strlen( path ) + 1 );\r
308         strcpy( gamePaths[ numGamePaths ], path );\r
309         CleanPath( gamePaths[ numGamePaths ] );\r
310         numGamePaths++;\r
311 }\r
312 \r
313 \r
314 \r
315 \r
316 /*\r
317 InitPaths() - ydnar\r
318 cleaned up some of the path initialization code from bsp.c\r
319 will remove any arguments it uses\r
320 */\r
321 \r
322 void InitPaths( int *argc, char **argv )\r
323 {\r
324         int             i, j, k, len, len2;\r
325         char    temp[ MAX_OS_PATH ];\r
326         \r
327         \r
328         /* note it */\r
329         Sys_FPrintf( SYS_VRB, "--- InitPaths ---\n" );\r
330         \r
331         /* get the install path for backup */\r
332         LokiInitPaths( argv[ 0 ] );\r
333         \r
334         /* set game to default (q3a) */\r
335         game = &games[ 0 ];\r
336         numBasePaths = 0;\r
337         numGamePaths = 0;\r
338         \r
339         /* parse through the arguments and extract those relevant to paths */\r
340         for( i = 0; i < *argc; i++ )\r
341         {\r
342                 /* check for null */\r
343                 if( argv[ i ] == NULL )\r
344                         continue;\r
345                 \r
346                 /* -game */\r
347                 if( strcmp( argv[ i ], "-game" ) == 0 )\r
348                 {\r
349                         if( ++i >= *argc )\r
350                                 Error( "Out of arguments: No game specified after %s", argv[ i - 1 ] );\r
351                         argv[ i - 1 ] = NULL;\r
352                         SetGame( argv[ i ] );\r
353                         argv[ i ] = NULL;\r
354                 }\r
355 \r
356                 /* -fs_basepath */\r
357                 else if( strcmp( argv[ i ], "-fs_basepath" ) == 0 )\r
358                 {\r
359                         if( ++i >= *argc )\r
360                                 Error( "Out of arguments: No path specified after %s.", argv[ i - 1 ] );\r
361                         argv[ i - 1 ] = NULL;\r
362                         AddBasePath( argv[ i ] );\r
363                         argv[ i ] = NULL;\r
364                 }\r
365                 \r
366                 /* -fs_game */\r
367                 else if( strcmp( argv[ i ], "-fs_game" ) == 0 )\r
368                 {\r
369                         if( ++i >= *argc )\r
370                                 Error( "Out of arguments: No path specified after %s.", argv[ i - 1 ] );\r
371                         argv[ i - 1 ] = NULL;\r
372                         AddGamePath( argv[ i ] );\r
373                         argv[ i ] = NULL;\r
374                 }\r
375         }\r
376         \r
377         /* remove processed arguments */\r
378         for( i = 0, j = 0, k = 0; i < *argc && j < *argc; i++, j++ )\r
379         {\r
380                 for( j; j < *argc && argv[ j ] == NULL; j++ );\r
381                 argv[ i ] = argv[ j ];\r
382                 if( argv[ i ] != NULL )\r
383                         k++;\r
384         }\r
385         *argc = k;\r
386         \r
387         /* add standard game path */\r
388         AddGamePath( game->gamePath );\r
389         \r
390         /* if there is no base path set, figure it out */\r
391         if( numBasePaths == 0 )\r
392         {\r
393                 /* this is another crappy replacement for SetQdirFromPath() */\r
394                 len2 = strlen( game->magic );\r
395                 for( i = 0; i < *argc && numBasePaths == 0; i++ )\r
396                 {\r
397                         /* extract the arg */\r
398                         strcpy( temp, argv[ i ] );\r
399                         CleanPath( temp );\r
400                         len = strlen( temp );\r
401                         Sys_FPrintf( SYS_VRB, "Searching for \"%s\" in \"%s\" (%d)...\n", game->magic, temp, i );\r
402                         \r
403                         /* this is slow, but only done once */\r
404                         for( j = 0; j < (len - len2); j++ )\r
405                         {\r
406                                 /* check for the game's magic word */\r
407                                 if( Q_strncasecmp( &temp[ j ], game->magic, len2 ) == 0 )\r
408                                 {\r
409                                         /* now find the next slash and nuke everything after it */\r
410                                         while( temp[ ++j ] != '/' && temp[ j ] != '\0' );\r
411                                         temp[ j ] = '\0';\r
412                                         \r
413                                         /* add this as a base path */\r
414                                         AddBasePath( temp );\r
415                                         break;\r
416                                 }\r
417                         }\r
418                 }\r
419                 \r
420                 /* add install path */\r
421                 if( numBasePaths == 0 )\r
422                         AddBasePath( installPath );\r
423                 \r
424                 /* check again */\r
425                 if( numBasePaths == 0 )\r
426                         Error( "Failed to find a valid base path." );\r
427         }\r
428         \r
429         /* this only affects unix */\r
430         AddHomeBasePath( game->homeBasePath );\r
431         \r
432         /* initialize vfs paths */\r
433         if( numBasePaths > MAX_BASE_PATHS )\r
434                 numBasePaths = MAX_BASE_PATHS;\r
435         if( numGamePaths > MAX_GAME_PATHS )\r
436                 numGamePaths = MAX_GAME_PATHS;\r
437         \r
438         /* walk the list of game paths */\r
439         for( j = 0; j < numGamePaths; j++ )\r
440         {\r
441                 /* walk the list of base paths */\r
442                 for( i = 0; i < numBasePaths; i++ )\r
443                 {\r
444                         /* create a full path and initialize it */\r
445                         sprintf( temp, "%s/%s/", basePaths[ i ], gamePaths[ j ] );\r
446                         vfsInitDirectory( temp );\r
447                 }\r
448         }\r
449         \r
450         /* done */\r
451         Sys_Printf( "\n" );\r
452 }\r
453 \r
454 \r
455 \r
456 \r