Index: XmlTools2/trunk/XmlTools.pro
===================================================================
--- XmlTools2/trunk/XmlTools.pro	(revision 962)
+++ XmlTools2/trunk/XmlTools.pro	(revision 964)
@@ -8,4 +8,10 @@
 QMAKE_CXXFLAGS+= -fopenmp
 QMAKE_LFLAGS +=  -fopenmp #OpenMP (multithreading) support
+
+# More optimization
+QMAKE_CFLAGS_RELEASE += -O3
+QMAKE_CXXFLAGS_RELEASE += -O3
+
+
 
 
@@ -25,5 +31,6 @@
     utilxmltools.cpp \
     xmlfilter.cpp \
-    optionsparser.cpp
+    optionsparser.cpp \
+    xmlcustomcode.cpp
 
 HEADERS += main.h \
@@ -36,5 +43,6 @@
     utilxmltools.h \
     xmlfilter.h \
-    optionsparser.h
+    optionsparser.h \
+    xmlcustomcode.h
 
 OTHER_FILES +=
Index: XmlTools2/trunk/libs/rexml.js
===================================================================
--- XmlTools2/trunk/libs/rexml.js	(revision 962)
+++ 	(revision )
@@ -1,150 +1,0 @@
-//////     JSXML XML Tools - REXML                /////////////
-//////     Regular Expression-based XML parser    /////////////
-//////     Ver 1.2 Jun 18 2001                    /////////////
-//////     Copyright 2000 Peter Tracey            /////////////
-//////     http://jsxml.homestead.com/            /////////////
-
-function REXML(XML) {
-	this.XML = XML;
-
-	this.rootElement = null;
-
-	this.parse = REXML_parse;
-	if (this.XML && this.XML != "") this.parse();
-}
-
-	function REXML_parse() {
-		var reTag = new RegExp("<([^>/ ]*)([^>]*)>","g"); // matches that tag name $1 and attribute string $2
-		var reTagText = new RegExp("<([^>/ ]*)([^>]*)>([^<]*)","g"); // matches tag name $1, attribute string $2, and text $3
-		var strType = "";
-		var strTag = "";
-		var strText = "";
-		var strAttributes = "";
-		var strOpen = "";
-		var strClose = "";
-		var iElements = 0;
-		var xmleLastElement = null;
-		if (this.XML.length == 0) return;
-		var arrElementsUnparsed = this.XML.match(reTag);
-		var arrElementsUnparsedText = this.XML.match(reTagText);
-		var i=0;
-		if (arrElementsUnparsed[0].replace(reTag, "$1") == "?xml") i++;
-
-		for (; i<arrElementsUnparsed.length; i++) {
-			strTag = arrElementsUnparsed[i].replace(reTag,"$1");
-			strAttributes = arrElementsUnparsed[i].replace(reTag,"$2");
-			strText = arrElementsUnparsedText[i].replace(reTagText,"$3").replace(/[\r\n\t ]+/g, " "); // remove white space
-			strClose = "";
-			if (strTag.indexOf("![CDATA[") == 0) {
-				strOpen = "<![CDATA[";
-				strClose = "]]>";
-				strType = "cdata";
-			} else if (strTag.indexOf("!--") == 0) {
-				strOpen = "<!--";
-				strClose = "-->";
-				strType = "comment";
-			} else if (strTag.indexOf("?") == 0) {
-				strOpen = "<?";
-				strClose = "?>";
-				strType = "pi";
-			} else strType = "element";
-			if (strClose != "") {
-				strText = "";
-				if (arrElementsUnparsedText[i].indexOf(strClose) > -1) strText = arrElementsUnparsedText[i];
-				else {
-					for (; i<arrElementsUnparsed.length && arrElementsUnparsedText[i].indexOf(strClose) == -1; i++) {
-						strText += arrElementsUnparsedText[i];
-					}
-					strText += arrElementsUnparsedText[i];
-				}
-				if (strText.substring(strOpen.length, strText.indexOf(strClose)) != "")	{
-					xmleLastElement.childElements[xmleLastElement.childElements.length] = new REXML_XMLElement(strType, "","",xmleLastElement,strText.substring(strOpen.length, strText.indexOf(strClose)));
-					if (strType == "cdata") xmleLastElement.text += strText.substring(strOpen.length, strText.indexOf(strClose));
-				}
-				if (strText.indexOf(strClose)+ strClose.length < strText.length) {
-					xmleLastElement.childElements[xmleLastElement.childElements.length] = new REXML_XMLElement("text", "","",xmleLastElement,strText.substring(strText.indexOf(strClose)+ strClose.length, strText.length));
-					if (strType == "cdata") xmleLastElement.text += strText.substring(strText.indexOf(strClose)+ strClose.length, strText.length);
-				}
-				continue;
-			}
-			if (strText.replace(/ */, "") == "") strText = "";
-			if (arrElementsUnparsed[i].substring(1,2) != "/") {
-				if (iElements == 0) {
-					xmleLastElement = this.rootElement = new REXML_XMLElement(strType, strTag,strAttributes,null,strText);
-					iElements++;
-					if (strText != "") xmleLastElement.childElements[xmleLastElement.childElements.length] = new REXML_XMLElement("text", "","",xmleLastElement,strText);
-				} else if (arrElementsUnparsed[i].substring(arrElementsUnparsed[i].length-2,arrElementsUnparsed[i].length-1) != "/") {
-					xmleLastElement = xmleLastElement.childElements[xmleLastElement.childElements.length] = new REXML_XMLElement(strType, strTag,strAttributes,xmleLastElement,strText);
-					iElements++;
-					if (strText != "") xmleLastElement.childElements[xmleLastElement.childElements.length] = new REXML_XMLElement("text", "","",xmleLastElement,strText);
-				} else {
-					xmleLastElement.childElements[xmleLastElement.childElements.length] = new REXML_XMLElement(strType, strTag,strAttributes,xmleLastElement,strText);
-					if (strText != "") xmleLastElement.childElements[xmleLastElement.childElements.length] = new REXML_XMLElement("text", "","",xmleLastElement,strText);
-				}
-			} else {
-				xmleLastElement = xmleLastElement.parentElement;
-				iElements--;
-				if (xmleLastElement && strText != "") {
-					xmleLastElement.text += strText;
-					xmleLastElement.childElements[xmleLastElement.childElements.length] = new REXML_XMLElement("text", "","",xmleLastElement,strText);
-				}
-			}
-		}
-	}
-
-	function REXML_XMLElement(strType, strName, strAttributes, xmlParent, strText) {
-		this.type = strType;
-		this.name = strName;
-		this.attributeString = strAttributes;
-		this.attributes = null;
-		this.childElements = new Array();
-		this.parentElement = xmlParent;
-		this.text = strText; // text of element
-
-		this.getText = REXML_XMLElement_getText; // text of element and child elements
-		this.childElement = REXML_XMLElement_childElement;
-		this.attribute = REXML_XMLElement_attribute;
-	}
-
-		function REXML_XMLElement_getText() {
-			if (this.type == "text" || this.type == "cdata") {
-				return this.text;
-			} else if (this.childElements.length) {
-				var L = "";
-				for (var i=0; i<this.childElements.length; i++) {
-					L += this.childElements[i].getText();
-				}
-				return L;
-			} else return "";
-		}
-		
-		function REXML_XMLElement_childElement(strElementName) {
-			for (var i=0; i<this.childElements.length; i++) if (this.childElements[i].name == strElementName) return this.childElements[i];
-			return null;
-		}
-
-		function REXML_XMLElement_attribute(strAttributeName) {
-			if (!this.attributes) {
-				var reAttributes = new RegExp(" ([^= ]*)=","g"); // matches attributes
-				if (this.attributeString.match(reAttributes) && this.attributeString.match(reAttributes).length) {
-					var arrAttributes = this.attributeString.match(reAttributes);
-					if (!arrAttributes.length) arrAttributes = null;
-					else for (var j=0; j<arrAttributes.length; j++) {
-						arrAttributes[j] = new Array(
-							(arrAttributes[j]+"").replace(/[= ]/g,""),
-							ParseAttribute(this.attributeString, (arrAttributes[j]+"").replace(/[= ]/g,""))
-										);
-					}
-					this.attributes = arrAttributes;
-				}
-			}
-			if (this.attributes) for (var i=0; i<this.attributes.length; i++) if (this.attributes[i][0] == strAttributeName) return this.attributes[i][1];
-			return "";
-		}
-
-function ParseAttribute(str,Attribute) {
-	var str = str +  ">";
-	if (str.indexOf(Attribute + "='")>-1) var Attr = new RegExp(".*" + Attribute + "='([^']*)'.*>");
-	else if (str.indexOf(Attribute + '="')>-1) var Attr = new RegExp(".*" + Attribute + '="([^"]*)".*>');
-	return str.replace(Attr, "$1");
-}
Index: XmlTools2/trunk/optionsparser.h
===================================================================
--- XmlTools2/trunk/optionsparser.h	(revision 962)
+++ XmlTools2/trunk/optionsparser.h	(revision 964)
@@ -3,4 +3,7 @@
 
 #include "xmlpatch.h"
