Index: cpp/frams/genetics/genman.cpp
===================================================================
--- cpp/frams/genetics/genman.cpp	(revision 896)
+++ cpp/frams/genetics/genman.cpp	(revision 955)
@@ -1,4 +1,4 @@
 // This file is a part of Framsticks SDK.  http://www.framsticks.com/
-// Copyright (C) 1999-2018  Maciej Komosinski and Szymon Ulatowski.
+// Copyright (C) 1999-2020  Maciej Komosinski and Szymon Ulatowski.
 // See LICENSE.txt for details.
 
@@ -68,4 +68,7 @@
 #ifdef USE_GENMAN_fL
 #include "fL/fL_oper.h"
+#endif
+#ifdef USE_GENMAN_fS
+#include "fS/fS_oper.h"
 #endif
 
@@ -177,4 +180,7 @@
 	oper_fx_list.push_back(new Geno_fL);
 #endif
+#ifdef USE_GENMAN_fS
+	oper_fx_list.push_back(new GenoOper_fS);
+#endif
 
 	seloper = new int[oper_fx_list.size()]; //may result in a little overhead if some of the operators on the oper_fx_list concern the same genetic format
@@ -182,5 +188,5 @@
 	for (unsigned int i = 0; i < oper_fx_list.size(); i++)
 	{
-		if (operformats.find(oper_fx_list[i]->supported_format) != -1) continue;
+		if (findOperFormatIndex(oper_fx_list[i]->supported_format) != -1) continue;
 		string type = string("~") + oper_fx_list[i]->name;
 		int dup = 0;
@@ -188,15 +194,15 @@
 			if (oper_fx_list[i]->supported_format == oper_fx_list[j]->supported_format)
 			{
-			type += "~";
-			type += oper_fx_list[j]->name;
-			dup++;
+				type += "~";
+				type += oper_fx_list[j]->name;
+				dup++;
 			}
 		type = ssprintf("d 0 %d ", dup) + type;
-		string id = ssprintf("genoper_f%c", oper_fx_list[i]->supported_format);
-		string name = ssprintf("Operators for f%c", oper_fx_list[i]->supported_format);
+		string id = ssprintf("genoper_f%s", oper_fx_list[i]->supported_format.c_str());
+		string name = ssprintf("Operators for f%s", oper_fx_list[i]->supported_format.c_str());
 		seloper[selopercount] = 0;
-		operformats += oper_fx_list[i]->supported_format;
+		operformats += &oper_fx_list[i]->supported_format;
 		//printf("%x %s %s %s\n",&seloper[selopercount],(const char*)id,(const char*)type,(const char*)name);
-		seloperpar.addProperty(&seloper[selopercount++], id.c_str(), type.c_str(), name.c_str(), "", PARAM_READONLY*(dup == 0));
+		seloperpar.addProperty(&seloper[selopercount++], id.c_str(), type.c_str(), name.c_str(), "", PARAM_READONLY * (dup == 0));
 	}
 
@@ -214,4 +220,12 @@
 	for (unsigned int i = 0; i < oper_fx_list.size(); i++) delete oper_fx_list[i];
 	delete[] seloper;
+}
+
+int GenMan::findOperFormatIndex(const SString& format)
+{
+	for (int i = 0; i < operformats.size(); i++)
+		if (*operformats(i) == format)
+			return i;
+	return -1;
 }
 
@@ -265,8 +279,8 @@
 Geno GenMan::validate(const Geno& geny)
 {
-	char format = geny.getFormat();
+	SString format = geny.getFormat();
 	GenoOperators *gf = getOper_f(format);
 	if (gf == NULL)
-		return Geno(SString::empty(), -1, SString::empty(), SString::sprintf("GENOPER_NOOPER: Validate(): don't know how to handle genetic format %c", format));
+		return Geno("", Geno::INVALID_FORMAT, "", SString::sprintf("GENOPER_NOOPER: Validate(): don't know how to handle genetic format %s", format.c_str()));
 	char *g2 = strdup(geny.getGenes().c_str()); //copy for validation
 	int res = gf->validate(g2, geny.getName().c_str());
@@ -276,5 +290,5 @@
 		return Geno(sg2, format, geny.getName(), geny.getComment());
 	else
-		return Geno(SString::empty(), -1, SString::empty(), SString::sprintf("GENOPER_NOOPER: validate() for format %c returned invalid value", format));
+		return Geno("", Geno::INVALID_FORMAT, "", SString::sprintf("GENOPER_NOOPER: validate() for format %s returned invalid value", format.c_str()));
 }
 
@@ -283,12 +297,12 @@
 	float chg; //how many changes
 	int method; //mutation method
-	char format = g.getFormat();
+	SString format = g.getFormat();
 	GenoOperators *gf = getOper_f(format);
 	if (gf == NULL)
