| 318 | char *lookup(char *n, int levels); |
| 319 | |
| 320 | char *parseexp(const char *&p, int right, int rec) // parse any nested set of () or [] |
| 321 | { |
| 322 | if(rec > CSLIMIT_RECURSION) { cslimiterr("recursion depth"); return NULL; } |
| 323 | vector<char> res; |
| 324 | int left = *p++; |
| 325 | const char *word = p; |
| 326 | char *s; |
| 327 | bool quot = false, issq = left == '['; |
| 328 | for(int brak = 1; brak; ) |
| 329 | { |
| 330 | p += strcspn(p, "([\"])@"); |
| 331 | int c = *p++; |
| 332 | if(c==left && !quot) brak++; |
| 333 | else if(c=='"') quot = !quot; |
| 334 | else if(c==right && !quot) brak--; |
| 335 | else if(!c) |
| 336 | { |
| 337 | p--; |
| 338 | conoutf("missing \"%c\"", right); |
| 339 | goto screrr; |
| 340 | } |
| 341 | else if(issq && c == '@' && !quot) |
| 342 | { |
| 343 | const char *sq = p; |
| 344 | while(*p == '@') p++; |
| 345 | int level = p - sq + 1; |
| 346 | if(level == brak) |
| 347 | { |
| 348 | res.put(word, sq - word - 1); |
| 349 | char *n, a = *p; |
| 350 | switch(a) |
| 351 | { |
| 352 | case '(': n = parseexp(p, ')', rec + 1); break; |
| 353 | case '"': n = parsequotes(p); break; |
| 354 | case '[': |
| 355 | n = parseexp(p, ']', rec + 1); |
| 356 | if(n) n = lookup(n, 1); |
| 357 | break; |
| 358 | default: |
| 359 | { |
| 360 | const char *w = p; |
| 361 | p += strcspn(p, "])@; \t\n\r"); |
| 362 | n = lookup(newstring(w, p - w), 1); |
| 363 | break; |
| 364 | } |
| 365 | } |
| 366 | if(n) res.put(n, strlen(n)), delete[] n; |
| 367 | word = p; |
| 368 | } |
| 369 | else if(level > brak) { conoutf("too many @"); goto screrr; } |
| 370 | } |
| 371 | } |
| 372 | if(res.length()) |
| 373 | { |
| 374 | res.put(word, p - word - 1); |
| 375 | if(res.length() > CSLIMIT_STRINGLEN) { cslimiterr("string length"); return newstring(""); } |
| 376 | return newstring(res.getbuf(), res.length()); |
| 377 | } |
no test coverage detected