+
+#include <QCommandLineOption>
+#include <QCommandLineParser>
 
 class OptionsParser
Index: XmlTools2/trunk/resources.qrc
===================================================================
--- XmlTools2/trunk/resources.qrc	(revision 962)
+++ XmlTools2/trunk/resources.qrc	(revision 964)
@@ -2,5 +2,4 @@
     <qresource prefix="/resources">
         <file>libs/jsxml.js</file>
-        <file>libs/rexml.js</file>
     </qresource>
 </RCC>
Index: XmlTools2/trunk/util.h
===================================================================
--- XmlTools2/trunk/util.h	(revision 962)
+++ XmlTools2/trunk/util.h	(revision 964)
@@ -6,4 +6,5 @@
 #include <QString>
 #include <QStringList>
+#include <QVector>
 #include <iostream> // cout, cin etc.
 
Index: XmlTools2/trunk/utilxmltools.cpp
===================================================================
--- XmlTools2/trunk/utilxmltools.cpp	(revision 962)
+++ XmlTools2/trunk/utilxmltools.cpp	(revision 964)
@@ -3,5 +3,6 @@
 namespace UtilXmlTools{
 
-QStringList getAllXmlFilesByWildcard(const QString &wildcard){
+// As this will not likely be modified we use QVector instead of QList since it is more cache friendly
+QVector<QString> getAllXmlFilesByWildcard(const QString &wildcard){
     QStringList validFilesMatching;
     QStringList filesMatching;
@@ -19,9 +20,9 @@
     }
 
-    return validFilesMatching;
+    return validFilesMatching.toVector();
 
 }
 
-QStringList getAllPatchFilesByWildcard(const QString &wildcard){
+QVector<QString> getAllPatchFilesByWildcard(const QString &wildcard){
     QStringList validFilesMatching;
     QStringList filesMatching;
@@ -39,5 +40,5 @@
     }
 
-    return validFilesMatching;
+    return validFilesMatching.toVector();
 
 }
Index: XmlTools2/trunk/utilxmltools.h
===================================================================
--- XmlTools2/trunk/utilxmltools.h	(revision 962)
+++ XmlTools2/trunk/utilxmltools.h	(revision 964)
@@ -10,6 +10,6 @@
 namespace UtilXmlTools{
 
-QStringList getAllXmlFilesByWildcard(const QString &wildcard);
-QStringList getAllPatchFilesByWildcard(const QString &wildcard);
+QVector<QString> getAllXmlFilesByWildcard(const QString &wildcard);
+QVector<QString> getAllPatchFilesByWildcard(const QString &wildcard);
 void backupFile(const QString &file, bool verboseEnabled);
 void getAllNamedElements(pugi::xml_node &node, QList<pugi::xml_node> &result, XmlFilter &filters);
Index: XmlTools2/trunk/xmlcustomcode.cpp
===================================================================
--- XmlTools2/trunk/xmlcustomcode.cpp	(revision 964)
+++ XmlTools2/trunk/xmlcustomcode.cpp	(revision 964)
@@ -0,0 +1,111 @@
+#include "xmlcustomcode.h"
+
+// http://stackoverflow.com/questions/7092765/what-does-it-mean-to-have-an-undefined-reference-to-a-static-member
+QVector<QScriptEngine*> XmlCustomCode::scriptEngines;
+QVector<QScriptValue*> XmlCustomCode::jsFunctions;
+QVector<QScriptValue*> XmlCustomCode::getXmlDataFunctions;
+QVector<QScriptValue*> XmlCustomCode::setXmlDataFunctions;
+
+QScriptValue echo(QScriptContext *context, QScriptEngine*)
+{
+    std::cout << context->argument(0).toString().toUtf8().constData() << std::endl;
+
+    return "";
+}
+
+XmlCustomCode::XmlCustomCode(): numThreads(omp_get_num_procs()*2)
+{
+    // create individual thread script engines if empty
+    if(this->scriptEngines.isEmpty()){
+        this->scriptEngines.reserve(this->numThreads);
+        this->jsFunctions.reserve(this->numThreads);
+        this->getXmlDataFunctions.reserve(this->numThreads);
+        this->setXmlDataFunctions.reserve(this->numThreads);
+
+        QString jsxmlString;
+        QFile jsxmlfile(":/resources/libs/jsxml.js");
+
+        jsxmlfile.open(QFile::ReadOnly | QFile::Text);
+
+        jsxmlString=QTextStream(&jsxmlfile).readAll();
+
+        for(int i=0; i<this->numThreads; i++){
+            this->scriptEngines.append(new QScriptEngine());
+            this->jsFunctions.append(new QScriptValue());
+
+            // main needs to be called so the user code is evaluated
+            // alternatively you can do: myFunc=engine.evaluate('(function main(){})'); myFunc.call();
+            // Note the () around the function
+            this->getXmlDataFunctions.append(new QScriptValue(this->scriptEngines[i]->evaluate("(function getXmlData() { return $xmlData; })")));
+            this->setXmlDataFunctions.append(new QScriptValue(this->scriptEngines[i]->evaluate("(function setXmlData(newXmlData) { $xmlData=newXmlData; })")));
+
+            // Add echo function so user can debug the code
+            QScriptValue echoFunction = this->scriptEngines[i]->newFunction(echo);
+            this->scriptEngines[i]->globalObject().setProperty("echo", echoFunction);
+
+            // Add the js library for XmlEditing
+            this->scriptEngines[i]->evaluate(jsxmlString);
+        }
+    }
+}
+
+void XmlCustomCode::executeCustomCode(const QString &jsString, const QVector<QString> &filesToProcess, const bool backupsEnabled, const bool verboseEnabled){
+
+    // Reconstruct script functions
+    for(int i=0; i<this->numThreads; i++){
+        *this->jsFunctions[i]=this->scriptEngines[i]->evaluate("(function main() {"+jsString+"})");
+    }
+
+    QString currXmlFileString;
+
+    QScriptValue engineResult; // variable to check for js_errors
+    double elapsed_secs=0; // elapsed seconds that a user script took
+    clock_t begin; // seconds that a script started
+
+    // Single tread if small files
+    if(filesToProcess.size()<CUSTOM_FILES_PER_THREAD){
+        // Process all XmlFiles
+        for(int i=0; i<filesToProcess.size(); i++){
+
+            customCodeUnwinding(filesToProcess.at(i),currXmlFileString,*this->scriptEngines[0],begin,elapsed_secs,engineResult,
+                    *this->jsFunctions[0],*this->getXmlDataFunctions[0],*this->setXmlDataFunctions[0],backupsEnabled,verboseEnabled);
+        }
+    }
+    else{ // Multithread if there are many files
+        // Process all XmlFiles
+#pragma omp parallel for num_threads(this->numThreads) schedule(dynamic)
+        for(int i=0; i<filesToProcess.size()-CUSTOM_FILES_PER_THREAD; i+=CUSTOM_FILES_PER_THREAD){
+
+            const int tid=omp_get_thread_num();
+
+            QString currXmlFileStringThread;
+
+            QScriptValue engineResultThread; // variable to check for js_errors
+            double elapsedSecsThread=0; // elapsed seconds that a user script took
+            clock_t beginThread; // seconds that a script started
+
+            customCodeUnwinding(filesToProcess.at(i),currXmlFileStringThread,*this->scriptEngines[tid],beginThread,elapsedSecsThread,engineResultThread,
+                                *this->jsFunctions[tid],*this->getXmlDataFunctions[tid],*this->setXmlDataFunctions[tid],backupsEnabled,verboseEnabled);
+
+            customCodeUnwinding(filesToProcess.at(i+1),currXmlFileStringThread,*this->scriptEngines[tid],beginThread,elapsedSecsThread,engineResultThread,
+                                *this->jsFunctions[tid],*this->getXmlDataFunctions[tid],*this->setXmlDataFunctions[tid],backupsEnabled,verboseEnabled);
+        }
+
+        if(filesToProcess.size()%CUSTOM_FILES_PER_THREAD!=0){
+
+            int alreadyProcessedFiles=(filesToProcess.size()/CUSTOM_FILES_PER_THREAD)*CUSTOM_FILES_PER_THREAD;
+
+            for(int i=alreadyProcessedFiles; i<filesToProcess.size(); i++){
+
+                customCodeUnwinding(filesToProcess.at(i),currXmlFileString,*this->scriptEngines[0],begin,elapsed_secs,engineResult,
+                        *this->jsFunctions[0],*this->getXmlDataFunctions[0],*this->setXmlDataFunctions[0],backupsEnabled,verboseEnabled);
+            }
+        }
+    }
+}
+
+void XmlCustomCode::displayJsException(QScriptEngine &engine, QScriptValue &engineResult){
+    if (engine.hasUncaughtException()) {
+        UtilXmlTools::displayErrorMessage("@CUSTOM_CODE","Uncaught js exception (user code) at line " +QString::number(engine.uncaughtExceptionLineNumber()) + ":\n" + engineResult.toString());
+    }
+}
Index: XmlTools2/trunk/xmlcustomcode.h
===================================================================
--- XmlTools2/trunk/xmlcustomcode.h	(revision 964)
+++ XmlTools2/trunk/xmlcustomcode.h	(revision 964)
@@ -0,0 +1,83 @@
+#ifndef XMLCUSTOMCODE_H
+#define XMLCUSTOMCODE_H
+
+#include "utilxmltools.h"
+
+#include <omp.h> // OpenMP support
+#include <ctime> // script execution time calculation
+#include <QScriptEngine>
+#include <QTextStream>
+#include <QCoreApplication>
+
+#define SLOW_SCRIPT_TIME 0.1 // if a user script takes more than 0.1 seconds to execute give a warning.
+#define CUSTOM_FILES_PER_THREAD 2
+
+class XmlCustomCode
+{
+public:
+    XmlCustomCode();
+    void executeCustomCode(const QString &jsString, const QVector<QString> &filesToProcess, const bool backupsEnabled, const bool verboseEnabled);
+private:
+    const int numThreads;
+    static QVector<QScriptEngine*> scriptEngines; // allows each thread to keep one script engine without always create/destruct them
+    static QVector<QScriptValue*> jsFunctions;
+    static QVector<QScriptValue*> getXmlDataFunctions;
+    static QVector<QScriptValue*> setXmlDataFunctions;
+
+    void displayJsException(QScriptEngine &engine, QScriptValue &engineResult);
+
+    __attribute__((always_inline)) inline void customCodeUnwinding(const QString &fileName, QString &currXmlFileString,
+    QScriptEngine &engine, clock_t &begin, double elapsed_secs, QScriptValue &engineResult, QScriptValue &jsFunction,
+    QScriptValue &getXmlDataFunction, QScriptValue &setXmlDataFunction, const bool &backupsEnabled, const bool &verboseEnabled){
+        if(backupsEnabled){
+            UtilXmlTools::backupFile(fileName, verboseEnabled);
+        }
+
+        QFile currXmlFile(fileName);
+
+        if(!currXmlFile.open(QFile::ReadOnly | QFile::Text)){
+            UtilXmlTools::displayErrorMessage("@CUSTOM_CODE","Error loading '" + fileName + "' file for read operation.");
+        }
+
+        currXmlFileString=QTextStream(&currXmlFile).readAll();
+
+        currXmlFile.close(); // close reading
+
+        setXmlDataFunction.call(setXmlDataFunction,QScriptValueList() << currXmlFileString);
+
+        begin = clock();
+
+        engineResult=jsFunction.call(); // main funtion allows to use return to exit prematurely from user code
+
+        if(verboseEnabled){
+            elapsed_secs = double(clock() - begin) / CLOCKS_PER_SEC;
+
+            // Warn the user if the script took much time
+            if(elapsed_secs>SLOW_SCRIPT_TIME){
+                std::cout << "Warning: Slow javascript code detected.\n" <<
+                             "Warning: Script execution seconds: " << elapsed_secs
+                          << std::endl;
+            }
+        }
+
+        if (engine.hasUncaughtException()) {
+            displayJsException(engine,engineResult);
+        }
+
+        if(!currXmlFile.open(QFile::WriteOnly | QFile::Text | QIODevice::Truncate)){
+            UtilXmlTools::displayErrorMessage("@CUSTOM_CODE","Error loading '" + fileName + "' file for @CUSTOM_CODE write operation.");
+        }
+
+        engineResult=getXmlDataFunction.call();
+
+        if (engine.hasUncaughtException()) {
+            displayJsException(engine,engineResult);
+        }
+
+        QTextStream(&currXmlFile) << engineResult.toString(); // retreive the modified xml by javascript and save it to the file
+
+        currXmlFile.close();
+    }
+};
+
+#endif // XMLCUSTOMCODE_H
Index: XmlTools2/trunk/xmlpatch.cpp
===================================================================
--- XmlTools2/trunk/xmlpatch.cpp	(revision 962)
+++ XmlTools2/trunk/xmlpatch.cpp	(revision 964)
@@ -47,5 +47,5 @@
 void XmlPatch::insertNodesOperation(const QString &xmlString, XmlFilter &filters, const QString &xPathExpression, const QString &filesWildcard){
 
-    QStringList filesToProcess;
+    QVector<QString> filesToProcess;
     QList<pugi::xml_node> nodesToInsertion;
     pugi::xml_document newNode;
@@ -115,5 +115,5 @@
 void XmlPatch::removeNodesOperation(XmlFilter &filters, const QString &xPathExpression, const QString &filesWildcard){
 
-    QStringList filesToProcess;
+    QVector<QString> filesToProcess;
 
     QList<pugi::xml_node> nodesToDeletion;
@@ -212,15 +212,7 @@
 }
 
-QScriptValue echo(QScriptContext *context, QScriptEngine *engine)
-{
-    std::cout << context->argument(0).toString().toUtf8().constData() << std::endl;
-
-    return "";
-}
-
 void XmlPatch::executeCustomCommandOperation(const QString &jsString, const QString &filesWildcard){
 
-    QString rexmlString, jsxmlString;
-    QStringList filesToProcess=UtilXmlTools::getAllXmlFilesByWildcard(filesWildcard);
+    QVector<QString> filesToProcess=UtilXmlTools::getAllXmlFilesByWildcard(filesWildcard);
 
     if(filesToProcess.isEmpty()){
@@ -228,81 +220,6 @@
     }
 
-    QFile rexmlfile(":/resources/libs/rexml.js");
-    QFile jsxmlfile(":/resources/libs/jsxml.js");
-
-    rexmlfile.open(QFile::ReadOnly | QFile::Text);
-    jsxmlfile.open(QFile::ReadOnly | QFile::Text);
-
-    rexmlString=QTextStream(&rexmlfile).readAll();
-    jsxmlString=QTextStream(&jsxmlfile).readAll();
-
-    // Process all XmlFiles
-#pragma omp parallel for
-    for(int i=0; i<filesToProcess.size(); i++){
-
-        QString currXmlFileString;
-
-        QScriptEngine engine;
-        QScriptValue engineResult; // variable to check for js_errors
-        double elapsed_secs; // elapsed seconds that a user script took
-        clock_t begin; // seconds that a script started
-
-        // Add echo function so user can debug the code
-        QScriptValue echoFunction = engine.newFunction(echo);
-        engine.globalObject().setProperty("echo", echoFunction);
-
-        engine.evaluate(rexmlString); // load js libraries
-        engine.evaluate(jsxmlString);
-
-        if(this->backupsEnabled){
-            UtilXmlTools::backupFile(filesToProcess[i], this->verboseEnabled);
-        }
-
-        QFile currXmlFile(filesToProcess[i]);
-
-        if(!currXmlFile.open(QFile::ReadOnly | QFile::Text)){
-            UtilXmlTools::displayErrorMessage("@CUSTOM_CODE","Error loading '" + filesToProcess[i] + "' file for read operation.");
-        }
-
-        currXmlFileString=QTextStream(&currXmlFile).readAll();
-
-        currXmlFile.close(); // close reading
-
-        engine.globalObject().setProperty("$xmlData",currXmlFileString);
-
-        begin = clock();
-
-        // main needs to be called so the user code is evaluated
-        // alternatively you can do: myFunc=engine.evaluate('(function main(){})'); myFunc.call();
-        // Note the () around the function
-        engineResult=engine.evaluate("main(); function main() {"+jsString+"}"); // main funtion allows to use return to exit prematurely from user code
-
-        if(this->verboseEnabled){
-            elapsed_secs = double(clock() - begin) / CLOCKS_PER_SEC;
-
-            // Warn the user if the script took much time
-            if(elapsed_secs>SLOW_SCRIPT_TIME){
-                std::cout << "Warning: Slow javascript code detected.\n" <<
-                             "Warning: Script execution seconds: " << elapsed_secs
-                          << std::endl;
-            }
-        }
-
-        if (engine.hasUncaughtException()) {
-            displayJsException(engine,engineResult);
-        }
-
-        if(!currXmlFile.open(QFile::WriteOnly | QFile::Text | QIODevice::Truncate)){
-            UtilXmlTools::displayErrorMessage("@CUSTOM_CODE","Error loading '" + filesToProcess[i] + "' file for @CUSTOM_CODE write operation.");
-        }
-
-        engineResult=engine.globalObject().property("$xmlData");
-
-        if (engine.hasUncaughtException()) {
-            displayJsException(engine,engineResult);
-        }
-
-        QTextStream(&currXmlFile) << engineResult.toString(); // retreive the modified xml by javascript and save it to the file
-    }
+    this->customCodeOperation.executeCustomCode(jsString,filesToProcess,this->backupsEnabled,this->verboseEnabled);
+
 
     UtilXmlTools::displaySuccessMessage(filesToProcess.size(), "@CUSTOM_CODE");
@@ -515,8 +432,2 @@
     return line.mid(startValueIdx,endValueIdx-startValueIdx); // return the value of the parameter (is in the middle of the mandatory quotes)
 }
-
-void XmlPatch::displayJsException(QScriptEngine &engine, QScriptValue &engineResult){
-    if (engine.hasUncaughtException()) {
-        UtilXmlTools::displayErrorMessage("@CUSTOM_CODE","Uncaught js exception (user code) at line " +QString::number(engine.uncaughtExceptionLineNumber()) + ":\n" + engineResult.toString());
-    }
-}
Index: XmlTools2/trunk/xmlpatch.h
===================================================================
--- XmlTools2/trunk/xmlpatch.h	(revision 962)
+++ XmlTools2/trunk/xmlpatch.h	(revision 964)
@@ -3,9 +3,6 @@
 
 #include "xmltools.h"
+#include "xmlcustomcode.h"
 #include "optionsparser.h"
-#include <omp.h> // OpenMP support
-#include <ctime> // script execution time calculation
-
-#define SLOW_SCRIPT_TIME 0.1 // if a user script takes more than 0.1 seconds to execute give a warning.
 
 class XmlPatch
@@ -15,9 +12,10 @@
     void readAndProcessPatchFile();
 private:
-    QStringList patchFilesToProcess;
+    QVector<QString> patchFilesToProcess;
     QString forceTargetFilesWildcard;
     pugi::xml_document document;
     pugi::xml_node rootNode;
     bool backupsEnabled, verboseEnabled;
+    XmlCustomCode customCodeOperation;
     QString getPatchParameterValue(const QString& line, QString parameter);
     void insertNodesOperation(const QString &xmlString, XmlFilter &filters, const QString &xPathExpression, const QString &filesWildcard="");
@@ -27,5 +25,4 @@
     void checkPatchVersion(const QString &file, QTextStream &fileStream);
     void checkAndProcessValidCommands(QTextStream &fileStream);
-    void displayJsException(QScriptEngine &engine, QScriptValue &engineResult);
 };
 
Index: XmlTools2/trunk/xmltools.h
===================================================================
--- XmlTools2/trunk/xmltools.h	(revision 962)
+++ XmlTools2/trunk/xmltools.h	(revision 964)
@@ -4,7 +4,5 @@
 
 #include <string>
-#include <QtCore>
 #include <stdio.h>
-#include <QScriptEngine>
 
 #include "utilxmltools.h"
@@ -32,5 +30,5 @@
     pugi::xml_document document;
     pugi::xml_node rootNode;
-    QStringList filesToProcess;
+    QVector<QString> filesToProcess;
     QString xPathExpression;
     XmlFilter filters;