-		return Geno(SString::empty(), -1, SString::empty(), SString::sprintf("GENOPER_NOOPER: Mutate(): don't know how to handle genetic format %c", format));
+		return Geno("", Geno::INVALID_FORMAT, "", SString::sprintf("GENOPER_NOOPER: Mutate(): don't know how to handle genetic format %s", format.c_str()));
 	Geno gv = g;
 	bool canvalidate = true;
 	if (testValidity(gv, canvalidate) > 0 && canvalidate == false)
-		return Geno("", -1, "", "GENOPER_OPFAIL: Mutate(): cannot validate invalid source genotype");
+		return Geno("", Geno::INVALID_FORMAT, "", "GENOPER_OPFAIL: Mutate(): cannot validate invalid source genotype");
 	bool ok = false;
 	int pcount = count;
@@ -307,5 +321,5 @@
 				if (res > 0 && canvalidate == false) invalid_m++; else
 				{
-				validated_m++; ok = true;
+					validated_m++; ok = true;
 				}
 			if (ok) gv = G;
@@ -316,5 +330,5 @@
 		if (!ok && (count - pcount > GENMAN_REPEAT_FAILED))
 		{
-			logPrintf("GenMan", "Mutate", 2, "Tried " GENMAN_REPEAT_FAILED_STR "x and failed: %s", g.getGenes().c_str());
+			logPrintf("GenMan", "Mutate", LOG_WARN, "Tried " GENMAN_REPEAT_FAILED_STR "x and failed: %s", g.getGenes().c_str());
 			return Geno("", -1, "", "GENOPER_OPFAIL: Mutate() tried " GENMAN_REPEAT_FAILED_STR "x and failed");
 		}
@@ -332,9 +346,9 @@
 Geno GenMan::crossOver(const Geno& g1, const Geno& g2)
 {
-	char format = g1.getFormat();
-	if (format != g2.getFormat()) return Geno(SString::empty(), -1, SString::empty(), SString::sprintf("GENOPER_NOOPER: CrossOver(): does not work for parents with differing genetic formats (%c and %c)", format, g2.getFormat()));
+	SString format = g1.getFormat();
+	if (format != g2.getFormat()) return Geno("", Geno::INVALID_FORMAT, "", SString::sprintf("GENOPER_NOOPER: CrossOver(): does not work for parents with differing genetic formats (%s and %s)", format.c_str(), g2.getFormat().c_str()));
 	GenoOperators *gf = getOper_f(format);
 	if (gf == NULL)
-		return Geno(SString::empty(), -1, SString::empty(), SString::sprintf("GENOPER_NOOPER: CrossOver(): no operators found for genetic format %c", format));
+		return Geno("", Geno::INVALID_FORMAT, "", SString::sprintf("GENOPER_NOOPER: CrossOver(): no operators found for genetic format %s", format.c_str()));
 	Geno g1v = g1, g2v = g2;
 
@@ -343,8 +357,8 @@
 		bool canvalidate = true;
 		if (testValidity(g1v, canvalidate) > 0 && canvalidate == false)
-			return Geno("", -1, "", "GENOPER_OPFAIL: CrossOver(): cannot validate invalid source genotype #1");
+			return Geno("", Geno::INVALID_FORMAT, "", "GENOPER_OPFAIL: CrossOver(): cannot validate invalid source genotype #1");
 		canvalidate = true;
 		if (testValidity(g2v, canvalidate) > 0 && canvalidate == false)
-			return Geno("", -1, "", "GENOPER_OPFAIL: CrossOver(): cannot validate invalid source genotype #2");
+			return Geno("", Geno::INVALID_FORMAT, "", "GENOPER_OPFAIL: CrossOver(): cannot validate invalid source genotype #2");
 	}
 
@@ -373,5 +387,5 @@
 				if (res > 0 && canvalidate == false) invalid_xo++; else
 				{
-				validated_xo++; ok = true;
+					validated_xo++; ok = true;
 				}
 			if (ok) g1v = G;
@@ -383,6 +397,6 @@
 		if (!ok && (count - pcount > GENMAN_REPEAT_FAILED))
 		{
-			logPrintf("GenMan", "CrossOver", 2, "Tried " GENMAN_REPEAT_FAILED_STR "x and failed: %s and %s", g1.getGenes().c_str(), g2.getGenes().c_str());
-			return Geno("", -1, "", "GENOPER_OPFAIL: CrossOver() tried " GENMAN_REPEAT_FAILED_STR "x and failed");
+			logPrintf("GenMan", "CrossOver", LOG_WARN, "Tried " GENMAN_REPEAT_FAILED_STR "x and failed: %s and %s", g1.getGenes().c_str(), g2.getGenes().c_str());
+			return Geno("", Geno::INVALID_FORMAT, "", "GENOPER_OPFAIL: CrossOver() tried " GENMAN_REPEAT_FAILED_STR "x and failed");
 		}
 	}
