diff options
author | Eric S. Raymond <esr@thyrsus.com> | 2008-07-16 22:42:11 +0000 |
---|---|---|
committer | Eric S. Raymond <esr@thyrsus.com> | 2008-07-16 22:42:11 +0000 |
commit | 4ca672e113bd7ab6c106c41d53b10a4828228b4a (patch) | |
tree | cbb7a3fc813135f5d2e7ac2d22a113888d60b6f8 /bits.c | |
parent | 70c598e28e5cabe3694dcc4a894838a14a7cde15 (diff) | |
download | gpsd-4ca672e113bd7ab6c106c41d53b10a4828228b4a.tar.gz |
Factor out the bitfield functions, fix a bug in one, add tests.
Diffstat (limited to 'bits.c')
-rw-r--r-- | bits.c | 61 |
1 files changed, 61 insertions, 0 deletions
@@ -0,0 +1,61 @@ +#define DEBUG +/* + * Bitfield extraction functions. In each, start is a bit index (not a byte + * index) and width is a bit width (bounded above by the bit width of long + * long). + * + * The sbits() function assumes twos-complement arithmetic. + */ +#include <assert.h> + +#include "bits.h" +#ifdef DEBUG +#include <stdlib.h> +#include "gpsd_config.h" +#include "gpsd.h" +#endif /* DEBUG */ + + +#define BITS_PER_BYTE 8 + +unsigned long long ubits(char buf[], unsigned int start, unsigned int width) +/* extract a bitfield from the buffer as an unsigned big-endian long */ +{ + unsigned long long fld = 0; + unsigned int i;; + + assert(width <= sizeof(long long) * BITS_PER_BYTE); + for (i = 0; i < (width + BITS_PER_BYTE - 1) / BITS_PER_BYTE; i++) { + fld <<= BITS_PER_BYTE; + fld |= (unsigned char)buf[start / BITS_PER_BYTE + i]; + } +#ifdef DEBUG + printf("Extracting %d:%d from %s: segment 0x%llx = %lld\n", start, width, gpsd_hexdump(buf, 12), fld, fld); +#endif /* DEBUG */ + + fld &= (0xffffffff >> (start % BITS_PER_BYTE)); +#ifdef DEBUG + printf("After masking: 0x%llx = %lld\n", fld, fld); +#endif /* DEBUG */ + fld >>= (BITS_PER_BYTE - 1) - ((start + width) % BITS_PER_BYTE); +#ifdef DEBUG + printf("After downshifting: 0x%llx = %lld\n", fld, fld); +#endif /* DEBUG */ + + return fld; +} + +signed long long sbits(char buf[], unsigned int start, unsigned int width) +/* extract a bitfield from the buffer as a signed big-endian long */ +{ + unsigned long long un = ubits(buf, start, width); + signed long long fld; + + if (un & (1 << width)) + fld = -(un & ~(1 << width)); + else + fld = (signed long long)un; + + return fld; +} + |