1 /* 2 * Copyright (c) 1989, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * $FreeBSD: src/usr.bin/column/column.c,v 1.4.6.2 2001/08/02 01:34:19 obrien Exp $ 34 * $DragonFly: src/usr.bin/column/column.c,v 1.6 2006/10/08 09:12:32 corecode Exp $ 35 * 36 * @(#) Copyright (c) 1989, 1993, 1994 The Regents of the University of California. All rights reserved. 37 * @(#)column.c 8.4 (Berkeley) 5/4/95 38 */ 39 40 #include <sys/types.h> 41 #include <sys/ioctl.h> 42 43 #include <ctype.h> 44 #include <err.h> 45 #include <limits.h> 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <string.h> 49 #include <unistd.h> 50 51 #define TAB 8 52 53 void c_columnate(void); 54 void input(FILE *); 55 void maketbl(void); 56 void print(void); 57 void r_columnate(void); 58 void usage(void); 59 60 int termwidth = 80; /* default terminal width */ 61 62 int entries; /* number of records */ 63 int eval; /* exit value */ 64 int maxlength; /* longest record */ 65 char **list; /* array of pointers to records */ 66 const char *separator = "\t "; /* field separator for table option */ 67 68 int 69 main(int argc, char **argv) 70 { 71 struct winsize win; 72 FILE *fp; 73 int ch, tflag, xflag; 74 char *p; 75 76 if (ioctl(1, TIOCGWINSZ, &win) == -1 || !win.ws_col) { 77 if ((p = getenv("COLUMNS"))) 78 termwidth = atoi(p); 79 } else 80 termwidth = win.ws_col; 81 82 tflag = xflag = 0; 83 while ((ch = getopt(argc, argv, "c:s:tx")) != -1) 84 switch(ch) { 85 case 'c': 86 termwidth = atoi(optarg); 87 break; 88 case 's': 89 separator = optarg; 90 break; 91 case 't': 92 tflag = 1; 93 break; 94 case 'x': 95 xflag = 1; 96 break; 97 case '?': 98 default: 99 usage(); 100 } 101 argc -= optind; 102 argv += optind; 103 104 if (!*argv) 105 input(stdin); 106 else for (; *argv; ++argv) 107 if ((fp = fopen(*argv, "r"))) { 108 input(fp); 109 (void)fclose(fp); 110 } else { 111 warn("%s", *argv); 112 eval = 1; 113 } 114 115 if (!entries) 116 exit(eval); 117 118 maxlength = (maxlength + TAB) & ~(TAB - 1); 119 if (tflag) 120 maketbl(); 121 else if (maxlength >= termwidth) 122 print(); 123 else if (xflag) 124 c_columnate(); 125 else 126 r_columnate(); 127 exit(eval); 128 } 129 130 void 131 c_columnate(void) 132 { 133 int chcnt, col, cnt, endcol, numcols; 134 char **lp; 135 136 numcols = termwidth / maxlength; 137 endcol = maxlength; 138 for (chcnt = col = 0, lp = list;; ++lp) { 139 chcnt += printf("%s", *lp); 140 if (!--entries) 141 break; 142 if (++col == numcols) { 143 chcnt = col = 0; 144 endcol = maxlength; 145 putchar('\n'); 146 } else { 147 while ((cnt = ((chcnt + TAB) & ~(TAB - 1))) <= endcol) { 148 (void)putchar('\t'); 149 chcnt = cnt; 150 } 151 endcol += maxlength; 152 } 153 } 154 if (chcnt) 155 putchar('\n'); 156 } 157 158 void 159 r_columnate(void) 160 { 161 int base, chcnt, cnt, col, endcol, numcols, numrows, row; 162 163 numcols = termwidth / maxlength; 164 numrows = entries / numcols; 165 if (entries % numcols) 166 ++numrows; 167 168 for (row = 0; row < numrows; ++row) { 169 endcol = maxlength; 170 for (base = row, chcnt = col = 0; col < numcols; ++col) { 171 chcnt += printf("%s", list[base]); 172 if ((base += numrows) >= entries) 173 break; 174 while ((cnt = ((chcnt + TAB) & ~(TAB - 1))) <= endcol) { 175 (void)putchar('\t'); 176 chcnt = cnt; 177 } 178 endcol += maxlength; 179 } 180 putchar('\n'); 181 } 182 } 183 184 void 185 print(void) 186 { 187 int cnt; 188 char **lp; 189 190 for (cnt = entries, lp = list; cnt--; ++lp) 191 (void)printf("%s\n", *lp); 192 } 193 194 typedef struct _tbl { 195 char **list; 196 int cols, *len; 197 } TBL; 198 #define DEFCOLS 25 199 200 void 201 maketbl(void) 202 { 203 TBL *t; 204 int coloff, cnt; 205 char *p, **lp; 206 int *lens, maxcols; 207 TBL *tbl; 208 char **cols; 209 210 if ((t = tbl = calloc(entries, sizeof(TBL))) == NULL) 211 err(1, NULL); 212 if ((cols = calloc((maxcols = DEFCOLS), sizeof(char *))) == NULL) 213 err(1, NULL); 214 if ((lens = calloc(maxcols, sizeof(int))) == NULL) 215 err(1, NULL); 216 for (cnt = 0, lp = list; cnt < entries; ++cnt, ++lp, ++t) { 217 for (coloff = 0, p = *lp; (cols[coloff] = strtok(p, separator)); 218 p = NULL) 219 if (++coloff == maxcols) { 220 if (!(cols = realloc(cols, ((u_int)maxcols + 221 DEFCOLS) * sizeof(char *))) || 222 !(lens = realloc(lens, 223 ((u_int)maxcols + DEFCOLS) * sizeof(int)))) 224 err(1, NULL); 225 memset((char *)lens + maxcols * sizeof(int), 226 0, DEFCOLS * sizeof(int)); 227 maxcols += DEFCOLS; 228 } 229 if ((t->list = calloc(coloff, sizeof(char *))) == NULL) 230 err(1, NULL); 231 if ((t->len = calloc(coloff, sizeof(int))) == NULL) 232 err(1, NULL); 233 for (t->cols = coloff; --coloff >= 0;) { 234 t->list[coloff] = cols[coloff]; 235 t->len[coloff] = strlen(cols[coloff]); 236 if (t->len[coloff] > lens[coloff]) 237 lens[coloff] = t->len[coloff]; 238 } 239 } 240 for (cnt = 0, t = tbl; cnt < entries; ++cnt, ++t) { 241 for (coloff = 0; coloff < t->cols - 1; ++coloff) 242 (void)printf("%s%*s", t->list[coloff], 243 lens[coloff] - t->len[coloff] + 2, " "); 244 (void)printf("%s\n", t->list[coloff]); 245 } 246 } 247 248 #define DEFNUM 1000 249 #define MAXLINELEN (LINE_MAX + 1) 250 251 void 252 input(FILE *fp) 253 { 254 static int maxentry; 255 int len; 256 char *p, buf[MAXLINELEN]; 257 258 if (!list) 259 if ((list = calloc((maxentry = DEFNUM), sizeof(char *))) == 260 NULL) 261 err(1, NULL); 262 while (fgets(buf, MAXLINELEN, fp)) { 263 for (p = buf; *p && isspace(*p); ++p); 264 if (!*p) 265 continue; 266 if (!(p = strchr(p, '\n'))) { 267 warnx("line too long"); 268 eval = 1; 269 continue; 270 } 271 *p = '\0'; 272 len = p - buf; 273 if (maxlength < len) 274 maxlength = len; 275 if (entries == maxentry) { 276 maxentry += DEFNUM; 277 if (!(list = realloc(list, 278 (u_int)maxentry * sizeof(char *)))) 279 err(1, NULL); 280 } 281 list[entries++] = strdup(buf); 282 } 283 } 284 285 void 286 usage(void) 287 { 288 289 (void)fprintf(stderr, 290 "usage: column [-tx] [-c columns] [-s sep] [file ...]\n"); 291 exit(1); 292 } 293