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/
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 =============================================================================*/
16 #include <boost/filesystem/convenience.hpp>
17 #include <boost/filesystem/fstream.hpp>
18 #include <boost/range/distance.hpp>
19 #include <boost/range/algorithm/replace.hpp>
20 #include <boost/lexical_cast.hpp>
21 #include <boost/algorithm/string/replace.hpp>
22 #include <boost/next_prior.hpp>
23 #include <boost/foreach.hpp>
24 #include "quickbook.hpp"
25 #include "actions.hpp"
26 #include "syntax_highlight.hpp"
29 #include "markups.hpp"
31 #include "state_save.hpp"
32 #include "grammar.hpp"
33 #include "native_text.hpp"
34 #include "block_tags.hpp"
35 #include "phrase_tags.hpp"
36 #include "document_state.hpp"
37 #include "include_paths.hpp"
42 void write_anchors(quickbook::state
& state
, collector
& tgt
)
44 // TODO: This works but is a bit of an odd place to put it.
45 // Might need to redefine the purpose of this function.
46 if (state
.source_mode_next
) {
47 detail::outwarn(state
.source_mode_next_pos
.get_file(),
48 state
.source_mode_next_pos
.get_position())
49 << "Temporary source mode unsupported here."
51 state
.source_mode_next
= 0;
54 for(quickbook::state::string_list::iterator
55 it
= state
.anchors
.begin(),
56 end
= state
.anchors
.end();
59 tgt
<< "<anchor id=\"";
60 detail::print_string(*it
, tgt
.get());
64 state
.anchors
.clear();
67 std::string
add_anchor(quickbook::state
& state
,
69 id_category::categories category
=
70 id_category::explicit_anchor_id
)
72 std::string placeholder
= state
.document
.add_anchor(id
, category
);
73 state
.anchors
.push_back(placeholder
);
77 std::string
get_attribute_value(quickbook::state
& state
,
78 quickbook::value
const& value
)
80 std::string x
= value
.is_encoded() ?
81 value
.get_encoded() : detail::to_s(value
.get_quickbook());
84 detail::outerr(value
.get_file(), value
.get_position())
85 << "Empty attribute value."
94 std::string
validate_id(quickbook::state
& state
,
95 quickbook::value
const& id_value
)
98 std::string id
= get_attribute_value(state
, id_value
);
100 // Special case since I use dollar ids for id placeholders.
101 if (id
[0] == '$') { valid
= false; id
[0] = '_'; }
103 if (qbk_version_n
>= 107u) {
104 char const* allowed_punctuation
= "_.-";
106 BOOST_FOREACH(char c
, id
) {
107 if (!std::isalnum(c
) &&
108 !std::strchr(allowed_punctuation
, c
))
114 detail::outerr(id_value
.get_file(), id_value
.get_position())
116 << (id_value
.is_encoded() ? id_value
.get_encoded() :
117 detail::to_s(id_value
.get_quickbook()))
126 bool quickbook_range::in_range() const {
127 return qbk_version_n
>= lower
&& qbk_version_n
< upper
;
130 void explicit_list_action(quickbook::state
&, value
);
131 void header_action(quickbook::state
&, value
);
132 void begin_section_action(quickbook::state
&, value
);
133 void end_section_action(quickbook::state
&, value
, string_iterator
);
134 void block_action(quickbook::state
&, value
);
135 void block_empty_action(quickbook::state
&, value
);
136 void macro_definition_action(quickbook::state
&, value
);
137 void template_body_action(quickbook::state
&, value
);
138 void variable_list_action(quickbook::state
&, value
);
139 void table_action(quickbook::state
&, value
);
140 void xinclude_action(quickbook::state
&, value
);
141 void include_action(quickbook::state
&, value
, string_iterator
);
142 void image_action(quickbook::state
&, value
);
143 void anchor_action(quickbook::state
&, value
);
144 void link_action(quickbook::state
&, value
);
145 void phrase_action(quickbook::state
&, value
);
146 void role_action(quickbook::state
&, value
);
147 void footnote_action(quickbook::state
&, value
);
148 void raw_phrase_action(quickbook::state
&, value
);
149 void source_mode_action(quickbook::state
&, value
);
150 void next_source_mode_action(quickbook::state
&, value
);
151 void code_action(quickbook::state
&, value
);
152 void do_template_action(quickbook::state
&, value
, string_iterator
);
154 void element_action::operator()(parse_iterator first
, parse_iterator
) const
156 value_consumer values
= state
.values
.release();
157 if(!values
.check() || !state
.conditional
) return;
158 value v
= values
.consume();
163 case block_tags::ordered_list
:
164 case block_tags::itemized_list
:
165 return explicit_list_action(state
, v
);
166 case block_tags::generic_heading
:
167 case block_tags::heading1
:
168 case block_tags::heading2
:
169 case block_tags::heading3
:
170 case block_tags::heading4
:
171 case block_tags::heading5
:
172 case block_tags::heading6
:
173 return header_action(state
, v
);
174 case block_tags::begin_section
:
175 return begin_section_action(state
, v
);
176 case block_tags::end_section
:
177 return end_section_action(state
, v
, first
.base());
178 case block_tags::blurb
:
179 case block_tags::preformatted
:
180 case block_tags::blockquote
:
181 case block_tags::warning
:
182 case block_tags::caution
:
183 case block_tags::important
:
184 case block_tags::note
:
185 case block_tags::tip
:
186 case block_tags::block
:
187 return block_action(state
,v
);
189 return block_empty_action(state
,v
);
190 case block_tags::macro_definition
:
191 return macro_definition_action(state
,v
);
192 case block_tags::template_definition
:
193 return template_body_action(state
,v
);
194 case block_tags::variable_list
:
195 return variable_list_action(state
, v
);
196 case block_tags::table
:
197 return table_action(state
, v
);
198 case block_tags::xinclude
:
199 return xinclude_action(state
, v
);
200 case block_tags::import
:
201 case block_tags::include
:
202 return include_action(state
, v
, first
.base());
203 case phrase_tags::image
:
204 return image_action(state
, v
);
205 case phrase_tags::anchor
:
206 return anchor_action(state
, v
);
207 case phrase_tags::url
:
208 case phrase_tags::link
:
209 case phrase_tags::funcref
:
210 case phrase_tags::classref
:
211 case phrase_tags::memberref
:
212 case phrase_tags::enumref
:
213 case phrase_tags::macroref
:
214 case phrase_tags::headerref
:
215 case phrase_tags::conceptref
:
216 case phrase_tags::globalref
:
217 return link_action(state
, v
);
218 case phrase_tags::bold
:
219 case phrase_tags::italic
:
220 case phrase_tags::underline
:
221 case phrase_tags::teletype
:
222 case phrase_tags::strikethrough
:
223 case phrase_tags::quote
:
224 case phrase_tags::replaceable
:
225 return phrase_action(state
, v
);
226 case phrase_tags::footnote
:
227 return footnote_action(state
, v
);
228 case phrase_tags::escape
:
229 return raw_phrase_action(state
, v
);
230 case phrase_tags::role
:
231 return role_action(state
, v
);
232 case source_mode_tags::cpp
:
233 case source_mode_tags::python
:
234 case source_mode_tags::teletype
:
235 return source_mode_action(state
, v
);
236 case code_tags::next_source_mode
:
237 return next_source_mode_action(state
, v
);
238 case code_tags::code_block
:
239 case code_tags::inline_code_block
:
240 case code_tags::inline_code
:
241 return code_action(state
, v
);
242 case template_tags::attribute_template
:
243 case template_tags::template_
:
244 return do_template_action(state
, v
, first
.base());
250 void break_action::operator()(parse_iterator first
, parse_iterator
) const
252 write_anchors(state
, state
.phrase
);
256 detail::outwarn(state
.current_file
, first
.base())
257 //<< "in column:" << pos.column << ", "
258 << "'\\n' is deprecated, pleases use '[br]' instead" << ".\n";
261 if(!state
.warned_about_breaks
)
263 detail::outwarn(state
.current_file
, first
.base())
264 << "line breaks generate invalid boostbook "
265 "(will only note first occurrence).\n";
267 state
.warned_about_breaks
= true;
270 state
.phrase
<< detail::get_markup(phrase_tags::break_mark
).pre
;
273 void error_message_action::operator()(parse_iterator first
, parse_iterator last
) const
275 file_position
const pos
= state
.current_file
->position_of(first
.base());
277 std::string
value(first
, last
);
278 std::string formatted_message
= message
;
279 boost::replace_all(formatted_message
, "%s", value
);
280 boost::replace_all(formatted_message
, "%c",
281 boost::lexical_cast
<std::string
>(pos
.column
));
283 detail::outerr(state
.current_file
->path
, pos
.line
)
284 << formatted_message
<< std::endl
;
288 void error_action::operator()(parse_iterator first
, parse_iterator
/*last*/) const
290 file_position
const pos
= state
.current_file
->position_of(first
.base());
292 detail::outerr(state
.current_file
->path
, pos
.line
)
293 << "Syntax Error near column " << pos
.column
<< ".\n";
297 void block_action(quickbook::state
& state
, value block
)
299 write_anchors(state
, state
.out
);
301 detail::markup markup
= detail::get_markup(block
.get_tag());
303 value_consumer values
= block
;
304 state
.out
<< markup
.pre
<< values
.consume().get_encoded() << markup
.post
;
308 void block_empty_action(quickbook::state
& state
, value block
)
310 write_anchors(state
, state
.out
);
312 detail::markup markup
= detail::get_markup(block
.get_tag());
313 state
.out
<< markup
.pre
;
316 void phrase_action(quickbook::state
& state
, value phrase
)
318 write_anchors(state
, state
.phrase
);
320 detail::markup markup
= detail::get_markup(phrase
.get_tag());
322 value_consumer values
= phrase
;
323 state
.phrase
<< markup
.pre
<< values
.consume().get_encoded() << markup
.post
;
327 void role_action(quickbook::state
& state
, value role_list
)
329 write_anchors(state
, state
.phrase
);
331 value_consumer values
= role_list
;
332 value role
= values
.consume();
333 value phrase
= values
.consume();
337 << "<phrase role=\"";
338 detail::print_string(get_attribute_value(state
, role
),
342 << phrase
.get_encoded()
346 void footnote_action(quickbook::state
& state
, value phrase
)
348 write_anchors(state
, state
.phrase
);
350 value_consumer values
= phrase
;
353 << state
.document
.add_id("f", id_category::numbered
)
355 << values
.consume().get_encoded()
356 << "</para></footnote>";
360 void raw_phrase_action(quickbook::state
& state
, value phrase
)
362 write_anchors(state
, state
.phrase
);
364 detail::markup markup
= detail::get_markup(phrase
.get_tag());
365 state
.phrase
<< markup
.pre
<< phrase
.get_quickbook() << markup
.post
;
368 void paragraph_action::operator()() const
371 state
.phrase
.swap(str
);
373 std::string::const_iterator
377 while(pos
!= end
&& cl::space_p
.test(*pos
)) ++pos
;
380 detail::markup markup
= state
.in_list
?
381 detail::get_markup(block_tags::paragraph_in_list
) :
382 detail::get_markup(block_tags::paragraph
);
383 state
.out
<< markup
.pre
<< str
;
384 write_anchors(state
, state
.out
);
385 state
.out
<< markup
.post
;
389 void explicit_list_action::operator()() const
391 state
.explicit_list
= true;
394 void phrase_end_action::operator()() const
396 write_anchors(state
, state
.phrase
);
400 void write_bridgehead(quickbook::state
& state
, int level
,
401 std::string
const& str
, std::string
const& id
, bool self_link
)
403 if (self_link
&& !id
.empty())
405 state
.out
<< "<bridgehead renderas=\"sect" << level
<< "\"";
406 state
.out
<< " id=\"";
407 state
.out
<< state
.document
.add_id("h", id_category::numbered
);
409 state
.out
<< "<phrase id=\"" << id
<< "\"/>";
410 state
.out
<< "<link linkend=\"" << id
<< "\">";
412 state
.out
<< "</link>";
413 state
.out
<< "</bridgehead>";
417 state
.out
<< "<bridgehead renderas=\"sect" << level
<< "\"";
418 if(!id
.empty()) state
.out
<< " id=\"" << id
<< "\"";
421 state
.out
<< "</bridgehead>";
426 void header_action(quickbook::state
& state
, value heading_list
)
428 value_consumer values
= heading_list
;
430 bool generic
= heading_list
.get_tag() == block_tags::generic_heading
;
431 value element_id
= values
.optional_consume(general_tags::element_id
);
432 value content
= values
.consume();
439 level
= state
.document
.section_level() + 1;
440 // We need to use a heading which is one greater
442 if (level
> 6 ) // The max is h6, clip it if it goes
443 level
= 6; // further than that
447 level
= heading_list
.get_tag() - block_tags::heading1
+ 1;
450 write_anchors(state
, state
.out
);
452 if (!element_id
.empty())
454 // Use an explicit id.
456 std::string anchor
= state
.document
.add_id(
457 validate_id(state
, element_id
),
458 id_category::explicit_id
);
460 write_bridgehead(state
, level
,
461 content
.get_encoded(), anchor
, self_linked_headers
);
463 else if (state
.document
.compatibility_version() >= 106u)
465 // Generate ids for 1.6+
467 std::string anchor
= state
.document
.add_id(
468 detail::make_identifier(content
.get_quickbook()),
469 id_category::generated_heading
);
471 write_bridgehead(state
, level
,
472 content
.get_encoded(), anchor
, self_linked_headers
);
476 // Generate ids that are compatible with older versions of quickbook.
478 // Older versions of quickbook used the generated boostbook, but
479 // we only have an intermediate version which can contain id
480 // placeholders. So to generate the ids they must be replaced
481 // by the ids that the older versions would have used - i.e. the
484 // Note that this doesn't affect the actual boostbook generated for
485 // the content, it's just used to generate this id.
487 std::string id
= detail::make_identifier(
488 state
.document
.replace_placeholders_with_unresolved_ids(
489 content
.get_encoded()));
491 if (generic
|| state
.document
.compatibility_version() >= 103) {
493 state
.document
.add_id(id
, id_category::generated_heading
);
495 write_bridgehead(state
, level
,
496 content
.get_encoded(), anchor
, self_linked_headers
);
500 state
.document
.old_style_id(id
, id_category::generated_heading
);
502 write_bridgehead(state
, level
,
503 content
.get_encoded(), anchor
, false);
508 void simple_phrase_action::operator()(char mark
) const
510 write_anchors(state
, state
.phrase
);
513 mark
== '*' ? phrase_tags::bold
:
514 mark
== '/' ? phrase_tags::italic
:
515 mark
== '_' ? phrase_tags::underline
:
516 mark
== '=' ? phrase_tags::teletype
:
520 detail::markup markup
= detail::get_markup(tag
);
522 value_consumer values
= state
.values
.release();
523 value content
= values
.consume();
526 state
.phrase
<< markup
.pre
;
527 state
.phrase
<< content
.get_encoded();
528 state
.phrase
<< markup
.post
;
531 bool cond_phrase_push::start()
533 value_consumer values
= state
.values
.release();
535 saved_conditional
= state
.conditional
;
537 if (saved_conditional
)
539 boost::string_ref macro1
= values
.consume().get_quickbook();
540 std::string
macro(macro1
.begin(), macro1
.end());
542 state
.conditional
= find(state
.macro
, macro
.c_str());
544 if (!state
.conditional
) {
546 state
.anchors
.swap(anchors
);
553 void cond_phrase_push::cleanup()
555 if (saved_conditional
&& !state
.conditional
)
558 state
.anchors
.swap(anchors
);
561 state
.conditional
= saved_conditional
;
564 void state::start_list(char mark
)
566 push_tagged_source_mode(source_mode_next
);
567 source_mode_next
= 0;
569 write_anchors(*this, (in_list
? phrase
: out
));
570 assert(mark
== '*' || mark
== '#');
572 out
<< ((mark
== '#') ? "<orderedlist>\n" : "<itemizedlist>\n");
576 void state::end_list(char mark
)
578 write_anchors(*this, out
);
579 assert(mark
== '*' || mark
== '#');
580 out
<< ((mark
== '#') ? "\n</orderedlist>" : "\n</itemizedlist>");
582 std::string list_output
;
583 out
.swap(list_output
);
587 (in_list
? phrase
: out
) << list_output
;
589 pop_tagged_source_mode();
592 void state::start_list_item()
595 write_anchors(*this, phrase
);
598 void state::end_list_item()
600 write_anchors(*this, phrase
);
601 paragraph_action
para(*this);
603 out
<< "</listitem>";
608 bool parse_template(value
const&, quickbook::state
& state
,
609 bool is_attribute_template
= false);
612 void state::start_callouts()
617 std::string
state::add_callout(value v
)
619 std::string callout_id1
= document
.add_id("c", id_category::numbered
);
620 std::string callout_id2
= document
.add_id("c", id_category::numbered
);
622 callouts
.insert(encoded_value(callout_id1
));
623 callouts
.insert(encoded_value(callout_id2
));
627 code
+= "<co id=\"" + callout_id1
+ "\" ";
628 code
+= "linkends=\"" + callout_id2
+ "\" />";
633 std::string
state::end_callouts()
635 assert(callout_depth
> 0);
639 if (callout_depth
> 0) return block
;
641 value_consumer c
= callouts
.release();
642 if (!c
.check()) return block
;
644 block
+= "<calloutlist>";
647 std::string callout_id1
= c
.consume().get_encoded();
648 std::string callout_id2
= c
.consume().get_encoded();
649 value callout_body
= c
.consume();
651 std::string callout_value
;
654 state_save
save(*this, state_save::scope_all
);
657 bool r
= parse_template(callout_body
, *this);
661 detail::outerr(callout_body
.get_file(), callout_body
.get_position())
662 << "Expanding callout." << std::endl
663 << "------------------begin------------------" << std::endl
664 << callout_body
.get_quickbook()
666 << "------------------end--------------------" << std::endl
671 out
.swap(callout_value
);
674 block
+= "<callout arearefs=\"" + callout_id1
+ "\" ";
675 block
+= "id=\"" + callout_id2
+ "\">";
676 block
+= callout_value
;
677 block
+= "</callout>";
679 block
+= "</calloutlist>";
684 void explicit_list_action(quickbook::state
& state
, value list
)
686 write_anchors(state
, state
.out
);
688 detail::markup markup
= detail::get_markup(list
.get_tag());
690 state
.out
<< markup
.pre
;
692 BOOST_FOREACH(value item
, list
)
694 state
.out
<< "<listitem>";
695 state
.out
<< item
.get_encoded();
696 state
.out
<< "</listitem>";
699 state
.out
<< markup
.post
;
702 void anchor_action(quickbook::state
& state
, value anchor
)
704 value_consumer values
= anchor
;
705 value anchor_id
= values
.consume();
706 // Note: anchor_id is never encoded as boostbook. If it
707 // is encoded, it's just things like escapes.
708 add_anchor(state
, validate_id(state
, anchor_id
));
712 void do_macro_action::operator()(std::string
const& str
) const
714 write_anchors(state
, state
.phrase
);
716 if (str
== quickbook_get_date
)
719 strftime(strdate
, sizeof(strdate
), "%Y-%b-%d", current_time
);
720 state
.phrase
<< strdate
;
722 else if (str
== quickbook_get_time
)
725 strftime(strdate
, sizeof(strdate
), "%I:%M:%S %p", current_time
);
726 state
.phrase
<< strdate
;
734 void raw_char_action::operator()(char ch
) const
739 void raw_char_action::operator()(parse_iterator first
, parse_iterator last
) const
741 while (first
!= last
)
742 state
.phrase
<< *first
++;
745 void source_mode_action(quickbook::state
& state
, value source_mode
)
747 state
.change_source_mode(source_mode
.get_tag());
750 void next_source_mode_action(quickbook::state
& state
, value source_mode
)
752 value_consumer values
= source_mode
;
753 state
.source_mode_next_pos
= values
.consume();
754 state
.source_mode_next
= values
.consume().get_int();
758 void code_action(quickbook::state
& state
, value code_block
)
760 int code_tag
= code_block
.get_tag();
762 value_consumer values
= code_block
;
763 boost::string_ref code_value
= values
.consume().get_quickbook();
766 bool inline_code
= code_tag
== code_tags::inline_code
||
767 (code_tag
== code_tags::inline_code_block
&& qbk_version_n
< 106u);
768 bool block
= code_tag
!= code_tags::inline_code
;
770 source_mode_type source_mode
= state
.source_mode_next
?
771 state
.source_mode_next
: state
.current_source_mode().source_mode
;
772 state
.source_mode_next
= 0;
775 write_anchors(state
, state
.phrase
);
778 paragraph_action
para(state
);
780 write_anchors(state
, state
.out
);
784 // preprocess the code section to remove the initial indentation
785 mapped_file_builder mapped
;
786 mapped
.start(state
.current_file
);
787 mapped
.unindent_and_add(code_value
);
789 file_ptr f
= mapped
.release();
791 if (f
->source().empty())
792 return; // Nothing left to do here. The program is empty.
794 if (qbk_version_n
>= 107u) state
.start_callouts();
796 parse_iterator
first_(f
->source().begin());
797 parse_iterator
last_(f
->source().end());
799 file_ptr saved_file
= f
;
800 boost::swap(state
.current_file
, saved_file
);
802 // print the code with syntax coloring
804 // We must not place a \n after the <programlisting> tag
805 // otherwise PDF output starts code blocks with a blank line:
806 state
.phrase
<< "<programlisting>";
807 syntax_highlight(first_
, last_
, state
, source_mode
, block
);
808 state
.phrase
<< "</programlisting>\n";
810 boost::swap(state
.current_file
, saved_file
);
812 if (qbk_version_n
>= 107u) state
.phrase
<< state
.end_callouts();
815 state
.out
<< state
.phrase
.str();
816 state
.phrase
.clear();
820 parse_iterator
first_(code_value
.begin());
821 parse_iterator
last_(code_value
.end());
823 state
.phrase
<< "<code>";
824 syntax_highlight(first_
, last_
, state
, source_mode
, block
);
825 state
.phrase
<< "</code>";
829 void plain_char_action::operator()(char ch
) const
831 write_anchors(state
, state
.phrase
);
833 detail::print_char(ch
, state
.phrase
.get());
836 void plain_char_action::operator()(parse_iterator first
, parse_iterator last
) const
838 write_anchors(state
, state
.phrase
);
840 while (first
!= last
)
841 detail::print_char(*first
++, state
.phrase
.get());
844 void escape_unicode_action::operator()(parse_iterator first
, parse_iterator last
) const
846 write_anchors(state
, state
.phrase
);
848 while(first
!= last
&& *first
== '0') ++first
;
850 // Just ignore \u0000
851 // Maybe I should issue a warning?
852 if(first
== last
) return;
854 std::string
hex_digits(first
, last
);
856 if(hex_digits
.size() == 2 && *first
> '0' && *first
<= '7') {
858 detail::print_char(strtol(hex_digits
.c_str(), 0, 16),
862 state
.phrase
<< "&#x" << hex_digits
<< ";";
866 void write_plain_text(std::ostream
& out
, value
const& v
)
870 detail::print_string(v
.get_encoded(), out
);
873 boost::string_ref value
= v
.get_quickbook();
874 for(boost::string_ref::const_iterator
875 first
= value
.begin(), last
= value
.end();
876 first
!= last
; ++first
)
878 if (*first
== '\\' && ++first
== last
) break;
879 detail::print_char(*first
, out
);
884 void image_action(quickbook::state
& state
, value image
)
886 write_anchors(state
, state
.phrase
);
888 // Note: attributes are never encoded as boostbook, if they're
889 // encoded, it's just things like escapes.
890 typedef std::map
<std::string
, value
> attribute_map
;
891 attribute_map attributes
;
893 value_consumer values
= image
;
894 attributes
["fileref"] = values
.consume();
896 BOOST_FOREACH(value pair_
, values
)
898 value_consumer pair
= pair_
;
899 value name
= pair
.consume();
900 value value
= pair
.consume();
901 std::string
name_str(name
.get_quickbook().begin(),
902 name
.get_quickbook().end());
904 if(!attributes
.insert(std::make_pair(name_str
, value
)).second
)
906 detail::outwarn(name
.get_file(), name
.get_position())
907 << "Duplicate image attribute: "
908 << name
.get_quickbook()
915 // Find the file basename and extension.
917 // Not using Boost.Filesystem because I want to stay in UTF-8.
918 // Need to think about uri encoding.
920 std::string fileref
= attributes
["fileref"].is_encoded() ?
921 attributes
["fileref"].get_encoded() :
922 detail::to_s(attributes
["fileref"].get_quickbook());
924 // Check for windows paths, then convert.
925 // A bit crude, but there you go.
927 if(fileref
.find('\\') != std::string::npos
)
929 (qbk_version_n
>= 106u ?
930 detail::outerr(attributes
["fileref"].get_file(), attributes
["fileref"].get_position()) :
931 detail::outwarn(attributes
["fileref"].get_file(), attributes
["fileref"].get_position()))
932 << "Image path isn't portable: '"
936 if (qbk_version_n
>= 106u) ++state
.error_count
;
939 boost::replace(fileref
, '\\', '/');
941 // Find the file basename and extension.
943 // Not using Boost.Filesystem because I want to stay in UTF-8.
944 // Need to think about uri encoding.
946 std::string::size_type pos
;
947 std::string stem
, extension
;
949 pos
= fileref
.rfind('/');
950 stem
= pos
== std::string::npos
?
952 fileref
.substr(pos
+ 1);
954 pos
= stem
.rfind('.');
955 if (pos
!= std::string::npos
)
957 extension
= stem
.substr(pos
+ 1);
958 stem
= stem
.substr(0, pos
);
961 // Extract the alt tag, to use as a text description.
962 // Or if there isn't one, use the stem of the file name.
964 attribute_map::iterator alt_pos
= attributes
.find("alt");
965 quickbook::value alt_text
=
966 alt_pos
!= attributes
.end() ? alt_pos
->second
:
967 qbk_version_n
< 106u ? encoded_value(stem
) :
969 attributes
.erase("alt");
971 if(extension
== "svg")
974 // SVG's need special handling:
976 // 1) We must set the "format" attribute, otherwise
977 // HTML generation produces code that will not display
979 // 2) We need to set the "contentwidth" and "contentdepth"
980 // attributes, otherwise the image will be displayed inside
981 // a tiny box with scrollbars (Firefox), or else cropped to
982 // fit in a tiny box (IE7).
985 attributes
.insert(attribute_map::value_type("format",
986 encoded_value("SVG")));
989 // Image paths are relative to the html subdirectory:
991 fs::path img
= detail::generic_to_path(fileref
);
992 if (!img
.has_root_directory())
993 img
= quickbook::image_location
/ img
; // relative path
996 // Now load the SVG file:
998 std::string svg_text
;
999 if (state
.dependencies
.add_dependency(img
)) {
1000 fs::ifstream
fs(img
);
1001 std::stringstream buffer
;
1002 buffer
<< fs
.rdbuf();
1003 svg_text
= buffer
.str();
1007 // Extract the svg header from the file:
1009 std::string::size_type a
, b
;
1010 a
= svg_text
.find("<svg");
1011 b
= svg_text
.find('>', a
);
1012 svg_text
= (a
== std::string::npos
) ? "" : svg_text
.substr(a
, b
- a
);
1014 // Now locate the "width" and "height" attributes
1015 // and borrow their values:
1017 a
= svg_text
.find("width");
1018 a
= svg_text
.find('=', a
);
1019 a
= svg_text
.find('\"', a
);
1020 b
= svg_text
.find('\"', a
+ 1);
1021 if(a
!= std::string::npos
)
1023 attributes
.insert(std::make_pair(
1024 "contentwidth", encoded_value(std::string(
1025 svg_text
.begin() + a
+ 1, svg_text
.begin() + b
))
1028 a
= svg_text
.find("height");
1029 a
= svg_text
.find('=', a
);
1030 a
= svg_text
.find('\"', a
);
1031 b
= svg_text
.find('\"', a
+ 1);
1032 if(a
!= std::string::npos
)
1034 attributes
.insert(std::make_pair(
1035 "contentdepth", encoded_value(std::string(
1036 svg_text
.begin() + a
+ 1, svg_text
.begin() + b
))
1041 state
.phrase
<< "<inlinemediaobject>";
1043 state
.phrase
<< "<imageobject><imagedata";
1045 BOOST_FOREACH(attribute_map::value_type
const& attr
, attributes
)
1047 state
.phrase
<< " " << attr
.first
<< "=\"";
1048 write_plain_text(state
.phrase
.get(), attr
.second
);
1049 state
.phrase
<< "\"";
1052 state
.phrase
<< "></imagedata></imageobject>";
1054 // Add a textobject containing the alt tag from earlier.
1055 // This will be used for the alt tag in html.
1056 if (alt_text
.check()) {
1057 state
.phrase
<< "<textobject><phrase>";
1058 write_plain_text(state
.phrase
.get(), alt_text
);
1059 state
.phrase
<< "</phrase></textobject>";
1062 state
.phrase
<< "</inlinemediaobject>";
1065 void macro_definition_action(quickbook::state
& state
, quickbook::value macro_definition
)
1067 value_consumer values
= macro_definition
;
1068 std::string macro_id
= detail::to_s(values
.consume().get_quickbook());
1069 value phrase_value
= values
.optional_consume();
1071 if (phrase_value
.check()) phrase
= phrase_value
.get_encoded();
1074 std::string
* existing_macro
=
1075 boost::spirit::classic::find(state
.macro
, macro_id
.c_str());
1076 quickbook::ignore_variable(&existing_macro
);
1080 if (qbk_version_n
< 106) return;
1082 // Do this if you're using spirit's TST.
1084 // *existing_macro = phrase;
1094 void template_body_action(quickbook::state
& state
, quickbook::value template_definition
)
1096 value_consumer values
= template_definition
;
1097 std::string identifier
= detail::to_s(values
.consume().get_quickbook());
1099 std::vector
<std::string
> template_values
;
1100 BOOST_FOREACH(value
const& p
, values
.consume()) {
1101 template_values
.push_back(detail::to_s(p
.get_quickbook()));
1104 BOOST_ASSERT(values
.check(template_tags::block
) || values
.check(template_tags::phrase
));
1105 value body
= values
.consume();
1106 BOOST_ASSERT(!values
.check());
1108 if (!state
.templates
.add(
1113 &state
.templates
.top_scope())))
1115 detail::outwarn(body
.get_file(), body
.get_position())
1116 << "Template Redefinition: " << identifier
<< std::endl
;
1117 ++state
.error_count
;
1123 string_iterator
find_first_seperator(string_iterator begin
, string_iterator end
)
1125 if(qbk_version_n
< 105) {
1126 for(;begin
!= end
; ++begin
)
1141 unsigned int depth
= 0;
1143 for(;begin
!= end
; ++begin
)
1151 if(++begin
== end
) return begin
;
1154 if (depth
> 0) --depth
;
1160 if (depth
== 0) return begin
;
1170 std::pair
<string_iterator
, string_iterator
> find_seperator(string_iterator begin
, string_iterator end
)
1172 string_iterator first
= begin
= find_first_seperator(begin
, end
);
1174 for(;begin
!= end
; ++begin
)
1184 return std::make_pair(first
, begin
);
1188 return std::make_pair(first
, begin
);
1191 void break_arguments(
1192 std::vector
<value
>& args
1193 , std::vector
<std::string
> const& params
1194 , fs::path
const& filename
1197 // Quickbook 1.4-: If there aren't enough parameters seperated by
1198 // '..' then seperate the last parameter using
1200 // Quickbook 1.5+: If '..' isn't used to seperate the parameters
1201 // then use whitespace to separate them
1202 // (2 = template name + argument).
1204 if (qbk_version_n
< 105 || args
.size() == 1)
1207 while (args
.size() < params
.size())
1209 // Try to break the last argument at the first space found
1210 // and push it into the back of args. Do this
1211 // recursively until we have all the expected number of
1212 // arguments, or if there are no more spaces left.
1214 value last_arg
= args
.back();
1215 string_iterator begin
= last_arg
.get_quickbook().begin();
1216 string_iterator end
= last_arg
.get_quickbook().end();
1218 std::pair
<string_iterator
, string_iterator
> pos
=
1219 find_seperator(begin
, end
);
1220 if (pos
.second
== end
) break;
1222 qbk_value(last_arg
.get_file(),
1223 pos
.second
, end
, template_tags::phrase
));
1225 args
.back() = qbk_value(last_arg
.get_file(),
1226 begin
, pos
.first
, last_arg
.get_tag());
1227 args
.push_back(new_arg
);
1232 std::pair
<bool, std::vector
<std::string
>::const_iterator
>
1234 std::vector
<value
> const& args
1235 , std::vector
<std::string
> const& params
1236 , template_scope
const& scope
1237 , string_iterator first
1238 , quickbook::state
& state
1241 std::vector
<value
>::const_iterator arg
= args
.begin();
1242 std::vector
<std::string
>::const_iterator tpl
= params
.begin();
1243 std::vector
<std::string
> empty_params
;
1245 // Store each of the argument passed in as local templates:
1246 while (arg
!= args
.end())
1248 if (!state
.templates
.add(
1249 template_symbol(*tpl
, empty_params
, *arg
, &scope
)))
1251 detail::outerr(state
.current_file
, first
)
1252 << "Duplicate Symbol Found" << std::endl
;
1253 ++state
.error_count
;
1254 return std::make_pair(false, tpl
);
1258 return std::make_pair(true, tpl
);
1261 bool parse_template(
1262 value
const& content
1263 , quickbook::state
& state
1264 , bool is_attribute_template
1267 file_ptr saved_current_file
= state
.current_file
;
1269 state
.current_file
= content
.get_file();
1270 boost::string_ref source
= content
.get_quickbook();
1272 parse_iterator
first(source
.begin());
1273 parse_iterator
last(source
.end());
1275 bool r
= cl::parse(first
, last
,
1276 is_attribute_template
?
1277 state
.grammar().attribute_template_body
:
1278 content
.get_tag() == template_tags::phrase
?
1279 state
.grammar().inline_phrase
:
1280 state
.grammar().block_start
1283 boost::swap(state
.current_file
, saved_current_file
);
1289 void call_template(quickbook::state
& state
,
1290 template_symbol
const* symbol
,
1291 std::vector
<value
> const& args
,
1292 string_iterator first
,
1293 bool is_attribute_template
= false)
1295 bool is_block
= symbol
->content
.get_tag() != template_tags::phrase
;
1296 assert(!(is_attribute_template
&& is_block
));
1298 quickbook::paragraph_action
paragraph_action(state
);
1300 // Finish off any existing paragraphs.
1301 if (is_block
) paragraph_action();
1303 // If this template contains already encoded text, then just
1304 // write it out, without going through any of the rigamarole.
1306 if (symbol
->content
.is_encoded())
1308 (is_block
? state
.out
: state
.phrase
) << symbol
->content
.get_encoded();
1312 // The template arguments should have the scope that the template was
1313 // called from, not the template's own scope.
1315 // Note that for quickbook 1.4- this value is just ignored when the
1316 // arguments are expanded.
1317 template_scope
const& call_scope
= state
.templates
.top_scope();
1320 state_save
save(state
, state_save::scope_callables
);
1321 std::string save_block
;
1322 std::string save_phrase
;
1324 state
.templates
.start_template(symbol
);
1326 qbk_version_n
= symbol
->content
.get_file()->version();
1328 ++state
.template_depth
;
1329 if (state
.template_depth
> state
.max_template_depth
)
1331 detail::outerr(state
.current_file
, first
)
1332 << "Infinite loop detected" << std::endl
;
1333 ++state
.error_count
;
1337 // Store the current section level so that we can ensure that
1338 // [section] and [endsect] tags in the template are balanced.
1339 state
.min_section_level
= state
.document
.section_level();
1341 ///////////////////////////////////
1342 // Prepare the arguments as local templates
1343 bool get_arg_result
;
1344 std::vector
<std::string
>::const_iterator tpl
;
1345 boost::tie(get_arg_result
, tpl
) =
1346 get_arguments(args
, symbol
->params
, call_scope
, first
, state
);
1348 if (!get_arg_result
)
1353 ///////////////////////////////////
1354 // parse the template body:
1356 if (symbol
->content
.get_file()->version() < 107u) {
1357 state
.out
.swap(save_block
);
1358 state
.phrase
.swap(save_phrase
);
1361 if (!parse_template(symbol
->content
, state
, is_attribute_template
))
1363 detail::outerr(state
.current_file
, first
)
1365 << (is_block
? "block" : "phrase")
1366 << " template: " << symbol
->identifier
<< "\n\n"
1367 << "------------------begin------------------\n"
1368 << symbol
->content
.get_quickbook()
1369 << "------------------end--------------------\n"
1371 ++state
.error_count
;
1375 if (state
.document
.section_level() != state
.min_section_level
)
1377 detail::outerr(state
.current_file
, first
)
1378 << "Mismatched sections in template "
1379 << symbol
->identifier
1381 ++state
.error_count
;
1385 if (symbol
->content
.get_file()->version() < 107u) {
1386 state
.out
.swap(save_block
);
1387 state
.phrase
.swap(save_phrase
);
1389 if(is_block
|| !save_block
.empty()) {
1391 state
.out
<< save_block
;
1392 state
.phrase
<< save_phrase
;
1396 state
.phrase
<< save_phrase
;
1401 if (is_block
) paragraph_action();
1406 void call_code_snippet(quickbook::state
& state
,
1407 template_symbol
const* symbol
,
1408 string_iterator first
)
1410 assert(symbol
->params
.size() == 0);
1411 std::vector
<value
> args
;
1413 // Create a fake symbol for call_template
1418 symbol
->lexical_parent
);
1420 state
.start_callouts();
1421 call_template(state
, &t
, args
, first
);
1422 state
.out
<< state
.end_callouts();
1425 void do_template_action(quickbook::state
& state
, value template_list
,
1426 string_iterator first
)
1428 bool const is_attribute_template
=
1429 template_list
.get_tag() == template_tags::attribute_template
;
1431 // Get the arguments
1432 value_consumer values
= template_list
;
1434 bool template_escape
= values
.check(template_tags::escape
);
1435 if(template_escape
) values
.consume();
1437 std::string identifier
= detail::to_s(values
.consume(template_tags::identifier
).get_quickbook());
1439 std::vector
<value
> args
;
1441 BOOST_FOREACH(value arg
, values
)
1443 args
.push_back(arg
);
1448 template_symbol
const* symbol
= state
.templates
.find(identifier
);
1449 BOOST_ASSERT(symbol
);
1451 // Deal with escaped templates.
1453 if (template_escape
)
1457 detail::outerr(state
.current_file
, first
)
1458 << "Arguments for escaped template."
1460 ++state
.error_count
;
1463 if (symbol
->content
.is_encoded())
1465 state
.phrase
<< symbol
->content
.get_encoded();
1469 state
.phrase
<< symbol
->content
.get_quickbook();
1473 This would surround the escaped template in escape
1474 comments to indicate to the post-processor that it
1475 isn't quickbook generated markup. But I'm not sure if
1478 quickbook::detail::markup escape_markup
1479 = detail::get_markup(phrase_tags::escape);
1482 << escape_markup.pre
1483 << symbol->content.get_quickbook()
1484 << escape_markup.post
1492 ///////////////////////////////////
1493 // Check that attribute templates are phrase templates
1495 if (is_attribute_template
&&
1496 symbol
->content
.get_tag() != template_tags::phrase
)
1498 detail::outerr(state
.current_file
, first
)
1499 << "Only phrase templates can be used in attribute values."
1502 ++state
.error_count
;
1506 ///////////////////////////////////
1507 // Initialise the arguments
1509 switch(symbol
->content
.get_tag())
1511 case template_tags::block
:
1512 case template_tags::phrase
:
1513 // Break the arguments for a template
1515 break_arguments(args
, symbol
->params
, state
.current_file
->path
);
1517 if (args
.size() != symbol
->params
.size())
1519 detail::outerr(state
.current_file
, first
)
1520 << "Invalid number of arguments passed. Expecting: "
1521 << symbol
->params
.size()
1522 << " argument(s), got: "
1524 << " argument(s) instead."
1527 ++state
.error_count
;
1531 call_template(state
, symbol
, args
, first
, is_attribute_template
);
1534 case template_tags::snippet
:
1538 detail::outerr(state
.current_file
, first
)
1539 << "Arguments for code snippet."
1541 ++state
.error_count
;
1546 call_code_snippet(state
, symbol
, first
);
1554 void link_action(quickbook::state
& state
, value link
)
1556 write_anchors(state
, state
.phrase
);
1558 detail::markup markup
= detail::get_markup(link
.get_tag());
1560 value_consumer values
= link
;
1561 value dst_value
= values
.consume();
1562 value content
= values
.consume();
1567 if (link
.get_tag() == phrase_tags::link
) {
1568 dst
= validate_id(state
, dst_value
);
1571 dst
= get_attribute_value(state
, dst_value
);
1573 // TODO: Might be better to have an error for some invalid urls.
1574 if (link
.get_tag() == phrase_tags::url
) {
1575 dst
= detail::partially_escape_uri(dst
);
1579 state
.phrase
<< markup
.pre
;
1580 detail::print_string(dst
, state
.phrase
.get());
1581 state
.phrase
<< "\">";
1583 if (content
.empty())
1584 detail::print_string(dst
, state
.phrase
.get());
1586 state
.phrase
<< content
.get_encoded();
1588 state
.phrase
<< markup
.post
;
1591 void variable_list_action(quickbook::state
& state
, value variable_list
)
1593 write_anchors(state
, state
.out
);
1595 value_consumer values
= variable_list
;
1596 std::string title
= detail::to_s(values
.consume(table_tags::title
).get_quickbook());
1598 state
.out
<< "<variablelist>\n";
1600 state
.out
<< "<title>";
1601 detail::print_string(title
, state
.out
.get());
1602 state
.out
<< "</title>\n";
1604 BOOST_FOREACH(value_consumer entry
, values
) {
1605 state
.out
<< "<varlistentry>";
1608 state
.out
<< "<term>";
1609 state
.out
<< entry
.consume().get_encoded();
1610 state
.out
<< "</term>";
1614 state
.out
<< "<listitem>";
1615 BOOST_FOREACH(value phrase
, entry
) state
.out
<< phrase
.get_encoded();
1616 state
.out
<< "</listitem>";
1619 state
.out
<< "</varlistentry>\n";
1622 state
.out
<< "</variablelist>\n";
1627 void table_action(quickbook::state
& state
, value table
)
1629 write_anchors(state
, state
.out
);
1631 value_consumer values
= table
;
1633 std::string element_id
;
1634 if(values
.check(general_tags::element_id
)) {
1635 element_id
= validate_id(state
, values
.consume());
1638 value title
= values
.consume(table_tags::title
);
1639 bool has_title
= !title
.empty();
1641 std::string table_id
;
1643 if (!element_id
.empty()) {
1644 table_id
= state
.document
.add_id(element_id
, id_category::explicit_id
);
1646 else if (has_title
) {
1647 if (state
.document
.compatibility_version() >= 105) {
1648 table_id
= state
.document
.add_id(detail::make_identifier(title
.get_quickbook()), id_category::generated
);
1651 table_id
= state
.document
.add_id("t", id_category::numbered
);
1655 // Emulating the old behaviour which used the width of the final
1656 // row for span_count.
1660 value_consumer lookahead
= values
;
1661 BOOST_FOREACH(value row
, lookahead
) {
1663 span_count
= boost::distance(row
);
1669 state
.out
<< "<table frame=\"all\"";
1670 if(!table_id
.empty())
1671 state
.out
<< " id=\"" << table_id
<< "\"";
1673 state
.out
<< "<title>";
1674 if (qbk_version_n
< 106u) {
1675 detail::print_string(title
.get_quickbook(), state
.out
.get());
1678 state
.out
<< title
.get_encoded();
1680 state
.out
<< "</title>";
1684 state
.out
<< "<informaltable frame=\"all\"";
1685 if(!table_id
.empty())
1686 state
.out
<< " id=\"" << table_id
<< "\"";
1690 state
.out
<< "<tgroup cols=\"" << span_count
<< "\">\n";
1694 state
.out
<< "<thead>" << "<row>";
1695 BOOST_FOREACH(value cell
, values
.consume()) {
1696 state
.out
<< "<entry>" << cell
.get_encoded() << "</entry>";
1698 state
.out
<< "</row>\n" << "</thead>\n";
1701 state
.out
<< "<tbody>\n";
1703 BOOST_FOREACH(value row
, values
) {
1704 state
.out
<< "<row>";
1705 BOOST_FOREACH(value cell
, row
) {
1706 state
.out
<< "<entry>" << cell
.get_encoded() << "</entry>";
1708 state
.out
<< "</row>\n";
1713 state
.out
<< "</tbody>\n"
1718 state
.out
<< "</table>\n";
1722 state
.out
<< "</informaltable>\n";
1726 void begin_section_action(quickbook::state
& state
, value begin_section_list
)
1728 value_consumer values
= begin_section_list
;
1730 value element_id
= values
.optional_consume(general_tags::element_id
);
1731 value content
= values
.consume();
1734 std::string full_id
= state
.document
.begin_section(
1735 element_id
.empty() ?
1736 detail::make_identifier(content
.get_quickbook()) :
1737 validate_id(state
, element_id
),
1738 element_id
.empty() ?
1739 id_category::generated_section
:
1740 id_category::explicit_section_id
,
1741 state
.current_source_mode());
1743 state
.out
<< "\n<section id=\"" << full_id
<< "\">\n";
1744 state
.out
<< "<title>";
1746 write_anchors(state
, state
.out
);
1748 if (self_linked_headers
&& state
.document
.compatibility_version() >= 103)
1750 state
.out
<< "<link linkend=\"" << full_id
<< "\">"
1751 << content
.get_encoded()
1757 state
.out
<< content
.get_encoded();
1760 state
.out
<< "</title>\n";
1763 void end_section_action(quickbook::state
& state
, value end_section
, string_iterator first
)
1765 write_anchors(state
, state
.out
);
1767 if (state
.document
.section_level() <= state
.min_section_level
)
1769 file_position
const pos
= state
.current_file
->position_of(first
);
1771 detail::outerr(state
.current_file
->path
, pos
.line
)
1772 << "Mismatched [endsect] near column " << pos
.column
<< ".\n";
1773 ++state
.error_count
;
1778 state
.out
<< "</section>";
1779 state
.document
.end_section();
1782 void element_id_warning_action::operator()(parse_iterator first
, parse_iterator
) const
1784 detail::outwarn(state
.current_file
, first
.base()) << "Empty id.\n";
1787 void xinclude_action(quickbook::state
& state
, value xinclude
)
1789 write_anchors(state
, state
.out
);
1791 value_consumer values
= xinclude
;
1792 path_parameter x
= check_xinclude_path(values
.consume(), state
);
1795 if (x
.type
== path_parameter::path
)
1797 quickbook_path path
= resolve_xinclude_path(x
.value
, state
);
1799 state
.out
<< "\n<xi:include href=\"";
1800 detail::print_string(file_path_to_url(path
.abstract_file_path
), state
.out
.get());
1801 state
.out
<< "\" />\n";
1805 void load_quickbook(quickbook::state
& state
,
1806 quickbook_path
const& path
,
1807 value::tag_type load_type
,
1808 value
const& include_doc_id
= value())
1810 assert(load_type
== block_tags::include
||
1811 load_type
== block_tags::import
);
1813 // Check this before qbk_version_n gets changed by the inner file.
1814 bool keep_inner_source_mode
= (qbk_version_n
< 106);
1817 // When importing, state doesn't scope templates and macros so that
1818 // they're added to the existing scope. It might be better to add
1819 // them to a new scope then explicitly import them into the
1822 // For old versions of quickbook, templates aren't scoped by the
1824 state_save
save(state
,
1825 load_type
== block_tags::import
? state_save::scope_output
:
1826 qbk_version_n
>= 106u ? state_save::scope_callables
:
1827 state_save::scope_macros
);
1829 state
.current_file
= load(path
.file_path
); // Throws load_error
1830 state
.current_path
= path
;
1831 state
.imported
= (load_type
== block_tags::import
);
1833 // update the __FILENAME__ macro
1834 state
.update_filename_macro();
1837 quickbook::parse_file(state
, include_doc_id
, true);
1839 // Don't restore source_mode on older versions.
1840 if (keep_inner_source_mode
) save
.source_mode
= state
.source_mode
;
1843 // restore the __FILENAME__ macro
1844 state
.update_filename_macro();
1847 void load_source_file(quickbook::state
& state
,
1848 quickbook_path
const& path
,
1849 value::tag_type load_type
,
1850 string_iterator first
,
1851 value
const& include_doc_id
= value())
1853 assert(load_type
== block_tags::include
||
1854 load_type
== block_tags::import
);
1856 std::string ext
= path
.file_path
.extension().generic_string();
1857 std::vector
<template_symbol
> storage
;
1858 // Throws load_error
1859 state
.error_count
+=
1860 load_snippets(path
.file_path
, storage
, ext
, load_type
);
1862 if (load_type
== block_tags::include
)
1864 state
.templates
.push();
1867 BOOST_FOREACH(template_symbol
& ts
, storage
)
1869 std::string tname
= ts
.identifier
;
1872 ts
.lexical_parent
= &state
.templates
.top_scope();
1873 if (!state
.templates
.add(ts
))
1875 detail::outerr(ts
.content
.get_file(), ts
.content
.get_position())
1876 << "Template Redefinition: " << tname
<< std::endl
;
1877 ++state
.error_count
;
1882 if (load_type
== block_tags::include
)
1884 BOOST_FOREACH(template_symbol
& ts
, storage
)
1886 std::string tname
= ts
.identifier
;
1890 ts
.lexical_parent
= &state
.templates
.top_scope();
1891 call_code_snippet(state
, &ts
, first
);
1895 state
.templates
.pop();
1899 void include_action(quickbook::state
& state
, value include
, string_iterator first
)
1901 write_anchors(state
, state
.out
);
1903 value_consumer values
= include
;
1904 value include_doc_id
= values
.optional_consume(general_tags::include_id
);
1905 path_parameter parameter
= check_path(values
.consume(), state
);
1908 std::set
<quickbook_path
> search
=
1909 include_search(parameter
, state
, first
);
1910 std::set
<quickbook_path
>::iterator i
= search
.begin();
1911 std::set
<quickbook_path
>::iterator e
= search
.end();
1914 quickbook_path
const & path
= *i
;
1916 if (qbk_version_n
>= 106)
1918 if (state
.imported
&& include
.get_tag() == block_tags::include
)
1921 std::string ext
= path
.file_path
.extension().generic_string();
1923 if (ext
== ".qbk" || ext
== ".quickbook")
1925 load_quickbook(state
, path
, include
.get_tag(), include_doc_id
);
1929 load_source_file(state
, path
, include
.get_tag(), first
, include_doc_id
);
1934 if (include
.get_tag() == block_tags::include
)
1936 load_quickbook(state
, path
, include
.get_tag(), include_doc_id
);
1940 load_source_file(state
, path
, include
.get_tag(), first
, include_doc_id
);
1944 catch (load_error
& e
) {
1945 ++state
.error_count
;
1947 detail::outerr(state
.current_file
, first
)
1957 bool to_value_scoped_action::start(value::tag_type t
)
1959 state
.push_output();
1960 state
.anchors
.swap(saved_anchors
);
1966 void to_value_scoped_action::success(parse_iterator first
, parse_iterator last
)
1970 if (!state
.out
.str().empty())
1972 paragraph_action
para(state
);
1973 para(); // For paragraphs before the template call.
1974 write_anchors(state
, state
.out
);
1975 state
.out
.swap(value
);
1979 write_anchors(state
, state
.phrase
);
1980 state
.phrase
.swap(value
);
1983 state
.values
.builder
.insert(encoded_qbk_value(
1984 state
.current_file
, first
.base(), last
.base(), value
, tag
));
1988 void to_value_scoped_action::cleanup()
1991 state
.anchors
.swap(saved_anchors
);