From d019992c0798595d3d422672a21e3441b3cc6838 Mon Sep 17 00:00:00 2001 From: berteh Date: Wed, 5 Aug 2015 16:00:45 +0200 Subject: [PATCH 01/13] added command-line arguments to be passed to python script, some fix needed in scriptercore.cpp#283. --- scribus/plugins/scriptplugin/scriptercore.cpp | 30 ++++++++++++++++--- scribus/plugins/scriptplugin/scriptercore.h | 3 +- scribus/scribusapp.cpp | 22 ++++++++++++-- scribus/scribusapp.h | 2 ++ 4 files changed, 50 insertions(+), 7 deletions(-) diff --git a/scribus/plugins/scriptplugin/scriptercore.cpp b/scribus/plugins/scriptplugin/scriptercore.cpp index 3903617809..c27517b902 100644 --- a/scribus/plugins/scriptplugin/scriptercore.cpp +++ b/scribus/plugins/scriptplugin/scriptercore.cpp @@ -9,6 +9,7 @@ for which a new license (GPL+exception) is in place. #include #include #include +#include #include #include #include @@ -37,7 +38,7 @@ for which a new license (GPL+exception) is in place. #include "prefscontext.h" #include "prefstable.h" #include "prefsmanager.h" -#include "scribusapp.h" // need it to acces ScQApp->pythonScript +#include "scribusapp.h" // need it to acces ScQApp->pythonScript & ScQApp->pythonScriptArgs ScripterCore::ScripterCore(QWidget* parent) { @@ -227,6 +228,12 @@ void ScripterCore::RecentScript(QString fn) } void ScripterCore::slotRunScriptFile(QString fileName, bool inMainInterpreter) +{ + QStringList arguments = QStringList(); + slotRunScriptFileArgs(fileName, arguments, inMainInterpreter); +} + +void ScripterCore::slotRunScriptFileArgs(QString fileName, QStringList arguments, bool inMainInterpreter) { // Prevent two scripts to be run concurrently or face crash! if (ScCore->primaryMainWindow()->scriptIsRunning()) @@ -252,16 +259,31 @@ void ScripterCore::slotRunScriptFile(QString fileName, bool inMainInterpreter) // Init the scripter module in the sub-interpreter initscribus(ScCore->primaryMainWindow()); } + + // handle additional arguments + bool argsExtra = !(arguments.isEmpty()); + int argsc = 0; + if (argsExtra) + { + argsc = arguments.size(); + //std::cout << tr("running script with %1 arguments").arg(argsc).toLocal8Bit().data() << std::endl; + } // Make sure sys.argv[0] is the path to the script - char* comm[2]; + char* comm[2+argsc]; comm[0] = na.data(); + // and tell the script if it's running in the main intepreter or // a subinterpreter using the second argument, ie sys.argv[1] if (inMainInterpreter) comm[1] = const_cast("ext"); else comm[1] = const_cast("sub"); - PySys_SetArgv(2, comm); + for (int j = 0; j < argsc; ++j) + { + comm[2+j] = arguments.at(j).toLocal8Bit().data() ; // TODO fix here: some copy is needed, otherwise all comm[>2] point to same (last) value for j. + } + PySys_SetArgv(2+argsc, comm); + // call python script PyObject* m = PyImport_AddModule((char*)"__main__"); if (m == NULL) @@ -357,7 +379,7 @@ void ScripterCore::slotRunPythonScript() { if (!ScQApp->pythonScript.isNull()) { - slotRunScriptFile(ScQApp->pythonScript, true); + slotRunScriptFileArgs(ScQApp->pythonScript, ScQApp->pythonScriptArgs, true); FinishScriptRun(); } } diff --git a/scribus/plugins/scriptplugin/scriptercore.h b/scribus/plugins/scriptplugin/scriptercore.h index 1e929f4706..b8e2edf98e 100644 --- a/scribus/plugins/scriptplugin/scriptercore.h +++ b/scribus/plugins/scriptplugin/scriptercore.h @@ -39,8 +39,9 @@ public slots: void StdScript(QString filebasename); void RecentScript(QString fn); void slotRunScriptFile(QString fileName, bool inMainInterpreter = false); + void slotRunScriptFileArgs(QString fileName, QStringList arguments, bool inMainInterpreter = false); void slotRunPythonScript(); // needed for running python script from CLI - void slotRunScript(const QString Script); + void slotRunScript(const QString script); void slotInteractiveScript(bool); void slotExecute(); /*! \brief Show docstring of the script to the user. diff --git a/scribus/scribusapp.cpp b/scribus/scribusapp.cpp index fec40559ad..9c52c04dd7 100644 --- a/scribus/scribusapp.cpp +++ b/scribus/scribusapp.cpp @@ -32,6 +32,7 @@ for which a new license (GPL+exception) is in place. #include #include #include +#include #include #include #include @@ -71,6 +72,8 @@ for which a new license (GPL+exception) is in place. #define ARG_UPGRADECHECK "--upgradecheck" #define ARG_TESTS "--tests" #define ARG_PYTHONSCRIPT "--python-script" +#define ARG_SCRIPTARG_PREFIX "--python-arg" // directly followed by +#define ARG_SCRIPTFLAG_PREFIX "--python-flag" // directly followed by #define ARG_VERSION_SHORT "-v" #define ARG_HELP_SHORT "-h" @@ -108,6 +111,7 @@ ScribusQApp::ScribusQApp( int & argc, char ** argv ) : QApplication(argc, argv), m_scDLMgr = 0; m_ScCore = NULL; initDLMgr(); + } ScribusQApp::~ScribusQApp() @@ -213,6 +217,8 @@ void ScribusQApp::parseCommandLine() std::exit(EXIT_SUCCESS); useGUI = true; //We are going to run something other than command line help + QString qtARG_SCRIPTARG_PREFIX = QString(ARG_SCRIPTARG_PREFIX); + QString qtARG_SCRIPTFLAG_PREFIX = QString(ARG_SCRIPTFLAG_PREFIX); for(int i = 1; i < argsc; i++) { arg = args[i]; @@ -267,7 +273,17 @@ void ScribusQApp::parseCommandLine() } else { ++i; } - } else { + } else if (arg.startsWith(qtARG_SCRIPTARG_PREFIX)) { + QString arg_name = arg.mid(qtARG_SCRIPTARG_PREFIX.size()); + QString arg_value = QFile::decodeName(args[++i].toLocal8Bit()); + //std::cout << tr("got one script argument: %1 with value %2").arg(arg_name).arg(arg_value).toLocal8Bit().data() << std::endl; + pythonScriptArgs.append(arg_name); + pythonScriptArgs.append(arg_value); + } else if (arg.startsWith(qtARG_SCRIPTFLAG_PREFIX)) { + QString arg_name = arg.mid(qtARG_SCRIPTFLAG_PREFIX.size()); + //std::cout << tr("got one script flag: %1 ").arg(arg_name).toLocal8Bit().data() << std::endl; + pythonScriptArgs.append(arg_name); + } else { // (last) positional argument fileName = QFile::decodeName(args[i].toLocal8Bit()); if (!QFileInfo(fileName).exists()) { showHeader(); @@ -498,7 +514,9 @@ void ScribusQApp::showUsage() printArgLine(ts, ARG_UPGRADECHECK_SHORT, ARG_UPGRADECHECK, tr("Download a file from the Scribus website and show the latest available version") ); printArgLine(ts, ARG_VERSION_SHORT, ARG_VERSION, tr("Output version information and exit") ); printArgLine(ts, ARG_PYTHONSCRIPT_SHORT, qPrintable(QString("%1 <%2>").arg(ARG_PYTHONSCRIPT).arg(tr("filename"))), tr("Run filename in Python scripter") ); - printArgLine(ts, ARG_NOGUI_SHORT, ARG_NOGUI, tr("Do not start GUI") ); + ts << (QString(" %1<%2> <%3> ").arg(ARG_SCRIPTARG_PREFIX).arg(tr("argumentname")).arg(tr("value"))) << tr("Argument passed on to python script with its value, no effect without -py"); endl(ts); + ts << (QString(" %1<%2> ").arg(ARG_SCRIPTFLAG_PREFIX).arg(tr("flagname"))) << tr("Argument passed on to python script with no value, no effect without -py"); endl(ts); + printArgLine(ts, ARG_NOGUI_SHORT, ARG_NOGUI, tr("Do not start GUI") ); #if defined(_WIN32) && !defined(_CONSOLE) printArgLine(ts, ARG_CONSOLE_SHORT, ARG_CONSOLE, tr("Display a console window") ); diff --git a/scribus/scribusapp.h b/scribus/scribusapp.h index 2857306d75..7fc9f7f726 100644 --- a/scribus/scribusapp.h +++ b/scribus/scribusapp.h @@ -23,6 +23,7 @@ for which a new license (GPL+exception) is in place. #define SCRIBUSAPP_H #include #include +#include #include "scribusapi.h" @@ -71,6 +72,7 @@ class SCRIBUS_API ScribusQApp : public QApplication const QString& currGUILanguage() { return GUILang; } ScDLManager* dlManager() { return m_scDLMgr; } QString pythonScript; // script to be run in python from CLI + QStringList pythonScriptArgs; // command line arguments and flags for script from CLI private: ScribusCore* m_ScCore; From f4c7e635c738fb35114f9ffd6112c0e38990d55a Mon Sep 17 00:00:00 2001 From: berteh Date: Wed, 5 Aug 2015 17:05:56 +0200 Subject: [PATCH 02/13] help message layout --- scribus/scribusapp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scribus/scribusapp.cpp b/scribus/scribusapp.cpp index 9c52c04dd7..77be0887a8 100644 --- a/scribus/scribusapp.cpp +++ b/scribus/scribusapp.cpp @@ -514,8 +514,8 @@ void ScribusQApp::showUsage() printArgLine(ts, ARG_UPGRADECHECK_SHORT, ARG_UPGRADECHECK, tr("Download a file from the Scribus website and show the latest available version") ); printArgLine(ts, ARG_VERSION_SHORT, ARG_VERSION, tr("Output version information and exit") ); printArgLine(ts, ARG_PYTHONSCRIPT_SHORT, qPrintable(QString("%1 <%2>").arg(ARG_PYTHONSCRIPT).arg(tr("filename"))), tr("Run filename in Python scripter") ); - ts << (QString(" %1<%2> <%3> ").arg(ARG_SCRIPTARG_PREFIX).arg(tr("argumentname")).arg(tr("value"))) << tr("Argument passed on to python script with its value, no effect without -py"); endl(ts); - ts << (QString(" %1<%2> ").arg(ARG_SCRIPTFLAG_PREFIX).arg(tr("flagname"))) << tr("Argument passed on to python script with no value, no effect without -py"); endl(ts); + ts << (QString(" %1<%2> <%3> ").arg(ARG_SCRIPTARG_PREFIX).arg(tr("argumentname")).arg(tr("value"))) << tr("Argument passed on to python script with its value, no effect without -py"); endl(ts); + ts << (QString(" %1<%2> ").arg(ARG_SCRIPTFLAG_PREFIX).arg(tr("flagname"))) << tr("Argument passed on to python script with no value, no effect without -py"); endl(ts); printArgLine(ts, ARG_NOGUI_SHORT, ARG_NOGUI, tr("Do not start GUI") ); #if defined(_WIN32) && !defined(_CONSOLE) From 35e17efbc051678d5d78f4958a08ac6bc7079bc0 Mon Sep 17 00:00:00 2001 From: berteh Date: Wed, 5 Aug 2015 17:07:11 +0200 Subject: [PATCH 03/13] use QStringList to call python script with arguments --- scribus/plugins/scriptplugin/scriptercore.cpp | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/scribus/plugins/scriptplugin/scriptercore.cpp b/scribus/plugins/scriptplugin/scriptercore.cpp index c27517b902..f6456c46dd 100644 --- a/scribus/plugins/scriptplugin/scriptercore.cpp +++ b/scribus/plugins/scriptplugin/scriptercore.cpp @@ -234,6 +234,7 @@ void ScripterCore::slotRunScriptFile(QString fileName, bool inMainInterpreter) } void ScripterCore::slotRunScriptFileArgs(QString fileName, QStringList arguments, bool inMainInterpreter) +/** run "filename" python script with the additional arguments provided in "arguments" */ { // Prevent two scripts to be run concurrently or face crash! if (ScCore->primaryMainWindow()->scriptIsRunning()) @@ -260,29 +261,24 @@ void ScripterCore::slotRunScriptFileArgs(QString fileName, QStringList arguments initscribus(ScCore->primaryMainWindow()); } - // handle additional arguments - bool argsExtra = !(arguments.isEmpty()); - int argsc = 0; - if (argsExtra) - { - argsc = arguments.size(); - //std::cout << tr("running script with %1 arguments").arg(argsc).toLocal8Bit().data() << std::endl; - } // Make sure sys.argv[0] is the path to the script - char* comm[2+argsc]; - comm[0] = na.data(); + arguments.prepend(na.data()); // and tell the script if it's running in the main intepreter or // a subinterpreter using the second argument, ie sys.argv[1] if (inMainInterpreter) - comm[1] = const_cast("ext"); + arguments.insert(1,QString("ext")); else - comm[1] = const_cast("sub"); - for (int j = 0; j < argsc; ++j) + arguments.insert(1,QString("sub")); + + //convert arguments (QListString) to char** for Python bridge + /* typically arguments == ['path/to/script.py','ext','--argument1','valueforarg1','--flag']*/ + char *comm[arguments.size()]; + for (int i = 0; i < arguments.size(); i++) { - comm[2+j] = arguments.at(j).toLocal8Bit().data() ; // TODO fix here: some copy is needed, otherwise all comm[>2] point to same (last) value for j. + comm[i] = arguments.at(i).mid(0).toLocal8Bit().data(); // TODO fix here: unexpected border effects. all comm[*] point to same (last) value for i... despite mid() that should create a copy. } - PySys_SetArgv(2+argsc, comm); + PySys_SetArgv(arguments.size(), comm); // call python script PyObject* m = PyImport_AddModule((char*)"__main__"); From 50fca9e4feffa2337a1c8de5f0e99f9bf23bb248 Mon Sep 17 00:00:00 2001 From: berteh Date: Wed, 5 Aug 2015 18:31:30 +0200 Subject: [PATCH 04/13] fix arguments passing from command line to python script --- scribus/plugins/scriptplugin/scriptercore.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scribus/plugins/scriptplugin/scriptercore.cpp b/scribus/plugins/scriptplugin/scriptercore.cpp index f6456c46dd..41b2949669 100644 --- a/scribus/plugins/scriptplugin/scriptercore.cpp +++ b/scribus/plugins/scriptplugin/scriptercore.cpp @@ -276,7 +276,8 @@ void ScripterCore::slotRunScriptFileArgs(QString fileName, QStringList arguments char *comm[arguments.size()]; for (int i = 0; i < arguments.size(); i++) { - comm[i] = arguments.at(i).mid(0).toLocal8Bit().data(); // TODO fix here: unexpected border effects. all comm[*] point to same (last) value for i... despite mid() that should create a copy. + comm[i] = new char[arguments.at(i).toLocal8Bit().size()+1]; //+1 to allow adding '\0'. may be useless, don't know how to check. + strcpy(comm[i],arguments.at(i).toLocal8Bit().data()+'\0'); } PySys_SetArgv(arguments.size(), comm); From b90f29c7bdb9908c4addb31b8486c8ec8197650d Mon Sep 17 00:00:00 2001 From: berteh Date: Thu, 6 Aug 2015 11:32:17 +0200 Subject: [PATCH 05/13] add dash to prefix for command line arguments to python script --- scribus/scribusapp.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scribus/scribusapp.cpp b/scribus/scribusapp.cpp index 77be0887a8..46b7508876 100644 --- a/scribus/scribusapp.cpp +++ b/scribus/scribusapp.cpp @@ -72,8 +72,8 @@ for which a new license (GPL+exception) is in place. #define ARG_UPGRADECHECK "--upgradecheck" #define ARG_TESTS "--tests" #define ARG_PYTHONSCRIPT "--python-script" -#define ARG_SCRIPTARG_PREFIX "--python-arg" // directly followed by -#define ARG_SCRIPTFLAG_PREFIX "--python-flag" // directly followed by +#define ARG_SCRIPTARG_PREFIX "--python-arg-" // directly followed by +#define ARG_SCRIPTFLAG_PREFIX "--python-flag-" // directly followed by #define ARG_VERSION_SHORT "-v" #define ARG_HELP_SHORT "-h" @@ -274,13 +274,13 @@ void ScribusQApp::parseCommandLine() ++i; } } else if (arg.startsWith(qtARG_SCRIPTARG_PREFIX)) { - QString arg_name = arg.mid(qtARG_SCRIPTARG_PREFIX.size()); + QString arg_name = arg.mid(qtARG_SCRIPTARG_PREFIX.size()-1); //-1 to get the dash from prefix QString arg_value = QFile::decodeName(args[++i].toLocal8Bit()); //std::cout << tr("got one script argument: %1 with value %2").arg(arg_name).arg(arg_value).toLocal8Bit().data() << std::endl; pythonScriptArgs.append(arg_name); pythonScriptArgs.append(arg_value); } else if (arg.startsWith(qtARG_SCRIPTFLAG_PREFIX)) { - QString arg_name = arg.mid(qtARG_SCRIPTFLAG_PREFIX.size()); + QString arg_name = arg.mid(qtARG_SCRIPTFLAG_PREFIX.size()-1); //-1 to get the dash from prefix //std::cout << tr("got one script flag: %1 ").arg(arg_name).toLocal8Bit().data() << std::endl; pythonScriptArgs.append(arg_name); } else { // (last) positional argument @@ -514,8 +514,8 @@ void ScribusQApp::showUsage() printArgLine(ts, ARG_UPGRADECHECK_SHORT, ARG_UPGRADECHECK, tr("Download a file from the Scribus website and show the latest available version") ); printArgLine(ts, ARG_VERSION_SHORT, ARG_VERSION, tr("Output version information and exit") ); printArgLine(ts, ARG_PYTHONSCRIPT_SHORT, qPrintable(QString("%1 <%2>").arg(ARG_PYTHONSCRIPT).arg(tr("filename"))), tr("Run filename in Python scripter") ); - ts << (QString(" %1<%2> <%3> ").arg(ARG_SCRIPTARG_PREFIX).arg(tr("argumentname")).arg(tr("value"))) << tr("Argument passed on to python script with its value, no effect without -py"); endl(ts); - ts << (QString(" %1<%2> ").arg(ARG_SCRIPTFLAG_PREFIX).arg(tr("flagname"))) << tr("Argument passed on to python script with no value, no effect without -py"); endl(ts); + ts << (QString(" %1<%2> <%3> ").arg(ARG_SCRIPTARG_PREFIX).arg(tr("argumentname")).arg(tr("value"))) << tr("Argument passed on to python script with its value, no effect without -py"); endl(ts); + ts << (QString(" %1<%2> ").arg(ARG_SCRIPTFLAG_PREFIX).arg(tr("flagname"))) << tr("Argument passed on to python script with no value, no effect without -py"); endl(ts); printArgLine(ts, ARG_NOGUI_SHORT, ARG_NOGUI, tr("Do not start GUI") ); #if defined(_WIN32) && !defined(_CONSOLE) From 9aa5b6951f2ef8fd187a2c9e99fe491dcb95fffb Mon Sep 17 00:00:00 2001 From: berteh Date: Thu, 6 Aug 2015 15:30:32 +0200 Subject: [PATCH 06/13] command line arguments for script unified into --python-arg- ; added command-line double dash for options end --- scribus/scribusapp.cpp | 67 +++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 33 deletions(-) diff --git a/scribus/scribusapp.cpp b/scribus/scribusapp.cpp index 46b7508876..6be0cbc3c3 100644 --- a/scribus/scribusapp.cpp +++ b/scribus/scribusapp.cpp @@ -72,8 +72,8 @@ for which a new license (GPL+exception) is in place. #define ARG_UPGRADECHECK "--upgradecheck" #define ARG_TESTS "--tests" #define ARG_PYTHONSCRIPT "--python-script" -#define ARG_SCRIPTARG_PREFIX "--python-arg-" // directly followed by -#define ARG_SCRIPTFLAG_PREFIX "--python-flag-" // directly followed by +#define ARG_SCRIPTARG_PREFIX "--python-arg-" // directly followed by +#define CMD_OPTIONS_END "--" // end of command line options #define ARG_VERSION_SHORT "-v" #define ARG_HELP_SHORT "-h" @@ -218,8 +218,8 @@ void ScribusQApp::parseCommandLine() useGUI = true; //We are going to run something other than command line help QString qtARG_SCRIPTARG_PREFIX = QString(ARG_SCRIPTARG_PREFIX); - QString qtARG_SCRIPTFLAG_PREFIX = QString(ARG_SCRIPTFLAG_PREFIX); - for(int i = 1; i < argsc; i++) { + int i = 1; + for( ; i < argsc; i++) { //handle all options (not positional parameters) arg = args[i]; if ((arg == ARG_LANG || arg == ARG_LANG_SHORT) && (++i < argsc)) { @@ -247,7 +247,7 @@ void ScribusQApp::parseCommandLine() if (!QFileInfo(prefsUserFile).exists()) { showHeader(); if (prefsUserFile.left(1) == "-" || prefsUserFile.left(2) == "--") { - std::cout << tr("Invalid argument: ").toLocal8Bit().data() << prefsUserFile.toLocal8Bit().data() << std::endl; + std::cout << tr("Invalid option: ").toLocal8Bit().data() << prefsUserFile.toLocal8Bit().data() << std::endl; } else { std::cout << tr("File %1 does not exist, aborting.").arg(prefsUserFile).toLocal8Bit().data() << std::endl; } @@ -264,7 +264,7 @@ void ScribusQApp::parseCommandLine() if (!QFileInfo(pythonScript).exists()) { showHeader(); if (pythonScript.left(1) == "-" || pythonScript.left(2) == "--") { - std::cout << tr("Invalid argument: ").toLocal8Bit().data() << pythonScript.toLocal8Bit().data() << std::endl; + std::cout << tr("Invalid option: ").toLocal8Bit().data() << pythonScript.toLocal8Bit().data() << std::endl; } else { std::cout << tr("File %1 does not exist, aborting.").arg(pythonScript).toLocal8Bit().data() << std::endl; } @@ -273,32 +273,32 @@ void ScribusQApp::parseCommandLine() } else { ++i; } + } else if (arg == CMD_OPTIONS_END) { //double dash, indicates end of command line options, see http://unix.stackexchange.com/questions/11376/what-does-double-dash-mean-also-known-as-bare-double-dash + i++; + break; } else if (arg.startsWith(qtARG_SCRIPTARG_PREFIX)) { - QString arg_name = arg.mid(qtARG_SCRIPTARG_PREFIX.size()-1); //-1 to get the dash from prefix - QString arg_value = QFile::decodeName(args[++i].toLocal8Bit()); - //std::cout << tr("got one script argument: %1 with value %2").arg(arg_name).arg(arg_value).toLocal8Bit().data() << std::endl; - pythonScriptArgs.append(arg_name); - pythonScriptArgs.append(arg_value); - } else if (arg.startsWith(qtARG_SCRIPTFLAG_PREFIX)) { - QString arg_name = arg.mid(qtARG_SCRIPTFLAG_PREFIX.size()-1); //-1 to get the dash from prefix - //std::cout << tr("got one script flag: %1 ").arg(arg_name).toLocal8Bit().data() << std::endl; - pythonScriptArgs.append(arg_name); - } else { // (last) positional argument - fileName = QFile::decodeName(args[i].toLocal8Bit()); - if (!QFileInfo(fileName).exists()) { - showHeader(); - if (fileName.left(1) == "-" || fileName.left(2) == "--") { - std::cout << tr("Invalid argument: %1").arg(fileName).toLocal8Bit().data() << std::endl; - } else { - std::cout << tr("File %1 does not exist, aborting.").arg(fileName).toLocal8Bit().data() << std::endl; - } - showUsage(); - std::exit(EXIT_FAILURE); + pythonScriptArgs.append( arg.mid(qtARG_SCRIPTARG_PREFIX.size()-1) ); //-1 to get the dash from prefix + if (!args[i+1].startsWith("-")) { + pythonScriptArgs.append( QFile::decodeName(args[++i].toLocal8Bit()) ); } - else - { - filesToLoad.append(fileName); + } else { //argument is not a known option, but either positional parameter or invalid. + break; + } + } + //remaining arguments, if any + for ( ; i").arg(ARG_PYTHONSCRIPT).arg(tr("filename"))), tr("Run filename in Python scripter") ); - ts << (QString(" %1<%2> <%3> ").arg(ARG_SCRIPTARG_PREFIX).arg(tr("argumentname")).arg(tr("value"))) << tr("Argument passed on to python script with its value, no effect without -py"); endl(ts); - ts << (QString(" %1<%2> ").arg(ARG_SCRIPTFLAG_PREFIX).arg(tr("flagname"))) << tr("Argument passed on to python script with no value, no effect without -py"); endl(ts); - printArgLine(ts, ARG_NOGUI_SHORT, ARG_NOGUI, tr("Do not start GUI") ); + ts << (QString(" %1<%2> [%3] ").arg(ARG_SCRIPTARG_PREFIX).arg(tr("argumentname")).arg(tr("value"))) << tr("Argument passed on to python script, with an optional value, no effect without -py"); endl(ts); + printArgLine(ts, ARG_NOGUI_SHORT, ARG_NOGUI, tr("Do not start GUI") ); + ts << (QString(" %1").arg(CMD_OPTIONS_END,-39)) << tr("Explicit end of command line options"); endl(ts); + #if defined(_WIN32) && !defined(_CONSOLE) printArgLine(ts, ARG_CONSOLE_SHORT, ARG_CONSOLE, tr("Display a console window") ); From 6752a35215de21ff5b0b1e3530245f55c43bb655 Mon Sep 17 00:00:00 2001 From: berteh Date: Wed, 19 Aug 2015 17:09:19 +0200 Subject: [PATCH 07/13] polishing code for command line arguments for python script: overloading --- scribus/plugins/scriptplugin/scriptercore.cpp | 6 ++-- scribus/plugins/scriptplugin/scriptercore.h | 2 +- scribus/scribusapp.cpp | 32 +++++++++---------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/scribus/plugins/scriptplugin/scriptercore.cpp b/scribus/plugins/scriptplugin/scriptercore.cpp index 41b2949669..f1f45943a5 100644 --- a/scribus/plugins/scriptplugin/scriptercore.cpp +++ b/scribus/plugins/scriptplugin/scriptercore.cpp @@ -230,10 +230,10 @@ void ScripterCore::RecentScript(QString fn) void ScripterCore::slotRunScriptFile(QString fileName, bool inMainInterpreter) { QStringList arguments = QStringList(); - slotRunScriptFileArgs(fileName, arguments, inMainInterpreter); + slotRunScriptFile(fileName, arguments, inMainInterpreter); } -void ScripterCore::slotRunScriptFileArgs(QString fileName, QStringList arguments, bool inMainInterpreter) +void ScripterCore::slotRunScriptFile(QString fileName, QStringList arguments, bool inMainInterpreter) /** run "filename" python script with the additional arguments provided in "arguments" */ { // Prevent two scripts to be run concurrently or face crash! @@ -376,7 +376,7 @@ void ScripterCore::slotRunPythonScript() { if (!ScQApp->pythonScript.isNull()) { - slotRunScriptFileArgs(ScQApp->pythonScript, ScQApp->pythonScriptArgs, true); + slotRunScriptFile(ScQApp->pythonScript, ScQApp->pythonScriptArgs, true); FinishScriptRun(); } } diff --git a/scribus/plugins/scriptplugin/scriptercore.h b/scribus/plugins/scriptplugin/scriptercore.h index b8e2edf98e..72e546141e 100644 --- a/scribus/plugins/scriptplugin/scriptercore.h +++ b/scribus/plugins/scriptplugin/scriptercore.h @@ -39,7 +39,7 @@ public slots: void StdScript(QString filebasename); void RecentScript(QString fn); void slotRunScriptFile(QString fileName, bool inMainInterpreter = false); - void slotRunScriptFileArgs(QString fileName, QStringList arguments, bool inMainInterpreter = false); + void slotRunScriptFile(QString fileName, QStringList arguments, bool inMainInterpreter = false); void slotRunPythonScript(); // needed for running python script from CLI void slotRunScript(const QString script); void slotInteractiveScript(bool); diff --git a/scribus/scribusapp.cpp b/scribus/scribusapp.cpp index 6be0cbc3c3..8870934138 100644 --- a/scribus/scribusapp.cpp +++ b/scribus/scribusapp.cpp @@ -218,11 +218,11 @@ void ScribusQApp::parseCommandLine() useGUI = true; //We are going to run something other than command line help QString qtARG_SCRIPTARG_PREFIX = QString(ARG_SCRIPTARG_PREFIX); - int i = 1; - for( ; i < argsc; i++) { //handle all options (not positional parameters) - arg = args[i]; + int argi = 1; + for( ; argi < argsc; argi++) { //handle options (not positional parameters) + arg = args[argi]; - if ((arg == ARG_LANG || arg == ARG_LANG_SHORT) && (++i < argsc)) { + if ((arg == ARG_LANG || arg == ARG_LANG_SHORT) && (++argi < argsc)) { continue; } else if ( arg == ARG_CONSOLE || arg == ARG_CONSOLE_SHORT ) { continue; @@ -238,12 +238,12 @@ void ScribusQApp::parseCommandLine() showFontInfo=true; } else if (arg == ARG_PROFILEINFO || arg == ARG_PROFILEINFO_SHORT) { showProfileInfo=true; - } else if ((arg == ARG_DISPLAY || arg==ARG_DISPLAY_SHORT || arg==ARG_DISPLAY_QT) && ++i < argsc) { + } else if ((arg == ARG_DISPLAY || arg==ARG_DISPLAY_SHORT || arg==ARG_DISPLAY_QT) && ++argi < argsc) { // allow setting of display, QT expect the option -display so we discard the // last argument. FIXME: Qt only understands -display not --display and -d , we need to work // around this. } else if (arg == ARG_PREFS || arg == ARG_PREFS_SHORT) { - prefsUserFile = QFile::decodeName(args[i + 1].toLocal8Bit()); + prefsUserFile = QFile::decodeName(args[argi + 1].toLocal8Bit()); if (!QFileInfo(prefsUserFile).exists()) { showHeader(); if (prefsUserFile.left(1) == "-" || prefsUserFile.left(2) == "--") { @@ -254,40 +254,40 @@ void ScribusQApp::parseCommandLine() showUsage(); std::exit(EXIT_FAILURE); } else { - ++i; + ++argi; } } else if (strncmp(arg.toLocal8Bit().data(),"-psn_",4) == 0) { // Andreas Vox: Qt/Mac has -psn_blah flags that must be accepted. } else if (arg == ARG_PYTHONSCRIPT || arg == ARG_PYTHONSCRIPT_SHORT) { - pythonScript = QFile::decodeName(args[i + 1].toLocal8Bit()); + pythonScript = QFile::decodeName(args[argi + 1].toLocal8Bit()); if (!QFileInfo(pythonScript).exists()) { showHeader(); if (pythonScript.left(1) == "-" || pythonScript.left(2) == "--") { - std::cout << tr("Invalid option: ").toLocal8Bit().data() << pythonScript.toLocal8Bit().data() << std::endl; + std::cout << tr("Invalid argument: ").toLocal8Bit().data() << pythonScript.toLocal8Bit().data() << std::endl; } else { std::cout << tr("File %1 does not exist, aborting.").arg(pythonScript).toLocal8Bit().data() << std::endl; } showUsage(); std::exit(EXIT_FAILURE); } else { - ++i; + ++argi; } } else if (arg == CMD_OPTIONS_END) { //double dash, indicates end of command line options, see http://unix.stackexchange.com/questions/11376/what-does-double-dash-mean-also-known-as-bare-double-dash - i++; + argi++; break; } else if (arg.startsWith(qtARG_SCRIPTARG_PREFIX)) { pythonScriptArgs.append( arg.mid(qtARG_SCRIPTARG_PREFIX.size()-1) ); //-1 to get the dash from prefix - if (!args[i+1].startsWith("-")) { - pythonScriptArgs.append( QFile::decodeName(args[++i].toLocal8Bit()) ); + if (!args[argi+1].startsWith("-")) { + pythonScriptArgs.append( QFile::decodeName(args[++argi].toLocal8Bit()) ); } } else { //argument is not a known option, but either positional parameter or invalid. break; } } - //remaining arguments, if any - for ( ; i Date: Thu, 3 Sep 2015 22:21:32 +0200 Subject: [PATCH 08/13] modified syntax to --python-arg [value], per Craig request --- scribus/plugins/scriptplugin/scriptercore.cpp | 3 +-- scribus/scribusapp.cpp | 21 ++++++++++--------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/scribus/plugins/scriptplugin/scriptercore.cpp b/scribus/plugins/scriptplugin/scriptercore.cpp index f1f45943a5..cf41110b9f 100644 --- a/scribus/plugins/scriptplugin/scriptercore.cpp +++ b/scribus/plugins/scriptplugin/scriptercore.cpp @@ -229,8 +229,7 @@ void ScripterCore::RecentScript(QString fn) void ScripterCore::slotRunScriptFile(QString fileName, bool inMainInterpreter) { - QStringList arguments = QStringList(); - slotRunScriptFile(fileName, arguments, inMainInterpreter); + slotRunScriptFile(fileName, QStringList(), inMainInterpreter); } void ScripterCore::slotRunScriptFile(QString fileName, QStringList arguments, bool inMainInterpreter) diff --git a/scribus/scribusapp.cpp b/scribus/scribusapp.cpp index 8870934138..951889c04a 100644 --- a/scribus/scribusapp.cpp +++ b/scribus/scribusapp.cpp @@ -72,8 +72,8 @@ for which a new license (GPL+exception) is in place. #define ARG_UPGRADECHECK "--upgradecheck" #define ARG_TESTS "--tests" #define ARG_PYTHONSCRIPT "--python-script" -#define ARG_SCRIPTARG_PREFIX "--python-arg-" // directly followed by -#define CMD_OPTIONS_END "--" // end of command line options +#define ARG_SCRIPTARG "--python-arg" +#define CMD_OPTIONS_END "--" #define ARG_VERSION_SHORT "-v" #define ARG_HELP_SHORT "-h" @@ -89,6 +89,7 @@ for which a new license (GPL+exception) is in place. #define ARG_UPGRADECHECK_SHORT "-u" #define ARG_TESTS_SHORT "-T" #define ARG_PYTHONSCRIPT_SHORT "-py" +#define ARG_SCRIPTARG_SHORT "-pa" // Qt wants -display not --display or -d #define ARG_DISPLAY_QT "-display" @@ -217,12 +218,17 @@ void ScribusQApp::parseCommandLine() std::exit(EXIT_SUCCESS); useGUI = true; //We are going to run something other than command line help - QString qtARG_SCRIPTARG_PREFIX = QString(ARG_SCRIPTARG_PREFIX); int argi = 1; for( ; argi < argsc; argi++) { //handle options (not positional parameters) arg = args[argi]; - if ((arg == ARG_LANG || arg == ARG_LANG_SHORT) && (++argi < argsc)) { + if (arg == ARG_SCRIPTARG || arg == ARG_SCRIPTARG_SHORT) { //needs to be first to give precedence to script argument name over scribus' + pythonScriptArgs.append(args[++argi]); // arg name + if (!args[argi+1].startsWith("-")) { // arg value + pythonScriptArgs.append( QFile::decodeName(args[++argi].toLocal8Bit()) ); + } + } + else if ((arg == ARG_LANG || arg == ARG_LANG_SHORT) && (++argi < argsc)) { continue; } else if ( arg == ARG_CONSOLE || arg == ARG_CONSOLE_SHORT ) { continue; @@ -276,11 +282,6 @@ void ScribusQApp::parseCommandLine() } else if (arg == CMD_OPTIONS_END) { //double dash, indicates end of command line options, see http://unix.stackexchange.com/questions/11376/what-does-double-dash-mean-also-known-as-bare-double-dash argi++; break; - } else if (arg.startsWith(qtARG_SCRIPTARG_PREFIX)) { - pythonScriptArgs.append( arg.mid(qtARG_SCRIPTARG_PREFIX.size()-1) ); //-1 to get the dash from prefix - if (!args[argi+1].startsWith("-")) { - pythonScriptArgs.append( QFile::decodeName(args[++argi].toLocal8Bit()) ); - } } else { //argument is not a known option, but either positional parameter or invalid. break; } @@ -514,7 +515,7 @@ void ScribusQApp::showUsage() printArgLine(ts, ARG_UPGRADECHECK_SHORT, ARG_UPGRADECHECK, tr("Download a file from the Scribus website and show the latest available version") ); printArgLine(ts, ARG_VERSION_SHORT, ARG_VERSION, tr("Output version information and exit") ); printArgLine(ts, ARG_PYTHONSCRIPT_SHORT, qPrintable(QString("%1 <%2>").arg(ARG_PYTHONSCRIPT).arg(tr("filename"))), tr("Run filename in Python scripter") ); - ts << (QString(" %1<%2> [%3] ").arg(ARG_SCRIPTARG_PREFIX).arg(tr("argumentname")).arg(tr("value"))) << tr("Argument passed on to python script, with an optional value, no effect without -py"); endl(ts); + printArgLine(ts, ARG_SCRIPTARG_SHORT, qPrintable(QString("%1 <%2> [%3]").arg(ARG_SCRIPTARG).arg(tr("name")).arg(tr("value"))), tr("Argument passed on to python script, with an optional value, no effect without -py") ); printArgLine(ts, ARG_NOGUI_SHORT, ARG_NOGUI, tr("Do not start GUI") ); ts << (QString(" %1").arg(CMD_OPTIONS_END,-39)) << tr("Explicit end of command line options"); endl(ts); From 697424b382e8b1eabe485de262573d28d383c46a Mon Sep 17 00:00:00 2001 From: berteh Date: Thu, 3 Sep 2015 22:35:22 +0200 Subject: [PATCH 09/13] revert 'option' to 'argument' in CLI feedback --- scribus/scribusapp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scribus/scribusapp.cpp b/scribus/scribusapp.cpp index 951889c04a..21d7eccd22 100644 --- a/scribus/scribusapp.cpp +++ b/scribus/scribusapp.cpp @@ -253,7 +253,7 @@ void ScribusQApp::parseCommandLine() if (!QFileInfo(prefsUserFile).exists()) { showHeader(); if (prefsUserFile.left(1) == "-" || prefsUserFile.left(2) == "--") { - std::cout << tr("Invalid option: ").toLocal8Bit().data() << prefsUserFile.toLocal8Bit().data() << std::endl; + std::cout << tr("Invalid argument: ").toLocal8Bit().data() << prefsUserFile.toLocal8Bit().data() << std::endl; } else { std::cout << tr("File %1 does not exist, aborting.").arg(prefsUserFile).toLocal8Bit().data() << std::endl; } From ee137989816946b4bb308ca9d68ed41a1f4941b4 Mon Sep 17 00:00:00 2001 From: berteh Date: Thu, 10 Sep 2015 12:51:59 +0200 Subject: [PATCH 10/13] merged arguments parsing to handle precedence of -pa over header arguments --- scribus/scribusapp.cpp | 95 ++++++++++++++++++++++-------------------- 1 file changed, 49 insertions(+), 46 deletions(-) diff --git a/scribus/scribusapp.cpp b/scribus/scribusapp.cpp index 21d7eccd22..b476b49f19 100644 --- a/scribus/scribusapp.cpp +++ b/scribus/scribusapp.cpp @@ -158,16 +158,27 @@ void ScribusQApp::parseCommandLine() showFontInfo=false; showProfileInfo=false; - //Parse for command line information options, and lang + //Parse for command line options // Qt5 port: do this in a Qt compatible manner QStringList args = arguments(); int argsc = args.count(); - for(int i = 1; i < argsc; i++) - { - arg = args[i]; - if ((arg == ARG_LANG || arg == ARG_LANG_SHORT) && (++i < argsc)) { - lang = args[i]; + //Init translations + initLang(); + + useGUI = true; + int argi = 1; + for( ; argi < argsc; argi++) { //handle options (not positional parameters) + arg = args[argi]; + + if (arg == ARG_SCRIPTARG || arg == ARG_SCRIPTARG_SHORT) { //needs to be first to give precedence to script argument name over scribus' options + pythonScriptArgs.append(args[++argi]); // arg name + if (!args[argi+1].startsWith("-")) { // arg value + pythonScriptArgs.append( QFile::decodeName(args[++argi].toLocal8Bit()) ); + } + } + else if ((arg == ARG_LANG || arg == ARG_LANG_SHORT) && (++argi < argsc)) { + lang = args[argi]; } else if (arg == ARG_VERSION || arg == ARG_VERSION_SHORT) { header=true; @@ -180,8 +191,8 @@ void ScribusQApp::parseCommandLine() else if (arg == ARG_TESTS || arg == ARG_TESTS_SHORT) { header=true; runtests=true; - testargsc = argc() - i; - testargsv = argv() + i; + testargsc = argc() - argi; + testargsv = argv() + argi; break; } #endif @@ -192,45 +203,10 @@ void ScribusQApp::parseCommandLine() header=true; runUpgradeCheck=true; } - } - //Init translations - initLang(); - //Show command line help - if (header) - showHeader(); - if (version) - showVersion(); - if (availlangs) - showAvailLangs(); - if (usage) - showUsage(); -#ifdef WITH_TESTS - if (runtests) - RunTests::runTests(testargsc, testargsv); -#endif - if (runUpgradeCheck) - { - UpgradeChecker uc; - uc.fetch(); - } - //Dont run the GUI init process called from main.cpp, and return - if (header) - std::exit(EXIT_SUCCESS); - useGUI = true; - //We are going to run something other than command line help - int argi = 1; - for( ; argi < argsc; argi++) { //handle options (not positional parameters) - arg = args[argi]; - - if (arg == ARG_SCRIPTARG || arg == ARG_SCRIPTARG_SHORT) { //needs to be first to give precedence to script argument name over scribus' - pythonScriptArgs.append(args[++argi]); // arg name - if (!args[argi+1].startsWith("-")) { // arg value - pythonScriptArgs.append( QFile::decodeName(args[++argi].toLocal8Bit()) ); - } - } else if ((arg == ARG_LANG || arg == ARG_LANG_SHORT) && (++argi < argsc)) { continue; - } else if ( arg == ARG_CONSOLE || arg == ARG_CONSOLE_SHORT ) { + } + else if ( arg == ARG_CONSOLE || arg == ARG_CONSOLE_SHORT ) { continue; } else if (arg == ARG_NOSPLASH || arg == ARG_NOSPLASH_SHORT) { showSplash = false; @@ -286,7 +262,7 @@ void ScribusQApp::parseCommandLine() break; } } - //remaining (positional) arguments, if any + // parse for remaining (positional) arguments, if any for ( ; argi Date: Thu, 10 Sep 2015 19:28:09 +0200 Subject: [PATCH 11/13] cleaner commandline error display function --- scribus/scribusapp.cpp | 45 +++++++++++++++++++++--------------------- scribus/scribusapp.h | 1 + 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/scribus/scribusapp.cpp b/scribus/scribusapp.cpp index b476b49f19..f75491827d 100644 --- a/scribus/scribusapp.cpp +++ b/scribus/scribusapp.cpp @@ -156,7 +156,8 @@ void ScribusQApp::parseCommandLine() int testargsc; #endif showFontInfo=false; - showProfileInfo=false; + showProfileInfo=false; + bool neverSplash = false; //Parse for command line options // Qt5 port: do this in a Qt compatible manner @@ -213,7 +214,7 @@ void ScribusQApp::parseCommandLine() } else if (arg == ARG_NEVERSPLASH || arg == ARG_NEVERSPLASH_SHORT) { showSplash = false; - neverSplash(true); + neverSplash = true; } else if (arg == ARG_NOGUI || arg == ARG_NOGUI_SHORT) { useGUI=false; } else if (arg == ARG_FONTINFO || arg == ARG_FONTINFO_SHORT) { @@ -227,13 +228,7 @@ void ScribusQApp::parseCommandLine() } else if (arg == ARG_PREFS || arg == ARG_PREFS_SHORT) { prefsUserFile = QFile::decodeName(args[argi + 1].toLocal8Bit()); if (!QFileInfo(prefsUserFile).exists()) { - showHeader(); - if (prefsUserFile.left(1) == "-" || prefsUserFile.left(2) == "--") { - std::cout << tr("Invalid argument: ").toLocal8Bit().data() << prefsUserFile.toLocal8Bit().data() << std::endl; - } else { - std::cout << tr("File %1 does not exist, aborting.").arg(prefsUserFile).toLocal8Bit().data() << std::endl; - } - showUsage(); + showError(prefsUserFile); std::exit(EXIT_FAILURE); } else { ++argi; @@ -244,13 +239,7 @@ void ScribusQApp::parseCommandLine() } else if (arg == ARG_PYTHONSCRIPT || arg == ARG_PYTHONSCRIPT_SHORT) { pythonScript = QFile::decodeName(args[argi + 1].toLocal8Bit()); if (!QFileInfo(pythonScript).exists()) { - showHeader(); - if (pythonScript.left(1) == "-" || pythonScript.left(2) == "--") { - std::cout << tr("Invalid argument: ").toLocal8Bit().data() << pythonScript.toLocal8Bit().data() << std::endl; - } else { - std::cout << tr("File %1 does not exist, aborting.").arg(pythonScript).toLocal8Bit().data() << std::endl; - } - showUsage(); + showError(pythonScript); std::exit(EXIT_FAILURE); } else { ++argi; @@ -266,13 +255,7 @@ void ScribusQApp::parseCommandLine() for ( ; argi Date: Thu, 10 Sep 2015 20:44:32 +0200 Subject: [PATCH 12/13] fix case typo --- scribus/scribusapp.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scribus/scribusapp.cpp b/scribus/scribusapp.cpp index f75491827d..6a43590b61 100644 --- a/scribus/scribusapp.cpp +++ b/scribus/scribusapp.cpp @@ -157,7 +157,7 @@ void ScribusQApp::parseCommandLine() #endif showFontInfo=false; showProfileInfo=false; - bool neverSplash = false; + bool neversplash = false; //Parse for command line options // Qt5 port: do this in a Qt compatible manner @@ -214,7 +214,7 @@ void ScribusQApp::parseCommandLine() } else if (arg == ARG_NEVERSPLASH || arg == ARG_NEVERSPLASH_SHORT) { showSplash = false; - neverSplash = true; + neversplash = true; } else if (arg == ARG_NOGUI || arg == ARG_NOGUI_SHORT) { useGUI=false; } else if (arg == ARG_FONTINFO || arg == ARG_FONTINFO_SHORT) { @@ -255,7 +255,7 @@ void ScribusQApp::parseCommandLine() for ( ; argi Date: Mon, 14 Sep 2015 10:35:18 +0200 Subject: [PATCH 13/13] detect missing argument --- scribus/scribusapp.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/scribus/scribusapp.cpp b/scribus/scribusapp.cpp index 6a43590b61..a1f4c52c2c 100644 --- a/scribus/scribusapp.cpp +++ b/scribus/scribusapp.cpp @@ -173,9 +173,15 @@ void ScribusQApp::parseCommandLine() arg = args[argi]; if (arg == ARG_SCRIPTARG || arg == ARG_SCRIPTARG_SHORT) { //needs to be first to give precedence to script argument name over scribus' options - pythonScriptArgs.append(args[++argi]); // arg name - if (!args[argi+1].startsWith("-")) { // arg value - pythonScriptArgs.append( QFile::decodeName(args[++argi].toLocal8Bit()) ); + if (++argi [value]").arg(arg).toLocal8Bit().data() << std::endl; + showUsage(); + std::exit(EXIT_FAILURE); + } + if (++argi").arg(ARG_PYTHONSCRIPT).arg(tr("filename"))), tr("Run filename in Python scripter") ); - printArgLine(ts, ARG_SCRIPTARG_SHORT, qPrintable(QString("%1 <%2> [%3]").arg(ARG_SCRIPTARG).arg(tr("name")).arg(tr("value"))), tr("Argument passed on to python script, with an optional value, no effect without -py") ); + printArgLine(ts, ARG_SCRIPTARG_SHORT, qPrintable(QString("%1 <%2> [%3]").arg(ARG_SCRIPTARG).arg(tr("argument")).arg(tr("value"))), tr("Argument passed on to python script, with an optional value, no effect without -py") ); printArgLine(ts, ARG_NOGUI_SHORT, ARG_NOGUI, tr("Do not start GUI") ); ts << (QString(" %1").arg(CMD_OPTIONS_END,-39)) << tr("Explicit end of command line options"); endl(ts);