1 /*=============================================================================
2     Boost.Wave: A Standard compliant C++ preprocessor library
3     http://www.boost.org/
4 
5     Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost
6     Software License, Version 1.0. (See accompanying file
7     LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 =============================================================================*/
9 
10 #if !defined(BOOST_WAVE_emit_custom_line_directives_HOOKS_INCLUDED)
11 #define BOOST_WAVE_emit_custom_line_directives_HOOKS_INCLUDED
12 
13 #include <cstdio>
14 #include <ostream>
15 #include <string>
16 #include <algorithm>
17 
18 #include <boost/assert.hpp>
19 #include <boost/config.hpp>
20 
21 #include <boost/wave/token_ids.hpp>
22 #include <boost/wave/util/macro_helpers.hpp>
23 #include <boost/wave/preprocessing_hooks.hpp>
24 
25 ///////////////////////////////////////////////////////////////////////////////
26 //
27 //  The emit_custom_line_directives_hooks policy class is used to register some
28 //  of the more advanced (and probably more rarely used hooks with the Wave
29 //  library.
30 //
31 //  This policy type is used as a template parameter to the boost::wave::context<>
32 //  object.
33 //
34 ///////////////////////////////////////////////////////////////////////////////
35 class emit_custom_line_directives_hooks
36 :   public boost::wave::context_policies::default_preprocessing_hooks
37 {
38 public:
39     ///////////////////////////////////////////////////////////////////////////
40     //
41     //  The function 'emit_line_directive' is called whenever a #line directive
42     //  has to be emitted into the generated output.
43     //
44     //  The parameter 'ctx' is a reference to the context object used for
45     //  instantiating the preprocessing iterators by the user.
46     //
47     //  The parameter 'pending' may be used to push tokens back into the input
48     //  stream, which are to be used instead of the default output generated
49     //  for the #line directive.
50     //
51     //  The parameter 'act_token' contains the actual #pragma token, which may
52     //  be used for error output. The line number stored in this token can be
53     //  used as the line number emitted as part of the #line directive.
54     //
55     //  If the return value is 'false', a default #line directive is emitted
56     //  by the library. A return value of 'true' will inhibit any further
57     //  actions, the tokens contained in 'pending' will be copied verbatim
58     //  to the output.
59     //
60     ///////////////////////////////////////////////////////////////////////////
61     template <typename ContextT, typename ContainerT>
62     bool
emit_line_directive(ContextT const & ctx,ContainerT & pending,typename ContextT::token_type const & act_token)63     emit_line_directive(ContextT const& ctx, ContainerT &pending,
64         typename ContextT::token_type const& act_token)
65     {
66     // emit a #line directive showing the relative filename instead
67     typename ContextT::position_type pos = act_token.get_position();
68     unsigned int column = 1;
69 
70         typedef typename ContextT::token_type result_type;
71         using namespace boost::wave;
72 
73         pos.set_column(column);
74         pending.push_back(result_type(T_POUND, "#", pos));
75 
76         pos.set_column(++column);      // account for '#'
77         pending.push_back(result_type(T_SPACE, " ", pos));
78 
79     // 21 is the max required size for a 64 bit integer represented as a
80     // string
81     char buffer[22];
82 
83         using namespace std;    // for some systems sprintf is in namespace std
84         sprintf (buffer, "%d", pos.get_line());
85 
86         pos.set_column(++column);                 // account for ' '
87         pending.push_back(result_type(T_INTLIT, buffer, pos));
88         pos.set_column(column += (unsigned int)strlen(buffer)); // account for <number>
89         pending.push_back(result_type(T_SPACE, " ", pos));
90         pos.set_column(++column);                 // account for ' '
91 
92     std::string file("\"");
93     boost::filesystem::path filename(
94         boost::wave::util::create_path(ctx.get_current_relative_filename().c_str()));
95 
96         using boost::wave::util::impl::escape_lit;
97         file += escape_lit(boost::wave::util::native_file_string(filename)) + "\"";
98 
99         pending.push_back(result_type(T_STRINGLIT, file.c_str(), pos));
100         pos.set_column(column += (unsigned int)file.size());    // account for filename
101         pending.push_back(result_type(T_GENERATEDNEWLINE, "\n", pos));
102 
103         return true;
104     }
105 };
106 
107 #endif // !defined(BOOST_WAVE_ADVANCED_PREPROCESSING_HOOKS_INCLUDED)
108