/* Mantra - http://www.neuromancy.net/mantra * (c) 2007-2009 - The Neuromancy Society * * This code is released under the Artistic License 2.0. If you have not * received a copy of the license with this source code, you may find * this license at: * http://www.opensource.org/licenses/artistic-license-2.0.php * * $Id: param_extractor.h 615 2010-03-10 04:08:58Z prez $ */ #ifndef MANTRA_ADMIN_EXTRACTOR_H #define MANTRA_ADMIN_EXTRACTOR_H 1 #include #include #include #include #include #include namespace mantra { namespace admin { class MANTRA_API param_extractor { public: virtual ~param_extractor() {} /** * @brief Extract a parameter from a string. * @param in The string to extract the parameter from. * @param pos The position the parameter was extracte from. * @param sz The amount of data removed from the input string. * @return The extracted parameter. * * The results should be interpereted as such: * - If the optional value is NOT set (!rv), then the line is * incomplete, and we need more data. * - If the return value is an empty string, and pos is * std::string::npos, we did not have enough fields. * - If the return value is an empty string, and pos is set * accurately (ie. it is not std::string::npos), then we * have extracted an empty field (which includes the case of * an empty string, but we want the first field). * - Otherwise, pos will indicate which */ virtual boost::optional operator()(const std::string &in, std::string::size_type &pos, std::string::size_type &sz) const = 0; // For people who don't care about the position/size stuff. virtual boost::optional operator()(std::string &in) const; }; /** * @brief Extract a word, given delimiters from a series of words. * * Notes on operation: * - Any character prefixed by a '\' will be treated as a literal, and skipped * by any parsing for delimiters, quotes or replacements. The leading '\' * will be removed from the output string, so you must use '\\' to have a * literal '\' in the stream. * - If the last character on the input is a '\' we will expect more data, and * as such a request for a field that includes the end of the line will * return continuation required (empty boost::optional). * - Any time a start quote is encountered without an end quote, we will expect * continuation (same as the above condition). * - If merge is turned on, any delimiters before the first field are skipped. */ class MANTRA_API word_param_extractor : public param_extractor { unsigned int skip_; bool merge_; std::set delim_; std::map quote_; std::map replace_; size_t is_delim(const std::string &in, size_t offs) const; std::string is_quote(const std::string &in, size_t offs) const; std::string is_replace(const std::string &in, size_t offs) const; size_t next_field(const std::string &in, std::string::size_type &offs, size_t &sz) const; void prepare_field(std::string &in) const; public: /** * @param skip How many fields to skip (0 = capture the first field). * @param merge Merge delimiters (so , == ,,, if , is a delimiter). */ word_param_extractor(unsigned int skip = 0, bool merge = true); word_param_extractor &add_delim(const std::string &in); word_param_extractor &add_quote(const std::string &begin, const std::string &end = std::string()); // NOTE: Replacements ONLY occur once a field has been identified. So // you should not have quotes or delimiters in it, or it may not function // as you expect. This is mainly to automatically replace '\n' with ' '. word_param_extractor &add_replace(const std::string &search, const std::string &replace = std::string()); using param_extractor::operator(); boost::optional operator()(const std::string &in, std::string::size_type &pos, std::string::size_type &sz) const; }; class MANTRA_API substring_param_extractor : public param_extractor { std::string::size_type start_, size_; public: substring_param_extractor(std::string::size_type start, std::string::size_type size = std::string::npos); using param_extractor::operator(); boost::optional operator()(const std::string &in, std::string::size_type &pos, std::string::size_type &sz) const; }; template const boost::shared_ptr &default_param_extractor(); template const boost::shared_ptr &alt_param_extractor(); // --------------------------------------------------------------------------- // Inline Functions // --------------------------------------------------------------------------- inline boost::optional param_extractor::operator()(std::string &in) const { std::string::size_type pos, sz; boost::optional rv = operator()(in, pos, sz); if (rv && pos != std::string::npos && sz) in.erase(pos, sz); return rv; } inline word_param_extractor::word_param_extractor(unsigned int skip, bool merge) : skip_(skip), merge_(merge) { } inline word_param_extractor &word_param_extractor::add_delim(const std::string &in) { if (!in.empty()) delim_.insert(in); return *this; } inline word_param_extractor &word_param_extractor::add_quote(const std::string &begin, const std::string &end) { if (!begin.empty()) quote_[begin] = end; return *this; } inline word_param_extractor &word_param_extractor::add_replace(const std::string &search, const std::string &replace) { if (!search.empty()) replace_[search] = replace; return *this; } inline substring_param_extractor::substring_param_extractor(std::string::size_type start, std::string::size_type size) : start_(start), size_(size) { } template const boost::shared_ptr &default_param_extractor() { static boost::shared_ptr pe; if (!pe) { word_param_extractor *wpe = new word_param_extractor(skip); wpe->add_delim(" ").add_delim("\t").add_delim("\n"); wpe->add_quote("\"").add_quote("'"); wpe->add_replace("\n", " "); pe.reset(wpe); } return pe; } template const boost::shared_ptr &alt_param_extractor() { static boost::shared_ptr pe; if (!pe) { word_param_extractor *wpe = new word_param_extractor(skip); wpe->add_delim(" ").add_delim("\t").add_delim("\n").add_delim("="); wpe->add_quote("\"").add_quote("'"); wpe->add_replace("\n", " "); pe.reset(wpe); } return pe; } } } // namespace mantra::admin #endif // MANTRA_ADMIN_EXTRACTOR_H