/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * University Copyright- Copyright (c) 1982, 1986, 1988 * The Regents of the University of California * All Rights Reserved * * University Acknowledgment- Portions of this document are derived from * software developed by the University of California, Berkeley, and its * contributors. */ #include #include #include #include #include /* XCU4 */ #include #include #include #include #include #include #include /* * fold - fold long lines for finite output devices */ static int fold = 80; static int bflg = 0; static int sflg = 0; static int wflg = 0; static int lastc = 0; static int col = 0; static int ncol = 0; static int spcol = 0; static wchar_t line[LINE_MAX]; static wchar_t *lastout = line; static wchar_t *curc = line; static wchar_t *lastsp = NULL; #define MAXARG _POSIX_ARG_MAX /* * Fix lint errors */ void exit(); static void Usage(); static void putch(); static void newline_init(); static int chr_width(); extern int errno; static int get_foldw(); int main(int argc, char *argv[]) { int c, narg; int ch; char *cmdline[MAXARG]; int new_argc; int w; extern int optind; extern char *optarg; (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) #define TEXT_DOMAIN "SYS_TEST" #endif (void) textdomain(TEXT_DOMAIN); /* * Parse -width separately and build * the new command line without -width. * Next, use getopt() to parse this * new command line. */ for (narg = new_argc = 0; narg < argc; narg ++) { if (argv[narg][0] == '-' && isdigit(argv[narg][1])) { if (get_foldw((char *)&argv[narg][1], &w) < 0) exit(1); fold = w; /* Update with new width */ } else { /* Build the new command line */ cmdline[new_argc++] = argv[narg]; /* * Check to make sure the option with * required arg should have arg. * This would check errors introduced in * mixing non-getopt() options and that of * getopt()'s due to stripping non-getopt * options. */ if ((argv[narg][0] == '-') && (argv[narg][1] == 'w')) { if (((narg+1) < argc) && (argv[narg+1][0] == '-')) { (void) fprintf(stderr, "fold"); (void) fprintf(stderr, gettext( ": option requires an argument -- w\n")); Usage(); exit(1); } } } } while ((ch = getopt(new_argc, cmdline, "w:bs")) != EOF) { switch (ch) { case 'b': bflg++; break; case 's': sflg++; break; case 'w': wflg++; /* No required arg ? */ if ((optarg == (char *)NULL) || ((optarg != (char *)NULL) && (*optarg == '-'))) { (void) fprintf(stderr, "fold"); (void) fprintf(stderr, gettext( ": option requires an argument -- w\n")); Usage(); exit(1); } /* Bad number ? */ if (get_foldw(optarg, &w) < 0) exit(1); fold = w; break; default: /* * Errors should be filtered in previous * pass. */ Usage(); exit(1); } /* switch */ } /* while */ do { if (new_argc > optind) { if (freopen(cmdline[optind], "r", stdin) == NULL) { perror(cmdline[optind]); Usage(); exit(1); } optind++; } for (;;) { c = getwc(stdin); if (c == EOF) break; (void) putch(c); lastc = c; } if (col != 0) newline_init(); } while (new_argc > optind); return (0); } static void putch(int c) { wchar_t tline[LINE_MAX]; switch (c) { case '\n': ncol = 0; break; case '\t': if (bflg) ncol = col + chr_width(c); else ncol = (col + 8) &~ 7; break; case '\b': if (bflg) ncol = col + chr_width(c); else ncol = col ? col - 1 : 0; break; case '\r': if (bflg) ncol = col + chr_width(c); else ncol = 0; break; default: if (bflg) ncol = col + chr_width(c); else ncol = col + wcwidth(c); } /* * Special processing when -b is not specified * for backspace, and carriage return. * No newline is inseted before or after the * special character: backspace, or cr. * See man page for the handling of backspace * and CR when there is no -b. */ if ((ncol > fold) && (bflg || (!bflg && (lastc != '\b') && (c != '\b') && (lastc != '\n') && (c != '\n')))) { /* * Need to check the last position for blank */ if (sflg && lastsp) { /* * Save the output buffer * as NULL has to be insert into the last * sp position. */ (void) wscpy(tline, line); *lastsp = (wchar_t)NULL; (void) fputws(lastout, stdout); (void) putwchar('\n'); /* * Restore the output buffer to stuff * NULL into the last sp position * for the new line. */ (void) wscpy(line, tline); lastout = lastsp; lastsp = NULL; /* Reset the last sp */ ncol -= spcol; /* Reset column positions */ col -= spcol; } else { (void) newline_init(); (void) putwchar('\n'); lastout = curc; } } /* Output buffer is full ? */ if ((curc + 1) >= (line + LINE_MAX)) { /* Reach buffer limit */ if (col > 0) { *curc = (wchar_t)NULL; (void) fputws(lastout, stdout); lastsp = NULL; } curc = lastout = line; } /* Store in output buffer */ *curc++ = (wchar_t)c; switch (c) { case '\n': (void) newline_init(); curc = lastout = line; break; case '\t': if (bflg) col = col + chr_width(c); else col = (col + 8) &~ 7; if (sflg && iswspace(c)) { lastsp = curc; spcol = ncol; } break; case '\b': if (bflg) col = ncol; else { if (col) col--; } break; case '\r': col = 0; break; default: if (sflg && iswspace(c)) { lastsp = curc; spcol = ncol; } if (bflg) col += chr_width(c); else col += wcwidth(c); break; } } static void Usage() { (void) fprintf(stderr, gettext( "Usage: fold [-bs] [-w width | -width ] [file...]\n")); } static void newline_init() { *curc = (wchar_t)NULL; (void) fputws(lastout, stdout); ncol = col = spcol = 0; lastsp = NULL; } static int chr_width(c) register int c; { char chr[MB_LEN_MAX+1]; register int n; n = wctomb(chr, (wchar_t)c); return (n > 0 ? n : 0); } static int get_foldw(toptarg, width) char *toptarg; int *width; { char *p; if (!toptarg) goto badno; *width = 0; errno = 0; *width = strtoul(toptarg, &p, 10); if (*width == -1) goto badno; if (*p) goto badno; if (!*width) goto badno; return (0); badno: /* fold error message */ (void) fprintf(stderr, gettext( "Bad number for fold\n")); Usage(); return (-1); }