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.1 (Berkeley) 06/06/93"; 16 #endif /* not lint */ 17 18 #include <sys/types.h> 19 #include <sys/ioctl.h> 20 #include <errno.h> 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <ctype.h> 25 26 void c_columnate __P((void)); 27 void *emalloc __P((int)); 28 void input __P((FILE *)); 29 void maketbl __P((void)); 30 void nomem __P((void)); 31 void print __P((void)); 32 void r_columnate __P((void)); 33 void usage __P((void)); 34 35 int termwidth = 80; /* default terminal width */ 36 37 int entries; /* number of records */ 38 int eval; /* exit value */ 39 int maxlength; /* longest record */ 40 char **list; /* array of pointers to records */ 41 char *separator = "\t "; /* field separator for table option */ 42 43 int 44 main(argc, argv) 45 int argc; 46 char **argv; 47 { 48 struct winsize win; 49 FILE *fp; 50 int ch, tflag, xflag; 51 char *p; 52 53 if (ioctl(1, TIOCGWINSZ, &win) == -1 || !win.ws_col) { 54 if (p = getenv("COLUMNS")) 55 termwidth = atoi(p); 56 } else 57 termwidth = win.ws_col; 58 59 tflag = xflag = 0; 60 while ((ch = getopt(argc, argv, "c:s:tx")) != EOF) 61 switch(ch) { 62 case 'c': 63 termwidth = atoi(optarg); 64 break; 65 case 's': 66 separator = optarg; 67 break; 68 case 't': 69 tflag = 1; 70 break; 71 case 'x': 72 xflag = 1; 73 break; 74 case '?': 75 default: 76 usage(); 77 } 78 argc -= optind; 79 argv += optind; 80 81 if (!*argv) 82 input(stdin); 83 else for (; *argv; ++argv) 84 if (fp = fopen(*argv, "r")) { 85 input(fp); 86 (void)fclose(fp); 87 } else { 88 (void)fprintf(stderr, "column: %s: %s\n", *argv, 89 strerror(errno)); 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 register int chcnt, col, cnt, numcols; 112 int endcol; 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 register int base, chcnt, cnt, col; 142 int endcol, numcols, numrows, row; 143 144 maxlength = (maxlength + TAB) & ~(TAB - 1); 145 numcols = termwidth / maxlength; 146 numrows = entries / numcols; 147 if (entries % numcols) 148 ++numrows; 149 150 for (row = 0; row < numrows; ++row) { 151 endcol = maxlength; 152 for (base = row, chcnt = col = 0; col < numcols; ++col) { 153 chcnt += printf("%s", list[base]); 154 if ((base += numrows) >= entries) 155 break; 156 while ((cnt = (chcnt + TAB & ~(TAB - 1))) <= endcol) { 157 (void)putchar('\t'); 158 chcnt = cnt; 159 } 160 endcol += maxlength; 161 } 162 putchar('\n'); 163 } 164 } 165 166 void 167 print() 168 { 169 register int cnt; 170 register char **lp; 171 172 for (cnt = entries, lp = list; cnt--; ++lp) 173 (void)printf("%s\n", *lp); 174 } 175 176 typedef struct _tbl { 177 char **list; 178 int cols, *len; 179 } TBL; 180 #define DEFCOLS 25 181 182 void 183 maketbl() 184 { 185 register TBL *t; 186 register int coloff, cnt; 187 register char *p, **lp; 188 int *lens, maxcols; 189 TBL *tbl; 190 char **cols; 191 192 t = tbl = emalloc(entries * sizeof(TBL)); 193 cols = emalloc((maxcols = DEFCOLS) * sizeof(char *)); 194 lens = emalloc(maxcols * sizeof(int)); 195 for (cnt = 0, lp = list; cnt < entries; ++cnt, ++lp, ++t) { 196 for (coloff = 0, p = *lp; cols[coloff] = strtok(p, separator); 197 p = NULL) 198 if (++coloff == maxcols) { 199 if (!(cols = realloc(cols, (u_int)maxcols + 200 DEFCOLS * sizeof(char *))) || 201 !(lens = realloc(lens, 202 (u_int)maxcols + DEFCOLS * sizeof(int)))) 203 nomem(); 204 bzero((char *)lens + maxcols * sizeof(int), 205 DEFCOLS * sizeof(int)); 206 maxcols += DEFCOLS; 207 } 208 t->list = emalloc(coloff * sizeof(char *)); 209 t->len = emalloc(coloff * sizeof(int)); 210 for (t->cols = coloff; --coloff >= 0;) { 211 t->list[coloff] = cols[coloff]; 212 t->len[coloff] = strlen(cols[coloff]); 213 if (t->len[coloff] > lens[coloff]) 214 lens[coloff] = t->len[coloff]; 215 } 216 } 217 for (cnt = 0, t = tbl; cnt < entries; ++cnt, ++t) { 218 for (coloff = 0; coloff < t->cols - 1; ++coloff) 219 (void)printf("%s%*s", t->list[coloff], 220 lens[coloff] - t->len[coloff] + 2, " "); 221 (void)printf("%s\n", t->list[coloff]); 222 } 223 } 224 225 #define DEFNUM 1000 226 #define MAXLINELEN (2048 + 1) 227 228 void 229 input(fp) 230 register FILE *fp; 231 { 232 static int maxentry; 233 register int len; 234 register char *p; 235 char buf[MAXLINELEN]; 236 237 if (!list) 238 list = emalloc((maxentry = DEFNUM) * sizeof(char *)); 239 while (fgets(buf, MAXLINELEN, fp)) { 240 for (p = buf; *p && isspace(*p); ++p); 241 if (!*p) 242 continue; 243 if (!(p = index(p, '\n'))) { 244 (void)fprintf(stderr, "column: line too long.\n"); 245 eval = 1; 246 continue; 247 } 248 *p = '\0'; 249 len = p - buf; 250 if (maxlength < len) 251 maxlength = len; 252 if (entries == maxentry) { 253 maxentry += DEFNUM; 254 if (!(list = realloc(list, 255 (u_int)maxentry * sizeof(char *)))) 256 nomem(); 257 } 258 list[entries++] = strdup(buf); 259 } 260 } 261 262 void * 263 emalloc(size) 264 int size; 265 { 266 char *p; 267 268 if (!(p = malloc(size))) 269 nomem(); 270 bzero(p, size); 271 return(p); 272 } 273 274 void 275 nomem() 276 { 277 (void)fprintf(stderr, "column: out of memory.\n"); 278 exit(1); 279 } 280 281 void 282 usage() 283 { 284 (void)fprintf(stderr, 285 "usage: column [-tx] [-c columns] [file ...]\n"); 286 exit(1); 287 } 288