1 /*============================================================================= 2 Boost.Wave: A Standard compliant C++ preprocessor library 3 4 http://www.boost.org/ 5 6 Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost 7 Software License, Version 1.0. (See accompanying file 8 LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9 =============================================================================*/ 10 11 #if !defined(BOOST_MACRO_HELPERS_HPP_931BBC99_EBFA_4692_8FBE_B555998C2C39_INCLUDED) 12 #define BOOST_MACRO_HELPERS_HPP_931BBC99_EBFA_4692_8FBE_B555998C2C39_INCLUDED 13 14 #include <vector> 15 16 #include <boost/assert.hpp> 17 #include <boost/wave/wave_config.hpp> 18 #include <boost/wave/token_ids.hpp> 19 #include <boost/wave/cpplexer/validate_universal_char.hpp> 20 #include <boost/wave/util/unput_queue_iterator.hpp> 21 22 // this must occur after all of the includes and before any code appears 23 #ifdef BOOST_HAS_ABI_HEADERS 24 #include BOOST_ABI_PREFIX 25 #endif 26 27 /////////////////////////////////////////////////////////////////////////////// 28 namespace boost { 29 namespace wave { 30 namespace util { 31 32 namespace impl { 33 34 // escape a string literal (insert '\\' before every '\"', '?' and '\\') 35 template <typename StringT> 36 inline StringT escape_lit(StringT const & value)37 escape_lit(StringT const &value) 38 { 39 StringT result; 40 typename StringT::size_type pos = 0; 41 typename StringT::size_type pos1 = value.find_first_of ("\"\\?", 0); 42 if (StringT::npos != pos1) { 43 do { 44 result += value.substr(pos, pos1-pos) 45 + StringT("\\") 46 + StringT(1, value[pos1]); 47 pos1 = value.find_first_of ("\"\\?", pos = pos1+1); 48 } while (StringT::npos != pos1); 49 result += value.substr(pos); 50 } 51 else { 52 result = value; 53 } 54 return result; 55 } 56 57 // un-escape a string literal (remove '\\' just before '\\', '\"' or '?') 58 template <typename StringT> 59 inline StringT unescape_lit(StringT const & value)60 unescape_lit(StringT const &value) 61 { 62 StringT result; 63 typename StringT::size_type pos = 0; 64 typename StringT::size_type pos1 = value.find_first_of ("\\", 0); 65 if (StringT::npos != pos1) { 66 do { 67 switch (value[pos1+1]) { 68 case '\\': 69 case '\"': 70 case '?': 71 result = result + value.substr(pos, pos1-pos); 72 pos1 = value.find_first_of ("\\", (pos = pos1+1)+1); 73 break; 74 75 case 'n': 76 result = result + value.substr(pos, pos1-pos) + "\n"; 77 pos1 = value.find_first_of ("\\", pos = pos1+1); 78 ++pos; 79 break; 80 81 default: 82 result = result + value.substr(pos, pos1-pos+1); 83 pos1 = value.find_first_of ("\\", pos = pos1+1); 84 } 85 86 } while (pos1 != StringT::npos); 87 result = result + value.substr(pos); 88 } 89 else { 90 // the string doesn't contain any escaped character sequences 91 result = value; 92 } 93 return result; 94 } 95 96 // return the string representation of a token sequence 97 template <typename ContainerT, typename PositionT> 98 inline typename ContainerT::value_type::string_type as_stringlit(ContainerT const & token_sequence,PositionT const & pos)99 as_stringlit (ContainerT const &token_sequence, PositionT const &pos) 100 { 101 using namespace boost::wave; 102 typedef typename ContainerT::value_type::string_type string_type; 103 104 string_type result("\""); 105 bool was_whitespace = false; 106 typename ContainerT::const_iterator end = token_sequence.end(); 107 for (typename ContainerT::const_iterator it = token_sequence.begin(); 108 it != end; ++it) 109 { 110 token_id id = token_id(*it); 111 112 if (IS_CATEGORY(*it, WhiteSpaceTokenType) || T_NEWLINE == id) { 113 if (!was_whitespace) { 114 // C++ standard 16.3.2.2 [cpp.stringize] 115 // Each occurrence of white space between the argument's 116 // preprocessing tokens becomes a single space character in the 117 // character string literal. 118 result += " "; 119 was_whitespace = true; 120 } 121 } 122 else if (T_STRINGLIT == id || T_CHARLIT == id) { 123 // string literals and character literals have to be escaped 124 result += impl::escape_lit((*it).get_value()); 125 was_whitespace = false; 126 } 127 else 128 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 129 if (T_PLACEMARKER != id) 130 #endif 131 { 132 // now append this token to the string 133 result += (*it).get_value(); 134 was_whitespace = false; 135 } 136 } 137 result += "\""; 138 139 // validate the resulting literal to contain no invalid universal character 140 // value (throws if invalid chars found) 141 boost::wave::cpplexer::impl::validate_literal(result, pos.get_line(), 142 pos.get_column(), pos.get_file()); 143 return result; 144 } 145 146 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 147 // return the string representation of a token sequence 148 template <typename ContainerT, typename PositionT> 149 inline typename ContainerT::value_type::string_type as_stringlit(std::vector<ContainerT> const & arguments,typename std::vector<ContainerT>::size_type i,PositionT const & pos)150 as_stringlit (std::vector<ContainerT> const &arguments, 151 typename std::vector<ContainerT>::size_type i, PositionT const &pos) 152 { 153 using namespace boost::wave; 154 typedef typename ContainerT::value_type::string_type string_type; 155 156 BOOST_ASSERT(i < arguments.size()); 157 158 string_type result("\""); 159 bool was_whitespace = false; 160 161 for (/**/; i < arguments.size(); ++i) { 162 // stringize all remaining arguments 163 typename ContainerT::const_iterator end = arguments[i].end(); 164 for (typename ContainerT::const_iterator it = arguments[i].begin(); 165 it != end; ++it) 166 { 167 token_id id = token_id(*it); 168 169 if (IS_CATEGORY(*it, WhiteSpaceTokenType) || T_NEWLINE == id) { 170 if (!was_whitespace) { 171 // C++ standard 16.3.2.2 [cpp.stringize] 172 // Each occurrence of white space between the argument's 173 // preprocessing tokens becomes a single space character in the 174 // character string literal. 175 result += " "; 176 was_whitespace = true; 177 } 178 } 179 else if (T_STRINGLIT == id || T_CHARLIT == id) { 180 // string literals and character literals have to be escaped 181 result += impl::escape_lit((*it).get_value()); 182 was_whitespace = false; 183 } 184 else if (T_PLACEMARKER != id) { 185 // now append this token to the string 186 result += (*it).get_value(); 187 was_whitespace = false; 188 } 189 } 190 191 // append comma, if not last argument 192 if (i < arguments.size()-1) { 193 result += ","; 194 was_whitespace = false; 195 } 196 } 197 result += "\""; 198 199 // validate the resulting literal to contain no invalid universal character 200 // value (throws if invalid chars found) 201 boost::wave::cpplexer::impl::validate_literal(result, pos.get_line(), 202 pos.get_column(), pos.get_file()); 203 return result; 204 } 205 #endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 206 207 // return the string representation of a token sequence 208 template <typename StringT, typename IteratorT> 209 inline StringT as_string(IteratorT it,IteratorT const & end)210 as_string(IteratorT it, IteratorT const& end) 211 { 212 StringT result; 213 for (/**/; it != end; ++it) 214 { 215 result += (*it).get_value(); 216 } 217 return result; 218 } 219 220 // return the string representation of a token sequence 221 template <typename ContainerT> 222 inline typename ContainerT::value_type::string_type as_string(ContainerT const & token_sequence)223 as_string (ContainerT const &token_sequence) 224 { 225 typedef typename ContainerT::value_type::string_type string_type; 226 return as_string<string_type>(token_sequence.begin(), 227 token_sequence.end()); 228 } 229 230 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 231 /////////////////////////////////////////////////////////////////////////// 232 // 233 // Copies all arguments beginning with the given index to the output 234 // sequence. The arguments are separated by commas. 235 // 236 template <typename ContainerT, typename PositionT> replace_ellipsis(std::vector<ContainerT> const & arguments,typename ContainerT::size_type index,ContainerT & expanded,PositionT const & pos)237 void replace_ellipsis (std::vector<ContainerT> const &arguments, 238 typename ContainerT::size_type index, 239 ContainerT &expanded, PositionT const &pos) 240 { 241 using namespace cpplexer; 242 typedef typename ContainerT::value_type token_type; 243 244 token_type comma(T_COMMA, ",", pos); 245 for (/**/; index < arguments.size(); ++index) { 246 ContainerT const &arg = arguments[index]; 247 248 std::copy(arg.begin(), arg.end(), 249 std::inserter(expanded, expanded.end())); 250 251 if (index < arguments.size()-1) 252 expanded.push_back(comma); 253 } 254 } 255 256 #if BOOST_WAVE_SUPPORT_VA_OPT != 0 257 /////////////////////////////////////////////////////////////////////////// 258 // 259 // Finds the token range inside __VA_OPT__. 260 // Updates mdit to the position of the final rparen. 261 // If the parenthesis do not match up, or there are none, returns false 262 // and leaves mdit unchanged. 263 // 264 template <typename MDefIterT> find_va_opt_args(MDefIterT & mdit,MDefIterT mdend)265 bool find_va_opt_args ( 266 MDefIterT & mdit, // VA_OPT 267 MDefIterT mdend) 268 { 269 if ((std::distance(mdit, mdend) < 3) || 270 (T_LEFTPAREN != next_token<MDefIterT>::peek(mdit, mdend))) { 271 return false; 272 } 273 274 MDefIterT mdstart_it = mdit; 275 ++mdit; // skip to lparen 276 std::size_t scope = 0; 277 // search for final rparen, leaving iterator there 278 for (; (mdit != mdend) && !((scope == 1) && (T_RIGHTPAREN == token_id(*mdit))); 279 ++mdit) { 280 // count balanced parens 281 if (T_RIGHTPAREN == token_id(*mdit)) { 282 scope--; 283 } else if (T_LEFTPAREN == token_id(*mdit)) { 284 scope++; 285 } 286 } 287 if ((mdit == mdend) && ((scope != 1) || (T_RIGHTPAREN != token_id(*mdit)))) { 288 // arrived at end without matching rparen 289 mdit = mdstart_it; 290 return false; 291 } 292 293 return true; 294 } 295 296 #endif 297 #endif 298 299 // Skip all whitespace characters and queue the skipped characters into the 300 // given container 301 template <typename IteratorT> 302 inline boost::wave::token_id skip_whitespace(IteratorT & first,IteratorT const & last)303 skip_whitespace(IteratorT &first, IteratorT const &last) 304 { 305 token_id id = util::impl::next_token<IteratorT>::peek(first, last, false); 306 if (IS_CATEGORY(id, WhiteSpaceTokenType)) { 307 do { 308 ++first; 309 id = util::impl::next_token<IteratorT>::peek(first, last, false); 310 } while (IS_CATEGORY(id, WhiteSpaceTokenType)); 311 } 312 ++first; 313 return id; 314 } 315 316 template <typename IteratorT, typename ContainerT> 317 inline boost::wave::token_id skip_whitespace(IteratorT & first,IteratorT const & last,ContainerT & queue)318 skip_whitespace(IteratorT &first, IteratorT const &last, ContainerT &queue) 319 { 320 queue.push_back (*first); // queue up the current token 321 322 token_id id = util::impl::next_token<IteratorT>::peek(first, last, false); 323 if (IS_CATEGORY(id, WhiteSpaceTokenType)) { 324 do { 325 queue.push_back(*++first); // queue up the next whitespace 326 id = util::impl::next_token<IteratorT>::peek(first, last, false); 327 } while (IS_CATEGORY(id, WhiteSpaceTokenType)); 328 } 329 ++first; 330 return id; 331 } 332 333 // trim all whitespace from the beginning and the end of the given string 334 template <typename StringT> 335 inline StringT trim_whitespace(StringT const & s)336 trim_whitespace(StringT const &s) 337 { 338 typedef typename StringT::size_type size_type; 339 340 size_type first = s.find_first_not_of(" \t\v\f"); 341 if (StringT::npos == first) 342 return StringT(); 343 size_type last = s.find_last_not_of(" \t\v\f"); 344 return s.substr(first, last-first+1); 345 } 346 347 } // namespace impl 348 349 /////////////////////////////////////////////////////////////////////////////// 350 } // namespace util 351 } // namespace wave 352 } // namespace boost 353 354 // the suffix header occurs after all of the code 355 #ifdef BOOST_HAS_ABI_HEADERS 356 #include BOOST_ABI_SUFFIX 357 #endif 358 359 #endif // !defined(BOOST_MACRO_HELPERS_HPP_931BBC99_EBFA_4692_8FBE_B555998C2C39_INCLUDED) 360