// Copyright (c) 2008 João Abecasis // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #ifndef SAGA_ADAPTORS_CONDOR_JOB_CLASSAD_HPP_INCLUDED #define SAGA_ADAPTORS_CONDOR_JOB_CLASSAD_HPP_INCLUDED #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace saga { namespace adaptors { namespace condor { // // Quick notes on the parser: // // - Lists and nested ClassAds not currently supported. // - XML headers and enclosing are not parsed and have to be // skipped externally. // // TODO // - Add an "unparser" // - Error recovery mechanisms: // * need more data // * skip to next entry if malformed // - Support lists and nested ClassAds // // References: // 1. Marvin Solomon (2005), ClassAd XML Document Type Definition, // http://www.cs.wisc.edu/condor/classad/refman/node8.html // struct classad : boost::spirit::grammar { private: struct actor { struct assign { assign(std::string & s) : s_(s) {} template void operator()(I const & b, I const & e) const { s_.assign(b, e); } private: std::string & s_; }; template struct assign_iterators_ { assign_iterators_(I & b, I & e) : b_(b), e_(e) {} void operator()(I const & b, I const & e) const { b_ = b; e_ = e; } private: I & b_; I & e_; }; template static assign_iterators_ assign_iterators(I & b, I & e) { return assign_iterators_(b, e); } struct clear { clear(std::string & str) : s_(str) {} template void operator()(I const &, I const &) const { s_.clear(); } private: std::string & s_; }; struct set_attribute { set_attribute(classad const & c, std::string & k, std::string const & t, std::string & v) : c_(c), k_(k), t_(t), v_(v) { } template void operator()(I const &, I const &) const { // TODO Use classad_type // TODO should we process numeric character references (in // the formats &#nnn; or &#xhhh;)? That will also // require messing with encodings. char const * escapes[][2] = { { """, "\"" }, { "&", "&" }, { "'", "'" }, { "<", "<" }, { ">", ">" } }; for (std::size_t i = 0; i < sizeof(escapes)/sizeof(*escapes); ++i) { boost::replace_all(k_, escapes[i][0], escapes[i][1]); boost::replace_all(v_, escapes[i][0], escapes[i][1]); } value v = { t_, v_ }; c_.attributes_[ k_ ] = v; } private: classad const & c_; std::string & k_; std::string const & t_; std::string & v_; }; }; public: enum classad_type { Integer, Real, String, ClassAdExpression, Boolean, AbsoluteTime, RelativeTime, Undefined, Error, List }; struct value { // classad_type type; std::string type; std::string value_; }; typedef std::map attribute_map_type; typedef attribute_map_type::iterator attribute_iterator; void clear() { attributes_.clear(); } void set_attribute(std::string const & key, /* classad_type type, */ std::string const & type, std::string const & val) { value v = { type, val }; attributes_[ key ] = v; } boost::optional get_attribute(std::string const & key) const { boost::optional attr; attribute_iterator iter = attributes_.find(key); if (attributes_.end() != iter) attr.reset(iter->second); return attr; } void remove_attribute(std::string const & key) const { attributes_.erase(key); } bool has_attribute(std::string const & key) const { return attributes_.count(key) ? true : false; } attribute_iterator attributes_begin() { return attributes_.begin(); } attribute_iterator attributes_end() { return attributes_.end(); } typedef boost::spirit::space_parser skipper; template struct definition { typedef boost::spirit::rule rule; definition(classad const & self) { BOOST_SPIRIT_DEBUG_RULE(entry_); BOOST_SPIRIT_DEBUG_RULE(attribute_); BOOST_SPIRIT_DEBUG_RULE(type_); BOOST_SPIRIT_DEBUG_RULE(bool_value_); BOOST_SPIRIT_DEBUG_RULE(value_); using boost::spirit::ch_p; using boost::spirit::chset; using boost::spirit::eps_p; using boost::spirit::lexeme_d; using boost::spirit::str_p; entry_ = str_p("") >> *( attribute_ ) >> ""; attribute_ = str_p("> "n=\"" >> ( * ~ch_p('\"') ) /* >>>>>>>>>>>>>>>>>>>>> */ [ actor::assign(attr_key_) ] >> '\"' >> '>' >> value_ >> str_p("") /* >>>>>>>>>>>>>>>>>>>>> */ [ actor::set_attribute(self, attr_key_, attr_type_, attr_value_) ]; bool_value_ = lexeme_d [ ch_p('<') >> str_p("b") /* >>>>>>>>>>>>>>>>>>>>> */ [ actor::assign(attr_type_) ] ] >> "v=\"" >> ( * ~ch_p('\"') ) /* >>>>>>>>>>>>>>>>>>>>> */ [ actor::assign(attr_value_) ] >> ch_p('\"') >> str_p("/>"); value_ = bool_value_ | lexeme_d [ ch_p('<') >> // TODO: lists ('l') and nested classads ('c') (chset("eirs")| "at" | "rt" | "un" | "er") /* >>>>>>>>>>>>>>>>>>>>> */ [ actor::assign(attr_type_) ] /* >>>>>>>>>>>>>>>>>>>>> */ [ actor::assign_iterators( type_begin_, type_end_) ] ] >> (ch_p('>') >> ( * ~ch_p('<') ) /* >>>>>>>>>>>>>>>>>>>>> */ [ actor::assign(attr_value_) ] >> lexeme_d [ "> str_p(boost::ref(type_begin_), boost::ref(type_end_)) ] >> '>' | str_p("/>") /* >>>>>>>>>>>>>>>>>>>>> */ [ actor::clear(attr_value_) ]); } rule const & start() const { return entry_; } private: std::string attr_key_; std::string attr_type_; std::string attr_value_; typedef typename Scanner::iterator_t iterator; iterator type_begin_; iterator type_end_; rule entry_, attribute_, type_, bool_value_, value_; }; private: std::map mutable attributes_; }; }}} // namespace saga::adaptors::condor #endif // include guard