xref: /minix3/usr.bin/expand/expand.c (revision 563dd2c8f457d86bc480c9174410214b1318927c)
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