| 521 | } |
| 522 | |
| 523 | int ConfigCommand::Search(const std::string& inputPath, const std::string& query) |
| 524 | { |
| 525 | ParamFile cfg; |
| 526 | if (!ParseConfig(cfg, inputPath)) |
| 527 | { |
| 528 | std::cerr << "Error: failed to parse config: " << inputPath << std::endl; |
| 529 | return 1; |
| 530 | } |
| 531 | |
| 532 | std::string q = query; |
| 533 | while (!q.empty() && q.front() == ' ') |
| 534 | q.erase(0, 1); |
| 535 | while (!q.empty() && q.back() == ' ') |
| 536 | q.pop_back(); |
| 537 | |
| 538 | if (q.empty()) |
| 539 | { |
| 540 | std::cerr << "Error: empty query" << std::endl; |
| 541 | return 1; |
| 542 | } |
| 543 | |
| 544 | if (q.find(">>") != std::string::npos) |
| 545 | { |
| 546 | std::vector<std::string> parts; |
| 547 | std::string rem = q; |
| 548 | while (true) |
| 549 | { |
| 550 | auto pos = rem.find(">>"); |
| 551 | if (pos == std::string::npos) |
| 552 | { |
| 553 | while (!rem.empty() && rem.front() == ' ') |
| 554 | rem.erase(0, 1); |
| 555 | while (!rem.empty() && rem.back() == ' ') |
| 556 | rem.pop_back(); |
| 557 | if (!rem.empty()) |
| 558 | parts.push_back(rem); |
| 559 | break; |
| 560 | } |
| 561 | std::string part = rem.substr(0, pos); |
| 562 | while (!part.empty() && part.front() == ' ') |
| 563 | part.erase(0, 1); |
| 564 | while (!part.empty() && part.back() == ' ') |
| 565 | part.pop_back(); |
| 566 | if (!part.empty()) |
| 567 | parts.push_back(part); |
| 568 | rem = rem.substr(pos + 2); |
| 569 | } |
| 570 | |
| 571 | const ParamClass* cur = &cfg; |
| 572 | std::string pathSoFar; |
| 573 | for (size_t pi = 0; pi < parts.size() && cur; pi++) |
| 574 | { |
| 575 | const std::string& p = parts[pi]; |
| 576 | pathSoFar += (pathSoFar.empty() ? "" : " >> ") + p; |
| 577 | const ParamEntry* found = cur->FindEntryNoInheritance(p.c_str()); |
| 578 | if (!found) |
| 579 | { |
| 580 | std::cerr << "Not found: " << pathSoFar << std::endl; |
nothing calls this directly
no test coverage detected