Statistics
| Branch: | Revision:

root / src / sim / cmsgpar.cc @ e26d3d25

History | View | Annotate | Download (25.6 KB)

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

15
  This file is distributed WITHOUT ANY WARRANTY. See the file
16
  `license' for details on this and other legal matters.
17
*--------------------------------------------------------------*/
18
19
#include <locale.h>
20
#include <math.h>
21
#include <string.h>
22
#include <stdio.h>
23
#include <stdlib.h>
24
#include <string>
25
#include "opp_ctype.h"
26
#include "cmsgpar.h"
27
#include "cstatistic.h"
28
#include "globals.h"
29
#include "cmathfunction.h"
30
#include "cnedfunction.h"
31
#include "cxmlelement.h"
32
#include "cconfiguration.h"
33
#include "cenvir.h"
34
#include "cexception.h"
35
#include "csimulation.h"
36
37
#ifdef WITH_PARSIM
38
#include "ccommbuffer.h"
39
#endif
40
41
USING_NAMESPACE
42
43
using std::ostream;
44
using std::string;
45
46
47
Register_Class(cMsgPar);
48
49
const char *cMsgPar::possibletypes = "SBLDFTP";
50
51
static const char *getTypeName(char typechar)
52
{
53
    switch (typechar)
54
    {
55
        case 'S': return "string (S)";
56
        case 'B': return "bool (B)";
57
        case 'L': return "long (L)";
58
        case 'D': return "double (D)";
59
        case 'F': return "function with constant args (F)";
60
        case 'T': return "random number from distribution (T)";
61
        case 'P': return "pointer (P)";
62
        case 'M': return "XML element (M)";
63
        default:  return "invalid type char";
64
    }
65
}
66
67
cMsgPar::cMsgPar(const char *name) : cOwnedObject(name)
68
{
69
    tkownership = false;
70
    changedflag = false;
71
    typechar = 'L';
72
    lng.val = 0L;
73
}
74
75
cMsgPar::cMsgPar(const cMsgPar& par) : cOwnedObject()
76
{
77
    tkownership = false;
78
    changedflag = false;
79
    typechar = 'L';
80
    lng.val = 0L;
81
82
    setName( par.getName() );
83
    cMsgPar::operator=(par);
84
}
85
86
cMsgPar::cMsgPar(const char *name, cMsgPar& other) : cOwnedObject(name)
87
{
88
    tkownership = false;
89
    changedflag = false;
90
    typechar = 'L';
91
    lng.val = 0L;
92
93
    setName(name);
94
    operator=(other);
95
}
96
97
cMsgPar::~cMsgPar()
98
{
99
    beforeChange();
100
    deleteOld();
101
}
102
103
void cMsgPar::deleteOld()
104
{
105
    if (typechar=='S' && !ls.sht)
106
    {
107
        delete [] ls.str;
108
    }
109
    else if (typechar=='T')
110
    {
111
        if (dtr.res->getOwner()==this)
112
            dropAndDelete(dtr.res);
113
    }
114
    else if (typechar=='P')
115
    {
116
        if (ptr.dupfunc || ptr.itemsize>0) // we're expected to do memory mgmt
117
        {
118
            if (ptr.delfunc)
119
                ptr.delfunc(ptr.ptr);
120
            else
121
                delete [] (char *)ptr.ptr;  // cast because delete void* is not legal
122
        }
123
    }
124
    else if (typechar=='O')
125
    {
126
        if (obj.obj->getOwner()==this)
127
            dropAndDelete(obj.obj);
128
    }
129
    typechar = 'L';
130
}
131
132
//----------------------------------------------------------------------
133
// redefine virtual cOwnedObject funcs
134
135
std::string cMsgPar::info() const
136
{
137
    std::stringstream out;
138
139
    // append useful info
140
    cMathFunction *ff;
141
    const char *s;
142
    switch (typechar) {
143
        case 'S': s = ls.sht ? ss.str:ls.str;
144
                  if (!s) s = "";
145
                  out << "\"" << s << "\" (S)";
146
                  break;
147
        case 'L': out << lng.val << " (L)"; break;
148
        case 'D': out << dbl.val << " (D)"; break;
149
        case 'T': out << (dtr.res ? dtr.res->getFullPath().c_str():"null") << " (T)"; break;
150
        case 'P': out << ptr.ptr << " (P)"; break;
151
        case 'O': out << (obj.obj ? obj.obj->getFullPath().c_str():"null") << " (O)"; break;
152
        case 'F': ff = cMathFunction::findByPointer(func.f);
153
                  out << (ff ? ff->getName() : "unknown") << "(";
154
                  switch(func.argc) {
155
                    case 0: out << ")"; break;
156
                    case 1: out << func.p1; break;
157
                    case 2: out << func.p1 << "," << func.p2; break;
158
                    case 3: out << func.p1 << "," << func.p2 << "," << func.p3; break;
159
                    case 4: out << func.p1 << "," << func.p2 << "," << func.p3 << "," << func.p4; break;
160
                    default:out << ") with " << func.argc << " args"; break;
161
                  };
162
                  out << " (F)";
163
                  break;
164
        case 'B': out << (lng.val?"true":"false") << " (B)"; break;
165
        case 'M': if (xmlp.node)
166
                      out << "<" << xmlp.node->getTagName() << "> from " << xmlp.node->getSourceLocation() << " (M)";
167
                  else
168
                      out << "null (M)";
169
                  break;
170
        default : out << "? (unknown type)"; break;
171
    }
172
    return out.str();
173
}
174
175
std::string cMsgPar::detailedInfo() const
176
{
177
    std::stringstream os;
178
    os << "  Type:  " << typechar << '\n';
179
    os << "  Value: " << str().c_str() << '\n';
180
    return os.str();
181
}
182
183
void cMsgPar::forEachChild(cVisitor *v)
184
{
185
    if (typechar=='T')
186
    {
187
        v->visit(dtr.res);
188
    }
189
    else if (typechar=='O')
190
    {
191
        if (obj.obj)
192
            v->visit(obj.obj);
193
    }
194
}
195
196
void cMsgPar::parsimPack(cCommBuffer *buffer)
197
{
198
#ifndef WITH_PARSIM
199
    throw cRuntimeError(this,eNOPARSIM);
200
#else
201
    cOwnedObject::parsimPack(buffer);
202
203
    // For error checking & handling
204
    if (typechar != 'S' && typechar != 'L' && typechar != 'D'
205
        && typechar != 'F' && typechar != 'T' && typechar != 'P'
206
        && typechar != 'O' && typechar != 'M')
207
    {
208
        throw cRuntimeError(this,"parsimPack: unsupported type '%c'",typechar);
209
    }
210
211
    buffer->pack(typechar);
212
    buffer->pack(changedflag);
213
214
    cMathFunction *ff;
215
    switch (typechar)
216
    {
217
    case 'S':
218
        buffer->pack(ls.sht);
219
        if (ls.sht)
220
            buffer->pack(ls.str, sizeof(ls.str));
221
        else
222
            buffer->pack(ss.str);
223
        break;
224
225
    case 'L':
226
        buffer->pack(lng.val);
227
        break;
228
229
    case 'D':
230
        buffer->pack(dbl.val);
231
        break;
232
233
    case 'F':
234
        ff = cMathFunction::findByPointer(func.f);
235
        if (ff == NULL)
236
            throw cRuntimeError(this,"parsimPack(): cannot transmit unregistered function");
237
238
        buffer->pack(ff->getName());
239
        buffer->pack(func.argc);
240
        buffer->pack(func.p1);
241
        buffer->pack(func.p2);
242
        buffer->pack(func.p3);
243
        buffer->pack(func.p4);
244
        break;
245
246
    case 'T':
247
        if (dtr.res && dtr.res->getOwner() != this)
248
            throw cRuntimeError(this,"parsimPack(): cannot transmit pointer to \"external\" object");
249
        if (buffer->packFlag(dtr.res!=NULL))
250
            buffer->packObject(dtr.res);
251
        break;
252
253
    case 'P':
254
        throw cRuntimeError(this,"parsimPack(): cannot transmit pointer to unknown data structure (type 'P')");
255
256
    case 'O':
257
        if (obj.obj && obj.obj->getOwner() != this)
258
            throw cRuntimeError(this,"parsimPack(): cannot transmit pointer to \"external\" object");
259
        if (buffer->packFlag(obj.obj!=NULL))
260
            buffer->packObject(obj.obj);
261
        break;
262
263
    case 'M':
264
        throw cRuntimeError(this,"parsimPack(): cannot transmit pointer to XML element (type 'M')");
265
    }
266
#endif
267
}
268
269
void cMsgPar::parsimUnpack(cCommBuffer *buffer)
270
{
271
#ifndef WITH_PARSIM
272
    throw cRuntimeError(this,eNOPARSIM);
273
#else
274
    char *funcname;
275
    int argc;
276
277
    cOwnedObject::parsimUnpack(buffer);
278
279
    buffer->unpack(typechar);
280
    buffer->unpack(changedflag);
281
282
    cMathFunction *ff;
283
    switch (typechar)
284
    {
285
    case 'S':
286
        buffer->unpack(ls.sht);
287
        ss.sht = ls.sht;
288
        if (ls.sht)
289
            buffer->unpack(ss.str, sizeof(ls.str));
290
        else
291
            buffer->unpack(ls.str);
292
        break;
293
294
    case 'L':
295
        buffer->unpack(lng.val);
296
        break;
297
298
    case 'D':
299
        buffer->unpack(dbl.val);
300
        break;
301
302
    case 'F':
303
        buffer->unpack(funcname);
304
        buffer->unpack(argc);
305
        ff = cMathFunction::find(funcname,argc);
306
        if (ff == NULL)
307
        {
308
            delete [] funcname;
309
            throw cRuntimeError(this,"parsimUnpack(): transmitted function `%s' with %d args not registered here",
