Statistics
| Branch: | Revision:

root / src / envir / startup.cc @ master

History | View | Annotate | Download (10.2 KB)

1 01873262 Georg Kunz
//==========================================================================
2
//  STARTUP.CC - part of
3
//                     OMNeT++/OMNEST
4
//            Discrete System Simulation in C++
5
//
6
//  Author: Andras Varga
7
//
8
//==========================================================================
9
10
/*--------------------------------------------------------------*
11
  Copyright (C) 1992-2008 Andras Varga
12
  Copyright (C) 2006-2008 OpenSim Ltd.
13

14
  This file is distributed WITHOUT ANY WARRANTY. See the file
15
  `license' for details on this and other legal matters.
16
*--------------------------------------------------------------*/
17
18
19
#include <stdarg.h>
20
#include <stdio.h>
21
#include <string.h>
22
23
#include "opp_ctype.h"
24
#include "args.h"
25
#include "distrib.h"
26
#include "cconfigoption.h"
27
#include "inifilereader.h"
28
#include "sectionbasedconfig.h"
29
#include "appreg.h"
30
#include "cmodule.h"
31
#include "fsutils.h"
32
#include "fnamelisttokenizer.h"
33
#include "stringutil.h"
34
#include "fileutil.h"
35
#include "intxtypes.h"
36
#include "startup.h"
37
38
39
USING_NAMESPACE;
40
41
Register_GlobalConfigOption(CFGID_LOAD_LIBS, "load-libs", CFG_FILENAMES, "", "A space-separated list of dynamic libraries to be loaded on startup. The libraries should be given without the `.dll' or `.so' suffix -- that will be automatically appended.");
42
Register_GlobalConfigOption(CFGID_CONFIGURATION_CLASS, "configuration-class", CFG_STRING, "", "Part of the Envir plugin mechanism: selects the class from which all configuration information will be obtained. This option lets you replace omnetpp.ini with some other implementation, e.g. database input. The simulation program still has to bootstrap from an omnetpp.ini (which contains the configuration-class setting). The class should implement the cConfigurationEx interface.");
43
Register_GlobalConfigOption(CFGID_USER_INTERFACE, "user-interface", CFG_STRING, "", "Selects the user interface to be started. Possible values are Cmdenv and Tkenv. This option is normally left empty, as it is more convenient to specify the user interface via a command-line option or the IDE's Run and Debug dialogs. New user interfaces can be defined by subclassing cRunnableEnvir.");
44
45
46
// helper macro
47
#define CREATE_BY_CLASSNAME(var,classname,baseclass,description) \
48
     baseclass *var ## _tmp = (baseclass *) createOne(classname); \
