Adjust for recent changes.
[dragonfly.git] / usr.bin / column / column.c
blob37187d2558903b238600bee4cd818f6164f5b363
1 /*
2 * Copyright (c) 1989, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
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.
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.
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 $
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
40 #include <sys/types.h>
41 #include <sys/ioctl.h>
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>
51 #define TAB 8
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);
60 int termwidth = 80; /* default terminal width */
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 */
68 int
69 main(int argc, char **argv)
71 struct winsize win;
72 FILE *fp;
73 int ch, tflag, xflag;
74 char *p;
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;
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();
101 argc -= optind;
102 argv += optind;
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;
115 if (!entries)
116 exit(eval);
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);
130 void
131 c_columnate(void)
133 int chcnt, col, cnt, endcol, numcols;
134 char **lp;
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;
151 endcol += maxlength;
154 if (chcnt)
155 putchar('\n');
158 void
159 r_columnate(void)
161 int base, chcnt, cnt, col, endcol, numcols, numrows, row;
163 numcols = termwidth / maxlength;
164 numrows = entries / numcols;
165 if (entries % numcols)
166 ++numrows;
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;
178 endcol += maxlength;
180 putchar('\n');
184 void
185 print(void)
187 int cnt;
188 char **lp;
190 for (cnt = entries, lp = list; cnt--; ++lp)
191 (void)printf("%s\n", *lp);
194 typedef struct _tbl {
195 char **list;
196 int cols, *len;
197 } TBL;
198 #define DEFCOLS 25
200 void
201 maketbl(void)
203 TBL *t;
204 int coloff, cnt;
205 char *p, **lp;
206 int *lens, maxcols;
207 TBL *tbl;
208 char **cols;
210 if ((t = tbl = calloc(entries, sizeof(TBL))) == NULL)
211 err(1, (char *)NULL);
212 if ((cols = calloc((maxcols = DEFCOLS), sizeof(char *))) == NULL)
213 err(1, (char *)NULL);
214 if ((lens = calloc(maxcols, sizeof(int))) == NULL)
215 err(1, (char *)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;
229 if ((t->list = calloc(coloff, sizeof(char *))) == NULL)
230 err(1, (char *)NULL);
231 if ((t->len = calloc(coloff, sizeof(int))) == NULL)
232 err(1, (char *)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];
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]);
248 #define DEFNUM 1000
249 #define MAXLINELEN (LINE_MAX + 1)
251 void
252 input(FILE *fp)
254 static int maxentry;
255 int len;
256 char *p, buf[MAXLINELEN];
258 if (!list)
259 if ((list = calloc((maxentry = DEFNUM), sizeof(char *))) ==
260 NULL)
261 err(1, (char *)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;
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);
281 list[entries++] = strdup(buf);
285 void
286 usage(void)
289 (void)fprintf(stderr,
290 "usage: column [-tx] [-c columns] [-s sep] [file ...]\n");
291 exit(1);