public ExpandResult ExpandStringFull(string line, out string result, int recdepth) { int noexpansion = 0; int pos = 0; do { pos = line.IndexOf('%', pos); if (pos >= 0) { pos++; // move on, if it fails, next pos= will be past this point int startexpression = pos; int apos = pos; while (apos < line.Length && char.IsLetter(line[apos])) { apos++; } if (apos < line.Length && line[apos] == '(') // now must be bracket.. if not, its not in form, ignore %, or its past the EOL { string funcname = line.Substring(pos, apos - pos); apos++; // past the ( ConditionFunctionHandlers cfh = GetCFH(this, vars, persistentdata, recdepth); while (true) { while (apos < line.Length && char.IsWhiteSpace(line[apos])) // remove white space { apos++; } if (apos < line.Length && line[apos] == ')' && cfh.paras.Count == 0) // ) here must be on first only, and is valid { apos++; // skip by break; } int start = apos; if (apos < line.Length && (line[apos] == '"' || line[apos] == '\'')) { char quote = line[apos++]; string res = ""; while (apos < line.Length && line[apos] != quote) { if (line[apos] == '\\' && (apos + 1) < line.Length && line[apos + 1] == quote) // if \" { apos++; } res += line[apos++]; } if (apos >= line.Length) { result = "Terminal quote missing at '" + line.Substring(startexpression, apos - startexpression) + "'"; return(ExpandResult.Failed); } apos++; // remove quote string resexp; // expand out any strings.. recursion ExpandResult sexpresult = ExpandStringFull(res, out resexp, recdepth + 1); if (sexpresult == ExpandResult.Failed) { result = resexp; return(sexpresult); } cfh.paras.Add(new ConditionFunctionHandlers.Parameter() { value = resexp, isstring = true }); } else { if (funcname.Length > 0) // functions can have () embedded .. in literals { int blevel = 0; while (apos < line.Length && (blevel > 0 || "), ".IndexOf(line[apos]) == -1)) { if (line[apos] == '(') { blevel++; } else if (line[apos] == ')') { blevel--; } apos++; } } else { while (apos < line.Length && "), ".IndexOf(line[apos]) == -1) { apos++; } } if (apos == start) { result = "Missing variable name at '" + line.Substring(startexpression, apos - startexpression) + "'"; return(ExpandResult.Failed); } string res = line.Substring(start, apos - start); if (funcname.Length > 0 && line.Contains("%")) // function paramters can be expanded if they have a % { string resexp; // expand out any strings.. recursion ExpandResult sexpresult = ExpandStringFull(res, out resexp, recdepth + 1); if (sexpresult == ExpandResult.Failed) { result = resexp; return(sexpresult); } res = resexp; } else { // not an expansion.. see if it needs mangling res = vars.Qualify(res); } cfh.paras.Add(new ConditionFunctionHandlers.Parameter() { value = res, isstring = false }); } while (apos < line.Length && char.IsWhiteSpace(line[apos])) { apos++; } char c = (apos < line.Length) ? line[apos++] : '-'; if (c == ')') // must be ) { break; } if (c != ',') // must be , { result = "Incorrectly formed parameter list at '" + line.Substring(startexpression, apos - startexpression) + "'"; return(ExpandResult.Failed); } } string expand = null; if (funcname.Length > 0) // functions! { if (!cfh.RunFunction(funcname, out expand)) { result = "Function " + funcname + ": " + expand; return(ExpandResult.Failed); } } else if (cfh.paras.Count != 1) // only 1 { result = "Variable name missing between () at '" + line.Substring(startexpression, apos - startexpression) + "'"; return(ExpandResult.Failed); } else { // variables if (cfh.paras[0].isstring) { result = "Must be a variable not a string for non function expansions"; return(ExpandResult.Failed); } else if (vars.Exists(cfh.paras[0].value)) { expand = vars[cfh.paras[0].value]; } else { result = "Variable '" + cfh.paras[0].value + "' does not exist"; return(ExpandResult.Failed); } } noexpansion++; line = line.Substring(0, pos - 1) + expand + line.Substring(apos); pos = (pos - 1) + expand.Length; // System.Diagnostics.Debug.WriteLine("<" + funcname + "> var <" + varnames[0] + ">" + " line <" + line + "> left <" + line.Substring(pos) + ">"); } } } while (pos != -1); result = line; return((noexpansion > 0) ? ExpandResult.Expansion : ExpandResult.NoExpansion); }
public bool?CheckConditions(List <Condition> fel, ConditionVariables values, out string errlist, List <Condition> passed = null, ConditionFunctions cf = null) { errlist = null; bool?outerres = null; foreach (Condition fe in fel) // find all values needed { bool?innerres = null; foreach (ConditionEntry f in fe.fields) { bool matched = false; if (f.matchtype == ConditionEntry.MatchType.AlwaysTrue || f.matchtype == ConditionEntry.MatchType.AlwaysFalse) { if (f.itemname.Length == 0 || f.itemname.Equals("Condition", StringComparison.InvariantCultureIgnoreCase)) // empty (legacy) or { if (f.matchtype == ConditionEntry.MatchType.AlwaysTrue) { matched = true; // matched, else if false, leave as false. } } else { errlist += "AlwaysFalse/True does not have left side text of Condition"; innerres = false; break; } } else { string leftside = null; ConditionFunctions.ExpandResult er = ConditionFunctions.ExpandResult.NoExpansion; if (cf != null) // if we have a string expander, try the left side { er = cf.ExpandString(f.itemname, out leftside); if (er == ConditionFunctions.ExpandResult.Failed) // stop on error { errlist += leftside; // add on errors.. innerres = false; // stop loop, false break; } } if (f.matchtype == ConditionEntry.MatchType.IsPresent) // these use f.itemname without any expansion { if (leftside == null || er == ConditionFunctions.ExpandResult.NoExpansion) // no expansion, must be a variable name { leftside = values.Qualify(f.itemname); // its a straight variable name, allow any special formatting } if (values.Exists(leftside) && values[leftside] != null) { matched = true; } } else if (f.matchtype == ConditionEntry.MatchType.IsNotPresent) { if (leftside == null || er == ConditionFunctions.ExpandResult.NoExpansion) // no expansion, must be a variable name { leftside = values.Qualify(f.itemname); // its a straight variable name, allow any special formatting } if (!values.Exists(leftside) || values[leftside] == null) { matched = true; } } else { if (er == ConditionFunctions.ExpandResult.NoExpansion) // no expansion, must be a variable name { leftside = values.Qualify(f.itemname); leftside = values.Exists(leftside) ? values[leftside] : null; // then lookup if (leftside == null) { errlist += "Item " + leftside + " is not available" + Environment.NewLine; innerres = false; break; // stop the loop, its a false } } string rightside; if (cf != null) // if we have a string expander, pass it thru { er = cf.ExpandString(f.matchstring, out rightside); if (er == ConditionFunctions.ExpandResult.Failed) // if error, abort { errlist += rightside; // add on errors.. innerres = false; // stop loop, false break; } } else { rightside = f.matchstring; } if (f.matchtype == ConditionEntry.MatchType.DateBefore || f.matchtype == ConditionEntry.MatchType.DateAfter) { DateTime tmevalue, tmecontent; if (!DateTime.TryParse(leftside, System.Globalization.CultureInfo.CreateSpecificCulture("en-US"), System.Globalization.DateTimeStyles.None, out tmevalue)) { errlist += "Date time not in correct format on left side" + Environment.NewLine; innerres = false; break; } else if (!DateTime.TryParse(rightside, System.Globalization.CultureInfo.CreateSpecificCulture("en-US"), System.Globalization.DateTimeStyles.None, out tmecontent)) { errlist += "Date time not in correct format on right side" + Environment.NewLine; innerres = false; break; } else { if (f.matchtype == ConditionEntry.MatchType.DateBefore) { matched = tmevalue.CompareTo(tmecontent) < 0; } else { matched = tmevalue.CompareTo(tmecontent) >= 0; } } } else if (f.matchtype == ConditionEntry.MatchType.Equals) { matched = leftside.Equals(rightside, StringComparison.InvariantCultureIgnoreCase); } else if (f.matchtype == ConditionEntry.MatchType.EqualsCaseSensitive) { matched = leftside.Equals(rightside); } else if (f.matchtype == ConditionEntry.MatchType.NotEqual) { matched = !leftside.Equals(rightside, StringComparison.InvariantCultureIgnoreCase); } else if (f.matchtype == ConditionEntry.MatchType.NotEqualCaseSensitive) { matched = !leftside.Equals(rightside); } else if (f.matchtype == ConditionEntry.MatchType.Contains) { matched = leftside.IndexOf(rightside, StringComparison.InvariantCultureIgnoreCase) >= 0; } else if (f.matchtype == ConditionEntry.MatchType.ContainsCaseSensitive) { matched = leftside.Contains(rightside); } else if (f.matchtype == ConditionEntry.MatchType.DoesNotContain) { matched = leftside.IndexOf(rightside, StringComparison.InvariantCultureIgnoreCase) < 0; } else if (f.matchtype == ConditionEntry.MatchType.DoesNotContainCaseSensitive) { matched = !leftside.Contains(rightside); } else if (f.matchtype == ConditionEntry.MatchType.IsOneOf) { StringParser p = new StringParser(rightside); List <string> ret = p.NextQuotedWordList(); if (ret == null) { errlist += "IsOneOf value list is not in a optionally quoted comma separated form" + Environment.NewLine; innerres = false; break; // stop the loop, its a false } else { matched = ret.Contains(leftside, StringComparer.InvariantCultureIgnoreCase); } } else if (f.matchtype == ConditionEntry.MatchType.MatchSemicolon) { string[] list = rightside.Split(';').Select(x => x.Trim()).ToArray(); // split and trim matched = list.Contains(leftside.Trim(), StringComparer.InvariantCultureIgnoreCase); // compare, trimmed, case insensitive } else if (f.matchtype == ConditionEntry.MatchType.MatchCommaList) { StringCombinations sc = new StringCombinations(','); sc.ParseString(rightside); // parse, give all combinations matched = sc.Permutations.Contains(leftside.Trim(), StringComparer.InvariantCultureIgnoreCase); // compare, trimmed, case insensitive } else if (f.matchtype == ConditionEntry.MatchType.MatchSemicolonList) { StringCombinations sc = new StringCombinations(';'); sc.ParseString(rightside); // parse, give all combinations matched = sc.Permutations.Contains(leftside.Trim(), StringComparer.InvariantCultureIgnoreCase); // compare, trimmed, case insensitive } else if (f.matchtype == ConditionEntry.MatchType.AnyOfAny) { StringParser l = new StringParser(leftside); List <string> ll = l.NextQuotedWordList(); StringParser r = new StringParser(rightside); List <string> rl = r.NextQuotedWordList(); if (ll == null || rl == null) { errlist += "AnyOfAny value list is not in a optionally quoted comma separated form on both sides" + Environment.NewLine; innerres = false; break; // stop the loop, its a false } else { foreach (string s in ll) // for all left strings { if (rl.Contains(s, StringComparer.InvariantCultureIgnoreCase)) // if right has it.. { matched = true; // matched and break break; } } } } else if (f.matchtype == ConditionEntry.MatchType.IsEmpty) { matched = leftside.Length == 0; } else if (f.matchtype == ConditionEntry.MatchType.IsNotEmpty) { matched = leftside.Length > 0; } else if (f.matchtype == ConditionEntry.MatchType.IsTrue || f.matchtype == ConditionEntry.MatchType.IsFalse) { int inum = 0; if (leftside.InvariantParse(out inum)) { matched = (f.matchtype == ConditionEntry.MatchType.IsTrue) ? (inum != 0) : (inum == 0); } else { errlist += "True/False value is not an integer on left side" + Environment.NewLine; innerres = false; break; } } else { double fnum = 0, num = 0; if (!leftside.InvariantParse(out num)) { errlist += "Number not in correct format on left side" + Environment.NewLine; innerres = false; break; } else if (!rightside.InvariantParse(out fnum)) { errlist += "Number not in correct format on right side" + Environment.NewLine; innerres = false; break; } else { if (f.matchtype == ConditionEntry.MatchType.NumericEquals) { matched = Math.Abs(num - fnum) < 0.0000000001; // allow for rounding } else if (f.matchtype == ConditionEntry.MatchType.NumericNotEquals) { matched = Math.Abs(num - fnum) >= 0.0000000001; } else if (f.matchtype == ConditionEntry.MatchType.NumericGreater) { matched = num > fnum; } else if (f.matchtype == ConditionEntry.MatchType.NumericGreaterEqual) { matched = num >= fnum; } else if (f.matchtype == ConditionEntry.MatchType.NumericLessThan) { matched = num < fnum; } else if (f.matchtype == ConditionEntry.MatchType.NumericLessThanEqual) { matched = num <= fnum; } else { System.Diagnostics.Debug.Assert(false); } } } } } // System.Diagnostics.Debug.WriteLine(fe.eventname + ":Compare " + f.matchtype + " '" + f.contentmatch + "' with '" + vr.value + "' res " + matched + " IC " + fe.innercondition); if (fe.innercondition == ConditionEntry.LogicalCondition.And) // Short cut, if AND, all must pass, and it did not { if (!matched) { innerres = false; break; } } else if (fe.innercondition == ConditionEntry.LogicalCondition.Nand) // Short cut, if NAND, and not matched { if (!matched) { innerres = true; // positive non match - NAND produces a true break; } } else if (fe.innercondition == ConditionEntry.LogicalCondition.Or) // Short cut, if OR, and matched { if (matched) { innerres = true; break; } } else { // short cut, if NOR, and matched, its false if (matched) { innerres = false; break; } } } if (!innerres.HasValue) // All tests executed, without a short cut, we set it to a definitive state { if (fe.innercondition == ConditionEntry.LogicalCondition.And) // none did not match, producing a false, so therefore AND is true { innerres = true; } else if (fe.innercondition == ConditionEntry.LogicalCondition.Or) // none did match, producing a true, so therefore OR must be false { innerres = false; } else if (fe.innercondition == ConditionEntry.LogicalCondition.Nor) // none did match, producing a false, so therefore NOR must be true { innerres = true; } else // NAND none did match, producing a true, so therefore NAND must be false { innerres = false; } } if (innerres.Value && passed != null) // if want a list of passes, do it { passed.Add(fe); } if (!outerres.HasValue) // if first time, its just the value { outerres = innerres.Value; } else if (fe.outercondition == ConditionEntry.LogicalCondition.Or) { outerres |= innerres.Value; } else if (fe.outercondition == ConditionEntry.LogicalCondition.And) { outerres &= innerres.Value; } else if (fe.outercondition == ConditionEntry.LogicalCondition.Nor) { outerres = !(outerres | innerres.Value); } else if (fe.outercondition == ConditionEntry.LogicalCondition.Nand) { outerres = !(outerres & innerres.Value); } } return(outerres); }