11590Srgrimes/*- 21590Srgrimes * Copyright (c) 1990, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * This code is derived from software contributed to Berkeley by 61590Srgrimes * Kevin Ruddy. 71590Srgrimes * 81590Srgrimes * Redistribution and use in source and binary forms, with or without 91590Srgrimes * modification, are permitted provided that the following conditions 101590Srgrimes * are met: 111590Srgrimes * 1. Redistributions of source code must retain the above copyright 121590Srgrimes * notice, this list of conditions and the following disclaimer. 131590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141590Srgrimes * notice, this list of conditions and the following disclaimer in the 151590Srgrimes * documentation and/or other materials provided with the distribution. 161590Srgrimes * 4. Neither the name of the University nor the names of its contributors 171590Srgrimes * may be used to endorse or promote products derived from this software 181590Srgrimes * without specific prior written permission. 191590Srgrimes * 201590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301590Srgrimes * SUCH DAMAGE. 311590Srgrimes */ 321590Srgrimes 331590Srgrimes#ifndef lint 3427270Scharnierstatic const char copyright[] = 351590Srgrimes"@(#) Copyright (c) 1990, 1993\n\ 361590Srgrimes The Regents of the University of California. All rights reserved.\n"; 371590Srgrimes#endif /* not lint */ 381590Srgrimes 391590Srgrimes#ifndef lint 4027270Scharnier#if 0 411590Srgrimesstatic char sccsid[] = "@(#)fold.c 8.1 (Berkeley) 6/6/93"; 4227270Scharnier#endif 431590Srgrimes#endif /* not lint */ 441590Srgrimes 4587751Scharnier#include <sys/cdefs.h> 4687751Scharnier__FBSDID("$FreeBSD: releng/10.2/usr.bin/fold/fold.c 227165 2011-11-06 08:15:23Z ed $"); 4787751Scharnier 4827270Scharnier#include <err.h> 4994978Stjr#include <limits.h> 5095033Sache#include <locale.h> 511590Srgrimes#include <stdio.h> 5227270Scharnier#include <stdlib.h> 53200462Sdelphij#include <string.h> 5427270Scharnier#include <unistd.h> 55131056Stjr#include <wchar.h> 56131056Stjr#include <wctype.h> 571590Srgrimes 581590Srgrimes#define DEFLINEWIDTH 80 591590Srgrimes 6092920Simpvoid fold(int); 61131056Stjrstatic int newpos(int, wint_t); 6292920Simpstatic void usage(void); 6327270Scharnier 64227165Sedstatic int bflag; /* Count bytes, not columns */ 65227165Sedstatic int sflag; /* Split on word boundaries */ 6694978Stjr 6727270Scharnierint 68102944Sdwmalonemain(int argc, char **argv) 691590Srgrimes{ 70214893Sdumbbell int ch, previous_ch; 7197266Stjr int rval, width; 721590Srgrimes 7395033Sache (void) setlocale(LC_CTYPE, ""); 7495033Sache 751590Srgrimes width = -1; 76214893Sdumbbell previous_ch = 0; 77214893Sdumbbell while ((ch = getopt(argc, argv, "0123456789bsw:")) != -1) { 781590Srgrimes switch (ch) { 7994978Stjr case 'b': 8094978Stjr bflag = 1; 8194978Stjr break; 8294978Stjr case 's': 8394978Stjr sflag = 1; 8494978Stjr break; 851590Srgrimes case 'w': 861590Srgrimes if ((width = atoi(optarg)) <= 0) { 8727270Scharnier errx(1, "illegal width value"); 881590Srgrimes } 891590Srgrimes break; 901590Srgrimes case '0': case '1': case '2': case '3': case '4': 911590Srgrimes case '5': case '6': case '7': case '8': case '9': 92214893Sdumbbell /* Accept a width as eg. -30. Note that a width 93214893Sdumbbell * specified using the -w option is always used prior 94214893Sdumbbell * to this undocumented option. */ 95214893Sdumbbell switch (previous_ch) { 96214893Sdumbbell case '0': case '1': case '2': case '3': case '4': 97214893Sdumbbell case '5': case '6': case '7': case '8': case '9': 98214893Sdumbbell /* The width is a number with multiple digits: 99214893Sdumbbell * add the last one. */ 100214893Sdumbbell width = width * 10 + (ch - '0'); 101214893Sdumbbell break; 102214893Sdumbbell default: 103214893Sdumbbell /* Set the width, unless it was previously 104214893Sdumbbell * set. For instance, the following options 105214893Sdumbbell * would all give a width of 5 and not 10: 106214893Sdumbbell * -10 -w5 107214893Sdumbbell * -5b10 108214893Sdumbbell * -5 -10b */ 109214893Sdumbbell if (width == -1) 110214893Sdumbbell width = ch - '0'; 111214893Sdumbbell break; 1121590Srgrimes } 1131590Srgrimes break; 1141590Srgrimes default: 11527270Scharnier usage(); 1161590Srgrimes } 117214893Sdumbbell previous_ch = ch; 118214893Sdumbbell } 1191590Srgrimes argv += optind; 1201590Srgrimes argc -= optind; 1211590Srgrimes 1221590Srgrimes if (width == -1) 1231590Srgrimes width = DEFLINEWIDTH; 12497266Stjr rval = 0; 1251590Srgrimes if (!*argv) 1261590Srgrimes fold(width); 1271590Srgrimes else for (; *argv; ++argv) 1281590Srgrimes if (!freopen(*argv, "r", stdin)) { 12997266Stjr warn("%s", *argv); 13097266Stjr rval = 1; 1311590Srgrimes } else 1321590Srgrimes fold(width); 13397266Stjr exit(rval); 1341590Srgrimes} 1351590Srgrimes 13627270Scharnierstatic void 137102944Sdwmaloneusage(void) 13827270Scharnier{ 13994978Stjr (void)fprintf(stderr, "usage: fold [-bs] [-w width] [file ...]\n"); 14027270Scharnier exit(1); 14127270Scharnier} 14227270Scharnier 14394978Stjr/* 14494978Stjr * Fold the contents of standard input to fit within WIDTH columns (or bytes) 14594978Stjr * and write to standard output. 14694978Stjr * 14794978Stjr * If sflag is set, split the line at the last space character on the line. 14894978Stjr * This flag necessitates storing the line in a buffer until the current 14994978Stjr * column > width, or a newline or EOF is read. 15094978Stjr * 15194978Stjr * The buffer can grow larger than WIDTH due to backspaces and carriage 15294978Stjr * returns embedded in the input stream. 15394978Stjr */ 15427270Scharniervoid 155102944Sdwmalonefold(int width) 1561590Srgrimes{ 157131056Stjr static wchar_t *buf; 15894978Stjr static int buf_max; 159131056Stjr int col, i, indx, space; 160131056Stjr wint_t ch; 1611590Srgrimes 16294978Stjr col = indx = 0; 163131056Stjr while ((ch = getwchar()) != WEOF) { 16494978Stjr if (ch == '\n') { 165131056Stjr wprintf(L"%.*ls\n", indx, buf); 16694978Stjr col = indx = 0; 16794978Stjr continue; 1681590Srgrimes } 16994978Stjr if ((col = newpos(col, ch)) > width) { 17094978Stjr if (sflag) { 17194978Stjr i = indx; 172131056Stjr while (--i >= 0 && !iswblank(buf[i])) 17394978Stjr ; 17494978Stjr space = i; 17594978Stjr } 17694978Stjr if (sflag && space != -1) { 17794978Stjr space++; 178131056Stjr wprintf(L"%.*ls\n", space, buf); 179131056Stjr wmemmove(buf, buf + space, indx - space); 18094978Stjr indx -= space; 18194978Stjr col = 0; 18294978Stjr for (i = 0; i < indx; i++) 183131056Stjr col = newpos(col, buf[i]); 18494978Stjr } else { 185131056Stjr wprintf(L"%.*ls\n", indx, buf); 18694978Stjr col = indx = 0; 18794978Stjr } 18894978Stjr col = newpos(col, ch); 1891590Srgrimes } 19094978Stjr if (indx + 1 > buf_max) { 19194978Stjr buf_max += LINE_MAX; 192131056Stjr buf = realloc(buf, sizeof(*buf) * buf_max); 193131056Stjr if (buf == NULL) 19494978Stjr err(1, "realloc()"); 19594978Stjr } 19694978Stjr buf[indx++] = ch; 19794978Stjr } 1981590Srgrimes 19994978Stjr if (indx != 0) 200131056Stjr wprintf(L"%.*ls", indx, buf); 20194978Stjr} 20294978Stjr 20394978Stjr/* 20494978Stjr * Update the current column position for a character. 20594978Stjr */ 20694978Stjrstatic int 207131056Stjrnewpos(int col, wint_t ch) 20894978Stjr{ 209131056Stjr char buf[MB_LEN_MAX]; 210131056Stjr size_t len; 211131056Stjr int w; 21294978Stjr 213131056Stjr if (bflag) { 214131056Stjr len = wcrtomb(buf, ch, NULL); 215131056Stjr col += len; 216131056Stjr } else 2171590Srgrimes switch (ch) { 2181590Srgrimes case '\b': 2191590Srgrimes if (col > 0) 2201590Srgrimes --col; 2211590Srgrimes break; 2221590Srgrimes case '\r': 2231590Srgrimes col = 0; 2241590Srgrimes break; 2251590Srgrimes case '\t': 22694978Stjr col = (col + 8) & ~7; 2271590Srgrimes break; 2281590Srgrimes default: 229131056Stjr if ((w = wcwidth(ch)) > 0) 230131056Stjr col += w; 2311590Srgrimes break; 2321590Srgrimes } 23394978Stjr 23494978Stjr return (col); 2351590Srgrimes} 236