Project

General

Profile

Statistics
| Branch: | Revision:

root / include / cenvir.h @ aeae20a1

History | View | Annotate | Download (24.4 KB)

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

13
  This file is distributed WITHOUT ANY WARRANTY. See the file
14
  `license' for details on this and other legal matters.
15
*--------------------------------------------------------------*/
16
17
#ifndef __CENVIR_H
18
#define __CENVIR_H
19
20
#include <sstream>
21
#include <iostream>
22
#include "simkerneldefs.h"
23
#include "simtime_t.h"
24
#include "opp_string.h"
25
#include "csimulation.h"
26
27
NAMESPACE_BEGIN
28
29
class cObject;
30
class cOwnedObject;
31
class cMessage;
32
class cPar;
33
class cGate;
34
class cComponent;
35
class cModule;
36
class cSimpleModule;
37
class cStatistic;
38
class cRNG;
39
class cXMLElement;
40
class cEnvir;
41
class cConfiguration;
42
class cConfigurationEx;
43
44
using std::endl;
45
46
// internal macro, usage: EVCB.beginSend(...)
47
#define EVCB  ev.suppress_notifications ? (void)0 : ev
48
49
/**
50
 * Represents the "environment" or user interface of the simulation.
51
 *
52
 * Most common usage from model code (simple modules) is to write log
53
 * messages, e.g.:
54
 *
55
 * <pre>
56
 * ev << "Received packet " << msg->getName() << ", length " << msg->getBitLength()/8 << " bytes\n";
57
 * ev << "Sending up to higher layer\n";
58
 * </pre>
59
 *
60
 * Other useful methods are cEnvir::isGUI() and cEnvir::isDisabled().
61
 *
62
 * The rest of cEnvir methods are used internally for communication between
63
 * the simulation kernel and the environment.
64
 *
65
 * @ingroup Envir
66
 */
67
#define ev  (*cSimulation::getActiveEnvir())
68
69
70
/**
71
 * <tt>EV&lt;&lt;</tt> can be used instead of <tt>ev&lt;&lt;</tt> to make
72
 * logging more efficient. An example:
73
 * <pre>
74
 * EV << "Packet " << msg->getName() << " received\n";
75
 * </pre>
76
 *
77
 * <tt>EV</tt> utilizes cEnvir::isDisabled() to check whether the logged text
78
 * is going to be printed/stored anywhere, or just gets discarded; in the
79
 * latter case the <tt>&lt;&lt;</tt> operators do not get evaluated at all,
80
 * making the log statement effectively a zero cost operation.
81
 *
82
 * @ingroup Envir
83
 */
84
#define EV  ev.isDisabled()?ev:ev   /*Note: deliberately NO parens*/
85
86
87
/**
88
 * cEnvir represents the "environment" of the simulation. cEnvir
89
 * is a common facade for the Cmdenv and Tkenv user interfaces (and any
90
 * other future user interface). The cEnvir object can be accessed
91
 * via cSimulation::getActiveEnvir() or the ev macro.
92
 *
93
 * The default implementation of cEnvir can be customized by subclassing
94
 * the classes declared in the envirext.h header (e.g. cConfiguration,
95
 * cRNG, cOutputVectorManager, cOutputScalarManager), and selecting the
96
 * new classes from <tt>omnetpp.ini</tt>.
97
 *
98
 * @ingroup Envir
99
 * @ingroup EnvirExtensions
100
 */
101
class SIM_API cEnvir
102
{
103
    friend class evbuf;
104
  public:
105
    // Internal flag for express mode.
106
    bool disable_tracing;
107
108
    // Indicates whether eventlog recording is currently enabled
109
    bool record_eventlog;
110
111
    // Internal flag. When set to true, the simulation kernel MAY omit calling
112
    // the following cEnvir methods: messageScheduled(), messageCancelled(),
113
    // beginSend(), messageSendDirect(), messageSendHop(), messageSendHop(),
114
    // messageSendHop(), messageDeleted(), moduleReparented(), simulationEvent(),
115
    // componentMethodBegin(), moduleCreated(), moduleDeleted(), connectionCreated(),
116
    // connectionDeleted(), displayStringChanged().
117
    bool suppress_notifications;
118
119
    // Internal flag. When set, cRuntimeError constructor to raises an exception.
120
    bool debug_on_errors;
121
122
  protected:
123
    // further internal vars
124
    std::ostream out;
125
126
  protected:
127
    // internal: ev.printf() and ev<< eventually ends up here; write the first n characters of string s
128
    virtual void sputn(const char *s, int n) = 0;
129
130
    // internal: pop up a dialog with the given message; called from printfmsg()
131
    virtual void putsmsg(const char *msg) = 0;
132
133
    // internal: ask a yes/no question, throws exception if cancelled; askYesNo() delegates here
134
    virtual bool askyesno(const char *msg) = 0;
135
136
    // internal: flushes the internal stream buffer by terminating last line if needed
137
    void flushLastLine();
138
139
  public:
140
    /** @name Constructor, destructor. */
141
    //@{
142
143
    /**
144
     * Constructor.
145
     */
146
    cEnvir();
147
148
    /**
149
     * Destructor.
150
     */
151
    virtual ~cEnvir();
152
    //@}
153
154
    /** @name Methods to be called by the simulation kernel to notify the environment about events. */
155
    //@{
156
157
    /**
158
     * Notifies the environment that the object no longer exists. The
159
     * user interface should close all inspector windows for the object
160
     * and remove it from object lists currently displayed. cObject's
161
     * destructor automatically calls this function.
162
     */
163
    // note: this cannot be pure virtual, because it has to work even after ev was disposed of
164
    virtual void objectDeleted(cObject *object) {}
165
166
    /**
167
     * Notifies the environment that a component's initialize method is about to be called.
168
     */
169
    virtual void componentInitBegin(cComponent *component, int stage) {}
170
171
    /**
172
     * Notifies the environment that a message was delivered to its destination
173
     * module, that is, a message arrival event occurred. Details can be
174
     * extracted from the message object itself. The user interface
175
     * implementation may use the notification to animate the message on a
176
     * network diagram, to write a log entry, etc.
177
     */
178
    virtual void simulationEvent(cMessage *msg) = 0;
179
180
    /**
181
     * Notifies the environment that a message was sent. Details can be
182
     * extracted from the message object itself. The user interface
183
     * implementation may use the notification to animate the message on a
184
     * network diagram, to write a log entry, etc.
185
     *
186
     * The second argument is non-NULL only when sendDirect() was used, and
187
     * identifies the target gate that was passed to the sendDirect() call.
188
     * (This information is necessary for proper animation: the target gate
189
     * might belong to a compound module and be further connected, and then
190
     * the message will additionally travel through a series of connections
191
     * before it arrives in a simple module.)
192
     */
193
    virtual void messageSent_OBSOLETE(cMessage *msg, cGate *directToGate=NULL) = 0;
194
195
    /**
196
     * Notifies the environment that a message was scheduled.
197
     * @see cSimpleModule::scheduleAt()
198
     */
199
    virtual void messageScheduled(cMessage *msg) = 0;
200
201
    /**
202
     * Notifies the environment that a scheduled message was cancelled.
203
     * @see cSimpleModule::cancelEvent()
204
     */
205
    virtual void messageCancelled(cMessage *msg) = 0;
206
207
    /**
208
     * Notifies the environment that a message is being sent from a
209
     * simple module. beginSend() will be followed by a messageSendDirect()
210
     * (optional, only present when cSimpleModule::sendDirect() was called),
211
     * several messageSendHop() calls (one for each connection in the path),
212
     * and finally an endSend().
213
     */
214
    virtual void beginSend(cMessage *msg) = 0;
215
216
    /** Part of the beginSend() sequence. @see beginSend() */
217
    virtual void messageSendDirect(cMessage *msg, cGate *toGate, simtime_t propagationDelay, simtime_t transmissionDelay) = 0;
218
219
    /** Part of the beginSend() sequence. @see beginSend() */
220
    virtual void messageSendHop(cMessage *msg, cGate *srcGate) = 0;
221
222
    /** Part of the beginSend() sequence. @see beginSend() */
223
    virtual void messageSendHop(cMessage *msg, cGate *srcGate, simtime_t propagationDelay, simtime_t transmissionDelay) = 0;
224
225
    /** Closes a beginSend() sequence. @see beginSend() */
226
    virtual void endSend(cMessage *msg) = 0;
227
228
    /**
229
     * Notifies the environment that a message object is being deleted.
230
     * This is called from the cMessage destructor, so any information added
231
     * to cMessage via subclassing is already lost at the time of the call.
232
     */
233
    virtual void messageDeleted(cMessage *msg) = 0;
234
235
    /**
236
     * Notifies the environment that a module changed parent.
237
     */
238
    virtual void moduleReparented(cModule *module, cModule *oldparent) = 0;
239
240
    /**
241
     * Notifies the environment that one component (module) called a member
242
     * function of another component. This hook enables a graphical user
243
     * interface to animate the method call in the network diagram.
244
     * Pass methodFmt==NULL for Enter_Method_Silent.
245
     */
246
    virtual void componentMethodBegin(cComponent *from, cComponent *to, const char *methodFmt, va_list va, bool silent) = 0;
247
248
    /**
249
     * Notifies the environment that the method entered in the last
250
     * componentMethodBegin() call has exited.
251
     */
252
    virtual void componentMethodEnd() = 0;
253
254
    /**
255
     * Notifies the environment that a module was created. This method is called
256
     * from cModuleType::create(), when the module has already been created
257
     * but buildInside() has not been invoked yet.
258
     */
259
    virtual void moduleCreated(cModule *newmodule) = 0;
260
261
    /**
262
     * Notifies the environment that a module was (more precisely: is being)
263
     * deleted. This method is called from cModule destructor, so the
264
     * "real" type (getClassName() and everything from the actual subclass)
265
     * is already lost at this point, however getName(), getFullName(), getFullPath(),
266
     * gates, parameters (everything that comes from cModule) are still valid.
267
     *
268
     * If a compound module (or a module with dynamically created submodules)
269
     * is deleted, one should not assume anything about the relative order
270
     * moduleDeleted() is called for the module and its submodules.
271
     */
272
    virtual void moduleDeleted(cModule *module) = 0;
273
274
    /**
275
     * Notifies the environment that a gates was created.
276
     */
277
    virtual void gateCreated(cGate *newgate) = 0;
278
279
    /**
280
     * Notifies the environment that a gates was (more precisely: is being)
281
     * deleted.
282
     */
283
    virtual void gateDeleted(cGate *gate) = 0;
284
285
    /**
286
     * Notifies the environment that a connection has been created using
287
     * srcgate->connectTo().
288
     */
289
    virtual void connectionCreated(cGate *srcgate) = 0;
290
291
    /**
292
     * Notifies the environment that a connection has been deleted using
293
     * srcgate->disconnect().
294
     */
295
    virtual void connectionDeleted(cGate *srcgate) = 0;
296
297
    /**
298
     * Notifies the environment that a module or channel display string has
299
     * changed.
300
     */
301
    virtual void displayStringChanged(cComponent *component) = 0;
302
303
    /**
304
     * Called from module destructors, to notify the environment about objects
305
     * that the user did not delete in the module destructor.
306
     */
307
    // Note: this may not be pure virtual, as it may get called even after main()
308
    // exited and StaticEnv was destructed, and we do not want to get a "pure virtual
309
    // method called" error
310
    virtual void undisposedObject(cObject *obj) {}
311
    //@}
312
313
    /** @name Methods called by the simulation kernel to access configuration settings. */
314
    //@{
315
316
    /**
317
     * Called when a module or channel has been created and installed in the model,
318
     * and lets the environment perform extra setup. One use is to add signal
319
     * listeners for result recording.
320
     */
321
    virtual void configure(cComponent *component) = 0;
322
323
    /**
324
     * Assigns the module or channel parameter from the configuration, or
325
     * by asking the user.
326
     */
327
    virtual void readParameter(cPar *parameter) = 0;
328
329
    /**
330
     * Used for parallel distributed simulation. Returns true if the
331
     * named future submodule of parentmod is (or will have any submodule)
332
     * in the local partition, and false otherwise.
333
     *
334
     * Note that for compound modules that contain simple modules in
335
     * several partitions, this function will return true on all those
336
     * partitions.
337
     */
338
    virtual bool isModuleLocal(cModule *parentmod, const char *modname, int index) = 0;
339
340
    /**
341
     * Resolves reference to an XML model configuration file. First argument
342
     * is the file name of the XML document. The optional second argument
343
     * may contain an XPath-like expression to denote an element within
344
     * the XML document. If path is not present, the root element is returned.
345
     *
346
     * See documentation of cXMLElement::getElementByPath() for path syntax.
347
     * There is a difference however: paths starting with "." are not
348
     * accepted, and the first path component must name the root element
349
     * of the document (with getElementByPath() it would match a child element
350
     * of the current element). That is, a leading "/" is always assumed
351
     * at the beginning of the path expression, even if it is not explicitly
352
     * there.
353
     *
354
     * The method throws an exception if the document cannot be found or the
355
     * given path expression is invalid. Returns NULL if the element denoted
356
     * by the path expression does not exist in the document.
357
     *
358
     * The returned object tree should not be modified because cEnvir may
359
     * cache the file and return the same pointer to several callers.
360
     */
361
    virtual cXMLElement *getXMLDocument(const char *filename, const char *path=NULL) = 0;
362
363
    /**
364
     * Removes the given document from the XML document cache (if cached), and
365
     * deletes the object tree from memory. Further getXMLDocument() calls will
366
     * reload the file from the disk. After forgetXMLDocument(), cXMLElement
367
     * objects returned for the same document by getXMLDocument() should
368
     * no longer be referenced. The call has no effect if the given file
369
     * does not exist or has not yet been loaded.
370
     *
371
     * CAUTION: As of version 4.1, this is not a safe operation, as module
372
     * parameters (cPar) of type "xml" hold pointers to the element trees
373
     * returned by getXMLDocument().
374
     */
375
    virtual void forgetXMLDocument(const char *filename) = 0;
376
377
    /**
378
     * Clears the XML document cache, and deletes the cached cXMLElement trees.
379
     *
380
     * CAUTION: As of version 4.1, this is not a safe operation, as module
381
     * parameters (cPar) of type "xml" hold pointers to the element trees
382
     * returned by getXMLDocument(), and this method makes those pointers
383
     * invalid.
384
     */
385
    virtual void flushXMLDocumentCache() = 0;
386
387
    /**
388
     * Called from cSimpleModule, it returns how much extra stack space
389
     * the user interface recommends for activity() simple modules.
390
     */
391
    virtual unsigned getExtraStackForEnvir() const = 0;
392
393
    /**
394
     * Access to the configuration (by default, omnetpp.ini).
395
     * This method is provided here for the benefit of schedulers, parallel
396
     * simulation algorithms and other simulation kernel extensions.
397
     * Models (simple modules) should NOT directly access the configuration --
398
     * they should rely on module parameters to get input.
399
     */
400
    virtual cConfiguration *getConfig() = 0;
401
402
    /**
403
     * Returns the configuration as used by the Envir library. It will throw
404
     * an error if the configuration object does not subclass from cConfigurationEx.
405
     * This method should not be used from the simulation kernel or model code.
406
     */
407
    virtual cConfigurationEx *getConfigEx();
408
    //@}
409
410
    /** @name Input/output methods called from simple modules or the simulation kernel. */
411
    //@{
412
    /**
413
     * Tells if the current environment is graphical or not. (For Tkenv it returns true,
414
     * and with Cmdenv it returns false.) Simple modules can examine this flag
415
     * to decide whether or not they need to bother updating display strings.
416
     */
417
    virtual bool isGUI() const = 0;
418
419
    /**
420
     * Returns true if the simulation is running in an Express or Express-like mode
421
     * where output from <tt>ev&lt;&lt;</tt> and <tt>ev.printf()</tt> statement is
422
     * not printed or logged anywhere but discarded. Model code may make <tt>ev&lt;&lt;</tt>
423
     * statements conditional on this flag to save CPU cycles. For example:
424
     * <pre>
425
     *     if (!ev.isDisabled())  ev << "Packet " << msg->getName() << " received";
426
     * </pre>
427
     *
428
     * which can be abbreviated with the <tt>EV</tt> macro:
429
     *
430
     * <pre>
431
     *     EV << "Packet " << msg->getName() << " received";
432
     * </pre>
433
     */
434
    bool isDisabled() const {return disable_tracing && !record_eventlog;}
435
436
    /**
437
     * Overloaded << operator to make cEnvir behave like an ostream.
438
     * @see getOStream()
439
     */
440
    // implementation note: needed because otherwise the templated version
441
    // would cause ambiguity errors in some cases
442
    cEnvir& operator<<(const std::string& t) {out << t; return *this;}
443
444
    /**
445
     * Overloaded << operator to make cEnvir behave like an ostream.
446
     *
447
     * This method can be used by modules and channels to display debugging output.
448
     * It is up to the user interface implementation to display the text in
449
     * the way it wants. The text is usually associated with the module or channel
450
     * in context (see cSimulation::getContext()), and may get displayed in the
451
     * module's debug window, or enabled/disabled per module.
452
     *
453
     * @see getOStream()
454
     */
455
    template<typename T> cEnvir& operator<<(const T& t) {out << t; return *this;}
456
457
    /**
458
     * Overloaded << operator to handle stream manipulators such as <tt>endl</tt>.
459
     */
460
    cEnvir& operator<<(std::ostream& (t)(std::ostream&)) {out << t; return *this;}
461
462
    /**
463
     * Returns the std::ostream instance where '<<' operators delegate.
464
     * Writes will be eventually delegated to cEnvir::sputn(), after buffering.
465
     */
466
    std::ostream& getOStream() {return out;}
467
468
    /**
469
     * In graphical user interfaces (Tkenv), it pops up a "bubble" over the
470
     * module icon.
471
     */
472
    virtual void bubble(cComponent *component, const char *text) = 0;
473
474
    /**
475
     * Displays the given text in a dialog box. This function should not be
476
     * used by simple modules. Delegates to putsmsg().
477
     */
478
    virtual void printfmsg(const char *fmt,...);
479
480
    /**
481
     * This method can be used by modules and channels to display debugging output.
482
     * It is up to the user interface implementation to display the text in
483
     * the way it wants. The text is usually associated with the module or channel
484
     * in context (see cSimulation::getContext()), and may get displayed in the
485
     * module's debug window, or enabled/disabled per module.
486
     *
487
     * The function's arguments are identical to the standard \<stdio.h\> printf().
488
     * It is recommended to use C++-style I/O (operator<<) instead of this function.
489
     */
490
    // note: non-virtual, delegates to sputn()
491
    virtual int printf(const char *fmt,...);
492
493
    /**
494
     * Flushes the output buffer of ev.printf() and ev<< operations.
495
     * Only some user interfaces need it: it can be useful with Cmdenv which
496
     * writes to the standard output, but no need for it with Tkenv which
497
     * displays all output immediately anyway.
498
     */
499
    virtual cEnvir& flush() = 0;
500
501
    /**
502
     * Interactively prompts the user to enter a string.
503
     */
504
    virtual std::string gets(const char *prompt, const char *defaultreply=NULL) = 0;
505
506
    /**
507
     * Asks the user a yes/no question. The question text is expected
508
     * in printf() format (format string + arguments). The return value
509
     * is true for "yes", and false for "no".
510
     */
511
    // note: non-virtual, delegates to askyesno()
512
    virtual bool askYesNo(const char *fmt,...);
513
    //@}
514
515
    /** @name Access to RNGs. */
516
    //@{
517
518
    /**
519
     * Returns the number of RNGs available for the simulation
520
     * ("num-rngs=" omnetpp.ini setting).
521
     */
522
    virtual int getNumRNGs() const = 0;
523
524
    /**
525
     * Returns pointer to "physical" RNG k (0 <= k < getNumRNGs()).
526
     */
527
    virtual cRNG *getRNG(int k) = 0;
528
529
        /**
530
     * Sets up RNG mapping (which maps module-local RNG numbers to "physical"
531
     * RNGs) for the given module or channel, by calling its setRNGMap() function.
532
     */
533
    virtual void getRNGMappingFor(cComponent *component) = 0;
534
    //@}
535
536
    /** @name Methods for recording data from output vectors.
537
     *
538
     * These are functions cOutVector internally relies on.
539
     *
540
     * The behavior of these functions can be changed by plugging in a different
541
     * cOutputVectorManager object into the user interface library. (Or alternatively,
542
     * by reimplementing the whole cEnvir of course).
543
     */
544
    //@{
545
546
    /**
547
     * This method is intended to be called by cOutVector objects to register
548
     * themselves. The returned value is a handle that identifies the vector
549
     * in subsequent recordInOutputVector() and deregisterOutputVector()
550
     * calls. The handle may have any value (it does not have to be a valid
551
     * pointer), but it should NOT be NULL.
552
     */
553
    virtual void *registerOutputVector(const char *modulename, const char *vectorname) = 0;
554
555
    /**
556
     * cOutVector objects must deregister themselves when they are no longer needed.
557
     */
558
    virtual void deregisterOutputVector(void *vechandle) = 0;
559
560
    /**
561
     * This method is called when an attribute of the output vector is set.
562
     */
563
    virtual void setVectorAttribute(void *vechandle, const char *name, const char *value) = 0;
564
565
    /**
566
     * This method is intended to be called by cOutVector objects to write
567
     * a value into the output vector. The return value is true if the data was
568
     * actually recorded, and false if it was not recorded (because of filtering, etc.)
569
     */
570
    virtual bool recordInOutputVector(void *vechandle, simtime_t t, double value) = 0;
571
    //@}
572
573
    /** @name Scalar statistics.
574
     *
575
     * The method cComponent::recordScalar() function internally relies on.
576
     *
577
     * The behavior of this function can be changed by plugging in a different
578
     * cOutputScalarManager object into the user interface library. (Or alternatively,
579
     * by reimplementing the whole cEnvir of course).
580
     */
581
    //@{
582
583
    /**
584
     * Records a double scalar result, in a default configuration into the scalar result file.
585
     */
586
    virtual void recordScalar(cComponent *component, const char *name, double value, opp_string_map *attributes=NULL) = 0;
587
588
    /**
589
     * Records a statistic object (histogram, etc) into the scalar result file.
590
     * This operation may invoke the transform() method on the histogram object.
591
     */
592
    virtual void recordStatistic(cComponent *component, const char *name, cStatistic *statistic, opp_string_map *attributes=NULL) = 0;
593
    //@}
594
595
    /** @name Management of streams where snapshots can be written.
596
     *
597
     * The behavior of these functions can be changed by plugging in a different
598
     * cSnapshotManager object into the user interface library. (Or alternatively,
599
     * by reimplementing the whole cEnvir of course).
600
     */
601
    //@{
602
603
    /**
604
     * Returns a stream where a snapshot can be written. Called from cSimulation::snapshot().
605
     */
606
    virtual std::ostream *getStreamForSnapshot() = 0;
607
608
    /**
609
     * Releases a stream after a snapshot was written.
610
     */
611
    virtual void releaseStreamForSnapshot(std::ostream *os) = 0;
612
    //@}
613
614
    /** @name Miscellaneous functions. */
615
    //@{
616
    /**
617
     * Access to original command-line arguments.
618
     */
619
    virtual int getArgCount() const = 0;
620
621
    /**
622
     * Access to original command-line arguments.
623
     */
624
    virtual char **getArgVector() const = 0;
625
626
    /**
627
     * Returns the partitionID when parallel simulation is active.
628
     */
629
    virtual int getParsimProcId() const = 0;
630
631
    /**
632
     * Returns the number of partitions when parallel simulation is active;
633
     * otherwise it returns 0.
634
     */
635
    virtual int getParsimNumPartitions() const = 0;
636
637
    /**
638
     * The function underlying cSimulation::getUniqueNumber().
639
     */
640
    virtual unsigned long getUniqueNumber() = 0;
641
642
    /**
643
     * May be called from the simulation while actively waiting
644
     * for some external condition to occur -- for example from
645
     * blocking receive in parallel simulation, or during wait
646
     * in real-time simulation.
647
     *
648
     * In a graphical user interface, this method may take care
649
     * of display redraw and handling user interaction (including
650
     * handling of the Stop button).
651
     *
652
     * Normally returns false. A true value means the user wants to
653
     * abort waiting (e.g. pushed the Stop button).
654
     */
655
    virtual bool idle() = 0;
656
    //@}
657
};
658
659
660
/**
661
 * The interface for cEnvir objects that can be instantiated as a user interface
662
 * like Cmdenv and Tkenv.
663
 *
664
 * @ingroup Envir
665
 * @ingroup EnvirExtensions
666
 */
667
class SIM_API cRunnableEnvir : public cEnvir
668
{
669
  public:
670
    /**
671
     * Runs the user interface. The return value will become the exit code
672
     * of the simulation program.
673
     */
674
    virtual int run(int argc, char *argv[], cConfiguration *cfg) = 0;
675
};
676
677
NAMESPACE_END
678
679
#endif
680