Angband 3.0.9b.
[angband.git] / src / main.c
blobc90d06368b6858ca1953f8501606a4c9054eb47f
1 /* File: main.c */
3 /*
4 * Copyright (c) 1997 Ben Harrison, and others
6 * This software may be copied and distributed for educational, research,
7 * and not for profit purposes provided that this copyright and statement
8 * are included in all such copies.
9 */
11 #include "angband.h"
15 * Some machines have a "main()" function in their "main-xxx.c" file,
16 * all the others use this file for their "main()" function.
20 #if defined(WIN32_CONSOLE_MODE) \
21 || (!defined(WINDOWS) && !defined(RISCOS)) \
22 || defined(USE_SDL)
24 #include "main.h"
28 * List of the available modules in the order they are tried.
30 static const struct module modules[] =
32 #ifdef USE_GTK
33 { "gtk", help_gtk, init_gtk },
34 #endif /* USE_GTK */
36 #ifdef USE_XAW
37 { "xaw", help_xaw, init_xaw },
38 #endif /* USE_XAW */
40 #ifdef USE_X11
41 { "x11", help_x11, init_x11 },
42 #endif /* USE_X11 */
44 #ifdef USE_SDL
45 { "sdl", help_sdl, init_sdl },
46 #endif /* USE_SDL */
48 #ifdef USE_GCU
49 { "gcu", help_gcu, init_gcu },
50 #endif /* USE_GCU */
54 #ifdef USE_SOUND
57 * List of sound modules in the order they should be tried.
59 static const struct module sound_modules[] =
61 #ifdef SOUND_SDL
62 { "sdl", "SDL_mixer sound module", init_sound_sdl },
63 #endif /* SOUND_SDL */
65 { "dummy", "Dummy module", NULL },
68 #endif
72 * A hook for "quit()".
74 * Close down, then fall back into "quit()".
76 static void quit_hook(cptr s)
78 int j;
80 /* Unused parameter */
81 (void)s;
83 /* Scan windows */
84 for (j = ANGBAND_TERM_MAX - 1; j >= 0; j--)
86 /* Unused */
87 if (!angband_term[j]) continue;
89 /* Nuke it */
90 term_nuke(angband_term[j]);
97 * SDL needs a look-in
99 #ifdef USE_SDL
100 # include "SDL.h"
101 #endif
105 * Initialize and verify the file paths, and the score file.
107 * Use the ANGBAND_PATH environment var if possible, else use
108 * DEFAULT_PATH, and in either case, branch off appropriately.
110 * First, we'll look for the ANGBAND_PATH environment variable,
111 * and then look for the files in there. If that doesn't work,
112 * we'll try the DEFAULT_PATH constant. So be sure that one of
113 * these two things works...
115 * We must ensure that the path ends with "PATH_SEP" if needed,
116 * since the "init_file_paths()" function will simply append the
117 * relevant "sub-directory names" to the given path.
119 * Make sure that the path doesn't overflow the buffer. We have
120 * to leave enough space for the path separator, directory, and
121 * filenames.
123 static void init_stuff(void)
125 char path[1024];
127 cptr tail = NULL;
129 #ifndef FIXED_PATHS
131 /* Get the environment variable */
132 tail = getenv("ANGBAND_PATH");
134 #endif /* FIXED_PATHS */
136 /* Use the angband_path, or a default */
137 my_strcpy(path, tail ? tail : DEFAULT_PATH, sizeof(path));
139 /* Make sure it's terminated */
140 path[511] = '\0';
142 /* Hack -- Add a path separator (only if needed) */
143 if (!suffix(path, PATH_SEP)) my_strcat(path, PATH_SEP, sizeof(path));
145 /* Initialize */
146 init_file_paths(path);
152 * Handle a "-d<what>=<path>" option
154 * The "<what>" can be any string starting with the same letter as the
155 * name of a subdirectory of the "lib" folder (i.e. "i" or "info").
157 * The "<path>" can be any legal path for the given system, and should
158 * not end in any special path separator (i.e. "/tmp" or "~/.ang-info").
160 static void change_path(cptr info)
162 cptr s;
164 /* Find equal sign */
165 s = strchr(info, '=');
167 /* Verify equal sign */
168 if (!s) quit_fmt("Try '-d<what>=<path>' not '-d%s'", info);
170 /* Analyze */
171 switch (tolower((unsigned char)info[0]))
173 #ifndef FIXED_PATHS
174 case 'a':
176 string_free(ANGBAND_DIR_APEX);
177 ANGBAND_DIR_APEX = string_make(s+1);
178 break;
181 case 'f':
183 string_free(ANGBAND_DIR_FILE);
184 ANGBAND_DIR_FILE = string_make(s+1);
185 break;
188 case 'h':
190 string_free(ANGBAND_DIR_HELP);
191 ANGBAND_DIR_HELP = string_make(s+1);
192 break;
195 case 'i':
197 string_free(ANGBAND_DIR_INFO);
198 ANGBAND_DIR_INFO = string_make(s+1);
199 break;
202 case 'x':
204 string_free(ANGBAND_DIR_XTRA);
205 ANGBAND_DIR_XTRA = string_make(s+1);
206 break;
209 case 'b':
211 string_free(ANGBAND_DIR_BONE);
212 ANGBAND_DIR_BONE = string_make(s+1);
213 break;
216 case 'd':
218 string_free(ANGBAND_DIR_DATA);
219 ANGBAND_DIR_DATA = string_make(s+1);
220 break;
223 case 'e':
225 string_free(ANGBAND_DIR_EDIT);
226 ANGBAND_DIR_EDIT = string_make(s+1);
227 break;
230 case 's':
232 string_free(ANGBAND_DIR_SAVE);
233 ANGBAND_DIR_SAVE = string_make(s+1);
234 break;
237 #endif /* FIXED_PATHS */
239 case 'u':
241 string_free(ANGBAND_DIR_USER);
242 ANGBAND_DIR_USER = string_make(s+1);
243 break;
246 default:
248 quit_fmt("Bad semantics in '-d%s'", info);
255 * Simple "main" function for multiple platforms.
257 * Note the special "--" option which terminates the processing of
258 * standard options. All non-standard options (if any) are passed
259 * directly to the "init_xxx()" function.
261 int main(int argc, char *argv[])
263 int i;
265 bool done = FALSE;
266 bool new_game = FALSE;
268 int show_score = 0;
270 const char *mstr = NULL;
272 bool args = TRUE;
275 /* Save the "program name" XXX XXX XXX */
276 argv0 = argv[0];
279 #ifdef SET_UID
281 /* Default permissions on files */
282 (void)umask(022);
284 #endif /* SET_UID */
287 /* Get the file paths */
288 init_stuff();
291 #ifdef SET_UID
293 /* Get the user id */
294 player_uid = getuid();
296 /* Save the effective GID for later recall */
297 player_egid = getegid();
299 #endif /* SET_UID */
302 /* Drop permissions */
303 safe_setuid_drop();
306 #ifdef SET_UID
308 /* Get the "user name" as a default player name */
309 user_name(op_ptr->full_name, sizeof(op_ptr->full_name), player_uid);
311 #ifdef PRIVATE_USER_PATH
313 /* Create directories for the users files */
314 create_user_dirs();
316 #endif /* PRIVATE_USER_PATH */
318 #endif /* SET_UID */
321 /* Process the command line arguments */
322 for (i = 1; args && (i < argc); i++)
324 cptr arg = argv[i];
326 /* Require proper options */
327 if (*arg++ != '-') goto usage;
329 /* Analyze option */
330 switch (*arg++)
332 case 'N':
333 case 'n':
335 new_game = TRUE;
336 break;
339 case 'F':
340 case 'f':
342 arg_fiddle = TRUE;
343 break;
346 case 'W':
347 case 'w':
349 arg_wizard = TRUE;
350 break;
353 case 'V':
354 case 'v':
356 arg_sound = TRUE;
357 break;
360 case 'G':
361 case 'g':
363 /* Default graphics tile */
364 arg_graphics = GRAPHICS_ADAM_BOLT;
365 break;
368 case 'S':
369 case 's':
371 show_score = atoi(arg);
372 if (show_score <= 0) show_score = 10;
373 continue;
376 case 'u':
377 case 'U':
379 if (!*arg) goto usage;
381 /* Get the savefile name */
382 my_strcpy(op_ptr->full_name, arg, sizeof(op_ptr->full_name));
383 continue;
386 case 'm':
387 case 'M':
389 if (!*arg) goto usage;
390 mstr = arg;
391 continue;
394 case 'd':
395 case 'D':
397 change_path(arg);
398 continue;
401 case '-':
403 argv[i] = argv[0];
404 argc = argc - i;
405 argv = argv + i;
406 args = FALSE;
407 break;
410 default:
411 usage:
413 /* Dump usage information */
414 puts("Usage: angband [options] [-- subopts]");
415 puts(" -n Start a new character");
416 puts(" -w Resurrect dead character (marks savefile)");
417 puts(" -f Request fiddle (verbose) mode");
418 puts(" -v Request sound mode");
419 puts(" -g Request graphics mode");
420 puts(" -s<num> Show <num> high scores (default: 10)");
421 puts(" -u<who> Use your <who> savefile");
422 puts(" -d<def>=<path> Instead of lib/<def>, use <path>");
423 puts(" -m<sys> Use module <sys>, where <sys> can be:");
425 /* Print the name and help for each available module */
426 for (i = 0; i < (int)N_ELEMENTS(modules); i++)
428 printf(" %s %s\n",
429 modules[i].name, modules[i].help);
432 /* Actually abort the process */
433 quit(NULL);
436 if (*arg) goto usage;
439 /* Hack -- Forget standard args */
440 if (args)
442 argc = 1;
443 argv[1] = NULL;
447 /* Process the player name */
448 process_player_name(TRUE);
451 /* Install "quit" hook */
452 quit_aux = quit_hook;
454 /* Try the modules in the order specified by modules[] */
455 for (i = 0; i < (int)N_ELEMENTS(modules); i++)
457 /* User requested a specific module? */
458 if (!mstr || (streq(mstr, modules[i].name)))
460 if (0 == modules[i].init(argc, argv))
462 ANGBAND_SYS = modules[i].name;
463 done = TRUE;
464 break;
469 /* Make sure we have a display! */
470 if (!done) quit("Unable to prepare any 'display module'!");
473 #ifdef USE_SOUND
475 /* Try the modules in the order specified by sound_modules[] */
476 for (i = 0; i < (int)N_ELEMENTS(sound_modules) - 1; i++)
478 if (0 == sound_modules[i].init(argc, argv))
479 break;
482 #endif
485 /* Catch nasty signals */
486 signals_init();
488 /* Initialize */
489 init_angband();
491 /* Hack -- If requested, display scores and quit */
492 if (show_score > 0) display_scores(0, show_score);
494 /* Wait for response */
495 pause_line(Term->hgt - 1);
497 /* Play the game */
498 play_game(new_game);
500 /* Free resources */
501 cleanup_angband();
503 /* Quit */
504 quit(NULL);
506 /* Exit */
507 return (0);
510 #endif /* !defined(MACINTOSH) && !defined(WINDOWS) && !defined(RISCOS) */