diff --git a/src/kOS.Safe/Compilation/Opcode.cs b/src/kOS.Safe/Compilation/Opcode.cs index 345a331b3..332c8b3f2 100644 --- a/src/kOS.Safe/Compilation/Opcode.cs +++ b/src/kOS.Safe/Compilation/Opcode.cs @@ -1420,14 +1420,14 @@ public static int StaticExecute(ICpu cpu, bool direct, object destination, bool if (functionPointer is string || functionPointer is StringValue) { string functionName = functionPointer.ToString(); - if (functionName.EndsWith("()")) + if (StringUtil.EndsWith(functionName, "()")) functionName = functionName.Substring(0, functionName.Length - 2); if (!(cpu.BuiltInExists(functionName))) { // It is not a built-in, so instead get its value as a user function pointer variable, despite // the fact that it's being called AS IF it was direct. - if (!functionName.EndsWith("*")) functionName = functionName + "*"; - if (!functionName.StartsWith("$")) functionName = "$" + functionName; + if (!StringUtil.EndsWith(functionName, "*")) functionName = functionName + "*"; + if (!StringUtil.StartsWith(functionName, "$")) functionName = "$" + functionName; functionPointer = cpu.GetValue(functionName); } } @@ -1482,7 +1482,7 @@ public static int StaticExecute(ICpu cpu, bool direct, object destination, bool // might want to change that. var name = functionPointer as string; string functionName = name; - if (functionName.EndsWith("()")) + if (StringUtil.EndsWith(functionName, "()")) functionName = functionName.Substring(0, functionName.Length - 2); cpu.CallBuiltinFunction(functionName); diff --git a/src/kOS.Safe/Execution/CPU.cs b/src/kOS.Safe/Execution/CPU.cs index a15af5e20..980d91791 100644 --- a/src/kOS.Safe/Execution/CPU.cs +++ b/src/kOS.Safe/Execution/CPU.cs @@ -404,7 +404,7 @@ private void SaveAndClearPointers() // IP jump location for subprograms. // IP jump location for functions. savedPointers = new VariableScope(0, null); - var pointers = new List>(globalVariables.Locals.Where(entry => entry.Key.Contains('*'))); + var pointers = new List>(globalVariables.Locals.Where(entry => StringUtil.EndsWith(entry.Key, "*"))); foreach (var entry in pointers) { @@ -720,7 +720,7 @@ private Variable GetVariable(string identifier, bool barewordOkay = false, bool // In the case where we were looking for a function pointer but didn't find one, and would // have failed with exception, then it's still acceptable to find a hit that isn't a function // pointer (has no trailing asterisk '*') but only if it's a delegate of some sort: - if (identifier[identifier.Length - 1] == '*') + if (StringUtil.EndsWith(identifier, "*")) { string trimmedTail = identifier.TrimEnd('*'); Variable retryVal = GetVariable(trimmedTail, barewordOkay, failOkay); @@ -744,7 +744,7 @@ private Variable GetVariable(string identifier, bool barewordOkay = false, bool /// true if it's okay to overwrite an existing variable public void AddVariable(Variable variable, string identifier, bool local, bool overwrite = false) { - if (identifier[0] != '$') + if (!StringUtil.StartsWith(identifier, "$")) { identifier = "$" + identifier; } diff --git a/src/kOS.Safe/Utilities/StringUtil.cs b/src/kOS.Safe/Utilities/StringUtil.cs new file mode 100644 index 000000000..9e8fd6b5b --- /dev/null +++ b/src/kOS.Safe/Utilities/StringUtil.cs @@ -0,0 +1,51 @@ +using System; +namespace kOS.Safe +{ + /// + /// String utility functions that avoid the culture-aware overhead of the builtin string functions. + /// + public static class StringUtil + { + public static bool EndsWith(string str, string suffix) + { + int strLen = str.Length; + int suffixLen = suffix.Length; + + if (strLen < suffixLen) + { + return false; + } + + for (int i = 0; i < suffixLen; i++) + { + if (str[strLen - i - 1] != suffix[suffixLen - i - 1]) + { + return false; + } + } + + return true; + } + + public static bool StartsWith(string str, string prefix) + { + int strLen = str.Length; + int prefixLen = prefix.Length; + + if (strLen < prefixLen) + { + return false; + } + + for (int i = 0; i < prefixLen; i++) + { + if (str[i] != prefix[i]) + { + return false; + } + } + + return true; + } + } +} diff --git a/src/kOS.Safe/kOS.Safe.csproj b/src/kOS.Safe/kOS.Safe.csproj index b11536eb2..2bab71216 100644 --- a/src/kOS.Safe/kOS.Safe.csproj +++ b/src/kOS.Safe/kOS.Safe.csproj @@ -283,6 +283,7 @@ + @@ -315,4 +316,4 @@ --> - \ No newline at end of file +