man: make width selection more thorough; explain how to override it
Fedora's "man CMD >file" still uses terminal width, not 80 (but disables formatting),
this change mimics that.
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c
index 3f9a84a..45650ed 100644
--- a/libbb/xfuncs.c
+++ b/libbb/xfuncs.c
@@ -237,16 +237,27 @@
static int wh_helper(int value, int def_val, const char *env_name, int *err)
{
- if (value == 0) {
- char *s = getenv(env_name);
- if (s) {
- value = atoi(s);
- /* If LINES/COLUMNS are set, pretend that there is
- * no error getting w/h, this prevents some ugly
- * cursor tricks by our callers */
- *err = 0;
- }
+ /* Envvars override even if "value" from ioctl is valid (>0).
+ * Rationale: it's impossible to guess what user wants.
+ * For example: "man CMD | ...": should "man" format output
+ * to stdout's width? stdin's width? /dev/tty's width? 80 chars?
+ * We _cant_ know it. If "..." saves text for e.g. email,
+ * then it's probably 80 chars.
+ * If "..." is, say, "grep -v DISCARD | $PAGER", then user
+ * would prefer his tty's width to be used!
+ *
+ * Since we don't know, at least allow user to do this:
+ * "COLUMNS=80 man CMD | ..."
+ */
+ char *s = getenv(env_name);
+ if (s) {
+ value = atoi(s);
+ /* If LINES/COLUMNS are set, pretend that there is
+ * no error getting w/h, this prevents some ugly
+ * cursor tricks by our callers */
+ *err = 0;
}
+
if (value <= 1 || value >= 30000)
value = def_val;
return value;
@@ -258,6 +269,20 @@
{
struct winsize win;
int err;
+ int close_me = -1;
+
+ if (fd == -1) {
+ if (isatty(STDOUT_FILENO))
+ fd = STDOUT_FILENO;
+ else
+ if (isatty(STDERR_FILENO))
+ fd = STDERR_FILENO;
+ else
+ if (isatty(STDIN_FILENO))
+ fd = STDIN_FILENO;
+ else
+ close_me = fd = open("/dev/tty", O_RDONLY);
+ }
win.ws_row = 0;
win.ws_col = 0;
@@ -268,6 +293,10 @@
*height = wh_helper(win.ws_row, 24, "LINES", &err);
if (width)
*width = wh_helper(win.ws_col, 80, "COLUMNS", &err);
+
+ if (close_me >= 0)
+ close(close_me);
+
return err;
}
int FAST_FUNC get_terminal_width(int fd)
diff --git a/miscutils/man.c b/miscutils/man.c
index 01382c4..adb7770 100644
--- a/miscutils/man.c
+++ b/miscutils/man.c
@@ -9,6 +9,8 @@
//usage: "Format and display manual page\n"
//usage: "\n -a Display all pages"
//usage: "\n -w Show page locations"
+//usage: "\n"
+//usage: "\n$COLUMNS overrides output width"
#include "libbb.h"
#include "common_bufsiz.h"
@@ -53,7 +55,7 @@
setup_common_bufsiz(); \
G.col = "col"; \
G.tbl = "tbl"; \
- /* replaced -Tlatin1 with -Tascii for non-UTF8 displays */; \
+ /* replaced -Tlatin1 with -Tascii for non-UTF8 displays */ \
G.nroff = "nroff -mandoc -Tascii"; \
G.pager = ENABLE_LESS ? "less" : "more"; \
} while (0)
@@ -132,15 +134,12 @@
close(STDIN_FILENO);
open_zipped(man_filename, /*fail_if_not_compressed:*/ 0); /* guaranteed to use fd 0 (STDIN_FILENO) */
if (man) {
- /* "man man" formats to screen width.
- * "man man >file" formats to default 80 columns.
- * "man man | cat" formats to default 80 columns.
- */
- int w = get_terminal_width(STDOUT_FILENO);
+ int w = get_terminal_width(-1);
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 */
+ * Otherwise it may show just empty screen.
+ */
cmd = xasprintf("%s | %s -rLL=%un -rLT=%un 2>&1 | %s",
G.tbl, G.nroff, w, w,
G.pager);