1// Copyright (C) 2016 Sune Vuorela <sune@kde.org>
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#include <QCoreApplication>
5#include <QCommandLineParser>
6#include <QStandardPaths>
7#include <QHash>
8#include <QLibraryInfo>
9
10#include <algorithm>
11
12#include <stdio.h>
13
14#if QT_CONFIG(settings)
15# include <private/qlibraryinfo_p.h>
16# include <qmakelibraryinfo.h>
17# include <propertyprinter.h>
18# include <property.h>
19#endif
20
21QT_USE_NAMESPACE
22
23/**
24 * Prints the string on stdout and appends a newline
25 * \param string printable string
26 */
27static void message(const QString &string)
28{
29 fprintf(stdout, format: "%s\n", qPrintable(string));
30}
31
32/**
33 * Writes error message and exits 1
34 * \param message to write
35 */
36Q_NORETURN static void error(const QString &message)
37{
38 fprintf(stderr, format: "%s\n", qPrintable(message));
39 ::exit(EXIT_FAILURE);
40}
41
42class StringEnum {
43public:
44 const char *stringvalue;
45 QStandardPaths::StandardLocation enumvalue;
46 bool hasappname;
47
48 /**
49 * Replace application name by generic name if requested
50 */
51 QString mapName(const QString &s) const
52 {
53 return hasappname ? QString(s).replace(before: "qtpaths", after: "<APPNAME>") : s;
54 }
55};
56
57static const StringEnum lookupTableData[] = {
58 { .stringvalue: "AppConfigLocation", .enumvalue: QStandardPaths::AppConfigLocation, .hasappname: true },
59 { .stringvalue: "AppDataLocation", .enumvalue: QStandardPaths::AppDataLocation, .hasappname: true },
60 { .stringvalue: "AppLocalDataLocation", .enumvalue: QStandardPaths::AppLocalDataLocation, .hasappname: true },
61 { .stringvalue: "ApplicationsLocation", .enumvalue: QStandardPaths::ApplicationsLocation, .hasappname: false },
62 { .stringvalue: "CacheLocation", .enumvalue: QStandardPaths::CacheLocation, .hasappname: true },
63 { .stringvalue: "ConfigLocation", .enumvalue: QStandardPaths::ConfigLocation, .hasappname: false },
64 { .stringvalue: "DesktopLocation", .enumvalue: QStandardPaths::DesktopLocation, .hasappname: false },
65 { .stringvalue: "DocumentsLocation", .enumvalue: QStandardPaths::DocumentsLocation, .hasappname: false },
66 { .stringvalue: "DownloadLocation", .enumvalue: QStandardPaths::DownloadLocation, .hasappname: false },
67 { .stringvalue: "FontsLocation", .enumvalue: QStandardPaths::FontsLocation, .hasappname: false },
68 { .stringvalue: "GenericCacheLocation", .enumvalue: QStandardPaths::GenericCacheLocation, .hasappname: false },
69 { .stringvalue: "GenericConfigLocation", .enumvalue: QStandardPaths::GenericConfigLocation, .hasappname: false },
70 { .stringvalue: "GenericDataLocation", .enumvalue: QStandardPaths::GenericDataLocation, .hasappname: false },
71 { .stringvalue: "GenericStateLocation", .enumvalue: QStandardPaths::GenericStateLocation, .hasappname: false },
72 { .stringvalue: "HomeLocation", .enumvalue: QStandardPaths::HomeLocation, .hasappname: false },
73 { .stringvalue: "MoviesLocation", .enumvalue: QStandardPaths::MoviesLocation, .hasappname: false },
74 { .stringvalue: "MusicLocation", .enumvalue: QStandardPaths::MusicLocation, .hasappname: false },
75 { .stringvalue: "PicturesLocation", .enumvalue: QStandardPaths::PicturesLocation, .hasappname: false },
76 { .stringvalue: "PublicShareLocation", .enumvalue: QStandardPaths::PublicShareLocation, .hasappname: false },
77 { .stringvalue: "RuntimeLocation", .enumvalue: QStandardPaths::RuntimeLocation, .hasappname: false },
78 { .stringvalue: "StateLocation", .enumvalue: QStandardPaths::StateLocation, .hasappname: true },
79 { .stringvalue: "TemplatesLocation", .enumvalue: QStandardPaths::TemplatesLocation, .hasappname: false },
80 { .stringvalue: "TempLocation", .enumvalue: QStandardPaths::TempLocation, .hasappname: false }
81};
82
83/**
84 * \return available types as a QStringList.
85 */
86static QStringList types()
87{
88 QStringList typelist;
89 for (const StringEnum &se : lookupTableData)
90 typelist << QString::fromLatin1(ba: se.stringvalue);
91 std::sort(first: typelist.begin(), last: typelist.end());
92 return typelist;
93}
94
95/**
96 * Tries to parse the location string into a reference to a StringEnum entry or alternatively
97 * calls \ref error with a error message
98 */
99static const StringEnum &parseLocationOrError(const QString &locationString)
100{
101 for (const StringEnum &se : lookupTableData)
102 if (locationString == QLatin1StringView(se.stringvalue))
103 return se;
104
105 QString message = QStringLiteral("Unknown location: %1");
106 error(message: message.arg(a: locationString));
107}
108
109/**
110 * searches for exactly one remaining argument and returns it.
111 * If not found, \ref error is called with a error message.
112 * \param parser to ask for remaining arguments
113 * \return one extra argument
114 */
115static QString searchStringOrError(QCommandLineParser *parser)
116{
117 int positionalArgumentCount = parser->positionalArguments().size();
118 if (positionalArgumentCount != 1)
119 error(QStringLiteral("Exactly one argument needed as searchitem"));
120 return parser->positionalArguments().constFirst();
121}
122
123int main(int argc, char **argv)
124{
125 QString qtconfManualPath;
126 QCoreApplication app(argc, argv);
127 app.setApplicationVersion(QTPATHS_VERSION_STR);
128
129#ifdef Q_OS_WIN
130 const QLatin1Char pathsep(';');
131#else
132 const QLatin1Char pathsep(':');
133#endif
134
135 QCommandLineParser parser;
136 parser.setApplicationDescription(QStringLiteral("Command line client to QStandardPaths and QLibraryInfo"));
137 parser.addPositionalArgument(QStringLiteral("[name]"), QStringLiteral("Name of file or directory"));
138 parser.addPositionalArgument(QStringLiteral("[properties]"), QStringLiteral("List of the Qt properties to query by the --qt-query argument."));
139 parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
140 parser.addHelpOption();
141 parser.addVersionOption();
142
143 //setting up options
144 QCommandLineOption types(QStringLiteral("types"), QStringLiteral("Available location types."));
145 parser.addOption(commandLineOption: types);
146
147 QCommandLineOption paths(QStringLiteral("paths"), QStringLiteral("Find paths for <type>."), QStringLiteral("type"));
148 parser.addOption(commandLineOption: paths);
149
150 QCommandLineOption writablePath(QStringLiteral("writable-path"),
151 QStringLiteral("Find writable path for <type>."), QStringLiteral("type"));
152 parser.addOption(commandLineOption: writablePath);
153
154 QCommandLineOption locateDir(QStringList() << QStringLiteral("locate-dir") << QStringLiteral("locate-directory"),
155 QStringLiteral("Locate directory [name] in <type>."), QStringLiteral("type"));
156 parser.addOption(commandLineOption: locateDir);
157
158 QCommandLineOption locateDirs(QStringList() << QStringLiteral("locate-dirs") << QStringLiteral("locate-directories"),
159 QStringLiteral("Locate directories [name] in all paths for <type>."), QStringLiteral("type"));
160 parser.addOption(commandLineOption: locateDirs);
161
162 QCommandLineOption locateFile(QStringLiteral("locate-file"),
163 QStringLiteral("Locate file [name] for <type>."), QStringLiteral("type"));
164 parser.addOption(commandLineOption: locateFile);
165
166 QCommandLineOption locateFiles(QStringLiteral("locate-files"),
167 QStringLiteral("Locate files [name] in all paths for <type>."), QStringLiteral("type"));
168 parser.addOption(commandLineOption: locateFiles);
169
170 QCommandLineOption findExe(QStringList() << QStringLiteral("find-exe") << QStringLiteral("find-executable"),
171 QStringLiteral("Find executable with [name]."));
172 parser.addOption(commandLineOption: findExe);
173
174 QCommandLineOption display(QStringList() << QStringLiteral("display"),
175 QStringLiteral("Prints user readable name for <type>."), QStringLiteral("type"));
176 parser.addOption(commandLineOption: display);
177
178 QCommandLineOption testmode(QStringList() << QStringLiteral("testmode") << QStringLiteral("test-mode"),
179 QStringLiteral("Use paths specific for unit testing."));
180 parser.addOption(commandLineOption: testmode);
181
182 QCommandLineOption qtversion(QStringLiteral("qt-version"), QStringLiteral("Qt version."));
183 qtversion.setFlags(QCommandLineOption::HiddenFromHelp);
184 parser.addOption(commandLineOption: qtversion);
185
186 QCommandLineOption installprefix(QStringLiteral("install-prefix"), QStringLiteral("Installation prefix for Qt."));
187 installprefix.setFlags(QCommandLineOption::HiddenFromHelp);
188 parser.addOption(commandLineOption: installprefix);
189
190 QCommandLineOption bindir(QStringList() << QStringLiteral("binaries-dir") << QStringLiteral("binaries-directory"),
191 QStringLiteral("Location of Qt executables."));
192 bindir.setFlags(QCommandLineOption::HiddenFromHelp);
193 parser.addOption(commandLineOption: bindir);
194
195 QCommandLineOption plugindir(QStringList() << QStringLiteral("plugin-dir") << QStringLiteral("plugin-directory"),
196 QStringLiteral("Location of Qt plugins."));
197 plugindir.setFlags(QCommandLineOption::HiddenFromHelp);
198 parser.addOption(commandLineOption: plugindir);
199
200 QCommandLineOption query(
201 QStringList() << QStringLiteral("qt-query") << QStringLiteral("query"),
202 QStringLiteral("List of Qt properties. Can be used standalone or with the "
203 "--query-format and --qtconf options."));
204 parser.addOption(commandLineOption: query);
205
206 QCommandLineOption queryformat(QStringLiteral("query-format"),
207 QStringLiteral("Output format for --qt-query.\nSupported formats: qmake (default), json"),
208 QStringLiteral("format"));
209 queryformat.setDefaultValue("qmake");
210 parser.addOption(commandLineOption: queryformat);
211
212 QCommandLineOption qtconf(QStringLiteral("qtconf"),
213 QStringLiteral("Path to qt.conf file that will be used to override the queried Qt properties."),
214 QStringLiteral("path"));
215 parser.addOption(commandLineOption: qtconf);
216
217 parser.process(app);
218
219 QStandardPaths::setTestModeEnabled(parser.isSet(option: testmode));
220
221#if QT_CONFIG(settings)
222 if (parser.isSet(option: qtconf)) {
223 qtconfManualPath = parser.value(option: qtconf);
224 QLibraryInfoPrivate::setQtconfManualPath(&qtconfManualPath);
225 }
226#endif
227
228 QStringList results;
229 if (parser.isSet(option: qtversion)) {
230 QString qtversionstring = QString::fromLatin1(QT_VERSION_STR);
231 results << qtversionstring;
232 }
233
234 if (parser.isSet(option: installprefix)) {
235 QString path = QLibraryInfo::path(p: QLibraryInfo::PrefixPath);
236 results << path;
237 }
238
239 if (parser.isSet(option: bindir)) {
240 QString path = QLibraryInfo::path(p: QLibraryInfo::BinariesPath);
241 results << path;
242 }
243
244 if (parser.isSet(option: plugindir)) {
245 QString path = QLibraryInfo::path(p: QLibraryInfo::PluginsPath);
246 results << path;
247 }
248
249 if (parser.isSet(option: types)) {
250 QStringList typesList = ::types();
251 results << typesList.join(sep: '\n');
252 }
253
254 QT_WARNING_PUSH
255#if defined(Q_CC_GNU_ONLY) && Q_CC_GNU >= 1300 && Q_CC_GNU < 1500
256 QT_WARNING_DISABLE_GCC("-Wdangling-reference")
257#endif
258 if (parser.isSet(option: display)) {
259 const StringEnum &location = parseLocationOrError(locationString: parser.value(option: display));
260 QString text = QStandardPaths::displayName(type: location.enumvalue);
261 results << location.mapName(s: text);
262 }
263
264 if (parser.isSet(option: paths)) {
265 const StringEnum &location = parseLocationOrError(locationString: parser.value(option: paths));
266 QStringList paths = QStandardPaths::standardLocations(type: location.enumvalue);
267 results << location.mapName(s: paths.join(sep: pathsep));
268 }
269
270 if (parser.isSet(option: writablePath)) {
271 const StringEnum &location = parseLocationOrError(locationString: parser.value(option: writablePath));
272 QString path = QStandardPaths::writableLocation(type: location.enumvalue);
273 results << location.mapName(s: path);
274 }
275
276 if (parser.isSet(option: findExe)) {
277 QString searchitem = searchStringOrError(parser: &parser);
278 QString path = QStandardPaths::findExecutable(executableName: searchitem);
279 results << path;
280 }
281
282 if (parser.isSet(option: locateDir)) {
283 const StringEnum &location = parseLocationOrError(locationString: parser.value(option: locateDir));
284 QString searchitem = searchStringOrError(parser: &parser);
285 QString path = QStandardPaths::locate(type: location.enumvalue, fileName: searchitem, options: QStandardPaths::LocateDirectory);
286 results << location.mapName(s: path);
287 }
288
289 if (parser.isSet(option: locateFile)) {
290 const StringEnum &location = parseLocationOrError(locationString: parser.value(option: locateFile));
291 QString searchitem = searchStringOrError(parser: &parser);
292 QString path = QStandardPaths::locate(type: location.enumvalue, fileName: searchitem, options: QStandardPaths::LocateFile);
293 results << location.mapName(s: path);
294 }
295
296 if (parser.isSet(option: locateDirs)) {
297 const StringEnum &location = parseLocationOrError(locationString: parser.value(option: locateDirs));
298 QString searchitem = searchStringOrError(parser: &parser);
299 QStringList paths = QStandardPaths::locateAll(type: location.enumvalue, fileName: searchitem, options: QStandardPaths::LocateDirectory);
300 results << location.mapName(s: paths.join(sep: pathsep));
301 }
302
303 if (parser.isSet(option: locateFiles)) {
304 const StringEnum &location = parseLocationOrError(locationString: parser.value(option: locateFiles));
305 QString searchitem = searchStringOrError(parser: &parser);
306 QStringList paths = QStandardPaths::locateAll(type: location.enumvalue, fileName: searchitem, options: QStandardPaths::LocateFile);
307 results << location.mapName(s: paths.join(sep: pathsep));
308 }
309 QT_WARNING_POP
310
311#if !QT_CONFIG(settings)
312 if (parser.isSet(query) || parser.isSet(qtconf) || parser.isSet(queryformat)) {
313 error(QStringLiteral("--qt-query, --qtconf and --query-format options are not supported. The 'settings' feature is missing."));
314 }
315#else
316 if (parser.isSet(option: query)) {
317 if (!results.isEmpty()) {
318 QString errorMessage = QStringLiteral("Several options given, only one is supported at a time.");
319 error(message: errorMessage);
320 }
321
322 PropertyPrinter printer;
323 if (parser.isSet(option: queryformat)) {
324 QString formatValue = parser.value(option: queryformat);
325 if (formatValue == "json") {
326 printer = jsonPropertyPrinter;
327 } else if (formatValue != "qmake") {
328 QString errorMessage = QStringLiteral("Invalid output format %1. Supported formats: qmake, json").arg(a: formatValue);
329 error(message: errorMessage);
330 }
331 }
332
333 QStringList optionProperties = parser.positionalArguments();
334 QMakeProperty prop;
335 if (printer) {
336 return prop.queryProperty(optionProperties, printer);
337 }
338 return prop.queryProperty(optionProperties);
339 } else if (parser.isSet(option: queryformat)) {
340 error(QStringLiteral("--query-format is set, but --qt-query is not requested."));
341 }
342#endif
343
344 if (results.isEmpty()) {
345 parser.showHelp();
346 } else if (results.size() == 1) {
347 const QString &item = results.constFirst();
348 message(string: item);
349 if (item.isEmpty())
350 return EXIT_FAILURE;
351 } else {
352 QString errorMessage = QStringLiteral("Several options given, only one is supported at a time.");
353 error(message: errorMessage);
354 }
355 return EXIT_SUCCESS;
356}
357

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtbase/src/tools/qtpaths/qtpaths.cpp