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 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 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 336 Usage() 337 { 338 (void) fprintf(stderr, gettext( 339 "Usage: fold [-bs] [-w width | -width ] [file...]\n")); 340 } 341 342 static 343 void 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 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 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