PageRenderTime 52ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

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