diff --git a/docs/sdk/script/fn/ParseInt.xml b/docs/sdk/script/fn/ParseInt.xml
new file mode 100644
index 000000000..094ea17f2
--- /dev/null
+++ b/docs/sdk/script/fn/ParseInt.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+ ParseInt
+ Arithmetics
+ 8.0 OC
+
+ int
+
+
+ string
+ value
+ Absolute coordinate you want to convert to a relative coordinate.
+
+
+
+ Parses a string representing a base 10 number into an integer value. If the string does not entirely consist of a base 10 number, optionally signed, nil
is returned.
+
+
+ ParseInt("14")
+ Returns the integer 14
.
+ ParseInt("fourteen")
+ Returns nil
.
+
+
+
+
diff --git a/src/lib/Standard.cpp b/src/lib/Standard.cpp
index 0acdaebcf..ac2357616 100644
--- a/src/lib/Standard.cpp
+++ b/src/lib/Standard.cpp
@@ -94,8 +94,9 @@ static int ToNumber(char c)
//------------------------------- Strings ------------------------------------------------
-int32_t StrToI32(const char *s, int base, const char **scan_end)
+int32_t StrToI32(const char *str, int base, const char **scan_end)
{
+ const char *s = str;
int sign = 1;
int32_t result = 0;
if (*s == '-')
@@ -107,6 +108,12 @@ int32_t StrToI32(const char *s, int base, const char **scan_end)
{
s++;
}
+ if (!*s)
+ {
+ // Abort if there are no digits to parse
+ if (scan_end) *scan_end = str;
+ return 0;
+ }
while (IsNumber(*s,base))
{
int value = ToNumber(*s++);
diff --git a/src/script/C4Script.cpp b/src/script/C4Script.cpp
index 042a9a4d0..26d3dddcd 100644
--- a/src/script/C4Script.cpp
+++ b/src/script/C4Script.cpp
@@ -617,6 +617,16 @@ static C4Value FnFormat(C4PropList * _this, C4Value * Pars)
return C4VString(FnStringFormat(_this, Pars[0].getStr(), &Pars[1], 9));
}
+// Parse a string into an integer. Returns nil if the conversion fails.
+static Nillable FnParseInt(C4PropList *_this, C4String *str)
+{
+ const char *cstr = str->GetCStr();
+ const char *end = nullptr;
+ int32_t result = StrToI32(cstr, 10, &end);
+ if (end == cstr || *end != '\0') return C4Void();
+ return result;
+}
+
static long FnAbs(C4PropList * _this, long iVal)
{
return Abs(iVal);
@@ -1142,6 +1152,7 @@ void InitCoreFunctionMap(C4AulScriptEngine *pEngine)
for (C4ScriptFnDef *pDef = &C4ScriptFnMap[0]; pDef->Identifier; pDef++)
new C4AulDefFunc(p, pDef);
#define F(f) ::AddFunc(p, #f, Fn##f)
+ F(ParseInt);
F(Abs);
F(Min);
F(Max);
diff --git a/tests/aul/AulPredefinedFunctionTest.cpp b/tests/aul/AulPredefinedFunctionTest.cpp
index e62d84497..190347cee 100644
--- a/tests/aul/AulPredefinedFunctionTest.cpp
+++ b/tests/aul/AulPredefinedFunctionTest.cpp
@@ -147,6 +147,25 @@ TEST_F(AulPredefFunctionTest, CreateEffect)
EXPECT_EQ(C4VInt(3), RunScript("local A = { Construction=func() { this.Magicnumber = 3; } }; func Main() { return CreateEffect(A, 1).Magicnumber; }"));
}
+TEST_F(AulPredefFunctionTest, ParseInt)
+{
+ auto ParseInt = [this](const std::string &value) { return RunExpr("ParseInt(\"" + value + "\")"); };
+ EXPECT_EQ(C4VInt(0), ParseInt("0"));
+ EXPECT_EQ(C4VInt(0), ParseInt("-0"));
+ EXPECT_EQ(C4VInt(0), ParseInt("+0"));
+ EXPECT_EQ(C4VINT_MIN, ParseInt("-2147483648"));
+ EXPECT_EQ(C4VINT_MAX, ParseInt("2147483647"));
+
+ EXPECT_EQ(C4VNull, ParseInt(""));
+ EXPECT_EQ(C4VNull, ParseInt("-"));
+ EXPECT_EQ(C4VNull, ParseInt("+"));
+ EXPECT_EQ(C4VNull, ParseInt("--23"));
+ EXPECT_EQ(C4VNull, ParseInt("-+1234"));
+ EXPECT_EQ(C4VNull, ParseInt("a"));
+ EXPECT_EQ(C4VNull, ParseInt("0a"));
+ EXPECT_EQ(C4VNull, ParseInt("2147483647a"));
+}
+
TEST_F(AulPredefFunctionTest, Trivial)
{
EXPECT_EQ(C4VInt(100), RunExpr("Sin(900,100,10)"));