@@ -398,5 +412,5 @@
 float GenMan::similarity(const Geno& g1, const Geno& g2)
 {
-	char format = g1.getFormat();
+	SString format = g1.getFormat();
 	if (format != g2.getFormat()) return GENOPER_NOOPER;
 	GenoOperators *gf = getOper_f(format);
@@ -406,5 +420,5 @@
 uint32_t GenMan::getStyle(const char *g, const Geno *G, int pos)
 {
-	char format = G->getFormat();
+	SString format = G->getFormat();
 	if (format == Geno::INVALID_FORMAT)
 		return GENSTYLE_RGBS(64, 64, 64, 0); // gray & "valid" (unknown format so we don't know what is valid and what is not)
@@ -423,5 +437,5 @@
 void GenMan::getFullStyle(const char *g, const Geno *G, uint32_t *styletab)
 {
-	char format = G->getFormat();
+	SString format = G->getFormat();
 	if (format == Geno::INVALID_FORMAT)
 	{
@@ -438,5 +452,5 @@
 		else if (!gf) styletab[pos] = GENSTYLE_CS(0, 0); //black & valid
 		else styletab[pos] = gf->style(geny.c_str(), posmapped);
-		//logPrintf("GenMan", "getFullStyle", 0, "%d  char='%c' (%d)  format=0x%08x", pos, g[pos], g[pos], styletab[pos]);
+		//logPrintf("GenMan", "getFullStyle", LOG_INFO, "%d  char='%c' (%d)  format=0x%08x", pos, g[pos], g[pos], styletab[pos]);
 	}
 }
@@ -473,15 +487,15 @@
 		color = GENGETCOLOR(styletab[i]);
 		if ((i != 0 && (color != prevcolor))) html += "</font>";
-		if ((style&GENSTYLE_INVALID) != (prevstyle&GENSTYLE_INVALID))
-		{
-			html += "<"; if (!(style&GENSTYLE_INVALID)) html += "/"; html += "u>";
-		}
-		if ((style&GENSTYLE_BOLD) != (prevstyle&GENSTYLE_BOLD))
-		{
-			html += "<"; if (!(style&GENSTYLE_BOLD)) html += "/"; html += "b>";
-		}
-		if ((style&GENSTYLE_ITALIC) != (prevstyle&GENSTYLE_ITALIC))
-		{
-			html += "<"; if (!(style&GENSTYLE_ITALIC)) html += "/"; html += "i>";
+		if ((style & GENSTYLE_INVALID) != (prevstyle & GENSTYLE_INVALID))
+		{
+			html += "<"; if (!(style & GENSTYLE_INVALID)) html += "/"; html += "u>";
+		}
+		if ((style & GENSTYLE_BOLD) != (prevstyle & GENSTYLE_BOLD))
+		{
+			html += "<"; if (!(style & GENSTYLE_BOLD)) html += "/"; html += "b>";
+		}
+		if ((style & GENSTYLE_ITALIC) != (prevstyle & GENSTYLE_ITALIC))
+		{
+			html += "<"; if (!(style & GENSTYLE_ITALIC)) html += "/"; html += "i>";
 		}
 		if ((i == 0 || (color != prevcolor)))
@@ -509,9 +523,9 @@
 }
 
-Geno GenMan::getSimplest(char format)
+Geno GenMan::getSimplest(const SString& format)
 {
 	GenoOperators *gf = getOper_f(format);
 	if (!gf) return Geno();
-	string info = "The simplest genotype of format f"; info += format;
+	string info = "The simplest genotype of format f"; info += format.c_str();
 	info += " for operators '"; info += gf->name; info += "'.";
 	return Geno(gf->getSimplest(), format, "Root", info.c_str());
@@ -520,5 +534,5 @@
 void GenMan::p_getsimplest(ExtValue *args, ExtValue *ret)
 {
-	int format = GenoObj::formatFromExtValue(args[0]);
+	SString format = GenoObj::formatFromExtValue(args[0]);
 	if (!getOper_f(format))
 		ret->setEmpty();
@@ -527,5 +541,5 @@
 }
 
-const char *GenMan::getOpName(char format)
+const char *GenMan::getOpName(const SString& format)
 {
 	GenoOperators *gf = getOper_f(format);
@@ -533,7 +547,7 @@
 }
 
-GenoOperators* GenMan::getOper_f(char format)
-{
-	int ind = operformats.find(format);
+GenoOperators* GenMan::getOper_f(const SString& format)
+{
+	int ind = findOperFormatIndex(format);
 	if (ind == -1) return NULL;
 	int which_oper_of_format = seloper[ind];
@@ -602,6 +616,6 @@
 		}
 		//      if (oper_fx_list[i]->similarity("","")!=GENOPER_NOOPER) l+=" similarity";
-		logPrintf("GenMan", "Report", 0, "format f%c (%s):%s",
-			oper_fx_list[i]->supported_format, oper_fx_list[i]->name.c_str(), l.c_str());
+		logPrintf("GenMan", "Report", LOG_INFO, "format f%s (%s):%s",
+			oper_fx_list[i]->supported_format.c_str(), oper_fx_list[i]->name.c_str(), l.c_str());
 	}
 }
