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. 13*fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 140da30e9aSPeter Wemm * may be used to endorse or promote products derived from this software 150da30e9aSPeter Wemm * without specific prior written permission. 160da30e9aSPeter Wemm * 170da30e9aSPeter Wemm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 180da30e9aSPeter Wemm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 190da30e9aSPeter Wemm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 200da30e9aSPeter Wemm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 210da30e9aSPeter Wemm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 220da30e9aSPeter Wemm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 230da30e9aSPeter Wemm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 240da30e9aSPeter Wemm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 250da30e9aSPeter Wemm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 260da30e9aSPeter Wemm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 270da30e9aSPeter Wemm * SUCH DAMAGE. 280da30e9aSPeter Wemm */ 290da30e9aSPeter Wemm 300da30e9aSPeter Wemm #ifndef lint 31fa146c53SArchie Cobbs static const char copyright[] = 320da30e9aSPeter Wemm "@(#) Copyright (c) 1989, 1993, 1994\n\ 330da30e9aSPeter Wemm The Regents of the University of California. All rights reserved.\n"; 3492407069SMark Murray #endif 350da30e9aSPeter Wemm 369f5b04e9SDavid Malone #if 0 370da30e9aSPeter Wemm #ifndef lint 389f5b04e9SDavid Malone static char sccsid[] = "@(#)column.c 8.4 (Berkeley) 5/4/95"; 3992407069SMark Murray #endif 409f5b04e9SDavid Malone #endif 419f5b04e9SDavid Malone 429f5b04e9SDavid Malone #include <sys/cdefs.h> 439f5b04e9SDavid Malone __FBSDID("$FreeBSD$"); 440da30e9aSPeter Wemm 450da30e9aSPeter Wemm #include <sys/types.h> 460da30e9aSPeter Wemm #include <sys/ioctl.h> 47e2816c14SJuli Mallett #include <sys/param.h> 480da30e9aSPeter Wemm 490da30e9aSPeter Wemm #include <err.h> 500da30e9aSPeter Wemm #include <limits.h> 515480f120STim J. Robbins #include <locale.h> 520da30e9aSPeter Wemm #include <stdio.h> 530da30e9aSPeter Wemm #include <stdlib.h> 540da30e9aSPeter Wemm #include <string.h> 550da30e9aSPeter Wemm #include <unistd.h> 565480f120STim J. Robbins #include <wchar.h> 575480f120STim J. Robbins #include <wctype.h> 580da30e9aSPeter Wemm 59983e044aSDavid Malone #define TAB 8 60983e044aSDavid Malone 61316b87cbSEd Schouten static void c_columnate(void); 62316b87cbSEd Schouten static void input(FILE *); 63316b87cbSEd Schouten static void maketbl(void); 64316b87cbSEd Schouten static void print(void); 65316b87cbSEd Schouten static void r_columnate(void); 66316b87cbSEd Schouten static void usage(void); 67316b87cbSEd Schouten static int width(const wchar_t *); 680da30e9aSPeter Wemm 69316b87cbSEd Schouten static int termwidth = 80; /* default terminal width */ 700da30e9aSPeter Wemm 71316b87cbSEd Schouten static int entries; /* number of records */ 72316b87cbSEd Schouten static int eval; /* exit value */ 73316b87cbSEd Schouten static int maxlength; /* longest record */ 74316b87cbSEd Schouten static wchar_t **list; /* array of pointers to records */ 75316b87cbSEd Schouten static const wchar_t *separator = L"\t "; /* field separator for table option */ 760da30e9aSPeter Wemm 770da30e9aSPeter Wemm int 78823ab23fSDavid Malone main(int argc, char **argv) 790da30e9aSPeter Wemm { 800da30e9aSPeter Wemm struct winsize win; 810da30e9aSPeter Wemm FILE *fp; 820da30e9aSPeter Wemm int ch, tflag, xflag; 830da30e9aSPeter Wemm char *p; 845480f120STim J. Robbins const char *src; 855480f120STim J. Robbins wchar_t *newsep; 865480f120STim J. Robbins size_t seplen; 875480f120STim J. Robbins 885480f120STim J. Robbins setlocale(LC_ALL, ""); 890da30e9aSPeter Wemm 900da30e9aSPeter Wemm if (ioctl(1, TIOCGWINSZ, &win) == -1 || !win.ws_col) { 91fa146c53SArchie Cobbs if ((p = getenv("COLUMNS"))) 920da30e9aSPeter Wemm termwidth = atoi(p); 930da30e9aSPeter Wemm } else 940da30e9aSPeter Wemm termwidth = win.ws_col; 950da30e9aSPeter Wemm 960da30e9aSPeter Wemm tflag = xflag = 0; 971c8af878SWarner Losh while ((ch = getopt(argc, argv, "c:s:tx")) != -1) 980da30e9aSPeter Wemm switch(ch) { 990da30e9aSPeter Wemm case 'c': 1000da30e9aSPeter Wemm termwidth = atoi(optarg); 1010da30e9aSPeter Wemm break; 1020da30e9aSPeter Wemm case 's': 1035480f120STim J. Robbins src = optarg; 1045480f120STim J. Robbins seplen = mbsrtowcs(NULL, &src, 0, NULL); 1055480f120STim J. Robbins if (seplen == (size_t)-1) 1065480f120STim J. Robbins err(1, "bad separator"); 1075480f120STim J. Robbins newsep = malloc((seplen + 1) * sizeof(wchar_t)); 1085480f120STim J. Robbins if (newsep == NULL) 1095480f120STim J. Robbins err(1, NULL); 1105480f120STim J. Robbins mbsrtowcs(newsep, &src, seplen + 1, NULL); 1115480f120STim J. Robbins separator = newsep; 1120da30e9aSPeter Wemm break; 1130da30e9aSPeter Wemm case 't': 1140da30e9aSPeter Wemm tflag = 1; 1150da30e9aSPeter Wemm break; 1160da30e9aSPeter Wemm case 'x': 1170da30e9aSPeter Wemm xflag = 1; 1180da30e9aSPeter Wemm break; 1190da30e9aSPeter Wemm case '?': 1200da30e9aSPeter Wemm default: 1210da30e9aSPeter Wemm usage(); 1220da30e9aSPeter Wemm } 1230da30e9aSPeter Wemm argc -= optind; 1240da30e9aSPeter Wemm argv += optind; 1250da30e9aSPeter Wemm 1260da30e9aSPeter Wemm if (!*argv) 1270da30e9aSPeter Wemm input(stdin); 1280da30e9aSPeter Wemm else for (; *argv; ++argv) 129fa146c53SArchie Cobbs if ((fp = fopen(*argv, "r"))) { 1300da30e9aSPeter Wemm input(fp); 1310da30e9aSPeter Wemm (void)fclose(fp); 1320da30e9aSPeter Wemm } else { 1330da30e9aSPeter Wemm warn("%s", *argv); 1340da30e9aSPeter Wemm eval = 1; 1350da30e9aSPeter Wemm } 1360da30e9aSPeter Wemm 1370da30e9aSPeter Wemm if (!entries) 1380da30e9aSPeter Wemm exit(eval); 1390da30e9aSPeter Wemm 140090782f5SRuslan Ermilov maxlength = roundup(maxlength + 1, TAB); 1410da30e9aSPeter Wemm if (tflag) 1420da30e9aSPeter Wemm maketbl(); 1430da30e9aSPeter Wemm else if (maxlength >= termwidth) 1440da30e9aSPeter Wemm print(); 1450da30e9aSPeter Wemm else if (xflag) 1460da30e9aSPeter Wemm c_columnate(); 1470da30e9aSPeter Wemm else 1480da30e9aSPeter Wemm r_columnate(); 1490da30e9aSPeter Wemm exit(eval); 1500da30e9aSPeter Wemm } 1510da30e9aSPeter Wemm 152316b87cbSEd Schouten static void 153823ab23fSDavid Malone c_columnate(void) 1540da30e9aSPeter Wemm { 1550da30e9aSPeter Wemm int chcnt, col, cnt, endcol, numcols; 1565480f120STim J. Robbins wchar_t **lp; 1570da30e9aSPeter Wemm 1580da30e9aSPeter Wemm numcols = termwidth / maxlength; 1590da30e9aSPeter Wemm endcol = maxlength; 1600da30e9aSPeter Wemm for (chcnt = col = 0, lp = list;; ++lp) { 1615480f120STim J. Robbins wprintf(L"%ls", *lp); 1625480f120STim J. Robbins chcnt += width(*lp); 1630da30e9aSPeter Wemm if (!--entries) 1640da30e9aSPeter Wemm break; 1650da30e9aSPeter Wemm if (++col == numcols) { 1660da30e9aSPeter Wemm chcnt = col = 0; 1670da30e9aSPeter Wemm endcol = maxlength; 1685480f120STim J. Robbins putwchar('\n'); 1690da30e9aSPeter Wemm } else { 170090782f5SRuslan Ermilov while ((cnt = roundup(chcnt + 1, TAB)) <= endcol) { 1715480f120STim J. Robbins (void)putwchar('\t'); 1720da30e9aSPeter Wemm chcnt = cnt; 1730da30e9aSPeter Wemm } 1740da30e9aSPeter Wemm endcol += maxlength; 1750da30e9aSPeter Wemm } 1760da30e9aSPeter Wemm } 1770da30e9aSPeter Wemm if (chcnt) 1785480f120STim J. Robbins putwchar('\n'); 1790da30e9aSPeter Wemm } 1800da30e9aSPeter Wemm 181316b87cbSEd Schouten static void 182823ab23fSDavid Malone r_columnate(void) 1830da30e9aSPeter Wemm { 1840da30e9aSPeter Wemm int base, chcnt, cnt, col, endcol, numcols, numrows, row; 1850da30e9aSPeter Wemm 1860da30e9aSPeter Wemm numcols = termwidth / maxlength; 1870da30e9aSPeter Wemm numrows = entries / numcols; 1880da30e9aSPeter Wemm if (entries % numcols) 1890da30e9aSPeter Wemm ++numrows; 1900da30e9aSPeter Wemm 1910da30e9aSPeter Wemm for (row = 0; row < numrows; ++row) { 1920da30e9aSPeter Wemm endcol = maxlength; 1930da30e9aSPeter Wemm for (base = row, chcnt = col = 0; col < numcols; ++col) { 1945480f120STim J. Robbins wprintf(L"%ls", list[base]); 1955480f120STim J. Robbins chcnt += width(list[base]); 1960da30e9aSPeter Wemm if ((base += numrows) >= entries) 1970da30e9aSPeter Wemm break; 198090782f5SRuslan Ermilov while ((cnt = roundup(chcnt + 1, TAB)) <= endcol) { 1995480f120STim J. Robbins (void)putwchar('\t'); 2000da30e9aSPeter Wemm chcnt = cnt; 2010da30e9aSPeter Wemm } 2020da30e9aSPeter Wemm endcol += maxlength; 2030da30e9aSPeter Wemm } 2045480f120STim J. Robbins putwchar('\n'); 2050da30e9aSPeter Wemm } 2060da30e9aSPeter Wemm } 2070da30e9aSPeter Wemm 208316b87cbSEd Schouten static void 209823ab23fSDavid Malone print(void) 2100da30e9aSPeter Wemm { 2110da30e9aSPeter Wemm int cnt; 2125480f120STim J. Robbins wchar_t **lp; 2130da30e9aSPeter Wemm 2140da30e9aSPeter Wemm for (cnt = entries, lp = list; cnt--; ++lp) 2155480f120STim J. Robbins (void)wprintf(L"%ls\n", *lp); 2160da30e9aSPeter Wemm } 2170da30e9aSPeter Wemm 2180da30e9aSPeter Wemm typedef struct _tbl { 2195480f120STim J. Robbins wchar_t **list; 2200da30e9aSPeter Wemm int cols, *len; 2210da30e9aSPeter Wemm } TBL; 2220da30e9aSPeter Wemm #define DEFCOLS 25 2230da30e9aSPeter Wemm 224316b87cbSEd Schouten static void 225823ab23fSDavid Malone maketbl(void) 2260da30e9aSPeter Wemm { 2270da30e9aSPeter Wemm TBL *t; 2280da30e9aSPeter Wemm int coloff, cnt; 2295480f120STim J. Robbins wchar_t *p, **lp; 2300da30e9aSPeter Wemm int *lens, maxcols; 2310da30e9aSPeter Wemm TBL *tbl; 2325480f120STim J. Robbins wchar_t **cols; 2335480f120STim J. Robbins wchar_t *last; 2340da30e9aSPeter Wemm 235d54a8ce7SDavid E. O'Brien if ((t = tbl = calloc(entries, sizeof(TBL))) == NULL) 23618463c77SKevin Lo err(1, NULL); 2375480f120STim J. Robbins if ((cols = calloc((maxcols = DEFCOLS), sizeof(*cols))) == NULL) 23818463c77SKevin Lo err(1, NULL); 239d54a8ce7SDavid E. O'Brien if ((lens = calloc(maxcols, sizeof(int))) == NULL) 24018463c77SKevin Lo err(1, NULL); 2410da30e9aSPeter Wemm for (cnt = 0, lp = list; cnt < entries; ++cnt, ++lp, ++t) { 2425480f120STim J. Robbins for (coloff = 0, p = *lp; 2435480f120STim J. Robbins (cols[coloff] = wcstok(p, separator, &last)); 2440da30e9aSPeter Wemm p = NULL) 2450da30e9aSPeter Wemm if (++coloff == maxcols) { 2466508a1ecSIan Dowse if (!(cols = realloc(cols, ((u_int)maxcols + 247c9e1c304SUlrich Spörlein DEFCOLS) * sizeof(wchar_t *))) || 2480da30e9aSPeter Wemm !(lens = realloc(lens, 2496508a1ecSIan Dowse ((u_int)maxcols + DEFCOLS) * sizeof(int)))) 2500da30e9aSPeter Wemm err(1, NULL); 2510da30e9aSPeter Wemm memset((char *)lens + maxcols * sizeof(int), 2520da30e9aSPeter Wemm 0, DEFCOLS * sizeof(int)); 2530da30e9aSPeter Wemm maxcols += DEFCOLS; 2540da30e9aSPeter Wemm } 2555480f120STim J. Robbins if ((t->list = calloc(coloff, sizeof(*t->list))) == NULL) 25618463c77SKevin Lo err(1, NULL); 257d54a8ce7SDavid E. O'Brien if ((t->len = calloc(coloff, sizeof(int))) == NULL) 25818463c77SKevin Lo err(1, NULL); 2590da30e9aSPeter Wemm for (t->cols = coloff; --coloff >= 0;) { 2600da30e9aSPeter Wemm t->list[coloff] = cols[coloff]; 2615480f120STim J. Robbins t->len[coloff] = width(cols[coloff]); 2620da30e9aSPeter Wemm if (t->len[coloff] > lens[coloff]) 2630da30e9aSPeter Wemm lens[coloff] = t->len[coloff]; 2640da30e9aSPeter Wemm } 2650da30e9aSPeter Wemm } 2660da30e9aSPeter Wemm for (cnt = 0, t = tbl; cnt < entries; ++cnt, ++t) { 2670da30e9aSPeter Wemm for (coloff = 0; coloff < t->cols - 1; ++coloff) 2685480f120STim J. Robbins (void)wprintf(L"%ls%*ls", t->list[coloff], 2695480f120STim J. Robbins lens[coloff] - t->len[coloff] + 2, L" "); 2705480f120STim J. Robbins (void)wprintf(L"%ls\n", t->list[coloff]); 2710da30e9aSPeter Wemm } 2720da30e9aSPeter Wemm } 2730da30e9aSPeter Wemm 2740da30e9aSPeter Wemm #define DEFNUM 1000 2750da30e9aSPeter Wemm #define MAXLINELEN (LINE_MAX + 1) 2760da30e9aSPeter Wemm 277316b87cbSEd Schouten static void 278823ab23fSDavid Malone input(FILE *fp) 2790da30e9aSPeter Wemm { 2800da30e9aSPeter Wemm static int maxentry; 2810da30e9aSPeter Wemm int len; 2825480f120STim J. Robbins wchar_t *p, buf[MAXLINELEN]; 2830da30e9aSPeter Wemm 2840da30e9aSPeter Wemm if (!list) 2855480f120STim J. Robbins if ((list = calloc((maxentry = DEFNUM), sizeof(*list))) == 286d54a8ce7SDavid E. O'Brien NULL) 28718463c77SKevin Lo err(1, NULL); 2885480f120STim J. Robbins while (fgetws(buf, MAXLINELEN, fp)) { 2895480f120STim J. Robbins for (p = buf; *p && iswspace(*p); ++p); 2900da30e9aSPeter Wemm if (!*p) 2910da30e9aSPeter Wemm continue; 2925480f120STim J. Robbins if (!(p = wcschr(p, L'\n'))) { 2930da30e9aSPeter Wemm warnx("line too long"); 2940da30e9aSPeter Wemm eval = 1; 2950da30e9aSPeter Wemm continue; 2960da30e9aSPeter Wemm } 2975480f120STim J. Robbins *p = L'\0'; 2985480f120STim J. Robbins len = width(buf); 2990da30e9aSPeter Wemm if (maxlength < len) 3000da30e9aSPeter Wemm maxlength = len; 3010da30e9aSPeter Wemm if (entries == maxentry) { 3020da30e9aSPeter Wemm maxentry += DEFNUM; 3030da30e9aSPeter Wemm if (!(list = realloc(list, 3045480f120STim J. Robbins (u_int)maxentry * sizeof(*list)))) 3050da30e9aSPeter Wemm err(1, NULL); 3060da30e9aSPeter Wemm } 3075480f120STim J. Robbins list[entries] = malloc((wcslen(buf) + 1) * sizeof(wchar_t)); 3085480f120STim J. Robbins if (list[entries] == NULL) 3095480f120STim J. Robbins err(1, NULL); 3105480f120STim J. Robbins wcscpy(list[entries], buf); 3115480f120STim J. Robbins entries++; 3120da30e9aSPeter Wemm } 3130da30e9aSPeter Wemm } 3140da30e9aSPeter Wemm 3155480f120STim J. Robbins /* Like wcswidth(), but ignores non-printing characters. */ 316316b87cbSEd Schouten static int 3175480f120STim J. Robbins width(const wchar_t *wcs) 3185480f120STim J. Robbins { 3195480f120STim J. Robbins int w, cw; 3205480f120STim J. Robbins 3215480f120STim J. Robbins for (w = 0; *wcs != L'\0'; wcs++) 3225480f120STim J. Robbins if ((cw = wcwidth(*wcs)) > 0) 3235480f120STim J. Robbins w += cw; 3245480f120STim J. Robbins return (w); 3255480f120STim J. Robbins } 3265480f120STim J. Robbins 327316b87cbSEd Schouten static void 328823ab23fSDavid Malone usage(void) 3290da30e9aSPeter Wemm { 3300da30e9aSPeter Wemm 3310da30e9aSPeter Wemm (void)fprintf(stderr, 3323b5ec5aaSPhilippe Charnier "usage: column [-tx] [-c columns] [-s sep] [file ...]\n"); 3330da30e9aSPeter Wemm exit(1); 3340da30e9aSPeter Wemm } 335