49
     var = dynamic_cast<baseclass *>(var ## _tmp); \
50
     if (!var) \
51
         throw cRuntimeError("Class \"%s\" is not subclassed from " #baseclass, (const char *)classname);
52
53
54
static void verifyIntTypes()
55
{
56
#define VERIFY(t,size) if (sizeof(t)!=size) {printf("INTERNAL ERROR: sizeof(%s)!=%d, please check typedefs in include/inttypes.h, and report this bug!\n\n", #t, size); abort();}
57
    VERIFY(int8,  1);
58
    VERIFY(int16, 2);
59
    VERIFY(int32, 4);
60
    VERIFY(int64, 8);
61
62
    VERIFY(uint8, 1);
63
    VERIFY(uint16,2);
64
    VERIFY(uint32,4);
65
    VERIFY(uint64,8);
66
#undef VERIFY
67
68
#define LL  INT64_PRINTF_FORMAT
69
    char buf[32];
70
    int64 a=1, b=2;
71
    sprintf(buf, "%"LL"d %"LL"d", a, b);
72
    if (strcmp(buf, "1 2")!=0) {printf("INTERNAL ERROR: INT64_PRINTF_FORMAT incorrectly defined in include/inttypes.h, please report this bug!\n\n"); abort();}
73
#undef LL
74
}
75
76
int setupUserInterface(int argc, char *argv[])
77
{
78
    //
79
    // SETUP
80
    //
81
    cSimulation *simulationobject = NULL;
82
    cRunnableEnvir *app = NULL;
83
    ArgList *args = NULL;
84
    SectionBasedConfiguration *bootconfig = NULL;
85
    cConfigurationEx *configobject = NULL;
86
    int exitcode = 0;
87
    try
88
    {
89
        // construct global lists
90
        ExecuteOnStartup::executeAll();
91
92
        // verify definitions of int64, int32, etc.
93
        verifyIntTypes();
94
95
        // args
96
        args = new ArgList();
97
        args->parse(argc, argv, "h?f:u:l:c:r:p:n:x:agGv");
98
99
        //
100
        // First, load the ini file. It might contain the name of the user interface
101
        // to instantiate.
102
        //
103
        const char *fname = args->optionValue('f',0);  // 1st '-f filename' option
104
        if (!fname) fname = args->argument(0);   // first argument
105
        if (!fname) fname = "omnetpp.ini";   // or default filename
106
107
        // when -h or -v is specified, be forgiving about nonexistent omnetpp.ini
108
        InifileReader *inifile = new InifileReader();
109
        if ((!args->optionGiven('v') && !args->optionGiven('h')) || fileExists(fname))
110
            inifile->readFile(fname);
111
112
        // process additional '-f filename' options or arguments if there are any
113
        for (int k=1; (fname=args->optionValue('f',k))!=NULL; k++)
114
            inifile->readFile(fname);
115
        for (int k=(args->optionValue('f',0) ? 0 : 1); (fname=args->argument(k))!=NULL; k++)
116
            inifile->readFile(fname);
117
118
        // activate [General] section so that we can read global settings from it
119
        bootconfig = new SectionBasedConfiguration();
120
        bootconfig->setConfigurationReader(inifile);
121
        bootconfig->setCommandLineConfigOptions(args->getLongOptions());
122
        bootconfig->activateConfig("General", 0);
123
124
        //
125
        // Load all libraries specified on the command line ('-l' options),
126
        // and in the configuration [General]/load-libs=.
127
        // (The user interface library also might be among them.)
128
        //
129
        const char *libname;
130
        for (int k=0; (libname=args->optionValue('l',k))!=NULL; k++)
131
            loadExtensionLibrary(libname);
132
        std::vector<std::string> libs = bootconfig->getAsFilenames(CFGID_LOAD_LIBS);
133
        for (int k=0; k<(int)libs.size(); k++)
134
            loadExtensionLibrary(libs[k].c_str());
135
136
        //
137
        // Create custom configuration object, if needed.
138
        //
139
        std::string configclass = bootconfig->getAsString(CFGID_CONFIGURATION_CLASS);
140
        if (configclass.empty())
141
        {
142
            configobject = bootconfig;
143
        }
144
        else
145
        {
146
            // create custom configuration object
147
            CREATE_BY_CLASSNAME(configobject, configclass.c_str(), cConfigurationEx, "configuration");
148
            configobject->initializeFrom(bootconfig);
149
            delete bootconfig;
150
            bootconfig = NULL;
151
152
            // load libs from this config as well
153
            std::vector<std::string> libs = configobject->getAsFilenames(CFGID_LOAD_LIBS);
154
            for (int k=0; k<(int)libs.size(); k++)
155
                loadExtensionLibrary(libs[k].c_str());
156
        }
157
158
159
        // validate the configuration, but make sure we don't report cmdenv-* keys
160
        // as errors if Cmdenv is absent; same for Tkenv.
161
        std::string ignorablekeys;
162
        if (omnetapps.getInstance()->lookup("Cmdenv")==NULL)
163
            ignorablekeys += " cmdenv-*";
164
        if (omnetapps.getInstance()->lookup("Tkenv")==NULL)
165
            ignorablekeys += " tkenv-*";
166
        configobject->validate(ignorablekeys.c_str());
167
168
        //
169
        // Choose and set up user interface (EnvirBase subclass). Everything else
170
        // will be done by the user interface class.
171
        //
172
173
        // was it specified explicitly which one to use?
174
        std::string appname = opp_nulltoempty(args->optionValue('u',0));  // 1st '-u name' option
175
        if (appname.empty())
176
            appname = configobject->getAsString(CFGID_USER_INTERFACE);
177
178
        cOmnetAppRegistration *appreg = NULL;
179
        if (!appname.empty())
180
        {
181
            // look up specified user interface
182
            appreg = static_cast<cOmnetAppRegistration *>(omnetapps.getInstance()->lookup(appname.c_str()));
183
            if (!appreg)
184
            {
185
                ::printf("\n"
186
                         "User interface '%s' not found (not linked in or loaded dynamically).\n"
187
                         "Available ones are:\n", appname.c_str());
188
                cRegistrationList *a = omnetapps.getInstance();
189
                for (int i=0; i<a->size(); i++)
190
                    ::printf("  %s : %s\n", a->get(i)->getName(), a->get(i)->info().c_str());
191
192
                throw cRuntimeError("Could not start user interface '%s'", appname.c_str());
193
            }
194
        }
195
        else
196
        {
197
            // user interface not explicitly selected: pick one from what we have
198
            appreg = cOmnetAppRegistration::chooseBest();
199
            if (!appreg)
200
                throw cRuntimeError("No user interface (Cmdenv, Tkenv, etc.) found");
201
        }
202
203
        //
204
        // Create interface object.
205
        //
206
        ::printf("Setting up %s...\n", appreg->getName());
207
        app = appreg->createOne();
208
    }
209
    catch (std::exception& e)
210
    {
211
        ::fprintf(stderr, "\n<!> Error during startup: %s.\n", e.what());
212
        if (app)
213
        {
214
            delete app;
215
            app = NULL;
216
        }
217
        else
218
        {
219
            // normally, these two get deleted by app
220
            delete args;
221
            delete bootconfig;
222
        }
223
    }
224
225
    //
226
    // RUN
227
    //
228
    try
229
    {
230
        if (app)
231
        {
232
            simulationobject = new cSimulation("simulation", app);
233
            cSimulation::setActiveSimulation(simulationobject);
234
            exitcode = app->run(argc, argv, configobject);
235
        }
236
        else
237
        {
238
            exitcode = 1;
239
        }
240
    }
241
    catch (std::exception& e)
242
    {
243
        ::fprintf(stderr, "\n<!> %s.\n", e.what());
244
        exitcode = 1;
245
    }
246
247
    //
248
    // SHUTDOWN
249
    //
250
    cSimulation::setActiveSimulation(NULL);
251
    delete simulationobject;  // will delete app as well
252
253
    componentTypes.clear();
254
    nedFunctions.clear();
255
    classes.clear();
256
    enums.clear();
257
    classDescriptors.clear();
258
    configOptions.clear();
259
    omnetapps.clear();
260
    cSimulation::clearLoadedNedFiles();
261
262
    return exitcode;
263
}
264
265
266
//---------------------------------------------------------
267
268
#include "speedometer.h"
269
#include "fileoutvectormgr.h"
270
#include "fileoutscalarmgr.h"
271
#include "filesnapshotmgr.h"
272
#include "indexedfileoutvectormgr.h"
273
#include "akaroarng.h"
274
#include "akoutvectormgr.h"
275
#include "matchableobject.h"
276
277
// A dummy function to force UNIX linkers collect all symbols we need
278
void env_dummy_function() {
279
    exponential(1.0);
280
    Speedometer a;
281
    cFileOutputVectorManager ovm;
282
    cFileOutputScalarManager osm;
283
    cFileSnapshotManager sm;
284
    cIndexedFileOutputVectorManager iovm;
285
    MatchableObjectAdapter moa;
286
    (void)a; (void)ovm; (void)osm; (void)sm; (void)iovm; (void)moa; // eliminate 'unused var' warnings
287
#ifdef WITH_AKAROA
288
    cAkOutputVectorManager ao;
289
    cAkaroaRNG ar;
290
    (void)ao; (void)ar; // eliminate 'unused var' warning
291
#endif
292
}