lib/stream: add float/double <-> IEEE-754 single/double mux/demuxers
* stream.{c,h}: Add stream_get{f,d} and stream_put{f,d}) demux and muxers to
safely convert between big-endian IEEE-754 single and double binary
format, as used in IETF RFCs, and C99. Implementation depends on host
using __STDC_IEC_559__, which should be everything we care about. Should
correctly error out otherwise.
Thanks to Aidan Delaney <aidan@phoric.eu> and Olivier Dugeon for pointing
out the __STDC_IEC_559__ macro.
Update: GCC does not per se set __STDC_IEC_559__, so also test for
__GCC_IEC_559 >= 1.
diff --git a/lib/stream.c b/lib/stream.c
index ca1a40f..4d4f867 100644
--- a/lib/stream.c
+++ b/lib/stream.c
@@ -22,6 +22,8 @@
#include <zebra.h>
#include <stddef.h>
+/* primarily for __STDC_IEC_559__ with clang */
+#include <features.h>
#include "stream.h"
#include "memory.h"
@@ -493,6 +495,38 @@
return l;
}
+float
+stream_getf (struct stream *s)
+{
+#if defined(__STDC_IEC_559__) || __GCC_IEC_559 >= 1
+/* we can safely assume 'float' is in the single precision
+ IEC 60559 binary format in host order */
+ union {
+ float r;
+ uint32_t d;
+ } u;
+ u.d = stream_getl (s);
+ return u.r;
+#else
+#error "Please supply stream_getf implementation for this platform"
+#endif
+}
+
+double
+stream_getd (struct stream *s)
+{
+#if defined(__STDC_IEC_559__) || __GCC_IEC_559 >= 1
+ union {
+ double r;
+ uint64_t d;
+ } u;
+ u.d = stream_getq (s);
+ return u.r;
+#else
+#error "Please supply stream_getd implementation for this platform"
+#endif
+}
+
/* Copy to source to stream.
*
* XXX: This uses CHECK_SIZE and hence has funny semantics -> Size will wrap
@@ -602,6 +636,38 @@
}
int
+stream_putf (struct stream *s, float f)
+{
+#if defined(__STDC_IEC_559__) || __GCC_IEC_559 >= 1
+/* we can safely assume 'float' is in the single precision
+ IEC 60559 binary format in host order */
+ union {
+ float i;
+ uint32_t o;
+ } u;
+ u.i = f;
+ return stream_putl (s, u.o);
+#else
+#error "Please supply stream_putf implementation for this platform"
+#endif
+}
+
+int
+stream_putd (struct stream *s, double d)
+{
+#if defined(__STDC_IEC_559__) || __GCC_IEC_559 >= 1
+ union {
+ double i;
+ uint64_t o;
+ } u;
+ u.i = d;
+ return stream_putq (s, u.o);
+#else
+#error "Please supply stream_putd implementation for this platform"
+#endif
+}
+
+int
stream_putc_at (struct stream *s, size_t putp, u_char c)
{
STREAM_VERIFY_SANE(s);
diff --git a/lib/stream.h b/lib/stream.h
index 1fc382d..06b0ee1 100644
--- a/lib/stream.h
+++ b/lib/stream.h
@@ -186,6 +186,12 @@
extern uint64_t stream_getq_from (struct stream *, size_t);
extern u_int32_t stream_get_ipv4 (struct stream *);
+/* IEEE-754 floats */
+extern float stream_getf (struct stream *);
+extern double stream_getd (struct stream *);
+extern int stream_putf (struct stream *, float);
+extern int stream_putd (struct stream *, double);
+
#undef stream_read
#undef stream_write