diff --git a/src/fmt.c b/src/fmt.c index 89d13a6..68d95f1 --- 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,23 @@ 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; + } + 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 +459,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 (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 (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 +995,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 +1081,10 @@ put_space (int space) out_column++; } } +/* + * Local Variables: + * mode: C + * c-file-style: "gnu" + * indent-tabs-mode: nil + * End: + * end of fmt.c */