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