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(MACRO_HELPERS_HPP_931BBC99_EBFA_4692_8FBE_B555998C2C39_INCLUDED)
12 #define 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 #endif
256 
257     // Skip all whitespace characters and queue the skipped characters into the
258     // given container
259     template <typename IteratorT>
260     inline boost::wave::token_id
skip_whitespace(IteratorT & first,IteratorT const & last)261     skip_whitespace(IteratorT &first, IteratorT const &last)
262     {
263         token_id id = util::impl::next_token<IteratorT>::peek(first, last, false);
264         if (IS_CATEGORY(id, WhiteSpaceTokenType)) {
265             do {
266                 ++first;
267                 id = util::impl::next_token<IteratorT>::peek(first, last, false);
268             } while (IS_CATEGORY(id, WhiteSpaceTokenType));
269         }
270         ++first;
271         return id;
272     }
273 
274     template <typename IteratorT, typename ContainerT>
275     inline boost::wave::token_id
skip_whitespace(IteratorT & first,IteratorT const & last,ContainerT & queue)276     skip_whitespace(IteratorT &first, IteratorT const &last, ContainerT &queue)
277     {
278         queue.push_back (*first);       // queue up the current token
279 
280         token_id id = util::impl::next_token<IteratorT>::peek(first, last, false);
281         if (IS_CATEGORY(id, WhiteSpaceTokenType)) {
282             do {
283                 queue.push_back(*++first);  // queue up the next whitespace
284                 id = util::impl::next_token<IteratorT>::peek(first, last, false);
285             } while (IS_CATEGORY(id, WhiteSpaceTokenType));
286         }
287         ++first;
288         return id;
289     }
290 
291 }   // namespace impl
292 
293 ///////////////////////////////////////////////////////////////////////////////
294 }   // namespace util
295 }   // namespace wave
296 }   // namespace boost
297 
298 // the suffix header occurs after all of the code
299 #ifdef BOOST_HAS_ABI_HEADERS
300 #include BOOST_ABI_SUFFIX
301 #endif
302 
303 #endif // !defined(MACRO_HELPERS_HPP_931BBC99_EBFA_4692_8FBE_B555998C2C39_INCLUDED)
304