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