diff options
author | Jakob Kaivo <jkk@ung.org> | 2022-04-17 21:24:23 -0400 |
---|---|---|
committer | Jakob Kaivo <jkk@ung.org> | 2022-04-17 21:24:23 -0400 |
commit | 05f7f67009c7aa605d1ec55a9df33f8ca250d584 (patch) | |
tree | 9dd8f992815bf6be00141f32f981ec6d7fdb700d /sum.c |
extract from cksum
Diffstat (limited to 'sum.c')
-rw-r--r-- | sum.c | 157 |
1 files changed, 157 insertions, 0 deletions
@@ -0,0 +1,157 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2022, Jakob Kaivo <jkk@ung.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#define _POSIX_C_SOURCE 200809L +#include <errno.h> +#include <inttypes.h> +#include <libgen.h> +#include <limits.h> +#include <locale.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#define MAX_SUM_WIDTH (32) +#define UINT32_BIT (32) +#define UINT16_BIT (16) +#define BLOCK_SIZE (512) + +enum algorithm { UNSPECIFIED, ALTERNATIVE }; + +struct sum { + uintmax_t size; + uintmax_t sum; +}; + +static char *progname = NULL; + +static uint32_t reverse(uint32_t n, int width) +{ + uint32_t r = 0; + for (int i = 0; i < width; i++) { + r |= (n & 0x1) << ((width - 1) - i); + n >>= 1; + } + return r; +} + +static struct sum sum_obsolete(FILE *f, int alt) +{ + struct sum sum = { 0 }; + + int c; + while ((c = fgetc(f)) != EOF) { + sum.size++; + + if (alt) { + sum.sum = (sum.sum >> 1) + + ((sum.sum & 1) << (UINT16_BIT - 1)); + } + + sum.sum += c; + + if (alt) { + sum.sum &= UINT16_MAX; + } + } + + sum.sum = (sum.sum & UINT16_MAX) + (sum.sum >> UINT16_BIT); + + /* obsolete sum program prints number of 512 byte blocks */ + if (sum.size % BLOCK_SIZE != 0) { + sum.size += BLOCK_SIZE; + } + sum.size /= BLOCK_SIZE; + + return sum; +} + +static struct sum sum_unspecified(FILE *f) +{ + return sum_obsolete(f, 0); +} + +static struct sum sum_alternative(FILE *f) +{ + return sum_obsolete(f, 1); +} + +int cksum(const char *path, enum algorithm alg) +{ + FILE *f = stdin; + if (path && strcmp(path, "-")) { + f = fopen(path, "rb"); + } + + if (f == NULL) { + fprintf(stderr, "%s: %s: %s\n", progname, path, strerror(errno)); + return 1; + } + + struct sum sum; + switch (alg) { + case UNSPECIFIED: + sum = sum_unspecified(f); + break; + + case ALTERNATIVE: + sum = sum_alternative(f); + break; + + default: + break; + } + + printf("%"PRIuMAX" %"PRIuMAX"", sum.sum, sum.size); + + if (f != stdin) { + printf(" %s", path); + fclose(f); + } + putchar('\n'); + + return 0; +} + +int main(int argc, char *argv[]) +{ + setlocale(LC_ALL, ""); + + fprintf(stderr, "sum: utility is obsolete; use cksum\n"); + + enum algorithm alg = UNSPECIFIED; + + int c; + while ((c = getopt(argc, argv, "r")) != -1) { + switch (c) { + case 'r': + alg = ALTERNATIVE; + break; + + default: + return 1; + } + } + + int r = 0; + do { + r |= cksum(argv[optind++], alg); + } while (optind < argc); + return r; +} |