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