/* fold -- wrap each input line to fit in specified width.                      This is the fold utility
   Copyright (C) 1991-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 David MacKenzie, djm@gnu.ai.mit.edu. */                           
                                                                                
#include <config.h>                                                             Provides system specific information
                                                                                
#include <stdio.h>                                                              Provides standard I/O capability
#include <getopt.h>                                                             ...!includes auto-comment...
#include <sys/types.h>                                                          Provides system data types
                                                                                
#include "system.h"                                                             ...!includes auto-comment...
#include "die.h"                                                                ...!includes auto-comment...
#include "error.h"                                                              ...!includes auto-comment...
#include "fadvise.h"                                                            ...!includes auto-comment...
#include "xdectoint.h"                                                          ...!includes auto-comment...
                                                                                
#define TAB_WIDTH 8                                                             Line 31
                                                                                
/* The official name of this program (e.g., no 'g' prefix).  */                 
#define PROGRAM_NAME "fold"                                                     Line 34
                                                                                
#define AUTHORS proper_name ("David MacKenzie")                                 Line 36
                                                                                
/* If nonzero, try to break on whitespace. */                                   
static bool break_spaces;                                                       Line 39
                                                                                
/* If nonzero, count bytes, not column positions. */                            
static bool count_bytes;                                                        Line 42
                                                                                
/* If nonzero, at least one of the files we read was standard input. */         
static bool have_read_stdin;                                                    Line 45
                                                                                
static char const shortopts[] = "bsw:0::1::2::3::4::5::6::7::8::9::";           Line 47
                                                                                
static struct option const longopts[] =                                         Line 49
{                                                                               
  {"bytes", no_argument, NULL, 'b'},                                            Line 51
  {"spaces", no_argument, NULL, 's'},                                           Line 52
  {"width", required_argument, NULL, 'w'},                                      Line 53
  {GETOPT_HELP_OPTION_DECL},                                                    Line 54
  {GETOPT_VERSION_OPTION_DECL},                                                 Line 55
  {NULL, 0, NULL, 0}                                                            Line 56
};                                                                              Block 1
                                                                                
