#ifndef __JSYSTEM__JSHELL__ #define __JSYSTEM__JSHELL__ #include #include #include #include "JSystem/JProcess.hh" #include "JLang/JFileStream.hh" #include "JLang/JNullStream.hh" #include "JLang/JAbstractObjectStatus.hh" /** * \file * Shell interaction via I/O streams. * \author mdejong */ namespace JSYSTEM {} namespace JPP { using namespace JSYSTEM; } namespace JSYSTEM { using JLANG::JFileStream; using JLANG::JAbstractObjectStatus; using JLANG::null; /** * The JShell clas can be used to interact with the shell via I/O streams. */ class JShell : public JProcess, public JFileStream, public JAbstractObjectStatus { public: using std::istream::get; using JAbstractObjectStatus::operator bool; /** * Constructor. * * \param size size of internal buffer */ JShell(const std::size_t size = 65536) : JProcess(), JFileStream(JProcess::out, JProcess::in, size) { using namespace std; prompt = "_abc321_"; static_cast(*this) << "set prompt=" << prompt << endl; static_cast(*this) << "echo hello" << endl; flush(); } /** * Destructor. */ ~JShell() { this->exit(); } /** * Get reference to unique instance of this class object. * * \return reference to this class object */ static JShell& getInstance() { static JShell shell; return shell; } /** * Get prompt. * * \return prompt */ const std::string& getPrompt() const { return prompt; } /** * Get value. * * Note that * - in case of success, the input stream is flushed; and * - in case of failure, the input stream is cleared and flushed. * * \param value value * \return true if valid; else false */ template inline bool get(T& value) { using namespace std; if (*this >> value) { this->flush(); return true; } else { static_cast(*this).clear(); this->flush(); return false; } } /** * Get line of text. * * Extracts characters from this shell and stores them into the given buffer * until the end of line character is found or the prompt is read. * * \param buffer buffer * \param eol end of line character * \return true if valid; else false */ inline bool getline(std::string& buffer, const char eol = '\n') { using namespace std; buffer.clear(); while (this->getStatus()) { const int c = this->get(); if (c == streambuf::traits_type::eof()) { return !buffer.empty(); } else if (c == eol) { return true; } else { buffer += (char) c; if (buffer.size() >= prompt.size()) { const size_t pos = buffer.size() - this->prompt.size(); if (buffer.substr(pos) == this->prompt) { buffer.erase(pos); return !buffer.empty(); } } } } return false; } /** * Extracts characters from this shell and flush them to the given output stream * until the prompt is read. * * \param out output stream * \return this shell */ JShell& flush(std::ostream& out = null) { using namespace std; for (string buffer; this->getline(buffer); ) { out << buffer << endl; } return *this; } /** * Get status of this shell. * * \return status of this shell */ virtual bool getStatus() const override { return ((bool) static_cast(*this) && (bool) static_cast(*this)); } /** * Exit this shell. */ void exit() { using namespace std; static_cast(*this) << "exit" << endl; } protected: std::string prompt; private: JShell(const JShell&); JShell(JShell&&); JShell& operator=(const JShell&); JShell& operator=(JShell&&); }; } #endif