1 | #include "xmlcustomcode.h"
|
---|
2 |
|
---|
3 | // http://stackoverflow.com/questions/7092765/what-does-it-mean-to-have-an-undefined-reference-to-a-static-member
|
---|
4 | QVector<QScriptEngine*> XmlCustomCode::scriptEngines;
|
---|
5 | QVector<QScriptValue*> XmlCustomCode::jsFunctions;
|
---|
6 | QVector<QScriptValue*> XmlCustomCode::getXmlDataFunctions;
|
---|
7 | QVector<QScriptValue*> XmlCustomCode::setXmlDataFunctions;
|
---|
8 |
|
---|
9 | QScriptValue echo(QScriptContext *context, QScriptEngine*)
|
---|
10 | {
|
---|
11 | std::cout << context->argument(0).toString().toUtf8().constData() << std::endl;
|
---|
12 |
|
---|
13 | return "";
|
---|
14 | }
|
---|
15 |
|
---|
16 | XmlCustomCode::XmlCustomCode(): numThreads(omp_get_num_procs()*2)
|
---|
17 | {
|
---|
18 | // create individual thread script engines if empty
|
---|
19 | if(this->scriptEngines.isEmpty()){
|
---|
20 | this->scriptEngines.reserve(this->numThreads);
|
---|
21 | this->jsFunctions.reserve(this->numThreads);
|
---|
22 | this->getXmlDataFunctions.reserve(this->numThreads);
|
---|
23 | this->setXmlDataFunctions.reserve(this->numThreads);
|
---|
24 |
|
---|
25 | QString jsxmlString;
|
---|
26 | QFile jsxmlfile(":/resources/libs/jsxml.js");
|
---|
27 |
|
---|
28 | jsxmlfile.open(QFile::ReadOnly | QFile::Text);
|
---|
29 |
|
---|
30 | jsxmlString=QTextStream(&jsxmlfile).readAll();
|
---|
31 |
|
---|
32 | for(int i=0; i<this->numThreads; i++){
|
---|
33 | this->scriptEngines.append(new QScriptEngine());
|
---|
34 | this->jsFunctions.append(new QScriptValue());
|
---|
35 |
|
---|
36 | // main needs to be called so the user code is evaluated
|
---|
37 | // alternatively you can do: myFunc=engine.evaluate('(function main(){})'); myFunc.call();
|
---|
38 | // Note the () around the function
|
---|
39 | this->getXmlDataFunctions.append(new QScriptValue(this->scriptEngines[i]->evaluate("(function getXmlData() { return $xmlData; })")));
|
---|
40 | this->setXmlDataFunctions.append(new QScriptValue(this->scriptEngines[i]->evaluate("(function setXmlData(newXmlData) { $xmlData=newXmlData; })")));
|
---|
41 |
|
---|
42 | // Add echo function so user can debug the code
|
---|
43 | QScriptValue echoFunction = this->scriptEngines[i]->newFunction(echo);
|
---|
44 | this->scriptEngines[i]->globalObject().setProperty("echo", echoFunction);
|
---|
45 |
|
---|
46 | // Add the js library for XmlEditing
|
---|
47 | this->scriptEngines[i]->evaluate(jsxmlString);
|
---|
48 | }
|
---|
49 | }
|
---|
50 | }
|
---|
51 |
|
---|
52 | void XmlCustomCode::executeCustomCode(const QString &jsString, const QVector<QString> &filesToProcess, const bool backupsEnabled, const bool verboseEnabled){
|
---|
53 |
|
---|
54 | // Reconstruct script functions
|
---|
55 | for(int i=0; i<this->numThreads; i++){
|
---|
56 | *this->jsFunctions[i]=this->scriptEngines[i]->evaluate("(function main() {"+jsString+"})");
|
---|
57 | }
|
---|
58 |
|
---|
59 | QString currXmlFileString;
|
---|
60 |
|
---|
61 | QScriptValue engineResult; // variable to check for js_errors
|
---|
62 | double elapsed_secs=0; // elapsed seconds that a user script took
|
---|
63 | clock_t begin; // seconds that a script started
|
---|
64 |
|
---|
65 | // Single tread if small files
|
---|
66 | if(filesToProcess.size()<CUSTOM_FILES_PER_THREAD){
|
---|
67 | // Process all XmlFiles
|
---|
68 | for(int i=0; i<filesToProcess.size(); i++){
|
---|
69 |
|
---|
70 | customCodeUnwinding(filesToProcess.at(i),currXmlFileString,*this->scriptEngines[0],begin,elapsed_secs,engineResult,
|
---|
71 | *this->jsFunctions[0],*this->getXmlDataFunctions[0],*this->setXmlDataFunctions[0],backupsEnabled,verboseEnabled);
|
---|
72 | }
|
---|
73 | }
|
---|
74 | else{ // Multithread if there are many files
|
---|
75 | // Process all XmlFiles
|
---|
76 | #pragma omp parallel for num_threads(this->numThreads) schedule(dynamic)
|
---|
77 | for(int i=0; i<filesToProcess.size()-CUSTOM_FILES_PER_THREAD; i+=CUSTOM_FILES_PER_THREAD){
|
---|
78 |
|
---|
79 | const int tid=omp_get_thread_num();
|
---|
80 |
|
---|
81 | QString currXmlFileStringThread;
|
---|
82 |
|
---|
83 | QScriptValue engineResultThread; // variable to check for js_errors
|
---|
84 | double elapsedSecsThread=0; // elapsed seconds that a user script took
|
---|
85 | clock_t beginThread; // seconds that a script started
|
---|
86 |
|
---|
87 | customCodeUnwinding(filesToProcess.at(i),currXmlFileStringThread,*this->scriptEngines[tid],beginThread,elapsedSecsThread,engineResultThread,
|
---|
88 | *this->jsFunctions[tid],*this->getXmlDataFunctions[tid],*this->setXmlDataFunctions[tid],backupsEnabled,verboseEnabled);
|
---|
89 |
|
---|
90 | customCodeUnwinding(filesToProcess.at(i+1),currXmlFileStringThread,*this->scriptEngines[tid],beginThread,elapsedSecsThread,engineResultThread,
|
---|
91 | *this->jsFunctions[tid],*this->getXmlDataFunctions[tid],*this->setXmlDataFunctions[tid],backupsEnabled,verboseEnabled);
|
---|
92 | }
|
---|
93 |
|
---|
94 | if(filesToProcess.size()%CUSTOM_FILES_PER_THREAD!=0){
|
---|
95 |
|
---|
96 | int alreadyProcessedFiles=(filesToProcess.size()/CUSTOM_FILES_PER_THREAD)*CUSTOM_FILES_PER_THREAD;
|
---|
97 |
|
---|
98 | for(int i=alreadyProcessedFiles; i<filesToProcess.size(); i++){
|
---|
99 |
|
---|
100 | customCodeUnwinding(filesToProcess.at(i),currXmlFileString,*this->scriptEngines[0],begin,elapsed_secs,engineResult,
|
---|
101 | *this->jsFunctions[0],*this->getXmlDataFunctions[0],*this->setXmlDataFunctions[0],backupsEnabled,verboseEnabled);
|
---|
102 | }
|
---|
103 | }
|
---|
104 | }
|
---|
105 | }
|
---|
106 |
|
---|
107 | void XmlCustomCode::displayJsException(QScriptEngine &engine, QScriptValue &engineResult){
|
---|
108 | if (engine.hasUncaughtException()) {
|
---|
109 | UtilXmlTools::displayErrorMessage("@CUSTOM_CODE","Uncaught js exception (user code) at line " +QString::number(engine.uncaughtExceptionLineNumber()) + ":\n" + engineResult.toString());
|
---|
110 | }
|
---|
111 | }
|
---|