1*39bbc68aSsevan /* $NetBSD: expand.c,v 1.14 2016/09/05 00:40:28 sevan Exp $ */
271bb6ddaSjtc
361f28255Scgd /*
471bb6ddaSjtc * Copyright (c) 1980, 1993
571bb6ddaSjtc * The Regents of the University of California. All rights reserved.
661f28255Scgd *
761f28255Scgd * Redistribution and use in source and binary forms, with or without
861f28255Scgd * modification, are permitted provided that the following conditions
961f28255Scgd * are met:
1061f28255Scgd * 1. Redistributions of source code must retain the above copyright
1161f28255Scgd * notice, this list of conditions and the following disclaimer.
1261f28255Scgd * 2. Redistributions in binary form must reproduce the above copyright
1361f28255Scgd * notice, this list of conditions and the following disclaimer in the
1461f28255Scgd * documentation and/or other materials provided with the distribution.
1589aaa1bbSagc * 3. Neither the name of the University nor the names of its contributors
1661f28255Scgd * may be used to endorse or promote products derived from this software
1761f28255Scgd * without specific prior written permission.
1861f28255Scgd *
1961f28255Scgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2061f28255Scgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2161f28255Scgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2261f28255Scgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2361f28255Scgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2461f28255Scgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2561f28255Scgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2661f28255Scgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2761f28255Scgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2861f28255Scgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2961f28255Scgd * SUCH DAMAGE.
3061f28255Scgd */
3161f28255Scgd
3295737feeSlukem #include <sys/cdefs.h>
3361f28255Scgd #ifndef lint
3498e5374cSlukem __COPYRIGHT("@(#) Copyright (c) 1980, 1993\
3598e5374cSlukem The Regents of the University of California. All rights reserved.");
3661f28255Scgd #endif /* not lint */
3761f28255Scgd
3861f28255Scgd #ifndef lint
3971bb6ddaSjtc #if 0
4071bb6ddaSjtc static char sccsid[] = "@(#)expand.c 8.1 (Berkeley) 6/9/93";
4171bb6ddaSjtc #endif
42*39bbc68aSsevan __RCSID("$NetBSD: expand.c,v 1.14 2016/09/05 00:40:28 sevan Exp $");
4361f28255Scgd #endif /* not lint */
4461f28255Scgd
4561f28255Scgd #include <stdio.h>
46fe201006Sjtc #include <stdlib.h>
47fe201006Sjtc #include <ctype.h>
482ddbb97fSjtc #include <unistd.h>
491c7109cbSchristos #include <err.h>
50fe201006Sjtc
5161f28255Scgd /*
5261f28255Scgd * expand - expand tabs to equivalent spaces
5361f28255Scgd */
541c7109cbSchristos size_t nstops;
551c7109cbSchristos size_t tabstops[100];
5661f28255Scgd
571c7109cbSchristos static void getstops(const char *);
588b0f9554Sperry static void usage(void) __dead;
59fe201006Sjtc
60fe201006Sjtc int
main(int argc,char * argv[])611c7109cbSchristos main(int argc, char *argv[])
6261f28255Scgd {
631c7109cbSchristos int c;
641c7109cbSchristos size_t n, column;
651c7109cbSchristos
661c7109cbSchristos setprogname(argv[0]);
6761f28255Scgd
68fe201006Sjtc /* handle obsolete syntax */
6923a9f6e8Skleink while (argc > 1 &&
7023a9f6e8Skleink argv[1][0] == '-' && isdigit((unsigned char)argv[1][1])) {
71fe201006Sjtc getstops(&argv[1][1]);
72fe201006Sjtc argc--; argv++;
7361f28255Scgd }
74fe201006Sjtc
75fe201006Sjtc while ((c = getopt (argc, argv, "t:")) != -1) {
76fe201006Sjtc switch (c) {
77fe201006Sjtc case 't':
78fe201006Sjtc getstops(optarg);
79fe201006Sjtc break;
80fe201006Sjtc case '?':
81fe201006Sjtc default:
82fe201006Sjtc usage();
83fe201006Sjtc /* NOTREACHED */
84fe201006Sjtc }
85fe201006Sjtc }
86fe201006Sjtc argc -= optind;
87fe201006Sjtc argv += optind;
88fe201006Sjtc
89fe201006Sjtc do {
9061f28255Scgd if (argc > 0) {
911c7109cbSchristos if (freopen(argv[0], "r", stdin) == NULL)
921c7109cbSchristos err(EXIT_FAILURE, "Cannot open `%s'", argv[0]);
9361f28255Scgd argc--, argv++;
9461f28255Scgd }
9561f28255Scgd column = 0;
96fe201006Sjtc while ((c = getchar()) != EOF) {
9761f28255Scgd switch (c) {
9861f28255Scgd case '\t':
9961f28255Scgd if (nstops == 0) {
10061f28255Scgd do {
10161f28255Scgd putchar(' ');
10261f28255Scgd column++;
10361f28255Scgd } while (column & 07);
10461f28255Scgd continue;
10561f28255Scgd }
10661f28255Scgd if (nstops == 1) {
10761f28255Scgd do {
10861f28255Scgd putchar(' ');
10961f28255Scgd column++;
1101c7109cbSchristos } while (((column - 1) % tabstops[0])
1111c7109cbSchristos != (tabstops[0] - 1));
11261f28255Scgd continue;
11361f28255Scgd }
11461f28255Scgd for (n = 0; n < nstops; n++)
11561f28255Scgd if (tabstops[n] > column)
11661f28255Scgd break;
11761f28255Scgd if (n == nstops) {
11861f28255Scgd putchar(' ');
11961f28255Scgd column++;
12061f28255Scgd continue;
12161f28255Scgd }
12261f28255Scgd while (column < tabstops[n]) {
12361f28255Scgd putchar(' ');
12461f28255Scgd column++;
12561f28255Scgd }
12661f28255Scgd continue;
12761f28255Scgd
12861f28255Scgd case '\b':
12961f28255Scgd if (column)
13061f28255Scgd column--;
13161f28255Scgd putchar('\b');
13261f28255Scgd continue;
13361f28255Scgd
13461f28255Scgd default:
13561f28255Scgd putchar(c);
13661f28255Scgd column++;
13761f28255Scgd continue;
13861f28255Scgd
13961f28255Scgd case '\n':
14061f28255Scgd putchar(c);
14161f28255Scgd column = 0;
14261f28255Scgd continue;
14361f28255Scgd }
14461f28255Scgd }
14561f28255Scgd } while (argc > 0);
1461c7109cbSchristos return EXIT_SUCCESS;
14761f28255Scgd }
14861f28255Scgd
149fe201006Sjtc static void
getstops(const char * spec)1501c7109cbSchristos getstops(const char *spec)
15161f28255Scgd {
15295737feeSlukem int i;
1531c7109cbSchristos const char *cp = spec;
15461f28255Scgd
15561f28255Scgd nstops = 0;
15661f28255Scgd for (;;) {
15761f28255Scgd i = 0;
15861f28255Scgd while (*cp >= '0' && *cp <= '9')
15961f28255Scgd i = i * 10 + *cp++ - '0';
1601c7109cbSchristos if (i <= 0 || i > 256)
1611c7109cbSchristos errx(EXIT_FAILURE, "Too large tab stop spec `%d'", i);
162bfbbea0bSlukem if (nstops > 0 && (size_t)i <= tabstops[nstops-1])
1631c7109cbSchristos errx(EXIT_FAILURE, "Out of order tabstop spec `%d'", i);
1641c7109cbSchristos if (nstops == sizeof(tabstops) / sizeof(tabstops[0]) - 1)
1651c7109cbSchristos errx(EXIT_FAILURE, "Too many tabstops");
16661f28255Scgd tabstops[nstops++] = i;
1671c7109cbSchristos if (*cp == '\0')
16861f28255Scgd break;
169fe201006Sjtc if (*cp != ',' && *cp != ' ')
1701c7109cbSchristos errx(EXIT_FAILURE, "Illegal tab stop spec `%s'", spec);
171fe201006Sjtc cp++;
17261f28255Scgd }
17361f28255Scgd }
174fe201006Sjtc
175fe201006Sjtc static void
usage(void)1761c7109cbSchristos usage(void)
177fe201006Sjtc {
17823a9f6e8Skleink
1791c7109cbSchristos (void)fprintf(stderr, "Usage: %s [-t tablist] [file ...]\n",
1801c7109cbSchristos getprogname());
18123a9f6e8Skleink exit(EXIT_FAILURE);
182fe201006Sjtc }
183