/* sum -- checksum and count the blocks in a file                               This is the sum utility
   Copyright (C) 1986-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
                                                                                
/* Like BSD sum or SysV sum -r, except like SysV sum if -s option is given. */  
                                                                                
/* Written by Kayvan Aghaiepour and David MacKenzie. */                         
                                                                                
#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 "system.h"                                                             ...!includes auto-comment...
#include "die.h"                                                                ...!includes auto-comment...
#include "error.h"                                                              ...!includes auto-comment...
#include "fadvise.h"                                                            ...!includes auto-comment...
#include "human.h"                                                              ...!includes auto-comment...
#include "safe-read.h"                                                          ...!includes auto-comment...
#include "xbinary-io.h"                                                         ...!includes auto-comment...
                                                                                
/* The official name of this program (e.g., no 'g' prefix).  */                 
#define PROGRAM_NAME "sum"                                                      Line 35
                                                                                
#define AUTHORS \                                                               Line 37
  proper_name ("Kayvan Aghaiepour"), \                                          Line 38
  proper_name ("David MacKenzie")                                               Line 39
                                                                                
/* True if any of the files read were the standard input. */                    
static bool have_read_stdin;                                                    Line 42
                                                                                
static struct option const longopts[] =                                         Line 44
{                                                                               
  {"sysv", no_argument, NULL, 's'},                                             Line 46
  {GETOPT_HELP_OPTION_DECL},                                                    Line 47
  {GETOPT_VERSION_OPTION_DECL},                                                 Line 48
  {NULL, 0, NULL, 0}                                                            Line 49
};                                                                              Block 1
                                                                                
