19b50d902SRodney W. Grimes /*- 2*8a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 3*8a16b7a1SPedro F. Giffuni * 49b50d902SRodney W. Grimes * Copyright (c) 1990, 1993 59b50d902SRodney W. Grimes * The Regents of the University of California. All rights reserved. 69b50d902SRodney W. Grimes * 79b50d902SRodney W. Grimes * This code is derived from software contributed to Berkeley by 89b50d902SRodney W. Grimes * Kevin Ruddy. 99b50d902SRodney W. Grimes * 109b50d902SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 119b50d902SRodney W. Grimes * modification, are permitted provided that the following conditions 129b50d902SRodney W. Grimes * are met: 139b50d902SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 149b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 159b50d902SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 169b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 179b50d902SRodney W. Grimes * documentation and/or other materials provided with the distribution. 18fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 199b50d902SRodney W. Grimes * may be used to endorse or promote products derived from this software 209b50d902SRodney W. Grimes * without specific prior written permission. 219b50d902SRodney W. Grimes * 229b50d902SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 239b50d902SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 249b50d902SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 259b50d902SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 269b50d902SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 279b50d902SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 289b50d902SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 299b50d902SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 309b50d902SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 319b50d902SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 329b50d902SRodney W. Grimes * SUCH DAMAGE. 339b50d902SRodney W. Grimes */ 349b50d902SRodney W. Grimes 359b50d902SRodney W. Grimes #ifndef lint 36f589c9aaSPhilippe Charnier static const char copyright[] = 379b50d902SRodney W. Grimes "@(#) Copyright (c) 1990, 1993\n\ 389b50d902SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 399b50d902SRodney W. Grimes #endif /* not lint */ 409b50d902SRodney W. Grimes 419b50d902SRodney W. Grimes #ifndef lint 42f589c9aaSPhilippe Charnier #if 0 439b50d902SRodney W. Grimes static char sccsid[] = "@(#)fold.c 8.1 (Berkeley) 6/6/93"; 44f589c9aaSPhilippe Charnier #endif 459b50d902SRodney W. Grimes #endif /* not lint */ 469b50d902SRodney W. Grimes 47a9c9a0d1SPhilippe Charnier #include <sys/cdefs.h> 48a9c9a0d1SPhilippe Charnier __FBSDID("$FreeBSD$"); 49a9c9a0d1SPhilippe Charnier 50f589c9aaSPhilippe Charnier #include <err.h> 5113e06695STim J. Robbins #include <limits.h> 52a243305fSAndrey A. Chernov #include <locale.h> 539b50d902SRodney W. Grimes #include <stdio.h> 54f589c9aaSPhilippe Charnier #include <stdlib.h> 55821df508SXin LI #include <string.h> 56f589c9aaSPhilippe Charnier #include <unistd.h> 5719657ec3STim J. Robbins #include <wchar.h> 5819657ec3STim J. Robbins #include <wctype.h> 599b50d902SRodney W. Grimes 609b50d902SRodney W. Grimes #define DEFLINEWIDTH 80 619b50d902SRodney W. Grimes 62f1bb2cd2SWarner Losh void fold(int); 6319657ec3STim J. Robbins static int newpos(int, wint_t); 64f1bb2cd2SWarner Losh static void usage(void); 65f589c9aaSPhilippe Charnier 66385c1d29SEd Schouten static int bflag; /* Count bytes, not columns */ 67385c1d29SEd Schouten static int sflag; /* Split on word boundaries */ 6813e06695STim J. Robbins 69f589c9aaSPhilippe Charnier int 70f4ac32deSDavid Malone main(int argc, char **argv) 719b50d902SRodney W. Grimes { 7276423301SJean-Sébastien Pédron int ch, previous_ch; 73fb2582c0STim J. Robbins int rval, width; 749b50d902SRodney W. Grimes 75a243305fSAndrey A. Chernov (void) setlocale(LC_CTYPE, ""); 76a243305fSAndrey A. Chernov 779b50d902SRodney W. Grimes width = -1; 7876423301SJean-Sébastien Pédron previous_ch = 0; 7976423301SJean-Sébastien Pédron while ((ch = getopt(argc, argv, "0123456789bsw:")) != -1) { 809b50d902SRodney W. Grimes switch (ch) { 8113e06695STim J. Robbins case 'b': 8213e06695STim J. Robbins bflag = 1; 8313e06695STim J. Robbins break; 8413e06695STim J. Robbins case 's': 8513e06695STim J. Robbins sflag = 1; 8613e06695STim J. Robbins break; 879b50d902SRodney W. Grimes case 'w': 889b50d902SRodney W. Grimes if ((width = atoi(optarg)) <= 0) { 89f589c9aaSPhilippe Charnier errx(1, "illegal width value"); 909b50d902SRodney W. Grimes } 919b50d902SRodney W. Grimes break; 929b50d902SRodney W. Grimes case '0': case '1': case '2': case '3': case '4': 939b50d902SRodney W. Grimes case '5': case '6': case '7': case '8': case '9': 9476423301SJean-Sébastien Pédron /* Accept a width as eg. -30. Note that a width 9576423301SJean-Sébastien Pédron * specified using the -w option is always used prior 9676423301SJean-Sébastien Pédron * to this undocumented option. */ 9776423301SJean-Sébastien Pédron switch (previous_ch) { 9876423301SJean-Sébastien Pédron case '0': case '1': case '2': case '3': case '4': 9976423301SJean-Sébastien Pédron case '5': case '6': case '7': case '8': case '9': 10076423301SJean-Sébastien Pédron /* The width is a number with multiple digits: 10176423301SJean-Sébastien Pédron * add the last one. */ 10276423301SJean-Sébastien Pédron width = width * 10 + (ch - '0'); 10376423301SJean-Sébastien Pédron break; 10476423301SJean-Sébastien Pédron default: 10576423301SJean-Sébastien Pédron /* Set the width, unless it was previously 10676423301SJean-Sébastien Pédron * set. For instance, the following options 10776423301SJean-Sébastien Pédron * would all give a width of 5 and not 10: 10876423301SJean-Sébastien Pédron * -10 -w5 10976423301SJean-Sébastien Pédron * -5b10 11076423301SJean-Sébastien Pédron * -5 -10b */ 11176423301SJean-Sébastien Pédron if (width == -1) 11276423301SJean-Sébastien Pédron width = ch - '0'; 11376423301SJean-Sébastien Pédron break; 1149b50d902SRodney W. Grimes } 1159b50d902SRodney W. Grimes break; 1169b50d902SRodney W. Grimes default: 117f589c9aaSPhilippe Charnier usage(); 1189b50d902SRodney W. Grimes } 11976423301SJean-Sébastien Pédron previous_ch = ch; 12076423301SJean-Sébastien Pédron } 1219b50d902SRodney W. Grimes argv += optind; 1229b50d902SRodney W. Grimes argc -= optind; 1239b50d902SRodney W. Grimes 1249b50d902SRodney W. Grimes if (width == -1) 1259b50d902SRodney W. Grimes width = DEFLINEWIDTH; 126fb2582c0STim J. Robbins rval = 0; 1279b50d902SRodney W. Grimes if (!*argv) 1289b50d902SRodney W. Grimes fold(width); 1299b50d902SRodney W. Grimes else for (; *argv; ++argv) 1309b50d902SRodney W. Grimes if (!freopen(*argv, "r", stdin)) { 131fb2582c0STim J. Robbins warn("%s", *argv); 132fb2582c0STim J. Robbins rval = 1; 1339b50d902SRodney W. Grimes } else 1349b50d902SRodney W. Grimes fold(width); 135fb2582c0STim J. Robbins exit(rval); 1369b50d902SRodney W. Grimes } 1379b50d902SRodney W. Grimes 138f589c9aaSPhilippe Charnier static void 139f4ac32deSDavid Malone usage(void) 140f589c9aaSPhilippe Charnier { 14113e06695STim J. Robbins (void)fprintf(stderr, "usage: fold [-bs] [-w width] [file ...]\n"); 142f589c9aaSPhilippe Charnier exit(1); 143f589c9aaSPhilippe Charnier } 144f589c9aaSPhilippe Charnier 14513e06695STim J. Robbins /* 14613e06695STim J. Robbins * Fold the contents of standard input to fit within WIDTH columns (or bytes) 14713e06695STim J. Robbins * and write to standard output. 14813e06695STim J. Robbins * 14913e06695STim J. Robbins * If sflag is set, split the line at the last space character on the line. 15013e06695STim J. Robbins * This flag necessitates storing the line in a buffer until the current 15113e06695STim J. Robbins * column > width, or a newline or EOF is read. 15213e06695STim J. Robbins * 15313e06695STim J. Robbins * The buffer can grow larger than WIDTH due to backspaces and carriage 15413e06695STim J. Robbins * returns embedded in the input stream. 15513e06695STim J. Robbins */ 156f589c9aaSPhilippe Charnier void 157f4ac32deSDavid Malone fold(int width) 1589b50d902SRodney W. Grimes { 15919657ec3STim J. Robbins static wchar_t *buf; 16013e06695STim J. Robbins static int buf_max; 16119657ec3STim J. Robbins int col, i, indx, space; 16219657ec3STim J. Robbins wint_t ch; 1639b50d902SRodney W. Grimes 16413e06695STim J. Robbins col = indx = 0; 16519657ec3STim J. Robbins while ((ch = getwchar()) != WEOF) { 16613e06695STim J. Robbins if (ch == '\n') { 16719657ec3STim J. Robbins wprintf(L"%.*ls\n", indx, buf); 16813e06695STim J. Robbins col = indx = 0; 16913e06695STim J. Robbins continue; 1709b50d902SRodney W. Grimes } 17113e06695STim J. Robbins if ((col = newpos(col, ch)) > width) { 17213e06695STim J. Robbins if (sflag) { 17313e06695STim J. Robbins i = indx; 17419657ec3STim J. Robbins while (--i >= 0 && !iswblank(buf[i])) 17513e06695STim J. Robbins ; 17613e06695STim J. Robbins space = i; 17713e06695STim J. Robbins } 17813e06695STim J. Robbins if (sflag && space != -1) { 17913e06695STim J. Robbins space++; 18019657ec3STim J. Robbins wprintf(L"%.*ls\n", space, buf); 18119657ec3STim J. Robbins wmemmove(buf, buf + space, indx - space); 18213e06695STim J. Robbins indx -= space; 18313e06695STim J. Robbins col = 0; 18413e06695STim J. Robbins for (i = 0; i < indx; i++) 18519657ec3STim J. Robbins col = newpos(col, buf[i]); 18613e06695STim J. Robbins } else { 18719657ec3STim J. Robbins wprintf(L"%.*ls\n", indx, buf); 18813e06695STim J. Robbins col = indx = 0; 18913e06695STim J. Robbins } 19013e06695STim J. Robbins col = newpos(col, ch); 19113e06695STim J. Robbins } 19213e06695STim J. Robbins if (indx + 1 > buf_max) { 19313e06695STim J. Robbins buf_max += LINE_MAX; 19419657ec3STim J. Robbins buf = realloc(buf, sizeof(*buf) * buf_max); 19519657ec3STim J. Robbins if (buf == NULL) 19613e06695STim J. Robbins err(1, "realloc()"); 19713e06695STim J. Robbins } 19813e06695STim J. Robbins buf[indx++] = ch; 19913e06695STim J. Robbins } 2009b50d902SRodney W. Grimes 20113e06695STim J. Robbins if (indx != 0) 20219657ec3STim J. Robbins wprintf(L"%.*ls", indx, buf); 20313e06695STim J. Robbins } 20413e06695STim J. Robbins 20513e06695STim J. Robbins /* 20613e06695STim J. Robbins * Update the current column position for a character. 20713e06695STim J. Robbins */ 20813e06695STim J. Robbins static int 20919657ec3STim J. Robbins newpos(int col, wint_t ch) 21013e06695STim J. Robbins { 21119657ec3STim J. Robbins char buf[MB_LEN_MAX]; 21219657ec3STim J. Robbins size_t len; 21319657ec3STim J. Robbins int w; 21413e06695STim J. Robbins 21519657ec3STim J. Robbins if (bflag) { 21619657ec3STim J. Robbins len = wcrtomb(buf, ch, NULL); 21719657ec3STim J. Robbins col += len; 21819657ec3STim J. Robbins } else 2199b50d902SRodney W. Grimes switch (ch) { 2209b50d902SRodney W. Grimes case '\b': 2219b50d902SRodney W. Grimes if (col > 0) 2229b50d902SRodney W. Grimes --col; 2239b50d902SRodney W. Grimes break; 2249b50d902SRodney W. Grimes case '\r': 2259b50d902SRodney W. Grimes col = 0; 2269b50d902SRodney W. Grimes break; 2279b50d902SRodney W. Grimes case '\t': 22813e06695STim J. Robbins col = (col + 8) & ~7; 2299b50d902SRodney W. Grimes break; 2309b50d902SRodney W. Grimes default: 23119657ec3STim J. Robbins if ((w = wcwidth(ch)) > 0) 23219657ec3STim J. Robbins col += w; 2339b50d902SRodney W. Grimes break; 2349b50d902SRodney W. Grimes } 23513e06695STim J. Robbins 23613e06695STim J. Robbins return (col); 2379b50d902SRodney W. Grimes } 238