COLUMNS handling in our tree is inconsistent.

POSIX specifies that if COLUMNS is a valid value (read: 1 or greater),
it takes precedence; otherwise, width is handled in an unspecified 
manner.

Most programs follow COLUMNS, TIOCGWINSZ if that fails, and use 80 if
that fails. Some do TIOCGWINSZ, then COLUMNS, then 80. Some use a
different value than 80. And they're all inconsistently documented, if
they're documented at all.

This diff switches the tree to a single pattern: COLUMNS, TIOCGWINSZ, 80;
strtonum() for range checking; and documents it in the relevant manuals.
The odd one out is ps, which respected COLUMNS but otherwise used
TIOCGWINSZ - 1 and 80 - 1. Changing that behavior seemed potentially 
scary so I left it as is.

Comments? ok?

Index: bin/ls/ls.1
===================================================================
RCS file: /cvs/src/bin/ls/ls.1,v
retrieving revision 1.74
diff -u -p -r1.74 ls.1
--- bin/ls/ls.1 11 Mar 2016 02:35:57 -0000      1.74
+++ bin/ls/ls.1 13 Mar 2016 11:10:57 -0000
@@ -436,10 +436,12 @@ option is not specified, the block count
 .Fl s )
 will be displayed in units of that size block.
 .It Ev COLUMNS
-If this variable contains a string representing a
-decimal integer, it is used as the
-column position width for displaying
-multiple-text-column output.
+If set to a positive integer,
+.Nm Ns 's
+output is formatted to the given width in columns.
+Otherwise,
+.Nm
+defaults to the terminal width, or 80 columns if the output is not a terminal.
 .It Ev LC_CTYPE
 If set to a string ending in
 .Qq .UTF-8 ,
