1 /*=============================================================================
2     Copyright (c) 2002 2004 2006 Joel de Guzman
3     Copyright (c) 2004 Eric Niebler
4     Copyright (c) 2005 Thomas Guest
5     http://spirit.sourceforge.net/
6 
7     Use, modification and distribution is subject to the Boost Software
8     License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
9     http://www.boost.org/LICENSE_1_0.txt)
10 =============================================================================*/
11 #include "state.hpp"
12 #include "state_save.hpp"
13 #include "document_state.hpp"
14 #include "quickbook.hpp"
15 #include "grammar.hpp"
16 #include "native_text.hpp"
17 #include "utils.hpp"
18 #include "phrase_tags.hpp"
19 #include <boost/foreach.hpp>
20 
21 #if (defined(BOOST_MSVC) && (BOOST_MSVC <= 1310))
22 #pragma warning(disable:4355)
23 #endif
24 
25 namespace quickbook
26 {
27     char const* quickbook_get_date = "__quickbook_get_date__";
28     char const* quickbook_get_time = "__quickbook_get_time__";
29 
30     unsigned qbk_version_n = 0; // qbk_major_version * 100 + qbk_minor_version
31 
state(fs::path const & filein_,fs::path const & xinclude_base_,string_stream & out_,document_state & document)32     state::state(fs::path const& filein_, fs::path const& xinclude_base_,
33             string_stream& out_, document_state& document)
34         : grammar_()
35 
36         , order_pos(0)
37         , xinclude_base(xinclude_base_)
38 
39         , templates()
40         , error_count(0)
41         , anchors()
42         , warned_about_breaks(false)
43         , conditional(true)
44         , document(document)
45         , callouts()
46         , callout_depth(0)
47         , dependencies()
48         , explicit_list(false)
49 
50         , imported(false)
51         , macro()
52         , source_mode()
53         , source_mode_next()
54         , source_mode_next_pos()
55         , current_file(0)
56         , current_path(filein_, 0, filein_.filename())
57 
58         , template_depth(0)
59         , min_section_level(1)
60 
61         , in_list(false)
62         , in_list_save()
63         , out(out_)
64         , phrase()
65 
66         , values(&current_file)
67     {
68         // add the predefined macros
69         macro.add
70             ("__DATE__", std::string(quickbook_get_date))
71             ("__TIME__", std::string(quickbook_get_time))
72             ("__FILENAME__", std::string())
73         ;
74         update_filename_macro();
75 
76         boost::scoped_ptr<quickbook_grammar> g(
77             new quickbook_grammar(*this));
78         grammar_.swap(g);
79     }
80 
grammar() const81     quickbook_grammar& state::grammar() const {
82         return *grammar_;
83     }
84 
update_filename_macro()85     void state::update_filename_macro() {
86         *boost::spirit::classic::find(macro, "__FILENAME__")
87             = detail::encode_string(
88                     detail::path_to_generic(current_path.abstract_file_path));
89     }
90 
get_new_order_pos()91     unsigned state::get_new_order_pos() {
92         return ++order_pos;
93     }
94 
push_output()95     void state::push_output() {
96         out.push();
97         phrase.push();
98         in_list_save.push(in_list);
99     }
100 
pop_output()101     void state::pop_output() {
102         phrase.pop();
103         out.pop();
104         in_list = in_list_save.top();
105         in_list_save.pop();
106     }
107 
tagged_source_mode() const108     source_mode_info state::tagged_source_mode() const {
109         source_mode_info result;
110 
111         BOOST_FOREACH(source_mode_info const& s, tagged_source_mode_stack) {
112             result.update(s);
113         }
114 
115         return result;
116     }
117 
current_source_mode() const118     source_mode_info state::current_source_mode() const {
119         source_mode_info result = source_mode;
120 
121         result.update(document.section_source_mode());
122 
123         BOOST_FOREACH(source_mode_info const& s, tagged_source_mode_stack) {
124             result.update(s);
125         }
126 
127         return result;
128     }
129 
change_source_mode(source_mode_type s)130     void state::change_source_mode(source_mode_type s) {
131         source_mode = source_mode_info(s, get_new_order_pos());
132     }
133 
push_tagged_source_mode(source_mode_type s)134     void state::push_tagged_source_mode(source_mode_type s) {
135         tagged_source_mode_stack.push_back(
136             source_mode_info(s, s ? get_new_order_pos() : 0));
137     }
138 
pop_tagged_source_mode()139     void state::pop_tagged_source_mode() {
140         assert(!tagged_source_mode_stack.empty());
141         tagged_source_mode_stack.pop_back();
142     }
143 
state_save(quickbook::state & state,scope_flags scope)144     state_save::state_save(quickbook::state& state, scope_flags scope)
145         : state(state)
146         , scope(scope)
147         , qbk_version(qbk_version_n)
148         , imported(state.imported)
149         , current_file(state.current_file)
150         , current_path(state.current_path)
151         , xinclude_base(state.xinclude_base)
152         , source_mode(state.source_mode)
153         , macro()
154         , template_depth(state.template_depth)
155         , min_section_level(state.min_section_level)
156     {
157         if (scope & scope_macros) macro = state.macro;
158         if (scope & scope_templates) state.templates.push();
159         if (scope & scope_output) {
160             state.push_output();
161         }
162         state.values.builder.save();
163     }
164 
~state_save()165     state_save::~state_save()
166     {
167         state.values.builder.restore();
168         boost::swap(qbk_version_n, qbk_version);
169         boost::swap(state.imported, imported);
170         boost::swap(state.current_file, current_file);
171         boost::swap(state.current_path, current_path);
172         boost::swap(state.xinclude_base, xinclude_base);
173         boost::swap(state.source_mode, source_mode);
174         if (scope & scope_output) {
175             state.pop_output();
176         }
177         if (scope & scope_templates) state.templates.pop();
178         if (scope & scope_macros) state.macro = macro;
179         boost::swap(state.template_depth, template_depth);
180         boost::swap(state.min_section_level, min_section_level);
181     }
182 }
183