]> granicus.if.org Git - nethack/commitdiff
'nethack --usage' and '?' menu
authorPatR <rankin@nethack.org>
Sat, 19 Nov 2022 00:07:15 +0000 (16:07 -0800)
committerPatR <rankin@nethack.org>
Sat, 19 Nov 2022 00:07:15 +0000 (16:07 -0800)
Write up a description of how the command line works on UNIX and put
that in new file dat/usagehlp.  Add support for
|nethack --usage | --help | -? | ?
to display it and exit.

Also add a menu entry for nethack's help command to show it during
play.  That can be suppressed by uncommenting new '#define HIDE_USAGE'
in config.h since it won't be useful on servers that don't give
players access to command lines.

New genl_display_file() just writes to stdout.  opt_usage(), which
calls it, might need some suid/sgid handling to make sure the output
is done as the player rather than as nethack.

doc/nethack.6 is already out of date again.

dat/usagehlp [new file with mode: 0644]
include/config.h
include/extern.h
include/global.h
src/pager.c
src/windows.c
sys/unix/Makefile.src
sys/unix/Makefile.top
sys/unix/unixmain.c

diff --git a/dat/usagehlp b/dat/usagehlp
new file mode 100644 (file)
index 0000000..a6a4b6b
--- /dev/null
@@ -0,0 +1,132 @@
+This is a terse description of nethack's command line arguments.
+It is oriented toward UNIX (including descendants such as linux and
+macOS) and might not be accurate for other platforms.
+
+This text is available in the menu for the game's '?' command or can be
+viewed via 'nethack --usage | more' at the shell prompt.
+
+In all cases, if there is a save file for the chosen character name then
+it will be restored, otherwise a new game using that name will start.
+
+nethack
+  with no arguments; uses character name from run-time configuration file's
+  OPTIONS=name:character-name entry, or player's username if none.
+
+nethack -u character-name [-X or -D]
+  '-u character-name' specifies the name to use for this game's character;
+       -u must be lowercase; the space between it and character-name may
+       be omitted;
+  '-X' play in non-scoring explore mode also known as discovery mode;
+       -X must be uppercase; character starts with a wand of wishing and
+       player may opt to be life-saved and keep going if character dies;
+  '-D' run in debug mode also known as wizard mode; -D must be uppercase;
+       if player is not allowed then nethack will switch to -X.
+
+  A character name may have a suffix specifying any or all of role, race,
+  gender, and alignment such as -u Conan-Bar-Hum-Mal-Neu or -u Tim-Wiz.
+  The components present must be at least three letters long but can be
+  longer; their case doesn't matter.  See also -p and -r, next,
+
+nethack -p Ppp -r Rrr [-@]
+  '-p Ppp' specify role; p for "profession" is used because -r is in use;
+       'Ppp' is three or more letters of the role name such as Val for
+       Valkyrie; unlike -p itself, upper/lower case of Ppp doesn't matter
+  '-r Rrr' specify race or species: Hum[an], Elf, Orc, Dwa[rf], Gno[me];
+  '-@' force non-interactive start; any of role, race, gender, and
+       alignment that is not specified on the command line or in the
+       run-time configuration file gets chosen randomly without prompting;
+       the at-sign might need to be quoted by preceding it with backslash.
+
+  The old form for role is also still accepted:  -A or -Arc[heologist],
+  -B or -Bar[barian], -C or -Cav[eman] or -Cavew[oman], -H or -Hea[ler],
+  -K or -Kni[ght], -M or -Mon[k], -P or -Pri[est] or -Prieste[ss],
+  -Ran[ger], -R or -Rog[ue], -S or -Sam[urai], -T or -Tou[rist],
+  -V or -Val[kyrie], -W or -Wiz[ard].  The single-letter form must be in
+  uppercase, the three or more letter form can be in any case.  There is
+  no single-letter option for the Ranger role.
+
+nethack -DEC[graphics]
+nethack -IBM[graphics]
+  selects the DEC or IBM symbol set to use line-drawing characters on a
+  text map; might be ignored depending on interface, or ineffective or
+  even scrambled depending on display capability; -DECgraphics and
+  -IBMgraphics are mutually exclusive; they can be any case but must use
+  at least three letters.
+
+nethack -wIii
+nethack --windowtype:Iii
+  where 'Iii' represents an interface designation:  tty, curses, X11, or
+  Qt; only useful if the program was built to support more than one
+  interface (the game's '#version' command will disclose that); overrides
+  OPTIONS=windowtype:Iii in run-time configuration file and build-time
+  default; '-w' or '--windowtype' must be lowercase, the interface
+  designation itself may be any case; variations '--windowtype Iii' and
+  '-w Iii' work too.
+
+  On Windows, nethack.exe might support both tty and curses; nethackW.exe
+  supports mswin only.  MS-DOS is tty only.
+
+nethack -n
+  don't show the 'news' file is one is present in nethack's directory.
+
+nethack --nethackrc:File
+  use File instead of the default run-time configuration file (which is
+  usually '~/.nethackrc'); the file name should include full path unless
+  located in nethack's directory;
+nethack --no-nethackrc
+  don't use any run-time configuration file; equivalent to
+  --nethackrc:/dev/null which behaves as if an empty file.
+
+nethack -dDir
+nethack --directory:Dir
+  could be used to override the build-time value of NETHACKDIR with
+  location Dir; if used, it should precede other command line arguments.
+
+The assorted options above can be combined on a single command line;
+they're listed separately for readability.
+
+*******
+
+Other options which perform some action and then exit rather than play
+the game:
+
+nethack --usage
+nethack --help
+  show this text; 'nethack ?' and 'nethack -?' might also work but the
+  question mark will need to be quoted to prevent the shell from attempting
+  filename matching.
+
+nethack -s
+nethack --scores
+  show scores for the default character; optional additional arguments:
+nethack -s character-name [character-name2 [character-name3 [...]]]
+  show scores for one or more specific character names (might not be
+  effective if PERS_IS_UID=1 is specified in nethack's sysconf file);
+  character names may be preceded by '-u' but that isn't required;
+  special character-name "all" is used to display all scores that pass
+  other criteria;
+nethack -s -p Ppp -r Rrr
+  show scores for specific roles or races; multiple instances can be used;
+  if both '-p' and '-r' are used, scores that match either will be shown
+  rather than scores that match both;
+nethack -s -v
+  show scores only for the current version if the high scores file (record)
+  also contains entries for any older versions; when -v is used, it should
+  immediately follow -s or --scores, preceding any name(s) or -p or -r;
+nethack -dDir -s
+nethack --directory:Dir -s
+  as above; alternative directory, if specified, should come first.
+
+nethack --version
+nethack --version:paste
+  '--version' display the program's version number and exit;
+  '--version:paste' display version number and also copy it into system
+  pasteboard (should work on macOS and Windows; might not work on other
+  systems) so that it could be copied from there into a subsequent email
+  or web contact form, then exit.
+
+nethack --showpaths
+  list expected locations for various files and directorys, then exit;
+  includes the name and location for the run-time configuration file which
+  can vary from platform to platform.
+
index 07e350a72939dadb8f37e183703f4092d4cda0f5..f518340cc149b2627e0a8a7442a37ada4c71e993 100644 (file)
  */
 #endif /* CHDIR */
 
+/*
+ * Define HIDE_USAGE to keep the "description of command line" out of
+ * the help menu if players have no access to a command line or if that
+ * is radically different from the description for UNIX in dat/usagehlp
+ * (a better solution for that would be a separate file and different
+ * value for USAGEHELP in global.h).
+ */
+/* #define HIDE_USAGE */ /* */
+
 /*
  * Section 3:   Definitions that may vary with system type.
  *              For example, both schar and uchar should be short ints on
index 979331619c6ab2e1e0a3343733cbdf05784226cf..b2d15cb0de35e2a10cb01763a8c3ac95c16f5400 100644 (file)
@@ -3303,6 +3303,7 @@ extern char *encglyph(int);
 extern int decode_glyph(const char *str, int *glyph_ptr);
 extern char *decode_mixed(char *, const char *);
 extern void genl_putmixed(winid, int, const char *);
+extern void genl_display_file(const char *, boolean);
 extern boolean menuitem_invert_test(int, unsigned, boolean);
 
 /* ### windows.c ### */
index b04668ea2db852eca84e5b06301ca336cc6d208f..6b53a4b95d46875b2637641be48ff460bda4987b 100644 (file)
@@ -26,6 +26,7 @@
 #define LICENSE "license"       /* file with license information */
 #define OPTIONFILE "opthelp"    /* file explaining runtime options */
 #define OPTMENUHELP "optmenu"   /* file explaining #options command */
+#define USAGEHELP "usagehlp"    /* file explaining command line use */
 #define OPTIONS_USED "options"  /* compile-time options, for #version */
 #define SYMBOLS "symbols"       /* replacement symbol sets */
 #define EPITAPHFILE "epitaph"   /* random epitaphs on graves */
index 6d72ffb46c75c1d5248dd6eefd9b20f2bd1c5242..dc323cd8076ac077fc958c37b6390f559a807700 100644 (file)
@@ -32,6 +32,9 @@ static void dispfile_optionfile(void);
 static void dispfile_optmenu(void);
 static void dispfile_license(void);
 static void dispfile_debughelp(void);
+#ifndef HIDE_USAGE
+static void dispfile_usagehelp(void);
+#endif
 static void hmenu_doextversion(void);
 static void hmenu_dohistory(void);
 static void hmenu_dowhatis(void);
@@ -2355,6 +2358,14 @@ dispfile_debughelp(void)
     display_file(DEBUGHELP, TRUE);
 }
 
+#ifndef HIDE_USAGE
+static void
+dispfile_usagehelp(void)
+{
+    display_file(USAGEHELP, TRUE);
+}
+#endif
+
 static void
 hmenu_doextversion(void)
 {
@@ -2389,6 +2400,7 @@ static void
 domenucontrols(void)
 {
     winid cwin = create_nhwindow(NHW_TEXT);
+
     show_menu_controls(cwin, FALSE);
     display_nhwindow(cwin, FALSE);
     destroy_nhwindow(cwin);
@@ -2411,6 +2423,9 @@ static const struct {
     { dokeylist, "Full list of keyboard commands." },
     { hmenu_doextlist, "List of extended commands." },
     { domenucontrols, "List menu control keys." },
+#ifndef HIDE_USAGE
+    { dispfile_usagehelp, "Description of NetHack's command line." },
+#endif
     { dispfile_license, "The NetHack license." },
     { docontact, "Support information." },
 #ifdef PORT_HELP
index f7981e28e3cca09487b08e3aa513f4a9cc5d133a..f1440efdf07042f70a754e92cc38b8294d57a445 100644 (file)
@@ -3,6 +3,7 @@
 /* NetHack may be freely redistributed.  See license for details. */
 
 #include "hack.h"
+#include "dlb.h"
 #ifdef TTY_GRAPHICS
 #include "wintty.h"
 #endif
@@ -533,7 +534,8 @@ static win_request_info *hup_ctrl_nhwindow(winid, int, win_request_info *);
 
 static struct window_procs hup_procs = {
     WPID(hup), 0L, 0L,
-    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+    { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
+      FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, /* colors */
     hup_init_nhwindows,
     hup_void_ndecl,                                    /* player_selection */
     hup_void_ndecl,                                    /* askname */
@@ -577,7 +579,7 @@ static struct window_procs hup_procs = {
     hup_void_ndecl,                                   /* status_finish */
     genl_status_enablefield, hup_status_update,
     genl_can_suspend_no,
-    hup_void_fdecl_int,                                /* update_inventory */
+    hup_void_fdecl_int,                               /* update_inventory */
     hup_ctrl_nhwindow,
 };
 
@@ -634,9 +636,10 @@ hup_nhgetch(void)
 
 /*ARGSUSED*/
 static char
-hup_yn_function(const char *prompt UNUSED,
-                const char *resp UNUSED,
-                char deflt)
+hup_yn_function(
+    const char *prompt UNUSED,
+    const char *resp UNUSED,
+    char deflt)
 {
     if (!deflt)
         deflt = '\033';
@@ -673,23 +676,26 @@ hup_create_nhwindow(int type UNUSED)
 
 /*ARGSUSED*/
 static int
-hup_select_menu(winid window UNUSED, int how UNUSED,
-                struct mi **menu_list UNUSED)
+hup_select_menu(
+    winid window UNUSED,
+    int how UNUSED,
+    struct mi **menu_list UNUSED)
 {
     return -1;
 }
 
 /*ARGSUSED*/
 static void
-hup_add_menu(winid window UNUSED,
-             const glyph_info *glyphinfo UNUSED,
-             const anything *identifier UNUSED,
-             char sel UNUSED,
-             char grpsel UNUSED,
-             int attr UNUSED,
-             int clr UNUSED,
-             const char *txt UNUSED,
-             unsigned int itemflags UNUSED)
+hup_add_menu(
+    winid window UNUSED,
+    const glyph_info *glyphinfo UNUSED,
+    const anything *identifier UNUSED,
+    char sel UNUSED,
+    char grpsel UNUSED,
+    int attr UNUSED,
+    int clr UNUSED,
+    const char *txt UNUSED,
+    unsigned int itemflags UNUSED)
 {
     return;
 }
@@ -710,10 +716,11 @@ hup_putstr(winid window UNUSED, int attr UNUSED, const char *text UNUSED)
 
 /*ARGSUSED*/
 static void
-hup_print_glyph(winid window UNUSED,
-                coordxy x UNUSED, coordxy y UNUSED,
-                const glyph_info *glyphinfo UNUSED,
-                const glyph_info *bkglyphinfo UNUSED)
+hup_print_glyph(
+    winid window UNUSED,
+    coordxy x UNUSED, coordxy y UNUSED,
+    const glyph_info *glyphinfo UNUSED,
+    const glyph_info *bkglyphinfo UNUSED)
 {
     return;
 }
@@ -781,9 +788,10 @@ hup_get_color_string(void)
 
 /*ARGSUSED*/
 static void
-hup_status_update(int idx UNUSED, genericptr_t ptr UNUSED, int chg UNUSED,
-                  int pc UNUSED, int color UNUSED,
-                  unsigned long *colormasks UNUSED)
+hup_status_update(
+    int idx UNUSED, genericptr_t ptr UNUSED,
+    int chg UNUSED, int pc UNUSED,
+    int color UNUSED, unsigned long *colormasks UNUSED)
 {
     return;
 }
@@ -820,8 +828,9 @@ hup_void_fdecl_winid(winid window UNUSED)
 
 /*ARGUSED*/
 static void
-hup_void_fdecl_winid_ulong(winid window UNUSED,
-                           unsigned long mbehavior UNUSED)
+hup_void_fdecl_winid_ulong(
+    winid window UNUSED,
+    unsigned long mbehavior UNUSED)
 {
     return;
 }
@@ -885,8 +894,11 @@ genl_status_finish(void)
 }
 
 void
-genl_status_enablefield(int fieldidx, const char *nm, const char *fmt,
-                        boolean enable)
+genl_status_enablefield(
+    int fieldidx,
+    const char *nm,
+    const char *fmt,
+    boolean enable)
 {
     status_fieldfmt[fieldidx] = fmt;
     status_fieldnm[fieldidx] = nm;
@@ -897,9 +909,11 @@ DISABLE_WARNING_FORMAT_NONLITERAL
 
 /* call once for each field, then call with BL_FLUSH to output the result */
 void
-genl_status_update(int idx, genericptr_t ptr, int chg UNUSED,
-                   int percent UNUSED, int color UNUSED,
-                   unsigned long *colormasks UNUSED)
+genl_status_update(
+    int idx,
+    genericptr_t ptr,
+    int chg UNUSED, int percent UNUSED,
+    int color UNUSED, unsigned long *colormasks UNUSED)
 {
     char newbot1[MAXCO], newbot2[MAXCO];
     long cond, *condptr = (long *) ptr;
@@ -1084,11 +1098,12 @@ static FILE *dumplog_file;
 static time_t dumplog_now;
 
 char *
-dump_fmtstr(const char *fmt, char *buf,
-            boolean fullsubs) /* True -> full substitution for file name,
-                                 False -> partial substitution for
-                                          '--showpaths' feedback where there's
-                                          no game in progress when executed */
+dump_fmtstr(
+    const char *fmt,
+    char *buf,
+    boolean fullsubs) /* True -> full substitution for file name,
+                       * False -> partial substitution for '--showpaths'
+                       * feedback where there's no game in progress */
 {
     const char *fp = fmt;
     char *bp = buf;
@@ -1493,6 +1508,27 @@ genl_putmixed(winid window, int attr, const char *str)
     putstr(window, attr, decode_mixed(buf, str));
 }
 
+/* possibly called to show usage info during command line processing when
+   an interface hasn't yet been chosen and set up */
+void
+genl_display_file(const char *fname, boolean complain)
+{
+    char buf[BUFSZ];
+    dlb *f = dlb_fopen(fname, "r");
+
+    if (!f) {
+        if (complain) /* send complaint to stdout rather than to stderr */
+            fprintf(stdout, "\nCannot open \"%s\".\n", fname);
+    } else {
+        /* straight copy to stdout, no pagination or other interaction */
+        while (dlb_fgets(buf, BUFSZ, f)) {
+            if (fputs(buf, stdout) < 0)
+                break;
+        }
+        (void) dlb_fclose(f);
+    }
+}
+
 /*
  * Window port helper function for menu invert routines to move the decision
  * logic into one place instead of 7 different window-port routines.
index 423465bf2051ca9185f01960b69db6dc0dcd2a4e..903feb3a07fec2f979ceb472397b7b6f20f8cb5d 100644 (file)
@@ -1191,7 +1191,7 @@ $(TARGETPFX)vision.o: vision.c $(HACK_H)
 $(TARGETPFX)weapon.o: weapon.c $(HACK_H)
 $(TARGETPFX)were.o: were.c $(HACK_H)
 $(TARGETPFX)wield.o: wield.c $(HACK_H)
-$(TARGETPFX)windows.o: windows.c $(HACK_H) ../include/wintty.h
+$(TARGETPFX)windows.o: windows.c $(HACK_H) ../include/dlb.h ../include/wintty.h
 $(TARGETPFX)wizard.o: wizard.c $(HACK_H)
 $(TARGETPFX)worm.o: worm.c $(HACK_H)
 $(TARGETPFX)worn.o: worn.c $(HACK_H)
index 802e9b7e3b940db45c7d21884ff094881ece1436..f3cc25fe1a99e0a7852777a75b3185a817a11904 100644 (file)
@@ -91,7 +91,7 @@ LUA_VERSION = 5.4.4
 # end of configuration
 #
 
-DATHELP = help hh cmdhelp keyhelp history opthelp optmenu wizhelp
+DATHELP = help hh cmdhelp keyhelp history opthelp optmenu usagehlp wizhelp
 
 SPEC_LEVS = asmodeus.lua baalz.lua bigrm-*.lua castle.lua fakewiz?.lua \
        juiblex.lua knox.lua medusa-?.lua minend-?.lua minefill.lua \
index 6cdf30c9439e3e0706d8b4a5459134346c7dfdbe..b212208832e9b786f5ddcd357c21738d2b1ce79b 100644 (file)
@@ -36,6 +36,7 @@ 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_usage(const char *) NORETURN;
 static void opt_showpaths(const char *);
 static void scores_only(int, char **, const char *) NORETURN;
 
@@ -571,6 +572,12 @@ early_options(int *argc_p, char ***argv_p, char **hackdir_p)
 
     config_error_init(FALSE, "command line", FALSE);
 
+    /* treat "nethack ?" as a request for usage info; due to shell
+       processing, player likely has to use "nethack \?" or "nethack '?'"
+       [won't work if used as "nethack -dpath ?" or "nethack -d path ?"] */
+    if (*argc_p > 1 && !strcmp((*argv_p)[1], "?"))
+        opt_usage(*hackdir_p); /* doesn't return */
+
     /*
      * 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).
@@ -617,6 +624,12 @@ early_options(int *argc_p, char ***argv_p, char **hackdir_p)
 #endif /* CHDIR */
             }
             break;
+        case 'h':
+        case '?':
+            if (lopt(arg, ArgValDisallowed, "-help", origarg, &argc, &argv)
+                || lopt(arg, ArgValDisallowed, "-?", origarg, &argc, &argv))
+                opt_usage(*hackdir_p); /* doesn't return */
+            break;
         case 'n':
             oldargc = argc;
             if (!strcmp(arg, "-no-nethackrc")) /* no abbreviation allowed */
@@ -653,6 +666,10 @@ early_options(int *argc_p, char ***argv_p, char **hackdir_p)
                 /*NOTREACHED*/
             }
             break;
+        case 'u':
+            if (lopt(arg, ArgValDisallowed, "-usage", origarg, &argc, &argv))
+                opt_usage(*hackdir_p);
+            break;
         case 'v':
             if (argcheck(argc, argv, ARG_VERSION) == 2) {
                 opt_terminate();
@@ -689,6 +706,20 @@ opt_terminate(void)
     /*NOTREACHED*/
 }
 
+static void
+opt_usage(const char *hackdir)
+{
+#ifdef CHDIR
+    chdirx(hackdir, TRUE);
+#else
+    nhUse(hackdir);
+#endif
+    dlb_init();
+
+    genl_display_file(USAGEHELP, TRUE);
+    opt_terminate();
+}
+
 /* show the sysconf file name, playground directory, run-time configuration
    file name, dumplog file name if applicable, and some other things */
 static void