Change Windows startup
remove the safeproc pseudo-windowport routines from
almost a decade ago.
A very early pass is made through the config file,
seeking out just the interface-related OPTIONS=windowport
and OPTIONS=soundlib and ignoring all other options in the
config file during that early pass, so the windowport
can be activated without the NetHack core initialization
in place that some of the other rcfile OPTIONS require.
Bundles the existing rcfile processing code into rcfile().
New functions to control which rcfile options will be
disregarded in the early config file pass, and which will be
processed:
set_all_options_disregarded();
set_all_options_heeded();
disregard_this_option(opt_xx);
heed_this_option(opt_xx);
Windows calls rcfile_interface_options(), which is
a bundling of a series of function calls to achieve
the desired result.
void
rcfile_interface_options(void)
{
allopt_array_init();
set_all_options_disregarded();
heed_this_option(opt_windowtype);
heed_this_option(opt_soundlib);
rcfile();
set_all_options_heeded();
disregard_this_option(opt_windowtype);
disregard_this_option(opt_soundlib);
}
This commit is contained in:
@@ -1881,6 +1881,85 @@ vconfig_error_add(const char *str, va_list the_args)
|
||||
config_erradd(buf);
|
||||
}
|
||||
|
||||
void
|
||||
rcfile(void)
|
||||
{
|
||||
char *opts = 0, *xtraopts = 0;
|
||||
const char *envname, *namesrc, *nameval;
|
||||
|
||||
go.opt_phase = environ_opt;
|
||||
/* getenv() instead of nhgetenv(): let total length of options be long;
|
||||
parseoptions() will check each individually */
|
||||
envname = "NETHACKOPTIONS";
|
||||
opts = getenv(envname);
|
||||
if (!opts) {
|
||||
/* fall back to original name; discouraged */
|
||||
envname = "HACKOPTIONS";
|
||||
opts = getenv(envname);
|
||||
}
|
||||
|
||||
if (gc.cmdline_rcfile) {
|
||||
namesrc = "command line";
|
||||
nameval = gc.cmdline_rcfile;
|
||||
xtraopts = opts;
|
||||
if (opts && (*opts == '/' || *opts == '\\' || *opts == '@'))
|
||||
xtraopts = 0; /* NETHACKOPTIONS is a file name; ignore it */
|
||||
} else if (opts && (*opts == '/' || *opts == '\\' || *opts == '@')) {
|
||||
/* NETHACKOPTIONS is a file name; use that instead of the default */
|
||||
if (*opts == '@')
|
||||
++opts; /* @filename */
|
||||
namesrc = envname;
|
||||
nameval = opts;
|
||||
xtraopts = 0;
|
||||
} else {
|
||||
/* either no NETHACKOPTIONS or it wasn't a file name;
|
||||
read the default configuration file */
|
||||
nameval = namesrc = 0;
|
||||
xtraopts = opts;
|
||||
}
|
||||
|
||||
go.opt_phase = rc_file_opt;
|
||||
/* seemingly arbitrary name length restriction is to prevent error
|
||||
messages, if any were to be delivered while accessing the file,
|
||||
from potentially overflowing buffers */
|
||||
if (nameval && (int) strlen(nameval) >= BUFSZ / 2) {
|
||||
config_error_init(TRUE, namesrc, FALSE);
|
||||
config_error_add(
|
||||
"nethackrc file name \"%.40s\"... too long; using default",
|
||||
nameval);
|
||||
config_error_done();
|
||||
nameval = namesrc = 0; /* revert to default nethackrc */
|
||||
}
|
||||
|
||||
config_error_init(TRUE, nameval, nameval ? CONFIG_ERROR_SECURE : FALSE);
|
||||
(void) read_config_file(nameval, set_in_config);
|
||||
config_error_done();
|
||||
if (xtraopts) {
|
||||
/* NETHACKOPTIONS is present and not a file name */
|
||||
go.opt_phase = environ_opt;
|
||||
config_error_init(FALSE, envname, FALSE);
|
||||
(void) parseoptions(xtraopts, TRUE, FALSE);
|
||||
config_error_done();
|
||||
}
|
||||
|
||||
if (gc.cmdline_rcfile)
|
||||
free((genericptr_t) gc.cmdline_rcfile), gc.cmdline_rcfile = 0;
|
||||
/*[end of nethackrc handling]*/
|
||||
}
|
||||
|
||||
void
|
||||
rcfile_interface_options(void)
|
||||
{
|
||||
allopt_array_init();
|
||||
set_all_options_disregarded();
|
||||
heed_this_option(opt_windowtype);
|
||||
heed_this_option(opt_soundlib);
|
||||
rcfile();
|
||||
set_all_options_heeded();
|
||||
disregard_this_option(opt_windowtype);
|
||||
disregard_this_option(opt_soundlib);
|
||||
}
|
||||
|
||||
#ifdef SYSCF
|
||||
#ifdef SYSCF_FILE
|
||||
void
|
||||
|
||||
@@ -592,7 +592,7 @@ static const struct instance_globals_o g_init_o = {
|
||||
/* o_init.c */
|
||||
DUMMY, /* oclass_prob_totals */
|
||||
/* options.c */
|
||||
0, /* opt_phase */
|
||||
phase_not_set, /* opt_phase */
|
||||
FALSE, /* opt_initial */
|
||||
FALSE, /* opt_from_file */
|
||||
FALSE, /* opt_need_redraw */
|
||||
|
||||
279
src/options.c
279
src/options.c
@@ -56,21 +56,13 @@ NEARDATA struct accessibility_data a11y;
|
||||
#include "optlist.h"
|
||||
#undef NHOPT_PROTO
|
||||
|
||||
#define NHOPT_ENUM
|
||||
enum opt {
|
||||
opt_prefix_only = -1,
|
||||
#include "optlist.h"
|
||||
OPTCOUNT
|
||||
};
|
||||
#undef NHOPT_ENUM
|
||||
|
||||
#define NHOPT_PARSE
|
||||
static struct allopt_t allopt_init[] = {
|
||||
#include "optlist.h"
|
||||
{(const char *) 0, OptS_Advanced, 0, 0, 0, set_in_sysconf, BoolOpt,
|
||||
No, No, No, No, Term_False, 0, (boolean *) 0,
|
||||
(int (*)(int, int, boolean, char *, char *)) 0,
|
||||
(char *) 0, (const char *) 0, (const char *) 0, 0, 0, 0 }
|
||||
(char *) 0, (const char *) 0, (const char *) 0, 0, 0, 0, TRUE }
|
||||
};
|
||||
#undef NHOPT_PARSE
|
||||
|
||||
@@ -94,16 +86,6 @@ enum optn_result {
|
||||
enum requests {
|
||||
do_nothing, do_init, do_set, do_handler, get_val, get_cnf_val
|
||||
};
|
||||
/* these aren't the same as set_xxx in optlist.h */
|
||||
enum option_phases {
|
||||
builtin_opt=1,/* compiled-in default value of an option */
|
||||
syscf_opt, /* sysconf setting of an option, overrides builtin */
|
||||
rc_file_opt, /* player's run-time config file setting, overrides syscf */
|
||||
environ_opt, /* player's environment NETHACKOPTIONS, overrides rc_file */
|
||||
cmdline_opt, /* program invocation command-line, overrides environ */
|
||||
play_opt, /* 'O' command, interactively set so overrides all */
|
||||
num_opt_phases
|
||||
};
|
||||
|
||||
static struct allopt_t allopt[SIZE(allopt_init)];
|
||||
|
||||
@@ -124,6 +106,7 @@ extern char ttycolors[CLR_MAX]; /* in sys/msdos/video.c */
|
||||
static char empty_optstr[] = { '\0' };
|
||||
static boolean duplicate, using_alias;
|
||||
static boolean give_opt_msg = TRUE;
|
||||
static boolean restricted_options_mode = FALSE;
|
||||
|
||||
enum { MAX_ROLEOPT = 4 }; /* 4: role,race,gend,algn */
|
||||
static boolean opt_set_in_config[OPTCOUNT];
|
||||
@@ -357,6 +340,7 @@ static const menu_cmd_t default_menu_cmd_info[] = {
|
||||
|
||||
static const char n_currently_set[] = "(%d currently set)";
|
||||
|
||||
staticfn void allopt_array_init(void);
|
||||
staticfn void nmcpy(char *, const char *, int);
|
||||
staticfn void escapes(const char *, char *);
|
||||
staticfn void rejectoption(const char *);
|
||||
@@ -595,7 +579,7 @@ parseoptions(
|
||||
* placed that number into each option's allopt[n].minmatch.
|
||||
*
|
||||
*/
|
||||
if (!got_match)
|
||||
if (!got_match && allopt[i].name)
|
||||
got_match = match_optname(opts, allopt[i].name,
|
||||
allopt[i].minmatch, TRUE);
|
||||
if (got_match) {
|
||||
@@ -634,7 +618,8 @@ parseoptions(
|
||||
/* allow optfn's to test whether they were called from parseoptions() */
|
||||
program_state.in_parseoptions++;
|
||||
|
||||
if (got_match && matchidx >= 0) {
|
||||
if (got_match && (matchidx >= 0 && matchidx < OPTCOUNT)
|
||||
&& !allopt[matchidx].disregarded) {
|
||||
duplicate = duplicate_opt_detection(matchidx);
|
||||
if (duplicate && !allopt[matchidx].dupeok)
|
||||
complain_about_duplicate(matchidx);
|
||||
@@ -684,7 +669,7 @@ parseoptions(
|
||||
}
|
||||
}
|
||||
|
||||
if (optresult == optn_silenterr)
|
||||
if (optresult == optn_silenterr || restricted_options_mode)
|
||||
return FALSE;
|
||||
if (pfx_match && optresult == optn_err) {
|
||||
char pfxbuf[BUFSZ], *pfxp;
|
||||
@@ -4971,17 +4956,20 @@ optfn_windowtype(
|
||||
* _end_ because comma-separated option strings are processed from
|
||||
* right to left.
|
||||
*/
|
||||
if (iflags.windowtype_locked)
|
||||
return optn_ok;
|
||||
if (!iflags.window_inited) {
|
||||
if (iflags.windowtype_locked)
|
||||
return optn_ok;
|
||||
|
||||
if ((op = string_for_env_opt(allopt[optidx].name, opts, FALSE))
|
||||
!= empty_optstr) {
|
||||
nmcpy(gc.chosen_windowtype, op, WINTYPELEN);
|
||||
if (!iflags.windowtype_deferred) {
|
||||
choose_windows(gc.chosen_windowtype);
|
||||
if ((op = string_for_env_opt(allopt[optidx].name, opts, FALSE))
|
||||
!= empty_optstr) {
|
||||
nmcpy(gc.chosen_windowtype, op, WINTYPELEN);
|
||||
if (!iflags.windowtype_deferred) {
|
||||
choose_windows(gc.chosen_windowtype);
|
||||
}
|
||||
} else {
|
||||
return optn_err;
|
||||
}
|
||||
} else
|
||||
return optn_err;
|
||||
}
|
||||
return optn_ok;
|
||||
}
|
||||
if (req == get_val || req == get_cnf_val) {
|
||||
@@ -7066,29 +7054,14 @@ txt2key(char *txt)
|
||||
void
|
||||
initoptions(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Most places that call initoptions_init()/initoptions() would
|
||||
* have the calls next to each other, so instead of adding
|
||||
* initoptions_init() everywhere, just add it where it's needed in
|
||||
* a non-adjacent place and call it here for all the other cases.
|
||||
*/
|
||||
if(go.opt_phase != builtin_opt)
|
||||
if (go.opt_phase != builtin_opt)
|
||||
initoptions_init();
|
||||
|
||||
/*
|
||||
* Call each option function with an init flag and give it a chance
|
||||
* to make any preparations that it might require. We do this
|
||||
* whether or not the option itself is ever specified; that's
|
||||
* irrelevant for the init call. Doing this allows the prep code for
|
||||
* option settings to remain adjacent to, and in the same function as,
|
||||
* the code that processes those options.
|
||||
*/
|
||||
for (i = 0; i < OPTCOUNT; ++i) {
|
||||
if (allopt[i].optfn)
|
||||
(*allopt[i].optfn)(i, do_init, FALSE, empty_optstr, empty_optstr);
|
||||
}
|
||||
#ifdef SYSCF
|
||||
/* someday there may be other SYSCF alternatives besides text file */
|
||||
#ifdef SYSCF_FILE
|
||||
@@ -7130,9 +7103,7 @@ initoptions_init(void)
|
||||
go.opt_phase = builtin_opt; /* Did I need to move this here? */
|
||||
/* initialize the function pointers for saving the game */
|
||||
sf_init();
|
||||
memcpy(allopt, allopt_init, sizeof(allopt));
|
||||
determine_ambiguities();
|
||||
|
||||
allopt_array_init();
|
||||
/* if windowtype has been specified on the command line, set it up
|
||||
early so windowtype-specific options use it as their base */
|
||||
if (gc.cmdline_windowsys) {
|
||||
@@ -7286,6 +7257,28 @@ initoptions_init(void)
|
||||
/* since this is done before init_objects(), do partial init here */
|
||||
objects[SLIME_MOLD].oc_name_idx = SLIME_MOLD;
|
||||
nmcpy(svp.pl_fruit, OBJ_NAME(objects[SLIME_MOLD]), PL_FSIZ);
|
||||
|
||||
#ifdef SYSCF
|
||||
/* someday there may be other SYSCF alternatives besides text file */
|
||||
#ifdef SYSCF_FILE
|
||||
/* If SYSCF_FILE is specified, it _must_ exist... */
|
||||
assure_syscf_file();
|
||||
config_error_init(TRUE, SYSCF_FILE, FALSE);
|
||||
|
||||
/* ... and _must_ parse correctly. */
|
||||
go.opt_phase = syscf_opt;
|
||||
if (!read_config_file(SYSCF_FILE, set_in_sysconf)) {
|
||||
if (config_error_done() && !iflags.initoptions_noterminate)
|
||||
nh_terminate(EXIT_FAILURE);
|
||||
}
|
||||
config_error_done();
|
||||
/*
|
||||
* TODO [maybe]: parse the sysopt entries which are space-separated
|
||||
* lists of usernames into arrays with one name per element.
|
||||
*/
|
||||
#endif
|
||||
#endif /* SYSCF */
|
||||
initoptions_finish();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -7306,72 +7299,69 @@ initoptions_init(void)
|
||||
*/
|
||||
void
|
||||
initoptions_finish(void)
|
||||
{
|
||||
nhsym sym = 0;
|
||||
char *opts = 0, *xtraopts = 0;
|
||||
#ifndef MAC
|
||||
const char *envname, *namesrc, *nameval;
|
||||
{ nhsym sym = 0;
|
||||
|
||||
/* getenv() instead of nhgetenv(): let total length of options be long;
|
||||
parseoptions() will check each individually */
|
||||
envname = "NETHACKOPTIONS";
|
||||
opts = getenv(envname);
|
||||
if (!opts) {
|
||||
/* fall back to original name; discouraged */
|
||||
envname = "HACKOPTIONS";
|
||||
opts = getenv(envname);
|
||||
rcfile();
|
||||
|
||||
(void) fruitadd(svp.pl_fruit, (struct fruit *) 0);
|
||||
/*
|
||||
* Remove "slime mold" from list of object names. This will
|
||||
* prevent it from being wished unless it's actually present
|
||||
* as a named (or default) fruit. Wishing for "fruit" will
|
||||
* result in the player's preferred fruit. [Once upon a time
|
||||
* the override value used was "\033" which prevented wishing
|
||||
* for the slime mold object at all except by asking for a
|
||||
* specific named fruit.] Note that there are multiple fruit
|
||||
* object types (apple, melon, &c) but the "fruit" object is
|
||||
* slime mold or whatever custom name player assigns to that.
|
||||
*/
|
||||
obj_descr[SLIME_MOLD].oc_name = "fruit";
|
||||
|
||||
sym = get_othersym(SYM_BOULDER,
|
||||
Is_rogue_level(&u.uz) ? ROGUESET : PRIMARYSET);
|
||||
if (sym)
|
||||
gs.showsyms[SYM_BOULDER + SYM_OFF_X] = sym;
|
||||
reglyph_darkroom();
|
||||
reset_glyphmap(gm_optionchange);
|
||||
#ifdef STATUS_HILITES
|
||||
/*
|
||||
* A multi-interface binary might only support status highlighting
|
||||
* for some of the interfaces; check whether we asked for it but are
|
||||
* using one which doesn't.
|
||||
*
|
||||
* Option processing can take place before a user-decided WindowPort
|
||||
* is even initialized, so check for that too.
|
||||
*/
|
||||
if (!WINDOWPORT(safestartup)) {
|
||||
if (iflags.hilite_delta && !wc2_supported("statushilites")) {
|
||||
raw_printf("Status highlighting not supported for %s interface.",
|
||||
windowprocs.name);
|
||||
iflags.hilite_delta = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
update_rest_on_space();
|
||||
|
||||
if (gc.cmdline_rcfile) {
|
||||
namesrc = "command line";
|
||||
nameval = gc.cmdline_rcfile;
|
||||
xtraopts = opts;
|
||||
if (opts && (*opts == '/' || *opts == '\\' || *opts == '@'))
|
||||
xtraopts = 0; /* NETHACKOPTIONS is a file name; ignore it */
|
||||
} else if (opts && (*opts == '/' || *opts == '\\' || *opts == '@')) {
|
||||
/* NETHACKOPTIONS is a file name; use that instead of the default */
|
||||
if (*opts == '@')
|
||||
++opts; /* @filename */
|
||||
namesrc = envname;
|
||||
nameval = opts;
|
||||
xtraopts = 0;
|
||||
} else
|
||||
#endif /* !MAC */
|
||||
/*else*/ {
|
||||
/* either no NETHACKOPTIONS or it wasn't a file name;
|
||||
read the default configuration file */
|
||||
nameval = namesrc = 0;
|
||||
xtraopts = opts;
|
||||
}
|
||||
/* these can't rely on compile-time initialization for their defaults
|
||||
because a multi-interface binary might need different values for
|
||||
different interfaces; if neither tiled_map nor ascii_map pass the
|
||||
wc_supported() test, assume ascii_map */
|
||||
if (iflags.wc_tiled_map && !wc_supported("tiled_map"))
|
||||
iflags.wc_tiled_map = FALSE, iflags.wc_ascii_map = TRUE;
|
||||
else if (iflags.wc_ascii_map && !wc_supported("ascii_map")
|
||||
&& wc_supported("tiled_map"))
|
||||
iflags.wc_ascii_map = FALSE, iflags.wc_tiled_map = TRUE;
|
||||
|
||||
/* seemingly arbitrary name length restriction is to prevent error
|
||||
messages, if any were to be delivered while accessing the file,
|
||||
from potentially overflowing buffers */
|
||||
if (nameval && (int) strlen(nameval) >= BUFSZ / 2) {
|
||||
go.opt_phase = rc_file_opt;
|
||||
config_error_init(TRUE, namesrc, FALSE);
|
||||
config_error_add(
|
||||
"nethackrc file name \"%.40s\"... too long; using default",
|
||||
nameval);
|
||||
config_error_done();
|
||||
nameval = namesrc = 0; /* revert to default nethackrc */
|
||||
}
|
||||
|
||||
config_error_init(TRUE, nameval, nameval ? CONFIG_ERROR_SECURE : FALSE);
|
||||
(void) read_config_file(nameval, set_in_config);
|
||||
config_error_done();
|
||||
if (xtraopts) {
|
||||
/* NETHACKOPTIONS is present and not a file name */
|
||||
go.opt_phase = environ_opt;
|
||||
config_error_init(FALSE, envname, FALSE);
|
||||
(void) parseoptions(xtraopts, TRUE, FALSE);
|
||||
config_error_done();
|
||||
}
|
||||
|
||||
if (gc.cmdline_rcfile)
|
||||
free((genericptr_t) gc.cmdline_rcfile), gc.cmdline_rcfile = 0;
|
||||
/*[end of nethackrc handling]*/
|
||||
#ifdef ENHANCED_SYMBOLS
|
||||
if (glyphid_cache_status())
|
||||
free_glyphid_cache();
|
||||
apply_customizations(gc.currentgraphics, do_custom_symbols);
|
||||
#endif
|
||||
go.opt_initial = FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
(void) fruitadd(svp.pl_fruit, (struct fruit *) 0);
|
||||
/*
|
||||
* Remove "slime mold" from list of object names. This will
|
||||
@@ -7449,6 +7439,37 @@ initoptions_finish(void)
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
void
|
||||
allopt_array_init(void)
|
||||
{
|
||||
int i;
|
||||
static boolean options_array_inited_already = FALSE;
|
||||
|
||||
if (!options_array_inited_already) {
|
||||
memcpy(allopt, allopt_init, sizeof(allopt));
|
||||
determine_ambiguities();
|
||||
for (i = 0; allopt[i].name; i++) {
|
||||
if (allopt[i].addr)
|
||||
*(allopt[i].addr) = allopt[i].initval;
|
||||
}
|
||||
set_all_options_heeded();
|
||||
/*
|
||||
* Call each option function with an init flag and give it a chance
|
||||
* to make any preparations that it might require. We do this
|
||||
* whether or not the option itself is ever specified; that's
|
||||
* irrelevant for the init call. Doing this allows the prep code for
|
||||
* option settings to remain adjacent to, and in the same function as,
|
||||
* the code that processes those options.
|
||||
*/
|
||||
for (i = 0; i < OPTCOUNT; ++i) {
|
||||
if (allopt[i].optfn)
|
||||
(*allopt[i].optfn)(i, do_init, FALSE, empty_optstr,
|
||||
empty_optstr);
|
||||
}
|
||||
options_array_inited_already = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*******************************************
|
||||
@@ -8966,6 +8987,7 @@ doset(void) /* changing options via menu by Per Liboriussen */
|
||||
if (opt_indx < -1)
|
||||
opt_indx++; /* -1 offset for select_menu() */
|
||||
opt_indx -= indexoffset;
|
||||
assert(IndexOk(opt_indx, allopt));
|
||||
if (allopt[opt_indx].opttyp == BoolOpt) {
|
||||
/* boolean option */
|
||||
Sprintf(buf, "%s%s", *allopt[opt_indx].addr ? "!" : "",
|
||||
@@ -10220,6 +10242,41 @@ enhance_menu_text(
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
set_all_options_heeded(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < OPTCOUNT; i++)
|
||||
allopt[i].disregarded = FALSE;
|
||||
restricted_options_mode = FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
set_all_options_disregarded(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < OPTCOUNT ; i++)
|
||||
allopt[i].disregarded = TRUE;
|
||||
restricted_options_mode = TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
heed_this_option(enum opt optidx)
|
||||
{
|
||||
if (optidx >= 0 && optidx < (enum opt) OPTCOUNT)
|
||||
allopt[optidx].disregarded = FALSE;
|
||||
}
|
||||
void
|
||||
disregard_this_option(enum opt optidx)
|
||||
{
|
||||
if (optidx >= 0 && optidx < (enum opt) OPTCOUNT)
|
||||
allopt[optidx].disregarded = TRUE;
|
||||
if (!restricted_options_mode)
|
||||
restricted_options_mode = TRUE;
|
||||
}
|
||||
|
||||
#undef OPTIONS_HEADING
|
||||
#undef CONFIG_SLOT
|
||||
|
||||
|
||||
Reference in New Issue
Block a user