1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 1989 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30 /*
31 * University Copyright- Copyright (c) 1982, 1986, 1988
32 * The Regents of the University of California
33 * All Rights Reserved
34 *
35 * University Acknowledgment- Portions of this document are derived from
36 * software developed by the University of California, Berkeley, and its
37 * contributors.
38 */
39
40 #include <stdio.h>
41 #include <libintl.h>
42 #include <locale.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <ctype.h>
46 #include <limits.h>
47 #include <wchar.h>
48
49 /*
50 * expand - expand tabs to equivalent spaces
51 */
52 static int nstops = 0;
53 static int tabstops[100];
54 static int isClocale;
55
56 static void getstops(const char *);
57 static void usage(void);
58
59 int
main(argc,argv)60 main(argc, argv)
61 int argc;
62 char *argv[];
63 {
64 static char ibuf[BUFSIZ];
65 register int c, column;
66 register int n;
67 register int i, j;
68 char *locale;
69 int flag, tflag = 0;
70 int len;
71 int p_col;
72 wchar_t wc;
73 char *p1, *p2;
74
75 (void) setlocale(LC_ALL, "");
76 locale = setlocale(LC_CTYPE, NULL);
77 isClocale = (strcmp(locale, "C") == 0);
78 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
79 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
80 #endif
81 (void) textdomain(TEXT_DOMAIN);
82
83 /*
84 * First, look for and extract any "-<number>" args then pass
85 * them to getstops().
86 */
87 for (i = 1; i < argc; i++) {
88 if (strcmp(argv[i], "--") == 0)
89 break;
90
91 if (*argv[i] != '-')
92 continue;
93 if (!isdigit(*(argv[i]+1)))
94 continue;
95
96 getstops(argv[i]+1);
97 tflag++;
98
99 /* Pull this arg from list */
100 for (j = i; j < (argc-1); j++)
101 argv[j] = argv[j+1];
102 argc--;
103 }
104
105 while ((flag = getopt(argc, argv, "t:")) != EOF) {
106 switch (flag) {
107 case 't':
108 if (tflag)
109 usage();
110
111 getstops(optarg);
112 break;
113
114 default:
115 usage();
116 break;
117 }
118 }
119
120 argc -= optind;
121 argv = &argv[optind];
122
123 do {
124 if (argc > 0) {
125 if (freopen(argv[0], "r", stdin) == NULL) {
126 perror(argv[0]);
127 exit(1);
128 /* NOTREACHED */
129 }
130 argc--;
131 argv++;
132 }
133
134 column = 0;
135 p1 = p2 = ibuf;
136 for (;;) {
137 if (p1 >= p2) {
138 p1 = ibuf;
139 if ((len = fread(p1, 1, BUFSIZ, stdin)) <= 0)
140 break;
141 p2 = p1 + len;
142 }
143
144 c = *p1++;
145 switch (c) {
146 case '\t':
147 if (nstops == 0) {
148 do {
149 (void) putchar(' ');
150 column++;
151 } while (column & 07);
152 continue;
153 }
154 if (nstops == 1) {
155 do {
156 (void) putchar(' ');
157 column++;
158 } while (
159 ((column - 1) % tabstops[0]) !=
160 (tabstops[0] - 1));
161 continue;
162 }
163 for (n = 0; n < nstops; n++)
164 if (tabstops[n] > column)
165 break;
166 if (n == nstops) {
167 (void) putchar(' ');
168 column++;
169 continue;
170 }
171 while (column < tabstops[n]) {
172 (void) putchar(' ');
173 column++;
174 }
175 continue;
176
177 case '\b':
178 if (column)
179 column--;
180 (void) putchar('\b');
181 continue;
182
183 default:
184 if (isClocale) {
185 (void) putchar(c);
186 column++;
187 continue;
188 }
189
190 if (isascii(c)) {
191 (void) putchar(c);
192 column++;
193 continue;
194 }
195
196 p1--;
197 if ((len = (p2 - p1)) <
198 (unsigned int)MB_CUR_MAX) {
199 for (n = 0; n < len; n++)
200 ibuf[n] = *p1++;
201 p1 = ibuf;
202 p2 = p1 + n;
203 if ((len = fread(p2, 1, BUFSIZ - n,
204 stdin)) > 0)
205 p2 += len;
206 }
207 if ((len = (p2 - p1)) >
208 (unsigned int)MB_CUR_MAX)
209 len = (unsigned int)MB_CUR_MAX;
210
211 if ((len = mbtowc(&wc, p1, len)) <= 0) {
212 (void) putchar(c);
213 column++;
214 p1++;
215 continue;
216 }
217
218 if ((p_col = wcwidth(wc)) < 0)
219 p_col = len;
220 p1 += len;
221 (void) putwchar(wc);
222 column += p_col;
223 continue;
224
225 case '\n':
226 (void) putchar(c);
227 column = 0;
228 continue;
229 }
230 }
231 } while (argc > 0);
232
233 return (0);
234 /* NOTREACHED */
235 }
236
237 static void
getstops(const char * cp)238 getstops(const char *cp)
239 {
240 register int i;
241
242 for (;;) {
243 i = 0;
244 while (*cp >= '0' && *cp <= '9')
245 i = i * 10 + *cp++ - '0';
246
247 if (i <= 0 || i > INT_MAX) {
248 (void) fprintf(stderr, gettext(
249 "expand: invalid tablist\n"));
250 usage();
251 }
252
253 if (nstops > 0 && i <= tabstops[nstops-1]) {
254 (void) fprintf(stderr, gettext(
255 "expand: tablist must be increasing\n"));
256 usage();
257 }
258
259 tabstops[nstops++] = i;
260 if (*cp == 0)
261 break;
262
263 if (*cp != ',' && *cp != ' ') {
264 (void) fprintf(stderr, gettext(
265 "expand: invalid tablist\n"));
266 usage();
267 }
268 cp++;
269 }
270 }
271
272 static void
usage(void)273 usage(void)
274 {
275 (void) fprintf(stderr, gettext(
276 "usage: expand [-t tablist] [file ...]\n"
277 " expand [-tabstop] [-tab1,tab2,...,tabn] [file ...]\n"));
278 exit(2);
279 /* NOTREACHED */
280 }
281