PageRenderTime 236ms CodeModel.GetById 175ms app.highlight 53ms RepoModel.GetById 1ms app.codeStats 1ms

/omnetpp-4.1/src/sim/cmsgpar.cc

https://bitbucket.org/indigopony/omnetproject
C++ | 992 lines | 877 code | 82 blank | 33 comment | 105 complexity | 8815a3aeca03392316e5454a1265b8b1 MD5 | raw file
  1//=========================================================================
  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
 41USING_NAMESPACE
 42
 43using std::ostream;
 44using std::string;
 45
 46
 47Register_Class(cMsgPar);
 48
 49const char *cMsgPar::possibletypes = "SBLDFTP";
 50
 51static 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
 67cMsgPar::cMsgPar(const char *name) : cOwnedObject(name)
 68{
 69    tkownership = false;
 70    changedflag = false;
 71    typechar = 'L';
 72    lng.val = 0L;
 73}
 74
 75cMsgPar::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
 86cMsgPar::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
 97cMsgPar::~cMsgPar()
 98{
 99    beforeChange();
100    deleteOld();
101}
102
103void 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
135std::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
175std::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
183void 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
196void 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
269void 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
344char cMsgPar::getType() const
345{
346     return typechar;
347}
348
349bool cMsgPar::hasChanged()
350{
351     bool ch = changedflag;
352     changedflag=false;
353     return ch;
354}
355
356//----
357
358cMsgPar& 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
373cMsgPar& cMsgPar::setBoolValue(bool b)
374{
375    beforeChange();
376    deleteOld();
377    lng.val = b;
378    typechar = 'B';
379    afterChange();
380    return *this;
381}
382
383cMsgPar& cMsgPar::setLongValue(long l)
384{
385    beforeChange();
386    deleteOld();
387    lng.val = l;
388    typechar = 'L';
389    afterChange();
390    return *this;
391}
392
393cMsgPar& cMsgPar::setDoubleValue(double d)
394{
395    beforeChange();
396    deleteOld();
397    dbl.val = d;
398    typechar = 'D';
399    afterChange();
400    return *this;
401}
402
403cMsgPar& 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
414cMsgPar& 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
426cMsgPar& 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
439cMsgPar& 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
453cMsgPar& 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
468cMsgPar& 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
483cMsgPar& 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
500cMsgPar& 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
512cMsgPar& cMsgPar::setXMLValue(cXMLElement *node)
513{
514    beforeChange();
515    deleteOld();
516    xmlp.node = node;
517    typechar = 'M';
518    afterChange();
519    return *this;
520}
521
522void 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
534const 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
547bool 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
557inline 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
567long 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
577double 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
595void *cMsgPar::pointerValue()
596{
597    if (typechar=='P')
598        return ptr.ptr;
599    else
600        throw cRuntimeError(this,eBADCAST,getTypeName(typechar),getTypeName('P'));
601}
602
603cOwnedObject *cMsgPar::getObjectValue()
604{
605    if (typechar=='O')
606        return obj.obj;
607    else
608        throw cRuntimeError(this,eBADCAST,getTypeName(typechar),getTypeName('O'));
609}
610
611cXMLElement *cMsgPar::xmlValue()
612{
613    if (typechar=='M')
614        return xmlp.node;
615    else
616        throw cRuntimeError(this,eBADCAST,getTypeName(typechar),getTypeName('M'));
617}
618
619bool cMsgPar::isNumeric() const
620{
621    return typechar=='B' ||
622           typechar=='L' ||
623           typechar=='D' ||
624           typechar=='T' ||
625           typechar=='F';
626}
627
628bool cMsgPar::isConstant() const
629{
630    return typechar=='S' ||
631           typechar=='B' ||
632           typechar=='L' ||
633           typechar=='D';
634}
635
636bool 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
664void cMsgPar::beforeChange()
665{
666}
667
668void cMsgPar::afterChange()
669{
670    changedflag=true;
671}
672
673string 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
713static 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
726bool 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
836static 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
849bool 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
930double cMsgPar::getFromstat()
931{
932    if (typechar!='T')
933        throw cRuntimeError(this,eBADCAST,getTypeName(typechar),getTypeName('T'));
934    return  dtr.res->random();
935}
936
937
938cMsgPar& 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
983void cMsgPar::convertToConst ()
984{
985    if (strchr("FT", typechar))
986    {
987       double d = doubleValue();
988       setDoubleValue(d);
989    }
990}
991
992