/// <summary> /// Handler of general containers. /// Moving upward from deepest container. /// /// $(name) or $(name:project) or $([MSBuild]::MakeRelative($(path1), ...):project) .. /// https://msdn.microsoft.com/en-us/library/vstudio/dd633440%28v=vs.120%29.aspx /// </summary> /// <param name="data"></param> /// <param name="sh"></param> /// <param name="limit">Limitation to containers. Aborts if reached</param> /// <exception cref="LimitException"></exception> /// <returns></returns> protected string containerIn(string data, StringHandler sh, uint limit) { Regex con = new Regex(RPattern.ContainerIn, RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled); int maxRep = 1; // rule of depth, e.g.: $(p1 = $(Platform))$(p2 = $(p1))$(p2) //TODO: it's slowest but fully compatible with classic rules with minimal programming.. so, improve performance uint step = 0; do { if(step++ > limit) { throw new LimitException("Restriction of supported containers '{0}' reached. Aborted.", limit); } data = con.Replace(data, delegate(Match m) { string raw = m.Groups[1].Value; Log.Trace("containerIn: raw - '{0}'", raw); return evaluate(prepare(sh.recovery(raw))); }, maxRep); // protect before new checking data = sh.protectEscContainer(sh.protectSingleQuotes(data)); } while(con.IsMatch(data)); return data; }
/// <summary> /// Entry point to evaluating MSBuild data. /// </summary> /// <param name="data">mixed data</param> /// <returns>All evaluated values for data</returns> public virtual string parse(string data) { if(String.IsNullOrEmpty(data)) { return String.Empty; // convert to not null value } if(String.IsNullOrWhiteSpace(data)) { return data; // save all white-space characters } StringHandler sh = new StringHandler(); lock(_lock) { return sh.recovery( containerIn( sh.protectEscContainer( sh.protectSingleQuotes(data) ), sh, CONTAINERS_LIMIT ) ); } }