static int Main()

in SmvInterceptorWrapper/Program.cs [19:456]


        static int Main(string[] args)
        {
            // Get the output dir from the Environment variable set by SMV

            string smvOutDir = Environment.GetEnvironmentVariable("SMV_OUTPUT_DIR");
            if (string.IsNullOrWhiteSpace(smvOutDir))
            {
                smvOutDir = Environment.CurrentDirectory;
            }
            string smvclLogPath = Path.Combine(smvOutDir, "smvcl.log");
            string smvRecordLogPath = Path.Combine(smvOutDir, "record.log");
            StringBuilder smvclLogContents = new StringBuilder();
            List<string> iargs = args.Where(x => !x.Contains("/iwrap:") && !x.Contains(".rsp") && !x.Contains("/plugin:")).ToList();

            if (!String.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("SMV_DEBUG_MODE")))
            {
                debugMode = true;
            }

            #region cl.exe            
            if (args.Contains("/iwrap:cl.exe"))
            {
                if (args.Contains("/E")) return 0;
                smvclLogContents.Append("iwrap: cl.exe called with args " + string.Join(",", args));
                string[] unsupportedClExtensions = {".inf", ".mof", ".src", ".pdb", ".def", "~", ".rc" };

                // check for inf and other unsupported files and skip
                List<string> unsupportedArgs = args.Where(a => unsupportedClExtensions.Any(b => a.ToLowerInvariant().EndsWith(b))).ToList();
                args = args.Where(a => !unsupportedClExtensions.Any(b => a.ToLowerInvariant().EndsWith(b))).ToArray();
                iargs = iargs.Where(a => !unsupportedClExtensions.Any(b => a.ToLowerInvariant().EndsWith(b))).ToList();
                
                // try to make progress no matter what. 
                //if (unsupportedArgs.Count() > 0)
                //{
                //    smvclLogContents.Append("iwrap: cl.exe unsupported extension:" + string.Join(",", unsupportedArgs));
                //    File.WriteAllText(smvclLogPath, smvclLogContents.ToString());
                //    return 1;
                //}

                // get the name of the plugin
                string plugin = args.Where(x => x.Contains("/plugin:")).ToList().First().Replace("/plugin:", String.Empty);

                // call slamcl
                string rspContents = string.Empty;
                string rspFileContent = string.Empty;
                string rspFile = args.ToList().Find(x => x.Contains(".rsp") || x.StartsWith("@", StringComparison.OrdinalIgnoreCase));
                if (!string.IsNullOrEmpty(rspFile))
                {
                    rspFile = rspFile.Replace("@", "");
                    rspContents = System.IO.File.ReadAllText(rspFile);
                    rspContents = rspContents.Replace("/analyze-", "");
                }                              

                // remove unsupported flags. currently we are not removing anything.
                Regex[] unsupportedFlags = {new Regex(@"\s+\/Yu[^\s]+\s{1}", System.Text.RegularExpressions.RegexOptions.IgnoreCase),
                                               //new Regex(@"\s+\/Fp[^\s]+\s{1}", System.Text.RegularExpressions.RegexOptions.IgnoreCase),
                                               //new Regex(@"\s+\/Yc[^\s]+\s{1}", System.Text.RegularExpressions.RegexOptions.IgnoreCase),
                                               //new Regex(@"\s+(\/d1nodatetime)", System.Text.RegularExpressions.RegexOptions.IgnoreCase),
                                               //new Regex(@"\s+(\/d1trimfile:[^\s]*)", System.Text.RegularExpressions.RegexOptions.IgnoreCase),
                                               //new Regex(@"\s+(\/d2AllowCompatibleILVersions)", System.Text.RegularExpressions.RegexOptions.IgnoreCase),
                                               //new Regex(@"\s+(\/d2Zi\+)", System.Text.RegularExpressions.RegexOptions.IgnoreCase),
                                               //new Regex(@"\s+(\/d1nosafedelete)", System.Text.RegularExpressions.RegexOptions.IgnoreCase),
                                               //new Regex(@"\s+(\-nosafedelete)", System.Text.RegularExpressions.RegexOptions.IgnoreCase),
                                               //new Regex(@"-DDBG=\d\s{1}|\/DDBG=\d\s{1}", System.Text.RegularExpressions.RegexOptions.IgnoreCase),
                                               //new Regex(@"-DDEBUG\s{1}|\/DDEBUG\s{1}", System.Text.RegularExpressions.RegexOptions.IgnoreCase),            
                                               //new Regex("\\s+\\/Fp\"[^\"]+\"{1}", System.Text.RegularExpressions.RegexOptions.None)
                                           };

                foreach (Regex rgx in unsupportedFlags)
                {
                    rspContents = rgx.Replace(rspContents, " ");
                }
               
                rspContents = rspContents.Replace("\r", " ");
                rspContents = rspContents.Replace("\n", " ");
                rspContents = rspContents.Replace("/W4", string.Empty);
                rspContents = rspContents.Replace("/W3", string.Empty);
                rspContents = rspContents.Replace("/W2", string.Empty);
                rspContents = rspContents.Replace("/W1", string.Empty);
                rspContents = rspContents.Replace("/WX", string.Empty);

                rspFileContent = rspContents;

                string rspContentsDebug = Environment.ExpandEnvironmentVariables(" /nologo /w /Y- /D_PREFAST_ /errorReport:none" + " " + string.Join(" ", iargs)) + " " + rspContents + " /P /Fi.\\sdv\\";
                rspContentsDebug = rspContentsDebug.Replace("/analyze:only", " ");
                rspContentsDebug = rspContentsDebug.Replace("/analyze:autolog-", " ");

                rspContents = Environment.ExpandEnvironmentVariables(" /nologo /w /Y- /analyze:only /analyze:plugin \"" + plugin +
                              "\" /errorReport:none" + " " + string.Join(" ", iargs)) + " " + rspContents;



                // Persist the RSP file 
                // Remove file names (*.c) from the content
                Regex fileNameRegex1 = new Regex(@"([\s]+[\w\p{P}]+\.c\b(\\"")?)", RegexOptions.IgnoreCase|RegexOptions.Multiline);
                Regex fileNameRegex2 = new Regex(@"([\s]+[\w\p{P}]+\.(cpp|cxx)\b(\\"")?)", RegexOptions.IgnoreCase|RegexOptions.Multiline);

                List<string> fileNames = new List<string>();
                int count = 0;

                foreach (Match m in fileNameRegex1.Matches(rspContents))
                {
                    count++;
                    smvclLogContents.Append("match1: " + m.Value + Environment.NewLine);
                }
                foreach (Match m in fileNameRegex2.Matches(rspContents))
                {
                    count++;
                    smvclLogContents.Append("match2: " + m.Value + Environment.NewLine);
                }
                rspFileContent = fileNameRegex1.Replace(rspFileContent, String.Empty);
                rspFileContent = fileNameRegex2.Replace(rspFileContent, String.Empty);

                File.WriteAllText(Path.Combine(smvOutDir, "sdv_cl.rsp"), rspFileContent);

                // if no files are left (only .src etc. was given) then just return. nothing to do
                if(count == 0) { return 0; }

                // call CL.exe

                ProcessStartInfo psi = new ProcessStartInfo(System.IO.Path.GetFullPath(Environment.ExpandEnvironmentVariables("%SMV_ANALYSIS_COMPILER%")), Environment.ExpandEnvironmentVariables(rspContents));
                psi.RedirectStandardError = true;
                psi.RedirectStandardOutput = true;
                psi.UseShellExecute = false;
                
                if (!psi.EnvironmentVariables.ContainsKey("esp.cfgpersist.persistfile"))
                {
                    psi.EnvironmentVariables.Add("esp.cfgpersist.persistfile", smvOutDir + "\\$SOURCEFILE.rawcfgf");
                    psi.EnvironmentVariables.Add("Esp.CfgPersist.ExpandLocalStaticInitializer", "1");
                    psi.EnvironmentVariables.Add("ESP.BplFilesDir", smvOutDir);
                }
                
                WriteInterceptorLog("LAUNCH: iwrap: " + psi.FileName + " " + psi.Arguments);
                WriteInterceptorLog("PATH: " + Environment.ExpandEnvironmentVariables("%PATH%"));

                StringBuilder sb = new StringBuilder();
                sb.Append("esp.cfgpersist.persistfile=");
                sb.Append((smvOutDir + "\\$SOURCEFILE.rawcfgf"));
                sb.Append("  ");
                sb.Append("Esp.CfgPersist.ExpandLocalStaticInitializer=1");
                sb.Append("  ");
                sb.Append("ESP.BplFilesDir=");
                sb.Append(smvOutDir);
                
                WriteInterceptorLog("Process-specific environment variables: " + sb.ToString());

                Process p = System.Diagnostics.Process.Start(psi);

                smvclLogContents.Append(p.StandardOutput.ReadToEnd());
                smvclLogContents.Append(p.StandardError.ReadToEnd());
                File.WriteAllText(smvclLogPath, smvclLogContents.ToString());
                p.WaitForExit();
                
                WriteInterceptorLog("EXIT: CL.exe.  Exit code: " + p.ExitCode);

                if (debugMode)
                {
                    // Run with /P to get preprocessed output for debugging
                    psi = new ProcessStartInfo(System.IO.Path.GetFullPath(Environment.ExpandEnvironmentVariables("%SMV_ANALYSIS_COMPILER%")), Environment.ExpandEnvironmentVariables(rspContentsDebug));
                    psi.RedirectStandardError = true;
                    psi.RedirectStandardOutput = true;
                    psi.UseShellExecute = false;
                    p = System.Diagnostics.Process.Start(psi);

                    // Get debug timeout from environment variable set in XML or command line
                    int debugTimeout = 0;

                    try
                    {
                        debugTimeout = int.Parse(Environment.GetEnvironmentVariable("SMV_DEBUG_TIMEOUT"));
                    }
                    catch (Exception)
                    {
                        // If there was any trouble, just set it to 5 minutes
                        debugTimeout = DEFAULT_DEBUG_TIMEOUT;
                    }

                    // Allow 5 minutes for this, then continue; don't hang indefinitely on debug
                    p.WaitForExit(debugTimeout);

                    // Call ESPSMVPRINT_AUX
                    foreach (FileInfo f in new DirectoryInfo(smvOutDir).GetFiles())
                    {
                        if (f.Name.EndsWith(".rawcfgf"))
                        {
                            string espSmvPrintPath = Path.Combine(Environment.ExpandEnvironmentVariables("%SDV%"), "bin", "engine", "espsmvprintaux.exe");

                            // If we are not in an SDV environment, this is pointless; break
                            if (!File.Exists(espSmvPrintPath)) break;

                            psi = new ProcessStartInfo(espSmvPrintPath, '"' + f.FullName + '"');
                            psi.RedirectStandardOutput = true;
                            psi.RedirectStandardError = true;
                            psi.UseShellExecute = false;

                            string cfgOutputPath = f.FullName.Replace(".rawcfgf", ".rawcfgf.txt");
                            string cfgErrorPath = f.FullName.Replace(".rawcfgf", ".rawcfgf.err");

                            p = System.Diagnostics.Process.Start(psi);
                            File.WriteAllText(cfgOutputPath, p.StandardOutput.ReadToEnd());
                            File.WriteAllText(cfgErrorPath, p.StandardError.ReadToEnd());

                            // Allow 5 minutes for each, then continue; don't hang indefinitely on debug
                            p.WaitForExit(debugTimeout);
                        }
                    }
                }

                return p.ExitCode;
            }
            #endregion
            #region link.exe
            else if (args.Contains("/iwrap:link.exe"))
            {
                //Console.WriteLine("iwrap: link.exe called with args " + string.Join(" ", iargs));
                //Console.WriteLine("iwrap: link.exe --> " + Environment.ExpandEnvironmentVariables("slamcl_writer.exe"));

                // get rsp contents
                string rspContents = string.Empty;
                string rspFile = args.ToList().Find(x => x.Contains(".rsp") || x.StartsWith("@", StringComparison.OrdinalIgnoreCase));
                if (!string.IsNullOrEmpty(rspFile))
                {
                    rspFile = rspFile.Replace("@", "");
                    rspContents = System.IO.File.ReadAllText(rspFile);
                    rspContents = rspContents.Replace("\r", " ");
                    rspContents = rspContents.Replace("\n", " ");
                }
                
                // get out dir
                string outDir = smvOutDir;
                //Console.WriteLine("iwrap: link.exe --> outdir is " + outDir);

                // get rid of previous LI files, log files etc. 
                Directory.GetFiles(outDir, "*.li").ToList().ForEach(f => File.Delete(f));
                if(File.Exists(Path.Combine(outDir, "smvlink.log")))
                {
                    File.Delete(Path.Combine(outDir, "smvlink.log"));
                }

                //TODO: if link is called multiple times to create multiple binaries
                // we will still only create 1 LI file for all the LI files that are available
                // This happens in cases where a directory is used to store all the .obj 
                // files and then link is called multiple times with a subset of the .obj
                // files to produce various binaries. 
                // The solution is to look at the link command in its entirety, 
                // and extract the obj files that are being used in it. 
                // we should then produce the LI for the corresponding obj.li files.
                // the obj files are specified in the link rsp or command line and can 
                // be extracted using a regex, similar to how we extract lib files and locations.

                string[] rawcfgfFiles = System.IO.Directory.GetFiles(outDir, "*.rawcfgf");

                string[] files = rawcfgfFiles.Select(x => System.IO.Path.GetFileNameWithoutExtension(System.IO.Path.GetFileName(x))).ToArray();

                files = files.Where(x => !x.Contains(".obj")).ToArray();

                ProcessStartInfo psi;
                Process p;

                WriteInterceptorLog("PATH: " + Environment.ExpandEnvironmentVariables("%PATH%"));

                foreach (string file in rawcfgfFiles)
                {
                    psi = new ProcessStartInfo(Environment.ExpandEnvironmentVariables("slamcl_writer.exe"), "--smv " + '"' + file + '"' + " " + ('"' + file + ".obj\"") );
                    psi.RedirectStandardError = true;
                    psi.RedirectStandardOutput = true;
                    psi.UseShellExecute = false;
                    psi.WorkingDirectory = outDir;

                    WriteInterceptorLog("LAUNCH: link: " + psi.FileName + " " + psi.Arguments);

                    //Console.WriteLine("iwrap: link.exe --> " + psi.FileName + " " + psi.Arguments);

                    try
                    {
                        p = System.Diagnostics.Process.Start(psi);
                        File.AppendAllText(outDir + "\\smvlink1.log", p.StandardOutput.ReadToEnd());
                        File.AppendAllText(outDir + "\\smvlink1.log", p.StandardError.ReadToEnd());

                        p.WaitForExit();

                        WriteInterceptorLog("EXIT: slamcl_writer.exe.  Exit code: " + p.ExitCode);
                        if (p.ExitCode != 0) return p.ExitCode;
                    }
                    catch (System.ComponentModel.Win32Exception w)
                    {
                        // In event of a Win32 exception, dump useful info
                        WriteInterceptorLog(w.Message);
                        WriteInterceptorLog(w.ErrorCode.ToString());
                        WriteInterceptorLog(w.NativeErrorCode.ToString());
                        WriteInterceptorLog(w.StackTrace);
                        WriteInterceptorLog(w.Source);
                        Exception e = w.GetBaseException();
                        WriteInterceptorLog(e.Message);
                        return w.ErrorCode;
                    }
                }

                files = files.Select(x => x + ".rawcfgf.obj").ToArray();
                
                // if only 1 li file then just copy that to slam.li
                if (files.Length == 1)
                {
                    WriteInterceptorLog("DEBUG: only one .rawcfgf.obj file found.");
                    File.Copy(outDir + "\\" + files.ElementAt(0) + ".li", outDir + "\\slam.li", true);
                }
                else
                {
                    // many LI files, link all LIs together
                    psi = new ProcessStartInfo(Environment.ExpandEnvironmentVariables("slamlink.exe "));
                    psi.RedirectStandardError = true;
                    psi.RedirectStandardOutput = true;
                    psi.UseShellExecute = false;
                    psi.WorkingDirectory = outDir;
                    psi.Arguments = " --lib " + string.Join(" ", files);

                    WriteInterceptorLog("DEBUG: about to run slamlink on " + files.Length + " .rawcfgf.obj files");
                    WriteInterceptorLog("LAUNCH: iwrap: " + psi.FileName + " " + psi.Arguments);

                    //Console.WriteLine("iwrap: link.exe --> " + psi.FileName + " " + psi.Arguments);
                    Process slamLinkProcess = System.Diagnostics.Process.Start(psi);
                    File.AppendAllText(Path.Combine(outDir, "smvlink2.log"), slamLinkProcess.StandardOutput.ReadToEnd());
                    File.AppendAllText(Path.Combine(outDir, "smvlink2.log"), slamLinkProcess.StandardError.ReadToEnd());

                    // copy the slam.lib.li produced by slamlink to slam.li
                    if (File.Exists(outDir + "\\slam.lib.li"))
                    {
                        File.Copy(outDir + "\\slam.lib.li", outDir + "\\slam.li", true);
                    }
                    slamLinkProcess.WaitForExit();

                    WriteInterceptorLog("EXIT: slamlink.exe.  Exit code: " + slamLinkProcess.ExitCode);
                    if (slamLinkProcess.ExitCode != 0) return slamLinkProcess.ExitCode;
                }

                // remove rawcfgf files and their corresponding LI files
                //rawcfgfFiles.ToList().ForEach(f => { File.Delete(f); File.Delete(f + ".obj.li"); });

                // create copy for linking with libs
                if (File.Exists(outDir + "\\slam.li"))
                {
                    File.Copy(outDir + "\\slam.li", outDir + "\\slamout.obj.li", true);
                }
                else
                {
                    //Console.WriteLine("iwrap: link.exe --> No slam.li found in " + outDir);
                }

                // get any libs that need to be added and the corresponding rawcfgs
                List<string> libs = GetLibs(string.Join(" ", iargs) + " " + rspContents + " ");

                libs.RemoveAll(l => string.IsNullOrEmpty(l));

                WriteInterceptorLog("DEBUG: About to attempt processing " + libs.Count + " libraries." );

                foreach (string l in libs)
                {
                    //Console.WriteLine("lib is " + l);
                    if (l.Equals(outDir)) continue;
                    try
                    {
                        WriteInterceptorLog("DEBUG: Processing lib " + l);
                        string[] liFilesInLibDir = Directory.GetFiles(l, "slam.li");

                        foreach (string liFile in liFilesInLibDir)
                        {
                            Process slamLinkProcess;

                            //Console.WriteLine("iwrap: Linking " + liFile + " " + outDir + "\\slam.obj.li");

                            File.Copy(liFile, outDir + "\\slamlib.obj.li", true);
                            File.Copy(outDir + "\\slamout.obj.li", outDir + "\\slamorig.obj.li");

                            psi = new ProcessStartInfo(Environment.ExpandEnvironmentVariables("slamlink.exe"));
                            psi.RedirectStandardError = true;
                            psi.RedirectStandardOutput = true;
                            psi.UseShellExecute = false;
                            psi.WorkingDirectory = outDir;
                            psi.Arguments = " --lib slamorig.obj slamlib.obj /out:slamout.obj";

                            WriteInterceptorLog("DEBUG: about to run slamlink on " + liFile);
                            WriteInterceptorLog("LAUNCH: iwrap: " + psi.FileName + " " + psi.Arguments);

                            slamLinkProcess = System.Diagnostics.Process.Start(psi);

                            File.AppendAllText(outDir + "\\smvlink3.log", slamLinkProcess.StandardOutput.ReadToEnd());
                            File.AppendAllText(outDir + "\\smvlink3.log", slamLinkProcess.StandardError.ReadToEnd());

                            slamLinkProcess.WaitForExit();

                            WriteInterceptorLog("EXIT: slamlink.exe.  Exit code: " + slamLinkProcess.ExitCode);

                            if (slamLinkProcess.ExitCode != 0) return slamLinkProcess.ExitCode;
                        }
                    }
                    catch(Exception e)
                    {
                        WriteInterceptorLog(e.ToString());
                    }

                    if (File.Exists(outDir + "\\slamout.obj.li"))
                    {
                        File.Copy(outDir + "\\slamout.obj.li", outDir + "\\slam.li", true);
                    }
                }

                WriteInterceptorLog("DEBUG: Succesfully exiting link.exe section.");

                return 0;
            }
            #endregion
            #region lib.exe
            else if (args.Contains("/iwrap:lib.exe"))
            {
                //Console.WriteLine("iwrap: Currently unimplemented. Consider using link functionality.");
                WriteInterceptorLog("DEBUG: Entering lib.exe region.  This should never happen!");
                return 1;
            }
            #endregion
            #region record
            if (args.Any(a => a.Contains("/iwrap:record")))
            {
                string currentProcessName = args.First(a => a.Contains("/iwrap:record")).Split('-')[1];
                string[] calls = { };
                if (File.Exists(smvRecordLogPath))
                {
                    calls = File.ReadAllLines(smvRecordLogPath);
                }
                string content = currentProcessName + " " + string.Join(",", args) + Environment.NewLine;
                if (!calls.Contains(content))
                {
                    File.AppendAllText(smvRecordLogPath, content);
                }
                return 0;
            }
            #endregion
            return 0;
        }