1 /* 2 * Copyright (c) 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1989 The Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)column.c 5.7 (Berkeley) 02/24/91"; 16 #endif /* not lint */ 17 18 #include <sys/types.h> 19 #include <sys/ioctl.h> 20 #include <stdio.h> 21 #include <string.h> 22 #include <ctype.h> 23 24 int termwidth = 80; /* default terminal width */ 25 26 int entries; /* number of records */ 27 int eval; /* exit value */ 28 int maxlength; /* longest record */ 29 char **list; /* array of pointers to records */ 30 char *separator = "\t "; /* field separator for table option */ 31 32 main(argc, argv) 33 int argc; 34 char **argv; 35 { 36 extern char *optarg; 37 extern int errno, optind; 38 struct winsize win; 39 FILE *fp; 40 int ch, tflag, xflag; 41 char *p, *getenv(); 42 43 if (ioctl(1, TIOCGWINSZ, &win) == -1 || !win.ws_col) { 44 if (p = getenv("COLUMNS")) 45 termwidth = atoi(p); 46 } else 47 termwidth = win.ws_col; 48 49 xflag = 0; 50 while ((ch = getopt(argc, argv, "c:s:tx")) != EOF) 51 switch(ch) { 52 case 'c': 53 termwidth = atoi(optarg); 54 break; 55 case 's': 56 separator = optarg; 57 break; 58 case 't': 59 tflag = 1; 60 break; 61 case 'x': 62 xflag = 1; 63 break; 64 case '?': 65 default: 66 usage(); 67 } 68 argc -= optind; 69 argv += optind; 70 71 if (!*argv) 72 input(stdin); 73 else for (; *argv; ++argv) 74 if (fp = fopen(*argv, "r")) { 75 input(fp); 76 (void)fclose(fp); 77 } else { 78 (void)fprintf(stderr, "column: %s: %s\n", *argv, 79 strerror(errno)); 80 eval = 1; 81 } 82 83 if (!entries) 84 exit(eval); 85 86 if (tflag) 87 maketbl(); 88 else if (maxlength >= termwidth) 89 print(); 90 else if (xflag) 91 c_columnate(); 92 else 93 r_columnate(); 94 exit(eval); 95 } 96 97 #define TAB 8 98 c_columnate() 99 { 100 register int chcnt, col, cnt, numcols; 101 int endcol; 102 char **lp; 103 104 maxlength = (maxlength + TAB) & ~(TAB - 1); 105 numcols = termwidth / maxlength; 106 endcol = maxlength; 107 for (chcnt = col = 0, lp = list;; ++lp) { 108 chcnt += printf("%s", *lp); 109 if (!--entries) 110 break; 111 if (++col == numcols) { 112 chcnt = col = 0; 113 endcol = maxlength; 114 putchar('\n'); 115 } else { 116 while ((cnt = (chcnt + TAB & ~(TAB - 1))) <= endcol) { 117 (void)putchar('\t'); 118 chcnt = cnt; 119 } 120 endcol += maxlength; 121 } 122 } 123 if (chcnt) 124 putchar('\n'); 125 } 126 127 r_columnate() 128 { 129 register int base, chcnt, cnt, col; 130 int endcol, numcols, numrows, row; 131 132 maxlength = (maxlength + TAB) & ~(TAB - 1); 133 numcols = termwidth / maxlength; 134 numrows = entries / numcols; 135 if (entries % numcols) 136 ++numrows; 137 138 for (row = 0; row < numrows; ++row) { 139 endcol = maxlength; 140 for (base = row, chcnt = col = 0; col < numcols; ++col) { 141 chcnt += printf("%s", list[base]); 142 if ((base += numrows) >= entries) 143 break; 144 while ((cnt = (chcnt + TAB & ~(TAB - 1))) <= endcol) { 145 (void)putchar('\t'); 146 chcnt = cnt; 147 } 148 endcol += maxlength; 149 } 150 putchar('\n'); 151 } 152 } 153 154 print() 155 { 156 register int cnt; 157 register char **lp; 158 159 for (cnt = entries, lp = list; cnt--; ++lp) 160 (void)printf("%s\n", *lp); 161 } 162 163 typedef struct _tbl { 164 char **list; 165 int cols, *len; 166 } TBL; 167 #define DEFCOLS 25 168 169 maketbl() 170 { 171 register TBL *t; 172 register int coloff, cnt; 173 register char *p, **lp; 174 int *lens, maxcols; 175 TBL *tbl; 176 char **cols, *emalloc(), *realloc(); 177 178 t = tbl = (TBL *)emalloc(entries * sizeof(TBL)); 179 cols = (char **)emalloc((maxcols = DEFCOLS) * sizeof(char *)); 180 lens = (int *)emalloc(maxcols * sizeof(int)); 181 for (cnt = 0, lp = list; cnt < entries; ++cnt, ++lp, ++t) { 182 for (coloff = 0, p = *lp; cols[coloff] = strtok(p, separator); 183 p = NULL) 184 if (++coloff == maxcols) { 185 if (!(cols = (char **)realloc((char *)cols, 186 (u_int)maxcols + DEFCOLS * sizeof(char *))) || 187 !(lens = (int *)realloc((char *)lens, 188 (u_int)maxcols + DEFCOLS * sizeof(int)))) 189 nomem(); 190 bzero((char *)lens + maxcols * sizeof(int), 191 DEFCOLS * sizeof(int)); 192 maxcols += DEFCOLS; 193 } 194 t->list = (char **)emalloc(coloff * sizeof(char *)); 195 t->len = (int *)emalloc(coloff * sizeof(int)); 196 for (t->cols = coloff; --coloff >= 0;) { 197 t->list[coloff] = cols[coloff]; 198 t->len[coloff] = strlen(cols[coloff]); 199 if (t->len[coloff] > lens[coloff]) 200 lens[coloff] = t->len[coloff]; 201 } 202 } 203 for (cnt = 0, t = tbl; cnt < entries; ++cnt, ++t) { 204 for (coloff = 0; coloff < t->cols - 1; ++coloff) 205 (void)printf("%s%*s", t->list[coloff], 206 lens[coloff] - t->len[coloff] + 2, " "); 207 (void)printf("%s\n", t->list[coloff]); 208 } 209 } 210 211 #define DEFNUM 1000 212 #define MAXLINELEN (2048 + 1) 213 214 input(fp) 215 register FILE *fp; 216 { 217 static int maxentry; 218 register int len; 219 register char *p; 220 char buf[MAXLINELEN], *emalloc(), *realloc(); 221 222 if (!list) 223 list = (char **)emalloc((maxentry = DEFNUM) * sizeof(char *)); 224 while (fgets(buf, MAXLINELEN, fp)) { 225 for (p = buf; *p && isspace(*p); ++p); 226 if (!*p) 227 continue; 228 if (!(p = index(p, '\n'))) { 229 (void)fprintf(stderr, "column: line too long.\n"); 230 eval = 1; 231 continue; 232 } 233 *p = '\0'; 234 len = p - buf; 235 if (maxlength < len) 236 maxlength = len; 237 if (entries == maxentry) { 238 maxentry += DEFNUM; 239 if (!(list = 240 (char **)realloc((char *)list, 241 (u_int)maxentry * sizeof(char *)))) 242 nomem(); 243 } 244 list[entries++] = strdup(buf); 245 } 246 } 247 248 char * 249 emalloc(size) 250 int size; 251 { 252 char *p, *malloc(); 253 254 /* NOSTRICT */ 255 if (!(p = malloc((u_int)size))) 256 nomem(); 257 bzero(p, size); 258 return(p); 259 } 260 261 nomem() 262 { 263 (void)fprintf(stderr, "column: out of memory.\n"); 264 exit(1); 265 } 266 267 usage() 268 { 269 (void)fprintf(stderr, 270 "usage: column [-tx] [-c columns] [file ...]\n"); 271 exit(1); 272 } 273