Annotation of src/usr.bin/column/column.c, Revision 1.14
1.14 ! millert 1: /* $OpenBSD: column.c,v 1.13 2007/05/01 01:26:23 jdixon Exp $ */
1.1 deraadt 2: /* $NetBSD: column.c,v 1.4 1995/09/02 05:53:03 jtc Exp $ */
3:
4: /*
5: * Copyright (c) 1989, 1993, 1994
6: * The Regents of the University of California. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
1.8 millert 16: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 17: * may be used to endorse or promote products derived from this software
18: * without specific prior written permission.
19: *
20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30: * SUCH DAMAGE.
31: */
32:
33: #ifndef lint
34: static char copyright[] =
35: "@(#) Copyright (c) 1989, 1993, 1994\n\
36: The Regents of the University of California. All rights reserved.\n";
37: #endif /* not lint */
38:
39: #ifndef lint
40: #if 0
41: static char sccsid[] = "@(#)column.c 8.4 (Berkeley) 5/4/95";
42: #endif
1.14 ! millert 43: static char rcsid[] = "$OpenBSD: column.c,v 1.13 2007/05/01 01:26:23 jdixon Exp $";
1.1 deraadt 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:
1.7 millert 57: void c_columnate(void);
1.11 otto 58: void *emalloc(size_t);
1.14 ! millert 59: void *erealloc(void *, size_t);
1.7 millert 60: void input(FILE *);
61: void maketbl(void);
62: void print(void);
63: void r_columnate(void);
64: void usage(void);
1.1 deraadt 65:
66: int termwidth = 80; /* default terminal width */
67:
68: int entries; /* number of records */
69: int eval; /* exit value */
70: int maxlength; /* longest record */
71: char **list; /* array of pointers to records */
72: char *separator = "\t "; /* field separator for table option */
73:
74: int
1.9 deraadt 75: main(int argc, char *argv[])
1.1 deraadt 76: {
77: struct winsize win;
78: FILE *fp;
79: int ch, tflag, xflag;
80: char *p;
1.13 jdixon 81: const char *errstr;
1.1 deraadt 82:
83: if (ioctl(1, TIOCGWINSZ, &win) == -1 || !win.ws_col) {
1.13 jdixon 84: if ((p = getenv("COLUMNS")) && *p != '\0') {
85: termwidth = strtonum(p, 1, INT_MAX, &errstr);
86: if (errstr != NULL)
87: errx(1, "%s: %s", errstr, p);
88: }
1.1 deraadt 89: } else
90: termwidth = win.ws_col;
91:
92: tflag = xflag = 0;
1.3 millert 93: while ((ch = getopt(argc, argv, "c:s:tx")) != -1)
1.1 deraadt 94: switch(ch) {
95: case 'c':
1.13 jdixon 96: termwidth = strtonum(optarg, 1, INT_MAX, &errstr);
97: if (errstr != NULL)
98: errx(1, "%s: %s", errstr, optarg);
1.1 deraadt 99: break;
100: case 's':
101: separator = optarg;
102: break;
103: case 't':
104: tflag = 1;
105: break;
106: case 'x':
107: xflag = 1;
108: break;
109: case '?':
110: default:
111: usage();
112: }
113: argc -= optind;
114: argv += optind;
115:
116: if (!*argv)
117: input(stdin);
118: else for (; *argv; ++argv)
1.6 deraadt 119: if ((fp = fopen(*argv, "r"))) {
1.1 deraadt 120: input(fp);
121: (void)fclose(fp);
122: } else {
123: warn("%s", *argv);
124: eval = 1;
125: }
126:
127: if (!entries)
128: exit(eval);
129:
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: #define TAB 8
142: void
1.9 deraadt 143: c_columnate(void)
1.1 deraadt 144: {
145: int chcnt, col, cnt, endcol, numcols;
146: char **lp;
147:
148: maxlength = (maxlength + TAB) & ~(TAB - 1);
149: numcols = termwidth / maxlength;
150: endcol = maxlength;
151: for (chcnt = col = 0, lp = list;; ++lp) {
152: chcnt += printf("%s", *lp);
153: if (!--entries)
154: break;
155: if (++col == numcols) {
156: chcnt = col = 0;
157: endcol = maxlength;
158: putchar('\n');
159: } else {
1.6 deraadt 160: while ((cnt = ((chcnt + TAB) & ~(TAB - 1))) <= endcol) {
1.1 deraadt 161: (void)putchar('\t');
162: chcnt = cnt;
163: }
164: endcol += maxlength;
165: }
166: }
167: if (chcnt)
168: putchar('\n');
169: }
170:
171: void
1.9 deraadt 172: r_columnate(void)
1.1 deraadt 173: {
174: int base, chcnt, cnt, col, endcol, numcols, numrows, row;
175:
176: maxlength = (maxlength + TAB) & ~(TAB - 1);
177: numcols = termwidth / maxlength;
1.5 millert 178: if (numcols == 0)
179: numcols = 1;
1.1 deraadt 180: numrows = entries / numcols;
181: if (entries % numcols)
182: ++numrows;
183:
184: for (row = 0; row < numrows; ++row) {
185: endcol = maxlength;
186: for (base = row, chcnt = col = 0; col < numcols; ++col) {
187: chcnt += printf("%s", list[base]);
188: if ((base += numrows) >= entries)
189: break;
1.6 deraadt 190: while ((cnt = ((chcnt + TAB) & ~(TAB - 1))) <= endcol) {
1.1 deraadt 191: (void)putchar('\t');
192: chcnt = cnt;
193: }
194: endcol += maxlength;
195: }
196: putchar('\n');
197: }
198: }
199:
200: void
1.9 deraadt 201: print(void)
1.1 deraadt 202: {
203: int cnt;
204: char **lp;
205:
206: for (cnt = entries, lp = list; cnt--; ++lp)
207: (void)printf("%s\n", *lp);
208: }
209:
210: typedef struct _tbl {
211: char **list;
212: int cols, *len;
213: } TBL;
214: #define DEFCOLS 25
215:
216: void
1.9 deraadt 217: maketbl(void)
1.1 deraadt 218: {
219: TBL *t;
220: int coloff, cnt;
221: char *p, **lp;
1.14 ! millert 222: int *lens, maxcols;
1.1 deraadt 223: TBL *tbl;
1.14 ! millert 224: char **cols;
1.1 deraadt 225:
226: t = tbl = emalloc(entries * sizeof(TBL));
227: cols = emalloc((maxcols = DEFCOLS) * sizeof(char *));
228: lens = emalloc(maxcols * sizeof(int));
229: for (cnt = 0, lp = list; cnt < entries; ++cnt, ++lp, ++t) {
1.6 deraadt 230: for (coloff = 0, p = *lp; (cols[coloff] = strtok(p, separator));
1.1 deraadt 231: p = NULL)
232: if (++coloff == maxcols) {
233: maxcols += DEFCOLS;
1.14 ! millert 234: cols = erealloc(cols, maxcols * sizeof(char *));
! 235: lens = erealloc(lens, maxcols * sizeof(int));
! 236: memset(lens + coloff, 0, DEFCOLS * sizeof(int));
1.1 deraadt 237: }
1.14 ! millert 238: if (coloff == 0)
! 239: continue;
1.1 deraadt 240: t->list = emalloc(coloff * sizeof(char *));
241: t->len = emalloc(coloff * sizeof(int));
242: for (t->cols = coloff; --coloff >= 0;) {
243: t->list[coloff] = cols[coloff];
244: t->len[coloff] = strlen(cols[coloff]);
245: if (t->len[coloff] > lens[coloff])
246: lens[coloff] = t->len[coloff];
247: }
248: }
249: for (cnt = 0, t = tbl; cnt < entries; ++cnt, ++t) {
1.14 ! millert 250: if (t->cols > 0) {
! 251: for (coloff = 0; coloff < t->cols - 1; ++coloff)
! 252: (void)printf("%s%*s", t->list[coloff],
! 253: lens[coloff] - t->len[coloff] + 2, " ");
! 254: (void)printf("%s\n", t->list[coloff]);
! 255: }
1.1 deraadt 256: }
257: }
258:
259: #define DEFNUM 1000
260: #define MAXLINELEN (LINE_MAX + 1)
261:
262: void
1.9 deraadt 263: input(FILE *fp)
1.1 deraadt 264: {
1.11 otto 265: static size_t maxentry;
1.1 deraadt 266: int len;
267: char *p, buf[MAXLINELEN];
268:
269: if (!list)
270: list = emalloc((maxentry = DEFNUM) * sizeof(char *));
271: while (fgets(buf, MAXLINELEN, fp)) {
1.12 tedu 272: for (p = buf; isspace(*p); ++p);
1.1 deraadt 273: if (!*p)
274: continue;
275: if (!(p = strchr(p, '\n'))) {
276: warnx("line too long");
277: eval = 1;
278: continue;
279: }
280: *p = '\0';
281: len = p - buf;
282: if (maxlength < len)
283: maxlength = len;
284: if (entries == maxentry) {
1.14 ! millert 285: maxentry += DEFNUM;
! 286: list = erealloc(list, maxentry * sizeof(char *));
1.1 deraadt 287: }
1.11 otto 288: if (!(list[entries++] = strdup(buf)))
289: err(1, NULL);
1.1 deraadt 290: }
291: }
292:
293: void *
1.11 otto 294: emalloc(size_t size)
1.1 deraadt 295: {
1.11 otto 296: void *p;
1.1 deraadt 297:
298: if (!(p = malloc(size)))
299: err(1, NULL);
300: memset(p, 0, size);
1.14 ! millert 301: return (p);
! 302: }
! 303:
! 304: void *
! 305: erealloc(void *oldp, size_t size)
! 306: {
! 307: void *p;
! 308:
! 309: if (!(p = realloc(oldp, size)))
! 310: err(1, NULL);
1.1 deraadt 311: return (p);
312: }
313:
314: void
1.9 deraadt 315: usage(void)
1.1 deraadt 316: {
317:
318: (void)fprintf(stderr,
1.4 deraadt 319: "usage: column [-tx] [-c columns] [-s sep] [file ...]\n");
1.1 deraadt 320: exit(1);
321: }