Ejemplo n.º 1
0
		private static int Main(string[] args)
		{
			CommandLineParser clp = new CommandLineParser();
			clp.AddKnownOption("a", "assembly-info");
			clp.AddKnownOption("", "test-b36min");
			clp.AddKnownOption("b", "test-bmin");
			clp.AddKnownOption("f", "format", true);
			clp.AddKnownOption("h", "help");
			clp.AddKnownOption("i", "ignore-missing");
			clp.AddKnownOption("m", "multi-project");
			clp.AddKnownOption("r", "revision");
			clp.AddKnownOption("s", "restore");
			clp.AddKnownOption("v", "version");
			clp.AddKnownOption("x", "test-xmin");
			clp.AddKnownOption("B", "de-bmin");
			clp.AddKnownOption("", "de-b36min");
			clp.AddKnownOption("D", "de-dmin");
			clp.AddKnownOption("I", "only-infver");
			clp.AddKnownOption("M", "stop-if-modified");
			clp.AddKnownOption("X", "de-xmin");
			clp.AddKnownOption("", "debug");

			debugOutput = clp.IsOptionSet("debug");

			if (clp.IsOptionSet("h") || clp.IsOptionSet("v"))
			{
				HandleHelp(clp.IsOptionSet("h"));
				return 0;
			}
			if (clp.IsOptionSet("X"))
			{
				int baseYear;
				if (!int.TryParse(clp.GetArgument(0), out baseYear))
				{
					Console.Error.WriteLine("Invalid argument: Base year expected");
					return 1;
				}
				string xmin = clp.GetArgument(1).Trim().ToLowerInvariant();
				DateTime time = DehexMinutes(baseYear, xmin);
				if (time == DateTime.MinValue)
				{
					Console.Error.WriteLine("Invalid xmin value.");
					return 0;
				}
				Console.WriteLine(time.ToString("yyyy-MM-dd HH:mm") + " UTC");
				Console.WriteLine(time.ToLocalTime().ToString("yyyy-MM-dd HH:mm K"));
				return 0;
			}
			if (clp.IsOptionSet("B"))
			{
				int baseYear;
				if (!int.TryParse(clp.GetArgument(0), out baseYear))
				{
					Console.Error.WriteLine("Invalid argument: Base year expected");
					return 1;
				}
				string bmin = clp.GetArgument(1).Trim().ToLowerInvariant();
				DateTime time = Debase28Minutes(baseYear, bmin);
				if (time == DateTime.MinValue)
				{
					Console.Error.WriteLine("Invalid bmin value.");
					return 0;
				}
				Console.WriteLine(time.ToString("yyyy-MM-dd HH:mm") + " UTC");
				Console.WriteLine(time.ToLocalTime().ToString("yyyy-MM-dd HH:mm K"));
				return 0;
			}
			if (clp.IsOptionSet("de-b36min"))
			{
				int baseYear;
				if (!int.TryParse(clp.GetArgument(0), out baseYear))
				{
					Console.Error.WriteLine("Invalid argument: Base year expected");
					return 1;
				}
				string bmin = clp.GetArgument(1).Trim().ToLowerInvariant();
				DateTime time = Debase36Minutes(baseYear, bmin);
				if (time == DateTime.MinValue)
				{
					Console.Error.WriteLine("Invalid b36min value.");
					return 0;
				}
				Console.WriteLine(time.ToString("yyyy-MM-dd HH:mm") + " UTC");
				Console.WriteLine(time.ToLocalTime().ToString("yyyy-MM-dd HH:mm K"));
				return 0;
			}
			if (clp.IsOptionSet("D"))
			{
				int baseYear;
				if (!int.TryParse(clp.GetArgument(0), out baseYear))
				{
					Console.Error.WriteLine("Invalid argument: Base year expected");
					return 1;
				}
				string dmin = clp.GetArgument(1).Trim();
				DateTime time = DedecMinutes(baseYear, dmin);
				if (time == DateTime.MinValue)
				{
					Console.Error.WriteLine("Invalid dmin value.");
					return 0;
				}
				Console.WriteLine(time.ToString("yyyy-MM-dd HH:mm") + " UTC");
				Console.WriteLine(time.ToLocalTime().ToString("yyyy-MM-dd HH:mm K"));
				return 0;
			}
			if (clp.IsOptionSet("x"))
			{
				int baseYear;
				if (!int.TryParse(clp.GetArgument(0), out baseYear))
				{
					Console.Error.WriteLine("Invalid argument: Base year expected");
					return 1;
				}
				revTime = DateTime.UtcNow;
				long ticks1min = TimeSpan.FromMinutes(1).Ticks;
				revTime = new DateTime(revTime.Ticks / ticks1min * ticks1min, DateTimeKind.Utc);
				for (int i = 0; i < 10; i++)
				{
					Console.WriteLine(revTime.ToLocalTime().ToString("yyyy-MM-dd HH:mm K") + " = " + HexMinutes(baseYear, 1));
					revTime = revTime.AddMinutes(1);
				}
				return 0;
			}
			if (clp.IsOptionSet("b"))
			{
				int baseYear;
				if (!int.TryParse(clp.GetArgument(0), out baseYear))
				{
					Console.Error.WriteLine("Invalid argument: Base year expected");
					return 1;
				}
				revTime = DateTime.UtcNow;
				long ticks20min = TimeSpan.FromMinutes(20).Ticks;
				revTime = new DateTime(revTime.Ticks / ticks20min * ticks20min, DateTimeKind.Utc);
				for (int i = 0; i < 10; i++)
				{
					Console.WriteLine(revTime.ToLocalTime().ToString("yyyy-MM-dd HH:mm K") + " = " + Base28Minutes(baseYear, 1));
					revTime = revTime.AddMinutes(20);
				}
				return 0;
			}
			if (clp.IsOptionSet("test-b36min"))
			{
				int baseYear;
				if (!int.TryParse(clp.GetArgument(0), out baseYear))
				{
					Console.Error.WriteLine("Invalid argument: Base year expected");
					return 1;
				}
				revTime = DateTime.UtcNow;
				long ticks10min = TimeSpan.FromMinutes(10).Ticks;
				revTime = new DateTime(revTime.Ticks / ticks10min * ticks10min, DateTimeKind.Utc);
				for (int i = 0; i < 10; i++)
				{
					Console.WriteLine(revTime.ToLocalTime().ToString("yyyy-MM-dd HH:mm K") + " = " + Base36Minutes(baseYear, 1));
					revTime = revTime.AddMinutes(10);
				}
				return 0;
			}

			buildTime = DateTimeOffset.Now;

			bool patchAssemblyInfoFile = clp.IsOptionSet("a");
			bool restoreAssemblyInfoFile = clp.IsOptionSet("s");
			multiProjectMode = clp.IsOptionSet("m");
			bool showRevision = clp.IsOptionSet("r");
			bool stopIfModified = clp.IsOptionSet("M");
			bool ignoreMissing = clp.IsOptionSet("i");
			onlyInformationalVersion = clp.IsOptionSet("I");
			string path = clp.GetArgument(0);
			string customFormat = "{!}{commit}";
			if (clp.IsOptionSet("f"))
				customFormat = clp.GetOptionValue("f");

			if (!patchAssemblyInfoFile && !restoreAssemblyInfoFile && !showRevision)
				showRevision = true;   // Default action
			if (string.IsNullOrEmpty(path))
				path = ".";
			if (debugOutput)
				Console.Error.WriteLine("Working on path " + path);

			bool hasProcessed = false;

			List<string> projectDirs = new List<string>();
			if (multiProjectMode)
			{
				// Treat the single directory argument as the solution file name
				if (!path.ToLowerInvariant().EndsWith(".sln"))
				{
					Console.Error.WriteLine("Error: Specified file name is invalid. Only *.sln files accepted in\nmulti-project mode.");
					return 1;
				}
				if (!File.Exists(path))
				{
					Console.Error.WriteLine("Error: Specified solution file does not exist.");
					return 1;
				}

				// Scan the solution file for projects and add them to the list
				string solutionDir = Path.GetDirectoryName(path);
				using (StreamReader sr = new StreamReader(path))
				{
					while (!sr.EndOfStream)
					{
						string line = sr.ReadLine();
						Match m = Regex.Match(line, @"^Project\(.+\) = "".+"", ""(.+\.(?:csproj|vbproj))""");
						if (m.Success)
						{
							string projectPath = Path.Combine(solutionDir, m.Groups[1].Value);
							string projectDir = Path.GetDirectoryName(projectPath);
							if (debugOutput)
								Console.Error.WriteLine("Add project in " + projectDir);
							projectDirs.Add(projectDir);
						}
					}
				}

				if (projectDirs.Count == 0)
				{
					Console.Error.WriteLine("Error: Specified solution file contains no projects.");
					return 1;
				}

				// From now on, work with the solution directory as default path to get the revision of
				path = solutionDir;
			}

			if (patchAssemblyInfoFile)
			{
				if (!hasProcessed)
				{
					ProcessDirectory(path, ignoreMissing, true);
					if (revision == 0)
					{
						if (ignoreMissing)
						{
							revTime = DateTimeOffset.Now;
						}
						else
						{
							Console.Error.WriteLine("Error: Not a Subversion working directory.");
							return 1;
						}
					}
					hasProcessed = true;
				}

				if (stopIfModified && isModified)
				{
					Console.Error.WriteLine("Error: Subversion working directory contains uncommited changes, stop requested by option.");
					return 1;
				}

				if (multiProjectMode)
				{
					bool success = true;
					foreach (string projectDir in projectDirs)
					{
						success &= PatchAssemblyInfoFile(projectDir);
					}
					if (!success)
					{
						return 1;
					}
				}
				else
				{
					if (!PatchAssemblyInfoFile(path))
					{
						return 1;
					}
				}
			}
			if (restoreAssemblyInfoFile)
			{
				if (multiProjectMode)
				{
					bool success = true;
					foreach (string projectDir in projectDirs)
					{
						success &= RestoreAssemblyInfoFile(projectDir);
					}
					if (!success)
					{
						return 1;
					}
				}
				else
				{
					if (!RestoreAssemblyInfoFile(path))
					{
						return 1;
					}
				}
			}
			if (showRevision)
			{
				if (!hasProcessed)
				{
					ProcessDirectory(path, ignoreMissing, true);
					if (revision == 0)
					{
						if (ignoreMissing)
						{
							revTime = DateTimeOffset.Now;
						}
						else
						{
							Console.Error.WriteLine("Error: Not a Subversion working directory.");
							return 1;
						}
					}
					hasProcessed = true;
				}

				Console.WriteLine(ResolveFormat(customFormat));
			}

			return 0;
		}
