Index: /cpp/frams/param/param.cpp
===================================================================
--- /cpp/frams/param/param.cpp	(revision 821)
+++ /cpp/frams/param/param.cpp	(revision 822)
@@ -11,4 +11,9 @@
 #include <frams/util/sstringutils.h>
 #include <common/virtfile/stringfile.h>
+
+#ifdef _DEBUG
+//for sanityCheck - mutable param detection
+#include "mutparamiface.h"
+#endif
 
 //#define SAVE_ALL_NAMES
@@ -54,8 +59,8 @@
 			&& (*type(i) != 'p'))
 		{
-		j = src->findId(id(i));
-		if (j < 0) continue;
-		src->get(j, v);
-		set(i, v);
+			j = src->findId(id(i));
+			if (j < 0) continue;
+			src->get(j, v);
+			set(i, v);
 		}
 }
@@ -69,6 +74,6 @@
 			&& (*type(i) != 'p'))
 		{
-		src->get(i, v);
-		set(i, v);
+			src->get(i, v);
+			set(i, v);
 		}
 }
@@ -157,5 +162,5 @@
 		setDouble(i, def);
 	}
-		break;
+	break;
 	case 'd':
 	{
@@ -164,5 +169,5 @@
 		setInt(i, def);
 	}
-		break;
+	break;
 	case 's': case 'x':
 	{
@@ -176,5 +181,5 @@
 		}
 	}
-		break;
+	break;
 	case 'o':
 		setObject(i, ExtObject::empty());
@@ -194,5 +199,5 @@
 		setDouble(i, mn);
 	}
-		break;
+	break;
 	case 'd':
 	{
@@ -201,5 +206,5 @@
 		setInt(i, mn);
 	}
-		break;
+	break;
 	default: setFromString(i, "", false);
 	}
@@ -217,5 +222,5 @@
 		setDouble(i, mx);
 	}
-		break;
+	break;
 	case 'd':
 	{
@@ -224,5 +229,5 @@
 		setInt(i, mx);
 	}
-		break;
+	break;
 	default: setFromString(i, "", false);
 	}
@@ -370,36 +375,36 @@
 		if (!((fl = flags(i))&PARAM_DONTSAVE))
 		{
-		if (defdata && isequal(i, defdata))
-			needlabel = 1;
-		else
-		{
-			if (!first) t += ", ";
+			if (defdata && isequal(i, defdata))
+				needlabel = 1;
+			else
+			{
+				if (!first) t += ", ";
 #ifndef SAVE_ALL_NAMES
 #ifdef SAVE_SELECTED_NAMES
-			if (needlabel || all_names || !(fl & PARAM_CANOMITNAME))
+				if (needlabel || all_names || !(fl & PARAM_CANOMITNAME))
 #else
-			if (needlabel)
+				if (needlabel)
 #endif
 #endif
-			{
-				t += p; t += "="; needlabel = 0;
-			}
-			if (type(i)[0] == 's')
-			{ // string - special case
-				SString str = getString(i);
-				if (strContainsOneOf(str.c_str(), ", \\\n\r\t\""))
 				{
-					t += "\"";
-					sstringQuote(str);
-					t += str;
-					t += "\"";
+					t += p; t += "="; needlabel = 0;
+				}
+				if (type(i)[0] == 's')
+				{ // string - special case
+					SString str = getString(i);
+					if (strContainsOneOf(str.c_str(), ", \\\n\r\t\""))
+					{
+						t += "\"";
+						sstringQuote(str);
+						t += str;
+						t += "\"";
+					}
+					else
+						t += str;
 				}
 				else
-					t += str;
+					t += get(i);
+				first = 0;
 			}
-			else
-				t += get(i);
-			first = 0;
-		}
 		}
 	if (addcr)
@@ -445,5 +450,5 @@
 			(setflags&PSET_HITMAX) ? (s_type ? "long" : "big") : "small", s_type ? "Truncated" : "Adjusted",
 			::sstringDelimitAndShorten(actual, 30, show_length, quote, quote).c_str()
-			);
+		);
 	}
 }
@@ -569,5 +574,5 @@
 						if ((tmp = strchr(tmp, '\n')))
 						{
-						lfcount++; tmp++;
+							lfcount++; tmp++;
 						}
 					removeCR(s);
@@ -606,5 +611,5 @@
 					if ((tmp = strchr(tmp, '\n')))
 					{
-					lfcount++; tmp++;
+						lfcount++; tmp++;
 					}
 				(*options.linenum) += lfcount;
@@ -834,5 +839,5 @@
 		if ((have >= 2) && (b < a) && (a != 0) && (b != -1)) return false; // max<min meaning 'undefined' is only allowed as "d 0 -1"
 	}
-		break;
+	break;
 	case 'f':
 	{
@@ -842,5 +847,5 @@
 		if ((have >= 2) && (b < a) && (a != 0) && (b != -1)) return false; // max<min meaning 'undefined' is only allowed as "f 0 -1"
 	}
