Add fallback_type option (#772, #773)

This option sets the type used by FT_DEFAULT when static allocation is not possible.

Co-authored-by: Conrad Wood <cnw@singingcat.net>
diff --git a/generator/nanopb_generator.py b/generator/nanopb_generator.py
index 8ebab21..902b884 100755
--- a/generator/nanopb_generator.py
+++ b/generator/nanopb_generator.py
@@ -488,7 +488,7 @@
         self.callback_datatype = field_options.callback_datatype
         self.math_include_required = False
         self.sort_by_tag = field_options.sort_by_tag
-
+        
         if field_options.type == nanopb_pb2.FT_INLINE:
             # Before nanopb-0.3.8, fixed length bytes arrays were specified
             # by setting type to FT_INLINE. But to handle pointer typed fields,
@@ -554,7 +554,7 @@
             if can_be_static:
                 field_options.type = nanopb_pb2.FT_STATIC
             else:
-                field_options.type = nanopb_pb2.FT_CALLBACK
+                field_options.type = field_options.fallback_type
 
         if field_options.type == nanopb_pb2.FT_STATIC and not can_be_static:
             raise Exception("Field '%s' is defined as static, but max_size or "
diff --git a/generator/proto/nanopb.proto b/generator/proto/nanopb.proto
index 88ac2f6..b79267c 100644
--- a/generator/proto/nanopb.proto
+++ b/generator/proto/nanopb.proto
@@ -147,6 +147,12 @@
   // instead of the order in .proto. Set this to false to keep the .proto order.
   // The default value will probably change to false in nanopb-0.5.0.
   optional bool sort_by_tag = 28 [default = true];
+
+  // this affects the FT_DEFAULT (the default) field conversion strategy. A field
+  // that can become a static member of a c struct (e.g. int, bool, etc) will be a
+  // a static field. Fields with dynamic length are converted, to either a pointer or a callback.
+  // this defines wether it becomes a pointer or a callback.
+  optional FieldType fallback_type = 29 [default = FT_CALLBACK]; 
 }
 
 // Extensions to protoc 'Descriptor' type in order to define options
diff --git a/tests/fallback_type/SConscript b/tests/fallback_type/SConscript
new file mode 100644
index 0000000..22a7b1e
--- /dev/null
+++ b/tests/fallback_type/SConscript
@@ -0,0 +1,11 @@
+# Test fallback type
+
+Import("env")
+# the scons version on ubuntu honours this env - debians version does not
+# env['NANOPB_GENERATOR'] = env['NANOPB_GENERATOR'] + "-sfallback_type:FT_POINTER"
+# env.SetDefault(PROTOCFLAGS = "--plugin=protoc-gen-nanopb=foo")
+
+# so we also use an options file:
+env.NanopbProto(["fallback_type","fallback_type.options"])
+env.Object("fallback_type.pb.c")
+env.Match(['fallback_type.pb.h', 'fallback_type.expected'])
diff --git a/tests/fallback_type/fallback_type.expected b/tests/fallback_type/fallback_type.expected
new file mode 100644
index 0000000..3eff62b
--- /dev/null
+++ b/tests/fallback_type/fallback_type.expected
@@ -0,0 +1,2 @@
+int32_t member1;
+char \*member2
diff --git a/tests/fallback_type/fallback_type.options b/tests/fallback_type/fallback_type.options
new file mode 100644
index 0000000..29eddfa
--- /dev/null
+++ b/tests/fallback_type/fallback_type.options
@@ -0,0 +1 @@
+fallback_type.proto fallback_type:FT_POINTER
\ No newline at end of file
diff --git a/tests/fallback_type/fallback_type.proto b/tests/fallback_type/fallback_type.proto
new file mode 100644
index 0000000..97d069b
--- /dev/null
+++ b/tests/fallback_type/fallback_type.proto
@@ -0,0 +1,8 @@
+syntax = "proto2";
+
+message Message1
+{
+  required int32 member1 = 1; // must remain as int
+  required string member2 = 2; // must become a pointer
+}
+