'nethack --usage' and '?' menu

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.
This commit is contained in:
PatR
2022-11-18 16:07:15 -08:00
parent 75eaf59354
commit 9a7f8418ee
9 changed files with 262 additions and 37 deletions

View 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

View 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.