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 "document_state.hpp"
13 #include "for.hpp"
14 #include "grammar.hpp"
15 #include "path.hpp"
16 #include "phrase_tags.hpp"
17 #include "quickbook.hpp"
18 #include "state_save.hpp"
19 #include "utils.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(
33         fs::path const& filein_,
34         fs::path const& xinclude_base_,
35         string_stream& out_,
36         document_state& document_)
37         : grammar_()
38 
39         , order_pos(0)
40         , xinclude_base(xinclude_base_)
41 
42         , templates()
43         , error_count(0)
44         , anchors()
45         , warned_about_breaks(false)
46         , conditional(true)
47         , document(document_)
48         , callouts()
49         , callout_depth(0)
50         , dependencies()
51         , explicit_list(false)
52         , strict_mode(false)
53 
54         , imported(false)
55         , macro()
56         , source_mode()
57         , source_mode_next()
58         , source_mode_next_pos()
59         , current_file(0)
60         , current_path(filein_, 0, filein_.filename())
61 
62         , template_depth(0)
63         , min_section_level(1)
64 
65         , in_list(false)
66         , in_list_save()
67         , out(out_)
68         , phrase()
69 
70         , values(&current_file)
71     {
72         // add the predefined macros
73         macro.add("__DATE__", std::string(quickbook_get_date))(
74             "__TIME__",
75             std::string(quickbook_get_time))("__FILENAME__", std::string());
76         update_filename_macro();
77 
78         boost::scoped_ptr<quickbook_grammar> g(new quickbook_grammar(*this));
79         grammar_.swap(g);
80     }
81 
grammar() const82     quickbook_grammar& state::grammar() const { return *grammar_; }
83 
update_filename_macro()84     void state::update_filename_macro()
85     {
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() { return ++order_pos; }
92 
push_output()93     void state::push_output()
94     {
95         out.push();
96         phrase.push();
97         in_list_save.push(in_list);
98     }
99 
pop_output()100     void state::pop_output()
101     {
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     {
110         source_mode_info result;
111 
112         QUICKBOOK_FOR (source_mode_info const& s, tagged_source_mode_stack) {
113             result.update(s);
114         }
115 
116         return result;
117     }
118 
current_source_mode() const119     source_mode_info state::current_source_mode() const
120     {
121         source_mode_info result = source_mode;
122 
123         result.update(document.section_source_mode());
124 
125         QUICKBOOK_FOR (source_mode_info const& s, tagged_source_mode_stack) {
126             result.update(s);
127         }
128 
129         return result;
130     }
131 
change_source_mode(source_mode_type s)132     void state::change_source_mode(source_mode_type s)
133     {
134         source_mode = source_mode_info(s, get_new_order_pos());
135     }
136 
push_tagged_source_mode(source_mode_type s)137     void state::push_tagged_source_mode(source_mode_type s)
138     {
139         tagged_source_mode_stack.push_back(
140             source_mode_info(s, s ? get_new_order_pos() : 0));
141     }
142 
pop_tagged_source_mode()143     void state::pop_tagged_source_mode()
144     {
145         assert(!tagged_source_mode_stack.empty());
146         tagged_source_mode_stack.pop_back();
147     }
148 
state_save(quickbook::state & state_,scope_flags scope_)149     state_save::state_save(quickbook::state& state_, scope_flags scope_)
150         : state(state_)
151         , scope(scope_)
152         , qbk_version(qbk_version_n)
153         , imported(state.imported)
154         , current_file(state.current_file)
155         , current_path(state.current_path)
156         , xinclude_base(state.xinclude_base)
157         , source_mode(state.source_mode)
158         , macro()
159         , template_depth(state.template_depth)
160         , min_section_level(state.min_section_level)
161     {
162         if (scope & scope_macros) macro = state.macro;
163         if (scope & scope_templates) state.templates.push();
164         if (scope & scope_output) {
165             state.push_output();
166         }
167         state.values.builder.save();
168     }
169 
~state_save()170     state_save::~state_save()
171     {
172         state.values.builder.restore();
173         boost::swap(qbk_version_n, qbk_version);
174         boost::swap(state.imported, imported);
175         boost::swap(state.current_file, current_file);
176         boost::swap(state.current_path, current_path);
177         boost::swap(state.xinclude_base, xinclude_base);
178         boost::swap(state.source_mode, source_mode);
179         if (scope & scope_output) {
180             state.pop_output();
181         }
182         if (scope & scope_templates) state.templates.pop();
183         if (scope & scope_macros) state.macro = macro;
184         boost::swap(state.template_depth, template_depth);
185         boost::swap(state.min_section_level, min_section_level);
186     }
187 }
188