Index: bin/ls/ls.c
===================================================================
RCS file: /cvs/src/bin/ls/ls.c,v
retrieving revision 1.44
diff -u -p -r1.44 ls.c
--- bin/ls/ls.c 1 Dec 2015 18:36:13 -0000       1.44
+++ bin/ls/ls.c 13 Mar 2016 11:10:57 -0000
@@ -66,7 +66,7 @@ static int (*sortfcn)(const FTSENT *, co
 #define        BY_TIME 2
 
 long blocksize;                        /* block size units */
-int termwidth = 80;            /* default terminal width */
+int termwidth;                 /* default terminal width */
 int sortkey = BY_NAME;
 
 /* flags */
@@ -110,23 +110,19 @@ ls_main(int argc, char *argv[])
 
        /* Terminal defaults to -Cq, non-terminal defaults to -1. */
        if (isatty(STDOUT_FILENO)) {
-               if ((p = getenv("COLUMNS")) != NULL)
-                       width = strtonum(p, 1, INT_MAX, NULL);
-               if (width == 0 &&
-                   ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0 &&
-                   win.ws_col > 0)
-                       width = win.ws_col;
-               if (width)
-                       termwidth = width;
                f_column = f_nonprint = 1;
        } else {
                f_singlecol = 1;
-               /* retrieve environment variable, in case of explicit -C */
-               if ((p = getenv("COLUMNS")) != NULL)
-                       width = strtonum(p, 0, INT_MAX, NULL);
-               if (width)
-                       termwidth = width;
        }
+
+       termwidth = 0;
+       if ((p = getenv("COLUMNS")) != NULL)
+               termwidth = strtonum(p, 1, INT_MAX, NULL);
+       if (termwidth == 0 && ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0 &&
+           win.ws_col > 0)
+               termwidth = win.ws_col;
+       if (termwidth == 0)
+               termwidth = 80;
 
        if (pledge("stdio rpath getpw", NULL) == -1)
                err(1, "pledge");
Index: bin/ps/ps.1
===================================================================
RCS file: /cvs/src/bin/ps/ps.1,v
retrieving revision 1.102
diff -u -p -r1.102 ps.1
--- bin/ps/ps.1 22 Oct 2015 22:21:41 -0000      1.102
+++ bin/ps/ps.1 13 Mar 2016 11:10:58 -0000
@@ -543,10 +543,13 @@ The following environment variables affe
 .Nm :
 .Bl -tag -width "COLUMNS"
 .It Ev COLUMNS
-If set, specifies the user's preferred output width in column positions.
-By default,
+If set to a positive integer,
+.Nm Ns 's
+output is formatted to the given width in columns.
+Otherwise,
 .Nm
-attempts to automatically determine the terminal width.
+defaults to the terminal width \(mi 1, or 79 columns if the output is not a
+terminal.
 .It Ev TZ
 The time zone to use when displaying dates.
 See
Index: bin/ps/ps.c
===================================================================
RCS file: /cvs/src/bin/ps/ps.c,v
retrieving revision 1.69
diff -u -p -r1.69 ps.c
--- bin/ps/ps.c 10 Jan 2016 14:04:16 -0000      1.69
+++ bin/ps/ps.c 13 Mar 2016 11:10:58 -0000
@@ -102,22 +102,14 @@ main(int argc, char *argv[])
 
        setlocale(LC_CTYPE, "");
 
-       if ((cols = getenv("COLUMNS")) != NULL && *cols != '\0') {
-               const char *errstr;
-
-               termwidth = strtonum(cols, 1, INT_MAX, &errstr);
-               if (errstr != NULL)
-                       warnx("COLUMNS: %s: %s", cols, errstr);
-       }
-       if (termwidth == 0) {
-               if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1 &&
-                   ioctl(STDERR_FILENO, TIOCGWINSZ, &ws) == -1 &&
-                   ioctl(STDIN_FILENO,  TIOCGWINSZ, &ws) == -1) ||
-                   ws.ws_col == 0)
-                       termwidth = 79;
-               else
-                       termwidth = ws.ws_col - 1;
-       }
+       termwidth = 0;
+       if ((cols = getenv("COLUMNS")) != NULL)
+               termwidth = strtonum(cols, 1, INT_MAX, NULL);
+       if (termwidth == 0 && ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0 &&
+           ws.ws_col > 0)
+               termwidth = ws.ws_col - 1;
+       if (termwidth == 0)
+               termwidth = 79;
 
        if (argc > 1)
                argv[1] = kludge_oldps_options(argv[1]);
Index: usr.bin/column/column.1
===================================================================
RCS file: /cvs/src/usr.bin/column/column.1,v
retrieving revision 1.14
diff -u -p -r1.14 column.1
--- usr.bin/column/column.1     13 Mar 2015 19:58:41 -0000      1.14
+++ usr.bin/column/column.1     13 Mar 2016 11:10:58 -0000
@@ -75,10 +75,12 @@ Fill columns before filling rows.
 .Sh ENVIRONMENT
 .Bl -tag -width COLUMNS
 .It Ev COLUMNS
-The environment variable
-.Ev COLUMNS
-is used to determine the size of
-the screen if no other information is available.
+If set to a positive integer,
+.Nm Ns 's
+output is formatted to the given width in (terminal) columns.
+Otherwise,
+.Nm
+defaults to the terminal width, or 80 columns if the output is not a terminal.
 .El
 .Sh EXIT STATUS
 .Ex -std column
Index: usr.bin/column/column.c
===================================================================
RCS file: /cvs/src/usr.bin/column/column.c,v
retrieving revision 1.22
diff -u -p -r1.22 column.c
--- usr.bin/column/column.c     3 Nov 2015 04:55:44 -0000       1.22
+++ usr.bin/column/column.c     13 Mar 2016 11:10:59 -0000
@@ -50,7 +50,7 @@ void  print(void);
 void  r_columnate(void);
 void  usage(void);
 
-int termwidth = 80;            /* default terminal width */
+int termwidth;                 /* default terminal width */
 
 int entries;                   /* number of records */
 int eval;                      /* exit value */
@@ -67,14 +67,14 @@ main(int argc, char *argv[])
        char *p;
        const char *errstr;
 
