1*8a16b7a1SPedro F. Giffuni /*- 2*8a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 3*8a16b7a1SPedro F. Giffuni * 49b50d902SRodney W. Grimes * Copyright (c) 1980, 1993 59b50d902SRodney W. Grimes * The Regents of the University of California. All rights reserved. 69b50d902SRodney W. Grimes * 79b50d902SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 89b50d902SRodney W. Grimes * modification, are permitted provided that the following conditions 99b50d902SRodney W. Grimes * are met: 109b50d902SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 119b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 129b50d902SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 139b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 149b50d902SRodney W. Grimes * documentation and/or other materials provided with the distribution. 15fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 169b50d902SRodney W. Grimes * may be used to endorse or promote products derived from this software 179b50d902SRodney W. Grimes * without specific prior written permission. 189b50d902SRodney W. Grimes * 199b50d902SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 209b50d902SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 219b50d902SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 229b50d902SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 239b50d902SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 249b50d902SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 259b50d902SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 269b50d902SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 279b50d902SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 289b50d902SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 299b50d902SRodney W. Grimes * SUCH DAMAGE. 309b50d902SRodney W. Grimes */ 319b50d902SRodney W. Grimes 329b50d902SRodney W. Grimes #ifndef lint 33fa146c53SArchie Cobbs static const char copyright[] = 349b50d902SRodney W. Grimes "@(#) Copyright (c) 1980, 1993\n\ 359b50d902SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 369b50d902SRodney W. Grimes #endif /* not lint */ 379b50d902SRodney W. Grimes 389b50d902SRodney W. Grimes #ifndef lint 39ca156092SPhilippe Charnier #if 0 409b50d902SRodney W. Grimes static char sccsid[] = "@(#)expand.c 8.1 (Berkeley) 6/9/93"; 41a2995dd0SPhilippe Charnier #endif 429b50d902SRodney W. Grimes #endif /* not lint */ 43e026a48cSDavid E. O'Brien #include <sys/cdefs.h> 44e026a48cSDavid E. O'Brien __FBSDID("$FreeBSD$"); 459b50d902SRodney W. Grimes 46ca156092SPhilippe Charnier #include <ctype.h> 47a2995dd0SPhilippe Charnier #include <err.h> 48ec85e6a0STim J. Robbins #include <locale.h> 499b50d902SRodney W. Grimes #include <stdio.h> 507a19d1bbSDima Dorfman #include <stdlib.h> 51ca156092SPhilippe Charnier #include <unistd.h> 52e545e3c5STim J. Robbins #include <wchar.h> 53821df508SXin LI #include <wctype.h> 54ca156092SPhilippe Charnier 559b50d902SRodney W. Grimes /* 569b50d902SRodney W. Grimes * expand - expand tabs to equivalent spaces 579b50d902SRodney W. Grimes */ 58cb230716SEd Schouten static int nstops; 59cb230716SEd Schouten static int tabstops[100]; 609b50d902SRodney W. Grimes 61f1bb2cd2SWarner Losh static void getstops(char *); 62f1bb2cd2SWarner Losh static void usage(void); 63ca156092SPhilippe Charnier 64ca156092SPhilippe Charnier int 65f4ac32deSDavid Malone main(int argc, char *argv[]) 669b50d902SRodney W. Grimes { 67e545e3c5STim J. Robbins const char *curfile; 68e545e3c5STim J. Robbins wint_t wc; 69f4ac32deSDavid Malone int c, column; 70f4ac32deSDavid Malone int n; 715069e271STim J. Robbins int rval; 72e545e3c5STim J. Robbins int width; 739b50d902SRodney W. Grimes 74ec85e6a0STim J. Robbins setlocale(LC_CTYPE, ""); 75ec85e6a0STim J. Robbins 76ca156092SPhilippe Charnier /* handle obsolete syntax */ 77ec85e6a0STim J. Robbins while (argc > 1 && argv[1][0] == '-' && 78ec85e6a0STim J. Robbins isdigit((unsigned char)argv[1][1])) { 79ca156092SPhilippe Charnier getstops(&argv[1][1]); 80ca156092SPhilippe Charnier argc--; argv++; 819b50d902SRodney W. Grimes } 82ca156092SPhilippe Charnier 83ca156092SPhilippe Charnier while ((c = getopt (argc, argv, "t:")) != -1) { 84ca156092SPhilippe Charnier switch (c) { 85ca156092SPhilippe Charnier case 't': 86ca156092SPhilippe Charnier getstops(optarg); 87ca156092SPhilippe Charnier break; 88ca156092SPhilippe Charnier case '?': 89ca156092SPhilippe Charnier default: 90ca156092SPhilippe Charnier usage(); 91ca156092SPhilippe Charnier /* NOTREACHED */ 92ca156092SPhilippe Charnier } 93ca156092SPhilippe Charnier } 94ca156092SPhilippe Charnier argc -= optind; 95ca156092SPhilippe Charnier argv += optind; 96ca156092SPhilippe Charnier 975069e271STim J. Robbins rval = 0; 98ca156092SPhilippe Charnier do { 999b50d902SRodney W. Grimes if (argc > 0) { 1005069e271STim J. Robbins if (freopen(argv[0], "r", stdin) == NULL) { 1015069e271STim J. Robbins warn("%s", argv[0]); 1025069e271STim J. Robbins rval = 1; 1035069e271STim J. Robbins argc--, argv++; 1045069e271STim J. Robbins continue; 1055069e271STim J. Robbins } 106e545e3c5STim J. Robbins curfile = argv[0]; 1079b50d902SRodney W. Grimes argc--, argv++; 108e545e3c5STim J. Robbins } else 109e545e3c5STim J. Robbins curfile = "stdin"; 1109b50d902SRodney W. Grimes column = 0; 111e545e3c5STim J. Robbins while ((wc = getwchar()) != WEOF) { 112e545e3c5STim J. Robbins switch (wc) { 1139b50d902SRodney W. Grimes case '\t': 1149b50d902SRodney W. Grimes if (nstops == 0) { 1159b50d902SRodney W. Grimes do { 116e545e3c5STim J. Robbins putwchar(' '); 1179b50d902SRodney W. Grimes column++; 1189b50d902SRodney W. Grimes } while (column & 07); 1199b50d902SRodney W. Grimes continue; 1209b50d902SRodney W. Grimes } 1219b50d902SRodney W. Grimes if (nstops == 1) { 1229b50d902SRodney W. Grimes do { 123e545e3c5STim J. Robbins putwchar(' '); 1249b50d902SRodney W. Grimes column++; 1259b50d902SRodney W. Grimes } while (((column - 1) % tabstops[0]) != (tabstops[0] - 1)); 1269b50d902SRodney W. Grimes continue; 1279b50d902SRodney W. Grimes } 1289b50d902SRodney W. Grimes for (n = 0; n < nstops; n++) 1299b50d902SRodney W. Grimes if (tabstops[n] > column) 1309b50d902SRodney W. Grimes break; 1319b50d902SRodney W. Grimes if (n == nstops) { 132e545e3c5STim J. Robbins putwchar(' '); 1339b50d902SRodney W. Grimes column++; 1349b50d902SRodney W. Grimes continue; 1359b50d902SRodney W. Grimes } 1369b50d902SRodney W. Grimes while (column < tabstops[n]) { 137e545e3c5STim J. Robbins putwchar(' '); 1389b50d902SRodney W. Grimes column++; 1399b50d902SRodney W. Grimes } 1409b50d902SRodney W. Grimes continue; 1419b50d902SRodney W. Grimes 1429b50d902SRodney W. Grimes case '\b': 1439b50d902SRodney W. Grimes if (column) 1449b50d902SRodney W. Grimes column--; 145e545e3c5STim J. Robbins putwchar('\b'); 1469b50d902SRodney W. Grimes continue; 1479b50d902SRodney W. Grimes 1489b50d902SRodney W. Grimes default: 149e545e3c5STim J. Robbins putwchar(wc); 150e545e3c5STim J. Robbins if ((width = wcwidth(wc)) > 0) 151e545e3c5STim J. Robbins column += width; 1529b50d902SRodney W. Grimes continue; 1539b50d902SRodney W. Grimes 1549b50d902SRodney W. Grimes case '\n': 155e545e3c5STim J. Robbins putwchar(wc); 1569b50d902SRodney W. Grimes column = 0; 1579b50d902SRodney W. Grimes continue; 1589b50d902SRodney W. Grimes } 1599b50d902SRodney W. Grimes } 160e545e3c5STim J. Robbins if (ferror(stdin)) { 161e545e3c5STim J. Robbins warn("%s", curfile); 162e545e3c5STim J. Robbins rval = 1; 163e545e3c5STim J. Robbins } 1649b50d902SRodney W. Grimes } while (argc > 0); 1655069e271STim J. Robbins exit(rval); 1669b50d902SRodney W. Grimes } 1679b50d902SRodney W. Grimes 168ca156092SPhilippe Charnier static void 169f4ac32deSDavid Malone getstops(char *cp) 1709b50d902SRodney W. Grimes { 171f4ac32deSDavid Malone int i; 1729b50d902SRodney W. Grimes 1739b50d902SRodney W. Grimes nstops = 0; 1749b50d902SRodney W. Grimes for (;;) { 1759b50d902SRodney W. Grimes i = 0; 1769b50d902SRodney W. Grimes while (*cp >= '0' && *cp <= '9') 1779b50d902SRodney W. Grimes i = i * 10 + *cp++ - '0'; 17891dd86ffSDima Dorfman if (i <= 0) 179a2995dd0SPhilippe Charnier errx(1, "bad tab stop spec"); 1809b50d902SRodney W. Grimes if (nstops > 0 && i <= tabstops[nstops-1]) 181a2995dd0SPhilippe Charnier errx(1, "bad tab stop spec"); 182a6150e80SRuslan Ermilov if (nstops == sizeof(tabstops) / sizeof(*tabstops)) 183a6150e80SRuslan Ermilov errx(1, "too many tab stops"); 1849b50d902SRodney W. Grimes tabstops[nstops++] = i; 1859b50d902SRodney W. Grimes if (*cp == 0) 1869b50d902SRodney W. Grimes break; 187ec85e6a0STim J. Robbins if (*cp != ',' && !isblank((unsigned char)*cp)) 188a2995dd0SPhilippe Charnier errx(1, "bad tab stop spec"); 189ca156092SPhilippe Charnier cp++; 1909b50d902SRodney W. Grimes } 1919b50d902SRodney W. Grimes } 192ca156092SPhilippe Charnier 193ca156092SPhilippe Charnier static void 194f4ac32deSDavid Malone usage(void) 195ca156092SPhilippe Charnier { 196ca156092SPhilippe Charnier (void)fprintf (stderr, "usage: expand [-t tablist] [file ...]\n"); 197ca156092SPhilippe Charnier exit(1); 198ca156092SPhilippe Charnier } 199