From 43fc1b2959ea60bf55dbb9c5f7dd66bc79d36337 Mon Sep 17 00:00:00 2001 From: Jerome St-Louis Date: Tue, 11 Jul 2023 19:56:52 -0400 Subject: [PATCH] compiler/ecsss: Initial take at LIKE comparison function - Co-authored With Patrick --- compiler/eccss/eccss.ec | 84 ++++++++++++++++++++++++++++++++++- compiler/eccss/expressions.ec | 3 +- 2 files changed, 85 insertions(+), 2 deletions(-) diff --git a/compiler/eccss/eccss.ec b/compiler/eccss/eccss.ec index 896fb12341..2bb9dd0b37 100644 --- a/compiler/eccss/eccss.ec +++ b/compiler/eccss/eccss.ec @@ -11,7 +11,8 @@ enum ECCSSFunctionIndex : int strlwr, subst, format, - pow + pow, + like }; static int strncpymax(String output, const String input, int count, int max) @@ -235,6 +236,71 @@ static String formatValues(const String format, int numArgs, const FieldValue * return CopyString(output); } +#define MAX_WILDCARD 300 + +/*static */bool like(const String string, const String pattern) +{ + bool result = true; + int wildcardPosition[MAX_WILDCARD], stringPosition[MAX_WILDCARD], currentWildcard = 0; + int i, j; + char chp; + bool lastWasWildcard = false; + + for(i = 0, j = 0; (chp = pattern[i]); i++, j++) + { + char chs = string[j]; + + lastWasWildcard = false; + if(chs && chp == '_') + { + // Match any single char (but it might be multiple bytes for unicode chars) + int nb; + UTF8GetChar(string + j, &nb); + j += nb - 1; + } + else + { + if(chp == '%') + { + if(pattern[i+1] == '%') + i++; // Escaped (%%) actual % to match + else + { + lastWasWildcard = true; + // Wildcard + if(chs && currentWildcard < MAX_WILDCARD) + { + wildcardPosition[currentWildcard] = i; + stringPosition[currentWildcard] = j; + currentWildcard++; + } + j--; // Start trying at j + continue; + } + } + if(chs != chp) + { + // Mismatch, abort or continue trying to match wildcard + if(currentWildcard) + { + currentWildcard--; + i = wildcardPosition[currentWildcard]-1; + j = stringPosition[currentWildcard]; + } + else + { + if(!lastWasWildcard || pattern[i + 1]) + result = false; + break; + } + } + } + } + // Mismatch if we have any character left in the string and are not still in a wildcard + if(!lastWasWildcard && string[j]) result = false; + return result; +} + // For extending ECCSS with custom identifiers and styling properties public struct ECCSSEvaluator { @@ -307,6 +373,13 @@ public struct ECCSSEvaluator expType = class(double); break; } + case like: + { + if(args.list.count >= 1) args[0].destType = class(String); + if(args.list.count >= 2) args[1].destType = class(String); + expType = class(bool); + break; + } } } return expType; @@ -380,6 +453,15 @@ public struct ECCSSEvaluator } break; } + case like: + { + if(numArgs >= 2 && args[0].type.type == text && args[1].type.type == text) + { + value.type = { type = integer/*, format = boolean*/ }; + value.i = like(args[0].s, args[1].s); + } + break; + } } } return expType; diff --git a/compiler/eccss/expressions.ec b/compiler/eccss/expressions.ec index 74986da086..acd8fe97df 100644 --- a/compiler/eccss/expressions.ec +++ b/compiler/eccss/expressions.ec @@ -1261,7 +1261,8 @@ public: } if(nonResolved) flags.resolved = false; } - if(evaluator != null && computeType != preprocessing && flags.resolved) + // We need to evaluate the function if resolved is true (should not yet be set if e.g., featureID / geometry is needed) + if(evaluator != null && flags.resolved) expType = evaluator.evaluatorClass.computeFunction(evaluator, value, expValue, args, numArgs, &flags); } return flags;