X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=coreutils%2Fsum.c;h=c55293dc9673af11b3b12fb37e67989c8c2b7c27;hb=af3f42011628585cd5c8f5c1fd4b43f2e370a23d;hp=2618648b2f1fb5cea41f7e2f29114408480ac80c;hpb=4a2117027f12c43b93e4221f636074c881206a2d;p=oweals%2Fbusybox.git diff --git a/coreutils/sum.c b/coreutils/sum.c index 2618648b2..c55293dc9 100644 --- a/coreutils/sum.c +++ b/coreutils/sum.c @@ -1,3 +1,4 @@ +/* vi: set sw=4 ts=4: */ /* * sum -- checksum and count the blocks in a file * Like BSD sum or SysV sum -r, except like SysV sum if -s option is given. @@ -9,174 +10,109 @@ * Written by Kayvan Aghaiepour and David MacKenzie * Taken from coreutils and turned into a busybox applet by Mike Frysinger * - * 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 2 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//config:config SUM +//config: bool "sum" +//config: default y +//config: help +//config: checksum and count the blocks in a file -#include -#include -#include -#include -#include -#include - -#include "libbb.h" - -/* 1 if any of the files read were the standard input */ -static int have_read_stdin; - -/* make a little more readable and avoid using strcmp for just 2 bytes */ -#define IS_STDIN(s) (s[0] == '-' && s[1] == '\0') - -/* 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 1 if successful. */ -static int bsd_sum_file(const char *file, int print_name) -{ - register FILE *fp; - register int checksum = 0; /* The checksum mod 2^16. */ - register uintmax_t total_bytes = 0; /* The number of bytes. */ - register int ch; /* Each character read. */ - - if (IS_STDIN(file)) { - fp = stdin; - have_read_stdin = 1; - } else { - fp = fopen(file, "r"); - if (fp == NULL) { - bb_perror_msg("%s", file); - return 0; - } - } - - while ((ch = getc(fp)) != EOF) { - ++total_bytes; - checksum = (checksum >> 1) + ((checksum & 1) << 15); - checksum += ch; - checksum &= 0xffff; /* Keep it within bounds. */ - } +//applet:IF_SUM(APPLET(sum, BB_DIR_USR_BIN, BB_SUID_DROP)) - if (ferror(fp)) { - bb_perror_msg("%s", file); - if (!IS_STDIN(file)) - fclose(fp); - return 0; - } +//kbuild:lib-$(CONFIG_SUM) += sum.o - if (!IS_STDIN(file) && fclose(fp) == EOF) { - bb_perror_msg("%s", file); - return 0; - } +//usage:#define sum_trivial_usage +//usage: "[-rs] [FILE]..." +//usage:#define sum_full_usage "\n\n" +//usage: "Checksum and count the blocks in a file\n" +//usage: "\n -r Use BSD sum algorithm (1K blocks)" +//usage: "\n -s Use System V sum algorithm (512byte blocks)" - printf("%05d %5s", checksum, - make_human_readable_str(total_bytes, 1, 1024)); - if (print_name > 1) - printf(" %s", file); - putchar('\n'); +#include "libbb.h" +#include "common_bufsiz.h" - return 1; -} +enum { SUM_BSD, PRINT_NAME, SUM_SYSV }; -/* 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 1 if successful. */ -static int sysv_sum_file(const char *file, int print_name) +/* BSD: calculate and print the rotated checksum and the size in 1K blocks + The checksum varies depending on sizeof (int). */ +/* SYSV: calculate and print the checksum and the size in 512-byte blocks */ +/* Return 1 if successful. */ +static unsigned sum_file(const char *file, unsigned type) { - int fd; - unsigned char buf[8192]; - uintmax_t total_bytes = 0; - int r; - int checksum; - + unsigned long long total_bytes = 0; + int fd, r; /* The sum of all the input bytes, modulo (UINT_MAX + 1). */ - unsigned int s = 0; + unsigned s = 0; - if (IS_STDIN(file)) { - fd = 0; - have_read_stdin = 1; - } else { - fd = open(file, O_RDONLY); - if (fd == -1) { - bb_perror_msg("%s", file); - return 0; - } - } +#define buf bb_common_bufsiz1 + setup_common_bufsiz(); - while (1) { - size_t i; - size_t bytes_read = safe_read(fd, buf, sizeof(buf)); - - if (bytes_read == 0) - break; + fd = open_or_warn_stdin(file); + if (fd == -1) + return 0; - if (bytes_read == -1) { - bb_perror_msg("%s", file); - if (!IS_STDIN(file)) - close(fd); + while (1) { + size_t bytes_read = safe_read(fd, buf, COMMON_BUFSIZE); + + if ((ssize_t)bytes_read <= 0) { + r = (fd && close(fd) != 0); + if (!bytes_read && !r) + /* no error */ + break; + bb_simple_perror_msg(file); return 0; } - for (i = 0; i < bytes_read; i++) - s += buf[i]; total_bytes += bytes_read; + if (type >= SUM_SYSV) { + do s += buf[--bytes_read]; while (bytes_read); + } else { + r = 0; + do { + s = (s >> 1) + ((s & 1) << 15); + s += buf[r++]; + s &= 0xffff; /* Keep it within bounds. */ + } while (--bytes_read); + } } - if (!IS_STDIN(file) && close(fd) == -1) { - bb_perror_msg("%s", file); - return 0; - } - - r = (s & 0xffff) + ((s & 0xffffffff) >> 16); - checksum = (r & 0xffff) + (r >> 16); - - printf("%d %s", checksum, - make_human_readable_str(total_bytes, 1, 512)); - if (print_name) - printf(" %s", file); - putchar('\n'); - + if (type < PRINT_NAME) + file = ""; + if (type >= SUM_SYSV) { + r = (s & 0xffff) + ((s & 0xffffffff) >> 16); + s = (r & 0xffff) + (r >> 16); + printf("%u %llu %s\n", s, (total_bytes + 511) / 512, file); + } else + printf("%05u %5llu %s\n", s, (total_bytes + 1023) / 1024, file); return 1; +#undef buf } -int sum_main(int argc, char **argv) +int sum_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int sum_main(int argc UNUSED_PARAM, char **argv) { - int flags; - int ok; - int files_given; - int (*sum_func)(const char *, int) = bsd_sum_file; - - /* give the bsd func priority over sysv func */ - flags = bb_getopt_ulflags(argc, argv, "sr"); - if (flags & 1) - sum_func = sysv_sum_file; - if (flags & 2) - sum_func = bsd_sum_file; - - have_read_stdin = 0; - files_given = argc - optind; - if (files_given <= 0) - ok = sum_func("-", files_given); - else - for (ok = 1; optind < argc; optind++) - ok &= sum_func(argv[optind], files_given); - - if (have_read_stdin && fclose(stdin) == EOF) - bb_perror_msg_and_die("-"); - - exit(ok ? EXIT_SUCCESS : EXIT_FAILURE); + unsigned n; + unsigned type = SUM_BSD; + + n = getopt32(argv, "sr"); + argv += optind; + if (n & 1) type = SUM_SYSV; + /* give the bsd priority over sysv func */ + if (n & 2) type = SUM_BSD; + + if (!argv[0]) { + /* Do not print the name */ + n = sum_file("-", type); + } else { + /* Need to print the name if either + * - more than one file given + * - doing sysv */ + type += (argv[1] || type == SUM_SYSV); + n = 1; + do { + n &= sum_file(*argv, type); + } while (*++argv); + } + return !n; }