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 2004 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 #pragma ident "%Z%%M% %I% %E% SMI"
41
42 #include <stdio.h>
43 #include <locale.h>
44 #include <wchar.h>
45 #include <euc.h>
46 #include <stdlib.h> /* XCU4 */
47 #include <limits.h>
48 #include <libintl.h>
49 #include <langinfo.h>
50 #include <utime.h>
51 #include <widec.h>
52 #include <wctype.h>
53 #include <errno.h>
54
55
56 /*
57 * fold - fold long lines for finite output devices
58 */
59
60 static int fold = 80;
61 static int bflg = 0;
62 static int sflg = 0;
63 static int wflg = 0;
64 static int lastc = 0;
65 static int col = 0;
66 static int ncol = 0;
67 static int spcol = 0;
68 static wchar_t line[LINE_MAX];
69 static wchar_t *lastout = line;
70 static wchar_t *curc = line;
71 static wchar_t *lastsp = NULL;
72 #define MAXARG _POSIX_ARG_MAX
73
74 /*
75 * Fix lint errors
76 */
77 void exit();
78 static void Usage();
79 static void putch();
80 static void newline_init();
81 static int chr_width();
82 extern int errno;
83 static int get_foldw();
84
85
86 int
main(int argc,char * argv[])87 main(int argc, char *argv[])
88 {
89 int c, narg;
90 int ch;
91 char *cmdline[MAXARG];
92 int new_argc;
93 int w;
94 extern int optind;
95 extern char *optarg;
96
97 (void) setlocale(LC_ALL, "");
98 #if !defined(TEXT_DOMAIN)
99 #define TEXT_DOMAIN "SYS_TEST"
100 #endif
101 (void) textdomain(TEXT_DOMAIN);
102
103 /*
104 * Parse -width separately and build
105 * the new command line without -width.
106 * Next, use getopt() to parse this
107 * new command line.
108 */
109
110 for (narg = new_argc = 0; narg < argc; narg ++) {
111 if (argv[narg][0] == '-' &&
112 isdigit(argv[narg][1])) {
113
114 if (get_foldw((char *)&argv[narg][1], &w) < 0)
115 exit(1);
116
117 fold = w; /* Update with new width */
118 } else {
119 /* Build the new command line */
120 cmdline[new_argc++] = argv[narg];
121
122 /*
123 * Check to make sure the option with
124 * required arg should have arg.
125 * This would check errors introduced in
126 * mixing non-getopt() options and that of
127 * getopt()'s due to stripping non-getopt
128 * options.
129 */
130 if ((argv[narg][0] == '-') && (argv[narg][1] == 'w')) {
131 if (((narg+1) < argc) &&
132 (argv[narg+1][0] == '-')) {
133 (void) fprintf(stderr, "fold");
134 (void) fprintf(stderr, gettext(
135 ": option requires an argument -- w\n"));
136 Usage();
137 exit(1);
138 }
139 }
140 }
141 }
142
143 while ((ch = getopt(new_argc, cmdline, "w:bs")) != EOF) {
144 switch (ch) {
145 case 'b':
146 bflg++;
147 break;
148 case 's':
149 sflg++;
150 break;
151 case 'w':
152 wflg++;
153 /* No required arg ? */
154 if ((optarg == (char *)NULL) ||
155 ((optarg != (char *)NULL) &&
156 (*optarg == '-'))) {
157 (void) fprintf(stderr, "fold");
158 (void) fprintf(stderr, gettext(
159 ": option requires an argument -- w\n"));
160 Usage();
161 exit(1);
162 }
163 /* Bad number ? */
164 if (get_foldw(optarg, &w) < 0)
165 exit(1);
166
167 fold = w;
168 break;
169 default:
170 /*
171 * Errors should be filtered in previous
172 * pass.
173 */
174 Usage();
175 exit(1);
176 } /* switch */
177 } /* while */
178
179 do {
180 if (new_argc > optind) {
181 if (freopen(cmdline[optind], "r", stdin) == NULL) {
182 perror(cmdline[optind]);
183 Usage();
184 exit(1);
185 }
186 optind++;
187 }
188
189 for (;;) {
190 c = getwc(stdin);
191 if (c == EOF)
192 break;
193 (void) putch(c);
194 lastc = c;
195 }
196 if (col != 0) newline_init();
197 } while (new_argc > optind);
198
199 return (0);
200 }
201
202 static void
putch(int c)203 putch(int c)
204 {
205 wchar_t tline[LINE_MAX];
206
207 switch (c) {
208 case '\n':
209 ncol = 0;
210 break;
211 case '\t':
212 if (bflg)
213 ncol = col + chr_width(c);
214 else
215 ncol = (col + 8) &~ 7;
216 break;
217 case '\b':
218 if (bflg)
219 ncol = col + chr_width(c);
220 else
221 ncol = col ? col - 1 : 0;
222 break;
223 case '\r':
224 if (bflg)
225 ncol = col + chr_width(c);
226 else
227 ncol = 0;
228 break;
229
230 default:
231 if (bflg)
232 ncol = col + chr_width(c);
233 else
234 ncol = col + wcwidth(c);
235
236 }
237
238 /*
239 * Special processing when -b is not specified
240 * for backspace, and carriage return.
241 * No newline is inseted before or after the
242 * special character: backspace, or cr.
243 * See man page for the handling of backspace
244 * and CR when there is no -b.
245 */
246 if ((ncol > fold) && (bflg ||
247 (!bflg && (lastc != '\b') && (c != '\b') &&
248 (lastc != '\n') && (c != '\n')))) {
249 /*
250 * Need to check the last position for blank
251 */
252 if (sflg && lastsp) {
253 /*
254 * Save the output buffer
255 * as NULL has to be insert into the last
256 * sp position.
257 */
258 (void) wscpy(tline, line);
259 *lastsp = (wchar_t)NULL;
260 (void) fputws(lastout, stdout);
261 (void) putwchar('\n');
262 /*
263 * Restore the output buffer to stuff
264 * NULL into the last sp position
265 * for the new line.
266 */
267 (void) wscpy(line, tline);
268 lastout = lastsp;
269 lastsp = NULL; /* Reset the last sp */
270 ncol -= spcol; /* Reset column positions */
271 col -= spcol;
272 } else {
273 (void) newline_init();
274 (void) putwchar('\n');
275 lastout = curc;
276 }
277 }
278 /* Output buffer is full ? */
279 if ((curc + 1) >= (line + LINE_MAX)) {
280 /* Reach buffer limit */
281 if (col > 0) {
282 *curc = (wchar_t)NULL;
283 (void) fputws(lastout, stdout);
284 lastsp = NULL;
285 }
286 curc = lastout = line;
287
288 }
289
290 /* Store in output buffer */
291 *curc++ = (wchar_t)c;
292
293 switch (c) {
294 case '\n':
295 (void) newline_init();
296 curc = lastout = line;
297 break;
298 case '\t':
299 if (bflg)
300 col = col + chr_width(c);
301 else
302 col = (col + 8) &~ 7;
303 if (sflg && iswspace(c)) {
304 lastsp = curc;
305 spcol = ncol;
306 }
307
308 break;
309 case '\b':
310 if (bflg)
311 col = ncol;
312 else {
313 if (col)
314 col--;
315 }
316 break;
317 case '\r':
318 col = 0;
319 break;
320 default:
321 if (sflg && iswspace(c)) {
322 lastsp = curc;
323 spcol = ncol;
324 }
325
326 if (bflg)
327 col += chr_width(c);
328 else
329 col += wcwidth(c);
330
331 break;
332 }
333 }
334 static
335 void
Usage()336 Usage()
337 {
338 (void) fprintf(stderr, gettext(
339 "Usage: fold [-bs] [-w width | -width ] [file...]\n"));
340 }
341
342 static
343 void
newline_init()344 newline_init()
345 {
346 *curc = (wchar_t)NULL;
347 (void) fputws(lastout, stdout);
348 ncol = col = spcol = 0;
349 lastsp = NULL;
350 }
351
352 static int
chr_width(c)353 chr_width(c)
354 register int c;
355 {
356 char chr[MB_LEN_MAX+1];
357 register int n;
358
359 n = wctomb(chr, (wchar_t)c);
360
361 return (n > 0 ? n : 0);
362 }
363
364 static int
get_foldw(toptarg,width)365 get_foldw(toptarg, width)
366 char *toptarg;
367 int *width;
368 {
369 char *p;
370
371 if (!toptarg)
372 goto badno;
373
374 *width = 0;
375 errno = 0;
376 *width = strtoul(toptarg, &p, 10);
377 if (*width == -1)
378 goto badno;
379
380 if (*p)
381 goto badno;
382
383 if (!*width)
384 goto badno;
385
386 return (0);
387
388 badno:
389 /* fold error message */
390 (void) fprintf(stderr, gettext(
391 "Bad number for fold\n"));
392 Usage();
393 return (-1);
394 }
395