1 /* 2 * Copyright (c) 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 */ 17 18 #ifndef lint 19 char copyright[] = 20 "@(#) Copyright (c) 1989 The Regents of the University of California.\n\ 21 All rights reserved.\n"; 22 #endif /* not lint */ 23 24 #ifndef lint 25 static char sccsid[] = "@(#)column.c 5.5 (Berkeley) 05/15/90"; 26 #endif /* not lint */ 27 28 #include <sys/types.h> 29 #include <sys/ioctl.h> 30 #include <stdio.h> 31 #include <string.h> 32 #include <ctype.h> 33 34 int termwidth = 80; /* default terminal width */ 35 36 int entries; /* number of records */ 37 int eval; /* exit value */ 38 int maxlength; /* longest record */ 39 char **list; /* array of pointers to records */ 40 char *separator = "\t "; /* field separator for table option */ 41 42 main(argc, argv) 43 int argc; 44 char **argv; 45 { 46 extern char *optarg; 47 extern int errno, optind; 48 struct winsize win; 49 FILE *fp; 50 int ch, tflag, xflag; 51 char *p, *getenv(); 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 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 { 99 if (maxlength >= termwidth) 100 print(); 101 if (xflag) 102 c_columnate(); 103 else 104 r_columnate(); 105 } 106 exit(eval); 107 } 108 109 #define TAB 8 110 c_columnate() 111 { 112 register int chcnt, col, cnt, numcols; 113 int endcol; 114 char **lp; 115 116 maxlength = (maxlength + TAB) & ~(TAB - 1); 117 numcols = termwidth / maxlength; 118 endcol = maxlength; 119 for (chcnt = col = 0, lp = list;; ++lp) { 120 chcnt += printf("%s", *lp); 121 if (!--entries) 122 break; 123 if (++col == numcols) { 124 chcnt = col = 0; 125 endcol = maxlength; 126 putchar('\n'); 127 } else { 128 while ((cnt = (chcnt + TAB & ~(TAB - 1))) <= endcol) { 129 (void)putchar('\t'); 130 chcnt = cnt; 131 } 132 endcol += maxlength; 133 } 134 } 135 if (chcnt) 136 putchar('\n'); 137 } 138 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 print() 167 { 168 register int cnt; 169 register 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 maketbl() 182 { 183 register TBL *t; 184 register int coloff, cnt; 185 register char *p, **lp; 186 int *lens, maxcols; 187 TBL *tbl; 188 char **cols, *emalloc(), *realloc(); 189 190 t = tbl = (TBL *)emalloc(entries * sizeof(TBL)); 191 cols = (char **)emalloc((maxcols = DEFCOLS) * sizeof(char *)); 192 lens = (int *)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 = (char **)realloc((char *)cols, 198 (u_int)maxcols + DEFCOLS * sizeof(char *))) || 199 !(lens = (int *)realloc((char *)lens, 200 (u_int)maxcols + DEFCOLS * sizeof(int)))) 201 nomem(); 202 bzero((char *)lens + maxcols * sizeof(int), 203 DEFCOLS * sizeof(int)); 204 maxcols += DEFCOLS; 205 } 206 t->list = (char **)emalloc(coloff * sizeof(char *)); 207 t->len = (int *)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 (2048 + 1) 225 226 input(fp) 227 register FILE *fp; 228 { 229 static int maxentry; 230 register int len; 231 register char *p; 232 char buf[MAXLINELEN], *emalloc(), *realloc(); 233 234 if (!list) 235 list = (char **)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 = index(p, '\n'))) { 241 (void)fprintf(stderr, "column: line too long.\n"); 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 = 252 (char **)realloc((char *)list, 253 (u_int)maxentry * sizeof(char *)))) 254 nomem(); 255 } 256 list[entries++] = strdup(buf); 257 } 258 } 259 260 char * 261 emalloc(size) 262 int size; 263 { 264 char *p, *malloc(); 265 266 /* NOSTRICT */ 267 if (!(p = malloc((u_int)size))) 268 nomem(); 269 bzero(p, size); 270 return(p); 271 } 272 273 nomem() 274 { 275 (void)fprintf(stderr, "column: out of memory.\n"); 276 exit(1); 277 } 278 279 usage() 280 { 281 (void)fprintf(stderr, 282 "usage: column [-tx] [-c columns] [file ...]\n"); 283 exit(1); 284 } 285