Ejemplo n.º 2
0
		static int Main(string[] args)
		{
			//define command line args
			CommandLineParser clp = new CommandLineParser();
			clp.AddKnownOption("f", "format", true);
			clp.AddKnownOption("h", "help");
			clp.AddKnownOption("i", "ignore-missing");
			clp.AddKnownOption("M", "stop-if-modified");
			clp.AddKnownOption("r", "revision");
			clp.AddKnownOption("v", "version");
			clp.AddKnownOption("D", "debug");

			//initialize vars from args
			debugOutput = clp.IsOptionSet("D");
			bool showRevision = clp.IsOptionSet("r");
			bool ignoreMissing = clp.IsOptionSet("i");
			bool stopIfModified = clp.IsOptionSet("M");
			string inputFile = clp.GetArgument(0);
			string outputFile = clp.GetArgument(1);
			string customFormat = "{!}{commit}";
			if( clp.IsOptionSet("f") )
				customFormat = clp.GetOptionValue("f");

			//show help/version
			if( clp.IsOptionSet("h") || clp.IsOptionSet("v") )
			{
				HandleHelp(clp.IsOptionSet("h"));
				return 0;
			}

			//default action
			if( String.IsNullOrWhiteSpace(inputFile) && String.IsNullOrWhiteSpace(outputFile) && !showRevision )
				showRevision = true;

			if( String.IsNullOrWhiteSpace(inputFile) )
				inputFile = Environment.CurrentDirectory + @"\.";

			if( debugOutput )
				Console.Error.WriteLine("Working on path " + Path.GetDirectoryName(inputFile) );

			//process Git info and populate revision and revTime
			ProcessDirectory(Path.GetDirectoryName(inputFile), ignoreMissing);

			//show git revision
			if( showRevision )
			{
				if( revision == null )
				{
					if( ignoreMissing )
					{
						revision = "0000000000000000000000000000000000000000";
						revTime = DateTimeOffset.Now;
					}
					else
					{
						Console.Error.WriteLine("Error: Not a Git working directory.");
						return 1;
					}
				}

				Console.WriteLine( ResolveFormat(customFormat) );
				return 0;
			}

			///////////////////////////////////////////////////////////////////////////////////////////////////////////
			// Main processing
			///////////////////////////////////////////////////////////////////////////////////////////////////////////
			if( revision == null )
			{
				if( ignoreMissing )
				{
					revision = "0000000000000000000000000000000000000000";
					revTime = DateTimeOffset.Now;
				}
				else
				{
					Console.Error.WriteLine("Error: Not a Git working directory.");
					return 1;
				}
			}

			if( stopIfModified && isModified )
			{
				Console.Error.WriteLine("Error: Git working directory contains uncommited changes, stop requested by option.");
				return 1;
			}

			if( !File.Exists(inputFile) )
			{
				Console.Error.WriteLine("Error: Input file doesn't exist.");
				return 1;
			}

			if( debugOutput )
				Console.Error.WriteLine("Patching " + Path.GetFileName(inputFile) + "...");

			string attrStart = null, attrEnd = null;
			switch( Path.GetExtension(outputFile).ToLower() )
			{
				case ".cs":
					attrStart = "[";
					attrEnd = "]";
					break;

				case ".vb":
					attrStart = "<";
					attrEnd = ">";
					break;

				default:
					Console.Error.WriteLine("Logic error: invalid AssemblyInfo file extension: " + Path.GetExtension(outputFile).ToLower());
					return 1;
			}

			using( StreamReader sr = new StreamReader(inputFile, Encoding.Default, true) )
			{
				sr.Peek();
				using( StreamWriter sw = new StreamWriter(outputFile, false, sr.CurrentEncoding) )
				{
					while( !sr.EndOfStream )
					{
						string line = sr.ReadLine();

						Match m;
						m = Regex.Match(
							line,
							@"^(\s*\" + attrStart + @"\s*assembly\s*:\s*AssemblyInformationalVersion\s*\(\s*"")(.*)(""\s*\)\s*\" + attrEnd + @".*)$",
							RegexOptions.IgnoreCase);
						if( m.Success )
						{
							string value = m.Groups[2].Value;
							value = ResolveFormat(value);
							line = m.Groups[1].Value + value + m.Groups[3].Value;
							if( debugOutput )
								Console.Error.WriteLine("Found AssemblyInformationalVersion attribute");
						}

						sw.WriteLine(line);
					}
				}

				if( debugOutput )
					Console.Error.WriteLine("Patched " + Path.GetFileName(inputFile));
			}

			return 0;
		}