310
                                    funcname, argc);
311
        }
312
        func.f = ff->getMathFunc();
313
        func.argc = argc;
314
        buffer->unpack(func.p1);
315
        buffer->unpack(func.p2);
316
        buffer->unpack(func.p3);
317
        buffer->unpack(func.p4);
318
        delete [] funcname;
319
        break;
320
321
    case 'T':
322
        if (!buffer->checkFlag())
323
            dtr.res = NULL;
324
        else
325
            take(dtr.res = (cStatistic *) buffer->unpackObject());
326
        break;
327
328
    case 'P':
329
    case 'M':
330
        throw cRuntimeError(this,"parsimUnpack(): unpacking types I, P, M not implemented");
331
332
    case 'O':
333
        if (!buffer->checkFlag())
334
            obj.obj = NULL;
335
        else
336
            take(obj.obj = dynamic_cast<cOwnedObject *>(buffer->unpackObject()));
337
        break;
338
    }
339
#endif
340
}
341
342
//----
343
344
char cMsgPar::getType() const
345
{
346
     return typechar;
347
}
348
349
bool cMsgPar::hasChanged()
350
{
351
     bool ch = changedflag;
352
     changedflag=false;
353
     return ch;
354
}
355
356
//----
357
358
cMsgPar& cMsgPar::setStringValue(const char *s)
359
{
360
     beforeChange();
361
     deleteOld();
362
     typechar = 'S';
363
     if (!s)
364
         {ls.sht=true; *ss.str='\0';}
365
     else if ((ls.sht=(strlen(s)<=SHORTSTR_MAXLEN))!=0)
366
         strcpy(ss.str, s);
367
     else
368
         ls.str = opp_strdup(s);
369
     afterChange();
370
     return *this;
371
}
372
373
cMsgPar& cMsgPar::setBoolValue(bool b)
374
{
375
    beforeChange();
376
    deleteOld();
377
    lng.val = b;
378
    typechar = 'B';
379
    afterChange();
380
    return *this;
381
}
382
383
cMsgPar& cMsgPar::setLongValue(long l)
384
{
385
    beforeChange();
386
    deleteOld();
387
    lng.val = l;
388
    typechar = 'L';
389
    afterChange();
390
    return *this;
391
}
392
393
cMsgPar& cMsgPar::setDoubleValue(double d)
394
{
395
    beforeChange();
396
    deleteOld();
397
    dbl.val = d;
398
    typechar = 'D';
399
    afterChange();
400
    return *this;
401
}
402
403
cMsgPar& cMsgPar::setDoubleValue(MathFuncNoArg f)
404
{
405
    beforeChange();
406
    deleteOld();
407
    func.f = (MathFunc)f;
408
    func.argc=0;
409
    typechar = 'F';
410
    afterChange();
411
    return *this;
412
}
413
414
cMsgPar& cMsgPar::setDoubleValue(MathFunc1Arg f, double p1)
415
{
416
    beforeChange();
417
    deleteOld();
418
    func.f = (MathFunc)f;
419
    func.argc=1;
420
    func.p1 = p1;
421
    typechar = 'F';
422
    afterChange();
423
    return *this;
424
}
425
426
cMsgPar& cMsgPar::setDoubleValue(MathFunc2Args f, double p1, double p2)
427
{
428
    beforeChange();
429
    deleteOld();
430
    func.f = (MathFunc)f;
431
    func.argc=2;
432
    func.p1 = p1;
433
    func.p2 = p2;
434
    typechar = 'F';
435
    afterChange();
436
    return *this;
437
}
438
439
cMsgPar& cMsgPar::setDoubleValue(MathFunc3Args f, double p1, double p2, double p3)
440
{
441
    beforeChange();
442
    deleteOld();
443
    func.f = (MathFunc)f;
444
    func.argc=3;
445
    func.p1 = p1;
446
    func.p2 = p2;
447
    func.p3 = p3;
448
    typechar = 'F';
449
    afterChange();
450
    return *this;
451
}
452
453
cMsgPar& cMsgPar::setDoubleValue(MathFunc4Args f, double p1, double p2, double p3, double p4)
454
{
455
    beforeChange();
456
    deleteOld();
457
    func.f = (MathFunc)f;
458
    func.argc=4;
459
    func.p1 = p1;
460
    func.p2 = p2;
461
    func.p3 = p3;
462
    func.p4 = p4;
463
    typechar = 'F';
464
    afterChange();
465
    return *this;
466
}
467
468
cMsgPar& cMsgPar::setDoubleValue(cStatistic *res)
469
{
470
    if (!res)
471
        throw cRuntimeError(this,eBADINIT,getTypeName('T'));
472
473
    beforeChange();
474
    deleteOld();
475
    dtr.res = res;
476
    if (getTakeOwnership())
477
       take(res);
478
    typechar = 'T';
479
    afterChange();
480
    return *this;
481
}
482
483
cMsgPar& cMsgPar::setPointerValue(void *_ptr)
484
{
485
    beforeChange();
486
    // if it was a 'P' before, keep previous configuration
487
    if (typechar!='P')
488
    {
489
        deleteOld();
490
        ptr.delfunc=NULL;
491
        ptr.dupfunc=NULL;
492
        ptr.itemsize=0;
493
        typechar = 'P';
494
    }
495
    ptr.ptr = _ptr;
496
    afterChange();
497
    return *this;
498
}
499
500
cMsgPar& cMsgPar::setObjectValue(cOwnedObject *_obj)
501
{
502
    beforeChange();
503
    deleteOld();
504
    obj.obj = _obj;
505
    if (getTakeOwnership())
506
        take( _obj );
507
    typechar = 'O';
508
    afterChange();
509
    return *this;
510
}
511
512
cMsgPar& cMsgPar::setXMLValue(cXMLElement *node)
513
{
514
    beforeChange();
515
    deleteOld();
516
    xmlp.node = node;
517
    typechar = 'M';
518
    afterChange();
519
    return *this;
520
}
521
522
void cMsgPar::configPointer( VoidDelFunc delfunc, VoidDupFunc dupfunc,
523
                      size_t itemsize)