void                                                                            Line 59
usage (int status)                                                              Line 60
{                                                                               
  if (status != EXIT_SUCCESS)                                                   Line 62
    emit_try_help ();                                                           ...!common auto-comment...
  else                                                                          Line 64
    {                                                                           
      printf (_("\                                                              Line 66
Usage: %s [OPTION]... [FILE]...\n\                                              Line 67
"),                                                                             Line 68
              program_name);                                                    Line 69
      fputs (_("\                                                               Line 70
Wrap input lines in each FILE, writing to standard output.\n\                   Line 71
"), stdout);                                                                    Line 72
                                                                                
      emit_stdin_note ();                                                       ...!common auto-comment...
      emit_mandatory_arg_note ();                                               ...!common auto-comment...
                                                                                
      fputs (_("\                                                               Line 77
  -b, --bytes         count bytes rather than columns\n\                        Line 78
  -s, --spaces        break at spaces\n\                                        Line 79
  -w, --width=WIDTH   use WIDTH columns instead of 80\n\                        Line 80
"), stdout);                                                                    Line 81
      fputs (HELP_OPTION_DESCRIPTION, stdout);                                  Line 82
      fputs (VERSION_OPTION_DESCRIPTION, stdout);                               Line 83
      emit_ancillary_info (PROGRAM_NAME);                                       Line 84
    }                                                                           
  exit (status);                                                                Line 86
}                                                                               Block 2
                                                                                
/* Assuming the current column is COLUMN, return the column that                
   printing C will move the cursor to.                                          
   The first column is 0. */                                                    
                                                                                
static size_t                                                                   Line 93
adjust_column (size_t column, char c)                                           Line 94
{                                                                               
  if (!count_bytes)                                                             Line 96
    {                                                                           
      if (c == '\b')                                                            Line 98
        {                                                                       
          if (column > 0)                                                       Line 100
            column--;                                                           Line 101
        }                                                                       
      else if (c == '\r')                                                       Line 103
        column = 0;                                                             Line 104
      else if (c == '\t')                                                       Line 105
        column += TAB_WIDTH - column % TAB_WIDTH;                               Line 106
      else /* if (isprint (c)) */                                               Line 107
        column++;                                                               Line 108
    }                                                                           
  else                                                                          Line 110
    column++;                                                                   Line 111
  return column;                                                                Line 112
}                                                                               Block 3
                                                                                
/* Fold file FILENAME, or standard input if FILENAME is "-",                    
   to stdout, with maximum line length WIDTH.                                   
   Return true if successful.  */                                               
                                                                                
static bool                                                                     Line 119
fold_file (char const *filename, size_t width)                                  Line 120
{                                                                               
  FILE *istream;                                                                Line 122
  int c;                                                                        Line 123
  size_t column = 0;  /* Screen column where next char will go. */              Line 124
  size_t offset_out = 0; /* Index in 'line_out' for next char. */               Line 125
  static char *line_out = NULL;                                                 Line 126
  static size_t allocated_out = 0;                                              Line 127
  int saved_errno;                                                              Line 128
                                                                                
  if (STREQ (filename, "-"))                                                    Line 130
    {                                                                           
      istream = stdin;                                                          Line 132
      have_read_stdin = true;                                                   Line 133
    }                                                                           
  else                                                                          Line 135
    istream = fopen (filename, "r");                                            Line 136...!syscalls auto-comment...
                                                                                
  if (istream == NULL)                                                          Line 138
    {                                                                           
      error (0, errno, "%s", quotef (filename));                                Line 140
      return false;                                                             Line 141
    }                                                                           
                                                                                
  fadvise (istream, FADVISE_SEQUENTIAL);                                        Line 144...!syscalls auto-comment...
                                                                                
  while ((c = getc (istream)) != EOF)                                           Line 146
    {                                                                           
      if (offset_out + 1 >= allocated_out)                                      Line 148
        line_out = X2REALLOC (line_out, &allocated_out);                        Line 149
                                                                                
      if (c == '\n')                                                            Line 151
        {                                                                       
          line_out[offset_out++] = c;                                           Line 153
          fwrite (line_out, sizeof (char), offset_out, stdout);                 Line 154...!syscalls auto-comment...
          column = offset_out = 0;                                              Line 155
          continue;                                                             Line 156
        }                                                                       
                                                                                
    rescan:                                                                     Line 159
      column = adjust_column (column, c);                                       Line 160
                                                                                
      if (column > width)                                                       Line 162
        {                                                                       
          /* This character would make the line too long.                       
             Print the line plus a newline, and make this character             
             start the next line. */                                            
          if (break_spaces)                                                     Line 167
            {                                                                   
              bool found_blank = false;                                         Line 169
              size_t logical_end = offset_out;                                  Line 170
                                                                                
              /* Look for the last blank. */                                    
              while (logical_end)                                               Line 173
                {                                                               
                  --logical_end;                                                Line 175
                  if (isblank (to_uchar (line_out[logical_end])))               Line 176
                    {                                                           
                      found_blank = true;                                       Line 178
                      break;                                                    Line 179
                    }                                                           
                }                                                               
                                                                                
              if (found_blank)                                                  Line 183
                {                                                               
                  size_t i;                                                     Line 185
                                                                                
                  /* Found a blank.  Don't output the part after it. */         
                  logical_end++;                                                Line 188
                  fwrite (line_out, sizeof (char), (size_t) logical_end,        Line 189...!syscalls auto-comment...
                          stdout);                                              Line 190
                  putchar ('\n');                                               Line 191
                  /* Move the remainder to the beginning of the next line.      
                     The areas being copied here might overlap. */              
                  memmove (line_out, line_out + logical_end,                    Line 194
                           offset_out - logical_end);                           Line 195
                  offset_out -= logical_end;                                    Line 196
                  for (column = i = 0; i < offset_out; i++)                     Line 197
                    column = adjust_column (column, line_out[i]);               Line 198
                  goto rescan;                                                  Line 199
                }                                                               
            }                                                                   
                                                                                
          if (offset_out == 0)                                                  Line 203
            {                                                                   
              line_out[offset_out++] = c;                                       Line 205
              continue;                                                         Line 206
            }                                                                   
                                                                                
          line_out[offset_out++] = '\n';                                        Line 209
          fwrite (line_out, sizeof (char), (size_t) offset_out, stdout);        Line 210...!syscalls auto-comment...
          column = offset_out = 0;                                              Line 211
          goto rescan;                                                          Line 212
        }                                                                       
                                                                                
      line_out[offset_out++] = c;                                               Line 215
    }                                                                           
                                                                                
  saved_errno = errno;                                                          Line 218
                                                                                
  if (offset_out)                                                               Line 220
    fwrite (line_out, sizeof (char), (size_t) offset_out, stdout);              Line 221...!syscalls auto-comment...
                                                                                
  if (ferror (istream))                                                         Line 223
    {                                                                           
      error (0, saved_errno, "%s", quotef (filename));                          Line 225
      if (!STREQ (filename, "-"))                                               Line 226
        fclose (istream);                                                       Line 227...!syscalls auto-comment...
      return false;                                                             Line 228
    }                                                                           
  if (!STREQ (filename, "-") && fclose (istream) == EOF)                        Line 230...!syscalls auto-comment...
    {                                                                           
      error (0, errno, "%s", quotef (filename));                                Line 232
      return false;                                                             Line 233
    }                                                                           
                                                                                
  return true;                                                                  Line 236
}                                                                               Block 4
                                                                                
int                                                                             
main (int argc, char **argv)                                                    Line 240
{                                                                               
  size_t width = 80;                                                            Line 242
  int i;                                                                        Line 243
  int optc;                                                                     Line 244
  bool ok;                                                                      Line 245
                                                                                
  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)
                                                                                
  break_spaces = count_bytes = have_read_stdin = false;                         Line 255
                                                                                
  while ((optc = getopt_long (argc, argv, shortopts, longopts, NULL)) != -1)    Line 257
    {                                                                           
      char optargbuf[2];                                                        Line 259
                                                                                
      switch (optc)                                                             Line 261
        {                                                                       
        case 'b':  /* Count bytes rather than columns. */                       Line 263
          count_bytes = true;                                                   Line 264
          break;                                                                Line 265
                                                                                
        case 's':  /* Break at word boundaries. */                              Line 267
          break_spaces = true;                                                  Line 268
          break;                                                                Line 269
                                                                                
        case '0': case '1': case '2': case '3': case '4':                       Line 271
        case '5': case '6': case '7': case '8': case '9':                       Line 272
          if (optarg)                                                           Line 273
            optarg--;                                                           Line 274
          else                                                                  Line 275
            {                                                                   
              optargbuf[0] = optc;                                              Line 277
              optargbuf[1] = '\0';                                              Line 278
              optarg = optargbuf;                                               Line 279
            }                                                                   
          FALLTHROUGH;                                                          Line 281
        case 'w':  /* Line width. */                                            Line 282
          width = xdectoumax (optarg, 1, SIZE_MAX - TAB_WIDTH - 1, "",          Line 283
                              _("invalid number of columns"), 0);               Line 284
          break;                                                                Line 285
                                                                                
        case_GETOPT_HELP_CHAR;                                                  Line 287
                                                                                
        case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);                       Line 289
                                                                                
        default:                                                                Line 291
          usage (EXIT_FAILURE);                                                 Line 292
        }                                                                       
    }                                                                           
                                                                                
  if (argc == optind)                                                           Line 296
    ok = fold_file ("-", width);                                                Line 297
  else                                                                          Line 298
    {                                                                           
      ok = true;                                                                Line 300
      for (i = optind; i < argc; i++)                                           Line 301
        ok &= fold_file (argv[i], width);                                       Line 302
    }                                                                           
                                                                                
  if (have_read_stdin && fclose (stdin) == EOF)                                 Line 305...!syscalls auto-comment...
    die (EXIT_FAILURE, errno, "-");                                             Line 306
                                                                                
  return ok ? EXIT_SUCCESS : EXIT_FAILURE;                                      Line 308
}                                                                               Block 5