expand.c revision 131051
1234285Sdim/*
2234285Sdim * Copyright (c) 1980, 1993
3234285Sdim *	The Regents of the University of California.  All rights reserved.
4234285Sdim *
5234285Sdim * Redistribution and use in source and binary forms, with or without
6234285Sdim * modification, are permitted provided that the following conditions
7234285Sdim * are met:
8234285Sdim * 1. Redistributions of source code must retain the above copyright
9234285Sdim *    notice, this list of conditions and the following disclaimer.
10263508Sdim * 2. Redistributions in binary form must reproduce the above copyright
11263508Sdim *    notice, this list of conditions and the following disclaimer in the
12263508Sdim *    documentation and/or other materials provided with the distribution.
13263508Sdim * 3. All advertising materials mentioning features or use of this software
14263508Sdim *    must display the following acknowledgement:
15263508Sdim *	This product includes software developed by the University of
16263508Sdim *	California, Berkeley and its contributors.
17263508Sdim * 4. Neither the name of the University nor the names of its contributors
18263508Sdim *    may be used to endorse or promote products derived from this software
19263508Sdim *    without specific prior written permission.
20263508Sdim *
21263508Sdim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22263508Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23263508Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24263508Sdim * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25263508Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26263508Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27263508Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28263508Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29263508Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30263508Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31263508Sdim * SUCH DAMAGE.
32263508Sdim */
33263508Sdim
34263508Sdim#ifndef lint
35263508Sdimstatic const char copyright[] =
36263508Sdim"@(#) Copyright (c) 1980, 1993\n\
37263508Sdim	The Regents of the University of California.  All rights reserved.\n";
38263508Sdim#endif /* not lint */
39263508Sdim
40263508Sdim#ifndef lint
41263508Sdim#if 0
42263508Sdimstatic char sccsid[] = "@(#)expand.c	8.1 (Berkeley) 6/9/93";
43263508Sdim#endif
44263508Sdim#endif /* not lint */
45263508Sdim#include <sys/cdefs.h>
46263508Sdim__FBSDID("$FreeBSD: head/usr.bin/expand/expand.c 131051 2004-06-24 13:42:26Z tjr $");
47263508Sdim
48263508Sdim#include <ctype.h>
49263508Sdim#include <err.h>
50263508Sdim#include <locale.h>
51263508Sdim#include <stdio.h>
52234285Sdim#include <stdlib.h>
53234285Sdim#include <unistd.h>
54234285Sdim#include <wchar.h>
55234285Sdim#include <wctype.h>
56234285Sdim
57234285Sdim/*
58234285Sdim * expand - expand tabs to equivalent spaces
59234285Sdim */
60234285Sdimint	nstops;
61234285Sdimint	tabstops[100];
62263508Sdim
63263508Sdimstatic void getstops(char *);
64263508Sdimstatic void usage(void);
65263508Sdim
66263508Sdimint
67263508Sdimmain(int argc, char *argv[])
68263508Sdim{
69263508Sdim	const char *curfile;
70263508Sdim	wint_t wc;
71263508Sdim	int c, column;
72263508Sdim	int n;
73263508Sdim	int rval;
74263508Sdim	int width;
75234285Sdim
76234285Sdim	setlocale(LC_CTYPE, "");
77249423Sdim
78249423Sdim	/* handle obsolete syntax */
79234285Sdim	while (argc > 1 && argv[1][0] == '-' &&
80234285Sdim	    isdigit((unsigned char)argv[1][1])) {
81243830Sdim		getstops(&argv[1][1]);
82243830Sdim		argc--; argv++;
83234285Sdim	}
84234285Sdim
85234285Sdim	while ((c = getopt (argc, argv, "t:")) != -1) {
86243830Sdim		switch (c) {
87243830Sdim		case 't':
88243830Sdim			getstops(optarg);
89234285Sdim			break;
90234285Sdim		case '?':
91234285Sdim		default:
92234285Sdim			usage();
93239462Sdim			/* NOTREACHED */
94234285Sdim		}
95249423Sdim	}
96234285Sdim	argc -= optind;
97234285Sdim	argv += optind;
98234285Sdim
99234285Sdim	rval = 0;
100234285Sdim	do {
101234285Sdim		if (argc > 0) {
102234285Sdim			if (freopen(argv[0], "r", stdin) == NULL) {
103234285Sdim				warn("%s", argv[0]);
104234285Sdim				rval = 1;
105234285Sdim				argc--, argv++;
106234285Sdim				continue;
107239462Sdim			}
108239462Sdim			curfile = argv[0];
109239462Sdim			argc--, argv++;
110239462Sdim		} else
111234285Sdim			curfile = "stdin";
112234285Sdim		column = 0;
113234285Sdim		while ((wc = getwchar()) != WEOF) {
114234285Sdim			switch (wc) {
115234285Sdim			case '\t':
116234285Sdim				if (nstops == 0) {
117234285Sdim					do {
118234285Sdim						putwchar(' ');
119234285Sdim						column++;
120234285Sdim					} while (column & 07);
121234285Sdim					continue;
122234285Sdim				}
123234285Sdim				if (nstops == 1) {
124234285Sdim					do {
125234285Sdim						putwchar(' ');
126234285Sdim						column++;
127234285Sdim					} while (((column - 1) % tabstops[0]) != (tabstops[0] - 1));
128234285Sdim					continue;
129234285Sdim				}
130234285Sdim				for (n = 0; n < nstops; n++)
131234285Sdim					if (tabstops[n] > column)
132234285Sdim						break;
133234285Sdim				if (n == nstops) {
134234285Sdim					putwchar(' ');
135234285Sdim					column++;
136234285Sdim					continue;
137234285Sdim				}
138234285Sdim				while (column < tabstops[n]) {
139234285Sdim					putwchar(' ');
140234285Sdim					column++;
141234285Sdim				}
142234285Sdim				continue;
143243830Sdim
144243830Sdim			case '\b':
145263508Sdim				if (column)
146263508Sdim					column--;
147263508Sdim				putwchar('\b');
148263508Sdim				continue;
149263508Sdim
150263508Sdim			default:
151263508Sdim				putwchar(wc);
152263508Sdim				if ((width = wcwidth(wc)) > 0)
153263508Sdim					column += width;
154263508Sdim				continue;
155263508Sdim
156263508Sdim			case '\n':
157263508Sdim				putwchar(wc);
158263508Sdim				column = 0;
159263508Sdim				continue;
160263508Sdim			}
161243830Sdim		}
162243830Sdim		if (ferror(stdin)) {
163263508Sdim			warn("%s", curfile);
164263508Sdim			rval = 1;
165263508Sdim		}
166243830Sdim	} while (argc > 0);
167263508Sdim	exit(rval);
168243830Sdim}
169243830Sdim
170243830Sdimstatic void
171263508Sdimgetstops(char *cp)
172263508Sdim{
173263508Sdim	int i;
174263508Sdim
175263508Sdim	nstops = 0;
176263508Sdim	for (;;) {
177263508Sdim		i = 0;
178263508Sdim		while (*cp >= '0' && *cp <= '9')
179263508Sdim			i = i * 10 + *cp++ - '0';
180243830Sdim		if (i <= 0)
181243830Sdim			errx(1, "bad tab stop spec");
182243830Sdim		if (nstops > 0 && i <= tabstops[nstops-1])
183243830Sdim			errx(1, "bad tab stop spec");
184243830Sdim		if (nstops == sizeof(tabstops) / sizeof(*tabstops))
185243830Sdim			errx(1, "too many tab stops");
186243830Sdim		tabstops[nstops++] = i;
187243830Sdim		if (*cp == 0)
188243830Sdim			break;
189243830Sdim		if (*cp != ',' && !isblank((unsigned char)*cp))
190243830Sdim			errx(1, "bad tab stop spec");
191243830Sdim		cp++;
192249423Sdim	}
193249423Sdim}
194249423Sdim
195243830Sdimstatic void
196243830Sdimusage(void)
197243830Sdim{
198243830Sdim	(void)fprintf (stderr, "usage: expand [-t tablist] [file ...]\n");
199243830Sdim	exit(1);
200243830Sdim}
201243830Sdim