524
{
525
    if (typechar!='P')
526
        throw cRuntimeError(this,"configPointer(): type is '%c'; should be 'P'",typechar);
527
    ptr.delfunc = delfunc;
528
    ptr.dupfunc = dupfunc;
529
    ptr.itemsize = itemsize;
530
}
531
532
//----
533
534
const char *cMsgPar::stringValue()
535
{
536
    if (typechar!='S')
537
        throw cRuntimeError(this,eBADCAST,getTypeName(typechar),getTypeName('S'));
538
    return ss.sht ? ss.str : ls.str;
539
}
540
541
//
542
// Note:
543
// boolValue(), longValue() and doubleValue() are rather liberal: they all
544
// allow conversion from all of B,L and the double types D,T,F.
545
//
546
547
bool cMsgPar::boolValue()
548
{
549
    if (typechar=='B' || typechar=='L')
550
        return lng.val!=0;
551
    else if (isNumeric())
552
        return doubleValue()!=0;
553
    else
554
        throw cRuntimeError(this,eBADCAST,getTypeName(typechar),getTypeName('B'));
555
}
556
557
inline long _double_to_long(double d)
558
{
559
    // gcc 3.3 "feature": if double d=0xc0000000, (long)d yields 0x80000000!!!
560
    // This causes trouble if we in fact want to cast this long to unsigned long, see NED_expr_2.test.
561
    // Workaround follows. Note: even the ul variable is needed: when inlining it, gcc will do the wrong cast!
562
    long l = (long)d;
563
    unsigned long ul = (unsigned long)d;
564
    return d<0 ? l : ul;
565
}
566
567
long cMsgPar::longValue()
568
{
569
    if (typechar=='L' || typechar=='B')
570
        return lng.val;
571
    else if (isNumeric())
572
        return _double_to_long(doubleValue());
573
    else
574
        throw cRuntimeError(this,eBADCAST,getTypeName(typechar),getTypeName('L'));
575
}
576
577
double cMsgPar::doubleValue()
578
{
579
    if (typechar=='B' || typechar=='L')
580
        return (double)lng.val;
581
    else if (typechar=='D')
582
        return dbl.val;
583
    else if (typechar=='T')
584
        return getFromstat();
585
    else if (typechar=='F')
586
        return func.argc==0 ? ((MathFuncNoArg)func.f)() :
587
               func.argc==1 ? ((MathFunc1Arg) func.f)(func.p1) :
588
               func.argc==2 ? ((MathFunc2Args)func.f)(func.p1,func.p2) :
589
               func.argc==3 ? ((MathFunc3Args)func.f)(func.p1,func.p2,func.p3) :
590
                              ((MathFunc4Args)func.f)(func.p1,func.p2,func.p3,func.p4);
591
    else
592
        throw cRuntimeError(this,eBADCAST,getTypeName(typechar),getTypeName('D'));
593
}
594
595
void *cMsgPar::pointerValue()
596
{
597
    if (typechar=='P')
598
        return ptr.ptr;
599
    else
600
        throw cRuntimeError(this,eBADCAST,getTypeName(typechar),getTypeName('P'));
601
}
602
603
cOwnedObject *cMsgPar::getObjectValue()
604
{
605
    if (typechar=='O')
606
        return obj.obj;
607
    else
608
        throw cRuntimeError(this,eBADCAST,getTypeName(typechar),getTypeName('O'));
609
}
610
611
cXMLElement *cMsgPar::xmlValue()
612
{
613
    if (typechar=='M')
614
        return xmlp.node;
615
    else
616
        throw cRuntimeError(this,eBADCAST,getTypeName(typechar),getTypeName('M'));
617
}
618
619
bool cMsgPar::isNumeric() const
620
{
621
    return typechar=='B' ||
622
           typechar=='L' ||
623
           typechar=='D' ||
624
           typechar=='T' ||
625
           typechar=='F';
626
}
627
628
bool cMsgPar::isConstant() const
629
{
630
    return typechar=='S' ||
631
           typechar=='B' ||
632
           typechar=='L' ||
633
           typechar=='D';
634
}
635
636
bool cMsgPar::equalsTo(cMsgPar *par)
637
{
638
    if (typechar != par->typechar)
639
        return false;
640
641
    switch (typechar) {
642
        case 'S': return strcmp(stringValue(),par->stringValue())==0;
643
        case 'B': return lng.val == par->lng.val;
644
        case 'L': return lng.val == par->lng.val;
645
        case 'D': return dbl.val == par->dbl.val;
646
        case 'F': if (func.f!=par->func.f) return 0;
647
                  switch(func.argc) {
648
                      case 4: if (func.p4!=par->func.p4) return 0; // no break
649
                      case 3: if (func.p3!=par->func.p3) return 0; // no break
650
                      case 2: if (func.p2!=par->func.p2) return 0; // no break
651
                      case 1: if (func.p1!=par->func.p1) return 0; // no break
652
                  }
653
                  return 1;
654
        case 'T': return dtr.res == par->dtr.res;
655
        case 'P': return ptr.ptr == par->ptr.ptr;
656
        case 'O': return obj.obj == par->obj.obj;
657
        case 'M': return xmlp.node == par->xmlp.node;
658
        default: return 0;
659
    }
660
}
661
662
//----
663
664
void cMsgPar::beforeChange()
665
{
666
}
667
668
void cMsgPar::afterChange()
669
{
670
    changedflag=true;
671
}
672
673
string cMsgPar::str() const
674
{
675
    char bb[128];
676
    bb[0] = 0;
677
    cMathFunction *ff;
678
    const char *fn;
679
    const char *s;
680
681
    switch (typechar)
682
    {
683
       case 'S': s = ls.sht ? ss.str:ls.str;
684
                 return string("\"")+s+"\"";
685
       case 'B': return string(lng.val?"true":"false");
686
       case 'L': sprintf(bb,"%ld",lng.val);
687
                 return string(bb);
688
       case 'D': sprintf(bb,"%g",dbl.val);
689
                 return string(bb);
690
       case 'F': ff = cMathFunction::findByPointer(func.f);
691
                 fn = ff ? ff->getName() : "unknown";
692
                 switch(func.argc) {
693
                 case 0: sprintf(bb,"()"); break;
694
                 case 1: sprintf(bb,"(%g)",func.p1); break;
695
                 case 2: sprintf(bb,"(%g,%g)",func.p1,func.p2); break;
696
                 case 3: sprintf(bb,"(%g,%g,%g)",func.p1,func.p2,func.p3); break;
697
                 case 4: sprintf(bb,"(%g,%g,%g,%g)",func.p1,func.p2,func.p3,func.p4); break;
698
                 default: sprintf(bb,"() with %d args",func.argc); break;
699
                 };
700
                 return string(fn)+bb;
701
       case 'T': return string("distribution ")+(dtr.res?dtr.res->getFullPath().c_str():"NULL");
702
       case 'P': sprintf(bb,"pointer %p", ptr.ptr); return string(bb);
703
       case 'O': return string("object ")+(obj.obj?obj.obj->getFullPath().c_str():"NULL");
704
       case 'M': if (xmlp.node)
705
                     return string("<")+xmlp.node->getTagName()+"> from "+xmlp.node->getSourceLocation();
706
                 else
707
                     return string("NULL");
708
                 break;
709
       default : return string("???");
710
    }
711
}
712
713
static bool parseQuotedString(string& str, const char *&s)  //FIXME use opp_parsequotedstr() instead!
714
{
715
    while (*s==' ' || *s=='\t') s++;
716
    if (*s!='"') return false;
717
    const char *beg = ++s;
718
    while (*s && (*s!='"' || *(s-1)=='\\'))
719
        s++;
720
    if (*s!='"') return false;
721
    str.assign(beg, s-beg);
722
    s++;
723
    return true;
724
}
725
726
bool cMsgPar::parse(const char *text, char tp)
727
{
728
    tp = (char) opp_toupper(tp);
729
730
    // create a working copy and cut whitespaces (from both sides)
731
    if (!text) return false;  // error: no string
732
    while (*text==' ' || *text=='\t') text++;
733
    if (*text=='\0') return false; // error: empty string (or only whitespace)
734
    char *tmp = opp_strdup(text);
735
    char *s = tmp+strlen(tmp)-1;
736
    while (s>=tmp && (*s==' ' || *s=='\t')) *s--='\0';
737
738
    if (strcmp(tmp,"true")==0 || strcmp(tmp,"TRUE")==0 || strcmp(tmp,"True")==0) // bool?
739
    {
740
        if (!strchr("?B",tp)) goto error;
741
        setBoolValue(true);
742
    }
743
    else if (strcmp(tmp,"false")==0 || strcmp(tmp,"FALSE")==0 || strcmp(tmp,"False")==0) // bool?
744
    {
745
        if (!strchr("?B",tp)) goto error;
746
        setBoolValue(false);
747
    }
748
    else if (strcmp(tmp,"1")==0 && tp=='B') // bool?
749
    {
750
        setBoolValue(true);
751
    }
752
    else if (strcmp(tmp,"0")==0 && tp=='B') // bool?
753
    {
754
        setBoolValue(false);
755
    }
756
    else if (tmp[0]=='\'' && tmp[1] && tmp[2]=='\''&& !tmp[3]) // char? (->long)
757
    {
758
        if (!strchr("?L",tp)) goto error;
759
        setLongValue((long)tmp[1]);
760
    }
761
    else if (text[0]=='\"') // string?
762
    {
763
        if (!strchr("?S",tp)) goto error;
764
765
        // check closing quote
766
        if (!tmp[1] || tmp[strlen(tmp)-1]!='\"') goto error;  //FIXME use opp_parsequotedstr() and catch exception
767
768
        tmp[strlen(tmp)-1] = '\0'; // cut off closing quote
769
        setStringValue(tmp+1);
770
    }
771
    else if (strspn(tmp,"+-0123456789")==strlen(tmp)) // long?
772
    {
773
        long num;
774
        int len;
775
        if (0==sscanf(tmp,"%ld%n",&num,&len)) goto error;
776
        if (len < (int)strlen(tmp) || !strchr("?LD",tp)) goto error;
777
        if (tp=='?' || tp=='L')
778
           setLongValue(num);
779
        else
780
           setDoubleValue(num);
781
    }
782
    else if (strspn(tmp,"+-.eE0123456789")==strlen(tmp)) // double?
783
    {
784
        double num;
785
        int len;
786
        setlocale(LC_NUMERIC, "C");
787
        if (0==sscanf(tmp,"%lf%n",&num,&len)) goto error;
788
        if (len < (int)strlen(tmp) || !strchr("?D",tp)) goto error;
789
        setDoubleValue(num);
790
    }
791
    else if (!strncmp(tmp,"xmldoc",6))
792
    {
793
        if (!strchr("?M",tp)) goto error;
794
795
        // parse xmldoc("filename") or xmldoc("filename", "pathexpr")
796
        const char *s=tmp;
797
        s+=6;  // skip "xmldoc"
798
        while (*s==' ' || *s=='\t') s++;
799
        if (*s!='(') goto error;  // no "("
800
        s++; // skip "("
801
        std::string fname, pathexpr;
802
        while (*s==' ' || *s=='\t') s++;
803
        if (!parseQuotedString(fname, s)) goto error;
804
        while (*s==' ' || *s=='\t') s++;
805
        if (*s!=',' && *s!=')') goto error;  // no ")" or ","
806
        if (*s==',')
807
        {
808
            s++;  // skip ","
809
            if (!parseQuotedString(pathexpr, s)) goto error;
810
            while (*s==' ' || *s=='\t') s++;
811
            if (*s!=')') goto error;  // no ")"
812
        }
813
        s++; // skip ")"
814
        while (*s==' ' || *s=='\t') s++;
815
        if (*s) goto error;  // trailing rubbish
816
817
        cXMLElement *node = ev.getXMLDocument(fname.c_str(), pathexpr.empty() ? NULL : pathexpr.c_str());
818
        if (!node)
819
            throw cRuntimeError(this,"%s: element not found", tmp);
820
        setXMLValue(node);
821
    }
822
    else // maybe function; try to parse it
823
    {
824
        if (!strchr("?F",tp)) goto error;
825
        if (!setfunction(tmp)) goto error;
826
    }
827
828
    delete [] tmp;
829
    return true;
830
831
    error:
832
    delete [] tmp;
833
    return false;
834
}
835
836
static double parsedbl(const char *&s)
837
{
838
    while (*s==' ' || *s=='\t') s++;
839
    int len = 0;
840
    double num = 0;
841
    setlocale(LC_NUMERIC, "C");
842
    sscanf(s, "%lf%n", &num, &len);
843
    s += len;
844
    while (*s==' ' || *s=='\t') s++;
845
    return num;
846
}
847
848
849
bool cMsgPar::setfunction(char *text)
850
{
851
    // Note: this function *will* alter its input string
852
853
    // find '('
854
    char *d;
855
    for (d=text; *d!='(' && *d!='\0'; d++);
856
    if (*d!='(') return false;  // no opening paren
857
    char *args = d;
858
859
    // remove whitespaces in-place
860
    const char *s;
861
    for (s=d=args; *s; s++)
862
       if (!opp_isspace(*s))
863
          *d++ = *s;
864
    *d = '\0';
865
866
    // determine argccount: number of commas+1, or zero
867
    int commas = 0;
868
    for (d=args; *d; d++)
869
        if (*d==',')
870
            commas++;
871
    int argc;
872
    if (commas==0 && args[1]==')')
873
        argc = 0;
874
    else
875
        argc = commas+1;
876
877
    // look up function name (temporarily overwriting '(' with a '\0')
878
    *args = '\0';
879
    cMathFunction *ff = cMathFunction::find(text, argc);
880
    *args = '(';
881
    if (ff==NULL) return false;
882
883
884
    // now `args' points to something like '(10,1.5E-3)', without spaces
885
    s = args;
886
    double p1,p2,p3,p4;
887
    switch(ff->getNumArgs())
888
    {
889
       case 0: if (strcmp(s,"()")!=0) return false;
890
               setDoubleValue(ff->getMathFuncNoArg());
891
               return true;
892
       case 1: if (*s++!='(') return false;
893
               p1 = parsedbl(s);
894
               if (*s++!=')') return false;
895
               setDoubleValue(ff->getMathFunc1Arg(), p1);
896
               return true;
897
       case 2: if (*s++!='(') return false;
898
               p1 = parsedbl(s);
899
               if (*s++!=',') return false;
900
               p2 = parsedbl(s);
901
               if (*s++!=')') return false;
902
               setDoubleValue(ff->getMathFunc2Args(), p1,p2);
903
               return true;
904
       case 3: if (*s++!='(') return false;
905
               p1 = parsedbl(s);
906
               if (*s++!=',') return false;
907
               p2 = parsedbl(s);
908
               if (*s++!=',') return false;
909
               p3 = parsedbl(s);
910
               if (*s++!=')') return false;
911
               setDoubleValue(ff->getMathFunc3Args(), p1,p2,p3);
912
               return true;
913
       case 4: if (*s++!='(') return false;
914
               p1 = parsedbl(s);
915
               if (*s++!=',') return false;
916
               p2 = parsedbl(s);
917
               if (*s++!=',') return false;
918
               p3 = parsedbl(s);
919
               if (*s++!=',') return false;
920
               p4 = parsedbl(s);
921
               if (*s++!=')') return false;
922
               setDoubleValue(ff->getMathFunc4Args(), p1,p2,p3,p4);
923
               return true;
924
       default:
925
               return false; // invalid argcount
926
    }
927
}
928
929
930
double cMsgPar::getFromstat()
931
{
932
    if (typechar!='T')
933
        throw cRuntimeError(this,eBADCAST,getTypeName(typechar),getTypeName('T'));
934
    return  dtr.res->random();
935
}
936
937
938
cMsgPar& cMsgPar::operator=(const cMsgPar& val)
939
{
940
    if (this==&val) return *this;
941
942
    beforeChange();
943
    deleteOld();
944
945
    cOwnedObject::operator=(val);
946
    typechar = val.typechar;
947
    changedflag = val.changedflag;
948
949
    // this line is supposed to copy the whole data area.
950
    memcpy( &ss, &val.ss, std::max(sizeof(ss), sizeof(func)) );
951
952
    if (typechar=='S' && !ss.sht)
953
    {
954
         // make our copy of the string
955
         ls.str = opp_strdup(ls.str);
956
    }
957
    else if (typechar=='T')
958
    {
959
         cStatistic *&p = dtr.res;
960
         if (p->getOwner()==const_cast<cMsgPar*>(&val))
961
            take( p=(cStatistic *)p->dup() );
962
    }
963
    else if (typechar=='P')
964
    {
965
         if (ptr.dupfunc)
966
            ptr.ptr = ptr.dupfunc( ptr.ptr );
967
         else if (ptr.itemsize>0)
968
            memcpy(ptr.ptr=new char[ptr.itemsize],val.ptr.ptr,ptr.itemsize);
969
         // if no dupfunc or itemsize, only the pointer is copied
970
    }
971
    else if (typechar=='O')
972
    {
973
         cOwnedObject *&p = obj.obj;
974
         if (p->getOwner()==const_cast<cMsgPar*>(&val))
975
            take( p = (cOwnedObject *)p->dup() );
976
    }
977
978
    afterChange();
979
    return *this;
980
}
981
982
983
void cMsgPar::convertToConst ()
984
{
985
    if (strchr("FT", typechar))
986
    {
987
       double d = doubleValue();
988
       setDoubleValue(d);
989
    }
990
}
991