Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 andreas 1
/*
21 andreas 2
 * Copyright (C) 2020, 2021 by Andreas Theofilu <andreas@theosys.at>
2 andreas 3
 *
4
 * This program is free software; you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program; if not, write to the Free Software Foundation,
16
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
17
 */
18
#include <iostream>
19
#include <iomanip>
20
#include <string>
21
#include <vector>
22
#include <algorithm>
235 andreas 23
 
2 andreas 24
#include "tconfig.h"
235 andreas 25
#include "terror.h"
299 andreas 26
//#include "tsettings.h"
27
//#include "tpagelist.h"
28
//#include "tpage.h"
29
//#include "tsubpage.h"
3 andreas 30
#include "tpagemanager.h"
2 andreas 31
#include "tqtmain.h"
32
 
239 andreas 33
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
22 andreas 34
#include <QStandardPaths>
35
#endif
36
#ifdef __ANDROID__
37
#include <android/log.h>
38
#endif
39
 
2 andreas 40
using std::string;
41
using std::find;
42
using std::vector;
21 andreas 43
using std::cout;
239 andreas 44
using std::cerr;
21 andreas 45
using std::endl;
2 andreas 46
 
90 andreas 47
bool _restart_ = false;
239 andreas 48
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
91 andreas 49
extern std::atomic<bool> killed;
50
extern std::atomic<bool> _netRunning;
51
#endif
90 andreas 52
 
21 andreas 53
/**
54
 * @class InputParser
55
 * @brief The InputParser class parses the command line.
56
 *
57
 * This class takes the command line arguments and parses them. It creates an
58
 * internal vector array to hold the parameters.
59
 */
2 andreas 60
class InputParser
61
{
3 andreas 62
    public:
21 andreas 63
        /**
64
         * @brief InputParser is the constructor.
65
         *
66
         * The constructor requires the command line parameters. It immediately
118 andreas 67
         * starts to parse each parameter. If it finds the string `--` it stops
21 andreas 68
         * and ignores the rest of parameters. \p argc contains the rest of
69
         * the parameters after `--`, if there are any.
70
         *
71
         * @param argc  A pointer to the numbers of command line parameters.
72
         *              This parameter must not be `NULL`.
73
         * @param argv  The 2 dimensional array of command line parameters.
74
         *              This parameter must not be `NULL`.
75
         */
3 andreas 76
        InputParser(int *argc, char **argv)
77
        {
78
            int i;
2 andreas 79
 
3 andreas 80
            for (i = 1; i < *argc; ++i)
81
            {
82
                if (string(argv[i]).compare("--") == 0)
83
                    break;
2 andreas 84
 
3 andreas 85
                this->tokens.push_back(string(argv[i]));
86
            }
2 andreas 87
 
3 andreas 88
            *argc -= i;
2 andreas 89
 
3 andreas 90
            if (*argc <= 1)
91
                *argc = 1;
92
            else
93
            {
94
                *argc = *argc + 1;
95
                *(argv + i - 1) = *argv;
96
            }
97
        }
21 andreas 98
        /**
99
         * @brief getCmdOption searches for the command line option \p option.
100
         * @author iain
101
         *
102
         * The method searches for the command line option \p option and
103
         * returns the parameter after the option, if there is one.
104
         *
105
         * @param option    The name of a command line option. This is any
106
         *                  name starting with 1 or 2 dash (-). The name in
107
         *                  the parameter must include the dash(es) in front
108
         *                  of the name.\n
109
         *                  If the option was found and the next parameter on
110
         *                  the command line doesn't start with a dash, the
111
         *                  parameter is returned.
112
         *
113
         * @return Tf the option was found and the parameter on the command
114
         * line following the option doesn't start with a dash, it is returned.
115
         * Otherwise an empty string is returned.
116
         */
3 andreas 117
        const string& getCmdOption(const string &option) const
118
        {
119
            vector<string>::const_iterator itr;
120
            itr = find(this->tokens.begin(), this->tokens.end(), option);
2 andreas 121
 
3 andreas 122
            if (itr != this->tokens.end() && ++itr != this->tokens.end())
123
                return *itr;
2 andreas 124
 
3 andreas 125
            static const string empty_string("");
126
            return empty_string;
127
        }
21 andreas 128
 
129
        /**
130
         * @brief cmdOptionExists tests for an existing option.
131
         * @author iain
132
         *
133
         * This function tests whether the option \p option exists or not. If
134
         * the option was found, it returnes `true`.
135
         *
136
         * @param option    The name of a command line option. This is any
137
         *                  name starting with 1 or 2 dash (-). The name in
138
         *                  the parameter must include the dash(es) in front
139
         *                  of the name.\n
140
         *
141
         * @return If the command line option was found in the internal vector
142
         * array `true` is returned. Otherwise it returnes `false`.
143
         */
3 andreas 144
        bool cmdOptionExists(const string &option) const
145
        {
146
            return find(this->tokens.begin(), this->tokens.end(), option) != this->tokens.end();
147
        }
2 andreas 148
 
3 andreas 149
    private:
150
        vector <string> tokens;
2 andreas 151
};
152
 
