How to use QCommandLineParser for arguments with multiple params? - c++

I wonder, how can I use multiple- or sub-arguments with QCommandLineParser?
For example:
/home/my_app --my_option_with_two_params first_param second_param --my-option-with-one-param param?

Try this which has the analogy of -I /my/include/path1 -I /my/include/path2:
--my_option_with_two_params first_param --my_option_with_two_params second_param
... and then you can use this method to have access to the values:
QStringList QCommandLineParser::values(const QString & optionName) const
Returns a list of option values found for the given option name optionName, or an empty list if not found.
The name provided can be any long or short name of any option that was added with addOption().
Here you can find a simple test case that works:
main.cpp
#include <QCoreApplication>
#include <QCommandLineParser>
#include <QCommandLineOption>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
QCoreApplication::setApplicationName("multiple-values-program");
QCoreApplication::setApplicationVersion("1.0");
QCommandLineParser parser;
parser.setApplicationDescription("Test helper");
parser.addHelpOption();
parser.addVersionOption();
QCommandLineOption targetDirectoryOption(QStringList() << "t" << "target-directory",
QCoreApplication::translate("main", "Copy all source files into <directory>."),
QCoreApplication::translate("main", "directory"));
parser.addOption(targetDirectoryOption);
parser.process(app);
qDebug() << parser.values(targetDirectoryOption);
return 0;
}
main.pro
TEMPLATE = app
TARGET = main
QT = core
SOURCES += main.cpp
Build
qmake && make
Output when --help is used
Usage: main [options]
Test helper
Options:
-h, --help Displays this help.
-v, --version Displays version information.
-t, --target-directory <directory> Copy all source files into <directory>.
Run and Output
./main -t foo -t bar -> ("foo", "bar")
./main -t foo bar -> ("foo")

Related

Writing commands on linux terminal using Qt

I'm trying to get Qt creator to print a user input by using a push button on an UI into the terminal. As of now, the code is executable on the terminal via human input. Here is the code:
void MainWindow::on_pushButton_clicked()
{
QProcess::execute("/catkin_ws/devel/lib/submodbus");
system("cd catkin_ws/devel/lib/submodbus");
system("./submodbus_node");
}
Current output when using the code
Output via human input
The versions i'm running on are:
-Ubuntu 16.04
-QT Creator 3.5.1
system can't change the current directory globally. but could use like this:
system("cd /catkin_ws/devel/lib/submodbus && ./submodbus_node");
or using QProcess::setProgram with QProcess::setWorkingDirectory
QProcess p;
p.setProgram("submodbus_node");
//p.setArguments(QStringList()<<args); // if you need
p.setWorkingDirectory("/catkin_ws/devel/lib/submodbus");
p.start();
or QDir::setCurrent
QDir::setCurrent("/catkin_ws/devel/lib/submodbus");
QProcess::startDetached("submodbus_node");
Test demo, create three files in the parent directory:
#include <QApplication>
#include <QProcess>
#include <QDir>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
system("cd ../ && touch test1.txt");
QProcess p;
p.setProgram("touch");
p.setArguments(QStringList()<<"test2.txt");
p.setWorkingDirectory("../");
p.start();
QDir::setCurrent("../");
QProcess::startDetached("touch test3.txt");
return a.exec();
}

Non-expected result of QDir::homePath() for a program run by startproc

