[BACK]Return to column.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / column

Diff for /src/usr.bin/column/column.c between version 1.23 and 1.24

version 1.23, 2016/03/17 05:27:10 version 1.24, 2016/08/31 20:43:57
Line 48 
Line 48 
 void  maketbl(void);  void  maketbl(void);
 void  print(void);  void  print(void);
 void  r_columnate(void);  void  r_columnate(void);
 void  usage(void);  __dead void usage(void);
   
 int termwidth;                  /* default terminal width */  struct field {
           char *content;
           int width;
   };
   
   int termwidth;                  /* default terminal width */
 int entries;                    /* number of records */  int entries;                    /* number of records */
 int eval;                       /* exit value */  int eval;                       /* exit value */
 int maxlength;                  /* longest record */  int *maxwidths;                 /* longest record per column */
 char **list;                    /* array of pointers to records */  struct field **table;           /* one array of pointers per line */
 char *separator = "\t ";        /* field separator for table option */  char *separator = "\t ";        /* field separator for table option */
   
 int  int
Line 80 
Line 84 
                 err(1, "pledge");                  err(1, "pledge");
   
         tflag = xflag = 0;          tflag = xflag = 0;
         while ((ch = getopt(argc, argv, "c:s:tx")) != -1)          while ((ch = getopt(argc, argv, "c:s:tx")) != -1) {
                 switch(ch) {                  switch(ch) {
                 case 'c':                  case 'c':
                         termwidth = strtonum(optarg, 1, INT_MAX, &errstr);                          termwidth = strtonum(optarg, 1, INT_MAX, &errstr);
Line 96 
Line 100 
                 case 'x':                  case 'x':
                         xflag = 1;                          xflag = 1;
                         break;                          break;
                 case '?':  
                 default:                  default:
                         usage();                          usage();
                 }                  }
         argc -= optind;          }
   
           if (!tflag)
                   separator = "";
         argv += optind;          argv += optind;
   
         if (!*argv) {          if (*argv == NULL) {
                 input(stdin);                  input(stdin);
         } else {          } else {
                 for (; *argv; ++argv) {                  for (; *argv; ++argv) {
Line 121 
Line 127 
                 err(1, "pledge");                  err(1, "pledge");
   
         if (!entries)          if (!entries)
                 exit(eval);                  return eval;
   
         if (tflag)          if (tflag)
                 maketbl();                  maketbl();
         else if (maxlength >= termwidth)          else if (*maxwidths >= termwidth)
                 print();                  print();
         else if (xflag)          else if (xflag)
                 c_columnate();                  c_columnate();
         else          else
                 r_columnate();                  r_columnate();
         exit(eval);          return eval;
 }  }
   
 #define TAB     8  #define INCR_NEXTTAB(x) (x = (x + 8) & ~7)
 void  void
 c_columnate(void)  c_columnate(void)
 {  {
         int chcnt, col, cnt, endcol, numcols;          int col, numcols;
         char **lp;          struct field **row;
   
         maxlength = (maxlength + TAB) & ~(TAB - 1);          INCR_NEXTTAB(*maxwidths);
         numcols = termwidth / maxlength;          if ((numcols = termwidth / *maxwidths) == 0)
         endcol = maxlength;                  numcols = 1;
         for (chcnt = col = 0, lp = list;; ++lp) {          for (col = 0, row = table;; ++row) {
                 chcnt += printf("%s", *lp);                  fputs((*row)->content, stdout);
                 if (!--entries)                  if (!--entries)
                         break;                          break;
                 if (++col == numcols) {                  if (++col == numcols) {
                         chcnt = col = 0;                          col = 0;
                         endcol = maxlength;  
                         putchar('\n');                          putchar('\n');
                 } else {                  } else {
                         while ((cnt = ((chcnt + TAB) & ~(TAB - 1))) <= endcol) {                          while (INCR_NEXTTAB((*row)->width) <= *maxwidths)
                                 (void)putchar('\t');                                  putchar('\t');
                                 chcnt = cnt;  
                         }  
                         endcol += maxlength;  
                 }                  }
         }          }
         if (chcnt)          putchar('\n');
                 putchar('\n');  
 }  }
   
 void  void
 r_columnate(void)  r_columnate(void)
 {  {
         int base, chcnt, cnt, col, endcol, numcols, numrows, row;          int base, col, numcols, numrows, row;
   
         maxlength = (maxlength + TAB) & ~(TAB - 1);          INCR_NEXTTAB(*maxwidths);
         numcols = termwidth / maxlength;          if ((numcols = termwidth / *maxwidths) == 0)
         if (numcols == 0)  
                 numcols = 1;                  numcols = 1;
         numrows = entries / numcols;          numrows = entries / numcols;
         if (entries % numcols)          if (entries % numcols)
                 ++numrows;                  ++numrows;
   
         for (row = 0; row < numrows; ++row) {          for (base = row = 0; row < numrows; base = ++row) {
                 endcol = maxlength;                  for (col = 0; col < numcols; ++col, base += numrows) {
                 for (base = row, chcnt = col = 0; col < numcols; ++col) {                          fputs(table[base]->content, stdout);
                         chcnt += printf("%s", list[base]);                          if (base + numrows >= entries)
                         if ((base += numrows) >= entries)  
                                 break;                                  break;
                         while ((cnt = ((chcnt + TAB) & ~(TAB - 1))) <= endcol) {                          while (INCR_NEXTTAB(table[base]->width) <= *maxwidths)
                                 (void)putchar('\t');                                  putchar('\t');
                                 chcnt = cnt;  
                         }  
                         endcol += maxlength;  
                 }                  }
                 putchar('\n');                  putchar('\n');
         }          }
Line 196 
Line 192 
 void  void
 print(void)  print(void)
 {  {
         int cnt;          int row;
         char **lp;  
   
         for (cnt = entries, lp = list; cnt--; ++lp)          for (row = 0; row < entries; row++)
                 (void)printf("%s\n", *lp);                  puts(table[row]->content);
 }  }
   
 typedef struct _tbl {  
         char **list;  
         int cols, *len;  
 } TBL;  
 #define DEFCOLS 25  
   
 void  void
 maketbl(void)  maketbl(void)
 {  {
         TBL *t;          struct field **row;
         int coloff, cnt;          int col;
         char *p, **lp;  
         int *lens, maxcols = DEFCOLS;  
         TBL *tbl;  
         char **cols;  
   
         t = tbl = ecalloc(entries, sizeof(TBL));          for (row = table; entries--; ++row) {
         cols = ereallocarray(NULL, maxcols, sizeof(char *));                  for (col = 0; (*row)[col + 1].content != NULL; ++col)
         lens = ecalloc(maxcols, sizeof(int));                          printf("%s%*s  ", (*row)[col].content,
         for (cnt = 0, lp = list; cnt < entries; ++cnt, ++lp, ++t) {                              maxwidths[col] - (*row)[col].width, "");
                 for (coloff = 0, p = *lp; (cols[coloff] = strtok(p, separator));                  puts((*row)[col].content);
                     p = NULL)  
                         if (++coloff == maxcols) {  
                                 maxcols += DEFCOLS;  
                                 cols = ereallocarray(cols, maxcols,  
                                     sizeof(char *));  
                                 lens = ereallocarray(lens, maxcols,  
                                     sizeof(int));  
                                 memset(lens + coloff, 0, DEFCOLS * sizeof(int));  
                         }  
                 if (coloff == 0)  
                         continue;  
                 t->list = ecalloc(coloff, sizeof(char *));  
                 t->len = ecalloc(coloff, sizeof(int));  
                 for (t->cols = coloff; --coloff >= 0;) {  
                         t->list[coloff] = cols[coloff];  
                         t->len[coloff] = strlen(cols[coloff]);  
                         if (t->len[coloff] > lens[coloff])  
                                 lens[coloff] = t->len[coloff];  
                 }  
         }          }
         for (cnt = 0, t = tbl; cnt < entries; ++cnt, ++t) {  
                 if (t->cols > 0) {  
                         for (coloff = 0; coloff < t->cols - 1; ++coloff)  
                                 (void)printf("%s%*s", t->list[coloff],  
                                     lens[coloff] - t->len[coloff] + 2, " ");  
                         (void)printf("%s\n", t->list[coloff]);  
                 }  
         }  
         free(tbl);  
         free(lens);  
         free(cols);  
 }  }
   
 #define DEFNUM          1000  #define DEFNUM          1000
 #define MAXLINELEN      (LINE_MAX + 1)  #define DEFCOLS         25
   
 void  void
 input(FILE *fp)  input(FILE *fp)
 {  {
         static size_t maxentry = DEFNUM;          static int maxentry = 0;
         int len;          static int maxcols = 0;
         char *p, buf[MAXLINELEN];          static struct field *cols = NULL;
           int col, width;
           size_t blen;
           ssize_t llen;
           char *p, *s, *buf = NULL;
   
         if (!list)          while ((llen = getline(&buf, &blen, fp)) > -1) {
                 list = ecalloc(maxentry, sizeof(char *));                  if (buf[llen - 1] == '\n')
         while (fgets(buf, MAXLINELEN, fp)) {                          buf[llen - 1] = '\0';
                 for (p = buf; isspace((unsigned char)*p); ++p);  
                 if (!*p)                  p = buf;
                         continue;                  for (col = 0;; col++) {
                 if (!(p = strchr(p, '\n'))) {  
                         warnx("line too long");                          /* Skip lines containing nothing but whitespace. */
                         eval = 1;  
                         continue;                          for (s = p; s != '\0'; s++)
                                   if (!isspace((unsigned char)*s))
                                           break;
                           if (*s == '\0')
                                   break;
   
                           /* Skip leading, multiple, and trailing separators. */
   
                           while (*p != '\0' && strchr(separator, *p) != NULL)
                                   p++;
                           if (*p == '\0')
                                   break;
   
                           /*
                            * Found a non-empty field.
                            * Remember the start and measure the width.
                            */
   
                           s = p;
                           width = 0;
                           while (*p != '\0' && strchr(separator, *p) == NULL) {
                                   if (*p++ == '\t')
                                           INCR_NEXTTAB(width);
                                   else
                                           width++;
                           }
   
                           if (col + 1 >= maxcols) {
                                   if (maxcols > INT_MAX - DEFCOLS)
                                           err(1, "too many columns");
                                   maxcols += DEFCOLS;
                                   cols = ereallocarray(cols, maxcols,
                                       sizeof(*cols));
                                   maxwidths = ereallocarray(maxwidths, maxcols,
                                       sizeof(*maxwidths));
                                   memset(maxwidths + col, 0,
                                       DEFCOLS * sizeof(*maxwidths));
                           }
   
                           /*
                            * Remember the width of the field,
                            * NUL-terminate and remeber the content,
                            * and advance beyond the separator, if any.
                            */
   
                           cols[col].width = width;
                           if (maxwidths[col] < width)
                                   maxwidths[col] = width;
                           if (*p != '\0')
                                   *p++ = '\0';
                           if ((cols[col].content = strdup(s)) == NULL)
                                   err(1, NULL);
                 }                  }
                 *p = '\0';                  if (col == 0)
                 len = p - buf;                          continue;
                 if (maxlength < len)  
                         maxlength = len;                  /* Found a non-empty line; remember it. */
   
                 if (entries == maxentry) {                  if (entries == maxentry) {
                           if (maxentry > INT_MAX - DEFNUM)
                                   errx(1, "too many input lines");
                         maxentry += DEFNUM;                          maxentry += DEFNUM;
                         list = ereallocarray(list, maxentry, sizeof(char *));                          table = ereallocarray(table, maxentry, sizeof(*table));
                         memset(list + entries, 0, DEFNUM * sizeof(char *));  
                 }                  }
                 if (!(list[entries++] = strdup(buf)))                  table[entries] = ereallocarray(NULL, col + 1,
                         err(1, NULL);                      sizeof(*(table[entries])));
                   table[entries][col].content = NULL;
                   while (col--)
                           table[entries][col] = cols[col];
                   entries++;
         }          }
 }  }
   
 void *  void *
 ereallocarray(void *oldp, size_t sz1, size_t sz2)  ereallocarray(void *ptr, size_t nmemb, size_t size)
 {  {
         void *p;          if ((ptr = reallocarray(ptr, nmemb, size)) == NULL)
   
         if (!(p = reallocarray(oldp, sz1, sz2)))  
                 err(1, NULL);                  err(1, NULL);
         return (p);          return ptr;
 }  }
   
 void *  void *
 ecalloc(size_t sz1, size_t sz2)  ecalloc(size_t nmemb, size_t size)
 {  {
         void *p;          void *ptr;
   
         if (!(p = calloc(sz1, sz2)))          if ((ptr = calloc(nmemb, size)) == NULL)
                 err(1, NULL);                  err(1, NULL);
         return (p);          return ptr;
 }  }
   
 void  __dead void
 usage(void)  usage(void)
 {  {
   
         (void)fprintf(stderr,          (void)fprintf(stderr,
             "usage: column [-tx] [-c columns] [-s sep] [file ...]\n");              "usage: column [-tx] [-c columns] [-s sep] [file ...]\n");
         exit(1);          exit(1);

Legend:
Removed from v.1.23  
changed lines
  Added in v.1.24