/* GNU fmt -- simple text formatter. This is the fmt utility
Copyright (C) 1994-2018 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */ The GNUv3 license
/* Written by Ross Paterson <rap@doc.ic.ac.uk>. */
#include <config.h> Provides system specific information
#include <stdio.h> Provides standard I/O capability
#include <sys/types.h> Provides system data types
#include <getopt.h> ...!includes auto-comment...
#include <assert.h> ...!includes auto-comment...
/* Redefine. Otherwise, systems (Unicos for one) with headers that define
it to be a type get syntax errors for the variable declaration below. */
#define word unused_word_type Line 27
#include "system.h" ...!includes auto-comment...
#include "error.h" ...!includes auto-comment...
#include "fadvise.h" ...!includes auto-comment...
#include "xdectoint.h" ...!includes auto-comment...
/* The official name of this program (e.g., no 'g' prefix). */
#define PROGRAM_NAME "fmt" Line 35
#define AUTHORS proper_name ("Ross Paterson") Line 37
/* The following parameters represent the program's idea of what is
"best". Adjust to taste, subject to the caveats given. */
/* Default longest permitted line length (max_width). */
#define WIDTH 75 Line 43
/* Prefer lines to be LEEWAY % shorter than the maximum width, giving
room for optimization. */
#define LEEWAY 7 Line 47
/* The default secondary indent of tagged paragraph used for unindented
one-line paragraphs not preceded by any multi-line paragraphs. */
#define DEF_INDENT 3 Line 51
/* Costs and bonuses are expressed as the equivalent departure from the
optimal line length, multiplied by 10. e.g. assigning something a
cost of 50 means that it is as bad as a line 5 characters too short
or too long. The definition of SHORT_COST(n) should not be changed.
However, EQUIV(n) may need tuning. */
/* FIXME: "fmt" misbehaves given large inputs or options. One
possible workaround for part of the problem is to change COST to be
a floating-point type. There are other problems besides COST,
though; see MAXWORDS below. */
typedef long int COST; Line 64
#define MAXCOST TYPE_MAXIMUM (COST) Line 66
#define SQR(n) ((n) * (n)) Line 68
#define EQUIV(n) SQR ((COST) (n)) Line 69
/* Cost of a filled line n chars longer or shorter than goal_width. */
#define SHORT_COST(n) EQUIV ((n) * 10) Line 72
/* Cost of the difference between adjacent filled lines. */
#define RAGGED_COST(n) (SHORT_COST (n) / 2) Line 75
/* Basic cost per line. */
#define LINE_COST EQUIV (70) Line 78
/* Cost of breaking a line after the first word of a sentence, where
the length of the word is N. */
#define WIDOW_COST(n) (EQUIV (200) / ((n) + 2)) Line 82
/* Cost of breaking a line before the last word of a sentence, where
the length of the word is N. */
#define ORPHAN_COST(n) (EQUIV (150) / ((n) + 2)) Line 86
/* Bonus for breaking a line at the end of a sentence. */
#define SENTENCE_BONUS EQUIV (50) Line 89
/* Cost of breaking a line after a period not marking end of a sentence.
With the definition of sentence we are using (borrowed from emacs, see
get_line()) such a break would then look like a sentence break. Hence
we assign a very high cost -- it should be avoided unless things are
really bad. */
#define NOBREAK_COST EQUIV (600) Line 96
/* Bonus for breaking a line before open parenthesis. */
#define PAREN_BONUS EQUIV (40) Line 99
/* Bonus for breaking a line after other punctuation. */
#define PUNCT_BONUS EQUIV(40) Line 102
/* Credit for breaking a long paragraph one line later. */
#define LINE_CREDIT EQUIV(3) Line 105
/* Size of paragraph buffer, in words and characters. Longer paragraphs
are handled neatly (cf. flush_paragraph()), so long as these values
are considerably greater than required by the width. These values
cannot be extended indefinitely: doing so would run into size limits
and/or cause more overflows in cost calculations. FIXME: Remove these
arbitrary limits. */
#define MAXWORDS 1000 Line 114
#define MAXCHARS 5000 Line 115
/* Extra ctype(3)-style macros. */
#define isopen(c) (strchr ("(['`\"", c) != NULL) Line 119
#define isclose(c) (strchr (")]'\"", c) != NULL) Line 120
#define isperiod(c) (strchr (".?!", c) != NULL) Line 121
/* Size of a tab stop, for expansion on input and re-introduction on
output. */
#define TABWIDTH 8 Line 125
/* Word descriptor structure. */
typedef struct Word WORD; Line 129
struct Word Line 131
{
/* Static attributes determined during input. */
const char *text; /* the text of the word */ Line 136
int length; /* length of this word */ Line 137
int space; /* the size of the following space */ Line 138
unsigned int paren:1; /* starts with open paren */ Line 139
unsigned int period:1; /* ends in [.?!])* */ Line 140
unsigned int punct:1; /* ends in punctuation */ Line 141
unsigned int final:1; /* end of sentence */ Line 142
/* The remaining fields are computed during the optimization. */
int line_length; /* length of the best line starting here */ Line 146
COST best_cost; /* cost of best paragraph starting here */ Line 147
WORD *next_break; /* break which achieves best_cost */ Line 148
};
/* Forward declarations. */
static void set_prefix (char *p); Line 153
static void fmt (FILE *f); Line 154
static bool get_paragraph (FILE *f); Line 155
static int get_line (FILE *f, int c); Line 156
static int get_prefix (FILE *f); Line 157
static int get_space (FILE *f, int c); Line 158
static int copy_rest (FILE *f, int c); Line 159
static bool same_para (int c); Line 160
static void flush_paragraph (void); Line 161
static void fmt_paragraph (void); Line 162
static void check_punctuation (WORD *w); Line 163
static COST base_cost (WORD *this); Line 164
static COST line_cost (WORD *next, int len); Line 165
static void put_paragraph (WORD *finish); Line 166
static void put_line (WORD *w, int indent); Line 167
static void put_word (WORD *w); Line 168
static void put_space (int space); Line 169
/* Option values. */
/* If true, first 2 lines may have different indent (default false). */
static bool crown; Line 174
/* If true, first 2 lines _must_ have different indent (default false). */
static bool tagged; Line 177
/* If true, each line is a paragraph on its own (default false). */
static bool split; Line 180
/* If true, don't preserve inter-word spacing (default false). */
static bool uniform; Line 183
/* Prefix minus leading and trailing spaces (default ""). */
static const char *prefix; Line 186
/* User-supplied maximum line width (default WIDTH). The only output
lines longer than this will each comprise a single word. */
static int max_width; Line 190
/* Values derived from the option values. */
/* The length of prefix minus leading space. */
static int prefix_full_length; Line 195
/* The length of the leading space trimmed from the prefix. */
static int prefix_lead_space; Line 198
/* The length of prefix minus leading and trailing space. */
static int prefix_length; Line 201
/* The preferred width of text lines, set to LEEWAY % less than max_width. */
static int goal_width; Line 204
/* Dynamic variables. */
/* Start column of the character most recently read from the input file. */
static int in_column; Line 209
/* Start column of the next character to be written to stdout. */
static int out_column; Line 212
/* Space for the paragraph text -- longer paragraphs are handled neatly
(cf. flush_paragraph()). */
static char parabuf[MAXCHARS]; Line 216
/* A pointer into parabuf, indicating the first unused character position. */
static char *wptr; Line 219
/* The words of a paragraph -- longer paragraphs are handled neatly
(cf. flush_paragraph()). */
static WORD word[MAXWORDS]; Line 223
/* A pointer into the above word array, indicating the first position
after the last complete word. Sometimes it will point at an incomplete
word. */
static WORD *word_limit; Line 228
/* If true, current input file contains tab characters, and so tabs can be
used for white space on output. */
static bool tabs; Line 232
/* Space before trimmed prefix on each line of the current paragraph. */
static int prefix_indent; Line 235
/* Indentation of the first line of the current paragraph. */
static int first_indent; Line 238
/* Indentation of other lines of the current paragraph */
static int other_indent; Line 241
/* To detect the end of a paragraph, we need to look ahead to the first
non-blank character after the prefix on the next line, or the first
character on the following line that failed to match the prefix.
We can reconstruct the lookahead from that character (next_char), its
position on the line (in_column) and the amount of space before the
prefix (next_prefix_indent). See get_paragraph() and copy_rest(). */
/* The last character read from the input file. */
static int next_char; Line 251
/* The space before the trimmed prefix (or part of it) on the next line
after the current paragraph. */
static int next_prefix_indent; Line 255
/* If nonzero, the length of the last line output in the current
paragraph, used to charge for raggedness at the split point for long
paragraphs chosen by fmt_paragraph(). */
static int last_line_length; Line 260
void Line 262
usage (int status) Line 263
{
if (status != EXIT_SUCCESS) Line 265
emit_try_help (); ...!common auto-comment...
else Line 267
{
printf (_("Usage: %s [-WIDTH] [OPTION]... [FILE]...\n"), program_name); Line 269
fputs (_("\ Line 270
Reformat each paragraph in the FILE(s), writing to standard output.\n\ Line 271
The option -WIDTH is an abbreviated form of --width=DIGITS.\n\ Line 272
"), stdout); Line 273
emit_stdin_note (); ...!common auto-comment...
emit_mandatory_arg_note (); ...!common auto-comment...
fputs (_("\ Line 278
-c, --crown-margin preserve indentation of first two lines\n\ Line 279
-p, --prefix=STRING reformat only lines beginning with STRING,\n\ Line 280
reattaching the prefix to reformatted lines\n\ Line 281
-s, --split-only split long lines, but do not refill\n\ Line 282
"), Line 283
stdout); Line 284
/* Tell xgettext that the "% o" below is not a printf-style
format string: xgettext:no-c-format */
fputs (_("\ Line 287
-t, --tagged-paragraph indentation of first line different from second\n\ Line 288
-u, --uniform-spacing one space between words, two after sentences\n\ Line 289
-w, --width=WIDTH maximum line width (default of 75 columns)\n\ Line 290
-g, --goal=WIDTH goal width (default of 93% of width)\n\ Line 291
"), stdout); Line 292
fputs (HELP_OPTION_DESCRIPTION, stdout); Line 293
fputs (VERSION_OPTION_DESCRIPTION, stdout); Line 294
emit_ancillary_info (PROGRAM_NAME); Line 295
}
exit (status); Line 297
} Block 2
/* Decode options and launch execution. */
static struct option const long_options[] = Line 302
{
{"crown-margin", no_argument, NULL, 'c'}, Line 304
{"prefix", required_argument, NULL, 'p'}, Line 305
{"split-only", no_argument, NULL, 's'}, Line 306
{"tagged-paragraph", no_argument, NULL, 't'}, Line 307
{"uniform-spacing", no_argument, NULL, 'u'}, Line 308
{"width", required_argument, NULL, 'w'}, Line 309
{"goal", required_argument, NULL, 'g'}, Line 310
{GETOPT_HELP_OPTION_DECL}, Line 311
{GETOPT_VERSION_OPTION_DECL}, Line 312
{NULL, 0, NULL, 0}, Line 313
}; Block 3
int
main (int argc, char **argv) Line 317
{
int optchar; Line 319
bool ok = true; Line 320
char const *max_width_option = NULL; Line 321
char const *goal_width_option = NULL; Line 322
initialize_main (&argc, &argv); VMS-specific entry point handling wildcard expansion
set_program_name (argv[0]); Retains program name and discards path
setlocale (LC_ALL, ""); Sets up internationalization (i18n)
bindtextdomain (PACKAGE, LOCALEDIR); Assigns i18n directorySets text domain for _() [gettext()] function
textdomain (PACKAGE); Sets text domain for _() [gettext()] function
atexit (close_stdout); Close stdout on exit (see gnulib)
crown = tagged = split = uniform = false; Line 332
max_width = WIDTH; Line 333
prefix = ""; Line 334
prefix_length = prefix_lead_space = prefix_full_length = 0; Line 335
if (argc > 1 && argv[1][0] == '-' && ISDIGIT (argv[1][1])) Line 337
{
/* Old option syntax; a dash followed by one or more digits. */
max_width_option = argv[1] + 1; Line 340
/* Make the option we just parsed invisible to getopt. */
argv[1] = argv[0]; Line 343
argv++; Line 344
argc--; Line 345
}
while ((optchar = getopt_long (argc, argv, "0123456789cstuw:p:g:", Line 348
long_options, NULL)) Line 349
!= -1) Line 350
switch (optchar) Line 351
{
default: Line 353
if (ISDIGIT (optchar)) Line 354
error (0, 0, _("invalid option -- %c; -WIDTH is recognized\ Line 355
only when it is the first\noption; use -w N instead"), Line 356
optchar); Line 357
usage (EXIT_FAILURE); Line 358
case 'c': Line 360
crown = true; Line 361
break; Line 362
case 's': Line 364
split = true; Line 365
break; Line 366
case 't': Line 368
tagged = true; Line 369
break; Line 370
case 'u': Line 372
uniform = true; Line 373
break; Line 374
case 'w': Line 376
max_width_option = optarg; Line 377
break; Line 378
case 'g': Line 380
goal_width_option = optarg; Line 381
break; Line 382
case 'p': Line 384
set_prefix (optarg); Line 385
break; Line 386
case_GETOPT_HELP_CHAR; Line 388
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); Line 390
}
if (max_width_option) Line 394
{
/* Limit max_width to MAXCHARS / 2; otherwise, the resulting
output can be quite ugly. */
max_width = xdectoumax (max_width_option, 0, MAXCHARS / 2, "", Line 398
_("invalid width"), 0); Line 399
}
if (goal_width_option) Line 402
{
/* Limit goal_width to max_width. */
goal_width = xdectoumax (goal_width_option, 0, max_width, "", Line 405
_("invalid width"), 0); Line 406
if (max_width_option == NULL) Line 407
max_width = goal_width + 10; Line 408
}
else Line 410
{
goal_width = max_width * (2 * (100 - LEEWAY) + 1) / 200; Line 412
}
if (optind == argc) Line 415
fmt (stdin); Line 416
else Line 417
{
for (; optind < argc; optind++) Line 419
{
char *file = argv[optind]; Line 421
if (STREQ (file, "-")) Line 422
fmt (stdin); Line 423
else Line 424
{
FILE *in_stream; Line 426
in_stream = fopen (file, "r"); Line 427...!syscalls auto-comment...
if (in_stream != NULL) Line 428
{
fmt (in_stream); Line 430
if (fclose (in_stream) == EOF) Line 431...!syscalls auto-comment...
{
error (0, errno, "%s", quotef (file)); Line 433
ok = false; Line 434
}
}
else Line 437
{
error (0, errno, _("cannot open %s for reading"), Line 439
quoteaf (file)); Line 440
ok = false; Line 441
}
}
}
}
return ok ? EXIT_SUCCESS : EXIT_FAILURE; Line 447
} Block 4
/* 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. */
static void Line 453
set_prefix (char *p) Line 454
{
char *s; Line 456
prefix_lead_space = 0; Line 458
while (*p == ' ') Line 459
{
prefix_lead_space++; Line 461
p++; Line 462
}
prefix = p; Line 464
prefix_full_length = strlen (p); Line 465
s = p + prefix_full_length; Line 466
while (s > p && s[-1] == ' ') Line 467
s--; Line 468
*s = '\0'; Line 469
prefix_length = s - p; Line 470
} Block 5
/* read file F and send formatted output to stdout. */
static void Line 475
fmt (FILE *f) Line 476
{
fadvise (f, FADVISE_SEQUENTIAL); Line 478...!syscalls auto-comment...
tabs = false; Line 479
other_indent = 0; Line 480
next_char = get_prefix (f); Line 481
while (get_paragraph (f)) Line 482
{
fmt_paragraph (); Line 484
put_paragraph (word_limit); Line 485
}
} Block 6
/* Set the global variable 'other_indent' according to SAME_PARAGRAPH
and other global variables. */
static void Line 492
set_other_indent (bool same_paragraph) Line 493
{
if (split) Line 495
other_indent = first_indent; Line 496
else if (crown) Line 497
{
other_indent = (same_paragraph ? in_column : first_indent); Line 499
}
else if (tagged) Line 501
{
if (same_paragraph && in_column != first_indent) Line 503
{
other_indent = in_column; Line 505
}
/* Only one line: use the secondary indent from last time if it
splits, or 0 if there have been no multi-line paragraphs in the
input so far. But if these rules make the two indents the same,
pick a new secondary indent. */
else if (other_indent == first_indent) Line 513
other_indent = first_indent == 0 ? DEF_INDENT : 0; Line 514
}
else Line 516
{
other_indent = first_indent; Line 518
}
} Block 7
/* Read a paragraph from input file F. A paragraph consists of a
maximal number of non-blank (excluding any prefix) lines subject to:
* In split mode, a paragraph is a single non-blank line.
* In crown mode, the second and subsequent lines must have the
same indentation, but possibly different from the indent of the
first line.
* Tagged mode is similar, but the first and second lines must have
different indentations.
* Otherwise, all lines of a paragraph must have the same indent.
If a prefix is in effect, it must be present at the same indent for
each line in the paragraph.
Return false if end-of-file was encountered before the start of a
paragraph, else true. */
static bool Line 537
get_paragraph (FILE *f) Line 538
{
int c; Line 540
last_line_length = 0; Line 542
c = next_char; Line 543
/* Scan (and copy) blank lines, and lines not introduced by the prefix. */
while (c == '\n' || c == EOF Line 547
|| next_prefix_indent < prefix_lead_space Line 548
|| in_column < next_prefix_indent + prefix_full_length) Line 549
{
c = copy_rest (f, c); Line 551
if (c == EOF) Line 552
{
next_char = EOF; Line 554
return false; Line 555
}
putchar ('\n'); Line 557
c = get_prefix (f); Line 558
}
/* Got a suitable first line for a paragraph. */
prefix_indent = next_prefix_indent; Line 563
first_indent = in_column; Line 564
wptr = parabuf; Line 565
word_limit = word; Line 566
c = get_line (f, c); Line 567
set_other_indent (same_para (c)); Line 568
/* Read rest of paragraph (unless split is specified). */
if (split) Line 572
{
/* empty */
}
else if (crown) Line 576
{
if (same_para (c)) Line 578
{
do
{ /* for each line till the end of the para */ Line 581
c = get_line (f, c); Line 582
}
while (same_para (c) && in_column == other_indent); Line 584
}
}
else if (tagged) Line 587
{
if (same_para (c) && in_column != first_indent) Line 589
{
do
{ /* for each line till the end of the para */ Line 592
c = get_line (f, c); Line 593
}
while (same_para (c) && in_column == other_indent); Line 595
}
}
else Line 598
{
while (same_para (c) && in_column == other_indent) Line 600
c = get_line (f, c); Line 601
}
/* Tell static analysis tools that using word_limit[-1] is ok.
word_limit is guaranteed to have been incremented by get_line. */
assert (word < word_limit); Line 606
(word_limit - 1)->period = (word_limit - 1)->final = true; Line 608
next_char = c; Line 609
return true; Line 610
} Block 8
/* Copy to the output a line that failed to match the prefix, or that
was blank after the prefix. In the former case, C is the character
that failed to match the prefix. In the latter, C is \n or EOF.
Return the character (\n or EOF) ending the line. */
static int Line 618
copy_rest (FILE *f, int c) Line 619
{
const char *s; Line 621
out_column = 0; Line 623
if (in_column > next_prefix_indent || (c != '\n' && c != EOF)) Line 624
{
put_space (next_prefix_indent); Line 626
for (s = prefix; out_column != in_column && *s; out_column++) Line 627
putchar (*s++); Line 628
if (c != EOF && c != '\n') Line 629
put_space (in_column - out_column); Line 630
if (c == EOF && in_column >= next_prefix_indent + prefix_length) Line 631
putchar ('\n'); Line 632
}
while (c != '\n' && c != EOF) Line 634
{
putchar (c); Line 636
c = getc (f); Line 637
}
return c; Line 639
} Block 9
/* Return true if a line whose first non-blank character after the
prefix (if any) is C could belong to the current paragraph,
otherwise false. */
static bool Line 646
same_para (int c) Line 647
{
return (next_prefix_indent == prefix_indent Line 649
&& in_column >= next_prefix_indent + prefix_full_length Line 650
&& c != '\n' && c != EOF); Line 651
} Block 10
/* Read a line from input file F, given first non-blank character C
after the prefix, and the following indent, and break it into words.
A word is a maximal non-empty string of non-white characters. A word
ending in [.?!]["')\]]* and followed by end-of-line or at least two
spaces ends a sentence, as in emacs.
Return the first non-blank character of the next line. */
static int Line 662
get_line (FILE *f, int c) Line 663
{
int start; Line 665
char *end_of_parabuf; Line 666
WORD *end_of_word; Line 667
end_of_parabuf = ¶buf[MAXCHARS]; Line 669
end_of_word = &word[MAXWORDS - 2]; Line 670
do
{ /* for each word in a line */ Line 673
/* Scan word. */
word_limit->text = wptr; Line 677
do
{
if (wptr == end_of_parabuf) Line 680
{
set_other_indent (true); Line 682
flush_paragraph (); Line 683
}
*wptr++ = c; Line 685
c = getc (f); Line 686
}
while (c != EOF && !isspace (c)); Line 688
in_column += word_limit->length = wptr - word_limit->text; Line 689
check_punctuation (word_limit); Line 690
/* Scan inter-word space. */
start = in_column; Line 694
c = get_space (f, c); Line 695
word_limit->space = in_column - start; Line 696
word_limit->final = (c == EOF Line 697
|| (word_limit->period Line 698
&& (c == '\n' || word_limit->space > 1))); Line 699
if (c == '\n' || c == EOF || uniform) Line 700
word_limit->space = word_limit->final ? 2 : 1; Line 701
if (word_limit == end_of_word) Line 702
{
set_other_indent (true); Line 704
flush_paragraph (); Line 705
}
word_limit++; Line 707
}
while (c != '\n' && c != EOF); Line 709
return get_prefix (f); Line 710
} Block 11
/* Read a prefix from input file F. Return either first non-matching
character, or first non-blank character after the prefix. */
static int Line 716
get_prefix (FILE *f) Line 717
{
int c; Line 719
in_column = 0; Line 721
c = get_space (f, getc (f)); Line 722
if (prefix_length == 0) Line 723
next_prefix_indent = prefix_lead_space < in_column ? Line 724
prefix_lead_space : in_column; Line 725
else Line 726
{
const char *p; Line 728
next_prefix_indent = in_column; Line 729
for (p = prefix; *p != '\0'; p++) Line 730
{
unsigned char pc = *p; Line 732
if (c != pc) Line 733
return c; Line 734
in_column++; Line 735
c = getc (f); Line 736
}
c = get_space (f, c); Line 738
}
return c; Line 740
} Block 12
/* Read blank characters from input file F, starting with C, and keeping
in_column up-to-date. Return first non-blank character. */
static int Line 746
get_space (FILE *f, int c) Line 747
{
while (true) Line 749
{
if (c == ' ') Line 751
in_column++; Line 752
else if (c == '\t') Line 753
{
tabs = true; Line 755
in_column = (in_column / TABWIDTH + 1) * TABWIDTH; Line 756
}
else Line 758
return c; Line 759
c = getc (f); Line 760
}
} Block 13
/* Set extra fields in word W describing any attached punctuation. */
static void Line 766
check_punctuation (WORD *w) Line 767
{
char const *start = w->text; Line 769
char const *finish = start + (w->length - 1); Line 770
unsigned char fin = *finish; Line 771
w->paren = isopen (*start); Line 773...!syscalls auto-comment...
w->punct = !! ispunct (fin); Line 774
while (start < finish && isclose (*finish)) Line 775...!syscalls auto-comment...
finish--; Line 776
w->period = isperiod (*finish); Line 777
} Block 14
/* Flush part of the paragraph to make room. This function is called on
hitting the limit on the number of words or characters. */
static void Line 783
flush_paragraph (void) Line 784
{
WORD *split_point; Line 786
WORD *w; Line 787
int shift; Line 788
COST best_break; Line 789
/* In the special case where it's all one word, just flush it. */
if (word_limit == word) Line 793
{
fwrite (parabuf, sizeof *parabuf, wptr - parabuf, stdout); Line 795...!syscalls auto-comment...
wptr = parabuf; Line 796
return; Line 797
}
/* Otherwise:
- format what you have so far as a paragraph,
- find a low-cost line break near the end,
- output to there,
- make that the start of the paragraph. */
fmt_paragraph (); Line 806
/* Choose a good split point. */
split_point = word_limit; Line 810
best_break = MAXCOST; Line 811
for (w = word->next_break; w != word_limit; w = w->next_break) Line 812
{
if (w->best_cost - w->next_break->best_cost < best_break) Line 814
{
split_point = w; Line 816
best_break = w->best_cost - w->next_break->best_cost; Line 817
}
if (best_break <= MAXCOST - LINE_CREDIT) Line 819
best_break += LINE_CREDIT; Line 820
}
put_paragraph (split_point); Line 822
/* Copy text of words down to start of parabuf -- we use memmove because
the source and target may overlap. */
memmove (parabuf, split_point->text, wptr - split_point->text); Line 827
shift = split_point->text - parabuf; Line 828
wptr -= shift; Line 829
/* Adjust text pointers. */
for (w = split_point; w <= word_limit; w++) Line 833
w->text -= shift; Line 834
/* Copy words from split_point down to word -- we use memmove because
the source and target may overlap. */
memmove (word, split_point, (word_limit - split_point + 1) * sizeof *word); Line 839
word_limit -= split_point - word; Line 840
} Block 15
/* Compute the optimal formatting for the whole paragraph by computing
and remembering the optimal formatting for each suffix from the empty
one to the whole paragraph. */
static void Line 847
fmt_paragraph (void) Line 848
{
WORD *start, *w; Line 850
int len; Line 851
COST wcost, best; Line 852
int saved_length; Line 853
word_limit->best_cost = 0; Line 855
saved_length = word_limit->length; Line 856
word_limit->length = max_width; /* sentinel */ Line 857
for (start = word_limit - 1; start >= word; start--) Line 859
{
best = MAXCOST; Line 861
len = start == word ? first_indent : other_indent; Line 862
/* At least one word, however long, in the line. */
w = start; Line 866
len += w->length; Line 867
do
{
w++; Line 870
/* Consider breaking before w. */
wcost = line_cost (w, len) + w->best_cost; Line 874
if (start == word && last_line_length > 0) Line 875
wcost += RAGGED_COST (len - last_line_length); Line 876
if (wcost < best) Line 877
{
best = wcost; Line 879
start->next_break = w; Line 880
start->line_length = len; Line 881
}
/* This is a kludge to keep us from computing 'len' as the
sum of the sentinel length and some non-zero number.
Since the sentinel w->length may be INT_MAX, adding
to that would give a negative result. */
if (w == word_limit) Line 888
break; Line 889
len += (w - 1)->space + w->length; /* w > start >= word */ Line 891
}
while (len < max_width); Line 893
start->best_cost = best + base_cost (start); Line 894
}
word_limit->length = saved_length; Line 897
} Block 16
/* Return the constant component of the cost of breaking before the
word THIS. */
static COST Line 903
base_cost (WORD *this) Line 904
{
COST cost; Line 906
cost = LINE_COST; Line 908
if (this > word) Line 910
{
if ((this - 1)->period) Line 912
{
if ((this - 1)->final) Line 914
cost -= SENTENCE_BONUS; Line 915
else Line 916
cost += NOBREAK_COST; Line 917
}
else if ((this - 1)->punct) Line 919
cost -= PUNCT_BONUS; Line 920
else if (this > word + 1 && (this - 2)->final) Line 921
cost += WIDOW_COST ((this - 1)->length); Line 922
}
if (this->paren) Line 925
cost -= PAREN_BONUS; Line 926
else if (this->final) Line 927
cost += ORPHAN_COST (this->length); Line 928
return cost; Line 930
} Block 17
/* Return the component of the cost of breaking before word NEXT that
depends on LEN, the length of the line beginning there. */
static COST Line 936
line_cost (WORD *next, int len) Line 937
{
int n; Line 939
COST cost; Line 940
if (next == word_limit) Line 942
return 0; Line 943
n = goal_width - len; Line 944
cost = SHORT_COST (n); Line 945
if (next->next_break != word_limit) Line 946
{
n = len - next->line_length; Line 948
cost += RAGGED_COST (n); Line 949
}
return cost; Line 951
} Block 18
/* Output to stdout a paragraph from word up to (but not including)
FINISH, which must be in the next_break chain from word. */
static void Line 957
put_paragraph (WORD *finish) Line 958
{
WORD *w; Line 960
put_line (word, first_indent); Line 962
for (w = word->next_break; w != finish; w = w->next_break) Line 963
put_line (w, other_indent); Line 964
} Block 19
/* Output to stdout the line beginning with word W, beginning in column
INDENT, including the prefix (if any). */
static void Line 970
put_line (WORD *w, int indent) Line 971
{
WORD *endline; Line 973
out_column = 0; Line 975
put_space (prefix_indent); Line 976
fputs (prefix, stdout); Line 977
out_column += prefix_length; Line 978
put_space (indent - out_column); Line 979
endline = w->next_break - 1; Line 981
for (; w != endline; w++) Line 982
{
put_word (w); Line 984
put_space (w->space); Line 985
}
put_word (w); Line 987
last_line_length = out_column; Line 988
putchar ('\n'); Line 989
} Block 20
/* Output to stdout the word W. */
static void Line 994
put_word (WORD *w) Line 995
{
const char *s; Line 997
int n; Line 998
s = w->text; Line 1000
for (n = w->length; n != 0; n--) Line 1001
putchar (*s++); Line 1002
out_column += w->length; Line 1003
} Block 21
/* Output to stdout SPACE spaces, or equivalent tabs. */
static void Line 1008
put_space (int space) Line 1009
{
int space_target, tab_target; Line 1011
space_target = out_column + space; Line 1013
if (tabs) Line 1014
{
tab_target = space_target / TABWIDTH * TABWIDTH; Line 1016
if (out_column + 1 < tab_target) Line 1017
while (out_column < tab_target) Line 1018
{
putchar ('\t'); Line 1020
out_column = (out_column / TABWIDTH + 1) * TABWIDTH; Line 1021
}
}
while (out_column < space_target) Line 1024
{
putchar (' '); Line 1026
out_column++; Line 1027
}
} Block 22