Mercurial > ~dholland > hg > ag > index.cgi
view checksum/dosum.c @ 21:1c9dac05d040
Add lint-style FALLTHROUGH annotations to fallthrough cases.
(in the parse engine and thus the output code)
Document this, because the old output causes warnings with gcc10.
author | David A. Holland |
---|---|
date | Mon, 13 Jun 2022 00:04:38 -0400 |
parents | 3aa0f5a02342 |
children |
line wrap: on
line source
/* * AnaGram, A System for Syntax Directed Programming * Copyright 1993 Parsifal Software. All Rights Reserved. * Copyright 2006 David A. Holland. All Rights Reserved. * See the file COPYING for license and usage terms. * * dosum.c - checksums. */ /* * Fletcher's check-sum routines for AnaGram * * Freely adapted from routines published in Dr. Dobbs Journal * May 1992, p. 64 * * Revised as portable C in June 2006. */ #include <stdint.h> #include <string.h> #include <assert.h> #include "bits.h" struct sumstate { uint16_t k1, k2; }; static void sumstate_init(struct sumstate *s, size_t length) { s->k1 = (uint16_t) (length >> 16); s->k2 = (uint16_t) length; if (s->k1 == 0) s->k1++; if (s->k2 == 0) s->k2++; } static void sumstate_sum(struct sumstate *s, const void *buf, size_t len) { const uint8_t *cb; unsigned i, n; uint16_t x; cb = buf; n = len/sizeof(uint16_t); for (i=0; i<n; i++) { // read one octet at a time so the byte order is deterministic x = *cb++; x += ((uint16_t)*cb++) << 8; s->k1 += x; if (s->k1 < x) s->k1++; s->k2 += s->k1; if (s->k2 < s->k1) s->k2++; } } static uint32_t sumstate_finish(struct sumstate *s) { uint32_t sum; s->k1 ^= 0xffff; s->k2 ^= 0xffff; sum = 65535UL*s->k2 + s->k1; return sum; } uint32_t dosum(const char *buf, size_t len, size_t skipstart, size_t skiplen) { struct sumstate s; size_t numwords; assert(skiplen%2==0); assert(skipstart==0 || skipstart+skiplen <= len); sumstate_init(&s, len); /* * It would be nice if we could count on skipstart being aligned. * But we can't. Nor is the filesize necessarily even. * * The followed mangled logic that rounds some things up matches * what used to be done in an even uglier way. * * To wit: if there's a skip area, we start after it and read pairs * of octets, including a zero past the end of the file if the * remaining data length after the skip area has odd size, so as to * get the last byte. (The caller is responsible for making sure * there's a zero there.) Then we read the beginning of the file up * to the skip area, but round down so as to not read the first byte * of the skip area if skipstart is odd. If skipstart is odd then we * wedge in that last byte along with a zero. * * If there isn't a skip area, we read the whole thing in order, * including the zero past the end if the size is odd. */ assert(sizeof(uint16_t)==2); numwords = (len+1)/2; if (skipstart > 0) { size_t p0 = skipstart+skiplen; size_t l0 = (numwords - p0/2) * 2; size_t p1 = 0; size_t l1 = (skipstart/2) * 2; sumstate_sum(&s, buf+p0, l0); sumstate_sum(&s, buf+p1, l1); if (skipstart % 2 == 1) { char tmp[2]; tmp[0] = buf[skipstart - 1]; tmp[1] = 0; sumstate_sum(&s, tmp, 2); } } else { sumstate_sum(&s, buf, numwords * 2); } return sumstate_finish(&s); }