A grouped MIMO output is requested EXPLICITLY as a single structured `outputs` entry " : , ,..., ": the host then materializes ONE topic named with those N named columns (column k = the script's k-th result), instead of N separate scalar topics. Returns {topic, [fields]} when the single output entry has that shape (non-empty topic + >= 1 non-empty field); otherwi
| 453 | // intent unambiguous (unlike inferring a shared prefix) and entirely host-side — |
| 454 | // the plugin opts in by naming, e.g. outputs = {"rpy:roll,pitch,yaw"}. |
| 455 | std::pair<std::string, std::vector<std::string>> parseGroupedOutput(const std::vector<std::string>& outputs) { |
| 456 | if (outputs.size() != 1) { |
| 457 | return {"", {}}; |
| 458 | } |
| 459 | const std::string& spec = outputs.front(); |
| 460 | const auto colon = spec.find(':'); |
| 461 | if (colon == std::string::npos || colon == 0) { |
| 462 | return {"", {}}; |
| 463 | } |
| 464 | const std::string topic = spec.substr(0, colon); |
| 465 | std::vector<std::string> fields; |
| 466 | std::size_t start = colon + 1; |
| 467 | while (start <= spec.size()) { |
| 468 | const std::size_t comma = spec.find(',', start); |
| 469 | const std::size_t end = (comma == std::string::npos) ? spec.size() : comma; |
| 470 | std::string field = spec.substr(start, end - start); |
| 471 | const auto b = field.find_first_not_of(" \t"); |
| 472 | const auto e = field.find_last_not_of(" \t"); |
| 473 | if (b != std::string::npos) { |
| 474 | fields.push_back(field.substr(b, e - b + 1)); |
| 475 | } |
| 476 | if (comma == std::string::npos) { |
| 477 | break; |
| 478 | } |
| 479 | start = comma + 1; |
| 480 | } |
| 481 | if (fields.empty()) { |
| 482 | return {"", {}}; |
| 483 | } |
| 484 | return {topic, std::move(fields)}; |
| 485 | } |
| 486 | |
| 487 | } // namespace |
| 488 |
no test coverage detected