Ejemplo n.º 3
0
        private static int Main(string[] args)
        {
            CommandLineParser clp = new CommandLineParser();
            clp.AddKnownOption("h", "help");
            clp.AddKnownOption("v", "verbose");
            clp.AddKnownOption("o", "out", true);
            clp.AddKnownOption("c", "class", true);
            clp.AddKnownOption("d", "debug");

            bool debug = clp.IsOptionSet("d");
            bool verbose = clp.IsOptionSet("v");
            string inFile = clp.GetArgument(0);
            string outFile = clp.GetOptionValue("o");
            string clsName = clp.GetOptionValue("c");
            if (string.IsNullOrEmpty(clsName))
                clsName = "DllExport";

            if (clp.IsOptionSet("h") || string.IsNullOrEmpty(inFile))
            {
                string productVersion = "";

                object[] customAttributes = Assembly.GetEntryAssembly().GetCustomAttributes(typeof(AssemblyFileVersionAttribute), false);
                if (customAttributes != null && customAttributes.Length > 0)
                {
                    productVersion = ((AssemblyFileVersionAttribute) customAttributes[0]).Version;
                }

                Console.WriteLine("NetDllExport");
                Console.WriteLine("Exports static methods in a managed DLL as library functions that can be");
                Console.WriteLine("called from an unmanaged Windows application.");
                Console.WriteLine("Version " + productVersion);
                Console.WriteLine("Copyright by Yves Goergen, http://unclassified.software/apps/netdllexport");
                Console.WriteLine("");
                Console.WriteLine("No input file specified.");
                Console.WriteLine("");
                Console.WriteLine("Usage:");
                Console.WriteLine("  NetDllExport [options] InputFile");
                Console.WriteLine("");
                Console.WriteLine("Options:");
                Console.WriteLine("  -c, --class ClassName");
                Console.WriteLine("      Specifies the managed class whose static methods are exported.");
                Console.WriteLine("      Default: DllExport");
                Console.WriteLine("  -d, --debug");
                Console.WriteLine("      Rebuilds the assembly in debug mode and creates a PDB file.");
                Console.WriteLine("      Does not delete intermediate .il and .res files.");
                Console.WriteLine("  -h, --help");
                Console.WriteLine("      Show this help page.");
                Console.WriteLine("  -o, --out OutputFile");
                Console.WriteLine("      Specifies the output DLL file name.");
                Console.WriteLine("      Default: InputFile");
                Console.WriteLine("  -v, --verbose");
                Console.WriteLine("      Be verbose.");
                return 1;
            }

            if (string.IsNullOrEmpty(outFile))
            {
                outFile = inFile;
            }

            if (!Path.IsPathRooted(inFile))
            {
                inFile = Path.Combine(Environment.CurrentDirectory, inFile);
            }
            if (!Path.IsPathRooted(outFile))
            {
                outFile = Path.Combine(Environment.CurrentDirectory, outFile);
            }

            string ilFile = Path.Combine(
                Path.GetDirectoryName(inFile),
                Path.GetFileNameWithoutExtension(inFile) + ".il");
            string resFile = Path.Combine(
                Path.GetDirectoryName(inFile),
                Path.GetFileNameWithoutExtension(inFile) + ".res");

            if (verbose)
            {
                Console.WriteLine("Input file: " + inFile);
                Console.WriteLine("Output file: " + outFile);
                Console.WriteLine("IL file: " + ilFile);
                Console.WriteLine("RES file: " + resFile);
                Console.WriteLine("Exported class: " + clsName);
            }

            // Disassemble to IL and read that file
            if (verbose)
            {
                Console.WriteLine("Disassembling input file...");
            }
            ILHelper.DisassembleFile(inFile, ilFile);
            string ilCode = File.ReadAllText(ilFile);

            // TODO: Add more return values (void|string|...)
            string methodRegex =
                @"^\s*.method\s+public\s+(hidebysig\s+)?static\s+(void|bool|int32|int64|uint32|uint64|string|class\s+[\w.]+)\s+(marshal\s*\([^)]+\)\s+)?" +
                @"(\w+)\s*\([^)]*\)" +
                @"(\s+cil)?(\s+managed)?" +
                @"\s*\{";

            // Make class name case-insensitive
            string clsNameRegex = "";
            foreach (char c in clsName)
            {
                clsNameRegex += "[" + char.ToLower(c) + char.ToUpper(c) + "]";
            }

            // Extract the class to export
            int funcCount = 0;
            Match m = Regex.Match(ilCode, @"^(.*\n)(\.class\s([^ \t\r\n.]+\s+)*\w+\." + clsNameRegex + @"\s+.*?\{.*?)(\n.class\s.*)?$", RegexOptions.Singleline);
            if (m.Success)
            {
                string clsCode = m.Groups[2].Value;

                //string testMethodRegex =
                //    @"^\s*.method\s+public\s+(hidebysig\s+)?static\s+(void|int32|string|class\s+[\w.]+)\s+(marshal\s*\([^)]+\)\s+)?" +
                //    @"(EventMsg)\s*\([^)]*\)" +
                //    @"(\s+cil)?(\s+managed)?" +
                //    @"\s*\{";
                //if (Regex.IsMatch(clsCode, testMethodRegex, RegexOptions.Multiline | RegexOptions.Singleline))
                //{
                //}

                // Modify each .method in clsCode
                clsCode = Regex.Replace(
                    clsCode,
                    methodRegex,
                    delegate(Match m2)
                    {
                        funcCount++;
                        if (verbose)
                        {
                            Console.WriteLine("Exported function " + funcCount + ": " + m2.Groups[4].Value);
                        }
                        return m2.Value + Environment.NewLine +
                            ".vtentry " + funcCount + " : 1" + Environment.NewLine +
                            ".export [" + funcCount + "] as " + m2.Groups[4].Value + Environment.NewLine;
                    },
                    RegexOptions.Multiline | RegexOptions.Singleline);

                ilCode = m.Groups[1].Value + clsCode + m.Groups[4].Value;
            }
            else
            {
                Console.Error.WriteLine("Exported class \"" + clsName + "\" not found.");
                return 1;
            }

            if (funcCount == 0)
            {
                Console.Error.WriteLine("No functions to export.");
                return 1;
            }

            // Insert vtable code
            string vtCode = "";
            for (int i = 1; i <= funcCount; i++)
            {
                vtCode += ".vtfixup [1] int32 fromunmanaged at VT_" + i.ToString("00") + Environment.NewLine +
                    ".data VT_" + i.ToString("00") + " = int32(0)" + Environment.NewLine;
            }

            // Change to x86 - should better be done by the source assembly already.
            // corflags bit meanings: http://stackoverflow.com/a/13767541/143684
            ilCode = Regex.Replace(
                ilCode,
                "^.corflags 0x0000000[123] .*$",
                ".corflags 0x00000002" + Environment.NewLine + vtCode,
                RegexOptions.Multiline);

            // Write new IL file and assemble it
            if (verbose)
            {
                Console.WriteLine("Assembling IL file...");
            }
            File.WriteAllText(ilFile, ilCode);
            ILHelper.AssembleFile(ilFile, outFile, debug);

            // Clean up
            if (!debug)
            {
                File.Delete(ilFile);
                File.Delete(resFile);
            }

            // Finished
            if (verbose)
            {
                Console.WriteLine("DLL functions successfully exported.");
            }
            return 0;
        }