Add support for infinity and nan floating-point defaults (#530) (#538)

diff --git a/generator/nanopb_generator.py b/generator/nanopb_generator.py
index ae16064..b572940 100755
--- a/generator/nanopb_generator.py
+++ b/generator/nanopb_generator.py
@@ -354,6 +354,7 @@
         self.ctype = None
         self.fixed_count = False
         self.callback_datatype = field_options.callback_datatype
+        self.math_include_required = False
 
         if field_options.type == nanopb_pb2.FT_INLINE:
             # Before nanopb-0.3.8, fixed length bytes arrays were specified
@@ -487,6 +488,10 @@
         else:
             raise NotImplementedError(desc.type)
 
+        if self.default and self.pbtype in ['FLOAT', 'DOUBLE']:
+            if 'inf' in self.default or 'nan' in self.default:
+                self.math_include_required = True
+
     def __lt__(self, other):
         return self.tag < other.tag
 
@@ -584,11 +589,15 @@
                 inner_init = str(self.default) + 'ull'
             elif self.pbtype in ['SFIXED64', 'INT64']:
                 inner_init = str(self.default) + 'll'
-            elif self.pbtype == 'FLOAT':
+            elif self.pbtype in ['FLOAT', 'DOUBLE']:
                 inner_init = str(self.default)
-                if not '.' in inner_init:
+                if 'inf' in inner_init:
+                    inner_init = inner_init.replace('inf', 'INFINITY')
+                elif 'nan' in inner_init:
+                    inner_init = inner_init.replace('nan', 'NAN')
+                elif (not '.' in inner_init) and self.pbtype == 'FLOAT':
                     inner_init += '.0f'
-                else:
+                elif self.pbtype == 'FLOAT':
                     inner_init += 'f'
             else:
                 inner_init = str(self.default)
@@ -964,6 +973,7 @@
         self.fields = []
         self.oneofs = {}
         self.desc = desc
+        self.math_include_required = False
 
         if message_options.msgid:
             self.msgid = message_options.msgid
@@ -1017,6 +1027,8 @@
                     self.oneofs[f.oneof_index].add_field(field)
             else:
                 self.fields.append(field)
+                if field.math_include_required:
+                    self.math_include_required = True
 
         if len(desc.extension_range) > 0:
             field_options = get_nanopb_suboptions(desc, message_options, self.name + 'extensions')
@@ -1354,7 +1366,12 @@
         self.fdesc = fdesc
         self.file_options = file_options
         self.dependencies = {}
+        self.math_include_required = False
         self.parse()
+        for message in self.messages:
+            if message.math_include_required:
+                self.math_include_required = True
+                break
 
         # Some of types used in this file probably come from the file itself.
         # Thus it has implicit dependency on itself.
@@ -1489,6 +1506,8 @@
             symbol = make_identifier(headername)
         yield '#ifndef PB_%s_INCLUDED\n' % symbol
         yield '#define PB_%s_INCLUDED\n' % symbol
+        if self.math_include_required:
+            yield '#include <math.h>\n'
         try:
             yield options.libformat % ('pb.h')
         except TypeError:
diff --git a/tests/infinity_nan/SConscript b/tests/infinity_nan/SConscript
new file mode 100644
index 0000000..748719d
--- /dev/null
+++ b/tests/infinity_nan/SConscript
@@ -0,0 +1,8 @@
+# Build and run a basic test for floating point default values.
+
+Import("env")
+
+env.NanopbProto("floats")
+test = env.Program(["infinity_nan_test.c", "floats.pb.c", "$COMMON/pb_decode.o", "$COMMON/pb_common.o"])
+
+env.RunTest(test)
diff --git a/tests/infinity_nan/floats.proto b/tests/infinity_nan/floats.proto
new file mode 100644
index 0000000..7a5f40d
--- /dev/null
+++ b/tests/infinity_nan/floats.proto
@@ -0,0 +1,12 @@
+syntax = "proto2";
+
+message Floats {
+    optional float float_pos_inf = 1 [default = inf];
+    optional float float_neg_inf = 2 [default = -inf];
+    optional float float_pos_nan = 3 [default = nan];
+    optional float float_neg_nan = 4 [default = -nan];
+    optional double double_pos_inf = 5 [default = inf];
+    optional double double_neg_inf = 6 [default = -inf];
+    optional double double_pos_nan = 7 [default = nan];
+    optional double double_neg_nan = 8 [default = -nan];
+}
diff --git a/tests/infinity_nan/infinity_nan_test.c b/tests/infinity_nan/infinity_nan_test.c
new file mode 100644
index 0000000..ce06c62
--- /dev/null
+++ b/tests/infinity_nan/infinity_nan_test.c
@@ -0,0 +1,62 @@
+/* Tests for floating point default values +-infinity and nan. */
+#undef __STRICT_ANSI__
+#include <math.h>
+#include <pb_decode.h>
+#include "floats.pb.h"
+#include "unittests.h"
+
+bool check_floats(Floats *floats)
+{
+    int status = 0;
+
+    TEST(!floats->has_float_pos_inf);
+    TEST(isinf(floats->float_pos_inf));
+    TEST(!signbit(floats->float_pos_inf));
+
+    TEST(!floats->has_float_neg_inf);
+    TEST(isinf(floats->float_neg_inf));
+    TEST(signbit(floats->float_neg_inf));
+
+    TEST(!floats->has_float_pos_nan);
+    TEST(isnan(floats->float_pos_nan));
+
+    TEST(!floats->has_float_neg_nan);
+    TEST(isnan(floats->float_neg_nan));
+
+    TEST(!floats->has_double_pos_inf);
+    TEST(isinf(floats->double_pos_inf));
+    TEST(!signbit(floats->double_pos_inf));
+
+    TEST(!floats->has_double_neg_inf);
+    TEST(isinf(floats->double_neg_inf));
+    TEST(signbit(floats->double_neg_inf));
+
+    TEST(!floats->has_double_pos_nan);
+    TEST(isnan(floats->double_pos_nan));
+
+    TEST(!floats->has_double_neg_nan);
+    TEST(isnan(floats->double_neg_nan));
+
+    return status == 0;
+}
+
+int main()
+{
+    int status = 0;
+
+    {
+        Floats floats = Floats_init_default;
+        COMMENT("Checking init_default");
+        TEST(check_floats(&floats));
+    }
+
+    {
+        Floats floats = {0};
+        pb_istream_t stream = pb_istream_from_buffer(NULL, 0);
+        COMMENT("Check decoded");
+        TEST(pb_decode(&stream, Floats_fields, &floats));
+        TEST(check_floats(&floats));
+    }
+
+    return status;
+}