]> vaikene.ee Git - evaf/blob - src/main/CLI/main.cpp
Added eVaf Command Line Interface application.
[evaf] / src / main / CLI / main.cpp
1 /**
2 * @file main/CLI/main.cpp
3 * @brief The main eVaf CLI application class
4 *
5 * Copyright (c) 2011 Enar Vaikene
6 *
7 * This file is part of the eVaf C++ cross-platform application development framework.
8 *
9 * This file can be used under the terms of the GNU General Public License
10 * version 3.0 as published by the Free Software Foundation and appearing in
11 * the file LICENSE included in the packaging of this file. Please review the
12 * the following information to ensure the GNU General Public License version
13 * 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
14 *
15 * Alternatively, this file may be used in accordance with the Commercial License
16 * Agreement provided with the Software.
17 */
18
19 #include "main.h"
20 #include "exithandler.h"
21 //#include "version_p.h"
22 #include "version.h"
23
24 #include <Common/Globals>
25 #include <Common/iLogger>
26 #include <Common/iEnv>
27 #include <Common/iApp>
28
29 #include <Plugins/PluginManager>
30
31 #include <QtCore>
32
33 #ifdef Q_OS_LINUX
34 # include <sys/types.h>
35 # include <unistd.h>
36 #endif
37
38 using namespace eVaf;
39
40 //-------------------------------------------------------------------
41
42 namespace eVaf {
43 namespace CLI {
44 namespace Internal {
45
46 /**
47 * Qt message handler replacement.
48 * @param type Type of the message
49 * @param msg The message
50 *
51 * This function outputs messages to the console and to the log file.
52 */
53 static void messageOutput(QtMsgType type, char const * const msg)
54 {
55 static bool inHandler = false;
56
57 // Avoid recursions in case outputting a message causes another message to be output
58 if (inHandler)
59 return;
60 inHandler = true;
61
62 // Qt message type conversion to eVaf logger severity levels
63 Common::iLogger::Severity v;
64 switch (type) {
65 case QtWarningMsg:
66 v = Common::iLogger::Warning;
67 break;
68 case QtCriticalMsg:
69 v = Common::iLogger::Error;
70 break;
71 case QtFatalMsg:
72 v = Common::iLogger::Fatal;
73 break;
74 default:
75 v = Common::iLogger::Debug;
76 }
77
78 // Output to the log file and console
79 Common::iLogger::instance()->write(v, msg);
80
81 inHandler = false;
82 }
83
84 /**
85 * Fatal error message handler
86 * @param msg The error message
87 * @param source Source of the message
88 * @param where Where the error occurred
89 *
90 * This function shows a critical error message box on the screen if needed and then terminates
91 * the application.
92 *
93 * If the critical error message is shown, then the user has an option to ignore the error. In this
94 * case the application is not terminated.
95 */
96 static void fatalMsgHandler(QString const & msg, QString const & source, QString const & where)
97 {
98 #ifdef Q_OS_LINUX
99 abort();
100 #else
101 exit(1);
102 #endif
103 }
104
105 } // namespace eVaf::CLI::Internal
106 } // namespace eVaf::CLI
107 } // namespace eVaf
108
109 //-------------------------------------------------------------------
110
111 using namespace eVaf::CLI;
112
113 Application::Application(int & argc, char ** argv)
114 : QCoreApplication(argc, argv)
115 {
116 setObjectName(QString("%1-%2").arg(VER_MODULE_NAME_STR).arg(__FUNCTION__));
117 }
118
119 Application::~Application()
120 {
121 }
122
123 bool Application::processCommandLine(int argc, char ** argv)
124 {
125 Common::iLogger::Severity consoleSeverityLevel = Common::iLogger::Fatal;
126
127 QStringList args;
128 for (int i = 1; i < argc; ++i)
129 args += argv[i];
130
131 for (int i = 0; i < args.size(); ++i) {
132 // Get the argument and optional value
133 QStringList arg = args.at(i).simplified().split(QChar('='));
134
135 if (QRegExp("(-[-]?version)|([-//]V)").exactMatch(arg.at(0))) {
136 printVersion();
137 return false;
138 }
139 else if (QRegExp("(-[-]?help)|([-//][h/?])").exactMatch(arg.at(0))) {
140 printHelp();
141 return false;
142 }
143 else if (QRegExp("-[-]?verbose").exactMatch(arg.at(0)) && arg.size() > 1) {
144 QString v = arg.at(1).toLower();
145 if (v == "debug")
146 consoleSeverityLevel = Common::iLogger::Debug;
147 else if (v == "info")
148 consoleSeverityLevel = Common::iLogger::Info;
149 else if (v == "warning")
150 consoleSeverityLevel = Common::iLogger::Warning;
151 else if (v == "error")
152 consoleSeverityLevel = Common::iLogger::Error;
153 else if (v == "fatal")
154 consoleSeverityLevel = Common::iLogger::Fatal;
155 else if (v == "none") {
156 consoleSeverityLevel = Common::iLogger::None;
157 }
158 else {
159 printHelp();
160 return false;
161 }
162 }
163 else if (QRegExp("-[v]+").exactMatch(arg.at(0)) && arg.size() == 1) {
164 // The number of 'v's increases the verbosity
165 for (int j = 1; j < arg.at(0).size(); ++j) {
166 switch (consoleSeverityLevel) {
167 case Common::iLogger::None:
168 consoleSeverityLevel = Common::iLogger::Fatal;
169 break;
170 case Common::iLogger::Fatal:
171 consoleSeverityLevel = Common::iLogger::Error;
172 break;
173 case Common::iLogger::Error:
174 consoleSeverityLevel = Common::iLogger::Warning;
175 break;
176 case Common::iLogger::Warning:
177 consoleSeverityLevel = Common::iLogger::Info;
178 break;
179 case Common::iLogger::Info:
180 consoleSeverityLevel = Common::iLogger::Debug;
181 break;
182 case Common::iLogger::Debug:
183 break;
184 }
185 }
186 }
187 }
188
189 // Set the console severity
190 Common::iLogger::instance()->setConsoleSeverity(consoleSeverityLevel);
191
192 return true;
193 }
194
195 void Application::printHelp()
196 {
197 char const * const txt = QT_TR_NOOP(
198 "Usage: eVafCLI [options]\n"
199 "\n"
200 // General options
201 " -help Shows this help and quits.\n"
202 " -version Shows version information and quits.\n"
203 " -verbose=LEVEL Specifies the verbose level. LEVEL can be one of the\n"
204 " following: NONE, FATAL, ERROR, WARNING, INFO, DEBUG.\n"
205 " -v Makes the application more verbose. Can be repeated for\n"
206 " more verbosity.\n"
207 // Handled by the iApp interface implementation
208 " -appl[ication]=NAME Specifies the name of the application.\n"
209 " -lang[uage]=xx[_CC] Specifies the language, where xx is the ISO 639\n"
210 " language code followed by an optional ISO 3166 country\n"
211 " code.\n"
212 // Handled by the iEnv interface implementation
213 " -root[dir]=DIR Specifies the application's root directory.\n"
214 " -dataroot[dir]=DIR Specifies the data root directory.\n"
215 " -etc[dir]=DIR Specifies the configuration files directory.\n"
216 " -log[dir]=DIR Specifies the log files directory.\n"
217 " -doc[dir]=DIR Specifies the documentation directory.\n"
218 " -qtplugins[dir]=DIR Specifies the Qt plugins directory.\n"
219 );
220 ::fputs(tr(txt).toLocal8Bit().constData(), stdout);
221 }
222
223 void Application::printVersion()
224 {
225 ::printf("%s version %s release date %s, %s version %s\n",
226 VER_PRODUCT_NAME_STR,
227 VER_PRODUCT_VERSION_STR,
228 VER_PRODUCT_DATE_STR,
229 VER_MODULE_NAME_STR,
230 VER_FILE_VERSION_STR
231 );
232 }
233
234
235 //-------------------------------------------------------------------
236
237 int main(int argc, char ** argv)
238 {
239 Common::iLogger::instance()->setSeverity(Common::iLogger::Warning);
240
241 // Install our onw message handlers
242 Common::iLogger::instance()->installFatalMsgHandler(Internal::fatalMsgHandler);
243 qInstallMsgHandler(Internal::messageOutput);
244
245 // Process command-line arguments
246 if (!Application::processCommandLine(argc, argv))
247 return 1;
248
249 EVAF_INFO("%s version %s release date %s, %s version %s",
250 VER_PRODUCT_NAME_STR,
251 VER_PRODUCT_VERSION_STR,
252 VER_PRODUCT_DATE_STR,
253 VER_MODULE_NAME_STR,
254 VER_FILE_VERSION_STR);
255
256 #ifdef Q_OS_LINUX
257 EVAF_INFO("%s application pid = %d", VER_MODULE_NAME_STR, getpid());
258 #endif
259
260 Application app(argc, argv);
261
262 // Install the exit handler
263 if (!Internal::installExitHandler())
264 return 1;
265
266 // Plugin manager
267 Plugins::PluginManager pluginManager;
268
269 // The main run loop
270 bool quit = false;
271 int rval;
272 while (!quit) {
273
274 EVAF_INFO("%s is starting up", VER_MODULE_NAME_STR);
275
276 // Initialize the common library
277 if (!Common::init())
278 return 1;
279
280 // Initialize the plugin manager and load plugins
281 if (!pluginManager.init())
282 return 1;
283
284 // Run the application
285 EVAF_INFO("Running %s", VER_MODULE_NAME_STR);
286 rval = app.exec();
287
288 quit = rval != Common::iApp::RC_Restart;
289
290 EVAF_INFO("%s is %s", VER_MODULE_NAME_STR, quit ? "exiting" : "restarting");
291
292 // Unload plugins and finalize the plugin manager
293 pluginManager.done();
294 }
295
296 EVAF_INFO("%s exit with code %d", VER_MODULE_NAME_STR, rval);
297
298 return rval;
299 }