/* 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