1/****************************************************************************
2 * *
3 ** Copyright (C) 2016 Sune Vuorela <sune@kde.org>
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the tools applications of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:BSD$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** BSD License Usage
18 ** Alternatively, you may use this file under the terms of the BSD license
19 ** as follows:
20 **
21 ** "Redistribution and use in source and binary forms, with or without
22 ** modification, are permitted provided that the following conditions are
23 ** met:
24 ** * Redistributions of source code must retain the above copyright
25 ** notice, this list of conditions and the following disclaimer.
26 ** * Redistributions in binary form must reproduce the above copyright
27 ** notice, this list of conditions and the following disclaimer in
28 ** the documentation and/or other materials provided with the
29 ** distribution.
30 ** * Neither the name of The Qt Company Ltd nor the names of its
31 ** contributors may be used to endorse or promote products derived
32 ** from this software without specific prior written permission.
33 **
34 **
35 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
46 **
47 ** $QT_END_LICENSE$
48 **
49 ****************************************************************************/
50
51#include <QCoreApplication>
52#include <QCommandLineParser>
53#include <QStandardPaths>
54#include <QHash>
55#include <QLibraryInfo>
56
57#include <algorithm>
58
59#include <stdio.h>
60
61QT_USE_NAMESPACE
62
63/**
64 * Prints the string on stdout and appends a newline
65 * \param string printable string
66 */
67static void message(const QString &string)
68{
69 fprintf(stdout, format: "%s\n", qPrintable(string));
70}
71
72/**
73 * Writes error message and exits 1
74 * \param message to write
75 */
76Q_NORETURN static void error(const QString &message)
77{
78 fprintf(stderr, format: "%s\n", qPrintable(message));
79 ::exit(EXIT_FAILURE);
80}
81
82class StringEnum {
83public:
84 const char *stringvalue;
85 QStandardPaths::StandardLocation enumvalue;
86 bool hasappname;
87
88 /**
89 * Replace application name by generic name if requested
90 */
91 QString mapName(const QString &s) const
92 {
93 return hasappname ? QString(s).replace(before: "qtpaths", after: "<APPNAME>") : s;
94 }
95};
96
97static const StringEnum lookupTableData[] = {
98 { .stringvalue: "AppConfigLocation", .enumvalue: QStandardPaths::AppConfigLocation, .hasappname: true },
99 { .stringvalue: "AppDataLocation", .enumvalue: QStandardPaths::AppDataLocation, .hasappname: true },
100 { .stringvalue: "AppLocalDataLocation", .enumvalue: QStandardPaths::AppLocalDataLocation, .hasappname: true },
101 { .stringvalue: "ApplicationsLocation", .enumvalue: QStandardPaths::ApplicationsLocation, .hasappname: false },
102 { .stringvalue: "CacheLocation", .enumvalue: QStandardPaths::CacheLocation, .hasappname: true },
103 { .stringvalue: "ConfigLocation", .enumvalue: QStandardPaths::ConfigLocation, .hasappname: false },
104#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
105 { .stringvalue: "DataLocation", .enumvalue: QStandardPaths::DataLocation, .hasappname: true },
106#endif
107 { .stringvalue: "DesktopLocation", .enumvalue: QStandardPaths::DesktopLocation, .hasappname: false },
108 { .stringvalue: "DocumentsLocation", .enumvalue: QStandardPaths::DocumentsLocation, .hasappname: false },
109 { .stringvalue: "DownloadLocation", .enumvalue: QStandardPaths::DownloadLocation, .hasappname: false },
110 { .stringvalue: "FontsLocation", .enumvalue: QStandardPaths::FontsLocation, .hasappname: false },
111 { .stringvalue: "GenericCacheLocation", .enumvalue: QStandardPaths::GenericCacheLocation, .hasappname: false },
112 { .stringvalue: "GenericConfigLocation", .enumvalue: QStandardPaths::GenericConfigLocation, .hasappname: false },
113 { .stringvalue: "GenericDataLocation", .enumvalue: QStandardPaths::GenericDataLocation, .hasappname: false },
114 { .stringvalue: "HomeLocation", .enumvalue: QStandardPaths::HomeLocation, .hasappname: false },
115 { .stringvalue: "MoviesLocation", .enumvalue: QStandardPaths::MoviesLocation, .hasappname: false },
116 { .stringvalue: "MusicLocation", .enumvalue: QStandardPaths::MusicLocation, .hasappname: false },
117 { .stringvalue: "PicturesLocation", .enumvalue: QStandardPaths::PicturesLocation, .hasappname: false },
118 { .stringvalue: "RuntimeLocation", .enumvalue: QStandardPaths::RuntimeLocation, .hasappname: false },
119 { .stringvalue: "TempLocation", .enumvalue: QStandardPaths::TempLocation, .hasappname: false }
120};
121
122/**
123 * \return available types as a QStringList.
124 */
125static QStringList types()
126{
127 QStringList typelist;
128 for (const StringEnum &se : lookupTableData)
129 typelist << QString::fromLatin1(str: se.stringvalue);
130 std::sort(first: typelist.begin(), last: typelist.end());
131 return typelist;
132}
133
134/**
135 * Tries to arse the location string into a reference to a StringEnum entry or alternatively
136 * calls \ref error with a error message
137 */
138static const StringEnum &parseLocationOrError(const QString &locationString)
139{
140 for (const StringEnum &se : lookupTableData)
141 if (locationString == QLatin1String(se.stringvalue))
142 return se;
143
144 QString message = QCoreApplication::translate(context: "qtpaths", key: "Unknown location: %1");
145 error(message: message.arg(a: locationString));
146}
147
148/**
149 * searches for exactly one remaining argument and returns it.
150 * If not found, \ref error is called with a error message.
151 * \param parser to ask for remaining arguments
152 * \return one extra argument
153 */
154static QString searchStringOrError(QCommandLineParser *parser)
155{
156 int positionalArgumentCount = parser->positionalArguments().size();
157 if (positionalArgumentCount != 1)
158 error(message: QCoreApplication::translate(context: "qtpaths", key: "Exactly one argument needed as searchitem"));
159 return parser->positionalArguments().constFirst();
160}
161
162int main(int argc, char **argv)
163{
164 QCoreApplication app(argc, argv);
165 app.setApplicationVersion("1.0");
166
167#ifdef Q_OS_WIN
168 const QLatin1Char pathsep(';');
169#else
170 const QLatin1Char pathsep(':');
171#endif
172
173 QCommandLineParser parser;
174 parser.setApplicationDescription(QCoreApplication::translate(context: "qtpaths", key: "Command line client to QStandardPaths"));
175 parser.addPositionalArgument(name: QCoreApplication::translate(context: "qtpaths", key: "[name]"), description: QCoreApplication::tr(s: "Name of file or directory"));
176 parser.addHelpOption();
177 parser.addVersionOption();
178
179 //setting up options
180 QCommandLineOption types(QStringLiteral("types"), QCoreApplication::translate(context: "qtpaths", key: "Available location types."));
181 parser.addOption(commandLineOption: types);
182
183 QCommandLineOption paths(QStringLiteral("paths"), QCoreApplication::translate(context: "qtpaths", key: "Find paths for <type>."), QStringLiteral("type"));
184 parser.addOption(commandLineOption: paths);
185
186 QCommandLineOption writablePath(QStringLiteral("writable-path"),
187 QCoreApplication::translate(context: "qtpaths", key: "Find writable path for <type>."), QStringLiteral("type"));
188 parser.addOption(commandLineOption: writablePath);
189
190 QCommandLineOption locateDir(QStringList() << QStringLiteral("locate-dir") << QStringLiteral("locate-directory"),
191 QCoreApplication::translate(context: "qtpaths", key: "Locate directory [name] in <type>."), QStringLiteral("type"));
192 parser.addOption(commandLineOption: locateDir);
193
194 QCommandLineOption locateDirs(QStringList() << QStringLiteral("locate-dirs") << QStringLiteral("locate-directories"),
195 QCoreApplication::translate(context: "qtpaths", key: "Locate directories [name] in all paths for <type>."), QStringLiteral("type"));
196 parser.addOption(commandLineOption: locateDirs);
197
198 QCommandLineOption locateFile(QStringLiteral("locate-file"),
199 QCoreApplication::translate(context: "qtpaths", key: "Locate file [name] for <type>."), QStringLiteral("type"));
200 parser.addOption(commandLineOption: locateFile);
201
202 QCommandLineOption locateFiles(QStringLiteral("locate-files"),
203 QCoreApplication::translate(context: "qtpaths", key: "Locate files [name] in all paths for <type>."), QStringLiteral("type"));
204 parser.addOption(commandLineOption: locateFiles);
205
206 QCommandLineOption findExe(QStringList() << QStringLiteral("find-exe") << QStringLiteral("find-executable"),
207 QCoreApplication::translate(context: "qtpaths", key: "Find executable with [name]."));
208 parser.addOption(commandLineOption: findExe);
209
210 QCommandLineOption display(QStringList() << QStringLiteral("display"),
211 QCoreApplication::translate(context: "qtpaths", key: "Prints user readable name for <type>."), QStringLiteral("type"));
212 parser.addOption(commandLineOption: display);
213
214 QCommandLineOption testmode(QStringList() << QStringLiteral("testmode") << QStringLiteral("test-mode"),
215 QCoreApplication::translate(context: "qtpaths", key: "Use paths specific for unit testing."));
216 parser.addOption(commandLineOption: testmode);
217
218 QCommandLineOption qtversion(QStringLiteral("qt-version"), QCoreApplication::translate(context: "qtpaths", key: "Qt version."));
219 parser.addOption(commandLineOption: qtversion);
220
221 QCommandLineOption installprefix(QStringLiteral("install-prefix"), QCoreApplication::translate(context: "qtpaths", key: "Installation prefix for Qt."));
222 parser.addOption(commandLineOption: installprefix);
223
224 QCommandLineOption bindir(QStringList() << QStringLiteral("binaries-dir") << QStringLiteral("binaries-directory"),
225 QCoreApplication::translate(context: "qtpaths", key: "Location of Qt executables."));
226 parser.addOption(commandLineOption: bindir);
227
228 QCommandLineOption plugindir(QStringList() << QStringLiteral("plugin-dir") << QStringLiteral("plugin-directory"),
229 QCoreApplication::translate(context: "qtpaths", key: "Location of Qt plugins."));
230 parser.addOption(commandLineOption: plugindir);
231
232 parser.process(app);
233
234 QStandardPaths::setTestModeEnabled(parser.isSet(option: testmode));
235
236 QStringList results;
237 if (parser.isSet(option: qtversion)) {
238 QString qtversionstring = QString::fromLatin1(str: qVersion());
239 results << qtversionstring;
240 }
241
242 if (parser.isSet(option: installprefix)) {
243 QString path = QLibraryInfo::location(QLibraryInfo::PrefixPath);
244 results << path;
245 }
246
247 if (parser.isSet(option: bindir)) {
248 QString path = QLibraryInfo::location(QLibraryInfo::BinariesPath);
249 results << path;
250 }
251
252 if (parser.isSet(option: plugindir)) {
253 QString path = QLibraryInfo::location(QLibraryInfo::PluginsPath);
254 results << path;
255 }
256
257 if (parser.isSet(option: types)) {
258 QStringList typesList = ::types();
259 results << typesList.join(sep: '\n');
260 }
261
262 if (parser.isSet(option: display)) {
263 const StringEnum &location = parseLocationOrError(locationString: parser.value(option: display));
264 QString text = QStandardPaths::displayName(type: location.enumvalue);
265 results << location.mapName(s: text);
266 }
267
268 if (parser.isSet(option: paths)) {
269 const StringEnum &location = parseLocationOrError(locationString: parser.value(option: paths));
270 QStringList paths = QStandardPaths::standardLocations(type: location.enumvalue);
271 results << location.mapName(s: paths.join(sep: pathsep));
272 }
273
274 if (parser.isSet(option: writablePath)) {
275 const StringEnum &location = parseLocationOrError(locationString: parser.value(option: writablePath));
276 QString path = QStandardPaths::writableLocation(type: location.enumvalue);
277 results << location.mapName(s: path);
278 }
279
280 if (parser.isSet(option: findExe)) {
281 QString searchitem = searchStringOrError(parser: &parser);
282 QString path = QStandardPaths::findExecutable(executableName: searchitem);
283 results << path;
284 }
285
286 if (parser.isSet(option: locateDir)) {
287 const StringEnum &location = parseLocationOrError(locationString: parser.value(option: locateDir));
288 QString searchitem = searchStringOrError(parser: &parser);
289 QString path = QStandardPaths::locate(type: location.enumvalue, fileName: searchitem, options: QStandardPaths::LocateDirectory);
290 results << location.mapName(s: path);
291 }
292
293 if (parser.isSet(option: locateFile)) {
294 const StringEnum &location = parseLocationOrError(locationString: parser.value(option: locateFile));
295 QString searchitem = searchStringOrError(parser: &parser);
296 QString path = QStandardPaths::locate(type: location.enumvalue, fileName: searchitem, options: QStandardPaths::LocateFile);
297 results << location.mapName(s: path);
298 }
299
300 if (parser.isSet(option: locateDirs)) {
301 const StringEnum &location = parseLocationOrError(locationString: parser.value(option: locateDirs));
302 QString searchitem = searchStringOrError(parser: &parser);
303 QStringList paths = QStandardPaths::locateAll(type: location.enumvalue, fileName: searchitem, options: QStandardPaths::LocateDirectory);
304 results << location.mapName(s: paths.join(sep: pathsep));
305 }
306
307 if (parser.isSet(option: locateFiles)) {
308 const StringEnum &location = parseLocationOrError(locationString: parser.value(option: locateFiles));
309 QString searchitem = searchStringOrError(parser: &parser);
310 QStringList paths = QStandardPaths::locateAll(type: location.enumvalue, fileName: searchitem, options: QStandardPaths::LocateFile);
311 results << location.mapName(s: paths.join(sep: pathsep));
312 }
313 if (results.isEmpty()) {
314 parser.showHelp();
315 } else if (results.size() == 1) {
316 const QString &item = results.first();
317 message(string: item);
318 if (item.isEmpty())
319 return EXIT_FAILURE;
320 } else {
321 QString errorMessage = QCoreApplication::translate(context: "qtpaths", key: "Several options given, only one is supported at a time.");
322 error(message: errorMessage);
323 }
324 return EXIT_SUCCESS;
325}
326

source code of qttools/src/qtpaths/qtpaths.cpp