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