void                                                                            Line 52
usage (int status)                                                              Line 53
{                                                                               
  if (status != EXIT_SUCCESS)                                                   Line 55
    emit_try_help ();                                                           ...!common auto-comment...
  else                                                                          Line 57
    {                                                                           
      printf (_("\                                                              Line 59
Usage: %s [OPTION]... [FILE]...\n\                                              Line 60
"),                                                                             Line 61
              program_name);                                                    Line 62
      fputs (_("\                                                               Line 63
Print checksum and block counts for each FILE.\n\                               Line 64
"), stdout);                                                                    Line 65
                                                                                
      emit_stdin_note ();                                                       ...!common auto-comment...
                                                                                
      fputs (_("\                                                               Line 69
\n\                                                                             
  -r              use BSD sum algorithm, use 1K blocks\n\                       Line 71
  -s, --sysv      use System V sum algorithm, use 512 bytes blocks\n\           Line 72
"), stdout);                                                                    Line 73
      fputs (HELP_OPTION_DESCRIPTION, stdout);                                  Line 74
      fputs (VERSION_OPTION_DESCRIPTION, stdout);                               Line 75
      emit_ancillary_info (PROGRAM_NAME);                                       Line 76
    }                                                                           
  exit (status);                                                                Line 78
}                                                                               Block 2
                                                                                
/* Calculate and print the rotated checksum and the size in 1K blocks           
   of file FILE, or of the standard input if FILE is "-".                       
   If PRINT_NAME is >1, print FILE next to the checksum and size.               
   The checksum varies depending on sizeof (int).                               
   Return true if successful.  */                                               
                                                                                
static bool                                                                     Line 87
bsd_sum_file (const char *file, int print_name)                                 Line 88
{                                                                               
  FILE *fp;                                                                     Line 90
  int checksum = 0; /* The checksum mod 2^16. */                                Line 91
  uintmax_t total_bytes = 0; /* The number of bytes. */                         Line 92
  int ch;  /* Each character read. */                                           Line 93
  char hbuf[LONGEST_HUMAN_READABLE + 1];                                        Line 94
  bool is_stdin = STREQ (file, "-");                                            Line 95
                                                                                
  if (is_stdin)                                                                 Line 97
    {                                                                           
      fp = stdin;                                                               Line 99
      have_read_stdin = true;                                                   Line 100
      xset_binary_mode (STDIN_FILENO, O_BINARY);                                Line 101
    }                                                                           
  else                                                                          Line 103
    {                                                                           
      fp = fopen (file, (O_BINARY ? "rb" : "r"));                               Line 105...!syscalls auto-comment...
      if (fp == NULL)                                                           Line 106
        {                                                                       
          error (0, errno, "%s", quotef (file));                                Line 108
          return false;                                                         Line 109
        }                                                                       
    }                                                                           
                                                                                
  fadvise (fp, FADVISE_SEQUENTIAL);                                             Line 113...!syscalls auto-comment...
                                                                                
  while ((ch = getc (fp)) != EOF)                                               Line 115
    {                                                                           
      total_bytes++;                                                            Line 117
      checksum = (checksum >> 1) + ((checksum & 1) << 15);                      Line 118
      checksum += ch;                                                           Line 119
      checksum &= 0xffff; /* Keep it within bounds. */                          Line 120
    }                                                                           
                                                                                
  if (ferror (fp))                                                              Line 123
    {                                                                           
      error (0, errno, "%s", quotef (file));                                    Line 125
      if (!is_stdin)                                                            Line 126
        fclose (fp);                                                            Line 127...!syscalls auto-comment...
      return false;                                                             Line 128
    }                                                                           
                                                                                
  if (!is_stdin && fclose (fp) != 0)                                            Line 131...!syscalls auto-comment...
    {                                                                           
      error (0, errno, "%s", quotef (file));                                    Line 133
      return false;                                                             Line 134
    }                                                                           
                                                                                
  printf ("%05d %5s", checksum,                                                 Line 137
          human_readable (total_bytes, hbuf, human_ceiling, 1, 1024));          Line 138
  if (print_name > 1)                                                           Line 139
    printf (" %s", file);                                                       Line 140
  putchar ('\n');                                                               Line 141
                                                                                
  return true;                                                                  Line 143
}                                                                               Block 3
                                                                                
/* Calculate and print the checksum and the size in 512-byte blocks             
   of file FILE, or of the standard input if FILE is "-".                       
   If PRINT_NAME is >0, print FILE next to the checksum and size.               
   Return true if successful.  */                                               
                                                                                
static bool                                                                     Line 151
sysv_sum_file (const char *file, int print_name)                                Line 152
{                                                                               
  int fd;                                                                       Line 154
  unsigned char buf[8192];                                                      Line 155
  uintmax_t total_bytes = 0;                                                    Line 156
  char hbuf[LONGEST_HUMAN_READABLE + 1];                                        Line 157
  int r;                                                                        Line 158
  int checksum;                                                                 Line 159
                                                                                
  /* The sum of all the input bytes, modulo (UINT_MAX + 1).  */                 
  unsigned int s = 0;                                                           Line 162
                                                                                
  bool is_stdin = STREQ (file, "-");                                            Line 164
                                                                                
  if (is_stdin)                                                                 Line 166
    {                                                                           
      fd = STDIN_FILENO;                                                        Line 168
      have_read_stdin = true;                                                   Line 169
      xset_binary_mode (STDIN_FILENO, O_BINARY);                                Line 170
    }                                                                           
  else                                                                          Line 172
    {                                                                           
      fd = open (file, O_RDONLY | O_BINARY);                                    Line 174...!syscalls auto-comment...
      if (fd == -1)                                                             Line 175
        {                                                                       
          error (0, errno, "%s", quotef (file));                                Line 177
          return false;                                                         Line 178
        }                                                                       
    }                                                                           
                                                                                
  while (1)                                                                     Line 182
    {                                                                           
      size_t bytes_read = safe_read (fd, buf, sizeof buf);                      Line 184...!syscalls auto-comment...
                                                                                
      if (bytes_read == 0)                                                      Line 186
        break;                                                                  Line 187
                                                                                
      if (bytes_read == SAFE_READ_ERROR)                                        Line 189
        {                                                                       
          error (0, errno, "%s", quotef (file));                                Line 191
          if (!is_stdin)                                                        Line 192
            close (fd);                                                         Line 193...!syscalls auto-comment...
          return false;                                                         Line 194
        }                                                                       
                                                                                
      for (size_t i = 0; i < bytes_read; i++)                                   Line 197
        s += buf[i];                                                            Line 198
      total_bytes += bytes_read;                                                Line 199
    }                                                                           
                                                                                
  if (!is_stdin && close (fd) != 0)                                             Line 202...!syscalls auto-comment...
    {                                                                           
      error (0, errno, "%s", quotef (file));                                    Line 204
      return false;                                                             Line 205
    }                                                                           
                                                                                
  r = (s & 0xffff) + ((s & 0xffffffff) >> 16);                                  Line 208
  checksum = (r & 0xffff) + (r >> 16);                                          Line 209
                                                                                
  printf ("%d %s", checksum,                                                    Line 211
          human_readable (total_bytes, hbuf, human_ceiling, 1, 512));           Line 212
  if (print_name)                                                               Line 213
    printf (" %s", file);                                                       Line 214
  putchar ('\n');                                                               Line 215
                                                                                
  return true;                                                                  Line 217
}                                                                               Block 4
                                                                                
int                                                                             
main (int argc, char **argv)                                                    Line 221
{                                                                               
  bool ok;                                                                      Line 223
  int optc;                                                                     Line 224
  int files_given;                                                              Line 225
  bool (*sum_func) (const char *, int) = bsd_sum_file;                          Line 226
                                                                                
  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)
                                                                                
  /* Line buffer stdout to ensure lines are written atomically and immediately  
     so that processes running in parallel do not intersperse their output.  */ 
  setvbuf (stdout, NULL, _IOLBF, 0);                                            Line 238
                                                                                
  have_read_stdin = false;                                                      Line 240
                                                                                
  while ((optc = getopt_long (argc, argv, "rs", longopts, NULL)) != -1)         Line 242
    {                                                                           
      switch (optc)                                                             Line 244
        {                                                                       
        case 'r':  /* For SysV compatibility. */                                Line 246
          sum_func = bsd_sum_file;                                              Line 247
          break;                                                                Line 248
                                                                                
        case 's':                                                               Line 250
          sum_func = sysv_sum_file;                                             Line 251
          break;                                                                Line 252
                                                                                
        case_GETOPT_HELP_CHAR;                                                  Line 254
                                                                                
        case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);                       Line 256
                                                                                
        default:                                                                Line 258
          usage (EXIT_FAILURE);                                                 Line 259
        }                                                                       
    }                                                                           
                                                                                
  files_given = argc - optind;                                                  Line 263
  if (files_given <= 0)                                                         Line 264
    ok = sum_func ("-", files_given);                                           Line 265
  else                                                                          Line 266
    for (ok = true; optind < argc; optind++)                                    Line 267
      ok &= sum_func (argv[optind], files_given);                               Line 268
                                                                                
  if (have_read_stdin && fclose (stdin) == EOF)                                 Line 270...!syscalls auto-comment...
    die (EXIT_FAILURE, errno, "%s", quotef ("-"));                              Line 271
  return ok ? EXIT_SUCCESS : EXIT_FAILURE;                                      Line 272
}                                                                               Block 5