Package: coreutils;
Reported by: Bruce Korb <bruce.korb <at> gmail.com>
Date: Mon, 19 Mar 2012 19:18:02 UTC
Severity: wishlist
Tags: patch
Message #31 received at 11044 <at> debbugs.gnu.org (full text, mbox):
From: Bruce Korb <bruce.korb <at> gmail.com> To: Eric Blake <eblake <at> redhat.com> Cc: 11044 <at> debbugs.gnu.org, Bruce Korb <bruce.korb <at> gmail.com> Subject: Re: bug#11044: bug & RFE Date: Fri, 30 Mar 2012 14:37:15 -0700
Hi Eric, I guess nobody is listening. BSD's implementation allows a goal specification and has a different default goal width computation anyway. This change adds a "-g" option and allows the first two numeric operands to represent the goal width and actual line width. * src/fmt.c (main): implement the new option (check_for_goals): new function to implement the operands Based on BSD's and Plan-9's fmt programs. --- THANKS.in | 3 ++ doc/coreutils.texi | 23 +++++++++++-- src/fmt.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 106 insertions(+), 8 deletions(-) diff --git a/THANKS.in b/THANKS.in index d23f7b3..9a525c4 100644 --- a/THANKS.in +++ b/THANKS.in @@ -97,6 +99,7 @@ Brian M. Carlson sandals <at> crustytoothpaste.ath.cx Brian Silverman bsilverman <at> conceptxdesign.com Brian Youmans 3diff <at> gnu.org Britton Leo Kerin fsblk <at> aurora.uaf.edu +Bruce Korb bkorb <at> gnu.org Bruce Robertson brucer <at> theodolite.dyndns.org Carl Johnson carlj <at> cjlinux.home.org Carl Lowenstein cdl <at> mpl.UCSD.EDU diff --git a/doc/coreutils.texi b/doc/coreutils.texi index 835c245..91ca957 100644 --- a/doc/coreutils.texi +++ b/doc/coreutils.texi @@ -2133,7 +2133,7 @@ These commands reformat the contents of files. a given number of characters (75 by default). Synopsis: @example -fmt [@var{option}]@dots{} [@var{file}]@dots{} +fmt [@var{option}]@dots{} [@var{goal} [@var{width}]] [@var{file}]@dots{} @end example @command{fmt} reads from the specified @var{file} arguments (or standard @@ -2144,6 +2144,13 @@ preserved in the output; successive input lines with different indentation are not joined; tabs are expanded on input and introduced on output. +@var{goal} and @var{width} are only recognized if neither +@var{-g}/@var{--goal} nor @var{-w}/@var{--width} have been specified; and if +the strings represent numbers; and if the numbers do not exceed about 2,500; +and if these strings do not match existing file names. If @var{GOAL} is +provided but @var{width} not, then @var{width} will be set to @var{goal} +plus 10. + @cindex line-breaking @cindex sentences and line-breaking @cindex Knuth, Donald E. @@ -2203,9 +2210,17 @@ between sentences to two spaces. @opindex -@var{width} @opindex -w @opindex --width -Fill output lines up to @var{width} characters (default 75). @command{fmt} -initially tries to make lines about 7% shorter than this, to give it -room to balance line lengths. +Fill output lines up to @var{width} characters (default 75 or @var{goal} plus 10, +if @var{goal} is provided). + +@item -@var{goal} +@itemx -g @var{goal} +@itemx --goal=@var{goal} +@opindex -@var{goal} +@opindex -g +@opindex --goal +@command{fmt} initially tries to make lines @var{goal} characters wide. +By default, this is 7% shorter than @var{width}. @item -p @var{prefix} @itemx --prefix=@var{prefix} diff --git a/src/fmt.c b/src/fmt.c index 89d13a6..95ae149 100644 --- a/src/fmt.c +++ b/src/fmt.c @@ -68,7 +68,7 @@ typedef long int COST; #define SQR(n) ((n) * (n)) #define EQUIV(n) SQR ((COST) (n)) -/* Cost of a filled line n chars longer or shorter than best_width. */ +/* Cost of a filled line n chars longer or shorter than goal_width. */ #define SHORT_COST(n) EQUIV ((n) * 10) /* Cost of the difference between adjacent filled lines. */ @@ -167,6 +167,7 @@ static void put_paragraph (WORD *finish); static void put_line (WORD *w, int indent); static void put_word (WORD *w); static void put_space (int space); +static void check_for_goals (char ** argv); /* Option values. */ @@ -201,7 +202,7 @@ static int prefix_lead_space; static int prefix_length; /* The preferred width of text lines, set to LEEWAY % less than max_width. */ -static int best_width; +static int goal_width; /* Dynamic variables. */ @@ -286,6 +287,7 @@ Mandatory arguments to long options are mandatory for short options too.\n\ -t, --tagged-paragraph indentation of first line different from second\n\ -u, --uniform-spacing one space between words, two after sentences\n\ -w, --width=WIDTH maximum line width (default of 75 columns)\n\ + -g, --goal=WIDTH goal width (default of 93% of width)\n\ "), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); @@ -308,6 +310,7 @@ static struct option const long_options[] = {"tagged-paragraph", no_argument, NULL, 't'}, {"uniform-spacing", no_argument, NULL, 'u'}, {"width", required_argument, NULL, 'w'}, + {"goal", required_argument, NULL, 'g'}, {GETOPT_HELP_OPTION_DECL}, {GETOPT_VERSION_OPTION_DECL}, {NULL, 0, NULL, 0}, @@ -319,6 +322,7 @@ main (int argc, char **argv) int optchar; bool ok = true; char const *max_width_option = NULL; + char const *goal_width_option = NULL; initialize_main (&argc, &argv); set_program_name (argv[0]); @@ -376,6 +380,10 @@ main (int argc, char **argv) max_width_option = optarg; break; + case 'g': + goal_width_option = optarg; + break; + case 'p': set_prefix (optarg); break; @@ -398,7 +406,25 @@ main (int argc, char **argv) max_width = tmp; } - best_width = max_width * (2 * (100 - LEEWAY) + 1) / 200; + if (goal_width_option) + { + /* Limit goal_width to max_width. */ + unsigned long int tmp; + if (! (xstrtoul (goal_width_option, NULL, 10, &tmp, "") == LONGINT_OK + && tmp <= max_width)) + error (EXIT_FAILURE, 0, _("invalid width: %s"), + quote (goal_width_option)); + goal_width = tmp; + if (max_width_option == NULL) + max_width = goal_width + 10; + } + else + { + goal_width = max_width * (2 * (100 - LEEWAY) + 1) / 200; + } + + if ((max_width_option == NULL) && (goal_width_option == NULL)) + check_for_goals (argv); if (optind == argc) fmt (stdin); @@ -435,6 +461,53 @@ main (int argc, char **argv) exit (ok ? EXIT_SUCCESS : EXIT_FAILURE); } +/* Check the first two operands for being numbers without a file by that name. + If there are no such files and the numbers are not too big, then accept + them as -g and -w options, respectively. */ + +static void +check_for_goals (char ** argv) +{ + unsigned long v; + + /* see if the first operand is a number. That means there is no file + by that name and the operand fully translates to a number. */ + char * num = argv[optind]; + if ((num == NULL) || access (num, R_OK)) + return; + errno = 0; + v = strtoul (num, &num, 0); + if ((errno == 0) && (*num == '\0') && (v > 0) && (v < MAXCHARS/2)) + goal_width = v; + else + return; + optind++; + + /* see if the second operand is a number. That means there is no file + by that name and the operand fully translates to a number. */ + num = argv[optind]; + if ((num == NULL) || access (num, R_OK)) + { + max_width = goal_width + 10; + return; + } + errno = 0; + v = strtoul (num, &num, 0); + if ((errno == 0) && (*num == '\0') && (v > 0) && (v < MAXCHARS/2)) + { + max_width = v; + if (goal_width > max_width) + error (EXIT_FAILURE, 0, _("goal exceeds width: %u > %u"), + goal_width, max_width); + } + else + { + max_width = goal_width + 10; + return; + } + optind++; +} + /* Trim space from the front and back of the string P, yielding the prefix, and record the lengths of the prefix and the space trimmed. */ @@ -924,7 +997,7 @@ line_cost (WORD *next, int len) if (next == word_limit) return 0; - n = best_width - len; + n = goal_width - len; cost = SHORT_COST (n); if (next->next_break != word_limit) { @@ -1010,3 +1083,10 @@ put_space (int space) out_column++; } } +/* + * Local Variables: + * mode: C + * c-file-style: "gnu" + * indent-tabs-mode: nil + * End: + * end of fmt.c */ -- 1.7.7
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.