#include #include namespace t3devlib { namespace gen { /** Implementation of perl-like regular expressions to be used in a decoder * generated by T3DevKit. * * This class handles the regex compilation and execution. The result of * group matching is stored internally. * * It is designed to be used seamlessly in codets for T3DevKit, thus: * - it can interact with t3devlib data (Buffer, Variable, DecodeError) * - it reports errors using T3DevKit's exceptions * - it returns the length of the matches in bits * * * The regular expression is compiled at the construction of the object. Then * it can be used multiple times to search the regex in the buffer (with * Match() or AssertMatch()). * * After a regex search, it is possible to inspect the result at to take * actions with other member functions (GetMatchedLength(), MoveAt(), ...) * * \warning Apart from moving the cursor, the buffer MUST NOT be modified * between the call of Match() or AssertMatch() and the use of * inspection/action member functions (GetMatchedLength(), * MoveAt() ...) */ class Regex { public: typedef std::string::const_iterator iterator; /** Constructor * * This constructor compiles the regular expression given as a * parameter. It is based on the format of perl regular expressions. * * \warning it is assumed that regex is a static const string */ Regex(const char* regex) : mSource (regex), mRegex (regex, boost::regex_constants::perl | boost::regex_constants::no_mod_m) {} /** Try to match the regular expression in the buffer. * * The regular expression is searched in the buffer between the * position of its cursor and the first end marker set (thus between * the positions given by Buffer::GetPosition() and * Buffer::GetEndMarker()) * * \param buffer buffer on which the regex shall be searched * * \return true in case of success */ bool Match (Buffer& buffer) { mStart = iterator (reinterpret_cast (buffer.GetValueBin()) + (buffer.GetPosition() / 8)); mStop = iterator (reinterpret_cast (buffer.GetValueBin()) + (buffer.GetEndMarker() / 8)); int result = boost::regex_search (mStart, mStop, mResults, mRegex); return result; } /** Match the regular expression in the buffer or throw an exeption * if not successful. * * \param buffer buffer on which the regex shall be searched * \param v reference of the value being decoded; it is * used to allow locating the error in case an * exception is thrown */ void AssertMatch (Buffer& buffer, Variable* v) throw (DecodeError) { if (!Match (buffer)) { Error (v, buffer); } } /** Get the length of a group match * * \param id index of the '(...)' group to analyse (or 0 * to refer to the whole regular expression) * * \return the length of the group in bits */ int GetMatchedLength(int id = 0) { return mResults[id].length()*8; } /** Get the content of a group match * * \param id index of the '(...)' group to analyse (or 0 * to refer to the whole regular expression) * * \return the string matched by the group */ std::string GetMatchedString(int id = 0) { return std::string (mResults[id].first, mResults[id].second); } /** Move the cursor of the buffer past a group match * * \param id index of the '(...)' group to analyse (or 0 * to refer to the whole regular expression) */ void MovePast (Buffer& buffer, int id = 0) { buffer.SetPosition ((&*mResults[id].second - reinterpret_cast (buffer.GetValueBin())) * 8); } /** Move the cursor of the buffer at the beginning of group match * * \param id index of the '(...)' group to analyse (or 0 * to refer to the whole regular expression) */ void MoveAt (Buffer& buffer, int id = 0) { buffer.SetPosition ((&*mResults[id].first - reinterpret_cast (buffer.GetValueBin())) * 8); } /** Throw a decoding error * * This function will throw an exception telling that the codec * could not match the regular expression. The error message will * also contains details about the regular expression and the * content of the buffer at the position where the exception could * not be matched. * * \param v reference to the value being decoded * (used to locate the position of the error) * \param buffer buffer on which the regex could no be matched */ void Error (Variable* v, Buffer& buffer) throw (DecodeError) { std::string message ("cannot match regex /"); message += mSource; message += "/ in '"; if ((mStop - mStart) > 40) { message.append (&*mStart, 40); message += "..."; } else { message.append (mStart, mStop); } message += "'\n"; throw DecodeError (v, message); } private: /** source of the regular expression (should be a static string) */ const char* mSource; /** boost regex object used to implement the regular expression */ boost::regex mRegex; /** iterators delimiting the positions in the buffer where the regex * is applied (between GetPosition() and GetEndMarker) */ iterator mStart, mStop; /** boost match result used to store the results of the regex search */ boost::match_results mResults; }; }} //namespaces