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