#ifndef __JEEP__JCOMMENT__ #define __JEEP__JCOMMENT__ #include #include #include #include #include #include "JLang/JUUID.hh" #include "JLang/JException.hh" #include "Jeep/JPrint.hh" /** * \author mdejong */ namespace JEEP {} namespace JPP { using namespace JEEP; } namespace JEEP { using JLANG::JUUID; using JLANG::JNoValue; /** * Type definition of comment block. */ typedef std::vector JComment_t; /** * Auxiliary class for comment. * * A comment starts with a JComment::START_COMMENT and ends with a JComment::CLOSE_COMMENT.\n * The text between the quotes JComment::QUOTE is considered as one block which may cross newlines, etc.\n * The comments are appended. */ struct JComment : public JComment_t { enum { UUID_t = 0 //!< index of UUID }; static const char START_COMMENT = '#'; //!< start comment static const char CLOSE_COMMENT = '\n'; //!< close comment static const char START_SPECIAL = '$'; //!< start special comment static const char CLOSE_SPECIAL = '$'; //!< close special comment static const char QUOTE = '"'; //!< quote /** * Default constructor. */ JComment() {} /** * Update this comment with given UUID. * * \param uuid UUID * \return this comment */ JComment& update(const JUUID& uuid) { if (!this->hasUUID()) { if ((int) this->size() <= UUID_t) this->resize(UUID_t + 1); else this->insert(this->begin() + UUID_t, value_type()); } (*this)[UUID_t] = MAKE_STRING(START_SPECIAL << uuid << CLOSE_SPECIAL); return *this; } /** * Update this comment with random UUID. * * \return this comment */ JComment& update() { return this->update(JUUID::rndm()); } /** * Add comment. * * \param comment comment * \return this comment */ JComment& add(const std::string& comment) { this->push_back(comment); return this->update(); } /** * Add comment block. * * \param comment comment block * \return this comment */ JComment& add(const JComment_t& comment) { for (const_iterator i = comment.begin(); i != comment.end(); ++i) { this->push_back(*i); } return this->update(); } /** * Check if this comment has UUID. * * \return true if UUID present; else false */ bool hasUUID() const { return (UUID_t < (int) this->size() && is_special((*this)[UUID_t])); } /** * Get UUID. * * \return UUID */ JUUID getUUID() const { if (this->hasUUID()) { const std::string& buffer = (*this)[UUID_t]; return JUUID::valueOf(buffer.substr(1, buffer.size() - 2)); } else { THROW(JNoValue, "No UUID in comment."); } } /** * Read comment from input. * * \param in input stream * \param comment comment * \return input stream */ friend inline std::istream& operator>>(std::istream& in, JComment& comment) { using namespace std; while (in.peek() == (int) START_COMMENT) { in.get(); if (in.peek() == (int) ' ') { in.get(); } int c; string buffer; while ((c = in.get()) != EOF && c != (int) CLOSE_COMMENT) { buffer.push_back((char) c); if (c == (int) QUOTE) { while ((c = in.get()) != EOF && c != (int) QUOTE) { buffer.push_back((char) c); } buffer.push_back(QUOTE); } } comment.push_back(buffer); } return in; } /** * Write comment to output. * * \param out output stream * \param comment comment * \return output stream */ friend inline std::ostream& operator<<(std::ostream& out, const JComment& comment) { using namespace std; for (JComment::const_iterator i = comment.begin(); i != comment.end(); ++i) { out << START_COMMENT << ' ' << *i << CLOSE_COMMENT; } return out << flush; } /** * Check if given string is special. * * \param buffer input string * \return true if special; else false */ static bool is_special(const std::string& buffer) { const int N = buffer.size(); return (N > 2 && buffer[0] == START_SPECIAL && buffer[N-1] == CLOSE_SPECIAL); } }; } #endif