diff --git a/Documents/compilerinterfaces.txt b/Documents/compilerinterfaces.txt
index 17a3c971..80a41f1e 100644
--- a/Documents/compilerinterfaces.txt
+++ b/Documents/compilerinterfaces.txt
@@ -20,12 +20,11 @@ With this interface supports the following placeholders in command-line paramete
%FO indicates the output path and filename.
-%PI indicates the path of the input file (without filename).
-
-%PO indicates the path of the output file (without filename).
-
%PT indicates the temporary directory path where the compiler is located.
+%PW indicates the path of the open wad file when compiled as internal script lump.
+If compiled as file, or the wad file is not saved, %PW is the same as %PT
+
These placeholders are case-sensitive!
-------------------------------------------------------------------------------------
diff --git a/Source/Compilers/AccCompiler.cs b/Source/Compilers/AccCompiler.cs
index b6e05b91..76455c69 100644
--- a/Source/Compilers/AccCompiler.cs
+++ b/Source/Compilers/AccCompiler.cs
@@ -26,15 +26,19 @@ using System.Diagnostics;
using System.IO;
using CodeImp.DoomBuilder.Config;
using CodeImp.DoomBuilder.IO;
+using System.Windows.Forms;
+using System.Text.RegularExpressions;
#endregion
namespace CodeImp.DoomBuilder.Compilers
{
- public sealed class AccCompiler : Compiler
+ internal sealed class AccCompiler : Compiler
{
#region ================== Constants
+ private const string ACS_ERROR_FILE = "acs.err";
+
#endregion
#region ================== Variables
@@ -65,15 +69,113 @@ namespace CodeImp.DoomBuilder.Compilers
#region ================== Methods
- // This runs the compiler with a file as input.
- public override bool CompileFile(string filename)
- {
- return true;
- }
-
- // This runs the compiler with lump data as input.
- public override bool CompileLump(Stream lumpdata)
+ // This runs the compiler
+ public override bool Run()
{
+ ProcessStartInfo processinfo;
+ Process process;
+ TimeSpan deltatime;
+ string waddir = null;
+ int line = 0;
+
+ // Find wad directory
+ if(General.Map.FilePathName.Length > 0)
+ waddir = Path.GetDirectoryName(General.Map.FilePathName);
+
+ // When no luck, use temp path
+ if(waddir == null) waddir = this.tempdir.FullName;
+
+ // Create parameters
+ string args = this.parameters;
+ args = args.Replace("%FI", inputfile);
+ args = args.Replace("%FO", outputfile);
+ args = args.Replace("%PT", this.tempdir.FullName);
+ args = args.Replace("%PW", waddir);
+
+ // Setup process info
+ processinfo = new ProcessStartInfo();
+ processinfo.Arguments = args;
+ processinfo.FileName = Path.Combine(this.tempdir.FullName, info.ProgramFile);
+ processinfo.CreateNoWindow = false;
+ processinfo.ErrorDialog = false;
+ processinfo.UseShellExecute = true;
+ processinfo.WindowStyle = ProcessWindowStyle.Hidden;
+ processinfo.WorkingDirectory = this.workingdir;
+
+ // Output info
+ General.WriteLogLine("Running compiler...");
+ General.WriteLogLine("Program: " + processinfo.FileName);
+ General.WriteLogLine("Arguments: " + processinfo.Arguments);
+
+ try
+ {
+ // Start the compiler
+ process = Process.Start(processinfo);
+ }
+ catch(Exception e)
+ {
+ // Unable to start the compiler
+ General.ShowErrorMessage("Unable to start the compiler (" + info.Name + "). " + e.GetType().Name + ": " + e.Message, MessageBoxButtons.OK);
+ return false;
+ }
+
+ // Wait for compiler to complete
+ process.WaitForExit();
+ deltatime = TimeSpan.FromTicks(process.ExitTime.Ticks - process.StartTime.Ticks);
+ General.WriteLogLine("Compiler process has finished.");
+ General.WriteLogLine("Compile time: " + deltatime.TotalSeconds.ToString("########0.00") + " seconds");
+
+ // Now find the error file
+ string errfile = Path.Combine(this.tempdir.FullName, ACS_ERROR_FILE);
+ if(File.Exists(errfile))
+ {
+ try
+ {
+ // Regex to find error lines
+ Regex errlinematcher = new Regex("\\:[0-9]+\\:\\b", RegexOptions.Compiled | RegexOptions.CultureInvariant);
+
+ // Read all lines
+ string[] errlines = File.ReadAllLines(errfile);
+ while(line < errlines.Length)
+ {
+ // Check line
+ string linestr = errlines[line];
+ Match match = errlinematcher.Match(linestr);
+ if(match.Success && (match.Index > 0))
+ {
+ CompilerError err = new CompilerError();
+
+ // The match without spaces and semicolon is the line number
+ string linenr = match.Value.Replace(":", "").Trim();
+ if(!int.TryParse(linenr, out err.linenumber))
+ err.linenumber = CompilerError.NO_LINE_NUMBER;
+
+ // Everything before the match is the filename
+ err.filename = linestr.Substring(0, match.Index);
+ if(!Path.IsPathRooted(err.filename))
+ {
+ // Add working directory to filename
+ err.filename = Path.Combine(processinfo.WorkingDirectory, err.filename);
+ }
+
+ // Everything after the match is the description
+ err.description = linestr.Substring(match.Index + match.Length).Trim();
+
+ // Report the error
+ ReportError(err);
+ }
+
+ // Next line
+ line++;
+ }
+ }
+ catch(Exception e)
+ {
+ // Error reading errors (ironic, isn't it)
+ ReportError(new CompilerError("Failed to retrieve compiler error report. " + e.GetType().Name + ": " + e.Message));
+ }
+ }
+
return true;
}
diff --git a/Source/Compilers/Compiler.cs b/Source/Compilers/Compiler.cs
index ddc07217..289e3bb1 100644
--- a/Source/Compilers/Compiler.cs
+++ b/Source/Compilers/Compiler.cs
@@ -40,6 +40,8 @@ namespace CodeImp.DoomBuilder.Compilers
protected CompilerInfo info;
protected string parameters;
protected string workingdir;
+ protected string outputfile;
+ protected string inputfile;
// Files
protected DirectoryInfo tempdir;
@@ -53,9 +55,11 @@ namespace CodeImp.DoomBuilder.Compilers
#endregion
#region ================== Properties
-
+
public string Parameters { get { return parameters; } set { parameters = value; } }
public string WorkingDirectory { get { return workingdir; } set { workingdir = value; } }
+ public string InputFile { get { return inputfile; } set { inputfile = value; } }
+ public string OutputFile { get { return outputfile; } set { outputfile = value; } }
public string Location { get { return tempdir.FullName; } }
public bool IsDisposed { get { return isdisposed; } }
public CompilerError[] Errors { get { return errors.ToArray(); } }
@@ -114,16 +118,10 @@ namespace CodeImp.DoomBuilder.Compilers
}
///
- /// This runs the compiler with a file as input.
+ /// This runs the compiler.
///
/// Returns false when failed to start.
- public virtual bool CompileFile(string filename) { return false; }
-
- ///
- /// This runs the compiler with lump data as input.
- ///
- /// Returns false when failed to start.
- public virtual bool CompileLump(Stream lumpdata) { return false; }
+ public virtual bool Run() { return false; }
///
/// Use this to report an error.
@@ -151,8 +149,14 @@ namespace CodeImp.DoomBuilder.Compilers
// Go for all assemblies
foreach(Assembly a in asms)
{
+ Type[] types;
+
// Find the class
- Type[] types = a.GetExportedTypes();
+ if(a == General.ThisAssembly)
+ types = a.GetTypes();
+ else
+ types = a.GetExportedTypes();
+
foreach(Type t in types)
{
if(t.IsSubclassOf(typeof(Compiler)) && (t.Name == info.ProgramInterface))
diff --git a/Source/Compilers/CompilerError.cs b/Source/Compilers/CompilerError.cs
index 3a47a08e..956317d9 100644
--- a/Source/Compilers/CompilerError.cs
+++ b/Source/Compilers/CompilerError.cs
@@ -30,11 +30,30 @@ namespace CodeImp.DoomBuilder.Compilers
{
public struct CompilerError
{
+ // Constants
+ public const int NO_LINE_NUMBER = -1;
+
// Members
public string description;
public string filename;
public int linenumber;
+ // Constructor
+ public CompilerError(string description)
+ {
+ this.description = description;
+ this.filename = "";
+ this.linenumber = NO_LINE_NUMBER;
+ }
+
+ // Constructor
+ public CompilerError(string description, string filename)
+ {
+ this.description = description;
+ this.filename = filename;
+ this.linenumber = NO_LINE_NUMBER;
+ }
+
// Constructor
public CompilerError(string description, string filename, int linenumber)
{
diff --git a/Source/Compilers/NodesCompiler.cs b/Source/Compilers/NodesCompiler.cs
index 4de0c486..6ab73156 100644
--- a/Source/Compilers/NodesCompiler.cs
+++ b/Source/Compilers/NodesCompiler.cs
@@ -31,7 +31,7 @@ using System.Windows.Forms;
namespace CodeImp.DoomBuilder.Compilers
{
- public sealed class NodesCompiler : Compiler
+ internal sealed class NodesCompiler : Compiler
{
#region ================== Constants
@@ -39,15 +39,10 @@ namespace CodeImp.DoomBuilder.Compilers
#region ================== Variables
- // Output file
- private string outputfile;
-
#endregion
#region ================== Properties
- public string OutputFile { get { return outputfile; } set { outputfile = value; } }
-
#endregion
#region ================== Constructor / Disposer
@@ -79,7 +74,7 @@ namespace CodeImp.DoomBuilder.Compilers
#region ================== Methods
// This runs the compiler with a file as input.
- public override bool CompileFile(string filename)
+ public override bool Run()
{
ProcessStartInfo processinfo;
Process process;
@@ -87,7 +82,7 @@ namespace CodeImp.DoomBuilder.Compilers
// Create parameters
string args = this.parameters;
- args = args.Replace("%FI", filename);
+ args = args.Replace("%FI", inputfile);
args = args.Replace("%FO", outputfile);
// Setup process info
@@ -98,7 +93,7 @@ namespace CodeImp.DoomBuilder.Compilers
processinfo.ErrorDialog = false;
processinfo.UseShellExecute = true;
processinfo.WindowStyle = ProcessWindowStyle.Hidden;
- processinfo.WorkingDirectory = this.tempdir.FullName;
+ processinfo.WorkingDirectory = this.workingdir;
// Output info
General.WriteLogLine("Running compiler...");
diff --git a/Source/Config/NodebuilderInfo.cs b/Source/Config/NodebuilderInfo.cs
index a7eb15e5..79af5b93 100644
--- a/Source/Config/NodebuilderInfo.cs
+++ b/Source/Config/NodebuilderInfo.cs
@@ -66,7 +66,7 @@ namespace CodeImp.DoomBuilder.Config
string compilername;
General.WriteLogLine("Registered nodebuilder configuration '" + name + "' from '" + filename + "'");
-
+
// Initialize
this.name = name;
this.compiler = null;
@@ -111,20 +111,9 @@ namespace CodeImp.DoomBuilder.Config
}
// This runs the nodebuilder
- public NodesCompiler CreateCompiler()
+ public Compiler CreateCompiler()
{
- Compiler c = compiler.Create();
- if(c is NodesCompiler)
- {
- NodesCompiler ns = (c as NodesCompiler);
- ns.Parameters = parameters;
- return ns;
- }
- else
- {
- // Nodebuilders must use a NodesCompiler!
- throw new ArgumentException("Cannot create compiler interface '" + compiler.ProgramInterface + "' for nodebuilder '" + name + "'. Nodebuilders must use a NodesCompiler compiler interface!");
- }
+ return compiler.Create();
}
#endregion
diff --git a/Source/Controls/ScriptDocumentTab.cs b/Source/Controls/ScriptDocumentTab.cs
index 4e10ef2c..4b4104a1 100644
--- a/Source/Controls/ScriptDocumentTab.cs
+++ b/Source/Controls/ScriptDocumentTab.cs
@@ -93,7 +93,12 @@ namespace CodeImp.DoomBuilder.Controls
#endregion
#region ================== Methods
-
+
+ // This compiles the script
+ public virtual void Compile()
+ {
+ }
+
// This saves the document (used for both explicit and implicit)
// Return true when successfully saved
public virtual bool Save()
diff --git a/Source/Controls/ScriptEditorPanel.cs b/Source/Controls/ScriptEditorPanel.cs
index 27fa74c9..d9a9fc1c 100644
--- a/Source/Controls/ScriptEditorPanel.cs
+++ b/Source/Controls/ScriptEditorPanel.cs
@@ -394,7 +394,7 @@ namespace CodeImp.DoomBuilder.Controls
return true;
}
}
-
+
// A tab is selected
private void tabs_Selecting(object sender, TabControlCancelEventArgs e)
{
@@ -408,16 +408,19 @@ namespace CodeImp.DoomBuilder.Controls
CloseScript(t, false);
UpdateToolbar();
}
-
+
// Compile Script clicked
private void buttoncompile_Click(object sender, EventArgs e)
{
// First save all implicit scripts to the temporary wad file
ImplicitSave();
- // TODO: Now compile this lump
+ // Compile script
+ ScriptDocumentTab t = (tabs.SelectedTab as ScriptDocumentTab);
+ t.Compile();
+ UpdateToolbar();
}
-
+
// Undo clicked
private void buttonundo_Click(object sender, EventArgs e)
{
@@ -425,7 +428,7 @@ namespace CodeImp.DoomBuilder.Controls
t.Undo();
UpdateToolbar();
}
-
+
// Redo clicked
private void buttonredo_Click(object sender, EventArgs e)
{
@@ -433,7 +436,7 @@ namespace CodeImp.DoomBuilder.Controls
t.Redo();
UpdateToolbar();
}
-
+
// Cut clicked
private void buttoncut_Click(object sender, EventArgs e)
{
@@ -441,7 +444,7 @@ namespace CodeImp.DoomBuilder.Controls
t.Cut();
UpdateToolbar();
}
-
+
// Copy clicked
private void buttoncopy_Click(object sender, EventArgs e)
{
diff --git a/Source/Controls/ScriptFileDocumentTab.cs b/Source/Controls/ScriptFileDocumentTab.cs
index a975af4d..9daa6a5e 100644
--- a/Source/Controls/ScriptFileDocumentTab.cs
+++ b/Source/Controls/ScriptFileDocumentTab.cs
@@ -30,6 +30,7 @@ using CodeImp.DoomBuilder.Config;
using CodeImp.DoomBuilder.Types;
using CodeImp.DoomBuilder.IO;
using System.IO;
+using CodeImp.DoomBuilder.Compilers;
#endregion
@@ -80,6 +81,49 @@ namespace CodeImp.DoomBuilder.Controls
#region ================== Methods
+ // This compiles the script file
+ public override void Compile()
+ {
+ DirectoryInfo tempdir;
+ Compiler compiler;
+ string inputfile, outputfile;
+
+ // List of errors
+ List errors = new List();
+
+ try
+ {
+ // Initialize compiler
+ compiler = config.Compiler.Create();
+ }
+ catch(Exception e)
+ {
+ // Fail
+ errors.Add(new CompilerError("Unable to initialize compiler. " + e.GetType().Name + ": " + e.Message));
+ return;
+ }
+
+ // Make random output filename
+ outputfile = General.MakeTempFilename(compiler.Location, "tmp");
+
+ // Run compiler
+ compiler.Parameters = config.Parameters;
+ compiler.InputFile = Path.GetFileName(filepathname);
+ compiler.OutputFile = Path.GetFileName(outputfile);
+ compiler.WorkingDirectory = Path.GetDirectoryName(filepathname);
+ if(compiler.Run())
+ {
+ // Fetch errors
+ errors.AddRange(compiler.Errors);
+ }
+
+ // Dispose compiler
+ compiler.Dispose();
+
+ // TODO: Feed errors to panel
+
+ }
+
// This saves the document (used for both explicit and implicit)
// Return true when successfully saved
public override bool Save()
diff --git a/Source/Controls/ScriptLumpDocumentTab.cs b/Source/Controls/ScriptLumpDocumentTab.cs
index eb108e3d..0dc0723a 100644
--- a/Source/Controls/ScriptLumpDocumentTab.cs
+++ b/Source/Controls/ScriptLumpDocumentTab.cs
@@ -40,9 +40,9 @@ namespace CodeImp.DoomBuilder.Controls
#region ================== Constants
#endregion
-
+
#region ================== Variables
-
+
private string lumpname;
#endregion
@@ -90,6 +90,13 @@ namespace CodeImp.DoomBuilder.Controls
#region ================== Methods
+ // Compile script
+ public override void Compile()
+ {
+ // Do it!
+ General.Map.CompileLump(lumpname);
+ }
+
// Implicit save
public override bool Save()
{
diff --git a/Source/General/MapManager.cs b/Source/General/MapManager.cs
index 18ec0634..138483a5 100644
--- a/Source/General/MapManager.cs
+++ b/Source/General/MapManager.cs
@@ -89,6 +89,7 @@ namespace CodeImp.DoomBuilder
private Launcher launcher;
private ThingsFilter thingsfilter;
private ScriptEditorForm scriptwindow;
+ private List errors;
// Disposing
private bool isdisposed = false;
@@ -121,6 +122,7 @@ namespace CodeImp.DoomBuilder
public IMapSetIO FormatInterface { get { return io; } }
internal Launcher Launcher { get { return launcher; } }
public ThingsFilter ThingsFilter { get { return thingsfilter; } }
+ internal List Errors { get { return errors; } }
public bool IsScriptsWindowOpen { get { return (scriptwindow != null) && !scriptwindow.IsDisposed; } }
#endregion
@@ -557,7 +559,7 @@ namespace CodeImp.DoomBuilder
{
// Create the compiler interface that will run the nodebuilder
// This automatically creates a temporary directory for us
- NodesCompiler compiler = nodebuilder.CreateCompiler();
+ Compiler compiler = nodebuilder.CreateCompiler();
// Make temporary filename
tempfile1 = General.MakeTempFilename(compiler.Location);
@@ -587,8 +589,11 @@ namespace CodeImp.DoomBuilder
buildwad.Dispose();
// Run the nodebuilder
+ compiler.Parameters = nodebuilder.Parameters;
+ compiler.InputFile = Path.GetFileName(tempfile1);
compiler.OutputFile = Path.GetFileName(tempfile2);
- if(compiler.CompileFile(Path.GetFileName(tempfile1)))
+ compiler.WorkingDirectory = Path.GetDirectoryName(tempfile1);
+ if(compiler.Run())
{
// Open the output file
buildwad = new WAD(tempfile2);
@@ -1116,27 +1121,84 @@ namespace CodeImp.DoomBuilder
}
// This compiles a script lump and returns any errors that may have occurred
- internal CompilerError[] CompileLump(Lump scriptlump, bool showwarning)
+ // Returns true when our code worked properly (even when the compiler returned errors)
+ internal bool CompileLump(string lumpname)
{
DirectoryInfo tempdir;
- CompilerError[] errors;
+ Compiler compiler;
+ string inputfile, outputfile;
+
+ // Find the lump
+ Lump lump = tempwad.FindLump(lumpname);
+ if(lump == null) throw new Exception("No such lump in temporary wad file '" + lumpname + "'.");
+
+ // New list of errors
+ errors = new List();
// Determine the script configuration to use
- ScriptConfiguration scriptconfig = config.MapLumps[scriptlump.Name].script;
-
- // Initialize compiler
- Compiler compiler = scriptconfig.Compiler.Create();
-
+ ScriptConfiguration scriptconfig = config.MapLumps[lump.Name].script;
+
+ try
+ {
+ // Initialize compiler
+ compiler = scriptconfig.Compiler.Create();
+ }
+ catch(Exception e)
+ {
+ // Fail
+ errors.Add(new CompilerError("Unable to initialize compiler. " + e.GetType().Name + ": " + e.Message));
+ return false;
+ }
+
+ try
+ {
+ // Write lump data to temp script file in compiler's temp directory
+ inputfile = General.MakeTempFilename(compiler.Location, "tmp");
+ lump.Stream.Seek(0, SeekOrigin.Begin);
+ BinaryReader reader = new BinaryReader(lump.Stream);
+ File.WriteAllBytes(inputfile, reader.ReadBytes((int)lump.Stream.Length));
+ }
+ catch(Exception e)
+ {
+ // Fail
+ compiler.Dispose();
+ errors.Add(new CompilerError("Unable to write script to working file. " + e.GetType().Name + ": " + e.Message));
+ return false;
+ }
+
+ // Make random output filename
+ outputfile = General.MakeTempFilename(compiler.Location, "tmp");
+
// Run compiler
compiler.Parameters = scriptconfig.Parameters;
-
- errors = compiler.Errors;
-
- // Clean up
- compiler.Dispose();
-
- // Done
- return errors;
+ compiler.InputFile = Path.GetFileName(inputfile);
+ compiler.OutputFile = Path.GetFileName(outputfile);
+ compiler.WorkingDirectory = Path.GetDirectoryName(inputfile);
+ if(compiler.Run())
+ {
+ // Fetch errors
+ errors.AddRange(compiler.Errors);
+
+ // Clean up
+ compiler.Dispose();
+ if(errors.Count == 0) errors = null;
+
+ // Done
+ return true;
+ }
+ else
+ {
+ // Fail
+ compiler.Dispose();
+ errors = null;
+ return false;
+ }
+ }
+
+ // This clears all compiler errors
+ internal void ClearCompilerErrors()
+ {
+ errors = null;
}
#endregion