-       if (ioctl(1, TIOCGWINSZ, &win) == -1 || !win.ws_col) {
-               if ((p = getenv("COLUMNS")) && *p != '\0') {
-                       termwidth = strtonum(p, 1, INT_MAX, &errstr);
-                       if (errstr != NULL)
-                               errx(1, "%s: %s", errstr, p);
-               }
-       } else
+       termwidth = 0;
+       if ((p = getenv("COLUMNS")) != NULL)
+               termwidth = strtonum(p, 1, INT_MAX, NULL);
+       if (termwidth == 0 && ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0 &&
+           win.ws_col > 0)
                termwidth = win.ws_col;
+       if (termwidth == 0)
+               termwidth = 80;
 
        if (pledge("stdio rpath", NULL) == -1)
                err(1, "pledge");
Index: usr.bin/rusers/rusers.1
===================================================================
RCS file: /cvs/src/usr.bin/rusers/rusers.1,v
retrieving revision 1.15
diff -u -p -r1.15 rusers.1
--- usr.bin/rusers/rusers.1     24 Apr 2014 15:03:04 -0000      1.15
+++ usr.bin/rusers/rusers.1     13 Mar 2016 11:10:59 -0000
@@ -79,6 +79,16 @@ and the remote host they logged in from 
 .It Fl u
 Sort by number of users logged in.
 .El
+.Sh ENVIRONMENT
+.Bl -tag -width COLUMNS
+.It Ev COLUMNS
+If set to a positive integer,
+.Nm Ns 's
+output is formatted to the given width in columns.
+Otherwise,
+.Nm
+defaults to the terminal width, or 80 columns if the output is not a terminal.
+.El
 .Sh DIAGNOSTICS
 .Bl -tag -width indent
 .It rusers: RPC: Program not registered
Index: usr.bin/rusers/rusers.c
===================================================================
RCS file: /cvs/src/usr.bin/rusers/rusers.c,v
retrieving revision 1.36
diff -u -p -r1.36 rusers.c
--- usr.bin/rusers/rusers.c     9 Dec 2015 19:39:10 -0000       1.36
+++ usr.bin/rusers/rusers.c     13 Mar 2016 11:10:59 -0000
@@ -141,21 +141,15 @@ main(int argc, char **argv)
        if (hflag + iflag + uflag > 1)
                usage();
 
-       if (isatty(STDOUT_FILENO)) {
-               if ((cp = getenv("COLUMNS")) != NULL && *cp != '\0') {
-                       termwidth = strtol(cp, &ep, 10);
-                       if (*ep != '\0' || termwidth >= INT_MAX ||
-                           termwidth < 0)
-                               termwidth = 0;
-               }
-               if (termwidth == 0 &&
-                   ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0 &&
-                   win.ws_col > 0)
-                       termwidth = win.ws_col;
-               else
-                       termwidth = 80;
-       } else
+       termwidth = 0;
+       if ((cp = getenv("COLUMNS")) != NULL)
+               termwidth = strtonum(cp, 1, LONG_MAX, NULL);
+       if (termwidth == 0 && ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0 &&
+           win.ws_col > 0)
+               termwidth = win.ws_col;
+       if (termwidth == 0)
                termwidth = 80;