I have the following small program:
#include <unistd.h>
#include <pwd.h>
#include <QCoreApplication>
#include <QDir>
const char * homeDir()
{
return getpwuid(geteuid())->pw_dir;
}
int main(int argc, char *argv[])
{
printf("Qt homedir: %s\n", qPrintable(QDir::homePath()));
printf("Native homedir: %s\n", homeDir());
QCoreApplication a(argc, argv);
return a.exec();
}
Now:
when run directly by a "normal" user, ./program, the output is:
Qt homedir: /home/user
Native homedir: /home/usr
which is ok
when run directly by root, ./program, the output is:
Qt homedir: /root
Native homedir: /root
which is ok
when run by root as a different user by the means of sudo, e.g. sudo -u user ./program, the output is:
Qt homedir: /home/user
Native homedir: /home/user
which is ok
when run by root as a different user by the means of startproc, e.g. startproc -u user /full/path/to/program, the output is:
Qt homedir: /root
Native homedir: /home/user
which is NOT ok, or not expected (at least for me)
And my question is: why does the last run give a different result than the others? Is it a bug in Qt (doesn't take into account the fact, that the effective user is different than the real user, or something different), or am I missing some background info (e.g. the mechanism of how startproc works)?
The version of Qt in question is 5.6.1.
Qt's QFileSystemEngine uses the contents of the HOME environment variable on Unix - see its implementation. Yet startproc -u does not set HOME: that's why it fails.
The getpwuid call can be potentially very expensive and can block, i.e. by getting information from an LDAP or AD server, etc., and it's best if you take care of it yourself. Furthermore, it's not thread-safe, and you should use getpwuid_r instead.
An implementation might look as follows:
static QString getHomeDir() {
auto const N = sysconf(_SC_GETPW_R_SIZE_MAX);
auto *buffer = std::make_unique<char[]>(N);
passwd pwd;
passwd *result;
getpwuid_r(geteuid(), &pwd, buffer.get(), N, &result);
if (result) {
auto *dir = result->pw_dir;
auto const decoded = QFile::decodeName(dir);
return QDir::cleanPath(decoded);
}
return {};
}
enum class HomeDir { Default, Init };
QString homeDir(HomeDir option = HomeDir::Default) {
// needs a C++11 compiler for thread-safe initialization
static QFuture<QString> home = QtConcurrent::run(getHomeDir);
return (option == HomeDir::Init) ? QString() : home;
};
int main(int argc, char **argv) {
QCoreApplication app(argc, argv);
homeDir(HomeDir::Init);
// do other time-consuming initializations here
QString () << homeDir();
}

Qt - Use builtin translations

I'm using Qt and want to translate the texts "natively" shown by Qt widgets. By "texts natively shown" I'm for instance referring to the ones shown in context menus for text edits (copy, paste, ...).
Here is what I've already done:
#include <QApplication>
#include <QDebug>
#include <QTranslator>
#include <QFile>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QTranslator translator;
if(translator.load("qt_fr.qm", QApplication::applicationDirPath())) {
qDebug() << a.installTranslator(&translator);
}
qDebug() << QFile::exists(QApplication::applicationDirPath() + "/qt_fr.qm"); // just to debug file existence
// MainWindow w; // not related to my question
// w.showMaximized(); // neither is this
return a.exec();
}
The qt_fr.qm file is located at path_to_qt/Qt5.6.2/5.6/mingw49_32/translations for Qt5.6.2 and MinGW users. I copy the said file to the running software directory but the translator always fails to load it. But when I use my own qm file (built from a .ts file using the Qt lupdate and lrelease tools), the qm file is properly loaded and installed.
Is there something I'm missing or doing wrong?
I think the problem may be that you haven't copied the complete message catalog. The following works for me on a Debian system, using the QM files in their standard locations:
#include <QApplication>
#include <QDebug>
#include <QLocale>
#include <QTranslator>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QTranslator translator;
const QString dir = "/usr/share/qt5/translations";
if (translator.load("qt_fr", dir)) {
qDebug() << "first load succeeded:"
<< "'Open' =>" << translator.translate("QShortcut", "Open");
}
if (translator.load(QLocale::French, "qt", "_", dir)) {
qDebug() << "second load succeeded:"
<< "'Open' =>" << translator.translate("QShortcut", "Open");
}
}
Output is
first load succeeded: 'Open' => "Ouvrir"
second load succeeded: 'Open' => "Ouvrir"
(I removed the .qm from the filename, as Qt will try that first, and I've also shown how to compose the filename from a specific locale object).
If we inspect the qt_fr.qm file using lconvert -of ts /usr/share/qt5/translations/qt_fr.qm, we can see it's just a very small file that incorporates other files by reference:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="fr_FR">
<dependencies>
<dependency catalog="qtbase_fr"/>
<dependency catalog="qtscript_fr"/>
<dependency catalog="qtquick1_fr"/>
<dependency catalog="qtmultimedia_fr"/>
<dependency catalog="qtxmlpatterns_fr"/>
</dependencies>
</TS>
I think that the most likely cause of your symptoms is that one or more of the dependency files could not be loaded. You should ensure that all of those files area available in the same location that you copied qt_fr.qm to - or, if you only need the "base" translations, just copy qtbase_fr.qm, and change your translator.load() call appropriately.

run rsync through execvp: StrictHostKeyChecking=no: unknown option

I am trying to run rsync through execvp with StrictHostKeyChecking option.
This is my code:
#include <unistd.h>
int main() {
char *argv[] = {"rsync",
"remote_user#1.2.4.5:/tmp",
"/home/tmp/",
"-e 'ssh -o StrictHostKeyChecking=no'",
0};
execvp("rsync", argv);
}
I am getting this error:
rsync: -e '-o StrictHostKeyChecking=no': unknown option
rsync error: syntax or usage error (code 1) at main.c(1422) [client=3.0.6]
I have tried another way:
#include <unistd.h>
int main() {
char *argv[] = {"rsync",
"remote_user#1.2.4.5:/tmp",
"/home/tmp/",
"-e",
"'ssh -o StrictHostKeyChecking=no'",
0};
execvp("rsync", argv);
}
But now it is failing with error:
rsync: Failed to exec ssh -o StrictHostKeyChecking=no: No such file or directory (2) rsync error: error in IPC code (code 14) at pipe.c(84) [sender=3.0.6]
Why it don't understand StrictHostKeyChecking option?
rsync expects to receive the options first, followed by the hosts. You're doing it backwards: first you need to specify -e and -o.
You also shouldn't be single-quoting the -o option: that is needed when invoking it from bash, to prevent bash from interpreting the arguments and splitting them into separate argv[] entries. Think about it: when bash sees '-o StrictHostKeyChecking=no', it passes -o StrictHostKeyChecking=no as a single argv[] entry, without the single quotes (because the single quotes is your way to tell the shell that you don't want argument splitting).
Last, but not least, you should check that execvp(3) didn't fail.
So, this is what you need:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
char *argv[] = {
"rsync",
"-e",
"ssh -o StrictHostKeyChecking=no",
"remote_user#1.2.4.5:/tmp",
"/home/tmp/",
NULL
};
if (execvp("rsync", argv) < 0) {
perror("rsync(1) error");
exit(EXIT_FAILURE);
}
return 0;
}

Qt Lang environment?

I Have got an issue concerning Qt Locale environment when I execute the following code
QApplication(argc,argv) ;
float f = 42.5f
std::cout << std::to_string(f) ; // prints 42,5
Even if my computer got its locale to french I'd like my program to be compiled with us standard printing format (i.e. 42.5 ). Is there a way to do that with a compiler option ?
This works fine for me:
main.cpp
#include <QString>
#include <QDebug>
#include <QCoreApplication>
#include <QLocale>
int main(int argc, char **argv)
{
QCoreApplication coreApplication(argc, argv);
float f = 42.5f;
qDebug() << QString::number(f, 'f', 1);
QLocale locale;
qDebug() << locale.toString(f, 'f', 1);
return coreApplication.exec();
}
main.pro
TEMPLATE = app
TARGET = main
QT = core
SOURCES += main.cpp
Build and Run
qmake && make && ./main
Output
"42.5"
"42.5"
This may be interesting for you:
QString QString::number(double n, char format = 'g', int precision = 6) [static]
Returns a string equivalent of the number n, formatted according to the specified format and precision. See Argument Formats for details.
Unlike QLocale::toString(), this function does not honor the user's locale settings.