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. 16*fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 179b50d902SRodney W. Grimes * may be used to endorse or promote products derived from this software 189b50d902SRodney W. Grimes * without specific prior written permission. 199b50d902SRodney W. Grimes * 209b50d902SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 219b50d902SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 229b50d902SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 239b50d902SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 249b50d902SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 259b50d902SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 269b50d902SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 279b50d902SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 289b50d902SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 299b50d902SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 309b50d902SRodney W. Grimes * SUCH DAMAGE. 319b50d902SRodney W. Grimes */ 329b50d902SRodney W. Grimes 339b50d902SRodney W. Grimes #ifndef lint 34f589c9aaSPhilippe Charnier static const char copyright[] = 359b50d902SRodney W. Grimes "@(#) Copyright (c) 1990, 1993\n\ 369b50d902SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 379b50d902SRodney W. Grimes #endif /* not lint */ 389b50d902SRodney W. Grimes 399b50d902SRodney W. Grimes #ifndef lint 40f589c9aaSPhilippe Charnier #if 0 419b50d902SRodney W. Grimes static char sccsid[] = "@(#)fold.c 8.1 (Berkeley) 6/6/93"; 42f589c9aaSPhilippe Charnier #endif 439b50d902SRodney W. Grimes #endif /* not lint */ 449b50d902SRodney W. Grimes 45a9c9a0d1SPhilippe Charnier #include <sys/cdefs.h> 46a9c9a0d1SPhilippe Charnier __FBSDID("$FreeBSD$"); 47a9c9a0d1SPhilippe Charnier 48f589c9aaSPhilippe Charnier #include <err.h> 4913e06695STim J. Robbins #include <limits.h> 50a243305fSAndrey A. Chernov #include <locale.h> 519b50d902SRodney W. Grimes #include <stdio.h> 52f589c9aaSPhilippe Charnier #include <stdlib.h> 53821df508SXin LI #include <string.h> 54f589c9aaSPhilippe Charnier #include <unistd.h> 5519657ec3STim J. Robbins #include <wchar.h> 5619657ec3STim J. Robbins #include <wctype.h> 579b50d902SRodney W. Grimes 589b50d902SRodney W. Grimes #define DEFLINEWIDTH 80 599b50d902SRodney W. Grimes 60f1bb2cd2SWarner Losh void fold(int); 6119657ec3STim J. Robbins static int newpos(int, wint_t); 62f1bb2cd2SWarner Losh static void usage(void); 63f589c9aaSPhilippe Charnier 64385c1d29SEd Schouten static int bflag; /* Count bytes, not columns */ 65385c1d29SEd Schouten static int sflag; /* Split on word boundaries */ 6613e06695STim J. Robbins 67f589c9aaSPhilippe Charnier int 68f4ac32deSDavid Malone main(int argc, char **argv) 699b50d902SRodney W. Grimes { 7076423301SJean-Sébastien Pédron int ch, previous_ch; 71fb2582c0STim J. Robbins int rval, width; 729b50d902SRodney W. Grimes 73a243305fSAndrey A. Chernov (void) setlocale(LC_CTYPE, ""); 74a243305fSAndrey A. Chernov 759b50d902SRodney W. Grimes width = -1; 7676423301SJean-Sébastien Pédron previous_ch = 0; 7776423301SJean-Sébastien Pédron while ((ch = getopt(argc, argv, "0123456789bsw:")) != -1) { 789b50d902SRodney W. Grimes switch (ch) { 7913e06695STim J. Robbins case 'b': 8013e06695STim J. Robbins bflag = 1; 8113e06695STim J. Robbins break; 8213e06695STim J. Robbins case 's': 8313e06695STim J. Robbins sflag = 1; 8413e06695STim J. Robbins break; 859b50d902SRodney W. Grimes case 'w': 869b50d902SRodney W. Grimes if ((width = atoi(optarg)) <= 0) { 87f589c9aaSPhilippe Charnier errx(1, "illegal width value"); 889b50d902SRodney W. Grimes } 899b50d902SRodney W. Grimes break; 909b50d902SRodney W. Grimes case '0': case '1': case '2': case '3': case '4': 919b50d902SRodney W. Grimes case '5': case '6': case '7': case '8': case '9': 9276423301SJean-Sébastien Pédron /* Accept a width as eg. -30. Note that a width 9376423301SJean-Sébastien Pédron * specified using the -w option is always used prior 9476423301SJean-Sébastien Pédron * to this undocumented option. */ 9576423301SJean-Sébastien Pédron switch (previous_ch) { 9676423301SJean-Sébastien Pédron case '0': case '1': case '2': case '3': case '4': 9776423301SJean-Sébastien Pédron case '5': case '6': case '7': case '8': case '9': 9876423301SJean-Sébastien Pédron /* The width is a number with multiple digits: 9976423301SJean-Sébastien Pédron * add the last one. */ 10076423301SJean-Sébastien Pédron width = width * 10 + (ch - '0'); 10176423301SJean-Sébastien Pédron break; 10276423301SJean-Sébastien Pédron default: 10376423301SJean-Sébastien Pédron /* Set the width, unless it was previously 10476423301SJean-Sébastien Pédron * set. For instance, the following options 10576423301SJean-Sébastien Pédron * would all give a width of 5 and not 10: 10676423301SJean-Sébastien Pédron * -10 -w5 10776423301SJean-Sébastien Pédron * -5b10 10876423301SJean-Sébastien Pédron * -5 -10b */ 10976423301SJean-Sébastien Pédron if (width == -1) 11076423301SJean-Sébastien Pédron width = ch - '0'; 11176423301SJean-Sébastien Pédron break; 1129b50d902SRodney W. Grimes } 1139b50d902SRodney W. Grimes break; 1149b50d902SRodney W. Grimes default: 115f589c9aaSPhilippe Charnier usage(); 1169b50d902SRodney W. Grimes } 11776423301SJean-Sébastien Pédron previous_ch = ch; 11876423301SJean-Sébastien Pédron } 1199b50d902SRodney W. Grimes argv += optind; 1209b50d902SRodney W. Grimes argc -= optind; 1219b50d902SRodney W. Grimes 1229b50d902SRodney W. Grimes if (width == -1) 1239b50d902SRodney W. Grimes width = DEFLINEWIDTH; 124fb2582c0STim J. Robbins rval = 0; 1259b50d902SRodney W. Grimes if (!*argv) 1269b50d902SRodney W. Grimes fold(width); 1279b50d902SRodney W. Grimes else for (; *argv; ++argv) 1289b50d902SRodney W. Grimes if (!freopen(*argv, "r", stdin)) { 129fb2582c0STim J. Robbins warn("%s", *argv); 130fb2582c0STim J. Robbins rval = 1; 1319b50d902SRodney W. Grimes } else 1329b50d902SRodney W. Grimes fold(width); 133fb2582c0STim J. Robbins exit(rval); 1349b50d902SRodney W. Grimes } 1359b50d902SRodney W. Grimes 136f589c9aaSPhilippe Charnier static void 137f4ac32deSDavid Malone usage(void) 138f589c9aaSPhilippe Charnier { 13913e06695STim J. Robbins (void)fprintf(stderr, "usage: fold [-bs] [-w width] [file ...]\n"); 140f589c9aaSPhilippe Charnier exit(1); 141f589c9aaSPhilippe Charnier } 142f589c9aaSPhilippe Charnier 14313e06695STim J. Robbins /* 14413e06695STim J. Robbins * Fold the contents of standard input to fit within WIDTH columns (or bytes) 14513e06695STim J. Robbins * and write to standard output. 14613e06695STim J. Robbins * 14713e06695STim J. Robbins * If sflag is set, split the line at the last space character on the line. 14813e06695STim J. Robbins * This flag necessitates storing the line in a buffer until the current 14913e06695STim J. Robbins * column > width, or a newline or EOF is read. 15013e06695STim J. Robbins * 15113e06695STim J. Robbins * The buffer can grow larger than WIDTH due to backspaces and carriage 15213e06695STim J. Robbins * returns embedded in the input stream. 15313e06695STim J. Robbins */ 154f589c9aaSPhilippe Charnier void 155f4ac32deSDavid Malone fold(int width) 1569b50d902SRodney W. Grimes { 15719657ec3STim J. Robbins static wchar_t *buf; 15813e06695STim J. Robbins static int buf_max; 15919657ec3STim J. Robbins int col, i, indx, space; 16019657ec3STim J. Robbins wint_t ch; 1619b50d902SRodney W. Grimes 16213e06695STim J. Robbins col = indx = 0; 16319657ec3STim J. Robbins while ((ch = getwchar()) != WEOF) { 16413e06695STim J. Robbins if (ch == '\n') { 16519657ec3STim J. Robbins wprintf(L"%.*ls\n", indx, buf); 16613e06695STim J. Robbins col = indx = 0; 16713e06695STim J. Robbins continue; 1689b50d902SRodney W. Grimes } 16913e06695STim J. Robbins if ((col = newpos(col, ch)) > width) { 17013e06695STim J. Robbins if (sflag) { 17113e06695STim J. Robbins i = indx; 17219657ec3STim J. Robbins while (--i >= 0 && !iswblank(buf[i])) 17313e06695STim J. Robbins ; 17413e06695STim J. Robbins space = i; 17513e06695STim J. Robbins } 17613e06695STim J. Robbins if (sflag && space != -1) { 17713e06695STim J. Robbins space++; 17819657ec3STim J. Robbins wprintf(L"%.*ls\n", space, buf); 17919657ec3STim J. Robbins wmemmove(buf, buf + space, indx - space); 18013e06695STim J. Robbins indx -= space; 18113e06695STim J. Robbins col = 0; 18213e06695STim J. Robbins for (i = 0; i < indx; i++) 18319657ec3STim J. Robbins col = newpos(col, buf[i]); 18413e06695STim J. Robbins } else { 18519657ec3STim J. Robbins wprintf(L"%.*ls\n", indx, buf); 18613e06695STim J. Robbins col = indx = 0; 18713e06695STim J. Robbins } 18813e06695STim J. Robbins col = newpos(col, ch); 18913e06695STim J. Robbins } 19013e06695STim J. Robbins if (indx + 1 > buf_max) { 19113e06695STim J. Robbins buf_max += LINE_MAX; 19219657ec3STim J. Robbins buf = realloc(buf, sizeof(*buf) * buf_max); 19319657ec3STim J. Robbins if (buf == NULL) 19413e06695STim J. Robbins err(1, "realloc()"); 19513e06695STim J. Robbins } 19613e06695STim J. Robbins buf[indx++] = ch; 19713e06695STim J. Robbins } 1989b50d902SRodney W. Grimes 19913e06695STim J. Robbins if (indx != 0) 20019657ec3STim J. Robbins wprintf(L"%.*ls", indx, buf); 20113e06695STim J. Robbins } 20213e06695STim J. Robbins 20313e06695STim J. Robbins /* 20413e06695STim J. Robbins * Update the current column position for a character. 20513e06695STim J. Robbins */ 20613e06695STim J. Robbins static int 20719657ec3STim J. Robbins newpos(int col, wint_t ch) 20813e06695STim J. Robbins { 20919657ec3STim J. Robbins char buf[MB_LEN_MAX]; 21019657ec3STim J. Robbins size_t len; 21119657ec3STim J. Robbins int w; 21213e06695STim J. Robbins 21319657ec3STim J. Robbins if (bflag) { 21419657ec3STim J. Robbins len = wcrtomb(buf, ch, NULL); 21519657ec3STim J. Robbins col += len; 21619657ec3STim J. Robbins } else 2179b50d902SRodney W. Grimes switch (ch) { 2189b50d902SRodney W. Grimes case '\b': 2199b50d902SRodney W. Grimes if (col > 0) 2209b50d902SRodney W. Grimes --col; 2219b50d902SRodney W. Grimes break; 2229b50d902SRodney W. Grimes case '\r': 2239b50d902SRodney W. Grimes col = 0; 2249b50d902SRodney W. Grimes break; 2259b50d902SRodney W. Grimes case '\t': 22613e06695STim J. Robbins col = (col + 8) & ~7; 2279b50d902SRodney W. Grimes break; 2289b50d902SRodney W. Grimes default: 22919657ec3STim J. Robbins if ((w = wcwidth(ch)) > 0) 23019657ec3STim J. Robbins col += w; 2319b50d902SRodney W. Grimes break; 2329b50d902SRodney W. Grimes } 23313e06695STim J. Robbins 23413e06695STim J. Robbins return (col); 2359b50d902SRodney W. Grimes } 236