PageRenderTime 45ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/omnetpp-4.1/src/common/displaystring.cc

https://bitbucket.org/indigopony/omnetproject
C++ | 436 lines | 314 code | 73 blank | 49 comment | 75 complexity | 4a4b545cf936778464abccb522d1d7dd MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, GPL-2.0, Apache-2.0, JSON
  1. //==========================================================================
  2. // DISPLAYSTRING.CC - part of
  3. // OMNeT++/OMNEST
  4. // Discrete System Simulation in C++
  5. //
  6. // Author: Andras Varga
  7. //
  8. //==========================================================================
  9. /*--------------------------------------------------------------*
  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 "displaystring.h"
  18. #include "stringutil.h"
  19. USING_NAMESPACE
  20. DisplayString::DisplayString()
  21. {
  22. dispstr = NULL;
  23. buffer = NULL;
  24. bufferend = NULL;
  25. tags = NULL;
  26. numtags = 0;
  27. needsassemble = false;
  28. }
  29. DisplayString::DisplayString(const char *displaystr)
  30. {
  31. dispstr = opp_strdup(displaystr);
  32. buffer = NULL;
  33. bufferend = NULL;
  34. tags = NULL;
  35. numtags = 0;
  36. needsassemble = false;
  37. parse();
  38. }
  39. DisplayString::DisplayString(const DisplayString& ds)
  40. {
  41. dispstr = NULL;
  42. buffer = NULL;
  43. bufferend = NULL;
  44. tags = NULL;
  45. numtags = 0;
  46. needsassemble = false;
  47. operator=(ds);
  48. }
  49. DisplayString::~DisplayString()
  50. {
  51. delete [] dispstr;
  52. cleartags();
  53. }
  54. const char *DisplayString::str() const
  55. {
  56. if (needsassemble)
  57. assemble();
  58. return dispstr ? dispstr : "";
  59. }
  60. bool DisplayString::parse(const char *displaystr)
  61. {
  62. // if it's the same, nothing to do
  63. if (needsassemble)
  64. assemble();
  65. if (!opp_strcmp(dispstr,displaystr))
  66. return true;
  67. // parse and store new string
  68. delete [] dispstr;
  69. cleartags();
  70. dispstr = opp_strdup(displaystr);
  71. bool fullyOK = parse();
  72. return fullyOK;
  73. }
  74. void DisplayString::updateWith(const DisplayString& ds)
  75. {
  76. // elements in "ds" take precedence
  77. int n = ds.getNumTags();
  78. for (int i=0; i<n; i++)
  79. {
  80. int m = ds.getNumArgs(i);
  81. for (int j=0; j<m; j++)
  82. {
  83. const char *arg = ds.getTagArg(i,j);
  84. if (arg[0])
  85. setTagArg(ds.getTagName(i), j, arg);
  86. }
  87. }
  88. // optimize storage
  89. parse(str());
  90. }
  91. void DisplayString::updateWith(const char *s)
  92. {
  93. DisplayString ds(s);
  94. updateWith(ds);
  95. }
  96. bool DisplayString::containsTag(const char *tagname) const
  97. {
  98. int t = gettagindex(tagname);
  99. return t!=-1;
  100. }
  101. int DisplayString::getNumArgs(const char *tagname) const
  102. {
  103. return getNumArgs(gettagindex(tagname));
  104. }
  105. const char *DisplayString::getTagArg(const char *tagname, int index) const
  106. {
  107. return getTagArg(gettagindex(tagname), index);
  108. }
  109. bool DisplayString::setTagArg(const char *tagname, int index, const char *value)
  110. {
  111. int t = gettagindex(tagname);
  112. if (t==-1)
  113. t = insertTag(tagname);
  114. return setTagArg(t, index, value);
  115. }
  116. bool DisplayString::setTagArg(const char *tagname, int index, long value)
  117. {
  118. char buf[32];
  119. sprintf(buf, "%ld", value);
  120. return setTagArg(tagname, index, buf);
  121. }
  122. bool DisplayString::removeTag(const char *tagname)
  123. {
  124. return removeTag(gettagindex(tagname));
  125. }
  126. int DisplayString::getNumTags() const
  127. {
  128. return numtags;
  129. }
  130. const char *DisplayString::getTagName(int tagindex) const
  131. {
  132. if (tagindex<0 || tagindex>=numtags) return NULL;
  133. return tags[tagindex].name;
  134. }
  135. int DisplayString::getNumArgs(int tagindex) const
  136. {
  137. if (tagindex<0 || tagindex>=numtags) return -1;
  138. return tags[tagindex].numargs;
  139. }
  140. const char *DisplayString::getTagArg(int tagindex, int index) const
  141. {
  142. if (tagindex<0 || tagindex>=numtags) return "";
  143. if (index<0 || index>=tags[tagindex].numargs) return "";
  144. return opp_nulltoempty(tags[tagindex].args[index]);
  145. }
  146. bool DisplayString::setTagArg(int tagindex, int index, const char *value)
  147. {
  148. // check indices
  149. if (tagindex<0 || tagindex>=numtags) return false;
  150. if (index<0 || index>=MAXARGS) return false;
  151. Tag& tag = tags[tagindex];
  152. // adjust numargs if necessary
  153. if (index>=tag.numargs)
  154. tag.numargs = index+1;
  155. // if it's the same, nothing to do
  156. char *&slot = tag.args[index];
  157. if (!opp_strcmp(slot,value))
  158. return true;
  159. // set value
  160. if (slot && !isinbuffer(slot))
  161. delete [] slot;
  162. slot = opp_strdup(value);
  163. // get rid of possible empty trailing args
  164. while (tag.numargs>0 && tag.args[tag.numargs-1]==NULL)
  165. tag.numargs--;
  166. needsassemble = true;
  167. return true;
  168. }
  169. int DisplayString::insertTag(const char *tagname, int atindex)
  170. {
  171. // check uniqueness
  172. int t = gettagindex(tagname);
  173. if (t!=-1)
  174. return t;
  175. // check index
  176. if (atindex<0) atindex=0;
  177. if (atindex>numtags) atindex=numtags;
  178. // create new tags[] array with hole at atindex
  179. Tag *newtags = new Tag[numtags+1];
  180. for (int s=0,d=0; s<numtags; s++,d++)
  181. {
  182. if (d==atindex) d++; // make room for new item
  183. newtags[d] = tags[s];
  184. }
  185. delete [] tags;
  186. tags = newtags;
  187. numtags++;
  188. // fill in new tag
  189. tags[atindex].name = opp_strdup(tagname);
  190. tags[atindex].numargs = 0;
  191. for (int i=0; i<MAXARGS; i++) tags[atindex].args[i] = NULL;
  192. // success
  193. needsassemble = true;
  194. return atindex;
  195. }
  196. bool DisplayString::removeTag(int tagindex)
  197. {
  198. if (tagindex<0 || tagindex>=numtags) return false;
  199. // dealloc strings in tag
  200. if (!isinbuffer(tags[tagindex].name))
  201. delete [] tags[tagindex].name;
  202. for (int i=0; i<tags[tagindex].numargs; i++)
  203. if (!isinbuffer(tags[tagindex].args[i]))
  204. delete [] tags[tagindex].args[i];
  205. // eliminate hole in tags[] array
  206. for (int t=tagindex; t<numtags-1; t++)
  207. tags[t] = tags[t+1];
  208. numtags--;
  209. // success
  210. needsassemble = true;
  211. return true;
  212. }
  213. int DisplayString::gettagindex(const char *tagname) const
  214. {
  215. for (int t=0; t<numtags; t++)
  216. if (!strcmp(tagname,tags[t].name))
  217. return t;
  218. return -1;
  219. }
  220. void DisplayString::cleartags()
  221. {
  222. // delete tags array. string pointers that do not point inside the
  223. // buffer were allocated individually via new char[] and have to be
  224. // deleted.
  225. for (int t=0; t<numtags; t++)
  226. {
  227. if (!isinbuffer(tags[t].name))
  228. delete [] tags[t].name;
  229. for (int i=0; i<tags[t].numargs; i++)
  230. if (!isinbuffer(tags[t].args[i]))
  231. delete [] tags[t].args[i];
  232. }
  233. delete [] tags;
  234. tags = NULL;
  235. numtags = 0;
  236. // must be done after deleting tags[] because of isinbuffer()
  237. delete [] buffer;
  238. buffer = bufferend = NULL;
  239. needsassemble = true;
  240. }
  241. bool DisplayString::parse()
  242. {
  243. cleartags();
  244. if (dispstr==NULL)
  245. return true;
  246. bool fully_ok = true;
  247. buffer = new char[opp_strlen(dispstr)+1];
  248. bufferend = buffer + opp_strlen(dispstr);
  249. // count tags (#(';')+1) & allocate tags[] array
  250. int n = 1;
  251. for (char *s1 = dispstr; *s1; s1++)
  252. if (*s1==';')
  253. n++;
  254. tags = new Tag[n];
  255. // parse string into tags[]. To avoid several small allocations,
  256. // pointers in tags[] will point into the buffer.
  257. numtags = 1;
  258. tags[0].name = buffer;
  259. tags[0].numargs = 0;
  260. for (int i=0; i<MAXARGS; i++)
  261. tags[0].args[i] = NULL;
  262. char *s, *d;
  263. for (s=dispstr,d=buffer; *s; s++,d++)
  264. {
  265. if (*s=='\\' && *(s+1))
  266. {
  267. // allow escaping display string special chars (=,;) with backslash.
  268. // No need to deal with "\t", "\n" etc here, since they already got
  269. // interpreted by opp_parsequotedstr().
  270. *d = *++s;
  271. }
  272. else if (*s==';')
  273. {
  274. // new tag begins
  275. *d = '\0';
  276. numtags++;
  277. tags[numtags-1].name = d+1;
  278. tags[numtags-1].numargs = 0;
  279. for (int i=0; i<MAXARGS; i++) tags[numtags-1].args[i] = NULL;
  280. }
  281. else if (*s=='=')
  282. {
  283. // first argument of new tag begins
  284. *d = '\0';
  285. tags[numtags-1].numargs = 1;
  286. tags[numtags-1].args[0] = d+1;
  287. }
  288. else if (*s==',')
  289. {
  290. // new argument of current tag begins
  291. *d = '\0';
  292. if (tags[numtags-1].numargs>=MAXARGS)
  293. {
  294. fully_ok = false; // extra args ignored (there were too many)
  295. }
  296. else
  297. {
  298. tags[numtags-1].numargs++;
  299. tags[numtags-1].args[ tags[numtags-1].numargs-1 ] = d+1;
  300. }
  301. }
  302. else
  303. {
  304. *d = *s;
  305. }
  306. }
  307. *d = '\0';
  308. // check tag names are OK (matching [a-zA-Z0-9:]+)
  309. for (int i=0; i<numtags; i++)
  310. {
  311. if (!tags[i].name[0])
  312. fully_ok = false; // empty string as tagname
  313. for (const char *s=tags[i].name; *s; s++)
  314. if (!opp_isalnum(*s) && *s!=':')
  315. fully_ok = false; // tagname contains invalid character
  316. }
  317. return fully_ok;
  318. }
  319. void DisplayString::assemble() const
  320. {
  321. // calculate length of display string
  322. int size = 0;
  323. for (int t0=0; t0<numtags; t0++)
  324. {
  325. size += opp_strlen(tags[t0].name)+2;
  326. for (int i=0; i<tags[t0].numargs; i++)
  327. size += opp_strlen(tags[t0].args[i])+1;
  328. }
  329. size = 2*size+1; // 2* for worst case if every char has to be escaped
  330. // allocate display string
  331. delete [] dispstr;
  332. dispstr = new char[size];
  333. dispstr[0] = '\0';
  334. // assemble string
  335. for (int t=0; t<numtags; t++)
  336. {
  337. if (t!=0)
  338. strcat(dispstr, ";");
  339. strcatescaped(dispstr, tags[t].name);
  340. if (tags[t].numargs>0)
  341. strcat(dispstr, "=");
  342. for (int i=0; i<tags[t].numargs; i++)
  343. {
  344. if (i!=0) strcat(dispstr, ",");
  345. strcatescaped(dispstr, tags[t].args[i]);
  346. }
  347. }
  348. needsassemble = false;
  349. }
  350. void DisplayString::strcatescaped(char *d, const char *s)
  351. {
  352. if (!s) return;
  353. d += strlen(d);
  354. while (*s)
  355. {
  356. // quoting \t, \n etc is the job of opp_quotestr()
  357. if (*s==';' || *s==',' || *s=='=')
  358. *d++ = '\\';
  359. *d++ = *s++;
  360. }
  361. *d = '\0';
  362. }