-		break;
+	break;
 	case 's':
 	{
@@ -851,5 +856,5 @@
 		if ((have >= 2) && (b < 0)) return false; // max=0 means unlimited, max<0 is not allowed
 	}
-		break;
+	break;
 	}
 	return true;
@@ -863,11 +868,11 @@
 	case 'd': t += "integer";
 	{paInt a, b, c; int n = getMinMaxIntFromTypeDef(type, a, b, c); if ((n >= 2) && (b >= a)) t += SString::sprintf(" %d..%d", a, b); if (n >= 3) t += SString::sprintf(" (default %d)", c); }
-		break;
+	break;
 	case 'f': t += "float";
 	{double a, b, c; int n = getMinMaxDoubleFromTypeDef(type, a, b, c); if ((n >= 2) && (b >= a)) t += SString::sprintf(" %g..%g", a, b); if (n >= 3) t += SString::sprintf(" (default %g)", c); }
-		break;
+	break;
 	case 's': t += "string";
 	{int a, b; SString c; int n = getMinMaxStringFromTypeDef(type, a, b, c); if ((n >= 2) && (b > 0)) t += SString::sprintf(", max %d chars", b); if (n >= 3) t += SString::sprintf(" (default \"%s\")", c.c_str()); }
-		break;
+	break;
 	case 'x': t += "untyped value"; break;
 	case 'p': t += "function"; break;
@@ -893,5 +898,9 @@
 	{
 		if (pe->fun1 == NULL)
-			err = "no procedure defined";
+		{
+			MutableParamInterface *mpi = dynamic_cast<MutableParamInterface*>(this);
+			if (mpi == NULL) // Avoid false positives for script-driven mutable params, like expdefs. This can't be reliably verified. Function pointer checking is meant for static param tables anyway so it's probably not a big deal.
+				err = "no procedure defined";
+		}
 		if (pe->flags & PARAM_READONLY)
 			err = "function can't be PARAM_READONLY";
@@ -911,5 +920,5 @@
 	if (err != NULL)
 		logPrintf("SimpleAbstractParam", "sanityCheck", LOG_ERROR,
-		"Invalid ParamEntry for %s.%s (%s)", getName(), pe->id, err);
+			"Invalid ParamEntry for %s.%s (%s)", getName(), pe->id, err);
 }
 #endif
@@ -1029,6 +1038,6 @@
 		if (mn <= mx) // else if mn>mx then the min/max constraint makes no sense and there is no checking
 		{
-		if (x < mn) { x = mn; result = PSET_HITMIN; }
-		else if (x > mx) { x = mx; result = PSET_HITMAX; }
+			if (x < mn) { x = mn; result = PSET_HITMIN; }
+			else if (x > mx) { x = mx; result = PSET_HITMAX; }
 		}
 
@@ -1063,6 +1072,6 @@
 		if (mn <= mx) // else if mn>mx then the min/max constraint makes no sense and there is no checking
 		{
-		if (x < mn) { x = mn; result = PSET_HITMIN; }
-		else if (x > mx) { x = mx; result = PSET_HITMAX; }
+			if (x < mn) { x = mn; result = PSET_HITMIN; }
+			else if (x > mx) { x = mx; result = PSET_HITMAX; }
 		}
 
@@ -1145,5 +1154,5 @@
 		else
 			logPrintf("SimpleAbstractParam", "setObject", LOG_ERROR,
-			"'%s.%s' is PARAM_OBJECTSET but no 'assign()' in %s", getName(), pe->id, o.interfaceName());
+				"'%s.%s' is PARAM_OBJECTSET but no 'assign()' in %s", getName(), pe->id, o.interfaceName());
 		return PSET_CHANGED;
 	}
@@ -1263,5 +1272,5 @@
 		field_end = strchrlimit(t, ',', end); if (!field_end) field_end = end;
 		next_field = field_end;
-		while ((field_end>t) && isblank(field_end[-1])) field_end--;
+		while ((field_end > t) && isblank(field_end[-1])) field_end--;
 		quote = strchrlimit(t, '\"', field_end);
 		if (quote)
@@ -1304,8 +1313,8 @@
 #endif
 			{
-			if (id(i))
-				logPrintf("Param", "loadSingleLine", LOG_WARN, "Missing property name in '%s' (assuming '%s')", getName(), id(i));
-			else
-				logPrintf("Param", "loadSingleLine", LOG_WARN, "Value after the last property of '%s'", getName());
+				if (id(i))
+					logPrintf("Param", "loadSingleLine", LOG_WARN, "Missing property name in '%s' (assuming '%s')", getName(), id(i));
+				else
+					logPrintf("Param", "loadSingleLine", LOG_WARN, "Value after the last property of '%s'", getName());
 			}
 #endif
