<commit_before>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace vc2clangdb
{
	class Program
	{
		static string handleOption(string clOption)
		{
			if (clOption.StartsWith("D"))
				return "-" + clOption;
			else if (clOption.StartsWith("I"))
				return "-" + clOption;
			return "";
		}

		static string fixPath(string path)
		{
			return path.Replace('\\', '/');
		}

		static string escapeString(string str)
		{
			return fixPath(str);
		}

		static Dictionary<string, string> parseArgs(string[] args)
		{
			var dict = new Dictionary<string, string>();

			try
			{
				for (int i = 0; i < args.Length; ++i)
				{
					if (args[i].StartsWith("-"))
					{
						dict.Add(args[i].Substring(1), args[i + 1]);
						++i;
					}
					else
						dict.Add("", args[i]);
				}
			}
			catch(Exception)
			{
				Console.WriteLine("Error parsing arguments...");
			}
			return dict;
		}

		static void Main(string[] args)
		{
			var argDict = parseArgs(args);
			if (!argDict.ContainsKey("") || !argDict.ContainsKey("i"))
			{
				Console.WriteLine("Usage: vc2clangdb <path-to-vcxproj> -i <intermediate-path> [options]\n");
				Console.WriteLine("Options:");
				Console.WriteLine("-o <output-json>   - Target path for the output json. If not specified, compile_commands.json will be created in the same location as the .vcxproj");
				Console.WriteLine("-c <configuration> - Configuration name, e.g. 'Debug'. Currently only needed if intermediates do not exist. If not specified, msbuild will use the default");
				Console.WriteLine("-p <platform>      - Platform name, e.g. 'Win32'. Currently only needed if intermediates do not exist. If not specified, msbuild will use the default");
				return;
			}
			if(!File.Exists(args[0]))
			{
				Console.WriteLine(args[0] + " does not exist!");
				return;
			}

			string proj = argDict[""];
			string projDir = fixPath(Path.GetDirectoryName(proj));
			string tlogPath = Path.Combine(argDict["i"], Path.GetFileNameWithoutExtension(proj) + ".tlog\\cl.command.1.tlog");
			string target = argDict.ContainsKey("o") ? argDict["o"] : (fixPath(Path.Combine(projDir, "compile_commands.json")));
			string intermediate = argDict["i"].TrimEnd(new char[] { '/', '\\' }) + "\\"; // make sure theres exactly one backslash

			if (!File.Exists(tlogPath) || File.GetLastWriteTimeUtc(tlogPath) < File.GetLastWriteTimeUtc(proj))
			{
				var vs = VisualStudio.Find(12); // TODO: extract version from vcxproj
				vs.Build(proj, argDict.ContainsKey("p") ? argDict["p"] : null, argDict.ContainsKey("c") ? argDict["c"] : null, intermediate);
				if(!File.Exists(tlogPath))
					vs.Rebuild(proj, argDict.ContainsKey("p") ? argDict["p"] : null, argDict.ContainsKey("c") ? argDict["c"] : null, intermediate);
			}

			string[] lines = File.ReadAllLines(tlogPath);
			int index = 0;
			string compilationDatabase = "[";
			for(int i = 0; i < lines.Length / 2; ++i, ++index)
			{
				string clangCommandline = "clang++ ";

				string filename = fixPath(lines[index++].Substring(1));
				string commandline = lines[index];

				// this is not robust. if we encounter a / within a string, we might run into problems
				string[] options = commandline.Split(new char[] { '/' });
				foreach (string option in options)
					clangCommandline += escapeString(handleOption(option));

				clangCommandline += " -fms-compatibility";
				clangCommandline += " " + filename;
				<commit_msg>- added global include option - added more microsoft compatiblity flags (TODO: make those optional)<commit_after>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace vc2clangdb
{
	class Program
	{
		static string handleOption(string clOption)
		{
			if (clOption.StartsWith("D"))
				return "-" + clOption;
			else if (clOption.StartsWith("I"))
				return "-" + clOption;
			return "";
		}

		static string fixPath(string path)
		{
			return path.Replace('\\', '/');
		}

		static string escapeString(string str)
		{
			return fixPath(str);
		}

		static Dictionary<string, string> parseArgs(string[] args)
		{
			var dict = new Dictionary<string, string>();

			try
			{
				for (int i = 0; i < args.Length; ++i)
				{
					if (args[i].StartsWith("-"))
					{
						dict.Add(args[i].Substring(1), args[i + 1]);
						++i;
					}
					else
						dict.Add("", args[i]);
				}
			}
			catch(Exception)
			{
				Console.WriteLine("Error parsing arguments...");
			}
			return dict;
		}

		static void Main(string[] args)
		{
			var argDict = parseArgs(args);
			if (!argDict.ContainsKey("") || !argDict.ContainsKey("i"))
			{
				Console.WriteLine("Usage: vc2clangdb <path-to-vcxproj> -i <intermediate-path> [options]\n");
				Console.WriteLine("Options:");
				Console.WriteLine("-o <output-json>     - Target path for the output json. If not specified, compile_commands.json will be created in the same location as the .vcxproj");
				Console.WriteLine("-c <configuration>   - Configuration name, e.g. 'Debug'. Currently only needed if intermediates do not exist. If not specified, msbuild will use the default");
				Console.WriteLine("-p <platform>        - Platform name, e.g. 'Win32'. Currently only needed if intermediates do not exist. If not specified, msbuild will use the default");
				Console.WriteLine("-I <global-includes> - A list of global includes, separated by ? (question mark)");
				return;
			}
			if(!File.Exists(args[0]))
			{
				Console.WriteLine(args[0] + " does not exist!");
				return;
			}

			string proj = argDict[""];
			string projDir = fixPath(Path.GetDirectoryName(proj));
			string tlogPath = Path.Combine(argDict["i"], Path.GetFileNameWithoutExtension(proj) + ".tlog\\cl.command.1.tlog");
			string target = argDict.ContainsKey("o") ? argDict["o"] : (fixPath(Path.Combine(projDir, "compile_commands.json")));
			string intermediate = argDict["i"].TrimEnd(new char[] { '/', '\\' }) + "\\"; // make sure theres exactly one backslash
			string[] globalIncludes = argDict.ContainsKey("I") ? argDict["I"].Split(new char[]{'?'}) : new string[0];

			if (!File.Exists(tlogPath) || File.GetLastWriteTimeUtc(tlogPath) < File.GetLastWriteTimeUtc(proj))
			{
				var vs = VisualStudio.Find(12); // TODO: extract version from vcxproj
				vs.Build(proj, argDict.ContainsKey("p") ? argDict["p"] : null, argDict.ContainsKey("c") ? argDict["c"] : null, intermediate);
				if(!File.Exists(tlogPath))
					vs.Rebuild(proj, argDict.ContainsKey("p") ? argDict["p"] : null, argDict.ContainsKey("c") ? argDict["c"] : null, intermediate);
			}

			string[] lines = File.ReadAllLines(tlogPath);
			int index = 0;
			string compilationDatabase = "[";
			for(int i = 0; i < lines.Length / 2; ++i, ++index)
			{
				string clangCommandline = "clang++ ";

				string filename = fixPath(lines[index++].Substring(1));
				string commandline = lines[index];

				// this is not robust. if we encounter a / within a string, we might run into problems
				string[] options = commandline.Split(new char[] { '/' });

				foreach (string globalInclude in globalIncludes)
					clangCommandline += "-I" + globalInclude + " ";
	
				foreach (string option in options)
					clangCommandline += escapeString(handleOption(option));

				clangCommandline += " -fms-compatibility -fdelayed-template-parsing -fms-extensions";
				clangCommandline += " " + filename;
				
{'fraction_non_alphanumeric': 0.15511640498105037, 'fraction_numerical': 0.004466702761234434, 'mean_word_length': 3.533128834355828, 'pattern_counts': {'":': 0, '<': 24, '<?xml version=': 0, '>': 18, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7000277', 'n_tokens_mistral': 2791, 'n_tokens_neox': 2325, 'n_words': 591}