10da30e9aSPeter Wemm /* 20da30e9aSPeter Wemm * Copyright (c) 1989, 1993, 1994 30da30e9aSPeter Wemm * The Regents of the University of California. All rights reserved. 40da30e9aSPeter Wemm * 50da30e9aSPeter Wemm * Redistribution and use in source and binary forms, with or without 60da30e9aSPeter Wemm * modification, are permitted provided that the following conditions 70da30e9aSPeter Wemm * are met: 80da30e9aSPeter Wemm * 1. Redistributions of source code must retain the above copyright 90da30e9aSPeter Wemm * notice, this list of conditions and the following disclaimer. 100da30e9aSPeter Wemm * 2. Redistributions in binary form must reproduce the above copyright 110da30e9aSPeter Wemm * notice, this list of conditions and the following disclaimer in the 120da30e9aSPeter Wemm * documentation and/or other materials provided with the distribution. 130da30e9aSPeter Wemm * 3. All advertising materials mentioning features or use of this software 140da30e9aSPeter Wemm * must display the following acknowledgement: 150da30e9aSPeter Wemm * This product includes software developed by the University of 160da30e9aSPeter Wemm * California, Berkeley and its contributors. 170da30e9aSPeter Wemm * 4. Neither the name of the University nor the names of its contributors 180da30e9aSPeter Wemm * may be used to endorse or promote products derived from this software 190da30e9aSPeter Wemm * without specific prior written permission. 200da30e9aSPeter Wemm * 210da30e9aSPeter Wemm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 220da30e9aSPeter Wemm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 230da30e9aSPeter Wemm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 240da30e9aSPeter Wemm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 250da30e9aSPeter Wemm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 260da30e9aSPeter Wemm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 270da30e9aSPeter Wemm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 280da30e9aSPeter Wemm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 290da30e9aSPeter Wemm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 300da30e9aSPeter Wemm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 310da30e9aSPeter Wemm * SUCH DAMAGE. 320da30e9aSPeter Wemm */ 330da30e9aSPeter Wemm 340da30e9aSPeter Wemm #ifndef lint 35fa146c53SArchie Cobbs static const char copyright[] = 360da30e9aSPeter Wemm "@(#) Copyright (c) 1989, 1993, 1994\n\ 370da30e9aSPeter Wemm The Regents of the University of California. All rights reserved.\n"; 380da30e9aSPeter Wemm #endif /* not lint */ 390da30e9aSPeter Wemm 400da30e9aSPeter Wemm #ifndef lint 41fa146c53SArchie Cobbs static const char sccsid[] = "@(#)column.c 8.4 (Berkeley) 5/4/95"; 420da30e9aSPeter Wemm #endif /* not lint */ 430da30e9aSPeter Wemm 440da30e9aSPeter Wemm #include <sys/types.h> 450da30e9aSPeter Wemm #include <sys/ioctl.h> 460da30e9aSPeter Wemm 470da30e9aSPeter Wemm #include <ctype.h> 480da30e9aSPeter Wemm #include <err.h> 490da30e9aSPeter Wemm #include <limits.h> 500da30e9aSPeter Wemm #include <stdio.h> 510da30e9aSPeter Wemm #include <stdlib.h> 520da30e9aSPeter Wemm #include <string.h> 530da30e9aSPeter Wemm #include <unistd.h> 540da30e9aSPeter Wemm 550da30e9aSPeter Wemm void c_columnate __P((void)); 560da30e9aSPeter Wemm void *emalloc __P((int)); 570da30e9aSPeter Wemm void input __P((FILE *)); 580da30e9aSPeter Wemm void maketbl __P((void)); 590da30e9aSPeter Wemm void print __P((void)); 600da30e9aSPeter Wemm void r_columnate __P((void)); 610da30e9aSPeter Wemm void usage __P((void)); 620da30e9aSPeter Wemm 630da30e9aSPeter Wemm int termwidth = 80; /* default terminal width */ 640da30e9aSPeter Wemm 650da30e9aSPeter Wemm int entries; /* number of records */ 660da30e9aSPeter Wemm int eval; /* exit value */ 670da30e9aSPeter Wemm int maxlength; /* longest record */ 680da30e9aSPeter Wemm char **list; /* array of pointers to records */ 690da30e9aSPeter Wemm char *separator = "\t "; /* field separator for table option */ 700da30e9aSPeter Wemm 710da30e9aSPeter Wemm int 720da30e9aSPeter Wemm main(argc, argv) 730da30e9aSPeter Wemm int argc; 740da30e9aSPeter Wemm char **argv; 750da30e9aSPeter Wemm { 760da30e9aSPeter Wemm struct winsize win; 770da30e9aSPeter Wemm FILE *fp; 780da30e9aSPeter Wemm int ch, tflag, xflag; 790da30e9aSPeter Wemm char *p; 800da30e9aSPeter Wemm 810da30e9aSPeter Wemm if (ioctl(1, TIOCGWINSZ, &win) == -1 || !win.ws_col) { 82fa146c53SArchie Cobbs if ((p = getenv("COLUMNS"))) 830da30e9aSPeter Wemm termwidth = atoi(p); 840da30e9aSPeter Wemm } else 850da30e9aSPeter Wemm termwidth = win.ws_col; 860da30e9aSPeter Wemm 870da30e9aSPeter Wemm tflag = xflag = 0; 881c8af878SWarner Losh while ((ch = getopt(argc, argv, "c:s:tx")) != -1) 890da30e9aSPeter Wemm switch(ch) { 900da30e9aSPeter Wemm case 'c': 910da30e9aSPeter Wemm termwidth = atoi(optarg); 920da30e9aSPeter Wemm break; 930da30e9aSPeter Wemm case 's': 940da30e9aSPeter Wemm separator = optarg; 950da30e9aSPeter Wemm break; 960da30e9aSPeter Wemm case 't': 970da30e9aSPeter Wemm tflag = 1; 980da30e9aSPeter Wemm break; 990da30e9aSPeter Wemm case 'x': 1000da30e9aSPeter Wemm xflag = 1; 1010da30e9aSPeter Wemm break; 1020da30e9aSPeter Wemm case '?': 1030da30e9aSPeter Wemm default: 1040da30e9aSPeter Wemm usage(); 1050da30e9aSPeter Wemm } 1060da30e9aSPeter Wemm argc -= optind; 1070da30e9aSPeter Wemm argv += optind; 1080da30e9aSPeter Wemm 1090da30e9aSPeter Wemm if (!*argv) 1100da30e9aSPeter Wemm input(stdin); 1110da30e9aSPeter Wemm else for (; *argv; ++argv) 112fa146c53SArchie Cobbs if ((fp = fopen(*argv, "r"))) { 1130da30e9aSPeter Wemm input(fp); 1140da30e9aSPeter Wemm (void)fclose(fp); 1150da30e9aSPeter Wemm } else { 1160da30e9aSPeter Wemm warn("%s", *argv); 1170da30e9aSPeter Wemm eval = 1; 1180da30e9aSPeter Wemm } 1190da30e9aSPeter Wemm 1200da30e9aSPeter Wemm if (!entries) 1210da30e9aSPeter Wemm exit(eval); 1220da30e9aSPeter Wemm 1230da30e9aSPeter Wemm if (tflag) 1240da30e9aSPeter Wemm maketbl(); 1250da30e9aSPeter Wemm else if (maxlength >= termwidth) 1260da30e9aSPeter Wemm print(); 1270da30e9aSPeter Wemm else if (xflag) 1280da30e9aSPeter Wemm c_columnate(); 1290da30e9aSPeter Wemm else 1300da30e9aSPeter Wemm r_columnate(); 1310da30e9aSPeter Wemm exit(eval); 1320da30e9aSPeter Wemm } 1330da30e9aSPeter Wemm 1340da30e9aSPeter Wemm #define TAB 8 1350da30e9aSPeter Wemm void 1360da30e9aSPeter Wemm c_columnate() 1370da30e9aSPeter Wemm { 1380da30e9aSPeter Wemm int chcnt, col, cnt, endcol, numcols; 1390da30e9aSPeter Wemm char **lp; 1400da30e9aSPeter Wemm 1410da30e9aSPeter Wemm maxlength = (maxlength + TAB) & ~(TAB - 1); 1420da30e9aSPeter Wemm numcols = termwidth / maxlength; 1430da30e9aSPeter Wemm endcol = maxlength; 1440da30e9aSPeter Wemm for (chcnt = col = 0, lp = list;; ++lp) { 1450da30e9aSPeter Wemm chcnt += printf("%s", *lp); 1460da30e9aSPeter Wemm if (!--entries) 1470da30e9aSPeter Wemm break; 1480da30e9aSPeter Wemm if (++col == numcols) { 1490da30e9aSPeter Wemm chcnt = col = 0; 1500da30e9aSPeter Wemm endcol = maxlength; 1510da30e9aSPeter Wemm putchar('\n'); 1520da30e9aSPeter Wemm } else { 153fa146c53SArchie Cobbs while ((cnt = ((chcnt + TAB) & ~(TAB - 1))) <= endcol) { 1540da30e9aSPeter Wemm (void)putchar('\t'); 1550da30e9aSPeter Wemm chcnt = cnt; 1560da30e9aSPeter Wemm } 1570da30e9aSPeter Wemm endcol += maxlength; 1580da30e9aSPeter Wemm } 1590da30e9aSPeter Wemm } 1600da30e9aSPeter Wemm if (chcnt) 1610da30e9aSPeter Wemm putchar('\n'); 1620da30e9aSPeter Wemm } 1630da30e9aSPeter Wemm 1640da30e9aSPeter Wemm void 1650da30e9aSPeter Wemm r_columnate() 1660da30e9aSPeter Wemm { 1670da30e9aSPeter Wemm int base, chcnt, cnt, col, endcol, numcols, numrows, row; 1680da30e9aSPeter Wemm 1690da30e9aSPeter Wemm maxlength = (maxlength + TAB) & ~(TAB - 1); 1700da30e9aSPeter Wemm numcols = termwidth / maxlength; 1710da30e9aSPeter Wemm numrows = entries / numcols; 1720da30e9aSPeter Wemm if (entries % numcols) 1730da30e9aSPeter Wemm ++numrows; 1740da30e9aSPeter Wemm 1750da30e9aSPeter Wemm for (row = 0; row < numrows; ++row) { 1760da30e9aSPeter Wemm endcol = maxlength; 1770da30e9aSPeter Wemm for (base = row, chcnt = col = 0; col < numcols; ++col) { 1780da30e9aSPeter Wemm chcnt += printf("%s", list[base]); 1790da30e9aSPeter Wemm if ((base += numrows) >= entries) 1800da30e9aSPeter Wemm break; 181fa146c53SArchie Cobbs while ((cnt = ((chcnt + TAB) & ~(TAB - 1))) <= endcol) { 1820da30e9aSPeter Wemm (void)putchar('\t'); 1830da30e9aSPeter Wemm chcnt = cnt; 1840da30e9aSPeter Wemm } 1850da30e9aSPeter Wemm endcol += maxlength; 1860da30e9aSPeter Wemm } 1870da30e9aSPeter Wemm putchar('\n'); 1880da30e9aSPeter Wemm } 1890da30e9aSPeter Wemm } 1900da30e9aSPeter Wemm 1910da30e9aSPeter Wemm void 1920da30e9aSPeter Wemm print() 1930da30e9aSPeter Wemm { 1940da30e9aSPeter Wemm int cnt; 1950da30e9aSPeter Wemm char **lp; 1960da30e9aSPeter Wemm 1970da30e9aSPeter Wemm for (cnt = entries, lp = list; cnt--; ++lp) 1980da30e9aSPeter Wemm (void)printf("%s\n", *lp); 1990da30e9aSPeter Wemm } 2000da30e9aSPeter Wemm 2010da30e9aSPeter Wemm typedef struct _tbl { 2020da30e9aSPeter Wemm char **list; 2030da30e9aSPeter Wemm int cols, *len; 2040da30e9aSPeter Wemm } TBL; 2050da30e9aSPeter Wemm #define DEFCOLS 25 2060da30e9aSPeter Wemm 2070da30e9aSPeter Wemm void 2080da30e9aSPeter Wemm maketbl() 2090da30e9aSPeter Wemm { 2100da30e9aSPeter Wemm TBL *t; 2110da30e9aSPeter Wemm int coloff, cnt; 2120da30e9aSPeter Wemm char *p, **lp; 2130da30e9aSPeter Wemm int *lens, maxcols; 2140da30e9aSPeter Wemm TBL *tbl; 2150da30e9aSPeter Wemm char **cols; 2160da30e9aSPeter Wemm 2170da30e9aSPeter Wemm t = tbl = emalloc(entries * sizeof(TBL)); 2180da30e9aSPeter Wemm cols = emalloc((maxcols = DEFCOLS) * sizeof(char *)); 2190da30e9aSPeter Wemm lens = emalloc(maxcols * sizeof(int)); 2200da30e9aSPeter Wemm for (cnt = 0, lp = list; cnt < entries; ++cnt, ++lp, ++t) { 221fa146c53SArchie Cobbs for (coloff = 0, p = *lp; (cols[coloff] = strtok(p, separator)); 2220da30e9aSPeter Wemm p = NULL) 2230da30e9aSPeter Wemm if (++coloff == maxcols) { 2240da30e9aSPeter Wemm if (!(cols = realloc(cols, (u_int)maxcols + 2250da30e9aSPeter Wemm DEFCOLS * sizeof(char *))) || 2260da30e9aSPeter Wemm !(lens = realloc(lens, 2270da30e9aSPeter Wemm (u_int)maxcols + DEFCOLS * sizeof(int)))) 2280da30e9aSPeter Wemm err(1, NULL); 2290da30e9aSPeter Wemm memset((char *)lens + maxcols * sizeof(int), 2300da30e9aSPeter Wemm 0, DEFCOLS * sizeof(int)); 2310da30e9aSPeter Wemm maxcols += DEFCOLS; 2320da30e9aSPeter Wemm } 2330da30e9aSPeter Wemm t->list = emalloc(coloff * sizeof(char *)); 2340da30e9aSPeter Wemm t->len = emalloc(coloff * sizeof(int)); 2350da30e9aSPeter Wemm for (t->cols = coloff; --coloff >= 0;) { 2360da30e9aSPeter Wemm t->list[coloff] = cols[coloff]; 2370da30e9aSPeter Wemm t->len[coloff] = strlen(cols[coloff]); 2380da30e9aSPeter Wemm if (t->len[coloff] > lens[coloff]) 2390da30e9aSPeter Wemm lens[coloff] = t->len[coloff]; 2400da30e9aSPeter Wemm } 2410da30e9aSPeter Wemm } 2420da30e9aSPeter Wemm for (cnt = 0, t = tbl; cnt < entries; ++cnt, ++t) { 2430da30e9aSPeter Wemm for (coloff = 0; coloff < t->cols - 1; ++coloff) 2440da30e9aSPeter Wemm (void)printf("%s%*s", t->list[coloff], 2450da30e9aSPeter Wemm lens[coloff] - t->len[coloff] + 2, " "); 2460da30e9aSPeter Wemm (void)printf("%s\n", t->list[coloff]); 2470da30e9aSPeter Wemm } 2480da30e9aSPeter Wemm } 2490da30e9aSPeter Wemm 2500da30e9aSPeter Wemm #define DEFNUM 1000 2510da30e9aSPeter Wemm #define MAXLINELEN (LINE_MAX + 1) 2520da30e9aSPeter Wemm 2530da30e9aSPeter Wemm void 2540da30e9aSPeter Wemm input(fp) 2550da30e9aSPeter Wemm FILE *fp; 2560da30e9aSPeter Wemm { 2570da30e9aSPeter Wemm static int maxentry; 2580da30e9aSPeter Wemm int len; 2590da30e9aSPeter Wemm char *p, buf[MAXLINELEN]; 2600da30e9aSPeter Wemm 2610da30e9aSPeter Wemm if (!list) 2620da30e9aSPeter Wemm list = emalloc((maxentry = DEFNUM) * sizeof(char *)); 2630da30e9aSPeter Wemm while (fgets(buf, MAXLINELEN, fp)) { 2640da30e9aSPeter Wemm for (p = buf; *p && isspace(*p); ++p); 2650da30e9aSPeter Wemm if (!*p) 2660da30e9aSPeter Wemm continue; 2670da30e9aSPeter Wemm if (!(p = strchr(p, '\n'))) { 2680da30e9aSPeter Wemm warnx("line too long"); 2690da30e9aSPeter Wemm eval = 1; 2700da30e9aSPeter Wemm continue; 2710da30e9aSPeter Wemm } 2720da30e9aSPeter Wemm *p = '\0'; 2730da30e9aSPeter Wemm len = p - buf; 2740da30e9aSPeter Wemm if (maxlength < len) 2750da30e9aSPeter Wemm maxlength = len; 2760da30e9aSPeter Wemm if (entries == maxentry) { 2770da30e9aSPeter Wemm maxentry += DEFNUM; 2780da30e9aSPeter Wemm if (!(list = realloc(list, 2790da30e9aSPeter Wemm (u_int)maxentry * sizeof(char *)))) 2800da30e9aSPeter Wemm err(1, NULL); 2810da30e9aSPeter Wemm } 2820da30e9aSPeter Wemm list[entries++] = strdup(buf); 2830da30e9aSPeter Wemm } 2840da30e9aSPeter Wemm } 2850da30e9aSPeter Wemm 2860da30e9aSPeter Wemm void * 2870da30e9aSPeter Wemm emalloc(size) 2880da30e9aSPeter Wemm int size; 2890da30e9aSPeter Wemm { 2900da30e9aSPeter Wemm char *p; 2910da30e9aSPeter Wemm 2920da30e9aSPeter Wemm if (!(p = malloc(size))) 2930da30e9aSPeter Wemm err(1, NULL); 2940da30e9aSPeter Wemm memset(p, 0, size); 2950da30e9aSPeter Wemm return (p); 2960da30e9aSPeter Wemm } 2970da30e9aSPeter Wemm 2980da30e9aSPeter Wemm void 2990da30e9aSPeter Wemm usage() 3000da30e9aSPeter Wemm { 3010da30e9aSPeter Wemm 3020da30e9aSPeter Wemm (void)fprintf(stderr, 3033b5ec5aaSPhilippe Charnier "usage: column [-tx] [-c columns] [-s sep] [file ...]\n"); 3040da30e9aSPeter Wemm exit(1); 3050da30e9aSPeter Wemm } 306