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