From 2845baff59e5e2c3ec826f720e493d605bfdd962 Mon Sep 17 00:00:00 2001 From: Christopher Wellons Date: Thu, 22 Oct 2026 20:48:38 -0400 Subject: [PATCH] Let MANROFFOPT choose ragged-right manual pages nroff now accepts groff's -d option to define a string, and man appends $MANROFFOPT to the nroff command line, as man-db does. Since nroff already honors the man(7) AD string, MANROFFOPT=-dAD=l sets pages ragged-right instead of adjusting them to both margins. Co-Authored-By: Claude Opus 5.5 --- man/man1/man.1 | 28 ++++++++++++++++++++++++++-- man/man1/nroff.1 | 43 +++++++++++++++++++++++++++++++++++++++---- src/busybox/man.patch | 36 ++++++++++++++++++++++-------------- src/nroff.c | 16 +++++++++++++++- 4 files changed, 102 insertions(+), 21 deletions(-) diff --git a/man/man1/man.1 b/man/man1/man.1 index 2566edf..8f85116 100644 --- a/man/man1/man.1 +++ b/man/man1/man.1 @@ -1,4 +1,4 @@ -.TH MAN 1 2026-10-20 "w64devkit" "w64devkit Manual" +.TH MAN 1 2026-10-22 "w64devkit" "w64devkit Manual" .SH NAME man \- display manual pages .SH SYNOPSIS @@ -157,7 +157,10 @@ The page is its standard input, and its options are .BI \-T charset\fR, .BI \-rLL= w n\fR, and -.BI \-rLT= w n\fR. +.BI \-rLT= w n\fR, +followed by the value of +.B MANROFFOPT +when that is set. Its output and error messages go to the pager. .PP The @@ -323,6 +326,18 @@ still counts, and then nothing is displayed. .B MANPATH Manual directories to search first, separated by semicolons. .TP +.B MANROFFOPT +Further options for +.BR nroff , +added to its command line, where +.B sh +splits them into words. +For example, +.B \-dAD=l +sets man(7) pages ragged-right instead of adjusting them to both +margins; see +.BR nroff (1). +.TP .B PAGER The pager, when .B MANPAGER @@ -413,6 +428,15 @@ Save a page as plain text, formatted for a 100-column display: $ COLUMNS=100 man gcc >gcc.txt .EE .RE +.PP +Show pages with a ragged right margin, for example from +.IR $HOME/.profile : +.PP +.RS 4 +.EX +export MANROFFOPT=\-dAD=l +.EE +.RE .SH NOTES Differences from the .B man diff --git a/man/man1/nroff.1 b/man/man1/nroff.1 index 6f453ac..fbc7bb9 100644 --- a/man/man1/nroff.1 +++ b/man/man1/nroff.1 @@ -1,4 +1,4 @@ -.TH NROFF 1 2026-10-20 "w64devkit" "w64devkit Manual" +.TH NROFF 1 2026-10-22 "w64devkit" "w64devkit Manual" .SH NAME nroff \- format manual pages for a terminal .SH SYNOPSIS @@ -8,6 +8,7 @@ nroff \- format manual pages for a terminal .RB [ \-Tascii " | " \-Tutf8 ] [\fB\-rLL=\fIN\fBn\fR] [\fB\-r\fIreg\fB=\fIN\fR] +[\fB\-d\fIname\fB=\fIstring\fR] .RB [ \-w ] .RI [ file ...] .SH DESCRIPTION @@ -57,7 +58,9 @@ a line also breaks after an em dash written as .B \e(em between two letters. man(7) pages are adjusted to both margins, as in groff, unless the page -asks otherwise; mdoc(7) pages are left-aligned, as in mandoc. +asks otherwise or +.B \-dAD=l +is given; mdoc(7) pages are left-aligned, as in mandoc. .PP Bold text is written between the SGR escape sequences .B ESC[1m @@ -562,9 +565,10 @@ are approximated. .SH OPTIONS Options are not grouped. The arguments of -.B \-T +.BR \-T , +.BR \-r , and -.B \-r +.B \-d may be attached or separate, and .B \-\- ends the options. @@ -622,6 +626,37 @@ which .BR man (1) passes, has no effect. .TP +\fB\-d\fIname\fB=\fIstring\fR +Define the string +.I name +as +.IR string , +as +.B .ds +does. +Without +.BR = , +the first character is the name and the rest is the string, as in +groff. +A man(7) page reads the string +.B AD +at +.B .TH +and at each paragraph macro to choose its adjustment, as groff does: +.B l +sets text ragged-right, +.B c +centers it, +.B r +aligns it right, and anything else, the default, adjusts it to both +margins. +.BR man (1) +passes this option from +.BR MANROFFOPT , +so +.B MANROFFOPT=\-dAD=l +gives ragged-right pages. +.TP .B \-w Warn on standard error, with file names and line numbers, about unknown macros, requests, escapes, and glyphs, undefined strings, diff --git a/src/busybox/man.patch b/src/busybox/man.patch index febb0ab..28a960a 100644 --- a/src/busybox/man.patch +++ b/src/busybox/man.patch @@ -9,11 +9,12 @@ Run the formatter in the manpath element, or in the user's directory for an explicit path, so that .so requests in page bodies resolve. Look up x86_64-w64-mingw32-NAME and i686-w64-mingw32-NAME as NAME when there is no page under the full name. Accept backslashes in absolute paths, and -CRLF in .so stubs. +CRLF in .so stubs. Append $MANROFFOPT to the formatter options, as +man-db does, so that, e.g., MANROFFOPT=-dAD=l sets pages ragged-right. --- - miscutils/man.c | 90 +++++++++++++++++++++++++++++++++++++------------------- - 1 file changed, 60 insertions(+), 30 deletions(-) + miscutils/man.c | 92 +++++++++++++++++++++++++++++++++++++------------------- + 1 file changed, 62 insertions(+), 30 deletions(-) --- a/miscutils/man.c +++ b/miscutils/man.c @@ -70,7 +71,13 @@ CRLF in .so stubs. //testcase: // cd /usr/share/man/man2 // man ./path_resolution.2.gz -@@ -163,13 +180,20 @@ +@@ -158,18 +175,27 @@ + open_zipped(man_filename, /*die_if_not_compressed:*/ 0); /* guaranteed to use fd 0 (STDIN_FILENO) */ + if (man) { + int w = get_terminal_width(-1); ++ const char *opt = getenv("MANROFFOPT"); + if (w > 10) + w -= 2; /* "2>&1" is added so that nroff errors are shown in pager too. * Otherwise it may show just empty screen. */ @@ -78,8 +85,9 @@ CRLF in .so stubs. - G.tbl, G.nroff, w, w, - G.pager); - } else { -+ cmd = xasprintf("%s -T%s -rLL=%un -rLT=%un%s%s", ++ cmd = xasprintf("%s -T%s -rLL=%un -rLT=%un%s%s%s%s", + G.nroff, GetACP() == CP_UTF8 ? "utf8" : "ascii", w, w, ++ opt ? " " : "", opt ? opt : "", + G.pager ? " 2>&1 | " : "", G.pager ? G.pager : ""); + } else if (G.pager) { cmd = xstrdup(G.pager); @@ -95,7 +103,7 @@ CRLF in .so stubs. free(cmd); return 1; } -@@ -273,8 +297,7 @@ +@@ -273,8 +299,7 @@ char *token[2]; #if ENABLE_PLATFORM_MINGW32 char **ptr; @@ -105,7 +113,7 @@ CRLF in .so stubs. #endif INIT_G(); -@@ -285,8 +308,9 @@ +@@ -285,8 +310,9 @@ /* add system drive prefix to filenames, if necessary */ for (ptr = argv; *ptr; ++ptr) { if (strchr(*ptr, '/') || strchr(*ptr, '\\')) @@ -116,7 +124,7 @@ CRLF in .so stubs. chdir_system_drive(); #endif -@@ -309,8 +333,6 @@ +@@ -309,8 +335,6 @@ if (!token[1]) continue; if (strcmp("DEFINE", token[0]) == 0) { @@ -125,7 +133,7 @@ CRLF in .so stubs. G.nroff = if_redefined(G.nroff, "nroff", token[1]); G.pager = if_redefined(G.pager, "pager", token[1]); } else -@@ -328,15 +350,9 @@ +@@ -328,15 +352,9 @@ #if ENABLE_PLATFORM_MINGW32 /* allow man pages to be stored relative to the executable */ @@ -144,7 +152,7 @@ CRLF in .so stubs. #else if (!man_path_list) { static const char *const mpl[] ALIGN_PTR = { "/usr/man", "/usr/share/man", NULL }; -@@ -356,7 +372,10 @@ +@@ -356,7 +374,10 @@ if (!isatty(STDOUT_FILENO)) { putenv((char*)"GROFF_NO_SGR=1"); @@ -156,7 +164,7 @@ CRLF in .so stubs. } /* is 1st ARG a SECTION? */ -@@ -371,9 +390,12 @@ +@@ -371,9 +392,12 @@ const char *cur_path; int cur_mp; int found = 0; @@ -171,7 +179,7 @@ CRLF in .so stubs. goto check_found; } -@@ -383,7 +405,8 @@ +@@ -383,7 +407,8 @@ const char *cur_sect = sec_list; /* is MANPAGE of the form NAME.SECTION? */ @@ -181,7 +189,7 @@ CRLF in .so stubs. if (sect_ext && is_section_name(conf_sec_list, sect_ext + 1)) { *sect_ext = '\0'; cur_sect = sect_ext + 1; -@@ -402,7 +425,7 @@ +@@ -402,7 +427,7 @@ cur_path, "cat\0man" + (cat0man1 * 4), sect_len, cur_sect, @@ -190,7 +198,7 @@ CRLF in .so stubs. sect_len, cur_sect); found_here = show_manpage(man_filename, cat0man1, 0); found |= found_here; -@@ -421,6 +444,13 @@ +@@ -421,6 +446,13 @@ } check_found: if (!found) { diff --git a/src/nroff.c b/src/nroff.c index cdba2c2..133b91f 100644 --- a/src/nroff.c +++ b/src/nroff.c @@ -6919,12 +6919,14 @@ static void run(Ctx *c, Arena scratch) static void usage(Output *out) { print(out, S( - "usage: nroff [-man|-mdoc] [-Tascii|-Tutf8] [-rLL=Nn] [-w] [FILE...]\n" + "usage: nroff [-man|-mdoc] [-Tascii|-Tutf8] [-rLL=Nn] [-dNAME=STR] [-w]" + " [FILE...]\n" " -m* accepted and ignored; the format is detected\n" " -t accepted and ignored; tbl is built in\n" " -Tascii ASCII output (default)\n" " -Tutf8 UTF-8 output\n" " -rLL=N line length (default: $MANWIDTH, $COLUMNS, or 78)\n" + " -dAD=l ragged-right man(7) pages (also c, r; default b)\n" " -w warn about unsupported input\n" " -h print this message\n" "With no FILE, or when FILE is -, read standard input.\n")); @@ -7007,6 +7009,18 @@ static i32 nroff(i32 argc, u8 **argv, Plt *plt, Arena mem) Scaled v = scaled(val, 'u'); if (v.ok) setreg(c, key, v.value); } + } else if (arg.data[1] == 'd') { + Str d = cuthead(arg, 2); + if (!d.len && i+1