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