1*563dd2c8SLionel Sambuc /* $NetBSD: expand.c,v 1.13 2009/04/12 02:51:36 lukem Exp $ */
2*563dd2c8SLionel Sambuc
3*563dd2c8SLionel Sambuc /*
4*563dd2c8SLionel Sambuc * Copyright (c) 1980, 1993
5*563dd2c8SLionel Sambuc * The Regents of the University of California. All rights reserved.
6*563dd2c8SLionel Sambuc *
7*563dd2c8SLionel Sambuc * Redistribution and use in source and binary forms, with or without
8*563dd2c8SLionel Sambuc * modification, are permitted provided that the following conditions
9*563dd2c8SLionel Sambuc * are met:
10*563dd2c8SLionel Sambuc * 1. Redistributions of source code must retain the above copyright
11*563dd2c8SLionel Sambuc * notice, this list of conditions and the following disclaimer.
12*563dd2c8SLionel Sambuc * 2. Redistributions in binary form must reproduce the above copyright
13*563dd2c8SLionel Sambuc * notice, this list of conditions and the following disclaimer in the
14*563dd2c8SLionel Sambuc * documentation and/or other materials provided with the distribution.
15*563dd2c8SLionel Sambuc * 3. Neither the name of the University nor the names of its contributors
16*563dd2c8SLionel Sambuc * may be used to endorse or promote products derived from this software
17*563dd2c8SLionel Sambuc * without specific prior written permission.
18*563dd2c8SLionel Sambuc *
19*563dd2c8SLionel Sambuc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20*563dd2c8SLionel Sambuc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21*563dd2c8SLionel Sambuc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22*563dd2c8SLionel Sambuc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23*563dd2c8SLionel Sambuc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24*563dd2c8SLionel Sambuc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25*563dd2c8SLionel Sambuc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26*563dd2c8SLionel Sambuc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27*563dd2c8SLionel Sambuc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28*563dd2c8SLionel Sambuc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29*563dd2c8SLionel Sambuc * SUCH DAMAGE.
30*563dd2c8SLionel Sambuc */
31*563dd2c8SLionel Sambuc
32*563dd2c8SLionel Sambuc #include <sys/cdefs.h>
33*563dd2c8SLionel Sambuc #ifndef lint
34*563dd2c8SLionel Sambuc __COPYRIGHT("@(#) Copyright (c) 1980, 1993\
35*563dd2c8SLionel Sambuc The Regents of the University of California. All rights reserved.");
36*563dd2c8SLionel Sambuc #endif /* not lint */
37*563dd2c8SLionel Sambuc
38*563dd2c8SLionel Sambuc #ifndef lint
39*563dd2c8SLionel Sambuc #if 0
40*563dd2c8SLionel Sambuc static char sccsid[] = "@(#)expand.c 8.1 (Berkeley) 6/9/93";
41*563dd2c8SLionel Sambuc #endif
42*563dd2c8SLionel Sambuc __RCSID("$NetBSD: expand.c,v 1.13 2009/04/12 02:51:36 lukem Exp $");
43*563dd2c8SLionel Sambuc #endif /* not lint */
44*563dd2c8SLionel Sambuc
45*563dd2c8SLionel Sambuc #include <stdio.h>
46*563dd2c8SLionel Sambuc #include <stdlib.h>
47*563dd2c8SLionel Sambuc #include <ctype.h>
48*563dd2c8SLionel Sambuc #include <unistd.h>
49*563dd2c8SLionel Sambuc #include <err.h>
50*563dd2c8SLionel Sambuc
51*563dd2c8SLionel Sambuc /*
52*563dd2c8SLionel Sambuc * expand - expand tabs to equivalent spaces
53*563dd2c8SLionel Sambuc */
54*563dd2c8SLionel Sambuc size_t nstops;
55*563dd2c8SLionel Sambuc size_t tabstops[100];
56*563dd2c8SLionel Sambuc
57*563dd2c8SLionel Sambuc static void getstops(const char *);
58*563dd2c8SLionel Sambuc int main(int, char **);
59*563dd2c8SLionel Sambuc static void usage(void) __dead;
60*563dd2c8SLionel Sambuc
61*563dd2c8SLionel Sambuc int
main(int argc,char * argv[])62*563dd2c8SLionel Sambuc main(int argc, char *argv[])
63*563dd2c8SLionel Sambuc {
64*563dd2c8SLionel Sambuc int c;
65*563dd2c8SLionel Sambuc size_t n, column;
66*563dd2c8SLionel Sambuc
67*563dd2c8SLionel Sambuc setprogname(argv[0]);
68*563dd2c8SLionel Sambuc
69*563dd2c8SLionel Sambuc /* handle obsolete syntax */
70*563dd2c8SLionel Sambuc while (argc > 1 &&
71*563dd2c8SLionel Sambuc argv[1][0] == '-' && isdigit((unsigned char)argv[1][1])) {
72*563dd2c8SLionel Sambuc getstops(&argv[1][1]);
73*563dd2c8SLionel Sambuc argc--; argv++;
74*563dd2c8SLionel Sambuc }
75*563dd2c8SLionel Sambuc
76*563dd2c8SLionel Sambuc while ((c = getopt (argc, argv, "t:")) != -1) {
77*563dd2c8SLionel Sambuc switch (c) {
78*563dd2c8SLionel Sambuc case 't':
79*563dd2c8SLionel Sambuc getstops(optarg);
80*563dd2c8SLionel Sambuc break;
81*563dd2c8SLionel Sambuc case '?':
82*563dd2c8SLionel Sambuc default:
83*563dd2c8SLionel Sambuc usage();
84*563dd2c8SLionel Sambuc /* NOTREACHED */
85*563dd2c8SLionel Sambuc }
86*563dd2c8SLionel Sambuc }
87*563dd2c8SLionel Sambuc argc -= optind;
88*563dd2c8SLionel Sambuc argv += optind;
89*563dd2c8SLionel Sambuc
90*563dd2c8SLionel Sambuc do {
91*563dd2c8SLionel Sambuc if (argc > 0) {
92*563dd2c8SLionel Sambuc if (freopen(argv[0], "r", stdin) == NULL)
93*563dd2c8SLionel Sambuc err(EXIT_FAILURE, "Cannot open `%s'", argv[0]);
94*563dd2c8SLionel Sambuc argc--, argv++;
95*563dd2c8SLionel Sambuc }
96*563dd2c8SLionel Sambuc column = 0;
97*563dd2c8SLionel Sambuc while ((c = getchar()) != EOF) {
98*563dd2c8SLionel Sambuc switch (c) {
99*563dd2c8SLionel Sambuc case '\t':
100*563dd2c8SLionel Sambuc if (nstops == 0) {
101*563dd2c8SLionel Sambuc do {
102*563dd2c8SLionel Sambuc putchar(' ');
103*563dd2c8SLionel Sambuc column++;
104*563dd2c8SLionel Sambuc } while (column & 07);
105*563dd2c8SLionel Sambuc continue;
106*563dd2c8SLionel Sambuc }
107*563dd2c8SLionel Sambuc if (nstops == 1) {
108*563dd2c8SLionel Sambuc do {
109*563dd2c8SLionel Sambuc putchar(' ');
110*563dd2c8SLionel Sambuc column++;
111*563dd2c8SLionel Sambuc } while (((column - 1) % tabstops[0])
112*563dd2c8SLionel Sambuc != (tabstops[0] - 1));
113*563dd2c8SLionel Sambuc continue;
114*563dd2c8SLionel Sambuc }
115*563dd2c8SLionel Sambuc for (n = 0; n < nstops; n++)
116*563dd2c8SLionel Sambuc if (tabstops[n] > column)
117*563dd2c8SLionel Sambuc break;
118*563dd2c8SLionel Sambuc if (n == nstops) {
119*563dd2c8SLionel Sambuc putchar(' ');
120*563dd2c8SLionel Sambuc column++;
121*563dd2c8SLionel Sambuc continue;
122*563dd2c8SLionel Sambuc }
123*563dd2c8SLionel Sambuc while (column < tabstops[n]) {
124*563dd2c8SLionel Sambuc putchar(' ');
125*563dd2c8SLionel Sambuc column++;
126*563dd2c8SLionel Sambuc }
127*563dd2c8SLionel Sambuc continue;
128*563dd2c8SLionel Sambuc
129*563dd2c8SLionel Sambuc case '\b':
130*563dd2c8SLionel Sambuc if (column)
131*563dd2c8SLionel Sambuc column--;
132*563dd2c8SLionel Sambuc putchar('\b');
133*563dd2c8SLionel Sambuc continue;
134*563dd2c8SLionel Sambuc
135*563dd2c8SLionel Sambuc default:
136*563dd2c8SLionel Sambuc putchar(c);
137*563dd2c8SLionel Sambuc column++;
138*563dd2c8SLionel Sambuc continue;
139*563dd2c8SLionel Sambuc
140*563dd2c8SLionel Sambuc case '\n':
141*563dd2c8SLionel Sambuc putchar(c);
142*563dd2c8SLionel Sambuc column = 0;
143*563dd2c8SLionel Sambuc continue;
144*563dd2c8SLionel Sambuc }
145*563dd2c8SLionel Sambuc }
146*563dd2c8SLionel Sambuc } while (argc > 0);
147*563dd2c8SLionel Sambuc return EXIT_SUCCESS;
148*563dd2c8SLionel Sambuc }
149*563dd2c8SLionel Sambuc
150*563dd2c8SLionel Sambuc static void
getstops(const char * spec)151*563dd2c8SLionel Sambuc getstops(const char *spec)
152*563dd2c8SLionel Sambuc {
153*563dd2c8SLionel Sambuc int i;
154*563dd2c8SLionel Sambuc const char *cp = spec;
155*563dd2c8SLionel Sambuc
156*563dd2c8SLionel Sambuc nstops = 0;
157*563dd2c8SLionel Sambuc for (;;) {
158*563dd2c8SLionel Sambuc i = 0;
159*563dd2c8SLionel Sambuc while (*cp >= '0' && *cp <= '9')
160*563dd2c8SLionel Sambuc i = i * 10 + *cp++ - '0';
161*563dd2c8SLionel Sambuc if (i <= 0 || i > 256)
162*563dd2c8SLionel Sambuc errx(EXIT_FAILURE, "Too large tab stop spec `%d'", i);
163*563dd2c8SLionel Sambuc if (nstops > 0 && (size_t)i <= tabstops[nstops-1])
164*563dd2c8SLionel Sambuc errx(EXIT_FAILURE, "Out of order tabstop spec `%d'", i);
165*563dd2c8SLionel Sambuc if (nstops == sizeof(tabstops) / sizeof(tabstops[0]) - 1)
166*563dd2c8SLionel Sambuc errx(EXIT_FAILURE, "Too many tabstops");
167*563dd2c8SLionel Sambuc tabstops[nstops++] = i;
168*563dd2c8SLionel Sambuc if (*cp == '\0')
169*563dd2c8SLionel Sambuc break;
170*563dd2c8SLionel Sambuc if (*cp != ',' && *cp != ' ')
171*563dd2c8SLionel Sambuc errx(EXIT_FAILURE, "Illegal tab stop spec `%s'", spec);
172*563dd2c8SLionel Sambuc cp++;
173*563dd2c8SLionel Sambuc }
174*563dd2c8SLionel Sambuc }
175*563dd2c8SLionel Sambuc
176*563dd2c8SLionel Sambuc static void
usage(void)177*563dd2c8SLionel Sambuc usage(void)
178*563dd2c8SLionel Sambuc {
179*563dd2c8SLionel Sambuc
180*563dd2c8SLionel Sambuc (void)fprintf(stderr, "Usage: %s [-t tablist] [file ...]\n",
181*563dd2c8SLionel Sambuc getprogname());
182*563dd2c8SLionel Sambuc exit(EXIT_FAILURE);
183*563dd2c8SLionel Sambuc }
184