Statistics
| Branch: | Revision:

root / src / sim / util.cc @ 08285dff

History | View | Annotate | Download (14.4 KB)

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

17
  This file is distributed WITHOUT ANY WARRANTY. See the file
18
  `license' for details on this and other legal matters.
19
*--------------------------------------------------------------*/
20
21
#include <time.h>
22
#include <stdio.h>
23
#include <string.h>
24
#include <math.h>
25
#include "commonutil.h"
26
#include "unitconversion.h"
27
#include "opp_ctype.h"
28
#include "simutil.h"
29
#include "cenvir.h"
30
#include "csimulation.h"
31
#include "globals.h"
32
#include "cexception.h"
33
#include "cmathfunction.h"
34
#include "cscheduler.h" // dummy()
35
#include "distrib.h" // dummy()
36
37
NAMESPACE_BEGIN
38
39
#ifdef USE_DOUBLE_SIMTIME
40
//
41
// This function is legacy from OMNeT++ 3.x, and it is only used if simtime_t
42
// is double. It will be removed in the future.
43
//
44
char *simtimeToStr(double t, char *buf)
45
{
46
   // Print simulation time into a string.
47
   // The result has two fields:
48
   //   a)  A real number meaning the sim.time expressed in seconds.
49
   //       Always has (at least) 8 significant digits
50
   //   b)  Time expressed in units such as us,ns,ms,s,m,h,d.
51
   //       The numbers in this field are truncated.
52
   // Conversion method (%f or %e) and lengths were chosen to
53
   // minimize fluctuations in total string length.
54
   // Result is typically 19,20 or 22 chars long.
55
56
   static char buf2[48];
57
   char *b = buf ? buf : buf2;
58
59
   if (t==0.0)
60
       sprintf(b,"0.0000000  ( 0.00s)");
61
   // Note that in the following line, a small constant is added to t
62
   // in order to eliminate truncation errors (like: "1.0000000e-6 (0us)")
63
   else if (t+=1e-16, t<1e-9)
64
       sprintf(b,"%8.8e ( <1ns)", t);
65
   else if (t<1e-6)
66
       sprintf(b,"%8.8e (%3dns)", t,int(t*1e9));
67
   else if (t<1e-3)
68
       sprintf(b,"%8.8e (%3dus)", t,int(t*1e6));
69
   else if (t<1.0)
70
       sprintf(b,"%.10f (%3dms)", t,int(t*1e3));
71
   else if (t<60.0)
72
       sprintf(b,"%8.8g  (%2d.%2.2ds)", t,int(t*100)/100,int(t*100)%100);
73
   else if (t<3600.0)
74
       sprintf(b,"%8.8g (%2dm %2ds)", t,int(t)/60, int(t)%60);
75
   else if (t<86400.0)
76
       sprintf(b,"%8.8g (%2dh %2dm)", t,int(long(t)/3600L), int((long(t)%3600L)/60L));
77
   else if (t<8640000.0)
78
       sprintf(b,"%8.8g (%2dd %2dh)", t,int(t/86400L), int((long(t)%86400L)/3600L));
79
   else
80
       sprintf(b,"%8.8e (%2gd)", t,floor(t/86400L));
81
82
   return b;
83
}
84
85
//
86
// This function is legacy from OMNeT++ 3.x, and it is only used if simtime_t
87
// is double. It will be removed in the future.
88
//
89
char *simtimeToStrShort(double t, char *buf)
90
{
91
   // Print simulation time into a string -- short version.
92
   static char buf2[48];
93
   char *b = buf ? buf : buf2;
94
95
   if (t==0.0)
96
       sprintf(b,"0s");
97
   // Note that in the following line, a small constant is added to t
98
   // in order to eliminate truncation errors (like: "1.0000000e-6 (0us)")
99
   else if (t+=1e-16, t<1e-9)
100
       sprintf(b,"%.5gs", t);
101
   else if (t<1e-6)
102
       sprintf(b,"%.5gns", t*1e9);
103
   else if (t<1e-3)
104
       sprintf(b,"%.5gus", t*1e6);
105
   else if (t<1.0)
106
       sprintf(b,"%.5gms", t*1e3);
107
   else if (t<3600.0)
108
       sprintf(b,"%.5gs", t);
109
   else if (t<86400.0)
110
       sprintf(b,"%dh %dm", int(long(t)/3600L), int((long(t)%3600L)/60L));
111
   else if (t<864000000.0)
112
       sprintf(b,"%dd %dh", int(t/86400L), int((long(t)%86400L)/3600L));
113
   else
114
       sprintf(b,"%.5gs", t);
115
116
   return b;
117
}
118
119
//
120
// This function is legacy from OMNeT++ 3.x, and it is only used if simtime_t
121
// is double. It will be removed in the future.
122
//
123
double strToSimtime(const char *str)
124
{
125
    try {
126
        return UnitConversion::parseQuantity(str, "s");
127
    }
128
    catch (std::exception& e) {
129
        throw cRuntimeError("strToSimtime(): %s", e.what());
130
    }
131
}
132
133
//
134
// This function is legacy from OMNeT++ 3.x, and it is only used if simtime_t
135
// is double. It will be removed in the future.
136
//
137
double strToSimtime0(const char *&str)
138
{
139
    const char *end = str;
140
    while (opp_isspace(*end))
141
        end++;
142
    if (!*end)
143
        return 0.0; // it was just space
144
145
    while (opp_isalnum(*end) || opp_isspace(*end) || *end=='+' || *end=='-' || *end=='.')
146
        end++;
147
    std::string tmp(str, end-str);
148
    str = end;
149
150
    try {
151
        return UnitConversion::parseQuantity(tmp.c_str(), "s");
152
    }
153
    catch (std::exception& e) {
154
        throw cRuntimeError("strToSimtime(): %s", e.what());
155
    }
156
}
157
#endif //USE_DOUBLE_SIMTIME
158
159
char *opp_strprettytrunc(char *dest, const char *src, unsigned maxlen)
160
{
161
    if (!src) {
162
        *dest = '\0';
163
        return dest;
164
    }
165
    strncpy(dest, src, maxlen);
166
    if (strlen(src) > maxlen) {
167
        dest[maxlen] = '\0';
168
        if (maxlen >= 3)
169
            dest[maxlen-1] = dest[maxlen-2] = dest[maxlen-3] = '.';
170
    }
171
    return dest;
172
}
173
174
//----
175
176
#define BUFLEN 512
177
178
void opp_error(OppErrorCode errorcode...)
179
{
180
    char message[BUFLEN];
181
    VSNPRINTF2(message, BUFLEN, errorcode, cErrorMessages::get(errorcode));
182
    throw cRuntimeError(errorcode, message);
183
}
184
185
void opp_error(const char *msgformat...)
186
{
187
    char message[BUFLEN];
188
    VSNPRINTF(message, BUFLEN, msgformat);
189
    throw cRuntimeError(eUSER, message);
190
}
191
192
void opp_warning(OppErrorCode errorcode...)
193
{
194
    char message[BUFLEN];
195
    VSNPRINTF2(message, BUFLEN, errorcode, cErrorMessages::get(errorcode));
196
197
    if (!simulation.getContextModule())
198
    {
199
        // we're called from global context
200
        ev.printfmsg("%s.", message);
201
    }
202
    else
203
    {
204
        ev.printfmsg("Module %s: %s.", simulation.getContextModule()->getFullPath().c_str(), message);
205
    }
206
}
207
208
void opp_warning(const char *msgformat...)
209
{
210
    char message[BUFLEN];
211
    VSNPRINTF(message, BUFLEN, msgformat);
212
213
    if (!simulation.getContextModule())
214
    {
215
        // we're called from global context
216
        ev.printfmsg("%s.", message);
217
    }
218
    else
219
    {
220
        ev.printfmsg("Module %s: %s.", simulation.getContextModule()->getFullPath().c_str(), message);
221
    }
222
}
223
224
void opp_terminate(OppErrorCode errorcode...)
225
{
226
    char message[BUFLEN];
227
    VSNPRINTF2(message, BUFLEN, errorcode, cErrorMessages::get(errorcode));
228
    throw cTerminationException(errorcode,message);
229
}
230
231
void opp_terminate(const char *msgformat...)
232
{
233
    char message[BUFLEN];
234
    VSNPRINTF(message, BUFLEN, msgformat);
235
    throw cTerminationException(message);
236
}
237
238
#undef BUFLEN
239
240
//----
241
242
#ifdef __GNUC__
243
typedef std::map<std::string,std::string> StringMap;
244
static StringMap demangledNames;
245
#endif
246
247
const char *opp_typename(const std::type_info& t)
248
{
249
    if (t == typeid(std::string))
250
        return "std::string"; // otherwise we'd get "std::basic_string<........>"
251
252
    const char *mangledName = t.name();
253
    const char *s = mangledName;
254
255
#ifdef __GNUC__
256
    // gcc's typeinfo returns mangled name:
257
    //   - Foo -> "3Foo"
258
    //   - omnetpp::Foo -> "N7omnetpp3FooE"
259
    //   - omnetpp::inner::Foo -> "N7omnetpp5inner3FooE"
260
    //   - std::runtime_error -> "St13runtime_error"
261
    //   - Foo* -> "P3Foo" (P prefix means pointer)
262
    // http://theoryx5.uwinnipeg.ca/gnu/gcc/gxxint_15.html
263
    // http://www.codesourcery.com/cxx-abi/abi.html#mangling
264
    // libiberty/cp_demangle.c
265
    //
266
    if (*s>='0' && *s<='9')
267
    {
268
        // no namespace: just skip the leading number
269
        while (*s>='0' && *s<='9')
270
            s++;
271
        return s;
272
    }
273
274
    // if we've already seen this name, return cached result
275
    StringMap::const_iterator it = demangledNames.find(mangledName);
276
    if (it == demangledNames.end())
277
    {
278
        // not found -- demangle it and cache the result
279
        std::string result;
280
        std::string prefix, suffix;
281
        if (*s=='P' && *(s+1)=='K') {
282
            // PKx -> "const x *"
283
            prefix = "const ";
284
            suffix = " *";
285
            s += 2;
286
        }
287
        while (true) {
288
            if (*s=='P') suffix += " *";
289
            else if (*s=='K') suffix += " const";
290
            else break;
291
            s++;
292
        }
293
294
        switch (*s) {
295
            case 'v': result = "void"; break;
296
            case 'b': result = "bool"; break;
297
            case 's': result = "short"; break;
298
            case 't': result = "unsigned short"; break;
299
            case 'i': result = "int"; break;
300
            case 'j': result = "unsigned int"; break;
301
            case 'l': result = "long"; break;
302
            case 'm': result = "unsigned long"; break;
303
            case 'f': result = "float"; break;
304
            case 'd': result = "double"; break;
305
            case 'c': result = "char"; break;
306
            case 'a': result = "signed char"; break;
307
            case 'h': result = "unsigned char"; break;
308
            case 'N': {
309
                // mangled name contains namespace: decode it
310
                result.reserve(strlen(s)+8);
311
                s++; // skip leading 'N'
312
                while (*s>='0' && *s<='9') {
313
                    int len = (int)strtol(s, (char **)&s, 10);
314
                    if (!result.empty()) result += "::";
315
                    result.append(s, len);
316
                    s += len;
317
                }
318
                break;
319
            }
320
            case 'S': {
321
                // probably std::something, e.g. "St13runtime_error"
322
                switch (s[1]) {
323
                    // some "Sx" prefixes are special abbreviations
324
                    case 'a': result = "std::allocator"; break;
325
                    case 'b': result = "std::basic_string"; break;
326
                    case 's': result = "std::string"; break;
327
                    case 'i': result = "std::istream"; break;
328
                    case 'o': result = "std::ostream"; break;
329
                    case 'd': result = "std::iostream"; break;
330
                    case 't':
331
                        // "St" -> std::
332
                        s+=2;
333
                        result.reserve(strlen(s)+8);
334
                        result.append("std");
335
                        while (opp_isalpha(*s)) s++; // skip possible other modifiers
336
                        while (*s>='0' && *s<='9') {
337
                            int len = (int)strtol(s, (char **)&s, 10);
338
                            if (!result.empty()) result += "::";
339
                            result.append(s, len);
340
                            s += len;
341
                        }
342
                        break;
343
                }
344
                break;
345
            }
346
            default: {
347
                if (*s>='0' && *s<='9') {
348
                    // no namespace: just skip the leading number
349
                    while (*s>='0' && *s<='9')
350
                        s++;
351
                    result = s;
352
                }
353
                else {
354
                    // dunno how to interpret it, just return it unchanged
355
                    result = s;
356
                }
357
            }
358
        }
359
360
        demangledNames[mangledName] = prefix + result + suffix;
361
        it = demangledNames.find(mangledName);
362
    }
363
    return it->second.c_str();
364
#else
365
    // MSVC prepends the string with "class " (possibly other compilers too)
366
    if (s[0]=='c' && s[1]=='l' && s[2]=='a' && s[3]=='s' && s[4]=='s' && s[5]==' ')
367
        s+=6;
368
    else if (s[0]=='s' && s[1]=='t' && s[2]=='r' && s[3]=='u' && s[4]=='c' && s[5]=='t' && s[6]==' ')
369
        s+=7;
370
    else if (s[0]=='e' && s[1]=='n' && s[2]=='u' && s[3]=='m' && s[4]==' ')
371
        s+=5;
372
    return s;
373
#endif
374
}
375
376
//----
377
378
cContextSwitcher::cContextSwitcher(const cComponent *newContext)
379
{
380
    // save current context and switch to new
381
    callerContext = simulation.getContext();
382
    simulation.setContext(const_cast<cComponent *>(newContext));
383
}
384
385
cContextSwitcher::~cContextSwitcher()
386
{
387
    // restore old context
388
    if (!callerContext)
389
        simulation.setGlobalContext();
390
    else
391
        simulation.setContext(callerContext);
392
}
393
394
//----
395
396
static va_list dummy_va;
397
398
cMethodCallContextSwitcher::cMethodCallContextSwitcher(const cComponent *newContext) :
399
  cContextSwitcher(newContext)
400
{
401
}
402
403
void cMethodCallContextSwitcher::methodCall(const char *methodFmt,...)
404
{
405
    cComponent *newContext = simulation.getContext();
406
    if (newContext!=callerContext)
407
    {
408
        va_list va;
409
        va_start(va, methodFmt);
410
        EVCB.componentMethodBegin(callerContext, newContext, methodFmt, va, false);
411
        va_end(va);
412
    }
413
}
414
415
void cMethodCallContextSwitcher::methodCallSilent(const char *methodFmt,...)
416
{
417
    cComponent *newContext = simulation.getContext();
418
    if (newContext!=callerContext)
419
    {
420
        va_list va;
421
        va_start(va, methodFmt);
422
        EVCB.componentMethodBegin(callerContext, newContext, methodFmt, va, true);
423
        va_end(va);
424
    }
425
}
426
427
void cMethodCallContextSwitcher::methodCallSilent()
428
{
429
    cComponent *newContext = simulation.getContext();
430
    if (newContext!=callerContext)
431
        EVCB.componentMethodBegin(callerContext, newContext, NULL, dummy_va, true);
432
}
433
434
cMethodCallContextSwitcher::~cMethodCallContextSwitcher()
435
{
436
    cComponent *methodContext = simulation.getContext();
437
    if (methodContext!=callerContext)
438
        EVCB.componentMethodEnd();
439
}
440
441
//----
442
443
cContextTypeSwitcher::cContextTypeSwitcher(int contexttype)
444
{
445
    // save current context type and switch to new one
446
    savedcontexttype = simulation.getContextType();
447
    simulation.setContextType(contexttype);
448
}
449
450
cContextTypeSwitcher::~cContextTypeSwitcher()
451
{
452
    simulation.setContextType(savedcontexttype);
453
}
454
455
NAMESPACE_END
456
457
//----
458
// dummy function to force over-optimizing Unix linkers to include these symbols
459
// in the library
460
461
#include "cwatch.h"
462
#include "cstlwatch.h"
463
#include "clcg32.h"
464
#include "cmersennetwister.h"
465
#include "cksplit.h"
466
#include "cpsquare.h"
467
#include "cstringtokenizer.h"
468
#include "cxmlelement.h"
469
#include "cdelaychannel.h"
470
#include "cdataratechannel.h"
471
#include "cpacketqueue.h"
472
473
USING_NAMESPACE
474
475
//void _dummy_for_env();
476
void std_sim_descriptor_dummy();
477
void nedfunctions_dummy();
478
void _sim_dummy_func()
479
{
480
      bool bb;
481
      cWatch_bool w(NULL,bb);
482
      std::vector<int> v;
483
      WATCH_VECTOR(v);
484
      w.supportsAssignment();
485
      exponential(1.0);
486
      cSequentialScheduler sch;
487
      (void)sch;
488
      cLCG32 lcg;
489
      lcg.intRand();
490
      cMersenneTwister mt;
491
      mt.intRand();
492
      cKSplit ks;
493
      ks.info();
494
      cPSquare ps;
495
      ps.info();
496
      cStringTokenizer tok("");
497
      tok.nextToken();
498
      std_sim_descriptor_dummy();
499
      cXMLElement a(0,0,0);
500
      (void)a;
501
      cDelayChannel dc(NULL);
502
      (void)dc;
503
      cDatarateChannel c(NULL);
504
      (void)c;
505
      cPacketQueue pq;
506
      (void)pq;
507
      nedfunctions_dummy();
508
      //_dummy_for_env();
509
}