PageRenderTime 61ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

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

https://bitbucket.org/indigopony/omnetproject
C++ | 535 lines | 456 code | 37 blank | 42 comment | 129 complexity | 0d4c7e4f377eda95039889bd75259999 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, GPL-2.0, Apache-2.0, JSON
  1. //=========================================================================
  2. // STRINGUTIL.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 <stdio.h>
  15. #include <stdlib.h>
  16. #include <stdarg.h>
  17. #include <limits.h>
  18. #include <errno.h>
  19. #include <math.h> //HUGE_VAL
  20. #include <locale.h>
  21. #include "platmisc.h"
  22. #include "commonutil.h"
  23. #include "opp_ctype.h"
  24. #include "stringutil.h"
  25. #include "stringtokenizer.h"
  26. USING_NAMESPACE
  27. bool opp_isblank(const char *txt)
  28. {
  29. if (txt!=NULL)
  30. for (const char *s = txt; *s; s++)
  31. if (!opp_isspace(*s))
  32. return false;
  33. return true;
  34. }
  35. std::string opp_trim(const char *txt)
  36. {
  37. if (!txt)
  38. return "";
  39. while (opp_isspace(*txt))
  40. txt++;
  41. const char *end = txt + strlen(txt);
  42. while (end>txt && opp_isspace(*(end-1)))
  43. end--;
  44. return std::string(txt, end-txt);
  45. }
  46. std::string opp_parsequotedstr(const char *txt)
  47. {
  48. const char *endp;
  49. std::string ret = opp_parsequotedstr(txt, endp);
  50. if (*endp)
  51. throw opp_runtime_error("trailing garbage after string literal");
  52. return ret;
  53. }
  54. inline int h2d(char c)
  55. {
  56. if (c>='0' && c<='9') return c-'0';
  57. if (c>='A' && c<='F') return c-'A'+10;
  58. if (c>='a' && c<='f') return c-'a'+10;
  59. return -1;
  60. }
  61. inline int h2d(const char *&s)
  62. {
  63. int a = h2d(*s);
  64. if (a<0) return 0;
  65. s++;
  66. int b = h2d(*s);
  67. if (b<0) return a;
  68. s++;
  69. return a*16+b;
  70. }
  71. std::string opp_parsequotedstr(const char *txt, const char *&endp)
  72. {
  73. const char *s = txt;
  74. while (opp_isspace(*s))
  75. s++;
  76. if (*s++!='"')
  77. throw opp_runtime_error("missing opening quote");
  78. char *buf = new char [strlen(txt)+1];
  79. char *d = buf;
  80. for (; *s && *s!='"'; s++, d++)
  81. {
  82. if (*s=='\\')
  83. {
  84. // allow backslash as quote character, also interpret backslash sequences
  85. s++;
  86. switch(*s)
  87. {
  88. case 'b': *d = '\b'; break;
  89. case 'f': *d = '\f'; break;
  90. case 'n': *d = '\n'; break;
  91. case 'r': *d = '\r'; break;
  92. case 't': *d = '\t'; break;
  93. case 'x': s++; *d = h2d(s); s--; break; // hex code
  94. case '"': *d = '"'; break; // quote needs to be backslashed
  95. case '\\': *d = '\\'; break; // backslash needs to be backslashed
  96. case '\n': d--; break; // don't store line continuation (backslash followed by newline)
  97. case '\0': d--; s--; break; // string ends in stray backslash
  98. case '=':
  99. case ';':
  100. case ',': throw opp_runtime_error("illegal escape sequence `\\%c' "
  101. "(Hint: use double backslashes to quote display string "
  102. "special chars: equal sign, comma, semicolon)", *s);
  103. default: throw opp_runtime_error("illegal escape sequence `\\%c'", *s);
  104. }
  105. }
  106. else
  107. {
  108. *d = *s;
  109. }
  110. }
  111. *d = '\0';
  112. if (*s++!='"')
  113. {delete [] buf; throw opp_runtime_error("missing closing quote"); }
  114. while (opp_isspace(*s))
  115. s++;
  116. endp = s; // if (*s!='\0'), something comes after the string
  117. std::string ret = buf;
  118. delete [] buf;
  119. return ret;
  120. }
  121. std::string opp_quotestr(const char *txt)
  122. {
  123. char *buf = new char[4*strlen(txt)+3]; // a conservative guess
  124. char *d = buf;
  125. *d++ = '"';
  126. const char *s = txt;
  127. while (*s)
  128. {
  129. switch (*s)
  130. {
  131. case '\b': *d++ = '\\'; *d++ = 'b'; s++; break;
  132. case '\f': *d++ = '\\'; *d++ = 'f'; s++; break;
  133. case '\n': *d++ = '\\'; *d++ = 'n'; s++; break;
  134. case '\r': *d++ = '\\'; *d++ = 'r'; s++; break;
  135. case '\t': *d++ = '\\'; *d++ = 't'; s++; break;
  136. case '"': *d++ = '\\'; *d++ = '"'; s++; break;
  137. case '\\': *d++ = '\\'; *d++ = '\\'; s++; break;
  138. default: if (opp_iscntrl(*s)) {*d++='\\'; *d++='x'; sprintf(d,"%2.2X",*s++); d+=2;}
  139. else {*d++ = *s++;}
  140. }
  141. }
  142. *d++ = '"';
  143. *d = '\0';
  144. std::string ret = buf;
  145. delete [] buf;
  146. return ret;
  147. }
  148. bool opp_needsquotes(const char *txt)
  149. {
  150. if (!txt[0])
  151. return true;
  152. for (const char *s = txt; *s; s++)
  153. if (opp_isspace(*s) || *s=='\\' || *s=='"' || opp_iscntrl(*s))
  154. return true;
  155. return false;
  156. }
  157. #define BUFLEN 1024
  158. std::string opp_stringf(const char *fmt, ...)
  159. {
  160. char buf[BUFLEN];
  161. VSNPRINTF(buf, BUFLEN, fmt);
  162. return buf;
  163. }
  164. std::string opp_vstringf(const char *fmt, va_list& args)
  165. {
  166. char buf[BUFLEN];
  167. vsnprintf(buf, BUFLEN, fmt, args);
  168. buf[BUFLEN-1] = '\0';
  169. return buf;
  170. }
  171. #undef BUFLEN
  172. int opp_vsscanf(const char *s, const char *fmt, va_list va)
  173. {
  174. // A simplified vsscanf implementation, solely for cStatistic::freadvarsf.
  175. // Only recognizes %d, %u, %ld, %g and whitespace. '#' terminates scanning
  176. setlocale(LC_NUMERIC, "C");
  177. int k = 0;
  178. while (true)
  179. {
  180. if (*fmt=='%')
  181. {
  182. int n;
  183. if (fmt[1]=='d')
  184. {
  185. k+=sscanf(s,"%d%n",va_arg(va,int*),&n);
  186. s+=n; fmt+=2;
  187. }
  188. else if (fmt[1]=='u')
  189. {
  190. k+=sscanf(s,"%u%n",va_arg(va,unsigned int*),&n);
  191. s+=n; fmt+=2;
  192. }
  193. else if (fmt[1]=='l' && fmt[2]=='d')
  194. {
  195. k+=sscanf(s,"%ld%n",va_arg(va,long*),&n);
  196. s+=n; fmt+=3;
  197. }
  198. else if (fmt[1]=='l' && fmt[2]=='u')
  199. {
  200. k+=sscanf(s,"%lu%n",va_arg(va,unsigned long*),&n);
  201. s+=n; fmt+=3;
  202. }
  203. else if (fmt[1]=='l' && fmt[2]=='g')
  204. {
  205. k+=sscanf(s,"%lg%n",va_arg(va,double*),&n);
  206. s+=n; fmt+=3;
  207. }
  208. else if (fmt[1]=='g')
  209. {
  210. k+=sscanf(s,"%lg%n",va_arg(va,double*),&n);
  211. s+=n; fmt+=2;
  212. }
  213. else
  214. {
  215. throw opp_runtime_error("opp_vsscanf: unsupported format '%s'",fmt);
  216. }
  217. }
  218. else if (opp_isspace(*fmt))
  219. {
  220. while (opp_isspace(*s)) s++;
  221. fmt++;
  222. }
  223. else if (*fmt=='\0' || *fmt=='#')
  224. {
  225. return k;
  226. }
  227. else
  228. {
  229. throw opp_runtime_error("opp_vsscanf: unexpected char in format: '%s'",fmt);
  230. }
  231. }
  232. }
  233. std::string opp_replacesubstring(const char *s, const char *substring, const char *replacement, bool replaceAll)
  234. {
  235. std::string text = s;
  236. std::string::size_type pos = 0;
  237. do {
  238. pos = text.find(substring, pos);
  239. if (pos == std::string::npos)
  240. break;
  241. text.replace(pos, strlen(substring), replacement);
  242. pos += strlen(replacement);
  243. }
  244. while (replaceAll);
  245. return text;
  246. }
  247. std::string opp_breaklines(const char *text, int lineLength)
  248. {
  249. char *buf = new char[strlen(text)+1];
  250. strcpy(buf, text);
  251. int leftMargin = 0;
  252. int length = strlen(buf);
  253. while (true)
  254. {
  255. int rightMargin = leftMargin + lineLength;
  256. if (rightMargin>=length)
  257. break; // done
  258. bool here = false;
  259. int i;
  260. if (!here)
  261. for (i=leftMargin; i<rightMargin; i++)
  262. if (buf[i]=='\n')
  263. {here = true; break;}
  264. if (!here)
  265. for (; i>=leftMargin; i--)
  266. if (buf[i]==' ' || buf[i]=='\n')
  267. {here = true; break;}
  268. if (!here)
  269. for (i=leftMargin; i<length; i++)
  270. if (buf[i]==' ' || buf[i]=='\n')
  271. {here = true; break;}
  272. if (!here)
  273. break; // done
  274. buf[i] = '\n';
  275. leftMargin = i+1;
  276. }
  277. std::string tmp = buf;
  278. delete[] buf;
  279. return tmp;
  280. }
  281. std::string opp_indentlines(const char *text, const char *indent)
  282. {
  283. return std::string(indent) + opp_replacesubstring(text, "\n", (std::string("\n")+indent).c_str(), true);
  284. }
  285. bool opp_stringbeginswith(const char *s, const char *prefix)
  286. {
  287. return strlen(s) >= strlen(prefix) && strncmp(s, prefix, strlen(prefix))==0;
  288. }
  289. bool opp_stringendswith(const char *s, const char *ending)
  290. {
  291. int slen = strlen(s);
  292. int endinglen = strlen(ending);
  293. return slen >= endinglen && strcmp(s+slen-endinglen, ending)==0;
  294. }
  295. char *opp_concat(const char *s1,
  296. const char *s2,
  297. const char *s3,
  298. const char *s4)
  299. {
  300. // concatenate strings into a static buffer
  301. //FIXME throw error if string overflows!!!
  302. static char buf[256];
  303. char *bufEnd = buf+255;
  304. char *dest=buf;
  305. if (s1) while (*s1 && dest!=bufEnd) *dest++ = *s1++;
  306. if (s2) while (*s2 && dest!=bufEnd) *dest++ = *s2++;
  307. if (s3) while (*s3 && dest!=bufEnd) *dest++ = *s3++;
  308. if (s4) while (*s4 && dest!=bufEnd) *dest++ = *s4++;
  309. *dest = 0;
  310. return buf;
  311. }
  312. char *opp_strupr(char *s)
  313. {
  314. char *txt = s;
  315. while(*s) {
  316. *s = opp_toupper(*s);
  317. s++;
  318. }
  319. return txt;
  320. }
  321. char *opp_strlwr(char *s)
  322. {
  323. char *txt = s;
  324. while(*s) {
  325. *s = opp_tolower(*s);
  326. s++;
  327. }
  328. return txt;
  329. }
  330. std::string opp_join(const char *separator, const char *s1, const char *s2)
  331. {
  332. if (opp_isempty(s1))
  333. return opp_nulltoempty(s2);
  334. else if (opp_isempty(s2))
  335. return opp_nulltoempty(s1);
  336. else
  337. return std::string(s1) + separator + s2;
  338. }
  339. // returns 0 iff the two strings are equal by strcmp().
  340. int strdictcmp(const char *s1, const char *s2)
  341. {
  342. int firstdiff = 0;
  343. char c1, c2;
  344. while ((c1=*s1)!='\0' && (c2=*s2)!='\0')
  345. {
  346. if (opp_isdigit(c1) && opp_isdigit(c2))
  347. {
  348. char *s1end, *s2end;
  349. double d1 = strtod(s1, &s1end);
  350. double d2 = strtod(s2, &s2end);
  351. if (d1!=d2)
  352. return d1<d2 ? -1 : 1;
  353. if (!firstdiff) {
  354. if (s1end-s1 < s2end-s2)
  355. firstdiff = strncasecmp(s1, s2, s1end-s1);
  356. else
  357. firstdiff = strncasecmp(s1, s2, s2end-s2);
  358. if (!firstdiff && (s1end-s1) != (s2end-s2))
  359. firstdiff = (s1end-s1 < s2end-s2) ? -1 : 1;
  360. }
  361. s1 = s1end;
  362. s2 = s2end;
  363. }
  364. else if (c1==c2) // very frequent in our case
  365. {
  366. s1++;
  367. s2++;
  368. }
  369. else
  370. {
  371. char lc1 = opp_tolower(c1);
  372. char lc2 = opp_tolower(c2);
  373. if (lc1!=lc2)
  374. return lc1<lc2 ? -1 : 1;
  375. if (c1!=c2 && !firstdiff && opp_isalpha(c1) && opp_isalpha(c2))
  376. firstdiff = opp_isupper(c2) ? -1 : 1;
  377. s1++;
  378. s2++;
  379. }
  380. }
  381. if (!*s1 && !*s2)
  382. return firstdiff;
  383. return *s2 ? -1 : 1;
  384. }
  385. /* for testing:
  386. #include <stdio.h>
  387. int qsortfunc(const void *a, const void *b)
  388. {
  389. return strdictcmp(*(char**)a, *(char**)b);
  390. }
  391. int main(int argc, char **argv)
  392. {
  393. qsort(argv+1, argc-1, sizeof(char*), qsortfunc);
  394. for (int i=1; i<argc; i++)
  395. printf("%s ", argv[i]);
  396. printf("\n");
  397. return 0;
  398. }
  399. Expected results:
  400. dictcmp a b c d c1 c2 ca cd --> a b c c1 c2 ca cd d
  401. dictcmp a aaa aa aaaaa aaaa --> a aa aaa aaaa aaaaa
  402. dictcmp a aaa Aa AaAaa aaaa --> a Aa aaa aaaa AaAaa
  403. dictcmp a1b a2b a11b a13b a20b --> a1b a2b a11b a13b a20b
  404. */
  405. long opp_strtol(const char *s, char **endptr)
  406. {
  407. long d = strtol(s, endptr, 0);
  408. if ((d==LONG_MAX || d==LONG_MIN) && errno==ERANGE)
  409. throw opp_runtime_error("overflow converting `%s' to long", s);
  410. return d;
  411. }
  412. long opp_atol(const char *s)
  413. {
  414. char *endptr;
  415. long d = opp_strtol(s, &endptr);
  416. while (opp_isspace(*endptr))
  417. endptr++;
  418. if (*endptr)
  419. throw opp_runtime_error("`%s' is not a valid integer", s);
  420. return d;
  421. }
  422. unsigned long opp_strtoul(const char *s, char **endptr)
  423. {
  424. unsigned long d = strtoul(s, endptr, 0);
  425. if (d==ULONG_MAX && errno==ERANGE)
  426. throw opp_runtime_error("overflow converting `%s' to unsigned long", s);
  427. return d;
  428. }
  429. unsigned long opp_atoul(const char *s)
  430. {
  431. char *endptr;
  432. unsigned long d = opp_strtol(s, &endptr);
  433. while (opp_isspace(*endptr))
  434. endptr++;
  435. if (*endptr)
  436. throw opp_runtime_error("`%s' is not a valid unsigned integer", s);
  437. return d;
  438. }
  439. double opp_strtod(const char *s, char **endptr)
  440. {
  441. setlocale(LC_NUMERIC, "C");
  442. double d = strtod(s, endptr);
  443. if (d==-HUGE_VAL || d==HUGE_VAL)
  444. throw opp_runtime_error("overflow converting `%s' to double", s);
  445. return d;
  446. }
  447. double opp_atof(const char *s)
  448. {
  449. char *endptr;
  450. setlocale(LC_NUMERIC, "C");
  451. double d = opp_strtod(s, &endptr);
  452. while (opp_isspace(*endptr))
  453. endptr++;
  454. if (*endptr)
  455. throw opp_runtime_error("`%s' is not a valid double value", s);
  456. return d;
  457. }
  458. const char *opp_findmatchingquote(const char *s)
  459. {
  460. while (opp_isspace(*s))
  461. s++;
  462. if (*s++!='"')
  463. throw opp_runtime_error("missing opening quote");
  464. for (; *s && *s!='"'; s++)
  465. if (*s=='\\')
  466. s++;
  467. return *s ? s : NULL;
  468. }
  469. const char *opp_findmatchingparen(const char *s)
  470. {
  471. while (opp_isspace(*s))
  472. s++;
  473. if (*s++ != '(')
  474. throw opp_runtime_error("missing left parenthesis");
  475. int parens = 1;
  476. while (*s && parens>0)
  477. {
  478. if (*s == '(')
  479. parens++;
  480. else if (*s == ')')
  481. parens--;
  482. else if (*s == '"') {
  483. s = opp_findmatchingquote(s);
  484. if (!s)
  485. return NULL;
  486. }
  487. s++;
  488. }
  489. return parens>0 ? NULL : s;
  490. }