[nasm:nasm-2.16.xx] nasm.c: tidy up the help text and break it into topics
nasm-bot for H. Peter Anvin
hpa at zytor.com
Thu Apr 25 15:18:07 PDT 2024
Commit-ID: cd1fd8ac8e1ba1be52f93d2a87b5be31c55876fd
Gitweb: http://repo.or.cz/w/nasm.git?a=commitdiff;h=cd1fd8ac8e1ba1be52f93d2a87b5be31c55876fd
Author: H. Peter Anvin <hpa at zytor.com>
AuthorDate: Thu, 25 Apr 2024 15:14:20 -0700
Committer: H. Peter Anvin <hpa at zytor.com>
CommitDate: Thu, 25 Apr 2024 15:14:20 -0700
nasm.c: tidy up the help text and break it into topics
The help output has gotten way too long to be shown on a single
command line. It can of course be piped to a pager, but to be a little
nicer to the user, break it up into subtopics that can be individually
displayed. --help all (-h all) can still show all the help information
as a single data dump.
Signed-off-by: H. Peter Anvin <hpa at zytor.com>
---
asm/nasm.c | 468 +++++++++++++++++++++++++++++++++++++++++++------------------
1 file changed, 328 insertions(+), 140 deletions(-)
diff --git a/asm/nasm.c b/asm/nasm.c
index 97d926fc..e97a0af9 100644
--- a/asm/nasm.c
+++ b/asm/nasm.c
@@ -1,6 +1,6 @@
/* ----------------------------------------------------------------------- *
*
- * Copyright 1996-2022 The NASM Authors - All Rights Reserved
+ * Copyright 1996-2024 The NASM Authors - All Rights Reserved
* See the file AUTHORS included with the NASM distribution for
* the specific copyright holders.
*
@@ -76,7 +76,7 @@ static void parse_cmdline(int, char **, int);
static void assemble_file(const char *, struct strlist *);
static bool skip_this_pass(errflags severity);
static void usage(void);
-static void help(FILE *);
+static void help(FILE *out, const char *what);
struct error_format {
const char *beforeline; /* Before line number, if present */
@@ -752,8 +752,10 @@ int main(int argc, char **argv)
/*
* Get a parameter for a command line option.
* First arg must be in the form of e.g. -f...
+ *
+ * get_param() errors on a missing argument; get_opt_param() does not.
*/
-static char *get_param(char *p, char *q, bool *advance)
+static char *get_opt_param(char *p, char *q, bool *advance)
{
*advance = false;
if (p[2]) /* the parameter's in the option */
@@ -762,9 +764,15 @@ static char *get_param(char *p, char *q, bool *advance)
*advance = true;
return q;
}
- nasm_nonfatalf(ERR_USAGE, "option `-%c' requires an argument", p[1]);
return NULL;
}
+static char *get_param(char *p, char *q, bool *advance)
+{
+ char *r = get_opt_param(p, q, advance);
+ if (!r)
+ nasm_nonfatalf(ERR_USAGE, "option `-%c' requires an argument", p[1]);
+ return r;
+}
/*
* Copy a filename
@@ -956,7 +964,7 @@ struct textargs {
static const struct textargs textopts[] = {
{"v", OPT_VERSION, ARG_NO, 0},
{"version", OPT_VERSION, ARG_NO, 0},
- {"help", OPT_HELP, ARG_NO, 0},
+ {"help", OPT_HELP, ARG_MAYBE, 0},
{"abort-on-panic", OPT_ABORT_ON_PANIC, ARG_NO, 0},
{"prefix", OPT_MANGLE, ARG_YES, LM_GPREFIX},
{"postfix", OPT_MANGLE, ARG_YES, LM_GSUFFIX},
@@ -1113,12 +1121,17 @@ static bool process_arg(char *p, char *q, int pass)
case 'X': /* specify error reporting format */
if (pass == 1) {
- if (!nasm_stricmp("vc", param) || !nasm_stricmp("msvc", param) || !nasm_stricmp("ms", param))
+ if (!nasm_stricmp("vc", param) ||
+ !nasm_stricmp("msvc", param) ||
+ !nasm_stricmp("ms", param))
errfmt = &errfmt_msvc;
- else if (!nasm_stricmp("gnu", param) || !nasm_stricmp("gcc", param))
+ else if (!nasm_stricmp("gnu", param) ||
+ !nasm_stricmp("gcc", param))
errfmt = &errfmt_gnu;
else
- nasm_fatalf(ERR_USAGE, "unrecognized error reporting format `%s'", param);
+ nasm_fatalf(ERR_USAGE,
+ "unrecognized error reporting format `%s'",
+ param);
}
break;
@@ -1131,13 +1144,14 @@ static bool process_arg(char *p, char *q, int pass)
break;
case 'h':
- help(stdout);
+ case '?':
+ help(stdout, get_opt_param(p, q, &advance));
exit(0); /* never need usage message here */
break;
case 'y':
/* legacy option */
- dfmt_list(stdout);
+ help(stdout, "-F");
exit(0);
break;
@@ -1330,13 +1344,17 @@ static bool process_arg(char *p, char *q, int pass)
ppopt |= PP_NOLINE;
break;
case OPT_DEBUG:
- debug_nasm = param ? strtoul(param, NULL, 10) : debug_nasm+1;
+ debug_nasm = param ?
+ strtoul(param, NULL, 10) : debug_nasm+1;
break;
case OPT_REPRODUCIBLE:
reproducible = true;
break;
case OPT_HELP:
- help(stdout);
+ /* Allow --help topic without *requiring* topic */
+ if (!param)
+ param = q;
+ help(stdout, param);
exit(0);
default:
panic();
@@ -2210,143 +2228,313 @@ done:
static void usage(void)
{
- fprintf(error_file, "Type %s -h for help.\n", _progname);
+ fprintf(error_file,
+ "Usage: %s [-@ response_file] [options...] [--] filename\n"
+ " For additional help:\n"
+ " %s -h [run|topics|all|-option]\n",
+ _progname, _progname);
}
-static void help(FILE *out)
+enum help_with {
+ HW_ALL = 0,
+ HW_OPT = 1,
+ HW_ERR = 2,
+ HW_LIMIT = 3
+};
+
+static inline bool help_is(int with, int h) {
+ return with == HW_ALL || with == h;
+}
+static inline bool help_opt(int with)
{
- int i;
+ return help_is(with, HW_OPT);
+}
+static inline bool help_optor(int with, int h)
+{
+ return help_opt(with) || with == h;
+}
- fprintf(out,
- "Usage: %s [-@ response_file] [options...] [--] filename\n"
- " %s -v (or --v)\n",
- _progname, _progname);
- fputs(
- "\n"
- "Options (values in brackets indicate defaults):\n"
- "\n"
- " -h show this text and exit (also --help)\n"
- " -v (or --v) print the NASM version number and exit\n"
- " -@ file response file; one command line option per line\n"
- "\n"
- " -o outfile write output to outfile\n"
- " --keep-all output files will not be removed even if an error happens\n"
- "\n"
- " -Xformat specify error reporting format (gnu or vc)\n"
- " -s redirect error messages to stdout\n"
- " -Zfile redirect error messages to file\n"
- "\n"
- " -M generate Makefile dependencies on stdout\n"
- " -MG d:o, missing files assumed generated\n"
- " -MF file set Makefile dependency file\n"
- " -MD file assemble and generate dependencies\n"
- " -MT file dependency target name\n"
- " -MQ file dependency target name (quoted)\n"
- " -MP emit phony targets\n"
- "\n"
- " -f format select output file format\n"
- , out);
- ofmt_list(ofmt, out);
- fputs(
- "\n"
- " -g generate debugging information\n"
- " -F format select a debugging format (output format dependent)\n"
- " -gformat same as -g -F format\n"
- , out);
- dfmt_list(out);
- fputs(
- "\n"
- " -l listfile write listing to a list file\n"
- " -Lflags... add optional information to the list file\n"
- " -Lb show builtin macro packages (standard and %use)\n"
- " -Ld show byte and repeat counts in decimal, not hex\n"
- " -Le show the preprocessed output\n"
- " -Lf ignore .nolist (force output)\n"
- " -Lm show multi-line macro calls with expanded parameters\n"
- " -Lp output a list file every pass, in case of errors\n"
- " -Ls show all single-line macro definitions\n"
- " -Lw flush the output after every line (very slow!)\n"
- " -L+ enable all listing options except -Lw (very verbose!)\n"
- "\n"
- " -Oflags... optimize opcodes, immediates and branch offsets\n"
- " -O0 no optimization\n"
- " -O1 minimal optimization\n"
- " -Ox multipass optimization (default)\n"
- " -Ov display the number of passes executed at the end\n"
- " -t assemble in limited SciTech TASM compatible mode\n"
- "\n"
- " -E (or -e) preprocess only (writes output to stdout by default)\n"
- " -a don't preprocess (assemble only)\n"
- " -Ipath add a pathname to the include file path\n"
- " -Pfile pre-include a file (also --include)\n"
- " -Dmacro[=str] pre-define a macro\n"
- " -Umacro undefine a macro\n"
- " --pragma str pre-executes a specific %%pragma\n"
- " --before str add line (usually a preprocessor statement) before the input\n"
- " --no-line ignore %line directives in input\n"
- "\n"
- " --prefix str prepend the given string to the names of all extern,\n"
- " common and global symbols (also --gprefix)\n"
- " --suffix str append the given string to the names of all extern,\n"
- " common and global symbols (also --gprefix)\n"
- " --lprefix str prepend the given string to local symbols\n"
- " --lpostfix str append the given string to local symbols\n"
- "\n"
- " --reproducible attempt to produce run-to-run identical output\n"
- "\n"
- " -w+x enable warning x (also -Wx)\n"
- " -w-x disable warning x (also -Wno-x)\n"
- " -w[+-]error promote all warnings to errors (also -Werror)\n"
- " -w[+-]error=x promote warning x to errors (also -Werror=x)\n"
- , out);
-
- fprintf(out, " %-20s %s\n",
- warning_name[WARN_IDX_ALL], warning_help[WARN_IDX_ALL]);
-
- for (i = 1; i < WARN_IDX_ALL; i++) {
- const char *me = warning_name[i];
- const char *prev = warning_name[i-1];
- const char *next = warning_name[i+1];
-
- if (prev) {
- int prev_len = strlen(prev);
- const char *dash = me;
-
- while ((dash = strchr(dash+1, '-'))) {
- int prefix_len = dash - me; /* Not including final dash */
- if (strncmp(next, me, prefix_len+1)) {
- /* Only one or last option with this prefix */
- break;
- }
- if (prefix_len >= prev_len ||
- strncmp(prev, me, prefix_len) ||
- (prev[prefix_len] != '-' && prev[prefix_len] != '\0')) {
- /* This prefix is different from the previous option */
- fprintf(out, " %-20.*s all warnings prefixed with \"%.*s\"\n",
- prefix_len, me, prefix_len+1, me);
- }
- }
+static void help(FILE *out, const char *what)
+{
+ int i;
+ int with;
+
+#define SEE(x) (with == HW_OPT ? " (see -h " x ")" : "")
+
+ with = HW_ERR;
+
+ if (!what || !*what || !strcmp(what, "-") || !strcmp(what, "--") ||
+ !nasm_stricmp(what, "opt") ||
+ !nasm_stricmp(what, "run") ||
+ !nasm_stricmp(what, "cmd")) {
+ with = HW_OPT;
+ } else if (!nasm_stricmp(what, "all")) {
+ with = HW_ALL;
+ } else if (!nasm_strnicmp(what, "--limit", 7) ||
+ !nasm_strnicmp(what, "limit", 5)) {
+ with = HW_LIMIT;
+ } else if (!nasm_stricmp(what, "--help") ||
+ !nasm_stricmp(what, "help") ||
+ !nasm_stricmp(what, "list") ||
+ !nasm_stricmp(what, "topics") ||
+ !nasm_stricmp(what, "index")) {
+ with = 'h';
+ } else if ((what[0] == '-' && what[1] && !what[2]) ||
+ (what[0] && !what[1])) {
+ with = what[0] == '-' ? what[1] : what[0];
+ switch (with) {
+ case 'h':
+ case 'X':
+ case 'L':
+ case 'f':
+ case 'F':
+ case 'O':
+ case 'w':
+ case 'M':
+ break;
+ case 'g':
+ with = 'F';
+ break;
+ case 'W':
+ with = 'w';
+ break;
+ case '?':
+ with = 'h';
+ break;
+ case '*':
+ with = HW_ALL;
+ break;
+ default:
+ with = HW_ERR;
+ break;
}
-
- fprintf(out, " %-20s %s%s\n",
- warning_name[i], warning_help[i],
- (warning_default[i] & WARN_ST_ERROR) ? " [error]" :
- (warning_default[i] & WARN_ST_ENABLED) ? " [on]" : " [off]");
}
- fputs(
- "\n"
- " --limit-X val set execution limit X\n"
- , out);
+ if (with == HW_ERR) {
+ fprintf(out, "Sorry, no help available for `%s'\n", what);
+ return;
+ }
+ if (help_opt(with)) {
+ fprintf(out,
+ "Usage: %s [-@ response_file] [options...] [--] filename\n"
+ " Options:\n"
+ " -v (or --v) print the NASM version number and exit\n"
+ " -@ file response file; one command line option per line\n",
+ _progname);
+ }
+ if (help_optor(with, 'h')) {
+ fputs(
+ " -h list command line options and exit (also --help)\n"
+ , out);
+ if (with == HW_OPT) {
+ fputs(
+ " -h -opt show additional help for option \"-opt\"\n"
+ , out);
+ }
+ fputs(
+ " -h all show all available command line help\n"
+ " -h topics show list of help topics (also -h list)\n"
+ , out);
+ }
+ if (help_is(with, 'h')) {
+ fputs(
+ " -h -X show list of error message formats\n"
+ " -h -M show list of dependency generation options\n"
+ " -h -f show list of object code output formats\n"
+ " -h -F show list of debug information formats\n"
+ " -h -L show list of list file option flags\n"
+ " -h -O show list of optimization flags\n"
+ " -h -w show list of warning classes and defaults\n"
+ " -h --limit show list of resource limits and defaults\n"
+ , out);
+ }
+ if (help_opt(with)) {
+ fputs(
+ " -o outfile write output to outfile\n"
+ " --keep-all output files will not be removed even if an error happens\n"
+ , out);
+ }
+ if (help_optor(with, 'X')) {
+ fprintf(out,
+ " -Xformat specify error reporting format%s\n",
+ SEE("-X"));
+ }
+ if (help_is(with, 'X')) {
+ fputs(
+ " -Xgnu report errors in GNU format (default)\n"
+ " -Xgcc alias for -Xgnu\n"
+ " -Xvc report errors in Visual Studio format\n"
+ " -Xmsvc alias for -Xvc\n"
+ " -Xms alias for -Xvc\n"
+ , out);
+ }
+ if (help_opt(with)) {
+ fputs(
+ " -s redirect error messages to stdout\n"
+ " -Zfile redirect error messages to file\n"
+ , out);
+ }
+ if (help_optor(with, 'M')) {
+ fprintf(out,
+ " -M... generate Makefile dependencies%s\n",
+ with == HW_OPT
+ ? " (see -h -M)"
+ : " (multiple options permitted):");
+ }
+ if (help_is(with, 'M')) {
+ fputs(
+ " -M generate Makefile dependencies on stdout\n"
+ " -MG d:o, missing files assumed generated\n"
+ " -MF file set Makefile dependency file\n"
+ " -MD file assemble and generate dependencies\n"
+ " -MT file dependency target name\n"
+ " -MQ file dependency target name (quoted)\n"
+ " -MP emit phony targets\n"
+ " -MW generate output in Watcom wmake syntax\n"
+ , out);
+ }
+ if (help_optor(with, 'f')) {
+ fprintf(out,
+ " -f format select output file format%s\n",
+ SEE("-f"));
+ }
+ if (help_is(with, 'f')) {
+ ofmt_list(ofmt, out);
+ }
+ if (help_optor(with, 'F')) {
+ fprintf(out,
+ " -g generate debugging information\n"
+ " -F format select a debugging format%s\n"
+ " -gformat same as -g -F format\n",
+ SEE("-F"));
+ }
+ if (help_is(with, 'F')) {
+ dfmt_list(out);
+ }
+ if (help_optor(with, 'L')) {
+ fprintf(out,
+ " -l listfile write listing to a list file\n"
+ " -Lflags... add information to the list file%s\n",
+ SEE("-L"));
+ }
+ if (help_is(with, 'L')) {
+ fputs(
+ " -Lb show builtin macro packages (standard and %use)\n"
+ " -Ld show byte and repeat counts in decimal, not hex\n"
+ " -Le show the preprocessed output\n"
+ " -Lf ignore .nolist (force output)\n"
+ " -Lm show multi-line macro calls with expanded parameters\n"
+ " -Lp output a list file every pass, in case of errors\n"
+ " -Ls show all single-line macro definitions\n"
+ " -Lw flush the output after every line (very slow!)\n"
+ " -L+ enable all listing options except -Lw (very verbose!)\n"
+ , out);
+ }
+ if (help_optor(with, 'O')) {
+ fprintf(out,
+ " -Oflags... select optimization%s\n", SEE("-O"));
+ }
+ if (help_is(with, 'O')) {
+ fputs(
+ " -O0 no optimization\n"
+ " -O1 minimal optimization\n"
+ " -Ox multipass optimization (default, recommended)\n"
+ " -Ov display the number of passes executed at the end\n"
+ , out);
+ }
+ if (help_opt(with)) {
+ fputs(
+ " -t assemble in limited SciTech TASM compatible mode\n"
+ " -E (or -e) preprocess only (writes output to stdout by default)\n"
+ " -a don't preprocess (assemble only)\n"
+ " -Ipath add a pathname to the include file path\n"
+ " -Pfile pre-include a file (also --include)\n"
+ " -Dmacro[=str] pre-define a macro\n"
+ " -Umacro undefine a macro\n"
+ , out);
+ }
+ if (help_optor(with, 'w')) {
+ fprintf(out,
+ " -w+x enable warning x %s(also -Wx)\n"
+ " -w-x disable warning x (also -Wno-x)\n"
+ " -w[+-]error promote all warnings to errors (also -Werror)\n"
+ " -w[+-]error=x promote warning x to errors (also -Werror=x)\n",
+ SEE("-w"));
+ }
+ if (help_is(with, 'w')) {
+ fputs(" Defaults in brackets:\n", out);
+
+ fprintf(out, " %-20s %s\n",
+ warning_name[WARN_IDX_ALL], warning_help[WARN_IDX_ALL]);
+
+ for (i = 1; i < WARN_IDX_ALL; i++) {
+ static const char nl_indent[] =
+ "\n ";
+ const char *me = warning_name[i];
+ const char *prev = warning_name[i-1];
+ const char *next = warning_name[i+1];
+
+ if (prev) {
+ int prev_len = strlen(prev);
+ const char *dash = me;
+
+ while ((dash = strchr(dash+1, '-'))) {
+ int prefix_len = dash - me; /* Not including final dash */
+ if (strncmp(next, me, prefix_len+1)) {
+ /* Only one or last option with this prefix */
+ break;
+ }
+ if (prefix_len >= prev_len ||
+ strncmp(prev, me, prefix_len) ||
+ (prev[prefix_len] != '-' && prev[prefix_len] != '\0')) {
+ /* This prefix is different from the previous option */
+ fprintf(out, " %-20.*s%sall warnings prefixed with \"%.*s\"\n",
+ prefix_len, me,
+ prefix_len > 19 ? nl_indent : " ",
+ prefix_len+1, me);
+ }
+ }
+ }
- for (i = 0; i <= LIMIT_MAX; i++) {
- fprintf(out, " %-20s %s [",
- limit_info[i].name, limit_info[i].help);
- if (nasm_limit[i] < LIMIT_MAX_VAL) {
- fprintf(out, "%"PRId64"]\n", nasm_limit[i]);
- } else {
- fputs("unlimited]\n", out);
+ fprintf(out, " %-20s%s%s%s\n",
+ warning_name[i],
+ strlen(warning_name[i]) > 19 ? nl_indent : " ",
+ warning_help[i],
+ (warning_default[i] & WARN_ST_ERROR) ? " [error]" :
+ (warning_default[i] & WARN_ST_ENABLED) ? " [on]" : " [off]");
+ }
+ }
+ if (help_opt(with)) {
+ fputs(
+ " --pragma str pre-executes a specific %pragma\n"
+ " --before str add line (usually a preprocessor statement) before the input\n"
+ " --no-line ignore %line directives in input\n"
+ " --prefix str prepend the given string to the names of all extern,\n"
+ " common and global symbols (also --gprefix)\n"
+ " --suffix str append the given string to the names of all extern,\n"
+ " common and global symbols (also --gprefix)\n"
+ " --lprefix str prepend the given string to local symbols\n"
+ " --lpostfix str append the given string to local symbols\n"
+ " --reproducible attempt to produce run-to-run identical output\n"
+ , out);
+ }
+ if (help_optor(with, HW_LIMIT)) {
+ fprintf(out, " --limit-X val set execution limit X%s\n",
+ SEE("--limit"));
+ }
+ if (help_is(with, HW_LIMIT)) {
+ fputs(" Defaults in brackets:\n", out);
+
+ for (i = 0; i <= LIMIT_MAX; i++) {
+ fprintf(out, " %-20s %s [",
+ limit_info[i].name, limit_info[i].help);
+ if (nasm_limit[i] < LIMIT_MAX_VAL) {
+ fprintf(out, "%"PRId64"]\n", nasm_limit[i]);
+ } else {
+ fputs("unlimited]\n", out);
+ }
}
}
+#undef SEE
}
More information about the Nasm-commits
mailing list