Having a hard cap on the number of rerolls doesn't help save CPU usage from excessive rerolling, because if the cap is set low enough to keep the CPU usage reasonable it isn't high enough for players to actually use the feature. Instead, allow capping the number of rerolls per second. (Sensible values seem to be in the 5-10 range.) If the player attempts more rerolls than this, show a paranoid confirmation prompt: the need to type the answer to the prompt will slow a human user down (and if the prompt is filled in too quickly, it will simply just be shown again, preventing attempts to use automation to skip the prompt).
2233 lines
58 KiB
C
2233 lines
58 KiB
C
/* NetHack 5.0 cfgfiles.c $NHDT-Date: 1740532826 2025/02/25 17:20:26 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.417 $ */
|
|
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
|
/*-Copyright (c) Derek S. Ray, 2015. */
|
|
/* NetHack may be freely redistributed. See license for details. */
|
|
|
|
#define NEED_VARARGS
|
|
|
|
#include "hack.h"
|
|
#include "dlb.h"
|
|
#include <errno.h>
|
|
|
|
#if (!defined(MACOS9) && !defined(O_WRONLY) && !defined(AZTEC_C)) \
|
|
|| defined(USE_FCNTL)
|
|
#include <fcntl.h>
|
|
#endif
|
|
|
|
#define BIGBUFSZ (5 * BUFSZ) /* big enough to format a 4*BUFSZ string (from
|
|
* config file parsing) with modest decoration;
|
|
* result will then be truncated to BUFSZ-1 */
|
|
|
|
#ifdef USER_SOUNDS
|
|
extern char *sounddir; /* defined in sounds.c */
|
|
#endif
|
|
|
|
staticfn void vconfig_error_add(const char *, va_list);
|
|
staticfn FILE *fopen_config_file(const char *, int);
|
|
staticfn int get_uchars(char *, uchar *, boolean, int, const char *);
|
|
#ifdef NOCWD_ASSUMPTIONS
|
|
staticfn void adjust_prefix(char *, int);
|
|
#endif
|
|
staticfn char *choose_random_part(char *, char);
|
|
staticfn boolean config_error_nextline(const char *);
|
|
staticfn void free_config_sections(void);
|
|
staticfn char *is_config_section(char *);
|
|
staticfn boolean handle_config_section(char *);
|
|
boolean parse_config_line(char *);
|
|
staticfn char *find_optparam(char *);
|
|
#ifdef WIN32
|
|
staticfn boolean portable_sysconf_only_this_statement(int);
|
|
#endif
|
|
#ifndef SFCTOOL
|
|
staticfn boolean cnf_line_OPTIONS(char *);
|
|
staticfn boolean cnf_line_AUTOPICKUP_EXCEPTION(char *);
|
|
staticfn boolean cnf_line_BINDINGS(char *);
|
|
staticfn boolean cnf_line_AUTOCOMPLETE(char *);
|
|
staticfn boolean cnf_line_MSGTYPE(char *);
|
|
staticfn boolean cnf_line_HACKDIR(char *);
|
|
staticfn boolean cnf_line_LEVELDIR(char *);
|
|
staticfn boolean cnf_line_SAVEDIR(char *);
|
|
staticfn boolean cnf_line_BONESDIR(char *);
|
|
staticfn boolean cnf_line_DATADIR(char *);
|
|
staticfn boolean cnf_line_SCOREDIR(char *);
|
|
staticfn boolean cnf_line_LOCKDIR(char *);
|
|
staticfn boolean cnf_line_CONFIGDIR(char *);
|
|
staticfn boolean cnf_line_TROUBLEDIR(char *);
|
|
staticfn boolean cnf_line_NAME(char *);
|
|
staticfn boolean cnf_line_ROLE(char *);
|
|
staticfn boolean cnf_line_dogname(char *);
|
|
staticfn boolean cnf_line_catname(char *);
|
|
#endif /* SFCTOOL */
|
|
#ifdef SYSCF
|
|
staticfn boolean cnf_line_WIZARDS(char *);
|
|
staticfn boolean cnf_line_SHELLERS(char *);
|
|
staticfn boolean cnf_line_MSGHANDLER(char *);
|
|
staticfn boolean cnf_line_EXPLORERS(char *);
|
|
staticfn boolean cnf_line_DEBUGFILES(char *);
|
|
staticfn boolean cnf_line_DUMPLOGFILE(char *);
|
|
staticfn boolean cnf_line_GENERICUSERS(char *);
|
|
staticfn boolean cnf_line_BONES_POOLS(char *);
|
|
staticfn boolean cnf_line_SUPPORT(char *);
|
|
staticfn boolean cnf_line_RECOVER(char *);
|
|
staticfn boolean cnf_line_CHECK_SAVE_UID(char *);
|
|
staticfn boolean cnf_line_CHECK_PLNAME(char *);
|
|
staticfn boolean cnf_line_SEDUCE(char *);
|
|
staticfn boolean cnf_line_HIDEUSAGE(char *);
|
|
staticfn boolean cnf_line_MAXPLAYERS(char *);
|
|
staticfn boolean cnf_line_MAX_REROLL_RATE(char *);
|
|
staticfn boolean cnf_line_PERSMAX(char *);
|
|
staticfn boolean cnf_line_PERS_IS_UID(char *);
|
|
staticfn boolean cnf_line_ENTRYMAX(char *);
|
|
staticfn boolean cnf_line_POINTSMIN(char *);
|
|
staticfn boolean cnf_line_MAX_STATUENAME_RANK(char *);
|
|
staticfn boolean cnf_line_LIVELOG(char *);
|
|
staticfn boolean cnf_line_PANICTRACE_LIBC(char *);
|
|
staticfn boolean cnf_line_PANICTRACE_GDB(char *);
|
|
staticfn boolean cnf_line_GDBPATH(char *);
|
|
staticfn boolean cnf_line_GREPPATH(char *);
|
|
staticfn boolean cnf_line_CRASHREPORTURL(char *);
|
|
staticfn boolean cnf_line_ACCESSIBILITY(char *);
|
|
|
|
staticfn boolean cnf_line_PORTABLE_DEVICE_PATHS(char *);
|
|
#endif /* SYSCF */
|
|
#ifndef SFCTOOL
|
|
staticfn boolean cnf_line_BOULDER(char *);
|
|
staticfn boolean cnf_line_MENUCOLOR(char *);
|
|
staticfn boolean cnf_line_HILITE_STATUS(char *);
|
|
staticfn boolean cnf_line_WARNINGS(char *);
|
|
staticfn boolean cnf_line_ROGUESYMBOLS(char *);
|
|
staticfn boolean cnf_line_SYMBOLS(char *);
|
|
staticfn boolean cnf_line_WIZKIT(char *);
|
|
#ifdef USER_SOUNDS
|
|
staticfn boolean cnf_line_SOUNDDIR(char *);
|
|
staticfn boolean cnf_line_SOUND(char *);
|
|
#endif
|
|
staticfn boolean cnf_line_QT_TILEWIDTH(char *);
|
|
staticfn boolean cnf_line_QT_TILEHEIGHT(char *);
|
|
staticfn boolean cnf_line_QT_FONTSIZE(char *);
|
|
staticfn boolean cnf_line_QT_COMPACT(char *);
|
|
#endif /* SFCTOOL */
|
|
struct _cnf_parser_state; /* defined below (far below...) */
|
|
staticfn void cnf_parser_init(struct _cnf_parser_state *parser);
|
|
staticfn void cnf_parser_done(struct _cnf_parser_state *parser);
|
|
staticfn void parse_conf_buf(struct _cnf_parser_state *parser,
|
|
boolean (*proc)(char *arg));
|
|
/* next one is in extern.h; why here too? */
|
|
boolean parse_conf_str(const char *str, boolean (*proc)(char *arg));
|
|
static boolean ignore_errors_on_unmatched = FALSE,
|
|
ignore_statement_errors = FALSE;
|
|
|
|
#ifdef SFCTOOL
|
|
#ifdef wait_synch
|
|
#undef wait_synch
|
|
#endif
|
|
#define wait_synch()
|
|
#endif /* SFCTOOL */
|
|
|
|
/* ---------- BEGIN CONFIG FILE HANDLING ----------- */
|
|
|
|
/* used for messaging. Also used in options.c */
|
|
static const char *default_configfile =
|
|
#ifdef UNIX
|
|
".nethackrc";
|
|
#else
|
|
#if defined(MACOS9) || defined(__BEOS__)
|
|
"NetHack Defaults";
|
|
#else
|
|
#if defined(MSDOS) || defined(WIN32)
|
|
CONFIG_FILE;
|
|
#else
|
|
"NetHack.cnf";
|
|
#endif
|
|
#endif
|
|
#endif
|
|
static char configfile[BUFSZ];
|
|
|
|
char *
|
|
get_configfile(void)
|
|
{
|
|
return configfile;
|
|
}
|
|
|
|
const char *
|
|
get_default_configfile(void)
|
|
{
|
|
return default_configfile;
|
|
}
|
|
|
|
#ifdef MSDOS
|
|
/* conflict with speed-dial under windows
|
|
* for XXX.cnf file so support of NetHack.cnf
|
|
* is for backward compatibility only.
|
|
* Preferred name (and first tried) is now defaults.nh but
|
|
* the game will try the old name if there
|
|
* is no defaults.nh.
|
|
*/
|
|
const char *backward_compat_configfile = "nethack.cnf";
|
|
#endif
|
|
|
|
#ifndef SFCTOOL
|
|
|
|
/* #saveoptions - save config options into file */
|
|
int
|
|
do_write_config_file(void)
|
|
{
|
|
FILE *fp;
|
|
char tmp[BUFSZ];
|
|
|
|
if (!configfile[0]) {
|
|
pline("Strange, could not figure out config file name.");
|
|
return ECMD_OK;
|
|
}
|
|
if (flags.suppress_alert < FEATURE_NOTICE_VER(3,7,0)) {
|
|
pline("Warning: saveoptions is highly experimental!");
|
|
wait_synch();
|
|
pline("Some settings are not saved!");
|
|
wait_synch();
|
|
pline("All manual customization and comments are removed"
|
|
" from the file!");
|
|
wait_synch();
|
|
}
|
|
#define overwrite_prompt "Overwrite config file %.*s?"
|
|
Sprintf(tmp, overwrite_prompt,
|
|
(int) (BUFSZ - sizeof overwrite_prompt - 2), configfile);
|
|
#undef overwrite_prompt
|
|
if (!paranoid_query(TRUE, tmp))
|
|
return ECMD_OK;
|
|
|
|
fp = fopen(configfile, "w");
|
|
if (fp) {
|
|
size_t len, wrote;
|
|
strbuf_t buf;
|
|
|
|
strbuf_init(&buf);
|
|
all_options_strbuf(&buf);
|
|
len = strlen(buf.str);
|
|
wrote = fwrite(buf.str, 1, len, fp);
|
|
fclose(fp);
|
|
strbuf_empty(&buf);
|
|
if (wrote != len)
|
|
pline("An error occurred, wrote only partial data (%zu/%zu).",
|
|
wrote, len);
|
|
}
|
|
return ECMD_OK;
|
|
}
|
|
#endif /* SFCTOOL */
|
|
|
|
/* remember the name of the file we're accessing;
|
|
if may be used in option reject messages */
|
|
void
|
|
set_configfile_name(const char *fname)
|
|
{
|
|
(void) strncpy(configfile, fname, sizeof configfile - 1);
|
|
configfile[sizeof configfile - 1] = '\0';
|
|
}
|
|
|
|
staticfn FILE *
|
|
fopen_config_file(const char *filename, int src)
|
|
{
|
|
FILE *fp;
|
|
#if defined(UNIX) || defined(VMS)
|
|
char tmp_config[BUFSZ];
|
|
char *envp;
|
|
#endif
|
|
|
|
if (src == set_in_sysconf) {
|
|
/* SYSCF_FILE; if we can't open it, caller will bail */
|
|
if (filename && *filename) {
|
|
set_configfile_name(fqname(filename, SYSCONFPREFIX, 0));
|
|
fp = fopen(configfile, "r");
|
|
} else
|
|
fp = (FILE *) 0;
|
|
return fp;
|
|
}
|
|
/* If src != set_in_sysconf, "filename" is an environment variable, so it
|
|
* should hang around. If set, it is expected to be a full path name
|
|
* (if relevant)
|
|
*/
|
|
if (filename && *filename) {
|
|
set_configfile_name(filename);
|
|
#ifdef UNIX
|
|
if (!strncmp(configfile, "~/", 2) && (envp = nh_getenv("HOME")) != 0) {
|
|
/* support for command line '--nethackrc=~/path' (or for
|
|
NETHACKOPTIONS='@~/path'; we don't support ~user/path) */
|
|
Snprintf(tmp_config, sizeof tmp_config, "%s/%s",
|
|
envp, configfile + 2); /* insert $HOME/ and remove ~/ */
|
|
set_configfile_name(tmp_config);
|
|
}
|
|
if (access(configfile, 4) == -1) { /* 4 is R_OK on newer systems */
|
|
/* nasty sneaky attempt to read file through
|
|
* NetHack's setuid permissions -- this is the only
|
|
* place a file name may be wholly under the player's
|
|
* control (but SYSCF_FILE is not under the player's
|
|
* control so it's OK).
|
|
*/
|
|
raw_printf("Access to %s denied (%d).", configfile, errno);
|
|
wait_synch();
|
|
/* fall through to standard names */
|
|
} else
|
|
#endif
|
|
if ((fp = fopen(configfile, "r")) != (FILE *) 0) {
|
|
return fp;
|
|
#if defined(UNIX) || defined(VMS)
|
|
} else {
|
|
/* access() above probably caught most problems for UNIX */
|
|
raw_printf("Couldn't open requested config file %s (%d).",
|
|
configfile, errno);
|
|
wait_synch();
|
|
#endif
|
|
}
|
|
}
|
|
/* fall through to standard names */
|
|
|
|
#if defined(MICRO) || defined(MACOS9) || defined(__BEOS__) || defined(WIN32)
|
|
set_configfile_name(fqname(default_configfile, CONFIGPREFIX, 0));
|
|
if ((fp = fopen(configfile, "r")) != (FILE *) 0) {
|
|
return fp;
|
|
} else if (strcmp(default_configfile, configfile)) {
|
|
set_configfile_name(default_configfile);
|
|
if ((fp = fopen(configfile, "r")) != (FILE *) 0)
|
|
return fp;
|
|
}
|
|
#ifdef MSDOS
|
|
set_configfile_name(fqname(backward_compat_configfile, CONFIGPREFIX, 0));
|
|
if ((fp = fopen(configfile, "r")) != (FILE *) 0) {
|
|
return fp;
|
|
} else if (strcmp(backward_compat_configfile, configfile)) {
|
|
set_configfile_name(backward_compat_configfile);
|
|
if ((fp = fopen(configfile, "r")) != (FILE *) 0)
|
|
return fp;
|
|
}
|
|
#endif
|
|
#else
|
|
/* constructed full path names don't need fqname() */
|
|
#ifdef VMS
|
|
/* no punctuation, so might be a logical name */
|
|
set_configfile_name("nethackini");
|
|
if ((fp = fopen(configfile, "r")) != (FILE *) 0)
|
|
return fp;
|
|
set_configfile_name("sys$login:nethack.ini");
|
|
if ((fp = fopen(configfile, "r")) != (FILE *) 0)
|
|
return fp;
|
|
|
|
envp = nh_getenv("HOME");
|
|
if (!envp || !*envp)
|
|
Strcpy(tmp_config, "NetHack.cnf");
|
|
else
|
|
Sprintf(tmp_config, "%s%s%s", envp,
|
|
!strchr(":]>/", envp[strlen(envp) - 1]) ? "/" : "",
|
|
"NetHack.cnf");
|
|
set_configfile_name(tmp_config);
|
|
if ((fp = fopen(configfile, "r")) != (FILE *) 0)
|
|
return fp;
|
|
#else /* should be only UNIX left */
|
|
envp = nh_getenv("HOME");
|
|
if (!envp)
|
|
Strcpy(tmp_config, ".nethackrc");
|
|
else
|
|
Sprintf(tmp_config, "%s/%s", envp, ".nethackrc");
|
|
|
|
set_configfile_name(tmp_config);
|
|
if ((fp = fopen(configfile, "r")) != (FILE *) 0)
|
|
return fp;
|
|
#if defined(__APPLE__) /* UNIX+__APPLE__ => OSX || MacOS */
|
|
/* try an alternative */
|
|
if (envp) {
|
|
/* keep 'tmp_config' intact here; if alternates fail, use it to
|
|
restore configfile[] to its preferred setting (".nethackrc") */
|
|
char alt_config[sizeof tmp_config];
|
|
|
|
/* OSX-style configuration settings */
|
|
Snprintf(alt_config, sizeof alt_config, "%s/%s", envp,
|
|
"Library/Preferences/NetHack Defaults");
|
|
set_configfile_name(alt_config);
|
|
if ((fp = fopen(configfile, "r")) != (FILE *) 0)
|
|
return fp;
|
|
/* may be easier for user to edit if filename has '.txt' suffix */
|
|
Snprintf(alt_config, sizeof alt_config, "%s/%s", envp,
|
|
"Library/Preferences/NetHack Defaults.txt");
|
|
set_configfile_name(alt_config);
|
|
if ((fp = fopen(configfile, "r")) != (FILE *) 0)
|
|
return fp;
|
|
/* couldn't open either of the alternate names; for use in
|
|
messages, put 'configfile' back to the normal value rather than
|
|
leaving it set to last alternate; retry open() to reset 'errno' */
|
|
set_configfile_name(tmp_config);
|
|
if ((fp = fopen(configfile, "r")) != (FILE *) 0)
|
|
return fp;
|
|
}
|
|
#endif /*__APPLE__*/
|
|
if (errno != ENOENT) {
|
|
const char *details;
|
|
|
|
/* e.g., problems when setuid NetHack can't search home
|
|
directory restricted to user */
|
|
#if defined(NHSTDC) && !defined(NOTSTDC)
|
|
if ((details = strerror(errno)) == 0)
|
|
#endif
|
|
details = "";
|
|
raw_printf("Couldn't open default config file %s %s(%d).",
|
|
configfile, details, errno);
|
|
wait_synch();
|
|
}
|
|
#endif /* !VMS => Unix */
|
|
#endif /* !(MICRO || MACOS9 || __BEOS__ || WIN32) */
|
|
return (FILE *) 0;
|
|
}
|
|
|
|
/*
|
|
* Retrieve a list of integers from buf into a uchar array.
|
|
*
|
|
* NOTE: zeros are inserted unless modlist is TRUE, in which case the list
|
|
* location is unchanged. Callers must handle zeros if modlist is FALSE.
|
|
*/
|
|
staticfn int
|
|
get_uchars(char *bufp, /* current pointer */
|
|
uchar *list, /* return list */
|
|
boolean modlist, /* TRUE: list is being modified in place */
|
|
int size, /* return list size */
|
|
const char *name) /* name of option for error message */
|
|
{
|
|
unsigned int num = 0;
|
|
int count = 0;
|
|
boolean havenum = FALSE;
|
|
|
|
while (1) {
|
|
switch (*bufp) {
|
|
case ' ':
|
|
case '\0':
|
|
case '\t':
|
|
case '\n':
|
|
if (havenum) {
|
|
/* if modifying in place, don't insert zeros */
|
|
if (num || !modlist)
|
|
list[count] = num;
|
|
count++;
|
|
num = 0;
|
|
havenum = FALSE;
|
|
}
|
|
if (count == size || !*bufp)
|
|
return count;
|
|
bufp++;
|
|
break;
|
|
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
havenum = TRUE;
|
|
num = num * 10 + (*bufp - '0');
|
|
bufp++;
|
|
break;
|
|
|
|
case '\\':
|
|
goto gi_error;
|
|
break;
|
|
|
|
default:
|
|
gi_error:
|
|
raw_printf("Syntax error in %s", name);
|
|
wait_synch();
|
|
return count;
|
|
}
|
|
}
|
|
/*NOTREACHED*/
|
|
}
|
|
|
|
#ifdef NOCWD_ASSUMPTIONS
|
|
staticfn void
|
|
adjust_prefix(char *bufp, int prefixid)
|
|
{
|
|
char *ptr;
|
|
|
|
if (!bufp)
|
|
return;
|
|
#ifdef WIN32
|
|
if (fqn_prefix_locked[prefixid])
|
|
return;
|
|
#endif
|
|
/* Backward compatibility, ignore trailing ;n */
|
|
if ((ptr = strchr(bufp, ';')) != 0)
|
|
*ptr = '\0';
|
|
if (strlen(bufp) > 0) {
|
|
gf.fqn_prefix[prefixid] = (char *) alloc(strlen(bufp) + 2);
|
|
Strcpy(gf.fqn_prefix[prefixid], bufp);
|
|
append_slash(gf.fqn_prefix[prefixid]);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* Choose at random one of the sep separated parts from str. Mangles str. */
|
|
staticfn char *
|
|
choose_random_part(char *str, char sep)
|
|
{
|
|
int nsep = 1;
|
|
int csep;
|
|
int len = 0;
|
|
char *begin = str;
|
|
|
|
if (!str)
|
|
return (char *) 0;
|
|
|
|
while (*str) {
|
|
if (*str == sep)
|
|
nsep++;
|
|
str++;
|
|
}
|
|
#ifndef SFCTOOL
|
|
csep = rn2(nsep);
|
|
#else
|
|
nhUse(nsep);
|
|
csep = 1;
|
|
#endif
|
|
str = begin;
|
|
while ((csep > 0) && *str) {
|
|
str++;
|
|
if (*str == sep)
|
|
csep--;
|
|
}
|
|
if (*str) {
|
|
if (*str == sep)
|
|
str++;
|
|
begin = str;
|
|
while (*str && *str != sep) {
|
|
str++;
|
|
len++;
|
|
}
|
|
*str = '\0';
|
|
if (len)
|
|
return begin;
|
|
}
|
|
return (char *) 0;
|
|
}
|
|
|
|
staticfn void
|
|
free_config_sections(void)
|
|
{
|
|
if (gc.config_section_chosen) {
|
|
free(gc.config_section_chosen);
|
|
gc.config_section_chosen = NULL;
|
|
}
|
|
if (gc.config_section_current) {
|
|
free(gc.config_section_current);
|
|
gc.config_section_current = NULL;
|
|
}
|
|
}
|
|
|
|
/* check for " [ anything-except-bracket-or-empty ] # arbitrary-comment"
|
|
with spaces optional; returns pointer to "anything-except..." (with
|
|
trailing " ] #..." stripped) if ok, otherwise Null */
|
|
staticfn char *
|
|
is_config_section(
|
|
char *str) /* trailing spaces are stripped, ']' too iff result is good */
|
|
{
|
|
char *a, *c, *z;
|
|
|
|
/* remove any spaces at start and end; won't significantly interfere
|
|
with echoing the string in a config error message, if warranted */
|
|
a = trimspaces(str);
|
|
/* first character should be open square bracket; set pointer past it */
|
|
if (*a++ != '[')
|
|
return (char *) 0;
|
|
/* last character should be close bracket, ignoring any comment */
|
|
z = strchr(a, ']');
|
|
if (!z)
|
|
return (char *) 0;
|
|
/* comment, if present, can be preceded by spaces */
|
|
for (c = z + 1; *c == ' '; ++c)
|
|
continue;
|
|
if (*c && *c != '#')
|
|
return (char *) 0;
|
|
/* we now know that result is good; there won't be a config error
|
|
message so we can modify the input string */
|
|
*z = '\0';
|
|
/* 'a' points past '[' and the string ends where ']' was; remove any
|
|
spaces between '[' and choice-start and between choice-end and ']' */
|
|
return trimspaces(a);
|
|
}
|
|
|
|
staticfn boolean
|
|
handle_config_section(char *buf)
|
|
{
|
|
char *sect = is_config_section(buf);
|
|
|
|
if (sect) {
|
|
if (gc.config_section_current)
|
|
free(gc.config_section_current), gc.config_section_current = 0;
|
|
/* is_config_section() removed brackets from 'sect' */
|
|
if (!gc.config_section_chosen) {
|
|
config_error_add("Section \"[%s]\" without CHOOSE", sect);
|
|
return TRUE;
|
|
}
|
|
if (*sect) { /* got a section name */
|
|
gc.config_section_current = dupstr(sect);
|
|
debugpline1("set config section: '%s'",
|
|
gc.config_section_current);
|
|
} else { /* empty section name => end of sections */
|
|
free_config_sections();
|
|
debugpline0("unset config section");
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
if (gc.config_section_current) {
|
|
if (!gc.config_section_chosen)
|
|
return TRUE;
|
|
if (strcmp(gc.config_section_current, gc.config_section_chosen))
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
#define match_varname(INP, NAM, LEN) match_optname(INP, NAM, LEN, TRUE)
|
|
|
|
/* find the '=' or ':' */
|
|
staticfn char *
|
|
find_optparam(char *buf)
|
|
{
|
|
char *bufp, *altp;
|
|
|
|
bufp = strchr(buf, '=');
|
|
altp = strchr(buf, ':');
|
|
if (!bufp || (altp && altp < bufp))
|
|
bufp = altp;
|
|
|
|
return bufp;
|
|
}
|
|
|
|
#ifndef SFCTOOL
|
|
|
|
staticfn boolean
|
|
cnf_line_OPTIONS(char *origbuf)
|
|
{
|
|
char *bufp = find_optparam(origbuf);
|
|
|
|
++bufp; /* skip '='; parseoptions() handles spaces */
|
|
return parseoptions(bufp, TRUE, TRUE);
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_AUTOPICKUP_EXCEPTION(char *bufp)
|
|
{
|
|
add_autopickup_exception(bufp);
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_BINDINGS(char *bufp)
|
|
{
|
|
return parsebindings(bufp);
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_AUTOCOMPLETE(char *bufp)
|
|
{
|
|
parseautocomplete(bufp, TRUE);
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_MSGTYPE(char *bufp)
|
|
{
|
|
return msgtype_parse_add(bufp);
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_HACKDIR(char *bufp)
|
|
{
|
|
#ifdef NOCWD_ASSUMPTIONS
|
|
adjust_prefix(bufp, HACKPREFIX);
|
|
#else /*NOCWD_ASSUMPTIONS*/
|
|
#ifdef MICRO
|
|
(void) strncpy(gh.hackdir, bufp, PATHLEN - 1);
|
|
#else /* MICRO */
|
|
nhUse(bufp);
|
|
#endif /* MICRO */
|
|
#endif /*NOCWD_ASSUMPTIONS*/
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_LEVELDIR(char *bufp)
|
|
{
|
|
#ifdef NOCWD_ASSUMPTIONS
|
|
adjust_prefix(bufp, LEVELPREFIX);
|
|
#else /*NOCWD_ASSUMPTIONS*/
|
|
#ifdef MICRO
|
|
if (strlen(bufp) >= PATHLEN)
|
|
bufp[PATHLEN - 1] = '\0';
|
|
Strcpy(g.permbones, bufp);
|
|
if (!ramdisk_specified || !*levels)
|
|
Strcpy(levels, bufp);
|
|
gr.ramdisk = (strcmp(g.permbones, levels) != 0);
|
|
#else /* MICRO */
|
|
nhUse(bufp);
|
|
#endif /* MICRO */
|
|
#endif /*NOCWD_ASSUMPTIONS*/
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_SAVEDIR(char *bufp)
|
|
{
|
|
#ifdef NOCWD_ASSUMPTIONS
|
|
adjust_prefix(bufp, SAVEPREFIX);
|
|
#else /*NOCWD_ASSUMPTIONS*/
|
|
#ifdef MICRO
|
|
char *ptr;
|
|
|
|
if ((ptr = strchr(bufp, ';')) != 0) {
|
|
*ptr = '\0';
|
|
}
|
|
|
|
(void) strncpy(gs.SAVEP, bufp, SAVESIZE - 1);
|
|
append_slash(gs.SAVEP);
|
|
#else /* MICRO */
|
|
nhUse(bufp);
|
|
#endif /* MICRO */
|
|
#endif /*NOCWD_ASSUMPTIONS*/
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_BONESDIR(char *bufp)
|
|
{
|
|
#ifdef NOCWD_ASSUMPTIONS
|
|
adjust_prefix(bufp, BONESPREFIX);
|
|
#else
|
|
nhUse(bufp);
|
|
#endif
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_DATADIR(char *bufp)
|
|
{
|
|
#ifdef NOCWD_ASSUMPTIONS
|
|
adjust_prefix(bufp, DATAPREFIX);
|
|
#else
|
|
nhUse(bufp);
|
|
#endif
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_SCOREDIR(char *bufp)
|
|
{
|
|
#ifdef NOCWD_ASSUMPTIONS
|
|
adjust_prefix(bufp, SCOREPREFIX);
|
|
#else
|
|
nhUse(bufp);
|
|
#endif
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_LOCKDIR(char *bufp)
|
|
{
|
|
#ifdef NOCWD_ASSUMPTIONS
|
|
adjust_prefix(bufp, LOCKPREFIX);
|
|
#else
|
|
nhUse(bufp);
|
|
#endif
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_CONFIGDIR(char *bufp)
|
|
{
|
|
#ifdef NOCWD_ASSUMPTIONS
|
|
adjust_prefix(bufp, CONFIGPREFIX);
|
|
#else
|
|
nhUse(bufp);
|
|
#endif
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_TROUBLEDIR(char *bufp)
|
|
{
|
|
#ifdef NOCWD_ASSUMPTIONS
|
|
adjust_prefix(bufp, TROUBLEPREFIX);
|
|
#else
|
|
nhUse(bufp);
|
|
#endif
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_NAME(char *bufp)
|
|
{
|
|
(void) strncpy(svp.plname, bufp, PL_NSIZ - 1);
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_ROLE(char *bufp)
|
|
{
|
|
int len;
|
|
|
|
if ((len = str2role(bufp)) >= 0)
|
|
flags.initrole = len;
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_dogname(char *bufp)
|
|
{
|
|
(void) strncpy(gd.dogname, bufp, PL_PSIZ - 1);
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_catname(char *bufp)
|
|
{
|
|
(void) strncpy(gc.catname, bufp, PL_PSIZ - 1);
|
|
return TRUE;
|
|
}
|
|
#endif /* SFCTOOL */
|
|
|
|
#ifdef SYSCF
|
|
|
|
staticfn boolean
|
|
cnf_line_WIZARDS(char *bufp)
|
|
{
|
|
if (sysopt.wizards)
|
|
free((genericptr_t) sysopt.wizards);
|
|
sysopt.wizards = dupstr(bufp);
|
|
if (strlen(sysopt.wizards) && strcmp(sysopt.wizards, "*")) {
|
|
/* pre-format WIZARDS list now; it's displayed during a panic
|
|
and since that panic might be due to running out of memory,
|
|
we don't want to risk attempting to allocate any memory then */
|
|
if (sysopt.fmtd_wizard_list)
|
|
free((genericptr_t) sysopt.fmtd_wizard_list);
|
|
sysopt.fmtd_wizard_list = build_english_list(sysopt.wizards);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_SHELLERS(char *bufp)
|
|
{
|
|
if (sysopt.shellers)
|
|
free((genericptr_t) sysopt.shellers);
|
|
sysopt.shellers = dupstr(bufp);
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_MSGHANDLER(char *bufp)
|
|
{
|
|
if (sysopt.msghandler)
|
|
free((genericptr_t) sysopt.msghandler);
|
|
sysopt.msghandler = dupstr(bufp);
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_EXPLORERS(char *bufp)
|
|
{
|
|
if (sysopt.explorers)
|
|
free((genericptr_t) sysopt.explorers);
|
|
sysopt.explorers = dupstr(bufp);
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_DEBUGFILES(char *bufp)
|
|
{
|
|
/* might already have a vaule from getenv("DEBUGFILES");
|
|
if so, ignore this value from SYSCF */
|
|
if (!sysopt.env_dbgfl) {
|
|
if (sysopt.debugfiles)
|
|
free((genericptr_t) sysopt.debugfiles);
|
|
sysopt.debugfiles = dupstr(bufp);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_DUMPLOGFILE(char *bufp)
|
|
{
|
|
#ifdef DUMPLOG
|
|
if (sysopt.dumplogfile)
|
|
free((genericptr_t) sysopt.dumplogfile);
|
|
sysopt.dumplogfile = dupstr(bufp);
|
|
#else
|
|
nhUse(bufp);
|
|
#endif /*DUMPLOG*/
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_GENERICUSERS(char *bufp)
|
|
{
|
|
if (sysopt.genericusers)
|
|
free((genericptr_t) sysopt.genericusers);
|
|
sysopt.genericusers = dupstr(bufp);
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_BONES_POOLS(char *bufp)
|
|
{
|
|
/* max value of 10 guarantees (N % bones.pools) will be one digit
|
|
so we don't lose control of the length of bones file names */
|
|
int n = atoi(bufp);
|
|
|
|
sysopt.bones_pools = (n <= 0) ? 0 : min(n, 10);
|
|
/* note: right now bones_pools==0 is the same as bones_pools==1,
|
|
but we could change that and make bones_pools==0 become an
|
|
indicator to suppress bones usage altogether */
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_SUPPORT(char *bufp)
|
|
{
|
|
if (sysopt.support)
|
|
free((genericptr_t) sysopt.support);
|
|
sysopt.support = dupstr(bufp);
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_RECOVER(char *bufp)
|
|
{
|
|
if (sysopt.recover)
|
|
free((genericptr_t) sysopt.recover);
|
|
sysopt.recover = dupstr(bufp);
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_CHECK_SAVE_UID(char *bufp)
|
|
{
|
|
int n = atoi(bufp);
|
|
|
|
sysopt.check_save_uid = n;
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_CHECK_PLNAME(char *bufp)
|
|
{
|
|
int n = atoi(bufp);
|
|
|
|
sysopt.check_plname = n;
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_SEDUCE(char *bufp)
|
|
{
|
|
int n = !!atoi(bufp); /* XXX this could be tighter */
|
|
#ifdef SYSCF
|
|
int src = iflags.parse_config_file_src;
|
|
boolean in_sysconf = (src == set_in_sysconf);
|
|
#else
|
|
boolean in_sysconf = FALSE;
|
|
#endif
|
|
|
|
/* allow anyone to disable it but can only enable it in sysconf
|
|
or as a no-op for the user when sysconf hasn't disabled it */
|
|
if (!in_sysconf && !sysopt.seduce && n != 0) {
|
|
config_error_add("Illegal value in SEDUCE");
|
|
n = 0;
|
|
}
|
|
sysopt.seduce = n;
|
|
sysopt_seduce_set(sysopt.seduce);
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_HIDEUSAGE(char *bufp)
|
|
{
|
|
int n = !!atoi(bufp);
|
|
|
|
sysopt.hideusage = n;
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_MAXPLAYERS(char *bufp)
|
|
{
|
|
int n = atoi(bufp);
|
|
|
|
/* XXX to get more than 25, need to rewrite all lock code */
|
|
if (n < 0 || n > 25) {
|
|
config_error_add("Illegal value in MAXPLAYERS (maximum is 25)");
|
|
n = 5;
|
|
}
|
|
sysopt.maxplayers = n;
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_MAX_REROLL_RATE(char *bufp)
|
|
{
|
|
int n = atoi(bufp);
|
|
|
|
if (n < 0 || n > 255) {
|
|
config_error_add("Illegal value in MAX_REROLL_RATE (maximum is 255)");
|
|
n = 10;
|
|
}
|
|
sysopt.maxrerollrate = n;
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_PERSMAX(char *bufp)
|
|
{
|
|
int n = atoi(bufp);
|
|
|
|
if (n < 1) {
|
|
config_error_add("Illegal value in PERSMAX (minimum is 1)");
|
|
n = 0;
|
|
}
|
|
sysopt.persmax = n;
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_PERS_IS_UID(char *bufp)
|
|
{
|
|
int n = atoi(bufp);
|
|
|
|
if (n != 0 && n != 1) {
|
|
config_error_add("Illegal value in PERS_IS_UID (must be 0 or 1)");
|
|
n = 0;
|
|
}
|
|
sysopt.pers_is_uid = n;
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_ENTRYMAX(char *bufp)
|
|
{
|
|
int n = atoi(bufp);
|
|
|
|
if (n < 10) {
|
|
config_error_add("Illegal value in ENTRYMAX (minimum is 10)");
|
|
n = 10;
|
|
}
|
|
sysopt.entrymax = n;
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_POINTSMIN(char *bufp)
|
|
{
|
|
int n = atoi(bufp);
|
|
|
|
if (n < 1) {
|
|
config_error_add("Illegal value in POINTSMIN (minimum is 1)");
|
|
n = 100;
|
|
}
|
|
sysopt.pointsmin = n;
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_MAX_STATUENAME_RANK(char *bufp)
|
|
{
|
|
int n = atoi(bufp);
|
|
|
|
if (n < 1) {
|
|
config_error_add("Illegal value in MAX_STATUENAME_RANK"
|
|
" (minimum is 1)");
|
|
n = 10;
|
|
}
|
|
sysopt.tt_oname_maxrank = n;
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_LIVELOG(char *bufp)
|
|
{
|
|
/* using 0 for base accepts "dddd" as decimal provided that first 'd'
|
|
isn't '0', "0xhhhh" as hexadecimal, and "0oooo" as octal; ignores
|
|
any trailing junk, including '8' or '9' for leading '0' octal */
|
|
long L = strtol(bufp, NULL, 0);
|
|
|
|
if (L < 0L || L > 0xffffL) {
|
|
config_error_add("Illegal value for LIVELOG"
|
|
" (must be between 0 and 0xFFFF).");
|
|
return 0;
|
|
}
|
|
sysopt.livelog = L;
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_PANICTRACE_LIBC(char *bufp)
|
|
{
|
|
int n = atoi(bufp);
|
|
|
|
#if defined(PANICTRACE) && defined(PANICTRACE_LIBC)
|
|
if (n < 0 || n > 2) {
|
|
config_error_add("Illegal value in PANICTRACE_LIBC (not 0,1,2)");
|
|
n = 0;
|
|
}
|
|
#endif
|
|
sysopt.panictrace_libc = n;
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_PANICTRACE_GDB(char *bufp)
|
|
{
|
|
int n = atoi(bufp);
|
|
|
|
#if defined(PANICTRACE)
|
|
if (n < 0 || n > 2) {
|
|
config_error_add("Illegal value in PANICTRACE_GDB (not 0,1,2)");
|
|
n = 0;
|
|
}
|
|
#endif
|
|
sysopt.panictrace_gdb = n;
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_GDBPATH(char *bufp)
|
|
{
|
|
#if defined(PANICTRACE) && !defined(VMS)
|
|
if (!file_exists(bufp)) {
|
|
config_error_add("File specified in GDBPATH does not exist");
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
if (sysopt.gdbpath)
|
|
free((genericptr_t) sysopt.gdbpath);
|
|
sysopt.gdbpath = dupstr(bufp);
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_GREPPATH(char *bufp)
|
|
{
|
|
#if defined(PANICTRACE) && !defined(VMS)
|
|
if (!file_exists(bufp)) {
|
|
config_error_add("File specified in GREPPATH does not exist");
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
if (sysopt.greppath)
|
|
free((genericptr_t) sysopt.greppath);
|
|
sysopt.greppath = dupstr(bufp);
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_CRASHREPORTURL(char *bufp)
|
|
{
|
|
if (sysopt.crashreporturl)
|
|
free((genericptr_t) sysopt.crashreporturl);
|
|
sysopt.crashreporturl = dupstr(bufp);
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_ACCESSIBILITY(char *bufp)
|
|
{
|
|
int n = atoi(bufp);
|
|
|
|
if (n < 0 || n > 1) {
|
|
config_error_add("Illegal value in ACCESSIBILITY (not 0,1)");
|
|
n = 0;
|
|
}
|
|
sysopt.accessibility = n;
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_PORTABLE_DEVICE_PATHS(char *bufp)
|
|
{
|
|
#ifdef WIN32
|
|
int n = atoi(bufp);
|
|
|
|
if (n < 0 || n > 1) {
|
|
config_error_add("Illegal value in PORTABLE_DEVICE_PATHS"
|
|
" (not 0 or 1)");
|
|
n = 0;
|
|
}
|
|
sysopt.portable_device_paths = n;
|
|
#else /* Windows-only directive encountered by non-Windows config */
|
|
nhUse(bufp);
|
|
config_error_add("PORTABLE_DEVICE_PATHS is not supported");
|
|
#endif
|
|
return TRUE;
|
|
}
|
|
#endif /* SYSCF */
|
|
|
|
#ifndef SFCTOOL
|
|
|
|
staticfn boolean
|
|
cnf_line_BOULDER(char *bufp)
|
|
{
|
|
(void) get_uchars(bufp, &go.ov_primary_syms[SYM_BOULDER + SYM_OFF_X],
|
|
TRUE, 1, "BOULDER");
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_MENUCOLOR(char *bufp)
|
|
{
|
|
return add_menu_coloring(bufp);
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_HILITE_STATUS(char *bufp)
|
|
{
|
|
#ifdef STATUS_HILITES
|
|
return parse_status_hl1(bufp, TRUE);
|
|
#else
|
|
nhUse(bufp);
|
|
return TRUE;
|
|
#endif
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_WARNINGS(char *bufp)
|
|
{
|
|
uchar translate[MAXPCHARS];
|
|
|
|
(void) get_uchars(bufp, translate, FALSE, WARNCOUNT, "WARNINGS");
|
|
assign_warnings(translate);
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_ROGUESYMBOLS(char *bufp)
|
|
{
|
|
if (parsesymbols(bufp, ROGUESET)) {
|
|
switch_symbols(TRUE);
|
|
return TRUE;
|
|
}
|
|
config_error_add("Error in ROGUESYMBOLS definition '%s'", bufp);
|
|
return FALSE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_SYMBOLS(char *bufp)
|
|
{
|
|
if (parsesymbols(bufp, PRIMARYSET)) {
|
|
switch_symbols(TRUE);
|
|
return TRUE;
|
|
}
|
|
if (!config_unmatched_ignored())
|
|
config_error_add("Error in SYMBOLS definition '%s'", bufp);
|
|
return FALSE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_WIZKIT(char *bufp)
|
|
{
|
|
(void) strncpy(gw.wizkit, bufp, WIZKIT_MAX - 1);
|
|
return TRUE;
|
|
}
|
|
|
|
#ifdef USER_SOUNDS
|
|
staticfn boolean
|
|
cnf_line_SOUNDDIR(char *bufp)
|
|
{
|
|
if (sounddir)
|
|
free((genericptr_t) sounddir);
|
|
sounddir = dupstr(bufp);
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_SOUND(char *bufp)
|
|
{
|
|
add_sound_mapping(bufp);
|
|
return TRUE;
|
|
}
|
|
#endif /*USER_SOUNDS*/
|
|
|
|
staticfn boolean
|
|
cnf_line_QT_TILEWIDTH(char *bufp)
|
|
{
|
|
#ifdef QT_GRAPHICS
|
|
extern char *qt_tilewidth;
|
|
|
|
if (qt_tilewidth == NULL)
|
|
qt_tilewidth = dupstr(bufp);
|
|
#else
|
|
nhUse(bufp);
|
|
#endif
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_QT_TILEHEIGHT(char *bufp)
|
|
{
|
|
#ifdef QT_GRAPHICS
|
|
extern char *qt_tileheight;
|
|
|
|
if (qt_tileheight == NULL)
|
|
qt_tileheight = dupstr(bufp);
|
|
#else
|
|
nhUse(bufp);
|
|
#endif
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_QT_FONTSIZE(char *bufp)
|
|
{
|
|
#ifdef QT_GRAPHICS
|
|
extern char *qt_fontsize;
|
|
|
|
if (qt_fontsize == NULL)
|
|
qt_fontsize = dupstr(bufp);
|
|
#else
|
|
nhUse(bufp);
|
|
#endif
|
|
return TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
cnf_line_QT_COMPACT(char *bufp)
|
|
{
|
|
#ifdef QT_GRAPHICS
|
|
extern int qt_compact_mode;
|
|
|
|
qt_compact_mode = atoi(bufp);
|
|
#else
|
|
nhUse(bufp);
|
|
#endif
|
|
return TRUE;
|
|
}
|
|
#endif /* SFCTOOL */
|
|
|
|
typedef boolean (*config_line_stmt_func)(char *);
|
|
|
|
/* normal */
|
|
#define CNFL_N(n, l) { #n, l, FALSE, FALSE, cnf_line_##n }
|
|
/* normal, alias */
|
|
#define CNFL_NA(n, l, f) { #n, l, FALSE, FALSE, cnf_line_##f }
|
|
/* sysconf only */
|
|
#define CNFL_S(n, l) { #n, l, TRUE, FALSE, cnf_line_##n }
|
|
|
|
static const struct match_config_line_stmt {
|
|
const char *name;
|
|
int len;
|
|
boolean syscnf_only;
|
|
boolean origbuf;
|
|
config_line_stmt_func fn;
|
|
} config_line_stmt[] = {
|
|
#ifndef SFCTOOL
|
|
/* OPTIONS handled separately */
|
|
{ "OPTIONS", 4, FALSE, TRUE, cnf_line_OPTIONS },
|
|
CNFL_N(AUTOPICKUP_EXCEPTION, 5),
|
|
CNFL_N(BINDINGS, 4),
|
|
CNFL_N(AUTOCOMPLETE, 5),
|
|
CNFL_N(MSGTYPE, 7),
|
|
CNFL_N(HACKDIR, 4),
|
|
CNFL_N(LEVELDIR, 4),
|
|
CNFL_NA(LEVELS, 4, LEVELDIR),
|
|
CNFL_N(SAVEDIR, 4),
|
|
CNFL_N(BONESDIR, 5),
|
|
CNFL_N(DATADIR, 4),
|
|
CNFL_N(SCOREDIR, 4),
|
|
CNFL_N(LOCKDIR, 4),
|
|
CNFL_N(CONFIGDIR, 4),
|
|
CNFL_N(TROUBLEDIR, 4),
|
|
CNFL_N(NAME, 4),
|
|
CNFL_N(ROLE, 4),
|
|
CNFL_NA(CHARACTER, 4, ROLE),
|
|
CNFL_N(dogname, 3),
|
|
CNFL_N(catname, 3),
|
|
#endif /* SFCTOOL */
|
|
#ifdef SYSCF
|
|
CNFL_S(WIZARDS, 7),
|
|
CNFL_S(SHELLERS, 8),
|
|
CNFL_S(MSGHANDLER, 9),
|
|
CNFL_S(EXPLORERS, 7),
|
|
CNFL_S(DEBUGFILES, 5),
|
|
CNFL_S(DUMPLOGFILE, 7),
|
|
CNFL_S(GENERICUSERS, 12),
|
|
CNFL_S(BONES_POOLS, 10),
|
|
CNFL_S(SUPPORT, 7),
|
|
CNFL_S(RECOVER, 7),
|
|
CNFL_S(CHECK_SAVE_UID, 14),
|
|
CNFL_S(CHECK_PLNAME, 12),
|
|
CNFL_S(SEDUCE, 6),
|
|
CNFL_S(HIDEUSAGE, 9),
|
|
CNFL_S(MAXPLAYERS, 10),
|
|
CNFL_S(MAX_REROLL_RATE, 10),
|
|
CNFL_S(PERSMAX, 7),
|
|
CNFL_S(PERS_IS_UID, 11),
|
|
CNFL_S(ENTRYMAX, 8),
|
|
CNFL_S(POINTSMIN, 9),
|
|
CNFL_S(MAX_STATUENAME_RANK, 10),
|
|
CNFL_S(LIVELOG, 7),
|
|
CNFL_S(PANICTRACE_LIBC, 15),
|
|
CNFL_S(PANICTRACE_GDB, 14),
|
|
CNFL_S(CRASHREPORTURL, 13),
|
|
CNFL_S(GDBPATH, 7),
|
|
CNFL_S(GREPPATH, 7),
|
|
CNFL_S(ACCESSIBILITY, 13),
|
|
CNFL_S(PORTABLE_DEVICE_PATHS, 8),
|
|
#endif /*SYSCF*/
|
|
#ifndef SFCTOOL
|
|
CNFL_N(BOULDER, 3),
|
|
CNFL_N(MENUCOLOR, 9),
|
|
CNFL_N(HILITE_STATUS, 6),
|
|
CNFL_N(WARNINGS, 5),
|
|
CNFL_N(ROGUESYMBOLS, 4),
|
|
CNFL_N(SYMBOLS, 4),
|
|
CNFL_N(WIZKIT, 6),
|
|
#ifdef USER_SOUNDS
|
|
CNFL_N(SOUNDDIR, 8),
|
|
CNFL_N(SOUND, 5),
|
|
#endif /*USER_SOUNDS*/
|
|
CNFL_N(QT_TILEWIDTH, 12),
|
|
CNFL_N(QT_TILEHEIGHT, 13),
|
|
CNFL_N(QT_FONTSIZE, 11),
|
|
CNFL_N(QT_COMPACT, 10)
|
|
#endif /* SFCTOOL */
|
|
};
|
|
|
|
#undef CNFL_N
|
|
#undef CNFL_NA
|
|
#undef CNFL_S
|
|
|
|
static boolean disregarded_config_lines[SIZE(config_line_stmt)];
|
|
|
|
boolean
|
|
parse_config_line(char *origbuf)
|
|
{
|
|
#if defined(MICRO) && !defined(NOCWD_ASSUMPTIONS)
|
|
static boolean ramdisk_specified = FALSE;
|
|
#endif
|
|
#ifdef SYSCF
|
|
int src = iflags.parse_config_file_src;
|
|
boolean in_sysconf = (src == set_in_sysconf);
|
|
#endif
|
|
char *bufp, buf[4 * BUFSZ];
|
|
int i;
|
|
|
|
while (*origbuf == ' ' || *origbuf == '\t') /* skip leading whitespace */
|
|
++origbuf; /* (caller probably already did this) */
|
|
(void) strncpy(buf, origbuf, sizeof buf - 1);
|
|
buf[sizeof buf - 1] = '\0'; /* strncpy not guaranteed to NUL terminate */
|
|
/* convert any tab to space, condense consecutive spaces into one,
|
|
remove leading and trailing spaces (exception: if there is nothing
|
|
but spaces, one of them will be kept even though it leads/trails) */
|
|
mungspaces(buf);
|
|
|
|
/* find the '=' or ':' */
|
|
bufp = find_optparam(buf);
|
|
if (!bufp) {
|
|
if (!ignore_statement_errors)
|
|
config_error_add("Not a config statement, missing '='");
|
|
return FALSE;
|
|
}
|
|
/* skip past '=', then space between it and value, if any */
|
|
++bufp;
|
|
if (*bufp == ' ')
|
|
++bufp;
|
|
|
|
for (i = 0; i < SIZE(config_line_stmt); i++) {
|
|
#ifdef SYSCF
|
|
if (config_line_stmt[i].syscnf_only && !in_sysconf)
|
|
continue;
|
|
#endif
|
|
if (match_varname(buf, config_line_stmt[i].name,
|
|
config_line_stmt[i].len)) {
|
|
char *parm = config_line_stmt[i].origbuf ? origbuf : bufp;
|
|
|
|
if (!disregarded_config_lines[i])
|
|
return config_line_stmt[i].fn(parm);
|
|
}
|
|
}
|
|
|
|
if (!ignore_errors_on_unmatched)
|
|
config_error_add("Unknown config statement");
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef USER_SOUNDS
|
|
boolean
|
|
can_read_file(const char *filename)
|
|
{
|
|
return (boolean) (access(filename, 4) == 0);
|
|
}
|
|
#endif /* USER_SOUNDS */
|
|
|
|
struct _config_error_errmsg {
|
|
int line_num;
|
|
char *errormsg;
|
|
struct _config_error_errmsg *next;
|
|
};
|
|
|
|
struct _config_error_frame {
|
|
int line_num;
|
|
int num_errors;
|
|
boolean origline_shown;
|
|
boolean fromfile;
|
|
boolean secure;
|
|
char origline[4 * BUFSZ];
|
|
char source[BUFSZ];
|
|
struct _config_error_frame *next;
|
|
};
|
|
|
|
static struct _config_error_frame *config_error_data = 0;
|
|
static struct _config_error_errmsg *config_error_msg = 0;
|
|
|
|
void
|
|
config_error_init(boolean from_file, const char *sourcename, boolean secure)
|
|
{
|
|
struct _config_error_frame *tmp = (struct _config_error_frame *)
|
|
alloc(sizeof *tmp);
|
|
|
|
tmp->line_num = 0;
|
|
tmp->num_errors = 0;
|
|
tmp->origline_shown = FALSE;
|
|
tmp->fromfile = from_file;
|
|
tmp->secure = secure;
|
|
tmp->origline[0] = '\0';
|
|
if (sourcename && sourcename[0]) {
|
|
(void) strncpy(tmp->source, sourcename, sizeof (tmp->source) - 1);
|
|
tmp->source[sizeof (tmp->source) - 1] = '\0';
|
|
} else
|
|
tmp->source[0] = '\0';
|
|
|
|
tmp->next = config_error_data;
|
|
config_error_data = tmp;
|
|
program_state.config_error_ready = TRUE;
|
|
}
|
|
|
|
staticfn boolean
|
|
config_error_nextline(const char *line)
|
|
{
|
|
struct _config_error_frame *ced = config_error_data;
|
|
|
|
if (!ced)
|
|
return FALSE;
|
|
|
|
if (ced->num_errors && ced->secure)
|
|
return FALSE;
|
|
|
|
ced->line_num++;
|
|
ced->origline_shown = FALSE;
|
|
if (line && line[0]) {
|
|
(void) strncpy(ced->origline, line, sizeof (ced->origline) - 1);
|
|
ced->origline[sizeof (ced->origline) - 1] = '\0';
|
|
} else
|
|
ced->origline[0] = '\0';
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#ifndef SFCTOOL
|
|
int
|
|
l_get_config_errors(lua_State *L)
|
|
{
|
|
struct _config_error_errmsg *dat = config_error_msg;
|
|
struct _config_error_errmsg *tmp;
|
|
int idx = 1;
|
|
|
|
lua_newtable(L);
|
|
|
|
while (dat) {
|
|
lua_pushinteger(L, idx++);
|
|
lua_newtable(L);
|
|
nhl_add_table_entry_int(L, "line", dat->line_num);
|
|
nhl_add_table_entry_str(L, "error", dat->errormsg);
|
|
lua_settable(L, -3);
|
|
tmp = dat->next;
|
|
free(dat->errormsg);
|
|
dat->errormsg = (char *) 0;
|
|
free(dat);
|
|
dat = tmp;
|
|
}
|
|
config_error_msg = (struct _config_error_errmsg *) 0;
|
|
|
|
return 1;
|
|
}
|
|
#endif /* SFCTOOL */
|
|
|
|
/* varargs 'config_error_add()' moved to pline.c */
|
|
void
|
|
config_erradd(const char *buf)
|
|
{
|
|
char lineno[QBUFSZ];
|
|
const char *punct;
|
|
|
|
if (!buf || !*buf)
|
|
buf = "Unknown error";
|
|
|
|
/* if buf[] doesn't end in a period, exclamation point, or question mark,
|
|
we'll include a period (in the message, not appended to buf[]) */
|
|
punct = c_eos((char *) buf) - 1; /* eos(buf)-1 is valid */
|
|
punct = strchr(".!?", *punct) ? "" : ".";
|
|
|
|
if (!program_state.config_error_ready) {
|
|
/* either very early, where pline() will use raw_print(), or
|
|
player gave bad value when prompted by interactive 'O' command */
|
|
pline("%s%s%s", !iflags.window_inited ? "config_error_add: " : "",
|
|
buf, punct);
|
|
wait_synch();
|
|
return;
|
|
}
|
|
|
|
if (iflags.in_lua) {
|
|
struct _config_error_errmsg *dat
|
|
= (struct _config_error_errmsg *) alloc(sizeof *dat);
|
|
|
|
dat->next = config_error_msg;
|
|
dat->line_num = config_error_data->line_num;
|
|
dat->errormsg = dupstr(buf);
|
|
config_error_msg = dat;
|
|
return;
|
|
}
|
|
|
|
config_error_data->num_errors++;
|
|
if (!config_error_data->origline_shown && !config_error_data->secure) {
|
|
pline("\n%s", config_error_data->origline);
|
|
config_error_data->origline_shown = TRUE;
|
|
}
|
|
if (config_error_data->line_num > 0 && !config_error_data->secure) {
|
|
Sprintf(lineno, "Line %d: ", config_error_data->line_num);
|
|
} else
|
|
lineno[0] = '\0';
|
|
|
|
pline("%s %s%s%s", config_error_data->secure ? "Error:" : " *",
|
|
lineno, buf, punct);
|
|
}
|
|
|
|
int
|
|
config_error_done(void)
|
|
{
|
|
int n;
|
|
struct _config_error_frame *tmp = config_error_data;
|
|
|
|
if (!config_error_data)
|
|
return 0;
|
|
n = config_error_data->num_errors;
|
|
#ifndef USER_SOUNDS
|
|
if (gn.no_sound_notified > 0) {
|
|
/* no USER_SOUNDS; config_error_add() was called once for first
|
|
SOUND or SOUNDDIR entry seen, then skipped for any others;
|
|
include those skipped ones in the total error count */
|
|
n += (gn.no_sound_notified - 1);
|
|
gn.no_sound_notified = 0;
|
|
}
|
|
#endif
|
|
if (n) {
|
|
boolean cmdline = !strcmp(config_error_data->source, "command line");
|
|
|
|
pline("\n%d error%s %s %s.\n", n, plur(n), cmdline ? "on" : "in",
|
|
*config_error_data->source ? config_error_data->source
|
|
: configfile);
|
|
wait_synch();
|
|
}
|
|
config_error_data = tmp->next;
|
|
free(tmp);
|
|
program_state.config_error_ready = (config_error_data != 0);
|
|
return n;
|
|
}
|
|
|
|
boolean
|
|
read_config_file(const char *filename, int src)
|
|
{
|
|
FILE *fp;
|
|
boolean rv = TRUE;
|
|
|
|
if (!(fp = fopen_config_file(filename, src)))
|
|
return FALSE;
|
|
#ifndef SFCTOOL
|
|
/* begin detection of duplicate configfile options */
|
|
reset_duplicate_opt_detection();
|
|
#endif /* SFCTOOL */
|
|
free_config_sections();
|
|
iflags.parse_config_file_src = src;
|
|
|
|
rv = parse_conf_file(fp, parse_config_line);
|
|
(void) fclose(fp);
|
|
|
|
free_config_sections();
|
|
#ifndef SFCTOOL
|
|
/* turn off detection of duplicate configfile options */
|
|
reset_duplicate_opt_detection();
|
|
#endif /* SFCTOOL */
|
|
return rv;
|
|
}
|
|
|
|
struct _cnf_parser_state {
|
|
char *inbuf;
|
|
unsigned inbufsz;
|
|
int rv;
|
|
char *ep;
|
|
char *buf;
|
|
boolean skip, morelines;
|
|
boolean cont;
|
|
boolean pbreak;
|
|
};
|
|
|
|
/* Initialize config parser data */
|
|
staticfn void
|
|
cnf_parser_init(struct _cnf_parser_state *parser)
|
|
{
|
|
parser->rv = TRUE; /* assume successful parse */
|
|
parser->ep = parser->buf = (char *) 0;
|
|
parser->skip = FALSE;
|
|
parser->morelines = FALSE;
|
|
parser->inbufsz = 4 * BUFSZ;
|
|
parser->inbuf = (char *) alloc(parser->inbufsz);
|
|
parser->cont = FALSE;
|
|
parser->pbreak = FALSE;
|
|
memset(parser->inbuf, 0, parser->inbufsz);
|
|
}
|
|
|
|
/* caller has finished with 'parser' (except for 'rv' so leave that intact) */
|
|
staticfn void
|
|
cnf_parser_done(struct _cnf_parser_state *parser)
|
|
{
|
|
parser->ep = 0; /* points into parser->inbuf, so becoming stale */
|
|
if (parser->inbuf)
|
|
free(parser->inbuf), parser->inbuf = 0;
|
|
if (parser->buf)
|
|
free(parser->buf), parser->buf = 0;
|
|
}
|
|
|
|
/*
|
|
* Parse config buffer, handling comments, empty lines, config sections,
|
|
* CHOOSE, and line continuation, calling proc for every valid line.
|
|
*
|
|
* Continued lines are merged together with one space in between.
|
|
*/
|
|
staticfn void
|
|
parse_conf_buf(struct _cnf_parser_state *p, boolean (*proc)(char *arg))
|
|
{
|
|
p->cont = FALSE;
|
|
p->pbreak = FALSE;
|
|
p->ep = strchr(p->inbuf, '\n');
|
|
if (p->skip) { /* in case previous line was too long */
|
|
if (p->ep)
|
|
p->skip = FALSE; /* found newline; next line is normal */
|
|
} else {
|
|
if (!p->ep) { /* newline missing */
|
|
if (strlen(p->inbuf) < (p->inbufsz - 2)) {
|
|
/* likely the last line of file is just
|
|
missing a newline; process it anyway */
|
|
p->ep = eos(p->inbuf);
|
|
} else {
|
|
config_error_add("Line too long, skipping");
|
|
p->skip = TRUE; /* discard next fgets */
|
|
}
|
|
} else {
|
|
*p->ep = '\0'; /* remove newline */
|
|
}
|
|
if (p->ep) {
|
|
char *tmpbuf = (char *) 0;
|
|
int len;
|
|
boolean ignoreline = FALSE;
|
|
boolean oldline = FALSE;
|
|
|
|
/* line continuation (trailing '\') */
|
|
p->morelines = (--p->ep >= p->inbuf && *p->ep == '\\');
|
|
if (p->morelines)
|
|
*p->ep = '\0';
|
|
|
|
/* trim off spaces at end of line */
|
|
while (p->ep >= p->inbuf
|
|
&& (*p->ep == ' ' || *p->ep == '\t' || *p->ep == '\r'))
|
|
*p->ep-- = '\0';
|
|
|
|
if (!config_error_nextline(p->inbuf)) {
|
|
p->rv = FALSE;
|
|
if (p->buf)
|
|
free(p->buf), p->buf = (char *) 0;
|
|
p->pbreak = TRUE;
|
|
return;
|
|
}
|
|
|
|
p->ep = p->inbuf;
|
|
while (*p->ep == ' ' || *p->ep == '\t')
|
|
++p->ep;
|
|
|
|
/* ignore empty lines and full-line comment lines */
|
|
if (!*p->ep || *p->ep == '#')
|
|
ignoreline = TRUE;
|
|
|
|
if (p->buf)
|
|
oldline = TRUE;
|
|
|
|
/* merge now read line with previous ones, if necessary */
|
|
if (!ignoreline) {
|
|
len = (int) strlen(p->ep) + 1; /* +1: final '\0' */
|
|
if (p->buf)
|
|
len += (int) strlen(p->buf) + 1; /* +1: space */
|
|
tmpbuf = (char *) alloc(len);
|
|
*tmpbuf = '\0';
|
|
if (p->buf) {
|
|
Strcat(strcpy(tmpbuf, p->buf), " ");
|
|
free(p->buf), p->buf = 0;
|
|
}
|
|
p->buf = strcat(tmpbuf, p->ep);
|
|
if (strlen(p->buf) >= p->inbufsz)
|
|
p->buf[p->inbufsz - 1] = '\0';
|
|
}
|
|
|
|
if (p->morelines || (ignoreline && !oldline))
|
|
return;
|
|
|
|
if (handle_config_section(p->buf)) {
|
|
free(p->buf), p->buf = (char *) 0;
|
|
return;
|
|
}
|
|
|
|
/* from here onwards, we'll handle buf only */
|
|
|
|
if (match_varname(p->buf, "CHOOSE", 6)) {
|
|
char *section;
|
|
char *bufp = find_optparam(p->buf);
|
|
|
|
if (!bufp) {
|
|
config_error_add("Format is CHOOSE=section1"
|
|
",section2,...");
|
|
p->rv = FALSE;
|
|
free(p->buf), p->buf = (char *) 0;
|
|
return;
|
|
}
|
|
bufp++;
|
|
if (gc.config_section_chosen)
|
|
free(gc.config_section_chosen),
|
|
gc.config_section_chosen = 0;
|
|
section = choose_random_part(bufp, ',');
|
|
if (section) {
|
|
gc.config_section_chosen = dupstr(section);
|
|
} else {
|
|
config_error_add("No config section to choose");
|
|
p->rv = FALSE;
|
|
}
|
|
free(p->buf), p->buf = (char *) 0;
|
|
return;
|
|
}
|
|
|
|
if (!(*proc)(p->buf))
|
|
p->rv = FALSE;
|
|
|
|
free(p->buf), p->buf = (char *) 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
boolean
|
|
parse_conf_str(const char *str, boolean (*proc)(char *arg))
|
|
{
|
|
size_t len;
|
|
struct _cnf_parser_state parser;
|
|
|
|
cnf_parser_init(&parser);
|
|
free_config_sections();
|
|
config_error_init(FALSE, "parse_conf_str", FALSE);
|
|
while (str && *str) {
|
|
len = 0;
|
|
while (*str && len < (parser.inbufsz-1)) {
|
|
parser.inbuf[len] = *str;
|
|
len++;
|
|
str++;
|
|
if (parser.inbuf[len-1] == '\n')
|
|
break;
|
|
}
|
|
parser.inbuf[len] = '\0';
|
|
parse_conf_buf(&parser, proc);
|
|
if (parser.pbreak)
|
|
break;
|
|
}
|
|
cnf_parser_done(&parser);
|
|
|
|
free_config_sections();
|
|
config_error_done();
|
|
return parser.rv;
|
|
}
|
|
|
|
/* parse_conf_file
|
|
*
|
|
* Read from file fp, calling parse_conf_buf for each line.
|
|
*/
|
|
boolean
|
|
parse_conf_file(FILE *fp, boolean (*proc)(char *arg))
|
|
{
|
|
struct _cnf_parser_state parser;
|
|
|
|
cnf_parser_init(&parser);
|
|
free_config_sections();
|
|
|
|
while (fgets(parser.inbuf, parser.inbufsz, fp)) {
|
|
parse_conf_buf(&parser, proc);
|
|
if (parser.pbreak)
|
|
break;
|
|
}
|
|
cnf_parser_done(&parser);
|
|
|
|
free_config_sections();
|
|
return parser.rv;
|
|
}
|
|
|
|
DISABLE_WARNING_FORMAT_NONLITERAL
|
|
|
|
void
|
|
config_error_add(const char *str, ...)
|
|
{
|
|
va_list the_args;
|
|
|
|
va_start(the_args, str);
|
|
vconfig_error_add(str, the_args);
|
|
va_end(the_args);
|
|
}
|
|
|
|
staticfn void
|
|
vconfig_error_add(const char *str, va_list the_args)
|
|
{ /* start of vconf...() or of nested block in USE_OLDARG's conf...() */
|
|
int vlen = 0;
|
|
char buf[BIGBUFSZ]; /* will be chopped down to BUFSZ-1 if longer */
|
|
|
|
vlen = vsnprintf(buf, sizeof buf, str, the_args);
|
|
#if (NH_DEVEL_STATUS != NH_STATUS_RELEASED) && defined(DEBUG)
|
|
if (vlen >= (int) sizeof buf)
|
|
panic("%s: truncation of buffer at %zu of %d bytes",
|
|
"config_error_add", sizeof buf, vlen);
|
|
#else
|
|
nhUse(vlen);
|
|
#endif
|
|
buf[BUFSZ - 1] = '\0';
|
|
config_erradd(buf);
|
|
}
|
|
|
|
#ifndef SFCTOOL
|
|
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
|
|
heed_all_config_statements(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < SIZE(disregarded_config_lines); i++) {
|
|
disregarded_config_lines[i] = FALSE;
|
|
}
|
|
}
|
|
void
|
|
disregard_all_config_statements(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < SIZE(disregarded_config_lines); i++) {
|
|
disregarded_config_lines[i] = TRUE;
|
|
}
|
|
}
|
|
void
|
|
heed_this_config_statement(int statement_idx)
|
|
{
|
|
if (statement_idx >= 0 && statement_idx < SIZE(disregarded_config_lines))
|
|
disregarded_config_lines[statement_idx] = FALSE;
|
|
}
|
|
void
|
|
disregard_this_config_statement(int statement_idx)
|
|
{
|
|
if (statement_idx >= 0 && statement_idx < SIZE(disregarded_config_lines))
|
|
disregarded_config_lines[statement_idx] = TRUE;
|
|
}
|
|
|
|
void
|
|
clear_ignore_errors_on_unmatched(void)
|
|
{
|
|
ignore_errors_on_unmatched = FALSE;
|
|
}
|
|
void
|
|
set_ignore_errors_on_unmatched(void)
|
|
{
|
|
ignore_errors_on_unmatched = TRUE;
|
|
}
|
|
boolean
|
|
config_unmatched_ignored(void)
|
|
{
|
|
if (ignore_errors_on_unmatched)
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
void
|
|
rcfile_interface_options(void)
|
|
{
|
|
allopt_array_init();
|
|
disregard_all_options();
|
|
disregard_all_config_statements();
|
|
heed_this_option(opt_windowtype);
|
|
heed_this_option(opt_soundlib);
|
|
set_ignore_errors_on_unmatched();
|
|
ignore_statement_errors = TRUE;
|
|
rcfile();
|
|
heed_all_config_statements();
|
|
heed_all_options();
|
|
disregard_this_option(opt_windowtype);
|
|
disregard_this_option(opt_soundlib);
|
|
clear_ignore_errors_on_unmatched();
|
|
ignore_statement_errors = FALSE;
|
|
}
|
|
|
|
void
|
|
rcfile_only_this_option(enum opt heeded_option)
|
|
{
|
|
allopt_array_init();
|
|
disregard_all_options();
|
|
disregard_all_config_statements();
|
|
heed_this_option(heeded_option);
|
|
set_ignore_errors_on_unmatched();
|
|
ignore_statement_errors = TRUE;
|
|
rcfile();
|
|
heed_all_config_statements();
|
|
heed_all_options();
|
|
clear_ignore_errors_on_unmatched();
|
|
ignore_statement_errors = FALSE;
|
|
}
|
|
|
|
void
|
|
rcfile_only_this_statement(int statementid)
|
|
{
|
|
allopt_array_init();
|
|
disregard_all_options();
|
|
disregard_all_config_statements();
|
|
heed_this_config_statement(statementid);
|
|
set_ignore_errors_on_unmatched();
|
|
ignore_statement_errors = TRUE;
|
|
rcfile();
|
|
heed_all_config_statements();
|
|
heed_all_options();
|
|
clear_ignore_errors_on_unmatched();
|
|
ignore_statement_errors = FALSE;
|
|
}
|
|
|
|
#ifdef WIN32
|
|
extern char portable_device_path[_MAX_PATH]; /* windsys.c */
|
|
extern boolean portable;
|
|
|
|
staticfn boolean
|
|
portable_sysconf_only_this_statement(int statementid)
|
|
{
|
|
const char *exepath;
|
|
char portable_sysconf[_MAX_PATH];
|
|
|
|
exepath = windows_exepath();
|
|
if (exepath) {
|
|
Snprintf(portable_sysconf, sizeof portable_sysconf, "%s/sysconf",
|
|
exepath);
|
|
if (portable_sysconf[0] && file_exists(portable_sysconf)) {
|
|
#ifdef SYSCF
|
|
#ifdef SYSCF_FILE
|
|
allopt_array_init();
|
|
disregard_all_options();
|
|
disregard_all_config_statements();
|
|
heed_this_config_statement(statementid);
|
|
set_ignore_errors_on_unmatched();
|
|
ignore_statement_errors = TRUE;
|
|
|
|
config_error_init(TRUE, portable_sysconf, FALSE);
|
|
go.opt_phase = syscf_opt;
|
|
(void) read_config_file(portable_sysconf, set_in_sysconf);
|
|
config_error_done();
|
|
heed_all_config_statements();
|
|
heed_all_options();
|
|
clear_ignore_errors_on_unmatched();
|
|
ignore_statement_errors = FALSE;
|
|
if (sysopt.portable_device_paths) {
|
|
Snprintf(portable_device_path, sizeof portable_device_path,
|
|
"%s\\", exepath);
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
#endif /* SYSCF */
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
boolean
|
|
check_for_portable_config(void)
|
|
{
|
|
int i, target_index = -1;
|
|
|
|
for (i = 0; i < SIZE(config_line_stmt); i++) {
|
|
if (!strcmp(config_line_stmt[i].name, "PORTABLE_DEVICE_PATHS")) {
|
|
target_index = i;
|
|
break;
|
|
}
|
|
}
|
|
if (target_index >= 0) {
|
|
return portable_sysconf_only_this_statement(target_index);
|
|
}
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
|
|
#ifdef MSWIN_GRAPHICS
|
|
void
|
|
disregard_some_mswin_options(void)
|
|
{
|
|
/* later for these */
|
|
disregard_this_option(opt_map_mode);
|
|
disregard_this_option(opt_font_map);
|
|
disregard_this_option(opt_font_menu);
|
|
disregard_this_option(opt_font_message);
|
|
disregard_this_option(opt_font_status);
|
|
|
|
disregard_this_option(opt_font_size_map);
|
|
disregard_this_option(opt_font_size_menu);
|
|
disregard_this_option(opt_font_size_message);
|
|
disregard_this_option(opt_font_size_status);
|
|
}
|
|
|
|
void
|
|
rcfile_only_some_mswin_options(void)
|
|
{
|
|
allopt_array_init();
|
|
disregard_all_options();
|
|
disregard_all_config_statements();
|
|
heed_this_option(opt_map_mode);
|
|
heed_this_option(opt_font_map);
|
|
heed_this_option(opt_font_menu);
|
|
heed_this_option(opt_font_message);
|
|
heed_this_option(opt_font_status);
|
|
|
|
heed_this_option(opt_font_size_map);
|
|
heed_this_option(opt_font_size_menu);
|
|
heed_this_option(opt_font_size_message);
|
|
heed_this_option(opt_font_size_status);
|
|
set_ignore_errors_on_unmatched();
|
|
ignore_statement_errors = TRUE;
|
|
rcfile();
|
|
heed_all_config_statements();
|
|
heed_all_options();
|
|
clear_ignore_errors_on_unmatched();
|
|
ignore_statement_errors = FALSE;
|
|
}
|
|
#endif /* MSWIN_GRAPHICS */
|
|
|
|
#endif /* SFCTOOL */
|
|
|
|
#ifdef SYSCF
|
|
#ifdef SYSCF_FILE
|
|
void
|
|
assure_syscf_file(void)
|
|
{
|
|
int fd;
|
|
|
|
#ifdef WIN32
|
|
/* We are checking that the sysconf exists ... lock the path */
|
|
fqn_prefix_locked[SYSCONFPREFIX] = TRUE;
|
|
#endif
|
|
/*
|
|
* All we really care about is the end result - can we read the file?
|
|
* So just check that directly.
|
|
*
|
|
* Not tested on most of the old platforms (which don't attempt
|
|
* to implement SYSCF).
|
|
* Some ports don't like open()'s optional third argument;
|
|
* VMS overrides open() usage with a macro which requires it.
|
|
*/
|
|
#ifndef VMS
|
|
#if defined(NOCWD_ASSUMPTIONS) && defined(WIN32)
|
|
fd = open(fqname(SYSCF_FILE, SYSCONFPREFIX, 0), O_RDONLY);
|
|
#else
|
|
fd = open(SYSCF_FILE, O_RDONLY);
|
|
#endif
|
|
#else /* VMS */
|
|
fd = open(SYSCF_FILE, O_RDONLY, 0);
|
|
#endif /* VMS */
|
|
if (fd >= 0) {
|
|
/* readable */
|
|
close(fd);
|
|
return;
|
|
}
|
|
#ifndef SFCTOOL
|
|
if (gd.deferred_showpaths)
|
|
do_deferred_showpaths(1); /* does not return */
|
|
#endif
|
|
raw_printf("Unable to open SYSCF_FILE.\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
#endif /* SYSCF_FILE */
|
|
#endif /* SYSCF */
|
|
|
|
/* ---------- END CONFIG FILE HANDLING ----------- */
|
|
|
|
/*cfgfiles.c*/
|
|
|