]> granicus.if.org Git - nethack/commitdiff
unix command line
authorPatR <rankin@nethack.org>
Sat, 12 Feb 2022 19:42:17 +0000 (11:42 -0800)
committerPatR <rankin@nethack.org>
Sat, 12 Feb 2022 19:42:17 +0000 (11:42 -0800)
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.

src/allmain.c
src/files.c
sys/unix/unixmain.c

index 74260e859049f412d4cf65068b354905e3a7cd4a..7fcf18b19da42d57570d10979a015c67d6df0c82 100644 (file)
@@ -851,7 +851,7 @@ argcheck(int argc, char *argv[], enum earlyarg e_arg)
 {
     int i, idx;
     boolean match = FALSE;
-    char *userea = (char *)0;
+    char *userea = (char *) 0;
     const char *dashdash = "";
 
     for (idx = 0; idx < SIZE(earlyopts); idx++) {
@@ -859,7 +859,7 @@ argcheck(int argc, char *argv[], enum earlyarg e_arg)
             break;
     }
     if ((idx >= SIZE(earlyopts)) || (argc <= 1))
-            return FALSE;
+        return FALSE;
 
     for (i = 0; i < argc; ++i) {
         if (argv[i][0] != '-')
@@ -873,7 +873,8 @@ argcheck(int argc, char *argv[], enum earlyarg e_arg)
         match = match_optname(userea, earlyopts[idx].name,
                               earlyopts[idx].minlength,
                               earlyopts[idx].valallowed);
-        if (match) break;
+        if (match)
+            break;
     }
 
     if (match) {
index cb47ad4f0a0dbd34f813f3adcee3a71690fbc487..edbc7b1ec45f230c8eb5643410a3a34c5a76ddbc 100644 (file)
@@ -2992,7 +2992,9 @@ config_error_done(void)
     }
 #endif
     if (n) {
-        pline("\n%d error%s in %s.\n", n, plur(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();
index 59f41a7379bd9c4ccf2ec1a8edbd3031918c168c..ef27160c04efdebbc602dd5e13d2127a961ba827 100644 (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