Unix command line parsing
Move a bunch of stuff out of main() into new early_options(): '-dpath'
playground directory handling, '-s ...' show scores instead of playing,
and the 'argcheck()' options: --version, --showpaths, --dumpenums,
and --debug (not to be confused with -D). Also introduce
| --nethackrc=filename
| --no-nethackrc
to control RC file without using NETHACKOPTIONS so that that is still
available for setting other options. They can start with either one
or two dashes. --no-nethackrc is just --nethackrc=/dev/null under the
hood. '-dpath' can now be '--directory=path' or '--directory path'
but the old syntax should still work. '-s ...' can be '--scores ...'.
Basic call sequence in unixmain relating to options is now
|main() {
| early_options(argc, argv[]);
| initoptions(); /* process sysconf, .nethackrc, NETHACKOPTIONS */
| process_options(possibly_modified_argc, possibly_modified_argv[]);
|}
Options processed by early_options() that don't terminate the program
are moved to the end of argv[], with argc reduced accordingly. Then
process_options() only sees the ones that early_options() declines to
handle.
Most early options were using plain exit() instead of nh_terminate()
so not performing any nethack-specific cleanup. However, since they
run before the game starts, there wasn't much cleanup being overlooked.
chdirx() takes a boolean as second argument but all its callers were
passing int (with value of 1 or 0, so it still worked after being
implicitly fixed by prototype). Change them to pass TRUE or FALSE.
argcheck() was refusing (argc,argv[]) with count of 1 but then it was
checking 0..N-1 rather than 1..N-1, so it tested whether argv[0] was
an argument instead of skipping that as the program name. Change to
allow count of 1 with modified argv that has an option name in argv[0].
That happens to fit well with how early_options() wanted to use it.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.788 $ $NHDT-Date: 1644610217 2022/02/11 20:10:17 $
|
||||
NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.799 $ $NHDT-Date: 1645223893 2022/02/18 22:38:13 $
|
||||
|
||||
General Fixes and Modified Features
|
||||
-----------------------------------
|
||||
@@ -1232,6 +1232,7 @@ Unix: add "ec2-user" to the list of user names 'sysconf' classifies as generic
|
||||
Unix: work-around a build issue in ubuntu 21.10 by using ifdef to skip the
|
||||
define of warn_unused_result to empty string in tradstdc.h whenever
|
||||
__linux__ is defined during build unless GCC_URWARN is also defined
|
||||
Unix: re-do command line parsing
|
||||
user_sounds: move the message hook from inside individual window display ports
|
||||
to the core where it allows MSGTYP_NOSHOW msgtyp's to still trigger
|
||||
sounds to correct a reported github issue; also fixes a past reported
|
||||
@@ -1470,6 +1471,9 @@ tty: if a message is marked urgent, override message suppression initiated
|
||||
by user having typed ESC at previous --More-- prompt
|
||||
Unix: can define NOSUSPEND in config.h or src/Makefile's CFLAGS to prevent
|
||||
unixconf.h from enabling SUSPEND without need to modify unixconf.h
|
||||
Unix: support --nethackrc=filename on the command line; same effect as
|
||||
NETHACKOPTIONS='@filename' but leaves NETHACKOPTIONS available for
|
||||
specifying options; --no-nethackrc is same as --nethackrc=/dev/null
|
||||
X11: implement 'selectsaved', restore via menu of saved games
|
||||
X11: echo getline prompt and response (wishes, applying names) to message
|
||||
window and dumplog message history
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* NetHack 3.7 allmain.c $NHDT-Date: 1644517022 2022/02/10 18:17:02 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.174 $ */
|
||||
/* NetHack 3.7 allmain.c $NHDT-Date: 1645223894 2022/02/18 22:38:14 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.177 $ */
|
||||
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||
/*-Copyright (c) Robert Patrick Rankin, 2012. */
|
||||
/* NetHack may be freely redistributed. See license for details. */
|
||||
@@ -845,7 +845,6 @@ extern int windows_early_options(const char *);
|
||||
* 1 = found and skip past this argument
|
||||
* 2 = found and trigger immediate exit
|
||||
*/
|
||||
|
||||
int
|
||||
argcheck(int argc, char *argv[], enum earlyarg e_arg)
|
||||
{
|
||||
@@ -858,7 +857,7 @@ argcheck(int argc, char *argv[], enum earlyarg e_arg)
|
||||
if (earlyopts[idx].e == e_arg)
|
||||
break;
|
||||
}
|
||||
if ((idx >= SIZE(earlyopts)) || (argc <= 1))
|
||||
if (idx >= SIZE(earlyopts) || argc < 1)
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i < argc; ++i) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* NetHack 3.7 unixmain.c $NHDT-Date: 1644866265 2022/02/14 19:17:45 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.96 $ */
|
||||
/* NetHack 3.7 unixmain.c $NHDT-Date: 1645223897 2022/02/18 22:38:17 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.97 $ */
|
||||
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||
/*-Copyright (c) Robert Patrick Rankin, 2011. */
|
||||
/* NetHack may be freely redistributed. See license for details. */
|
||||
@@ -30,7 +30,14 @@ extern struct passwd *getpwnam(const char *);
|
||||
static void chdirx(const char *, boolean);
|
||||
#endif /* CHDIR */
|
||||
static boolean whoami(void);
|
||||
static char *lopt(char *, int, const char *, const char *, int *, char ***);
|
||||
static void process_options(int, char **);
|
||||
static void consume_arg(int, int *, char ***);
|
||||
static void consume_two_args(int, int *, char ***);
|
||||
static void early_options(int *, char ***, char **);
|
||||
static void opt_terminate(void) NORETURN;
|
||||
static void opt_showpaths(const char *);
|
||||
static void scores_only(int, char **, const char *) NORETURN;
|
||||
|
||||
#ifdef _M_UNIX
|
||||
extern void check_sco_console(void);
|
||||
@@ -48,9 +55,7 @@ static struct passwd *get_unix_pw(void);
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
#ifdef CHDIR
|
||||
char *dir;
|
||||
#endif
|
||||
char *dir = NULL;
|
||||
NHFILE *nhfp;
|
||||
boolean exact_username;
|
||||
boolean resuming = FALSE; /* assume new game */
|
||||
@@ -108,89 +113,23 @@ main(int argc, char *argv[])
|
||||
if (!dir)
|
||||
dir = nh_getenv("HACKDIR");
|
||||
#endif /* CHDIR */
|
||||
/* handle -dalthackdir, -s <score stuff>, --version, --showpaths */
|
||||
early_options(&argc, &argv, &dir);
|
||||
|
||||
if (argc > 1) {
|
||||
if (argcheck(argc, argv, ARG_VERSION) == 2)
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
#ifndef NODUMPENUMS
|
||||
if (argcheck(argc, argv, ARG_DUMPENUMS) == 2)
|
||||
exit(EXIT_SUCCESS);
|
||||
#endif
|
||||
if (argcheck(argc, argv, ARG_SHOWPATHS) == 2) {
|
||||
#ifdef CHDIR
|
||||
chdirx((char *) 0, 0);
|
||||
/*
|
||||
* Change directories before we initialize the window system so
|
||||
* we can find the tile file.
|
||||
*/
|
||||
chdirx(dir, TRUE);
|
||||
#endif
|
||||
iflags.initoptions_noterminate = TRUE;
|
||||
initoptions();
|
||||
iflags.initoptions_noterminate = FALSE;
|
||||
reveal_paths();
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
if (argcheck(argc, argv, ARG_DEBUG) == 1) {
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
#ifdef CHDIR
|
||||
if (argc > 1 && !strncmp(argv[1], "-d", 2) && argv[1][2] != 'e') {
|
||||
/* avoid matching "-dec" for DECgraphics; since the man page
|
||||
* says -d directory, hope nobody's using -desomething_else
|
||||
*/
|
||||
argc--;
|
||||
argv++;
|
||||
dir = argv[0] + 2;
|
||||
if (*dir == '=' || *dir == ':')
|
||||
dir++;
|
||||
if (!*dir && argc > 1) {
|
||||
argc--;
|
||||
argv++;
|
||||
dir = argv[0];
|
||||
}
|
||||
if (!*dir)
|
||||
error("Flag -d must be followed by a directory name.");
|
||||
}
|
||||
}
|
||||
#endif /* CHDIR */
|
||||
|
||||
if (argc > 1) {
|
||||
/*
|
||||
* Now we know the directory containing 'record' and
|
||||
* may do a prscore(). Exclude `-style' - it's a Qt option.
|
||||
*/
|
||||
if (!strncmp(argv[1], "-s", 2) && strncmp(argv[1], "-style", 6)) {
|
||||
#ifdef CHDIR
|
||||
chdirx(dir, 0);
|
||||
#endif
|
||||
#ifdef SYSCF
|
||||
initoptions();
|
||||
#endif
|
||||
#ifdef PANICTRACE
|
||||
ARGV0 = g.hname; /* save for possible stack trace */
|
||||
#ifndef NO_SIGNAL
|
||||
panictrace_setsignals(TRUE);
|
||||
#endif
|
||||
#endif
|
||||
prscore(argc, argv);
|
||||
/* FIXME: shouldn't this be using nh_terminate() to free
|
||||
up any memory allocated by initoptions() */
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
} /* argc > 1 */
|
||||
|
||||
/*
|
||||
* Change directories before we initialize the window system so
|
||||
* we can find the tile file.
|
||||
*/
|
||||
#ifdef CHDIR
|
||||
chdirx(dir, 1);
|
||||
#endif
|
||||
|
||||
#ifdef _M_UNIX
|
||||
check_sco_console();
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
check_linux_console();
|
||||
#endif
|
||||
|
||||
initoptions();
|
||||
#ifdef PANICTRACE
|
||||
ARGV0 = g.hname; /* save for possible stack trace */
|
||||
@@ -346,12 +285,94 @@ main(int argc, char *argv[])
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char ArgVal_novalue[] = "[nothing]"; /* note: not 'const' */
|
||||
|
||||
enum cmdlinearg {
|
||||
ArgValRequired = 0, ArgValOptional = 1,
|
||||
ArgValDisallowed = 2, ArgVal_mask = (1 | 2),
|
||||
ArgNamOneLetter = 4, ArgNam_mask = 4,
|
||||
ArgErrSilent = 0, ArgErrComplain = 8, ArgErr_mask = 8
|
||||
};
|
||||
|
||||
/* approximate 'getopt_long()' for one option; all the comments refer to
|
||||
"-windowtype" but the code isn't specific to that */
|
||||
static char *
|
||||
lopt(
|
||||
char *arg, /* command line token; beginning matches 'optname' */
|
||||
int lflags, /* cmdlinearg | errorhandling */
|
||||
const char *optname, /* option's name; "-windowtype" in examples below */
|
||||
const char *origarg, /* 'arg' might have had a dash prefix removed */
|
||||
int *argc_p, /* argc that can have changes passed to caller */
|
||||
char ***argv_p) /* argv[] ditto */
|
||||
{
|
||||
int argc = *argc_p;
|
||||
char **argv = *argv_p;
|
||||
char *p, *nextarg = (argc > 1 && argv[1][0] != '-') ? argv[1] : 0;
|
||||
int l, opttype = (lflags & ArgVal_mask);
|
||||
boolean oneletterok = ((lflags & ArgNam_mask) == ArgNamOneLetter),
|
||||
complain = ((lflags & ArgErr_mask) == ArgErrComplain);
|
||||
|
||||
/* first letter must match */
|
||||
if (arg[1] != optname[1]) {
|
||||
loptbail:
|
||||
if (complain)
|
||||
config_error_add("Unknown option: %.60s", origarg);
|
||||
return (char *) 0;
|
||||
loptnotallowed:
|
||||
if (complain)
|
||||
config_error_add("Value not allowed: %.60s", origarg);
|
||||
return (char *) 0;
|
||||
loptrequired:
|
||||
if (complain)
|
||||
config_error_add("Missing required value: %.60s", origarg);
|
||||
return (char *) 0;
|
||||
}
|
||||
|
||||
if ((p = index(arg, '=')) == 0)
|
||||
p = index(arg, ':');
|
||||
if (p && opttype == ArgValDisallowed)
|
||||
goto loptnotallowed;
|
||||
|
||||
l = (int) (p ? (p - arg) : strlen(arg));
|
||||
if (!strncmp(arg, optname, l)) {
|
||||
/* "-windowtype[=foo]" */
|
||||
if (p)
|
||||
++p; /* past '=' or ':' */
|
||||
else if (opttype == ArgValRequired)
|
||||
p = eos(arg); /* we have "-w[indowtype]" w/o "=foo"
|
||||
* so we'll take foo from next element */
|
||||
else
|
||||
return ArgVal_novalue;
|
||||
} else if (oneletterok) {
|
||||
/* "-w..." but not "-w[indowtype[=foo]]" */
|
||||
if (!p) {
|
||||
p = &arg[2]; /* past 'w' of "-wfoo" */
|
||||
} else {
|
||||
/* "-w...=foo" but not "-w[indowtype]=foo" */
|
||||
goto loptbail;
|
||||
}
|
||||
} else {
|
||||
goto loptbail;
|
||||
}
|
||||
if (!p || !*p) {
|
||||
/* "-w[indowtype]" w/o '='/':' if there is a next element, use
|
||||
it for "foo"; if not, supply a non-Null bogus value */
|
||||
if (nextarg && (opttype == ArgValRequired
|
||||
|| opttype == ArgValOptional))
|
||||
p = nextarg, --(*argc_p), ++(*argv_p);
|
||||
else if (opttype == ArgValRequired)
|
||||
goto loptrequired;
|
||||
else
|
||||
p = ArgVal_novalue; /* there is no next element */
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/* caveat: argv elements might be arbitrary long */
|
||||
static void
|
||||
process_options(int argc, char *argv[])
|
||||
{
|
||||
static char novalue[] = "[nothing]"; /* note: not 'const' */
|
||||
char *p, *arg, *origarg;
|
||||
char *arg, *origarg;
|
||||
int i, l;
|
||||
|
||||
config_error_init(FALSE, "command line", FALSE);
|
||||
@@ -373,9 +394,10 @@ process_options(int argc, char *argv[])
|
||||
&& (arg[3] != '\0' && arg[3] != '=' && arg[3] != ':'))
|
||||
++arg;
|
||||
l = (int) strlen(arg);
|
||||
/* must supply at least 4 chars to match "-XXXgraphics" */
|
||||
if (l < 4)
|
||||
l = 4;
|
||||
if (l < 6 && !strncmp(arg, "-no-", 4))
|
||||
l = 6;
|
||||
else if (l < 4)
|
||||
l = 4; /* must supply at least 4 chars to match "-XXXgraphics" */
|
||||
|
||||
switch (arg[1]) {
|
||||
case 'D':
|
||||
@@ -392,11 +414,18 @@ process_options(int argc, char *argv[])
|
||||
case 'X':
|
||||
discover = TRUE, wizard = FALSE;
|
||||
break;
|
||||
#ifdef NEWS
|
||||
case 'n':
|
||||
iflags.news = FALSE;
|
||||
break;
|
||||
#ifdef NEWS
|
||||
if (!arg[2] || !strcmp(arg, "-no-news")) {
|
||||
iflags.news = FALSE;
|
||||
break;
|
||||
} else if (!strcmp(arg, "-news")) {
|
||||
/* in case RC has !news, allow 'nethack -news' to override */
|
||||
iflags.news = TRUE;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 'u':
|
||||
if (arg[2]) {
|
||||
(void) strncpy(g.plname, arg + 2, sizeof g.plname - 1);
|
||||
@@ -407,7 +436,7 @@ process_options(int argc, char *argv[])
|
||||
(void) strncpy(g.plname, argv[0], sizeof g.plname - 1);
|
||||
g.plnamelen = 0;
|
||||
} else {
|
||||
config_error_add("Player name expected after -u");
|
||||
config_error_add("Character name expected after -u");
|
||||
}
|
||||
break;
|
||||
case 'I':
|
||||
@@ -444,34 +473,11 @@ process_options(int argc, char *argv[])
|
||||
break;
|
||||
case 'w': /* windowtype: "-wfoo" or "-w[indowtype]=foo"
|
||||
* or "-w[indowtype]:foo" or "-w[indowtype] foo" */
|
||||
if ((p = index(arg, '=')) == 0)
|
||||
p = index(arg, ':');
|
||||
l = (int) (p ? (p - arg) : strlen(arg));
|
||||
if (!strncmp(arg, "-windowtype", l)) {
|
||||
/* "-windowtype[=foo]" */
|
||||
if (p)
|
||||
++p; /* past '=' or ':' */
|
||||
else
|
||||
p = eos(arg); /* we have "-w[indowtype]" w/o "=foo"
|
||||
* so we'll take foo from next element */
|
||||
} else {
|
||||
/* "-w..." but not "-w[indowtype[=foo]]" */
|
||||
if (!p) {
|
||||
p = &arg[2]; /* past 'w' of "-wfoo" */
|
||||
} else {
|
||||
/* "-w...=foo" but not "-w[indowtype]=foo" */
|
||||
config_error_add("Unknown option: %.60s", origarg);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!*p) {
|
||||
/* "-w[indowtype]" w/o '='/':' use next element for "foo" */
|
||||
if (argc > 1)
|
||||
--argc, ++argv, p = argv[0];
|
||||
else
|
||||
p = novalue; /* there is no next element */
|
||||
}
|
||||
choose_windows(p);
|
||||
arg = lopt(arg,
|
||||
(ArgValRequired | ArgNamOneLetter | ArgErrComplain),
|
||||
"-windowtype", origarg, &argc, &argv);
|
||||
if (arg)
|
||||
choose_windows(arg);
|
||||
break;
|
||||
case '@':
|
||||
flags.randomall = 1;
|
||||
@@ -492,14 +498,22 @@ process_options(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
if (argc > 1) {
|
||||
int mxplyrs = atoi(argv[1]);
|
||||
boolean mx_ok = mxplyrs != 0;
|
||||
#ifdef SYSCF
|
||||
if (argc > 1)
|
||||
config_error_add("MAXPLAYERS are set in sysconf file.\n");
|
||||
config_error_add("%s%s%s",
|
||||
mx_ok ? "MAXPLAYERS are set in sysconf file"
|
||||
: "Expected MAXPLAYERS, found \"",
|
||||
mx_ok ? "" : argv[1], mx_ok ? "" : "\"");
|
||||
#else
|
||||
/* XXX This is deprecated in favor of SYSCF with MAXPLAYERS */
|
||||
if (argc > 1)
|
||||
g.locknum = atoi(argv[1]);
|
||||
/* XXX This is deprecated in favor of SYSCF with MAXPLAYERS */
|
||||
if (mx_ok)
|
||||
g.locknum = mxplyrs;
|
||||
else
|
||||
config_error_add("Invalid MAXPLATERS \"%s\"", argv[1]);
|
||||
#endif
|
||||
}
|
||||
#ifdef MAX_NR_OF_PLAYERS
|
||||
/* limit to compile-time limit */
|
||||
if (!g.locknum || g.locknum > MAX_NR_OF_PLAYERS)
|
||||
@@ -512,6 +526,207 @@ process_options(int argc, char *argv[])
|
||||
#endif
|
||||
/* empty or "N errors on command line" */
|
||||
config_error_done();
|
||||
return;
|
||||
}
|
||||
|
||||
/* move argv[ndx] to end of argv[] array, then reduce argc to hide it;
|
||||
prevents process_options() from encountering it after early_options()
|
||||
has processed it; elements get reordered but all remain intact */
|
||||
static void
|
||||
consume_arg(int ndx, int *ac_p, char ***av_p)
|
||||
{
|
||||
char *gone, **av = *av_p;
|
||||
int i, ac = *ac_p;
|
||||
|
||||
/* "-one -two -three -four" -> "-two -three -four -one" */
|
||||
if (ac > 2) {
|
||||
gone = av[ndx];
|
||||
for (i = ndx + 1; i < ac; ++i)
|
||||
av[i - 1] = av[i];
|
||||
av[ac - 1] = gone;
|
||||
}
|
||||
--(*ac_p);
|
||||
}
|
||||
|
||||
/* consume two tokens for '-argname value' w/o '=' or ':' */
|
||||
static void
|
||||
consume_two_args(int ndx, int *ac_p, char ***av_p)
|
||||
{
|
||||
/* when consuming "-two arg" from "-two arg -three -four",
|
||||
the *ac_p manipulation results in "-three -four -two arg"
|
||||
rather than the "-three -four arg -two" that would happen
|
||||
with just two ordinary consume_arg() calls */
|
||||
consume_arg(ndx, ac_p, av_p);
|
||||
++(*ac_p); /* bring the final slot back into view */
|
||||
consume_arg(ndx, ac_p, av_p);
|
||||
--(*ac_p); /* take away restored slot */
|
||||
}
|
||||
|
||||
/* process some command line arguments before loading options */
|
||||
static void
|
||||
early_options(int *argc_p, char ***argv_p, char **hackdir_p)
|
||||
{
|
||||
char **argv, *arg, *origarg;
|
||||
int argc, oldargc, ndx = 0, consumed = 0;
|
||||
|
||||
config_error_init(FALSE, "command line", FALSE);
|
||||
|
||||
/*
|
||||
* Both *argc_p and *argv_p account for the program name as (*argv_p)[0];
|
||||
* local argc and argv impicitly discard that (by starting 'ndx' at 1).
|
||||
* argcheck() doesn't mind, prscore() (via scores_only()) does.
|
||||
*/
|
||||
for (ndx = 1; ndx < *argc_p; ndx += (consumed ? 0 : 1)) {
|
||||
consumed = 0;
|
||||
argc = *argc_p - ndx;
|
||||
argv = *argv_p + ndx;
|
||||
|
||||
arg = origarg = argv[0];
|
||||
/* skip any args intended for deferred options */
|
||||
if (*arg != '-')
|
||||
continue;
|
||||
/* allow second dash if arg name is longer than one character */
|
||||
if (arg[0] == '-' && arg[1] == '-' && arg[2] != '\0'
|
||||
&& (arg[3] != '\0' && arg[3] != '=' && arg[3] != ':'))
|
||||
++arg;
|
||||
|
||||
switch (arg[1]) { /* char after leading dash */
|
||||
case 'd':
|
||||
if (argcheck(argc, argv, ARG_DEBUG) == 1) {
|
||||
consume_arg(ndx, argc_p, argv_p), consumed = 1;
|
||||
#ifndef NODUMPENUMS
|
||||
} else if (argcheck(argc, argv, ARG_DUMPENUMS) == 2) {
|
||||
opt_terminate();
|
||||
/*NOTREACHED*/
|
||||
#endif
|
||||
} else {
|
||||
#ifdef CHDIR
|
||||
oldargc = argc;
|
||||
arg = lopt(arg,
|
||||
(ArgValRequired | ArgNamOneLetter | ArgErrSilent),
|
||||
"-directory", origarg, &argc, &argv);
|
||||
if (!arg)
|
||||
error("Flag -d must be followed by a directory name.");
|
||||
if (*arg != 'e') { /* avoid matching -decgraphics or -debug */
|
||||
*hackdir_p = arg;
|
||||
if (oldargc == argc)
|
||||
consume_arg(ndx, argc_p, argv_p), consumed = 1;
|
||||
else
|
||||
consume_two_args(ndx, argc_p, argv_p), consumed = 2;
|
||||
}
|
||||
#endif /* CHDIR */
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
oldargc = argc;
|
||||
if (!strcmp(arg, "-no-nethackrc")) /* no abbreviation allowed */
|
||||
arg = nhStr("/dev/null");
|
||||
else
|
||||
arg = lopt(arg, (ArgValRequired | ArgErrComplain),
|
||||
"-nethackrc", origarg, &argc, &argv);
|
||||
if (arg) {
|
||||
g.cmdline_rcfile = dupstr(arg);
|
||||
if (oldargc == argc)
|
||||
consume_arg(ndx, argc_p, argv_p), consumed = 1;
|
||||
else
|
||||
consume_two_args(ndx, argc_p, argv_p), consumed = 2;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
if (argcheck(argc, argv, ARG_SHOWPATHS) == 2) {
|
||||
opt_showpaths(*hackdir_p);
|
||||
opt_terminate();
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
/* check for "-s" request to show scores */
|
||||
if (lopt(arg,
|
||||
(ArgValDisallowed | ArgNamOneLetter | ArgErrComplain),
|
||||
"-scores", origarg, &argc, &argv)) {
|
||||
/* at this point, argv[0] contains "-scores" or a leading
|
||||
substring of it; prscore() (via scores_only()) expects
|
||||
that to be in argv[1] so we adjust the pointer to make
|
||||
that be the case; if there are any non-early args waiting
|
||||
to be passed along to process_options(), the resulting
|
||||
argv[0] will be one of those rather than the program
|
||||
name but prscore() doesn't care */
|
||||
scores_only(argc + 1, argv - 1, *hackdir_p);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
break;
|
||||
case 'v':
|
||||
if (argcheck(argc, argv, ARG_VERSION) == 2) {
|
||||
opt_terminate();
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* empty or "N errors on command line" */
|
||||
config_error_done();
|
||||
return;
|
||||
}
|
||||
|
||||
/* for command-line options that perform some immediate action and then
|
||||
terminate the program without starting play, like 'nethack --version'
|
||||
or 'nethack -s Zelda'; do some cleanup before that termination */
|
||||
static void
|
||||
opt_terminate(void)
|
||||
{
|
||||
config_error_done(); /* free memory allocated by config_error_init() */
|
||||
|
||||
nh_terminate(EXIT_SUCCESS);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
/* show the sysconf file name, playground directory, run-time configuration
|
||||
file name, dumplog file name if applicable, and some other things */
|
||||
static void
|
||||
opt_showpaths(const char *dir)
|
||||
{
|
||||
#ifdef CHDIR
|
||||
chdirx(dir, FALSE);
|
||||
#else
|
||||
nhUse(dir);
|
||||
#endif
|
||||
iflags.initoptions_noterminate = TRUE;
|
||||
initoptions();
|
||||
iflags.initoptions_noterminate = FALSE;
|
||||
reveal_paths();
|
||||
}
|
||||
|
||||
/* handle "-s <score options> [character-names]" to show all the entries
|
||||
in the high scores file ('record') belonging to particular characters;
|
||||
nethack will end after doing so without starting play */
|
||||
static void
|
||||
scores_only(int argc, char **argv, const char *dir)
|
||||
{
|
||||
/* do this now rather than waiting for final termination, in case there
|
||||
is an error summary coming */
|
||||
config_error_done();
|
||||
|
||||
#ifdef CHDIR
|
||||
chdirx(dir, FALSE);
|
||||
#else
|
||||
nhUse(dir);
|
||||
#endif
|
||||
#ifdef SYSCF
|
||||
iflags.initoptions_noterminate = TRUE;
|
||||
initoptions(); /* sysconf options affect whether panictrace is enabled */
|
||||
iflags.initoptions_noterminate = FALSE;
|
||||
#endif
|
||||
#ifdef PANICTRACE
|
||||
ARGV0 = g.hname; /* save for possible stack trace */
|
||||
#ifndef NO_SIGNAL
|
||||
panictrace_setsignals(TRUE);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
prscore(argc, argv);
|
||||
|
||||
nh_terminate(EXIT_SUCCESS); /* bypass opt_terminate() */
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
#ifdef CHDIR
|
||||
@@ -535,24 +750,26 @@ chdirx(const char *dir, boolean wr)
|
||||
#ifdef VAR_PLAYGROUND
|
||||
int len = strlen(VAR_PLAYGROUND);
|
||||
|
||||
/* FIXME: this allocation never gets freed.
|
||||
*/
|
||||
g.fqn_prefix[SCOREPREFIX] = (char *) alloc(len + 2);
|
||||
Strcpy(g.fqn_prefix[SCOREPREFIX], VAR_PLAYGROUND);
|
||||
if (g.fqn_prefix[SCOREPREFIX][len - 1] != '/') {
|
||||
g.fqn_prefix[SCOREPREFIX][len] = '/';
|
||||
g.fqn_prefix[SCOREPREFIX][len + 1] = '\0';
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HACKDIR
|
||||
if (dir == (const char *) 0)
|
||||
if (!dir)
|
||||
dir = HACKDIR;
|
||||
#endif
|
||||
|
||||
if (dir && chdir(dir) < 0) {
|
||||
perror(dir);
|
||||
error("Cannot chdir to %s.", dir);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
/* warn the player if we can't write the record file
|
||||
@@ -561,6 +778,10 @@ chdirx(const char *dir, boolean wr)
|
||||
*/
|
||||
if (wr) {
|
||||
#ifdef VAR_PLAYGROUND
|
||||
/* FIXME: if termination cleanup ever frees fqn_prefix[0..N-1],
|
||||
* these will need to use dupstr() so that they have distinct
|
||||
* values that can be freed separately.
|
||||
*/
|
||||
g.fqn_prefix[LEVELPREFIX] = g.fqn_prefix[SCOREPREFIX];
|
||||
g.fqn_prefix[SAVEPREFIX] = g.fqn_prefix[SCOREPREFIX];
|
||||
g.fqn_prefix[BONESPREFIX] = g.fqn_prefix[SCOREPREFIX];
|
||||
@@ -569,6 +790,7 @@ chdirx(const char *dir, boolean wr)
|
||||
#endif
|
||||
check_recordfile(dir);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif /* CHDIR */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user