21 andreas 153
/**
154
 * @brief usage displays on the standard output a small help.
155
 *
156
 * This function shows a short help with all available parameters and a brief
157
 * description of them.
158
 * \verbatim
159
 * NOTE: This function is not available on Android systems.
160
 * \endverbatim
161
 */
2 andreas 162
void usage()
163
{
239 andreas 164
#if not defined(Q_OS_ANDROID) && not defined(Q_OS_IOS)
132 andreas 165
    cout << TConfig::getProgName() << " version " <<  VERSION_STRING() << endl << endl;
21 andreas 166
    cout << "Usage: tpanel [-c <config file>]" << endl;
167
    cout << "-c | --config-file <file> The path and name of the configuration file." << endl;
168
    cout << "                          This parameter is optional. If it is omitted," << endl;
169
    cout << "                          The standard path is searched for the" << endl;
170
    cout << "                          configuration file." << endl << endl;
171
    cout << "-h | --help               This help." << endl << endl;
172
#endif
2 andreas 173
}
174
 
239 andreas 175
#if not defined(Q_OS_ANDROID) && not defined(Q_OS_IOS)
21 andreas 176
/**
177
 * @brief banner displays a shor banner with informations about this application.
178
 *
179
 * This function shows a short information about this application. It prints
180
 * this on the standard output.
181
 * \verbatim
182
 * NOTE: This function is not available on Android systems.
183
 * \endverbatim
184
 *
185
 * @param pname The name of this application.
186
 */
2 andreas 187
void banner(const string& pname)
188
{
3 andreas 189
    if (!TConfig::showBanner())
190
        return;
2 andreas 191
 
132 andreas 192
    cout << pname << " v" << VERSION_STRING() << endl;
21 andreas 193
    cout << "(C) Andreas Theofilu <andreas@theosys.at>" << endl;
194
    cout << "This program is under the terms of GPL version 3" << endl << endl;
22 andreas 195
}
21 andreas 196
#endif
2 andreas 197
 
21 andreas 198
/**
90 andreas 199
 * @brief Is called whenever the program starts up.
200
 *
201
 * This method is called to start up the program. It initializes the main
202
 * classes and waits until the main loop ends.
203
 * It is also called if the program have to start over. This happens when
204
 * the settings change the host, port or channel ID, or after receiving a new
205
 * surface.
206
 *
93 andreas 207
 * @param oldArgc   This is the previous parameter counter (only for desktop).
90 andreas 208
 * @param argc      This is the actual parameter counter.
209
 * @param argv      This is the pointer array to the environment.
210
 *
211
 * @return of success TRUE is returned. Otherwise FALSE.
212
 */
239 andreas 213
#if not defined(Q_OS_ANDROID) && not defined(Q_OS_IOS)
90 andreas 214
bool _startUp(int oldArgc, int argc, char *argv[])
125 andreas 215
#else
216
bool _startUp(int, int argc, char *argv[])
217
#endif
90 andreas 218
{
92 andreas 219
    DECL_TRACER("_startUp(int oldArgc, int argc, char *argv[])");
90 andreas 220
 
92 andreas 221
    TPageManager *pageManager = new TPageManager;
222
 
90 andreas 223
    if (TError::isError())
92 andreas 224
    {
260 andreas 225
#ifdef __ANDROID__
226
        __android_log_print(ANDROID_LOG_FATAL, "tpanel", "There was an unrecoverable error in creating the page manager!");
227
#else
239 andreas 228
        cerr << "FATAL: There was an unrecoverable error in creating the page manager!" << endl;
260 andreas 229
#endif
92 andreas 230
        delete pageManager;
119 andreas 231
        pageManager = nullptr;
90 andreas 232
        return false;
92 andreas 233
    }
90 andreas 234
 
235
    // Prepare command line stack
239 andreas 236
#if not defined(Q_OS_ANDROID) && not defined(Q_OS_IOS)
90 andreas 237
    int pt = oldArgc - argc;
238
#else
239
    int pt = 0;
240
#endif
241
    // Start the graphical environment
242
    int ret = 0;
93 andreas 243
    // The _restart_ variable is reset in class initialization MainWindow.
92 andreas 244
    ret = qtmain(argc, &argv[pt], pageManager);
245
    delete pageManager;
119 andreas 246
    pageManager = nullptr;
90 andreas 247
 
248
    if (ret != 0)
249
        return false;
250
 
251
    return true;
252
}
253
 
