19b50d902SRodney W. Grimes /*- 29b50d902SRodney W. Grimes * Copyright (c) 1990, 1993 39b50d902SRodney W. Grimes * The Regents of the University of California. All rights reserved. 49b50d902SRodney W. Grimes * 59b50d902SRodney W. Grimes * This code is derived from software contributed to Berkeley by 69b50d902SRodney W. Grimes * Kevin Ruddy. 79b50d902SRodney W. Grimes * 89b50d902SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 99b50d902SRodney W. Grimes * modification, are permitted provided that the following conditions 109b50d902SRodney W. Grimes * are met: 119b50d902SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 129b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 139b50d902SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 149b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 159b50d902SRodney W. Grimes * documentation and/or other materials provided with the distribution. 169b50d902SRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 179b50d902SRodney W. Grimes * must display the following acknowledgement: 189b50d902SRodney W. Grimes * This product includes software developed by the University of 199b50d902SRodney W. Grimes * California, Berkeley and its contributors. 209b50d902SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 219b50d902SRodney W. Grimes * may be used to endorse or promote products derived from this software 229b50d902SRodney W. Grimes * without specific prior written permission. 239b50d902SRodney W. Grimes * 249b50d902SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 259b50d902SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 269b50d902SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 279b50d902SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 289b50d902SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 299b50d902SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 309b50d902SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 319b50d902SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 329b50d902SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 339b50d902SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 349b50d902SRodney W. Grimes * SUCH DAMAGE. 359b50d902SRodney W. Grimes */ 369b50d902SRodney W. Grimes 379b50d902SRodney W. Grimes #ifndef lint 38f589c9aaSPhilippe Charnier static const char copyright[] = 399b50d902SRodney W. Grimes "@(#) Copyright (c) 1990, 1993\n\ 409b50d902SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 419b50d902SRodney W. Grimes #endif /* not lint */ 429b50d902SRodney W. Grimes 439b50d902SRodney W. Grimes #ifndef lint 44f589c9aaSPhilippe Charnier #if 0 459b50d902SRodney W. Grimes static char sccsid[] = "@(#)fold.c 8.1 (Berkeley) 6/6/93"; 46f589c9aaSPhilippe Charnier #endif 479b50d902SRodney W. Grimes #endif /* not lint */ 489b50d902SRodney W. Grimes 49a9c9a0d1SPhilippe Charnier #include <sys/cdefs.h> 50a9c9a0d1SPhilippe Charnier __FBSDID("$FreeBSD$"); 51a9c9a0d1SPhilippe Charnier 52f589c9aaSPhilippe Charnier #include <err.h> 5313e06695STim J. Robbins #include <limits.h> 54a243305fSAndrey A. Chernov #include <locale.h> 559b50d902SRodney W. Grimes #include <stdio.h> 56f589c9aaSPhilippe Charnier #include <stdlib.h> 57821df508SXin LI #include <string.h> 58f589c9aaSPhilippe Charnier #include <unistd.h> 5919657ec3STim J. Robbins #include <wchar.h> 6019657ec3STim J. Robbins #include <wctype.h> 619b50d902SRodney W. Grimes 629b50d902SRodney W. Grimes #define DEFLINEWIDTH 80 639b50d902SRodney W. Grimes 64f1bb2cd2SWarner Losh void fold(int); 6519657ec3STim J. Robbins static int newpos(int, wint_t); 66f1bb2cd2SWarner Losh static void usage(void); 67f589c9aaSPhilippe Charnier 6813e06695STim J. Robbins int bflag; /* Count bytes, not columns */ 6913e06695STim J. Robbins int sflag; /* Split on word boundaries */ 7013e06695STim J. Robbins 71f589c9aaSPhilippe Charnier int 72f4ac32deSDavid Malone main(int argc, char **argv) 739b50d902SRodney W. Grimes { 74*76423301SJean-Sébastien Pédron int ch, previous_ch; 75fb2582c0STim J. Robbins int rval, width; 769b50d902SRodney W. Grimes 77a243305fSAndrey A. Chernov (void) setlocale(LC_CTYPE, ""); 78a243305fSAndrey A. Chernov 799b50d902SRodney W. Grimes width = -1; 80*76423301SJean-Sébastien Pédron previous_ch = 0; 81*76423301SJean-Sébastien Pédron while ((ch = getopt(argc, argv, "0123456789bsw:")) != -1) { 829b50d902SRodney W. Grimes switch (ch) { 8313e06695STim J. Robbins case 'b': 8413e06695STim J. Robbins bflag = 1; 8513e06695STim J. Robbins break; 8613e06695STim J. Robbins case 's': 8713e06695STim J. Robbins sflag = 1; 8813e06695STim J. Robbins break; 899b50d902SRodney W. Grimes case 'w': 909b50d902SRodney W. Grimes if ((width = atoi(optarg)) <= 0) { 91f589c9aaSPhilippe Charnier errx(1, "illegal width value"); 929b50d902SRodney W. Grimes } 939b50d902SRodney W. Grimes break; 949b50d902SRodney W. Grimes case '0': case '1': case '2': case '3': case '4': 959b50d902SRodney W. Grimes case '5': case '6': case '7': case '8': case '9': 96*76423301SJean-Sébastien Pédron /* Accept a width as eg. -30. Note that a width 97*76423301SJean-Sébastien Pédron * specified using the -w option is always used prior 98*76423301SJean-Sébastien Pédron * to this undocumented option. */ 99*76423301SJean-Sébastien Pédron switch (previous_ch) { 100*76423301SJean-Sébastien Pédron case '0': case '1': case '2': case '3': case '4': 101*76423301SJean-Sébastien Pédron case '5': case '6': case '7': case '8': case '9': 102*76423301SJean-Sébastien Pédron /* The width is a number with multiple digits: 103*76423301SJean-Sébastien Pédron * add the last one. */ 104*76423301SJean-Sébastien Pédron width = width * 10 + (ch - '0'); 105*76423301SJean-Sébastien Pédron break; 106*76423301SJean-Sébastien Pédron default: 107*76423301SJean-Sébastien Pédron /* Set the width, unless it was previously 108*76423301SJean-Sébastien Pédron * set. For instance, the following options 109*76423301SJean-Sébastien Pédron * would all give a width of 5 and not 10: 110*76423301SJean-Sébastien Pédron * -10 -w5 111*76423301SJean-Sébastien Pédron * -5b10 112*76423301SJean-Sébastien Pédron * -5 -10b */ 113*76423301SJean-Sébastien Pédron if (width == -1) 114*76423301SJean-Sébastien Pédron width = ch - '0'; 115*76423301SJean-Sébastien Pédron break; 1169b50d902SRodney W. Grimes } 1179b50d902SRodney W. Grimes break; 1189b50d902SRodney W. Grimes default: 119f589c9aaSPhilippe Charnier usage(); 1209b50d902SRodney W. Grimes } 121*76423301SJean-Sébastien Pédron previous_ch = ch; 122*76423301SJean-Sébastien Pédron } 1239b50d902SRodney W. Grimes argv += optind; 1249b50d902SRodney W. Grimes argc -= optind; 1259b50d902SRodney W. Grimes 1269b50d902SRodney W. Grimes if (width == -1) 1279b50d902SRodney W. Grimes width = DEFLINEWIDTH; 128fb2582c0STim J. Robbins rval = 0; 1299b50d902SRodney W. Grimes if (!*argv) 1309b50d902SRodney W. Grimes fold(width); 1319b50d902SRodney W. Grimes else for (; *argv; ++argv) 1329b50d902SRodney W. Grimes if (!freopen(*argv, "r", stdin)) { 133fb2582c0STim J. Robbins warn("%s", *argv); 134fb2582c0STim J. Robbins rval = 1; 1359b50d902SRodney W. Grimes } else 1369b50d902SRodney W. Grimes fold(width); 137fb2582c0STim J. Robbins exit(rval); 1389b50d902SRodney W. Grimes } 1399b50d902SRodney W. Grimes 140f589c9aaSPhilippe Charnier static void 141f4ac32deSDavid Malone usage(void) 142f589c9aaSPhilippe Charnier { 14313e06695STim J. Robbins (void)fprintf(stderr, "usage: fold [-bs] [-w width] [file ...]\n"); 144f589c9aaSPhilippe Charnier exit(1); 145f589c9aaSPhilippe Charnier } 146f589c9aaSPhilippe Charnier 14713e06695STim J. Robbins /* 14813e06695STim J. Robbins * Fold the contents of standard input to fit within WIDTH columns (or bytes) 14913e06695STim J. Robbins * and write to standard output. 15013e06695STim J. Robbins * 15113e06695STim J. Robbins * If sflag is set, split the line at the last space character on the line. 15213e06695STim J. Robbins * This flag necessitates storing the line in a buffer until the current 15313e06695STim J. Robbins * column > width, or a newline or EOF is read. 15413e06695STim J. Robbins * 15513e06695STim J. Robbins * The buffer can grow larger than WIDTH due to backspaces and carriage 15613e06695STim J. Robbins * returns embedded in the input stream. 15713e06695STim J. Robbins */ 158f589c9aaSPhilippe Charnier void 159f4ac32deSDavid Malone fold(int width) 1609b50d902SRodney W. Grimes { 16119657ec3STim J. Robbins static wchar_t *buf; 16213e06695STim J. Robbins static int buf_max; 16319657ec3STim J. Robbins int col, i, indx, space; 16419657ec3STim J. Robbins wint_t ch; 1659b50d902SRodney W. Grimes 16613e06695STim J. Robbins col = indx = 0; 16719657ec3STim J. Robbins while ((ch = getwchar()) != WEOF) { 16813e06695STim J. Robbins if (ch == '\n') { 16919657ec3STim J. Robbins wprintf(L"%.*ls\n", indx, buf); 17013e06695STim J. Robbins col = indx = 0; 17113e06695STim J. Robbins continue; 1729b50d902SRodney W. Grimes } 17313e06695STim J. Robbins if ((col = newpos(col, ch)) > width) { 17413e06695STim J. Robbins if (sflag) { 17513e06695STim J. Robbins i = indx; 17619657ec3STim J. Robbins while (--i >= 0 && !iswblank(buf[i])) 17713e06695STim J. Robbins ; 17813e06695STim J. Robbins space = i; 17913e06695STim J. Robbins } 18013e06695STim J. Robbins if (sflag && space != -1) { 18113e06695STim J. Robbins space++; 18219657ec3STim J. Robbins wprintf(L"%.*ls\n", space, buf); 18319657ec3STim J. Robbins wmemmove(buf, buf + space, indx - space); 18413e06695STim J. Robbins indx -= space; 18513e06695STim J. Robbins col = 0; 18613e06695STim J. Robbins for (i = 0; i < indx; i++) 18719657ec3STim J. Robbins col = newpos(col, buf[i]); 18813e06695STim J. Robbins } else { 18919657ec3STim J. Robbins wprintf(L"%.*ls\n", indx, buf); 19013e06695STim J. Robbins col = indx = 0; 19113e06695STim J. Robbins } 19213e06695STim J. Robbins col = newpos(col, ch); 19313e06695STim J. Robbins } 19413e06695STim J. Robbins if (indx + 1 > buf_max) { 19513e06695STim J. Robbins buf_max += LINE_MAX; 19619657ec3STim J. Robbins buf = realloc(buf, sizeof(*buf) * buf_max); 19719657ec3STim J. Robbins if (buf == NULL) 19813e06695STim J. Robbins err(1, "realloc()"); 19913e06695STim J. Robbins } 20013e06695STim J. Robbins buf[indx++] = ch; 20113e06695STim J. Robbins } 2029b50d902SRodney W. Grimes 20313e06695STim J. Robbins if (indx != 0) 20419657ec3STim J. Robbins wprintf(L"%.*ls", indx, buf); 20513e06695STim J. Robbins } 20613e06695STim J. Robbins 20713e06695STim J. Robbins /* 20813e06695STim J. Robbins * Update the current column position for a character. 20913e06695STim J. Robbins */ 21013e06695STim J. Robbins static int 21119657ec3STim J. Robbins newpos(int col, wint_t ch) 21213e06695STim J. Robbins { 21319657ec3STim J. Robbins char buf[MB_LEN_MAX]; 21419657ec3STim J. Robbins size_t len; 21519657ec3STim J. Robbins int w; 21613e06695STim J. Robbins 21719657ec3STim J. Robbins if (bflag) { 21819657ec3STim J. Robbins len = wcrtomb(buf, ch, NULL); 21919657ec3STim J. Robbins col += len; 22019657ec3STim J. Robbins } else 2219b50d902SRodney W. Grimes switch (ch) { 2229b50d902SRodney W. Grimes case '\b': 2239b50d902SRodney W. Grimes if (col > 0) 2249b50d902SRodney W. Grimes --col; 2259b50d902SRodney W. Grimes break; 2269b50d902SRodney W. Grimes case '\r': 2279b50d902SRodney W. Grimes col = 0; 2289b50d902SRodney W. Grimes break; 2299b50d902SRodney W. Grimes case '\t': 23013e06695STim J. Robbins col = (col + 8) & ~7; 2319b50d902SRodney W. Grimes break; 2329b50d902SRodney W. Grimes default: 23319657ec3STim J. Robbins if ((w = wcwidth(ch)) > 0) 23419657ec3STim J. Robbins col += w; 2359b50d902SRodney W. Grimes break; 2369b50d902SRodney W. Grimes } 23713e06695STim J. Robbins 23813e06695STim J. Robbins return (col); 2399b50d902SRodney W. Grimes } 240