PageRenderTime 56ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://bitbucket.org/indigopony/omnetproject
C++ | 524 lines | 398 code | 73 blank | 53 comment | 93 complexity | f94ec88ee696baa81e82fcbea0d7ba3a MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, GPL-2.0, Apache-2.0, JSON
  1. //==========================================================================
  2. // CDISPLAYSTRING.CC - part of
  3. // OMNeT++/OMNEST
  4. // Discrete System Simulation in C++
  5. //
  6. //
  7. //==========================================================================
  8. /*--------------------------------------------------------------*
  9. Copyright (C) 1992-2008 Andras Varga
  10. Copyright (C) 2006-2008 OpenSim Ltd.
  11. This file is distributed WITHOUT ANY WARRANTY. See the file
  12. `license' for details on this and other legal matters.
  13. *--------------------------------------------------------------*/
  14. #include <string.h>
  15. #include <stdio.h>
  16. #include "opp_ctype.h"
  17. #include "cenvir.h"
  18. #include "cmodule.h"
  19. #include "cchannel.h"
  20. #include "cgate.h"
  21. #include "cdisplaystring.h"
  22. #include "stringutil.h"
  23. #include "cmodelchange.h"
  24. USING_NAMESPACE
  25. cDisplayString::cDisplayString()
  26. {
  27. dispstr = NULL;
  28. buffer = NULL;
  29. bufferend = NULL;
  30. tags = NULL;
  31. numtags = 0;
  32. needsassemble = false;
  33. ownercomponent = NULL;
  34. }
  35. cDisplayString::cDisplayString(const char *displaystr)
  36. {
  37. dispstr = opp_strdup(displaystr);
  38. buffer = NULL;
  39. bufferend = NULL;
  40. tags = NULL;
  41. numtags = 0;
  42. needsassemble = false;
  43. ownercomponent = NULL;
  44. // doParse() should be the last one, as it may throw an error
  45. doParse();
  46. }
  47. cDisplayString::cDisplayString(const cDisplayString& ds)
  48. {
  49. dispstr = NULL;
  50. buffer = NULL;
  51. bufferend = NULL;
  52. tags = NULL;
  53. numtags = 0;
  54. needsassemble = false;
  55. ownercomponent = NULL;
  56. operator=(ds);
  57. }
  58. cDisplayString::~cDisplayString()
  59. {
  60. delete [] dispstr;
  61. clearTags();
  62. }
  63. void cDisplayString::beforeChange()
  64. {
  65. // notify pre-change listeners
  66. if (ownercomponent && ownercomponent->hasListeners(PRE_MODEL_CHANGE)) {
  67. cPreDisplayStringChangeNotification tmp;
  68. tmp.displayString = this;
  69. ownercomponent->emit(PRE_MODEL_CHANGE, &tmp);
  70. }
  71. }
  72. void cDisplayString::afterChange()
  73. {
  74. needsassemble = true;
  75. EVCB.displayStringChanged(ownercomponent);
  76. // notify post-change listeners
  77. if (ownercomponent && ownercomponent->hasListeners(POST_MODEL_CHANGE)) {
  78. cPostDisplayStringChangeNotification tmp;
  79. tmp.displayString = this;
  80. ownercomponent->emit(POST_MODEL_CHANGE, &tmp);
  81. }
  82. }
  83. const char *cDisplayString::str() const
  84. {
  85. if (needsassemble)
  86. assemble();
  87. return dispstr ? dispstr : "";
  88. }
  89. void cDisplayString::parse(const char *displaystr)
  90. {
  91. beforeChange();
  92. doParse(displaystr);
  93. afterChange();
  94. }
  95. void cDisplayString::doParse(const char *displaystr)
  96. {
  97. // if it's the same, nothing to do
  98. if (needsassemble)
  99. assemble();
  100. if (!opp_strcmp(dispstr,displaystr))
  101. return;
  102. // parse and store new string
  103. delete [] dispstr;
  104. clearTags();
  105. dispstr = opp_strdup(displaystr);
  106. doParse();
  107. }
  108. void cDisplayString::updateWith(const char *s)
  109. {
  110. cDisplayString ds(s);
  111. updateWith(ds);
  112. }
  113. void cDisplayString::updateWith(const cDisplayString& ds)
  114. {
  115. beforeChange();
  116. doUpdateWith(ds);
  117. afterChange();
  118. }
  119. void cDisplayString::doUpdateWith(const cDisplayString& ds)
  120. {
  121. // elements in "ds" take precedence
  122. int n = ds.getNumTags();
  123. for (int i=0; i<n; i++)
  124. {
  125. int m = ds.getNumArgs(i);
  126. for (int j=0; j<m; j++)
  127. {
  128. const char *arg = ds.getTagArg(i,j);
  129. if (arg[0]=='-' && !arg[1]) // "-" is the "antivalue"
  130. doSetTagArg(ds.getTagName(i), j, "");
  131. else if (arg[0])
  132. doSetTagArg(ds.getTagName(i), j, arg);
  133. }
  134. }
  135. // optimize storage
  136. doParse(str());
  137. }
  138. bool cDisplayString::containsTag(const char *tagname) const
  139. {
  140. int t = getTagIndex(tagname);
  141. return t!=-1;
  142. }
  143. int cDisplayString::getNumArgs(const char *tagname) const
  144. {
  145. return getNumArgs(getTagIndex(tagname));
  146. }
  147. const char *cDisplayString::getTagArg(const char *tagname, int index) const
  148. {
  149. return getTagArg(getTagIndex(tagname), index);
  150. }
  151. bool cDisplayString::setTagArg(const char *tagname, int index, long value)
  152. {
  153. char buf[32];
  154. sprintf(buf, "%ld", value);
  155. return setTagArg(tagname, index, buf);
  156. }
  157. bool cDisplayString::setTagArg(const char *tagname, int index, const char *value)
  158. {
  159. beforeChange();
  160. bool result = doSetTagArg(tagname, index, value);
  161. afterChange();
  162. return result;
  163. }
  164. bool cDisplayString::doSetTagArg(const char *tagname, int index, const char *value)
  165. {
  166. int t = getTagIndex(tagname);
  167. if (t==-1)
  168. t = doInsertTag(tagname);
  169. return doSetTagArg(t, index, value);
  170. }
  171. bool cDisplayString::removeTag(const char *tagname)
  172. {
  173. return removeTag(getTagIndex(tagname));
  174. }
  175. int cDisplayString::getNumTags() const
  176. {
  177. return numtags;
  178. }
  179. const char *cDisplayString::getTagName(int tagindex) const
  180. {
  181. if (tagindex<0 || tagindex>=numtags) return NULL;
  182. return tags[tagindex].name;
  183. }
  184. int cDisplayString::getNumArgs(int tagindex) const
  185. {
  186. if (tagindex<0 || tagindex>=numtags) return -1;
  187. return tags[tagindex].numargs;
  188. }
  189. const char *cDisplayString::getTagArg(int tagindex, int index) const
  190. {
  191. if (tagindex<0 || tagindex>=numtags) return "";
  192. if (index<0 || index>=tags[tagindex].numargs) return "";
  193. return opp_nulltoempty(tags[tagindex].args[index]);
  194. }
  195. bool cDisplayString::setTagArg(int tagindex, int index, const char *value)
  196. {
  197. beforeChange();
  198. bool result = doSetTagArg(tagindex, index, value);
  199. afterChange();
  200. return result;
  201. }
  202. bool cDisplayString::doSetTagArg(int tagindex, int index, const char *value)
  203. {
  204. // check indices
  205. if (tagindex<0 || tagindex>=numtags) return false;
  206. if (index<0 || index>=MAXARGS) return false;
  207. Tag& tag = tags[tagindex];
  208. // adjust numargs if necessary
  209. if (index>=tag.numargs)
  210. tag.numargs = index+1;
  211. // if it's the same, nothing to do
  212. char *&slot = tag.args[index];
  213. if (!opp_strcmp(slot,value))
  214. return true;
  215. // set value
  216. if (slot && !pointsIntoBuffer(slot))
  217. delete [] slot;
  218. slot = opp_strdup(value);
  219. // get rid of possible empty trailing args, throw out tag if it became empty
  220. while (tag.numargs>0 && tag.args[tag.numargs-1]==NULL)
  221. tag.numargs--;
  222. if (tag.numargs==0)
  223. doRemoveTag(tagindex);
  224. return true;
  225. }
  226. int cDisplayString::insertTag(const char *tagname, int atindex)
  227. {
  228. beforeChange();
  229. int result = doInsertTag(tagname, atindex);
  230. afterChange();
  231. return result;
  232. }
  233. int cDisplayString::doInsertTag(const char *tagname, int atindex)
  234. {
  235. // check name validity
  236. if (!tagname || !tagname[0])
  237. throw cRuntimeError("Error adding a new display string tag: tag name is empty");
  238. for (const char *s=tagname; *s; s++)
  239. if (!opp_isalnum(*s) && *s!=':')
  240. throw cRuntimeError("Error adding a new display string tag: tag name \"%s\" "
  241. "contains invalid character", tagname);
  242. // check uniqueness
  243. int t = getTagIndex(tagname);
  244. if (t!=-1)
  245. return t;
  246. // check index
  247. if (atindex<0) atindex=0;
  248. if (atindex>numtags) atindex=numtags;
  249. // create new tags[] array with hole at atindex
  250. Tag *newtags = new Tag[numtags+1];
  251. for (int s=0,d=0; s<numtags; s++,d++)
  252. {
  253. if (d==atindex) d++; // make room for new item
  254. newtags[d] = tags[s];
  255. }
  256. delete [] tags;
  257. tags = newtags;
  258. numtags++;
  259. // fill in new tag
  260. tags[atindex].name = opp_strdup(tagname);
  261. tags[atindex].numargs = 0;
  262. for (int i=0; i<MAXARGS; i++) tags[atindex].args[i] = NULL;
  263. // success
  264. return atindex;
  265. }
  266. bool cDisplayString::removeTag(int tagindex)
  267. {
  268. beforeChange();
  269. bool result = doRemoveTag(tagindex);
  270. afterChange();
  271. return result;
  272. }
  273. bool cDisplayString::doRemoveTag(int tagindex)
  274. {
  275. if (tagindex<0 || tagindex>=numtags) return false;
  276. // dealloc strings in tag
  277. if (!pointsIntoBuffer(tags[tagindex].name))
  278. delete [] tags[tagindex].name;
  279. for (int i=0; i<tags[tagindex].numargs; i++)
  280. if (!pointsIntoBuffer(tags[tagindex].args[i]))
  281. delete [] tags[tagindex].args[i];
  282. // eliminate hole in tags[] array
  283. for (int t=tagindex; t<numtags-1; t++)
  284. tags[t] = tags[t+1];
  285. numtags--;
  286. // success
  287. return true;
  288. }
  289. int cDisplayString::getTagIndex(const char *tagname) const
  290. {
  291. for (int t=0; t<numtags; t++)
  292. if (!strcmp(tagname,tags[t].name))
  293. return t;
  294. return -1;
  295. }
  296. void cDisplayString::clearTags()
  297. {
  298. // delete tags array. string pointers that do not point inside the
  299. // buffer were allocated individually via new char[] and have to be
  300. // deleted.
  301. for (int t=0; t<numtags; t++)
  302. {
  303. if (!pointsIntoBuffer(tags[t].name))
  304. delete [] tags[t].name;
  305. for (int i=0; i<tags[t].numargs; i++)
  306. if (!pointsIntoBuffer(tags[t].args[i]))
  307. delete [] tags[t].args[i];
  308. }
  309. delete [] tags;
  310. tags = NULL;
  311. numtags = 0;
  312. // must be done after deleting tags[] because of pointsIntoBuffer()
  313. delete [] buffer;
  314. buffer = bufferend = NULL;
  315. }
  316. void cDisplayString::doParse()
  317. {
  318. clearTags();
  319. if (dispstr==NULL)
  320. return;
  321. buffer = new char[opp_strlen(dispstr)+1];
  322. bufferend = buffer + opp_strlen(dispstr);
  323. // count tags (#(';')+1) & allocate tags[] array
  324. int n = 1;
  325. for (char *s1 = dispstr; *s1; s1++)
  326. if (*s1==';')
  327. n++;
  328. tags = new Tag[n];
  329. // parse string into tags[]. To avoid several small allocations,
  330. // pointers in tags[] will point into the buffer.
  331. numtags = 1;
  332. tags[0].name = buffer;
  333. tags[0].numargs = 0;
  334. for (int i=0; i<MAXARGS; i++)
  335. tags[0].args[i] = NULL;
  336. char *s, *d;
  337. for (s=dispstr,d=buffer; *s; s++,d++)
  338. {
  339. if (*s=='\\' && *(s+1))
  340. {
  341. // allow escaping display string special chars (=,;) with backslash.
  342. // No need to deal with "\t", "\n" etc here, since they already got
  343. // interpreted by opp_parsequotedstr().
  344. *d = *++s;
  345. }
  346. else if (*s==';')
  347. {
  348. // new tag begins
  349. *d = '\0';
  350. numtags++;
  351. tags[numtags-1].name = d+1;
  352. tags[numtags-1].numargs = 0;
  353. for (int i=0; i<MAXARGS; i++)
  354. tags[numtags-1].args[i] = NULL;
  355. }
  356. else if (*s=='=')
  357. {
  358. // first argument of new tag begins
  359. *d = '\0';
  360. tags[numtags-1].numargs = 1;
  361. tags[numtags-1].args[0] = d+1;
  362. }
  363. else if (*s==',')
  364. {
  365. // new argument of current tag begins
  366. *d = '\0';
  367. if (tags[numtags-1].numargs>=MAXARGS)
  368. throw cRuntimeError("Error parsing display string: too many parameters for a tag, "
  369. "max %d allowed in \"%s\"", MAXARGS, dispstr);
  370. tags[numtags-1].numargs++;
  371. tags[numtags-1].args[ tags[numtags-1].numargs-1 ] = d+1;
  372. }
  373. else
  374. {
  375. *d = *s;
  376. }
  377. }
  378. *d = '\0';
  379. // check tag names are OK (matching [a-zA-Z0-9:]+)
  380. for (int i=0; i<numtags; i++)
  381. {
  382. if (!tags[i].name[0]) {
  383. if (tags[i].numargs==0)
  384. ; // empty tag (occurs when there're redundant semicolons, or the display string is empty) -- XXX remove it
  385. else
  386. throw cRuntimeError("Error parsing display string: missing tag name in \"%s\"", dispstr);
  387. }
  388. for (const char *s=tags[i].name; *s; s++)
  389. if (!opp_isalnum(*s) && *s!=':')
  390. throw cRuntimeError("Error parsing display string: tag name \"%s\" contains invalid character in \"%s\"", tags[i].name, dispstr);
  391. }
  392. }
  393. void cDisplayString::assemble() const
  394. {
  395. // calculate length of display string
  396. int size = 0;
  397. for (int t0=0; t0<numtags; t0++)
  398. {
  399. size += opp_strlen(tags[t0].name)+2;
  400. for (int i=0; i<tags[t0].numargs; i++)
  401. size += opp_strlen(tags[t0].args[i])+1;
  402. }
  403. size = 2*size+1; // 2* for worst case if every char has to be escaped
  404. // allocate display string
  405. delete [] dispstr;
  406. dispstr = new char[size];
  407. dispstr[0] = '\0';
  408. // assemble string
  409. for (int t=0; t<numtags; t++)
  410. {
  411. if (t!=0)
  412. strcat(dispstr, ";");
  413. strcatescaped(dispstr, tags[t].name);
  414. if (tags[t].numargs>0)
  415. strcat(dispstr, "=");
  416. for (int i=0; i<tags[t].numargs; i++)
  417. {
  418. if (i!=0) strcat(dispstr, ",");
  419. strcatescaped(dispstr, tags[t].args[i]);
  420. }
  421. }
  422. needsassemble = false;
  423. }
  424. void cDisplayString::strcatescaped(char *d, const char *s)
  425. {
  426. if (!s) return;
  427. d += strlen(d);
  428. while (*s)
  429. {
  430. // quoting \t, \n etc is the job of opp_quotestr()
  431. if (*s==';' || *s==',' || *s=='=')
  432. *d++ = '\\';
  433. *d++ = *s++;
  434. }
  435. *d = '\0';
  436. }
  437. void cDisplayString::dump() const
  438. {
  439. for (int t=0; t<numtags; t++)
  440. {
  441. if (t!=0) printf("; ");
  442. printf("tags[%d]:\"%s\"=", t, tags[t].name);
  443. for (int i=0; i<tags[t].numargs; i++)
  444. {
  445. if (i!=0) printf(",");
  446. printf("\"%s\"", tags[t].args[i]);
  447. }
  448. }
  449. printf(" ==> \"%s\"\n", str());
  450. }