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