coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] fmt: optionalize line width goal


From: Bruce Korb
Subject: [PATCH] fmt: optionalize line width goal
Date: Tue, 20 Mar 2012 08:29:53 -0700
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:10.0.2) Gecko/20120215 Thunderbird/10.0.2


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
@@ -11,6 +11,8 @@ note to the bug-report mailing list (as seen at end of e.g., 
cp --help).
 ## is used to generate the THANKS file.  Note that numerous people listed
 ## here would have been listed as commit authors if we had been using git
 ## for version control when they contributed.
+##
+## Well, not completely true.  It misses sometimes.

 ???                                 address@hidden
 A Costa                             address@hidden
@@ -97,6 +99,7 @@ Brian M. Carlson                    address@hidden
 Brian Silverman                     address@hidden
 Brian Youmans                       address@hidden
 Britton Leo Kerin                   address@hidden
+Bruce Korb                          address@hidden
 Bruce Robertson                     address@hidden
 Carl Johnson                        address@hidden
 Carl Lowenstein                     address@hidden
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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]