254
/**
21 andreas 255
 * @brief main is the main entry function.
256
 *
257
 * This is where the program starts.
258
 *
259
 * @param argc  The number of command line arguments.
260
 * @param argv  A pointer to a 2 dimensional array containing the command line
261
 *              parameters.
262
 *
263
 * @return 0 on success. This means that no errors occured.\n
264
 * In case of an error a number grater than 0 is returned.
265
 */
2 andreas 266
int main(int argc, char *argv[])
267
{
3 andreas 268
    string configFile;
91 andreas 269
    int oldArgc = argc;
239 andreas 270
#if not defined(Q_OS_ANDROID) && not defined(Q_OS_IOS)
3 andreas 271
    string pname = *argv;
272
    size_t pos = pname.find_last_of("/");
251 andreas 273
    bool haveParameters = (argc > 1);
2 andreas 274
 
3 andreas 275
    if (pos != string::npos)
276
        pname = pname.substr(pos + 1);
22 andreas 277
#else
278
    string pname = "tpanel";
91 andreas 279
    killed = false;
280
    _netRunning = false;
251 andreas 281
    bool haveParameters = false;
22 andreas 282
#endif
21 andreas 283
    TConfig::setProgName(pname);    // Remember the name of this application.
239 andreas 284
#if not defined(Q_OS_ANDROID) && not defined(Q_OS_IOS)
21 andreas 285
    InputParser input(&argc, argv); // Parse the command line parameters.
2 andreas 286
 
21 andreas 287
    // Evaluate the command line parameters.
3 andreas 288
    if (input.cmdOptionExists("-h") || input.cmdOptionExists("--help"))
289
    {
290
        banner(pname);
291
        usage();
292
        return 0;
293
    }
2 andreas 294
 
3 andreas 295
    if (input.cmdOptionExists("-c") || input.cmdOptionExists("--config-file"))
296
    {
297
        configFile = input.getCmdOption("-c");
2 andreas 298
 
3 andreas 299
        if (configFile.empty())
300
            configFile = input.getCmdOption("--config-file");
2 andreas 301
 
3 andreas 302
        if (configFile.empty())
303
        {
304
            banner(pname);
305
            std::cerr << "Missing the path and name of the configuration file!" << std::endl;
306
            usage();
307
            return 1;
308
        }
309
    }
22 andreas 310
#endif
251 andreas 311
    if (haveParameters && configFile.empty())
312
    {
260 andreas 313
#ifdef __ANDROID__
314
        __android_log_print(ANDROID_LOG_ERROR, "tpanel", "Unknown command line parameter found!");
315
#else
251 andreas 316
        cerr << "ERROR: Unknown command line parameter found!" << endl;
260 andreas 317
#endif
251 andreas 318
        usage();
319
        return 1;
320
    }
321
 
21 andreas 322
    TError::clear();                    // Clear all errors (initialize)
323
    TConfig config(configFile);         // Read the configuration file.
2 andreas 324
 
21 andreas 325
    if (TError::isError())              // Exit if the previous command failed.
22 andreas 326
    {
126 andreas 327
#ifdef __ANDROID__
328
        __android_log_print(ANDROID_LOG_ERROR, "tpanel", "%s", TError::getErrorMsg().c_str());
329
#endif
22 andreas 330
        TError::displayMessage(TError::getErrorMsg());
3 andreas 331
        return 1;
22 andreas 332
    }
239 andreas 333
#if not defined(Q_OS_ANDROID) && not defined(Q_OS_IOS)
3 andreas 334
    banner(pname);
22 andreas 335
#endif
3 andreas 336
    TError::clear();
58 andreas 337
    // Start the page manager. This is the core class handling everything.
338
    try
339
    {
90 andreas 340
        bool ret;
2 andreas 341
 
90 andreas 342
        do
343
        {
344
            ret = _startUp(oldArgc, argc, argv);
2 andreas 345
 
90 andreas 346
            if (_restart_)
347
            {
348
                MSG_INFO("Starting over ...");
349
                prg_stopped = false;
350
                killed = false;
351
            }
352
        }
353
        while (_restart_);
21 andreas 354
 
90 andreas 355
        if (!ret)
356
        {
126 andreas 357
#ifdef __ANDROID__
260 andreas 358
            __android_log_print(ANDROID_LOG_FATAL, "tpanel", "Terminating because of a previous fatal error!");
359
#else
360
            MSG_ERROR("Terminating because of a previous fatal error!");
126 andreas 361
#endif
90 andreas 362
            return 1;
363
        }
58 andreas 364
    }
365
    catch (std::exception& e)
366
    {
126 andreas 367
#ifdef __ANDROID__
260 andreas 368
        __android_log_print(ANDROID_LOG_FATAL, "tpanel", "%s", e.what());
126 andreas 369
#endif
58 andreas 370
        MSG_ERROR("Fatal: " << e.what());
371
        return 1;
372
    }
2 andreas 373
 
3 andreas 374
    return 0;
2 andreas 375
}