diff --git a/src/olympic/CMakeLists.txt b/src/olympic/CMakeLists.txt index f054cdac..9661197f 100644 --- a/src/olympic/CMakeLists.txt +++ b/src/olympic/CMakeLists.txt @@ -19,6 +19,9 @@ else() endif() add_subdirectory(applib) +if(NOT APPLE) + add_subdirectory(hull) +endif() add_subdirectory(keel) add_subdirectory(turbine) if(${OLYMPIC_BUILD_STUDIO}) diff --git a/src/olympic/hull/CMakeLists.txt b/src/olympic/hull/CMakeLists.txt new file mode 100644 index 00000000..5fc56b05 --- /dev/null +++ b/src/olympic/hull/CMakeLists.txt @@ -0,0 +1,12 @@ + +add_library(Hull) +target_sources( + Hull PUBLIC + FILE_SET CXX_MODULES FILES + hull.cpp +) + +target_link_libraries( + Hull PUBLIC + OxStd +) diff --git a/src/olympic/hull/hull.cpp b/src/olympic/hull/hull.cpp new file mode 100644 index 00000000..9a9d7ca2 --- /dev/null +++ b/src/olympic/hull/hull.cpp @@ -0,0 +1,98 @@ +/* + * Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +module; + +#include + +export module hull; + +namespace hull { + +export +template +constexpr ox::Result> parseCmd(ox::StringViewCR cmd) noexcept + requires(ox::is_same_v || ox::is_same_v) { + auto const tokens = split(cmd, ' '); + ox::Vector args; + char waitingFor{}; + auto const handleString = [&waitingFor, &args]( + ox::StringViewCR token, + char const delimiter) { + if (endsWith(token, delimiter)) { + args.emplace_back(substr(token, 1, token.size() - 1)); + } else { + waitingFor = delimiter; + args.emplace_back(substr(token, 1)); + } + }; + for (auto const &token : tokens) { + if (waitingFor) { + if (endsWith(token, waitingFor)) { + waitingFor = 0; + } + auto &tgt = *args.back().value; + if constexpr (ox::is_same_v) { + tgt += substr(token, 0, token.size() - 1); + } else { + tgt = {tgt.data(), tgt.size() + token.size() - 1}; + } + } else if (beginsWith(token, '"')) { + handleString(token, '"'); + } else if (beginsWith(token, '\'')) { + handleString(token, '\''); + } else { + args.emplace_back(token); + } + } + if (waitingFor) { + return ox::Error{1, "unterminated string"}; + } + return args; +} + +template +[[nodiscard]] +static constexpr bool testParse(ox::StringViewCR cmd, std::initializer_list const &expected) noexcept { + auto const [args, err] = parseCmd(cmd); + static constexpr auto equals = [](auto const &a, auto const &b) { + if (a.size() != b.size()) { + return false; + } + for (auto i = 0u; i < a.size(); ++i) { + if (a[i] != b[i]) { + return false; + } + } + return true; + }; + return !err && equals(args, ox::Vector(expected)); +} + +static_assert(testParse("echo asdf", {"echo", "asdf"})); +static_assert(testParse("echo asdf", {"echo", "asdf"})); + +static_assert(testParse("echo \"asdf\"", {"echo", "asdf"})); +static_assert(testParse("echo \"asdf\"", {"echo", "asdf"})); + +static_assert(testParse("echo 'asdf'", {"echo", "asdf"})); +static_assert(testParse("echo 'asdf'", {"echo", "asdf"})); + +static_assert(testParse("echo 'asdf' aoue", {"echo", "asdf", "aoue"})); +static_assert(testParse("echo 'asdf' aoue", {"echo", "asdf", "aoue"})); + +export class Prompt { + + private: + ox::String m_cmd; + ox::String m_workingDir{"/"}; + ox::Vector m_prevCmds; + + public: + + private: + +}; + +}