+
        setvbuf(stdout, NULL, _IOLBF, 0);
 
        if (argc == optind) {
Index: usr.bin/sed/main.c
===================================================================
RCS file: /cvs/src/usr.bin/sed/main.c,v
retrieving revision 1.31
diff -u -p -r1.31 main.c
--- usr.bin/sed/main.c  1 Jan 2016 20:55:13 -0000       1.31
+++ usr.bin/sed/main.c  13 Mar 2016 11:10:59 -0000
@@ -150,14 +150,14 @@ main(int argc, char *argv[])
        argc -= optind;
        argv += optind;
 
-       if ((p = getenv("COLUMNS")))
+       termwidth = 0;
+       if ((p = getenv("COLUMNS")) != NULL)
                termwidth = strtonum(p, 0, INT_MAX, NULL);
-       if (termwidth == 0 &&
-           ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0 &&
+       if (termwidth == 0 && ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0 &&
            win.ws_col > 0)
                termwidth = win.ws_col;
        if (termwidth == 0)
-               termwidth = 60;
+               termwidth = 80;
 
        if (inplace != NULL) {
                if (pledge("stdio rpath wpath cpath fattr", NULL) == -1)
Index: usr.bin/sed/sed.1
===================================================================
RCS file: /cvs/src/usr.bin/sed/sed.1,v
retrieving revision 1.47
diff -u -p -r1.47 sed.1
--- usr.bin/sed/sed.1   4 Nov 2015 21:28:27 -0000       1.47
+++ usr.bin/sed/sed.1   13 Mar 2016 11:11:00 -0000
@@ -512,6 +512,17 @@ This is the same as specifying the
 .Fl n
 option on the command line.
 .El
+.Sh ENVIRONMENT
+.Bl -tag -width COLUMNS
+.It Ev COLUMNS
+If set to a positive integer,
+output from the
+.Ic l
+function is formatted to the given width in columns.
+Otherwise,
+.Nm
+defaults to the terminal with, or 80 columns if the output is not a terminal.
+.El
 .Sh EXIT STATUS
 .Ex -std sed
 .Sh EXAMPLES
Index: sbin/growfs/growfs.8
===================================================================
RCS file: /cvs/src/sbin/growfs/growfs.8,v
retrieving revision 1.12
diff -u -p -r1.12 growfs.8
--- sbin/growfs/growfs.8        19 Oct 2013 16:53:13 -0000      1.12
+++ sbin/growfs/growfs.8        13 Mar 2016 11:11:00 -0000
@@ -110,6 +110,15 @@ The
 flag suppresses this,
 so use this option with great care!
 .El
+.Sh ENVIRONMENT
+.Bl -tag -width COLUMNS
+.It Ev COLUMNS
+If set to a positive integer,
+.Nm Ns 's
+output is formatted to the given width in columns.
+Otherwise,
+.Nm
+defaults to the terminal width, or 80 columns if the output is not a terminal.
 .Sh SEE ALSO
 .Xr disklabel 8 ,
 .Xr dumpfs 8 ,
Index: sbin/growfs/growfs.c
===================================================================
RCS file: /cvs/src/sbin/growfs/growfs.c,v
retrieving revision 1.49
diff -u -p -r1.49 growfs.c
--- sbin/growfs/growfs.c        29 Jan 2016 11:50:40 -0000      1.49
+++ sbin/growfs/growfs.c        13 Mar 2016 11:11:03 -0000
@@ -1666,15 +1666,13 @@ charsperline(void)
        struct winsize  ws;
 
        columns = 0;
-       if (ioctl(0, TIOCGWINSZ, &ws) != -1) {
-               columns = ws.ws_col;
-       }
-       if (columns == 0 && (cp = getenv("COLUMNS"))) {
+       if ((cp = getenv("COLUMNS")) != NULL)
                columns = strtonum(cp, 1, INT_MAX, NULL);
-       }
-       if (columns == 0) {
-               columns = 80;   /* last resort */
-       }
+       if (columns == 0 && ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0 &&
+           ws.ws_col > 0)
+               columns = ws.ws_col;
+       if (columns == 0)
+               columns = 80;
 
        return columns;
 }
Index: sbin/newfs/mkfs.c
===================================================================
RCS file: /cvs/src/sbin/newfs/mkfs.c,v
retrieving revision 1.95
diff -u -p -r1.95 mkfs.c
--- sbin/newfs/mkfs.c   28 Jan 2016 17:26:10 -0000      1.95
+++ sbin/newfs/mkfs.c   13 Mar 2016 11:11:04 -0000
@@ -1144,12 +1144,14 @@ charsperline(void)
        struct winsize ws;
 
        columns = 0;
-       if (ioctl(0, TIOCGWINSZ, &ws) != -1)
-               columns = ws.ws_col;
-       if (columns == 0 && (cp = getenv("COLUMNS")))
+       if ((cp = getenv("COLUMNS")) != NULL)
                columns = strtonum(cp, 1, INT_MAX, NULL);
+       if (columns == 0 && ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0 &&
+           ws.ws_col > 0)
+               columns = ws.ws_col;
        if (columns == 0)
-               columns = 80;   /* last resort */
+               columns = 80;
+
        return columns;
 }
 
Index: sbin/newfs/newfs.8
===================================================================
RCS file: /cvs/src/sbin/newfs/newfs.8,v
retrieving revision 1.72
diff -u -p -r1.72 newfs.8
--- sbin/newfs/newfs.8  18 Feb 2016 21:57:26 -0000      1.72
+++ sbin/newfs/newfs.8  13 Mar 2016 11:11:05 -0000
@@ -301,6 +301,16 @@ If the
 .Fl P Ar file
 option is not used, the owner and mode of the created mfs file
 system will be the same as the owner and mode of the mount point.
+.Sh ENVIRONMENT
+.Bl -tag -width COLUMNS
+.It Ev COLUMNS
+If set to a positive integer,
+.Nm Ns 's
+output is formatted to the given width in columns.
+Otherwise,
+.Nm
+defaults to the terminal width, or 80 columns if the output is not a terminal.
+.El
 .Sh SEE ALSO
 .Xr disktab 5 ,
 .Xr fs 5 ,
Index: usr.sbin/lpr/common_source/displayq.c
===================================================================
RCS file: /cvs/src/usr.sbin/lpr/common_source/displayq.c,v
retrieving revision 1.38
diff -u -p -r1.38 displayq.c
--- usr.sbin/lpr/common_source/displayq.c       12 Jan 2016 23:35:13 -0000      
1.38
+++ usr.sbin/lpr/common_source/displayq.c       13 Mar 2016 11:11:05 -0000
@@ -101,14 +101,15 @@ displayq(int format)
        struct stat statb;
        FILE *fp;
 
-       termwidth = 80;
-       if (isatty(STDOUT_FILENO)) {
-               if ((p = getenv("COLUMNS")) != NULL)
-                       termwidth = atoi(p);
-               else if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0 &&
-                   win.ws_col > 0)
-                       termwidth = win.ws_col;
-       }
+       termwidth = 0;
+       if ((p = getenv("COLUMNS")) != NULL)
+               termwidth = strtonum(p, 1, INT_MAX, NULL);
+       if (termwidth == 0 && ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0 &&
+           win.ws_col > 0)
+               termwidth = win.ws_col;
+       if (termwidth == 0)
+               termwidth = 80;
+
        if (termwidth < 60)
                termwidth = 60;
 
Index: usr.sbin/lpr/lpq/lpq.1
===================================================================
RCS file: /cvs/src/usr.sbin/lpr/lpq/lpq.1,v
retrieving revision 1.10
diff -u -p -r1.10 lpq.1
--- usr.sbin/lpr/lpq/lpq.1      31 May 2007 19:20:25 -0000      1.10
+++ usr.sbin/lpr/lpq/lpq.1      13 Mar 2016 11:11:05 -0000
@@ -96,11 +96,18 @@ warns that there is no daemon present (i
 .Xr lpc 8
 command can be used to restart the printer daemon.
 .Sh ENVIRONMENT
-If the following environment variable exists, it is used by
+If the following environment variables exist, they are used by
 .Nm lpq :
 .Bl -tag -width PRINTER
 .It Ev PRINTER
 Specifies an alternate default printer.
+.It Ev COLUMNS
+If set to a positive integer,
+.Nm Ns 's
+output is formatted to the given width in columns.
+Otherwise,
+.Nm
+defaults to the terminal width, or 80 columns if the output is not a terminal.
 .El
 .Sh FILES
 .Bl -tag -width "/var/spool/output/*/lock" -compact

Reply via email to