unix command line

I wanted to be able to specify -windowtype:foo on the command line so
that I didn't have to use "NETHACKOPTIONS='windowtype:foo' nethack"
and it turned out that such an option already exists, as "-wfoo".
I either never knew about that or had completely forgotten it.  Anyway,
this makes specifying windowtype be more versatile.

"-wX11" still works; now "-w X11", "-windowtype=X11", "-windowtype:X11"
work too, with "--" variations of the latter too also supported.  The
long name can be truncated to any leading substring of "windowtype",
although it has to be at least "wi" for "--"; "--w" is rejected.

Also, any errors reported while processing the command line are
treated like config file processing errors rather than just delivered
with raw_printf().  On tty at least, they used to vanish when the
screen cleared to start the game, with no chance to read them.  Here's
an example from after this change.  It sets windowtype to tty and then
overrides that with X11.

|% ./nethack --w:Qt --win tty -wX11 -windowtype
|
|
| * Unknown option: --w:Qt.
| * Window type [nothing] not recognized.  Choices are:  tty, curses, X11, Qt.
|
|2 errors on command line.
|
|
|Hit return to continue:

This should probably be better integrated with argcheck() or vice
versa but the only change to that was a couple of formatting bits.

Anything that already worked should continue to work just the same,
aside from the improvement to the error feedback.
This commit is contained in:
PatR
2022-02-12 11:42:17 -08:00
parent 9389b915a3
commit a1bb10e8f6
3 changed files with 76 additions and 25 deletions

View File

@@ -348,30 +348,43 @@ main(int argc, char *argv[])
static void
process_options(int argc, char *argv[])
{
static char novalue[] = "[nothing]"; /* note: not 'const' */
char *p, *arg, *origarg;
int i, l;
config_error_init(FALSE, "command line", FALSE);
/*
* Process options.
*
* We don't support "-xyz" as shortcut for "-x -y -z" and we only
* simulate longopts by allowing "--foo" for "-foo" when the user
* specifies at least 2 characters of leading substring for "foo".
* If "foo" takes a value, both "--foo=value" and "--foo value" work.
*/
while (argc > 1 && argv[1][0] == '-') {
argv++;
argc--;
l = (int) strlen(*argv);
arg = origarg = argv[0];
/* allow second dash if arg is longer than one character */
if (arg[0] == '-' && arg[1] == '-' && arg[2] != '\0'
/* "--a=b" violates the "--" ok when at least 2 chars long rule */
&& (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;
switch (argv[0][1]) {
switch (arg[1]) {
case 'D':
case 'd':
if ((argv[0][1] == 'D' && !argv[0][2])
|| !strcmpi(*argv, "-debug")) {
if ((arg[1] == 'D' && !arg[2]) || !strcmpi(arg, "-debug")) {
wizard = TRUE, discover = FALSE;
} else if (!strncmpi(*argv, "-DECgraphics", l)) {
} else if (!strncmpi(arg, "-DECgraphics", l)) {
load_symset("DECGraphics", PRIMARY);
switch_symbols(TRUE);
} else {
raw_printf("Unknown option: %.60s", *argv);
config_error_add("Unknown option: %.60s", origarg);
}
break;
case 'X':
@@ -383,8 +396,8 @@ process_options(int argc, char *argv[])
break;
#endif
case 'u':
if (argv[0][2]) {
(void) strncpy(g.plname, argv[0] + 2, sizeof g.plname - 1);
if (arg[2]) {
(void) strncpy(g.plname, arg + 2, sizeof g.plname - 1);
g.plnamelen = 0; /* plname[] might have -role-race attached */
} else if (argc > 1) {
argc--;
@@ -392,22 +405,22 @@ process_options(int argc, char *argv[])
(void) strncpy(g.plname, argv[0], sizeof g.plname - 1);
g.plnamelen = 0;
} else {
raw_print("Player name expected after -u");
config_error_add("Player name expected after -u");
}
break;
case 'I':
case 'i':
if (!strncmpi(*argv, "-IBMgraphics", l)) {
if (!strncmpi(arg, "-IBMgraphics", l)) {
load_symset("IBMGraphics", PRIMARY);
load_symset("RogueIBM", ROGUESET);
switch_symbols(TRUE);
} else {
raw_printf("Unknown option: %.60s", *argv);
config_error_add("Unknown option: %.60s", origarg);
}
break;
case 'p': /* profession (role) */
if (argv[0][2]) {
if ((i = str2role(&argv[0][2])) >= 0)
if (arg[2]) {
if ((i = str2role(&arg[2])) >= 0)
flags.initrole = i;
} else if (argc > 1) {
argc--;
@@ -417,8 +430,8 @@ process_options(int argc, char *argv[])
}
break;
case 'r': /* race */
if (argv[0][2]) {
if ((i = str2race(&argv[0][2])) >= 0)
if (arg[2]) {
if ((i = str2race(&arg[2])) >= 0)
flags.initrace = i;
} else if (argc > 1) {
argc--;
@@ -427,26 +440,59 @@ process_options(int argc, char *argv[])
flags.initrace = i;
}
break;
case 'w': /* windowtype */
config_error_init(FALSE, "command line", FALSE);
choose_windows(&argv[0][2]);
config_error_done();
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);
break;
case '@':
flags.randomall = 1;
break;
case '-':
/* "--" or "--x" or "--x=y"; need at least 2 chars after the
dashes in order to accept "--x" as an alternative to "-x";
don't just silently ignore it */
config_error_add("Unknown option: %.60s", origarg);
break;
default:
/* default for "-x" is to play as the role that starts with "x" */
if ((i = str2role(&argv[0][1])) >= 0) {
flags.initrole = i;
break;
}
/* else raw_printf("Unknown option: %.60s", *argv); */
/* else config_error_add("Unknown option: %.60s", origarg); */
}
}
#ifdef SYSCF
if (argc > 1)
raw_printf("MAXPLAYERS are set in sysconf file.\n");
config_error_add("MAXPLAYERS are set in sysconf file.\n");
#else
/* XXX This is deprecated in favor of SYSCF with MAXPLAYERS */
if (argc > 1)
@@ -462,6 +508,8 @@ process_options(int argc, char *argv[])
if (!g.locknum || (sysopt.maxplayers && g.locknum > sysopt.maxplayers))
g.locknum = sysopt.maxplayers;
#endif
/* empty or "N errors on command line" */
config_error_done();
}
#ifdef CHDIR