From 13e06695bf59220c5d79acfce70fa5a97afabedd Mon Sep 17 00:00:00 2001 From: "Tim J. Robbins" Date: Thu, 18 Apr 2002 03:33:51 +0000 Subject: [PATCH] Add the -b option (break at byte position, not column number) and the -s option (try to break at word bounaries) for SUSv3 conformance. Partially based on the NetBSD version, with the following changes: - style(9) - break on s, not spaces, per POSIX (and GNU) - when looking for last space on line, search backwards instead of forwards; less comparisons needed this way. - use LINE_MAX macro instead of a magic number and a comment saying it is LINE_MAX. PR: 36245 Reviewed by: mike Obtained from: NetBSD (partially) --- usr.bin/fold/fold.1 | 16 ++++++- usr.bin/fold/fold.c | 112 ++++++++++++++++++++++++++++++++------------ 2 files changed, 98 insertions(+), 30 deletions(-) diff --git a/usr.bin/fold/fold.1 b/usr.bin/fold/fold.1 index 63a52f287ba7..071f39a12315 100644 --- a/usr.bin/fold/fold.1 +++ b/usr.bin/fold/fold.1 @@ -32,7 +32,7 @@ .\" @(#)fold.1 8.1 (Berkeley) 6/6/93 .\" $FreeBSD$ .\" -.Dd June 6, 1993 +.Dd April 17, 2002 .Dt FOLD 1 .Os .Sh NAME @@ -40,6 +40,7 @@ .Nd "fold long lines for finite width output device" .Sh SYNOPSIS .Nm +.Op Fl bs .Op Fl w Ar width .Op Ar .Sh DESCRIPTION @@ -50,6 +51,14 @@ breaking the lines to have a maximum of 80 characters. .Pp The following option is available: .Bl -tag -width indent +.It Fl b +Count +.Ar width +in bytes rather than column positions. +.It Fl s +Fold line after the last blank character within the first +.Ar width +column positions (or bytes). .It Fl w Ar width Specify a line width to use instead of the default 80 characters. .Ar Width @@ -61,5 +70,10 @@ before using .El .Sh SEE ALSO .Xr expand 1 +.Sh STANDARDS +The +.Nm +utility conforms to +.St -p1003.1-2001 . .Sh BUGS If underlining is present it may be messed up by folding. diff --git a/usr.bin/fold/fold.c b/usr.bin/fold/fold.c index 33208ae0d4c5..68a3ebed5fb4 100644 --- a/usr.bin/fold/fold.c +++ b/usr.bin/fold/fold.c @@ -49,16 +49,23 @@ static char sccsid[] = "@(#)fold.c 8.1 (Berkeley) 6/6/93"; #include __FBSDID("$FreeBSD$"); +#include #include +#include #include #include +#include #include #define DEFLINEWIDTH 80 void fold(int); +static int newpos(int, int); static void usage(void); +int bflag; /* Count bytes, not columns */ +int sflag; /* Split on word boundaries */ + int main(argc, argv) int argc; @@ -69,8 +76,14 @@ main(argc, argv) char *p; width = -1; - while ((ch = getopt(argc, argv, "0123456789w:")) != -1) + while ((ch = getopt(argc, argv, "0123456789bsw:")) != -1) switch (ch) { + case 'b': + bflag = 1; + break; + case 's': + sflag = 1; + break; case 'w': if ((width = atoi(optarg)) <= 0) { errx(1, "illegal width value"); @@ -107,57 +120,98 @@ main(argc, argv) static void usage() { - (void)fprintf(stderr, "usage: fold [-w width] [file ...]\n"); + (void)fprintf(stderr, "usage: fold [-bs] [-w width] [file ...]\n"); exit(1); } +/* + * Fold the contents of standard input to fit within WIDTH columns (or bytes) + * and write to standard output. + * + * If sflag is set, split the line at the last space character on the line. + * This flag necessitates storing the line in a buffer until the current + * column > width, or a newline or EOF is read. + * + * The buffer can grow larger than WIDTH due to backspaces and carriage + * returns embedded in the input stream. + */ void fold(width) register int width; { - register int ch, col, new; + static char *buf; + static int buf_max; + int ch, col, i, indx, space; - for (col = 0;;) { - switch (ch = getchar()) { - case EOF: - return; - case '\b': - new = col ? col - 1 : 0; - break; - case '\n': - case '\r': - new = 0; - break; - case '\t': - new = (col + 8) & ~7; - break; - default: - new = col + 1; - break; - } - - if (new > width) { + col = indx = 0; + while ((ch = getchar()) != EOF) { + if (ch == '\n') { + if (indx != 0) + fwrite(buf, 1, indx, stdout); putchar('\n'); - col = 0; + col = indx = 0; + continue; } - putchar(ch); + if ((col = newpos(col, ch)) > width) { + if (sflag) { + i = indx; + while (--i >= 0 && !isblank(buf[i])) + ; + space = i; + } + if (sflag && space != -1) { + space++; + fwrite(buf, 1, space, stdout); + memmove(buf, buf + space, indx - space); + indx -= space; + col = 0; + for (i = 0; i < indx; i++) + col = newpos(col, buf[i]); + } else { + fwrite(buf, 1, indx, stdout); + col = indx = 0; + } + putchar('\n'); + col = newpos(col, ch); + } + if (indx + 1 > buf_max) { + buf_max += LINE_MAX; + if ((buf = realloc(buf, buf_max)) == NULL) + err(1, "realloc()"); + } + buf[indx++] = ch; + } + if (indx != 0) + fwrite(buf, 1, indx, stdout); +} + +/* + * Update the current column position for a character. + */ +static int +newpos(col, ch) + int col, ch; +{ + + if (bflag) + ++col; + else switch (ch) { case '\b': if (col > 0) --col; break; - case '\n': case '\r': col = 0; break; case '\t': - col += 8; - col &= ~7; + col = (col + 8) & ~7; break; default: ++col; break; } - } + + return (col); }