summaryrefslogtreecommitdiff
path: root/bits.c
diff options
context:
space:
mode:
authorEric S. Raymond <esr@thyrsus.com>2009-03-13 12:04:42 +0000
committerEric S. Raymond <esr@thyrsus.com>2009-03-13 12:04:42 +0000
commit21a5f024aada70c30acf3b81876cac9a85b3bb5f (patch)
tree215336e18c39fd16416725e826b48eb76c19d216 /bits.c
parent0dcad7b8b1ae3d5e9ed3ed9d0e6680b0f58daa25 (diff)
downloadgpsd-21a5f024aada70c30acf3b81876cac9a85b3bb5f.tar.gz
Sign-extend negative long longs correctly.
Diffstat (limited to 'bits.c')
-rw-r--r--bits.c40
1 files changed, 23 insertions, 17 deletions
diff --git a/bits.c b/bits.c
index 8530c8c6..20a0dfea 100644
--- a/bits.c
+++ b/bits.c
@@ -8,6 +8,8 @@
*/
#include <assert.h>
+#define DEBUG
+
#include "bits.h"
#ifdef DEBUG
#include <stdio.h>
@@ -15,12 +17,10 @@
#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 */
+/* extract a bitfield from the buffer as an unsigned big-endian long long */
{
unsigned long long fld = 0;
unsigned int i;
@@ -31,25 +31,25 @@ unsigned long long ubits(char buf[], unsigned int start, unsigned int width)
fld <<= BITS_PER_BYTE;
fld |= (unsigned char)buf[i];
}
-#ifdef DEBUG
+#ifdef UDEBUG
printf("Extracting %d:%d from %s: segment 0x%llx = %lld\n", start, width,
gpsd_hexdump(buf, 12), fld, fld);
-#endif /* DEBUG */
+#endif /* UDEBUG */
end = (start + width) % BITS_PER_BYTE;
if (end != 0) {
fld >>= (BITS_PER_BYTE - end);
-#ifdef DEBUG
+#ifdef UDEBUG
printf("After downshifting by %d bits: 0x%llx = %lld\n",
BITS_PER_BYTE - end, fld, fld);
-#endif /* DEBUG */
+#endif /* UDEBUG */
}
fld &= ~(0xffffffff << width);
-#ifdef DEBUG
+#ifdef UDEBUG
printf("After selecting out the bottom %u bits: 0x%llx = %lld\n",
width, fld, fld);
-#endif /* DEBUG */
+#endif /* UDEBUG */
return fld;
}
@@ -57,16 +57,22 @@ unsigned long long ubits(char buf[], unsigned int start, unsigned int width)
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;
+ unsigned long long fld = ubits(buf, start, width);
+#ifdef DEBUG
+ (void)fprintf(stderr, "sbits(%d, %d) extracts %llx\n", start, width, fld);
+#endif /* DEBUG */
/*@ +relaxtypes */
- if (un & (1 << width))
- fld = -(un & ~(1 << width));
- else
- fld = (signed long long)un;
-
- return fld;
+ if (fld & (1 << (width-1))) {
+#ifdef DEBUG
+ (void)fprintf(stderr, "%llx is signed\n", fld);
+#endif /* DEBUG */
+ fld |= (-1LL << (width-1));
+ }
+#ifdef DEBUG
+ (void)fprintf(stderr, "sbits(%d, %d) returns %lld\n", start, width, (signed long long)fld);
+#endif /* DEBUG */
+ return (signed long long)fld;
/*@ -relaxtypes */
}