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