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