Dear all,

Following some back and forth on how disklabel output should be
formatted, I proposed to Kenneth to extend the column(1) utility. All that
was missing is the ability to right justify. I've longed for this
feature for a while: I often use 'column -t' to prettify data coming
from an awk pipeline.

Example:

job@vurt ~$ netstat -r | column -t -r | tail -5 
    ff01::%iwm0/32  fe80::4708:d2be:9a     Um     0        3      -     4     
iwm0  
     ff01::%lo0/32           localhost     Um     0        1  32768     4      
lo0  
         ff02::/16           localhost   UGRS     0        1  32768     8      
lo0  
    ff02::%iwm0/32  fe80::4708:d2be:9a     Um     0        3      -     4     
iwm0  
     ff02::%lo0/32           localhost     Um     0        1  32768     4      
lo0  


Patch courtesy of Kenneth R Westerback. OK?

Index: column.1
===================================================================
RCS file: /cvs/src/usr.bin/column/column.1,v
retrieving revision 1.18
diff -u -p -r1.18 column.1
--- column.1    24 Oct 2016 13:53:05 -0000      1.18
+++ column.1    4 Jul 2018 10:27:54 -0000
@@ -40,6 +40,7 @@
 .Nm column
 .Op Fl tx
 .Op Fl c Ar columns
+.Op Fl r Op Ar list
 .Op Fl s Ar sep
 .Op Ar
 .Sh DESCRIPTION
@@ -66,6 +67,16 @@ The options are as follows:
 Output is formatted for a display
 .Ar columns
 wide.
+.It Fl r Op Ar list
+Table mode will right justify the column contents for the
+specified columns.
+.Ar list
+is a list of comma separated column numbers or column ranges.
+Column numbers start at 1.
+The list must not contain whitespace.
+If no
+.Ar list
+is provided then all columns will be right justified.
 .It Fl s Ar sep
 Specify a set of characters to delimit columns for the
 .Fl t
Index: column.c
===================================================================
RCS file: /cvs/src/usr.bin/column/column.c,v
retrieving revision 1.26
diff -u -p -r1.26 column.c
--- column.c    22 Jun 2018 12:27:00 -0000      1.26
+++ column.c    4 Jul 2018 10:28:00 -0000
@@ -47,7 +47,8 @@
 void  c_columnate(void);
 void *ereallocarray(void *, size_t, size_t);
 void  input(FILE *);
-void  maketbl(void);
+int   rightjustify(const char *, const int);
+void  maketbl(const int, const char *);
 void  print(void);
 void  r_columnate(void);
 __dead void usage(void);
@@ -69,8 +70,8 @@ main(int argc, char *argv[])
 {
        struct winsize win;
        FILE *fp;
-       int ch, tflag, xflag;
-       char *p;
+       int ch, rflag, tflag, xflag;
+       char *p, *rcols;
        const char *errstr;
 
        setlocale(LC_CTYPE, "");
@@ -87,14 +88,19 @@ main(int argc, char *argv[])
        if (pledge("stdio rpath", NULL) == -1)
                err(1, "pledge");
 
-       tflag = xflag = 0;
-       while ((ch = getopt(argc, argv, "c:s:tx")) != -1) {
+       rcols = NULL;
+       rflag = 0; tflag = xflag = 0;
+       while ((ch = getopt(argc, argv, "c:r::s:tx")) != -1) {
                switch(ch) {
                case 'c':
                        termwidth = strtonum(optarg, 1, INT_MAX, &errstr);
                        if (errstr != NULL)
                                errx(1, "%s: %s", errstr, optarg);
                        break;
+               case 'r':
+                       rflag = 1;
+                       rcols = optarg;
+                       break;
                case 's':
                        if ((separator = reallocarray(NULL, strlen(optarg) + 1,
                            sizeof(*separator))) == NULL)
@@ -139,7 +145,7 @@ main(int argc, char *argv[])
                return eval;
 
        if (tflag)
-               maketbl();
+               maketbl(rflag, rcols);
        else if (*maxwidths >= termwidth)
                print();
        else if (xflag)
@@ -207,18 +213,69 @@ print(void)
                puts(table[row]->content);
 }
 
+int
+rightjustify(const char *rcols, const int col)
+{
+       const char *errstr;
+       char c, *num, *temp;
+       long long ch, rangestart;
+       unsigned int i;
+
+       if (rcols == NULL)
+               return 1;
+
+       temp = strdup(rcols);
+       num = temp;
+       rangestart = -1;
+
+       c = 0;
+       for (i = 0; i <= strlen(rcols); i++) {
+               ch = temp[i];
+               if (ch == ',' || ch == '-')
+                       temp[i] = '\0';
+               if (temp[i] != '\0')
+                       continue;
+
+               c = strtonum(num, 1, INT_MAX, &errstr);
+               if (errstr != NULL)
+                       break;
+               c--;    /* Users are 1-based. Reality is 0-based. */
+
+               if (c == col)
+                       goto found;
+               if (ch == '-') {
+                       rangestart = c;
+               } else if ((ch == ',' || ch == '\0') && rangestart != -1) {
+                       if (rangestart <= col && c >= col)
+                               goto found;
+                       rangestart = -1;
+               }
+               num = temp + i + 1;
+       }
+
+       free(temp);
+       return 0;
+found:
+       free(temp);
+       return 1;
+}
 
 void
-maketbl(void)
+maketbl(const int rflag, const char *rcols)
 {
        struct field **row;
        int col;
 
        for (row = table; entries--; ++row) {
-               for (col = 0; (*row)[col + 1].content != NULL; ++col)
-                       printf("%s%*s  ", (*row)[col].content,
-                           maxwidths[col] - (*row)[col].width, "");
-               puts((*row)[col].content);
+               for (col = 0; (*row)[col].content != NULL; ++col) {
+                       if (rflag && rightjustify(rcols, col))
+                               printf("%*s  ", maxwidths[col],
+                                   (*row)[col].content);
+                       else
+                               printf("%-*s  ", maxwidths[col],
+                                   (*row)[col].content);
+               }
+               putchar('\n');
        }
 }

Reply via email to