diff options
Diffstat (limited to 'tools/quickbook')
72 files changed, 3080 insertions, 1710 deletions
diff --git a/tools/quickbook/doc/1_6.qbk b/tools/quickbook/doc/1_6.qbk index c3ca99c0a0..89c41f2ac0 100644 --- a/tools/quickbook/doc/1_6.qbk +++ b/tools/quickbook/doc/1_6.qbk @@ -278,4 +278,86 @@ html. [endsect] -[endsect] [/ Quickbok 1.6]
\ No newline at end of file +[endsect] [/ Quickbok 1.6] + +[section:1_7 Quickbook 1.7] + +[section:source_mode Source mode for single entities] + +1.7 introduces a new `!` element type for setting the source mode of a single +entity without changing the source mode otherwise. This can be used for +code blocks and other elements. For example: + +``` +[!c++] + void foo() {}; + +[!python]``\`\`\`\ ``def foo():``\`\`\`\ `` +``` + +It can also be used to set the source mode for elements: + +``` +[!teletype][table + [[code][meaning]] + [[`+`][addition]] +] +``` + +When used a section, it's only set for the section element, not the +whole section. + +Currently it does support other syntactic entities such as paragraphs +and lists. I'm not sure if it would be a good idea. + +[endsect] + +[section:callouts Callouts in code block] + +Currently callouts can only be used in code snippets. 1.7 add +support in normal code blocks. The same syntax is used as in +code snippets, the callout descriptions appear immediately +after the code block. + +[endsect] + +[section:escaped_docinfo_attributes Escaped docbook in docinfo blocks] + +Quickbook docinfo attributes will probably never be as rich as docbook +attributes so to allow more flexible markup, not supported by quickbook +escaped docbook can be included in the docinfo block: + +``` +[article Some article +[quickbook 1.7] +'''<author> + <firstname>John</firstname> + <surname>Doe</surname> + <email>john.doe@example.com</email> +</author>''' +] +``` + +The escaped docbook is always placed at the end of the docinfo block, +so it shouldn't be assumed that it will interleave the markup. A mixture +of quickbook and docbook attributes for the same information will not work +well. + +[endsect] [/escaped_docinfo_attributes] + +[section:templates_in_link_values Templates in link values] + +There's very premilinary support for calling templates in link values. A lot +more work needs to be done, including: + +* Considering other places where templates could be called (e.g. images are + quite tricky, as templates could get confused with attributes, should + templates be callable from something like an element's id?). +* Trimming spaces from the body of the template (which can cause surprising + results). +* Checking that the contents of the template are appropriate for the context. + Possibly even using a different grammar. + +[endsect] [/templates_in_link_values] + +[endsect] [/ Quickbok 1.7] diff --git a/tools/quickbook/doc/block.qbk b/tools/quickbook/doc/block.qbk index f9da265b77..c6765131f7 100644 --- a/tools/quickbook/doc/block.qbk +++ b/tools/quickbook/doc/block.qbk @@ -14,7 +14,8 @@ [source-mode teletype] ] -[section xinclude] +[#quickbook.ref.xinclude] +[section:xinclude xinclude] You can include another XML file with: @@ -27,7 +28,8 @@ reference section. [endsect] [/xinclude] -[section Paragraphs] +[#quickbook.ref.paragraphs] +[section:paragraphs Paragraphs] Paragraphs start left-flushed and are terminated by two or more newlines. No markup is needed for paragraphs. QuickBook automatically detects paragraphs from @@ -36,10 +38,12 @@ the context. Block markups \[section, endsect, h1, h2, h3, h4, h5, h6, blurb, [/ <-- There's a space here. Don't remove. this is intentianal, for testing] This is a new paragraph... -[endsect] [/Paragraphs] +[endsect] [/paragraphs] -[section Lists] -[section Ordered lists] +[#quickbook.ref.lists] +[section:lists Lists] +[#quickbook.ref.ordered_lists] +[section:ordered_lists Ordered lists] [pre # One @@ -53,8 +57,9 @@ will generate: # Two # Three -[endsect] [/Ordered lists] -[section List Hierarchies] +[endsect] [/ordered_lists] +[#quickbook.ref.list_hierarchies] +[section:list_hierarchies List Hierarchies] List hierarchies are supported. Example: @@ -86,8 +91,9 @@ will generate: # Four.a.ii # Five -[endsect] [/List Hierarchies] -[section Long List Lines] +[endsect] [/list_hierarchies] +[#quickbook.ref.long_list_lines] +[section:long_list_lines Long List Lines] Long lines will be wrapped appropriately. Example: @@ -109,8 +115,9 @@ Long lines will be wrapped appropriately. Example: A very long item. A very long item. A very long item. # A short item. -[endsect] [/Long list lines] -[section Unordered lists] +[endsect] [/long_list_lines] +[#quickbook.ref.unordered_lists] +[section:unordered_lists Unordered lists] ``` * First @@ -124,8 +131,9 @@ will generate: * Second * Third -[endsect] [/Unordered lists] -[section Mixed lists] +[endsect] [/unordered_lists] +[#quickbook.ref.mixed_lists] +[section:mixed_lists Mixed lists] Mixed lists (ordered and unordered) are supported. Example: @@ -181,10 +189,11 @@ will generate: * 2.b.2.a * 2.b.2.b -[endsect] [/Mixed lists] -[endsect] [/Lists] +[endsect] [/mixed_lists] +[endsect] [/lists] -[section Code] +[#quickbook.ref.code] +[section:code Code] Preformatted code starts with a space or a tab. The code will be syntax highlighted according to the current __source_mode__: @@ -227,8 +236,9 @@ Generates: using __boost__::__array__; -[endsect] [/Code] +[endsect] [/code] +[#quickbook.ref.escape_back] [section:escape_back Escaping Back To QuickBook] Inside code, code blocks and inline code, QuickBook does not allow any @@ -252,9 +262,10 @@ Will generate: When escaping from code to QuickBook, only phrase level markups are allowed. Block level markups like lists, tables etc. are not allowed. -[endsect] [/Escaping back to quickbook] +[endsect] [/escaping_back_to_quickbook] -[section Preformatted] +[#quickbook.ref.preformatted] +[section:preformatted Preformatted] Sometimes, you don't want some preformatted text to be parsed as source code. In such cases, use the [^\[pre ... \]] markup block. @@ -288,9 +299,10 @@ Some *preformatted* text Some *preformatted* text Notice that unlike Code, phrase markup such as font style is still permitted inside =pre= blocks. -[endsect] [/Preformatted] +[endsect] [/preformatted] -[section Blockquote] +[#quickbook.ref.blockquote] +[section:blockquote Blockquote] [pre '''[:sometext...]''' @@ -298,9 +310,10 @@ inside =pre= blocks. [:Indents the paragraph. This applies to one paragraph only.] -[endsect] [/Blockquote] +[endsect] [/blockquote] -[section Admonitions] +[#quickbook.ref.admonitions] +[section:admonitions Admonitions] ``` [note This is a note] @@ -322,9 +335,10 @@ These are the only admonitions supported by __docbook__. So, for example [^\[information This is some information\]] is unlikely to produce the desired effect. -[endsect] [/Admonitions] +[endsect] [/admonitions] -[section Headings] +[#quickbook.ref.headings] +[section:headings Headings] ``` [h1 Heading 1] @@ -356,9 +370,10 @@ For example: Heading 1 in section Section 2 will be normalized to to link to them. See __anchor_links__ and __section__ for more info. -[endsect] [/Headings] +[endsect] [/headings] -[section Generic Heading] +[#quickbook.ref.generic_heading] +[section:generic_heading Generic Heading] In cases when you don't want to care about the heading level (1 to 6), you can use the /Generic Heading/: @@ -402,9 +417,10 @@ at will without any extra work to ensure correct heading levels. In fact, with /section/ and /heading/, you have all you need. /h1/../h6/ becomes redundant. /h1/../h6/ might be deprecated in the future. -[endsect] [/Generic Heading] +[endsect] [/generic_heading] -[section Macros] +[#quickbook.ref.macros] +[section:macros Macros] ``` [def macro_identifier some text] @@ -455,9 +471,10 @@ will generate this: Hi __spirit__ :-) -[endsect] [/Macros] +[endsect] [/macros] -[section Predefined Macros] +[#quickbook.ref.predefined_macros] +[section:predefined_macros Predefined Macros] Quickbook has some predefined macros that you can already use. @@ -468,9 +485,10 @@ Quickbook has some predefined macros that you can already use. [[[^\__FILENAME__]][Quickbook source filename] [__FILENAME__]] ] -[endsect] [/Predefined Macros] +[endsect] [/predefined_macros] -[section Templates] +[#quickbook.ref.templates] +[section:templates Templates] Templates provide a more versatile text substitution mechanism. Templates come in handy when you need to create parameterizable, multi-line, @@ -496,6 +514,7 @@ Hi, my name is [name]. I am [age] years old. I am a [what]. ] +[#quickbook.ref.template_identifier] [heading Template Identifier] Template identifiers can either consist of: @@ -513,7 +532,7 @@ alphanumeric characters or the underscore. This is similar to your typical C/C++ identifier. A template formal argument temporarily hides a template of the same name at -the point where the [link quickbook.syntax.block.templates.template_expansion +the point where the [link quickbook.ref.template_expansion template is expanded]. Note that the body of the [^person] template above refers to [^name] [^age] and [^what] as [^\[name\]] [^\[age\]] and [^\[what\]]. [^name] [^age] and [^what] are actually templates that exist @@ -620,7 +639,7 @@ Some squiggles...[*[alpha][beta]] The difference with macros are -* The explicit [link quickbook.syntax.block.templates.template_expansion +* The explicit [link quickbook.ref.template_expansion template expansion syntax]. This is an advantage because, now, we don't have to use obscure naming conventions like double underscores (e.g. \_\_alpha\_\_) to avoid unwanted @@ -729,7 +748,7 @@ With templates, one of our objectives is to allow us to rewrite QuickBook in QuickBook (as a qbk library). For that to happen, we need to accommodate single character punctuation templates which are fairly common in QuickBook. You might have noticed that single character punctuations are -allowed as [link quickbook.syntax.block.templates.template_identifier +allowed as [link quickbook.ref.template_identifier template identifiers]. Example: ``` @@ -748,9 +767,10 @@ We will have: <hey>baz</hey> ] -[endsect] [/Templates] +[endsect] [/templates] -[section Blurbs] +[#quickbook.ref.blurbs] +[section:blurbs Blurbs] ``` [blurb ``\:-)`` [*An eye catching advertisement or note...] @@ -772,12 +792,13 @@ will generate this: (EBNF) completely in C++. ] -[note Prefer [link quickbook.syntax.block.admonitions admonitions] wherever +[note Prefer [link quickbook.ref.admonitions admonitions] wherever appropriate.] -[endsect] [/Blurbs] +[endsect] [/blurbs] -[section Tables] +[#quickbook.ref.tables] +[section:tables Tables] ``` [table:id A Simple Table @@ -899,9 +920,10 @@ Here's how to have preformatted blocks of code in a table cell: ] ] -[endsect] [/Tables] +[endsect] [/tables] -[section Variable Lists] +[#quickbook.ref.variable_lists] +[section:variable_lists Variable Lists] ``` [variablelist A Variable List @@ -932,9 +954,10 @@ only 2 "columns" are allowed. The first column contains the terms, and the second column contains the definitions. Those familiar with HTML will recognize this as a "definition list". -[endsect] [/Variable Lists] +[endsect] [/variable_lists] -[section Include] +[#quickbook.ref.include] +[section:include Include] You can include one QuickBook file from another. The syntax is simply: @@ -963,9 +986,10 @@ for instance, if there is a top section in someother.qbk named "Intro", the named anchor for that section will be "someid.intro", and you can link to it with [^\[link someid.intro The Intro\]]. -[endsect] [/Include] +[endsect] [/include] -[section Import] +[#quickbook.ref.import] +[section:import Import] When documenting code, you'd surely need to present code from actual source files. While it is possible to copy some code and paste them in your QuickBook @@ -1110,4 +1134,4 @@ Example: See the actual code here: [@boost:/tools/quickbook/test/stub.cpp] -[endsect] [/Import] +[endsect] [/import] diff --git a/tools/quickbook/doc/phrase.qbk b/tools/quickbook/doc/phrase.qbk index 613d730bc5..f6f8859798 100644 --- a/tools/quickbook/doc/phrase.qbk +++ b/tools/quickbook/doc/phrase.qbk @@ -14,7 +14,8 @@ [source-mode teletype] ] -[section Font Styles] +[#quickbook.ref.font_styles] +[section:font_styles Font Styles] ``` ['italic], [*bold], [_underline], [^teletype], [-strikethrough] @@ -34,9 +35,10 @@ will generate: [*['bold-italic]] -[endsect] [/Font Styles] +[endsect] [/font_styles] -[section Replaceable] +[#quickbook.ref.replaceable] +[section:replaceable Replaceable] When you want content that may or must be replaced by the user, use the syntax: @@ -48,9 +50,10 @@ This will generate: [~replacement] -[endsect] [/Replaceable] +[endsect] [/replaceable] -[section Quotations] +[#quickbook.ref.quotations] +[section:quotations Quotations] ``` ["A question that sometimes drives me hazy: am I or are the others crazy?]--Einstein @@ -76,9 +79,10 @@ will generate: ["Here's the rule for bargains: ["Do other men, for they would do you.] That's the true business precept.] -[endsect] [/Quotations] +[endsect] [/quotations] -[section Simple formatting] +[#quickbook.ref.simple_formatting] +[section:simple_formatting Simple formatting] Simple markup for formatting text, common in many applications, is now supported: @@ -159,9 +163,10 @@ Yes sir, yes sir, three bags full! One for the master, one for the dame, And one for the little boy who lives down the lane. -[endsect] [/Simple Formatting] +[endsect] [/simple_formatting] -[section Inline code] +[#quickbook.ref.inline_code] +[section:inline_code Inline code] Inlining code in paragraphs is quite common when writing C++ documentation. We provide a very simple markup for this. For example, this: @@ -179,9 +184,10 @@ syntax highlighted. single quote: `"'"`. Note too that [^\`some code\`] is preferred over `[^some code]`. ] -[endsect] [/Inline Code] +[endsect] [/inline_code] -[section Code blocks] +[#quickbook.ref.code_blocks] +[section:code_blocks Code blocks] Preformatted code simply starts with a space or a tab (See __code__). However, such a simple syntax cannot be used as phrase elements in lists @@ -235,9 +241,10 @@ will generate: [teletype] -[endsect] [/Code blocks] +[endsect] [/code_blocks] -[section Source Mode] +[#quickbook.ref.source_mode] +[section:source_mode Source Mode] If a document contains more than one type of source code then the source mode may be changed dynamically as the document is processed. All QuickBook @@ -270,10 +277,10 @@ C++ comment `// looks like this` whereas a Python comment [python] [note The source mode strings are lowercase.] -[endsect] [/Source Mode] +[endsect] [/source_mode] -[#ref-line-break] -[section line-break] +[#quickbook.ref.line_break] +[section:line_break line-break] ``` [br] @@ -283,9 +290,10 @@ C++ comment `// looks like this` whereas a Python comment [python] there might be problems, especially when using an alternative docbook processor.] -[endsect] [/Line break] +[endsect] [/line_break] -[section Anchors] +[#quickbook.ref.anchors] +[section:anchors Anchors] ``` [#named_anchor] @@ -299,9 +307,10 @@ These anchors are global and can be accessed from anywhere in the quickbook documentation. Be careful to avoid clashes with anchors in other sections. -[endsect] [/Anchors] +[endsect] [/anchors] -[section Links] +[#quickbook.ref.links] +[section:links Links] ``` [@http://www.boost.org this is [*boost's] website....] @@ -339,9 +348,10 @@ will generate: [@boost:/libs/spirit/index.html the Boost.Spirit documentation] Note that this is only available when using BoostBook, and only for links - it can't be used for images. -[endsect] [/Links] +[endsect] [/links] -[section Anchor links] +[#quickbook.ref.anchor_links] +[section:anchor_links Anchor links] You can link within a document using: @@ -351,9 +361,10 @@ You can link within a document using: See sections __section__ and __heading__ for more info. -[endsect] [/Anchor links] +[endsect] [/anchor_links] -[section refentry links] +[#quickbook.ref.refentry_links] +[section:refentry_links refentry links] In addition, you can link internally to an XML refentry like: @@ -372,8 +383,9 @@ automatically be the refentry. Example: This gets converted into [^<link linkend="xml.refentry">xml.refentry</link>]. -[endsect] [/refentry links] +[endsect] [/refentry_links] +[#quickbook.ref.code_links] [section:code_links Code Links] If you want to link to a function, class, member, enum, concept, global, or header in @@ -400,9 +412,10 @@ Example: would have "boost::bar::baz" as the link text. -[endsect] [/Code Links] +[endsect] [/code_links] -[section Escape] +[#quickbook.ref.escape] +[section:escape Escape] The escape mark-up is used when we don't want to do any processing. @@ -427,9 +440,10 @@ Escaping allows us to pass XML markup to __boostbook__ or __docbook__. For examp [important Be careful when using the escape. The text must conform to __boostbook__/__docbook__ syntax.] -[endsect] [/Escape] +[endsect] [/escape] -[section Single char escape] +[#quickbook.ref.single_char_escape] +[section:single_char_escape Single char escape] The backslash may be used to escape a single punctuation character. The punctuation immediately after the backslash is passed without any processing. @@ -439,15 +453,16 @@ For example, how do you escape the triple quote? Simple: [^\\'\\'\\'] `\n` has a special meaning. It is used to generate line breaks. -[warning `\n` is now deprecated, use [link ref-line-break `[br]`] +[warning `\n` is now deprecated, use [link quickbook.ref.line_break `[br]`] instead. Although, use it sparingly as it can generated invalid docbook] The escaped space: `\ ` also has a special meaning. The escaped space is removed from the output. -[endsect] [/Single char escape] +[endsect] [/single_char_escape] -[section Unicode escape] +[#quickbook.ref.unicode_escape] +[section:unicode_escape Unicode escape] You can enter any 16-bit unicode character by using `\u` followed by its 4 digit hexadecimal code, or a 32-bit character by using `\U` followed by an 8 digit @@ -463,9 +478,10 @@ will generate: \u03B1 + \u03B2 ] -[endsect] [/Unicode escape] +[endsect] [/unicode_escape] -[section Images] +[#quickbook.ref.images] +[section:images Images] ``` [$image.jpg] @@ -479,9 +495,10 @@ DocBook imagedata attributes]: [$image.jpg [width 200in] [height 200in]] ``` -[endsect] [/Images] +[endsect] [/images] -[section Footnotes] +[#quickbook.ref.footnotes] +[section:footnotes Footnotes] As of version 1.3, QuickBook supports footnotes. Just put the text of the footnote in a `[footnote]` block, and the text will be put at the bottom @@ -493,9 +510,10 @@ of the current page. For example, this: will generate this[footnote A sample footnote]. -[endsect] [/Footnotes] +[endsect] [/footnotes] -[section Macro Expansion] +[#quickbook.ref.macro_expansion] +[section:macro_expansion Macro Expansion] ``` __a_macro_identifier__ @@ -503,9 +521,10 @@ __a_macro_identifier__ See __macros__ for details. -[endsect] [/Macro Expansion] +[endsect] [/macro_expansion] -[section Template Expansion] +[#quickbook.ref.template_expansion] +[section:template_expansion Template Expansion] ``` [a_template_identifier] @@ -513,8 +532,9 @@ See __macros__ for details. See __templates__ for details. -[endsect] [/Template Expansion] +[endsect] [/template_expansion] +[#quickbook.ref.cond] [section:cond Conditional Generation] Like C++ `#ifdef`, you can generate phrases depending on the presence of @@ -543,4 +563,4 @@ And try again: Yes! -[endsect] [/Condition Generation] +[endsect] [/cond] diff --git a/tools/quickbook/doc/quickbook.qbk b/tools/quickbook/doc/quickbook.qbk index da3f9a8fbe..ea988f9e2f 100644 --- a/tools/quickbook/doc/quickbook.qbk +++ b/tools/quickbook/doc/quickbook.qbk @@ -37,49 +37,49 @@ [def __boostbook__ [@http://www.boost.org/doc/html/boostbook.html BoostBook]] [def __docbook__ [@http://www.docbook.org/ DocBook]] -[def __comments__ [link quickbook.syntax.comments Comments]] +[def __comments__ [link quickbook.ref.comments Comments]] -[def __font_styles__ [link quickbook.syntax.phrase.font_styles Font Styles]] -[def __quotations__ [link quickbook.syntax.phrase.quotations Quotations]] -[def __replaceable__ [link quickbook.syntax.phrase.replaceable Replaceble]] -[def __simple_formatting__ [link quickbook.syntax.phrase.simple_formatting Simple formatting]] -[def __inline_code__ [link quickbook.syntax.phrase.inline_code Inline code]] -[def __code_blocks__ [link quickbook.syntax.phrase.code_blocks Code blocks]] -[def __source_mode__ [link quickbook.syntax.phrase.source_mode Source Mode]] -[def __line_break__ [link quickbook.syntax.phrase.line_break line-break]] -[def __anchors__ [link quickbook.syntax.phrase.anchors Anchors]] -[def __links__ [link quickbook.syntax.phrase.links Links]] -[def __anchor_links__ [link quickbook.syntax.phrase.anchor_links Anchor links]] -[def __refentry_links__ [link quickbook.syntax.phrase.refentry_links refentry links]] -[def __code_links__ [link quickbook.syntax.phrase.code_links function, class, member, enum, macro, concept or header links]] -[def __escape__ [link quickbook.syntax.phrase.escape Escape]] -[def __single_char_escape__ [link quickbook.syntax.phrase.single_char_escape Single char escape]] -[def __images__ [link quickbook.syntax.phrase.images Images]] -[def __cond__ [link quickbook.syntax.phrase.cond Conditional Generation]] +[def __font_styles__ [link quickbook.ref.font_styles Font Styles]] +[def __quotations__ [link quickbook.ref.quotations Quotations]] +[def __replaceable__ [link quickbook.ref.replaceable Replaceble]] +[def __simple_formatting__ [link quickbook.ref.simple_formatting Simple formatting]] +[def __inline_code__ [link quickbook.ref.inline_code Inline code]] +[def __code_blocks__ [link quickbook.ref.code_blocks Code blocks]] +[def __source_mode__ [link quickbook.ref.source_mode Source Mode]] +[def __line_break__ [link quickbook.ref.line_break line-break]] +[def __anchors__ [link quickbook.ref.anchors Anchors]] +[def __links__ [link quickbook.ref.links Links]] +[def __anchor_links__ [link quickbook.ref.anchor_links Anchor links]] +[def __refentry_links__ [link quickbook.ref.refentry_links refentry links]] +[def __code_links__ [link quickbook.ref.code_links function, class, member, enum, macro, concept or header links]] +[def __escape__ [link quickbook.ref.escape Escape]] +[def __single_char_escape__ [link quickbook.ref.single_char_escape Single char escape]] +[def __images__ [link quickbook.ref.images Images]] +[def __cond__ [link quickbook.ref.cond Conditional Generation]] -[def __document__ [link quickbook.syntax.structure.docinfo Document]] -[def __section__ [link quickbook.syntax.structure.section Section]] -[def __xinclude__ [link quickbook.syntax.block.xinclude xinclude]] -[def __paragraphs__ [link quickbook.syntax.block.paragraphs Paragraphs]] -[def __ordered_lists__ [link quickbook.syntax.block.lists.ordered_lists Ordered lists]] -[def __list_hierarchies__ [link quickbook.syntax.block.lists.list_hierarchies List Hierarchies]] -[def __long_list_lines__ [link quickbook.syntax.block.lists.long_list_lines Long List Lines]] -[def __unordered_lists__ [link quickbook.syntax.block.lists.unordered_lists Unordered lists]] -[def __mixed_lists__ [link quickbook.syntax.block.lists.mixed_lists Mixed lists]] -[def __code__ [link quickbook.syntax.block.code Code]] -[def __escape_back__ [link quickbook.syntax.block.escape_back Escaping Back To QuickBook]] -[def __preformatted__ [link quickbook.syntax.block.preformatted Preformatted]] -[def __blockquote__ [link quickbook.syntax.block.blockquote Blockquote]] -[def __heading__ [link quickbook.syntax.block.headings Heading]] -[def __macros__ [link quickbook.syntax.block.macros Macros]] -[def __templates__ [link quickbook.syntax.block.templates Templates]] -[def __predefined_macros__ [link quickbook.syntax.block.predefined_macros Predefined Macros]] -[def __blurbs__ [link quickbook.syntax.block.blurbs Blurbs]] -[def __admonitions__ [link quickbook.syntax.block.admonitions Admonitions]] -[def __tables__ [link quickbook.syntax.block.tables Tables]] -[def __variable_lists__ [link quickbook.syntax.block.variable_lists Variable Lists]] -[def __include__ [link quickbook.syntax.block.include Include]] -[def __import__ [link quickbook.syntax.block.import Import]] +[def __document__ [link quickbook.ref.docinfo Document]] +[def __section__ [link quickbook.ref.section Section]] +[def __xinclude__ [link quickbook.ref.xinclude xinclude]] +[def __paragraphs__ [link quickbook.ref.paragraphs Paragraphs]] +[def __ordered_lists__ [link quickbook.ref.ordered_lists Ordered lists]] +[def __list_hierarchies__ [link quickbook.ref.list_hierarchies List Hierarchies]] +[def __long_list_lines__ [link quickbook.ref.long_list_lines Long List Lines]] +[def __unordered_lists__ [link quickbook.ref.unordered_lists Unordered lists]] +[def __mixed_lists__ [link quickbook.ref.mixed_lists Mixed lists]] +[def __code__ [link quickbook.ref.code Code]] +[def __escape_back__ [link quickbook.ref.escape_back Escaping Back To QuickBook]] +[def __preformatted__ [link quickbook.ref.preformatted Preformatted]] +[def __blockquote__ [link quickbook.ref.blockquote Blockquote]] +[def __heading__ [link quickbook.ref.headings Heading]] +[def __macros__ [link quickbook.ref.macros Macros]] +[def __templates__ [link quickbook.ref.templates Templates]] +[def __predefined_macros__ [link quickbook.ref.predefined_macros Predefined Macros]] +[def __blurbs__ [link quickbook.ref.blurbs Blurbs]] +[def __admonitions__ [link quickbook.ref.admonitions Admonitions]] +[def __tables__ [link quickbook.ref.tables Tables]] +[def __variable_lists__ [link quickbook.ref.variable_lists Variable Lists]] +[def __include__ [link quickbook.ref.include Include]] +[def __import__ [link quickbook.ref.import Import]] [include introduction.qbk] [include change_log.qbk] diff --git a/tools/quickbook/doc/structure.qbk b/tools/quickbook/doc/structure.qbk index 80e812c2f1..c9a4be9c33 100644 --- a/tools/quickbook/doc/structure.qbk +++ b/tools/quickbook/doc/structure.qbk @@ -26,7 +26,7 @@ quickbook allows you to use it now, it isn't recommended as it is currently a work in progress and subject to change. ] -[#ref-docinfo] +[#quickbook.ref.docinfo] [section:docinfo Document Info] Every document must begin with a Document Info section, which looks something @@ -73,6 +73,7 @@ So the documentation for the 'foo' library might start: ] ``` +[#quickbook.ref.attributes] [section:attributes Document Info Attributes] The document info block has a few different types of attributes. @@ -145,6 +146,7 @@ that's just ignored by the style sheets. [endsect] [/docinfo] +[#quickbook.ref.section] [section:section Sections] Quickbook documents are structured using 'sections'. These are used @@ -173,11 +175,12 @@ A sectioned document might look like: ``` Sections start with the `section` tag, and end with the `[endsect]` tag. -(`[/...]` is a comment, [link quickbook.syntax.comments described later]). +(`[/...]` is a comment, [link quickbook.ref.comments described later]). Sections can be given an optional id: ``` +[#quickbook.ref.id] [section:id The Section Title] ``` diff --git a/tools/quickbook/doc/syntax.qbk b/tools/quickbook/doc/syntax.qbk index 2c3c41e465..5088278fc3 100644 --- a/tools/quickbook/doc/syntax.qbk +++ b/tools/quickbook/doc/syntax.qbk @@ -28,7 +28,8 @@ Phrases in each block cannot contain a block terminator. This way, syntax errors such as un-matched closing brackets do not go haywire and corrupt anything past a single block. -[section Comments] +[#quickbook.ref.comments] +[section:comments Comments] Can be placed anywhere. @@ -50,5 +51,4 @@ Can be placed anywhere. [/ for testing [*only ] ] -[endsect] [/Comments] - +[endsect] [/comments] diff --git a/tools/quickbook/src/Jamfile.v2 b/tools/quickbook/src/Jamfile.v2 index 9372559492..0c55c7ae8b 100644 --- a/tools/quickbook/src/Jamfile.v2 +++ b/tools/quickbook/src/Jamfile.v2 @@ -15,6 +15,8 @@ project quickbook <toolset>gcc:<cflags>-g0 <toolset>darwin:<cflags>-g0 <toolset>msvc:<cflags>/wd4709 + <toolset>gcc:<define>BOOST_DETAIL_CONTAINER_FWD + <toolset>darwin:<define>BOOST_DETAIL_CONTAINER_FWD ; lib shell32 ; @@ -24,7 +26,7 @@ exe quickbook quickbook.cpp actions.cpp doc_info_actions.cpp - actions_class.cpp + state.cpp utils.cpp files.cpp string_ref.cpp diff --git a/tools/quickbook/src/actions.cpp b/tools/quickbook/src/actions.cpp index 4802893cb1..304663ffe1 100644 --- a/tools/quickbook/src/actions.cpp +++ b/tools/quickbook/src/actions.cpp @@ -12,8 +12,9 @@ #include <functional> #include <vector> #include <map> -#include <boost/filesystem/v3/convenience.hpp> -#include <boost/filesystem/v3/fstream.hpp> +#include <set> +#include <boost/filesystem/convenience.hpp> +#include <boost/filesystem/fstream.hpp> #include <boost/range/distance.hpp> #include <boost/range/algorithm/replace.hpp> #include <boost/lexical_cast.hpp> @@ -25,8 +26,8 @@ #include "utils.hpp" #include "files.hpp" #include "markups.hpp" -#include "actions_class.hpp" -#include "actions_state.hpp" +#include "state.hpp" +#include "state_save.hpp" #include "grammar.hpp" #include "input_path.hpp" #include "block_tags.hpp" @@ -35,17 +36,22 @@ namespace quickbook { - char const* quickbook_get_date = "__quickbook_get_date__"; - char const* quickbook_get_time = "__quickbook_get_time__"; - - unsigned qbk_version_n = 0; // qbk_major_version * 100 + qbk_minor_version - namespace { - void write_anchors(quickbook::actions& actions, collector& tgt) + void write_anchors(quickbook::state& state, collector& tgt) { - for(quickbook::actions::string_list::iterator - it = actions.anchors.begin(), - end = actions.anchors.end(); + // TODO: This works but is a bit of an odd place to put it. + // Might need to redefine the purpose of this function. + if (!state.source_mode_next.empty()) { + detail::outwarn(state.source_mode_next.get_file(), + state.source_mode_next.get_position()) + << "Temporary source mode unsupported here." + << std::endl; + state.source_mode_next = value(); + } + + for(quickbook::state::string_list::iterator + it = state.anchors.begin(), + end = state.anchors.end(); it != end; ++it) { tgt << "<anchor id=\""; @@ -53,46 +59,52 @@ namespace quickbook tgt << "\"/>"; } - actions.anchors.clear(); + state.anchors.clear(); } - std::string add_anchor(quickbook::actions& actions, + std::string add_anchor(quickbook::state& state, std::string const& id, id_category::categories category = id_category::explicit_anchor_id) { - std::string placeholder = actions.ids.add_anchor(id, category); - actions.anchors.push_back(placeholder); + std::string placeholder = state.ids.add_anchor(id, category); + state.anchors.push_back(placeholder); return placeholder; } } - void explicit_list_action(quickbook::actions&, value); - void header_action(quickbook::actions&, value); - void begin_section_action(quickbook::actions&, value); - void end_section_action(quickbook::actions&, value, string_iterator); - void block_action(quickbook::actions&, value); - void block_empty_action(quickbook::actions&, value); - void macro_definition_action(quickbook::actions&, value); - void template_body_action(quickbook::actions&, value); - void variable_list_action(quickbook::actions&, value); - void table_action(quickbook::actions&, value); - void xinclude_action(quickbook::actions&, value); - void include_action(quickbook::actions&, value, string_iterator); - void image_action(quickbook::actions&, value); - void anchor_action(quickbook::actions&, value); - void link_action(quickbook::actions&, value); - void phrase_action(quickbook::actions&, value); - void role_action(quickbook::actions&, value); - void footnote_action(quickbook::actions&, value); - void raw_phrase_action(quickbook::actions&, value); - void source_mode_action(quickbook::actions&, value); - void do_template_action(quickbook::actions&, value, string_iterator); + bool quickbook_range::in_range() const { + return qbk_version_n >= lower && qbk_version_n < upper; + } + + void explicit_list_action(quickbook::state&, value); + void header_action(quickbook::state&, value); + void begin_section_action(quickbook::state&, value); + void end_section_action(quickbook::state&, value, string_iterator); + void block_action(quickbook::state&, value); + void block_empty_action(quickbook::state&, value); + void macro_definition_action(quickbook::state&, value); + void template_body_action(quickbook::state&, value); + void variable_list_action(quickbook::state&, value); + void table_action(quickbook::state&, value); + void xinclude_action(quickbook::state&, value); + void include_action(quickbook::state&, value, string_iterator); + void image_action(quickbook::state&, value); + void anchor_action(quickbook::state&, value); + void link_action(quickbook::state&, value); + void phrase_action(quickbook::state&, value); + void role_action(quickbook::state&, value); + void footnote_action(quickbook::state&, value); + void raw_phrase_action(quickbook::state&, value); + void source_mode_action(quickbook::state&, value); + void next_source_mode_action(quickbook::state&, value); + void code_action(quickbook::state&, value); + void do_template_action(quickbook::state&, value, string_iterator); void element_action::operator()(parse_iterator first, parse_iterator) const { - value_consumer values = actions.values.release(); - if(!values.check() || !actions.conditional) return; + value_consumer values = state.values.release(); + if(!values.check() || !state.conditional) return; value v = values.consume(); values.finish(); @@ -100,7 +112,7 @@ namespace quickbook { case block_tags::ordered_list: case block_tags::itemized_list: - return explicit_list_action(actions, v); + return explicit_list_action(state, v); case block_tags::generic_heading: case block_tags::heading1: case block_tags::heading2: @@ -108,11 +120,11 @@ namespace quickbook case block_tags::heading4: case block_tags::heading5: case block_tags::heading6: - return header_action(actions, v); + return header_action(state, v); case block_tags::begin_section: - return begin_section_action(actions, v); + return begin_section_action(state, v); case block_tags::end_section: - return end_section_action(actions, v, first.base()); + return end_section_action(state, v, first.base()); case block_tags::blurb: case block_tags::preformatted: case block_tags::blockquote: @@ -122,26 +134,26 @@ namespace quickbook case block_tags::note: case block_tags::tip: case block_tags::block: - return block_action(actions,v); + return block_action(state,v); case block_tags::hr: - return block_empty_action(actions,v); + return block_empty_action(state,v); case block_tags::macro_definition: - return macro_definition_action(actions,v); + return macro_definition_action(state,v); case block_tags::template_definition: - return template_body_action(actions,v); + return template_body_action(state,v); case block_tags::variable_list: - return variable_list_action(actions, v); + return variable_list_action(state, v); case block_tags::table: - return table_action(actions, v); + return table_action(state, v); case block_tags::xinclude: - return xinclude_action(actions, v); + return xinclude_action(state, v); case block_tags::import: case block_tags::include: - return include_action(actions, v, first.base()); + return include_action(state, v, first.base()); case phrase_tags::image: - return image_action(actions, v); + return image_action(state, v); case phrase_tags::anchor: - return anchor_action(actions, v); + return anchor_action(state, v); case phrase_tags::url: case phrase_tags::link: case phrase_tags::funcref: @@ -152,7 +164,7 @@ namespace quickbook case phrase_tags::headerref: case phrase_tags::conceptref: case phrase_tags::globalref: - return link_action(actions, v); + return link_action(state, v); case phrase_tags::bold: case phrase_tags::italic: case phrase_tags::underline: @@ -160,19 +172,25 @@ namespace quickbook case phrase_tags::strikethrough: case phrase_tags::quote: case phrase_tags::replaceable: - return phrase_action(actions, v); + return phrase_action(state, v); case phrase_tags::footnote: - return footnote_action(actions, v); + return footnote_action(state, v); case phrase_tags::escape: - return raw_phrase_action(actions, v); + return raw_phrase_action(state, v); case phrase_tags::role: - return role_action(actions, v); + return role_action(state, v); case source_mode_tags::cpp: case source_mode_tags::python: case source_mode_tags::teletype: - return source_mode_action(actions, v); + return source_mode_action(state, v); + case code_tags::next_source_mode: + return next_source_mode_action(state, v); + case code_tags::code_block: + case code_tags::inline_code_block: + case code_tags::inline_code: + return code_action(state, v); case template_tags::template_: - return do_template_action(actions, v, first.base()); + return do_template_action(state, v, first.base()); default: break; } @@ -180,22 +198,22 @@ namespace quickbook void break_action::operator()(parse_iterator first, parse_iterator) const { - write_anchors(actions, phrase); + write_anchors(state, phrase); if(*first == '\\') { - detail::outwarn(actions.current_file, first.base()) + detail::outwarn(state.current_file, first.base()) //<< "in column:" << pos.column << ", " << "'\\n' is deprecated, pleases use '[br]' instead" << ".\n"; } - if(!actions.warned_about_breaks) + if(!state.warned_about_breaks) { - detail::outwarn(actions.current_file, first.base()) + detail::outwarn(state.current_file, first.base()) << "line breaks generate invalid boostbook " "(will only note first occurrence).\n"; - actions.warned_about_breaks = true; + state.warned_about_breaks = true; } phrase << detail::get_markup(phrase_tags::break_mark).pre; @@ -203,7 +221,7 @@ namespace quickbook void error_message_action::operator()(parse_iterator first, parse_iterator last) const { - file_position const pos = actions.current_file->position_of(first.base()); + file_position const pos = state.current_file->position_of(first.base()); std::string value(first, last); std::string formatted_message = message; @@ -211,91 +229,91 @@ namespace quickbook boost::replace_all(formatted_message, "%c", boost::lexical_cast<std::string>(pos.column)); - detail::outerr(actions.current_file->path, pos.line) - << detail::utf8(formatted_message) << std::endl; - ++actions.error_count; + detail::outerr(state.current_file->path, pos.line) + << formatted_message << std::endl; + ++state.error_count; } void error_action::operator()(parse_iterator first, parse_iterator /*last*/) const { - file_position const pos = actions.current_file->position_of(first.base()); + file_position const pos = state.current_file->position_of(first.base()); - detail::outerr(actions.current_file->path, pos.line) + detail::outerr(state.current_file->path, pos.line) << "Syntax Error near column " << pos.column << ".\n"; - ++actions.error_count; + ++state.error_count; } - void block_action(quickbook::actions& actions, value block) + void block_action(quickbook::state& state, value block) { - write_anchors(actions, actions.out); + write_anchors(state, state.out); detail::markup markup = detail::get_markup(block.get_tag()); value_consumer values = block; - actions.out << markup.pre << values.consume().get_encoded() << markup.post; + state.out << markup.pre << values.consume().get_encoded() << markup.post; values.finish(); } - void block_empty_action(quickbook::actions& actions, value block) + void block_empty_action(quickbook::state& state, value block) { - write_anchors(actions, actions.out); + write_anchors(state, state.out); detail::markup markup = detail::get_markup(block.get_tag()); - actions.out << markup.pre; + state.out << markup.pre; } - void phrase_action(quickbook::actions& actions, value phrase) + void phrase_action(quickbook::state& state, value phrase) { - write_anchors(actions, actions.phrase); + write_anchors(state, state.phrase); detail::markup markup = detail::get_markup(phrase.get_tag()); value_consumer values = phrase; - actions.phrase << markup.pre << values.consume().get_encoded() << markup.post; + state.phrase << markup.pre << values.consume().get_encoded() << markup.post; values.finish(); } - void role_action(quickbook::actions& actions, value role) + void role_action(quickbook::state& state, value role) { - write_anchors(actions, actions.phrase); + write_anchors(state, state.phrase); value_consumer values = role; - actions.phrase + state.phrase << "<phrase role=\""; - detail::print_string(values.consume().get_quickbook(), actions.phrase.get()); - actions.phrase + detail::print_string(values.consume().get_quickbook(), state.phrase.get()); + state.phrase << "\">" << values.consume().get_encoded() << "</phrase>"; values.finish(); } - void footnote_action(quickbook::actions& actions, value phrase) + void footnote_action(quickbook::state& state, value phrase) { - write_anchors(actions, actions.phrase); + write_anchors(state, state.phrase); value_consumer values = phrase; - actions.phrase + state.phrase << "<footnote id=\"" - << actions.ids.add_id("f", id_category::numbered) + << state.ids.add_id("f", id_category::numbered) << "\"><para>" << values.consume().get_encoded() << "</para></footnote>"; values.finish(); } - void raw_phrase_action(quickbook::actions& actions, value phrase) + void raw_phrase_action(quickbook::state& state, value phrase) { - write_anchors(actions, actions.phrase); + write_anchors(state, state.phrase); detail::markup markup = detail::get_markup(phrase.get_tag()); - actions.phrase << markup.pre << phrase.get_quickbook() << markup.post; + state.phrase << markup.pre << phrase.get_quickbook() << markup.post; } void paragraph_action::operator()() const { std::string str; - actions.phrase.swap(str); + state.phrase.swap(str); std::string::const_iterator pos = str.begin(), @@ -305,53 +323,61 @@ namespace quickbook if(pos != end) { detail::markup markup = detail::get_markup(block_tags::paragraph); - actions.out << markup.pre << str; - write_anchors(actions, actions.out); - actions.out << markup.post; + state.out << markup.pre << str; + write_anchors(state, state.out); + state.out << markup.post; } } void list_item_action::operator()() const { + // Be careful as this is sometimes called in the wrong place + // for markup such as: + // + // * A + // [endsect] + // + // This action is called before [endsect] (to end the list item) + // and then also after it due to the way the parser works. std::string str; - actions.phrase.swap(str); - actions.out << str; - write_anchors(actions, actions.out); + state.phrase.swap(str); + state.out << str; + write_anchors(state, state.out); } void phrase_end_action::operator()() const { - write_anchors(actions, actions.phrase); + write_anchors(state, state.phrase); } namespace { - void write_bridgehead(quickbook::actions& actions, int level, + void write_bridgehead(quickbook::state& state, int level, std::string const& str, std::string const& id, bool self_link) { if (self_link && !id.empty()) { - actions.out << "<bridgehead renderas=\"sect" << level << "\""; - actions.out << " id=\""; - actions.out << actions.ids.add_id("h", id_category::numbered); - actions.out << "\">"; - actions.out << "<phrase id=\"" << id << "\"/>"; - actions.out << "<link linkend=\"" << id << "\">"; - actions.out << str; - actions.out << "</link>"; - actions.out << "</bridgehead>"; + state.out << "<bridgehead renderas=\"sect" << level << "\""; + state.out << " id=\""; + state.out << state.ids.add_id("h", id_category::numbered); + state.out << "\">"; + state.out << "<phrase id=\"" << id << "\"/>"; + state.out << "<link linkend=\"" << id << "\">"; + state.out << str; + state.out << "</link>"; + state.out << "</bridgehead>"; } else { - actions.out << "<bridgehead renderas=\"sect" << level << "\""; - if(!id.empty()) actions.out << " id=\"" << id << "\""; - actions.out << ">"; - actions.out << str; - actions.out << "</bridgehead>"; + state.out << "<bridgehead renderas=\"sect" << level << "\""; + if(!id.empty()) state.out << " id=\"" << id << "\""; + state.out << ">"; + state.out << str; + state.out << "</bridgehead>"; } } } - void header_action(quickbook::actions& actions, value heading_list) + void header_action(quickbook::state& state, value heading_list) { value_consumer values = heading_list; @@ -364,7 +390,7 @@ namespace quickbook if (generic) { - level = actions.ids.section_level() + 1; + level = state.ids.section_level() + 1; // We need to use a heading which is one greater // than the current. if (level > 6 ) // The max is h6, clip it if it goes @@ -375,51 +401,51 @@ namespace quickbook level = heading_list.get_tag() - block_tags::heading1 + 1; } - write_anchors(actions, actions.out); + write_anchors(state, state.out); if (!element_id.empty()) { - std::string anchor = actions.ids.add_id( + std::string anchor = state.ids.add_id( element_id.get_quickbook(), id_category::explicit_id); - write_bridgehead(actions, level, + write_bridgehead(state, level, content.get_encoded(), anchor, self_linked_headers); } - else if (!generic && actions.ids.compatibility_version() < 103) // version 1.2 and below + else if (!generic && state.ids.compatibility_version() < 103) // version 1.2 and below { // This generates the old id style if both the interpreting // version and the generation version are less then 103u. - std::string anchor = actions.ids.old_style_id( + std::string anchor = state.ids.old_style_id( detail::make_identifier( - actions.ids.replace_placeholders_with_unresolved_ids( + state.ids.replace_placeholders_with_unresolved_ids( content.get_encoded())), id_category::generated_heading); - write_bridgehead(actions, level, + write_bridgehead(state, level, content.get_encoded(), anchor, false); } else { - std::string anchor = actions.ids.add_id( + std::string anchor = state.ids.add_id( detail::make_identifier( - actions.ids.compatibility_version() >= 106 ? + state.ids.compatibility_version() >= 106 ? content.get_quickbook() : - actions.ids.replace_placeholders_with_unresolved_ids( + state.ids.replace_placeholders_with_unresolved_ids( content.get_encoded()) ), id_category::generated_heading); - write_bridgehead(actions, level, + write_bridgehead(state, level, content.get_encoded(), anchor, self_linked_headers); } } void simple_phrase_action::operator()(char mark) const { - write_anchors(actions, out); + write_anchors(state, out); int tag = mark == '*' ? phrase_tags::bold : @@ -431,7 +457,7 @@ namespace quickbook assert(tag != 0); detail::markup markup = detail::get_markup(tag); - value_consumer values = actions.values.release(); + value_consumer values = state.values.release(); value content = values.consume(); values.finish(); @@ -442,21 +468,21 @@ namespace quickbook bool cond_phrase_push::start() { - value_consumer values = actions.values.release(); + value_consumer values = state.values.release(); - saved_conditional = actions.conditional; + saved_conditional = state.conditional; if (saved_conditional) { string_ref macro1 = values.consume().get_quickbook(); std::string macro(macro1.begin(), macro1.end()); - actions.conditional = find(actions.macro, macro.c_str()); + state.conditional = find(state.macro, macro.c_str()); - if (!actions.conditional) { - actions.phrase.push(); - actions.out.push(); - actions.anchors.swap(anchors); + if (!state.conditional) { + state.phrase.push(); + state.out.push(); + state.anchors.swap(anchors); } } @@ -465,14 +491,14 @@ namespace quickbook void cond_phrase_push::cleanup() { - if (saved_conditional && !actions.conditional) + if (saved_conditional && !state.conditional) { - actions.phrase.pop(); - actions.out.pop(); - actions.anchors.swap(anchors); + state.phrase.pop(); + state.out.pop(); + state.anchors.swap(anchors); } - actions.conditional = saved_conditional; + state.conditional = saved_conditional; } namespace { @@ -494,64 +520,141 @@ namespace quickbook } } - void actions::start_list(char mark) + void state::start_list(char mark) { write_anchors(*this, out); assert(mark == '*' || mark == '#'); out << ((mark == '#') ? "<orderedlist>\n" : "<itemizedlist>\n"); } - void actions::end_list(char mark) + void state::end_list(char mark) { write_anchors(*this, out); assert(mark == '*' || mark == '#'); out << ((mark == '#') ? "\n</orderedlist>" : "\n</itemizedlist>"); } - void actions::start_list_item() + void state::start_list_item() { out << "<listitem><simpara>"; write_anchors(*this, out); } - void actions::end_list_item() + void state::end_list_item() { write_anchors(*this, out); out << "</simpara></listitem>"; } - void explicit_list_action(quickbook::actions& actions, value list) + namespace + { + bool parse_template(value const&, quickbook::state& state); + } + + void state::start_callouts() + { + ++callout_depth; + } + + std::string state::add_callout(value v) + { + std::string callout_id1 = ids.add_id("c", id_category::numbered); + std::string callout_id2 = ids.add_id("c", id_category::numbered); + + callouts.insert(encoded_value(callout_id1)); + callouts.insert(encoded_value(callout_id2)); + callouts.insert(v); + + std::string code; + code += "<co id=\"" + callout_id1 + "\" "; + code += "linkends=\"" + callout_id2 + "\" />"; + + return code; + } + + std::string state::end_callouts() { - write_anchors(actions, actions.out); + assert(callout_depth > 0); + std::string block; + + --callout_depth; + if (callout_depth > 0) return block; + + value_consumer c = callouts.release(); + if (!c.check()) return block; + + block += "<calloutlist>"; + while (c.check()) + { + std::string callout_id1 = c.consume().get_encoded(); + std::string callout_id2 = c.consume().get_encoded(); + value callout_body = c.consume(); + + std::string callout_value; + + { + template_state state(*this); + ++template_depth; + + bool r = parse_template(callout_body, *this); + + if(!r) + { + detail::outerr(callout_body.get_file(), callout_body.get_position()) + << "Expanding callout." << std::endl + << "------------------begin------------------" << std::endl + << callout_body.get_quickbook() + << std::endl + << "------------------end--------------------" << std::endl + ; + ++error_count; + } + + out.swap(callout_value); + } + + block += "<callout arearefs=\"" + callout_id1 + "\" "; + block += "id=\"" + callout_id2 + "\">"; + block += callout_value; + block += "</callout>"; + } + block += "</calloutlist>"; + + return block; + } + + void explicit_list_action(quickbook::state& state, value list) + { + write_anchors(state, state.out); detail::markup markup = detail::get_markup(list.get_tag()); - actions.out << markup.pre; + state.out << markup.pre; BOOST_FOREACH(value item, list) { - actions.out << "<listitem>"; - actions.out << item.get_encoded(); - actions.out << "</listitem>"; + state.out << "<listitem>"; + state.out << item.get_encoded(); + state.out << "</listitem>"; } - actions.out << markup.post; + state.out << markup.post; } - void anchor_action(quickbook::actions& actions, value anchor) + void anchor_action(quickbook::state& state, value anchor) { value_consumer values = anchor; value anchor_id = values.consume(); // Note: anchor_id is never encoded as boostbook. If it // is encoded, it's just things like escapes. - add_anchor(actions, anchor_id.is_encoded() ? + add_anchor(state, anchor_id.is_encoded() ? anchor_id.get_encoded() : anchor_id.get_quickbook()); values.finish(); } void do_macro_action::operator()(std::string const& str) const { - write_anchors(actions, phrase); + write_anchors(state, phrase); if (str == quickbook_get_date) { @@ -582,56 +685,69 @@ namespace quickbook out << *first++; } - void source_mode_action(quickbook::actions& actions, value source_mode) + void source_mode_action(quickbook::state& state, value source_mode) + { + state.source_mode = source_mode_tags::name(source_mode.get_tag()); + } + + void next_source_mode_action(quickbook::state& state, value source_mode) { - actions.source_mode = source_mode_tags::name(source_mode.get_tag()); + value_consumer values = source_mode; + state.source_mode_next = values.consume(); + values.finish(); } - void code_action::operator()(parse_iterator first, parse_iterator last) const + void code_action(quickbook::state& state, value code_block) { - bool inline_code = type == inline_ || - (type == inline_block && qbk_version_n < 106u); - bool block = type != inline_; + int code_tag = code_block.get_tag(); + + value_consumer values = code_block; + string_ref code_value = values.consume().get_quickbook(); + values.finish(); + + bool inline_code = code_tag == code_tags::inline_code || + (code_tag == code_tags::inline_code_block && qbk_version_n < 106u); + bool block = code_tag != code_tags::inline_code; + + std::string source_mode = state.source_mode_next.empty() ? + state.source_mode : state.source_mode_next.get_quickbook(); + state.source_mode_next = value(); if (inline_code) { - write_anchors(actions, actions.phrase); + write_anchors(state, state.phrase); } else { - actions.paragraph(); - write_anchors(actions, actions.out); + paragraph_action para(state); + para(); + write_anchors(state, state.out); } - std::string str; - if (block) { // preprocess the code section to remove the initial indentation mapped_file_builder mapped; - mapped.start(actions.current_file); - mapped.unindent_and_add(first.base(), last.base()); + mapped.start(state.current_file); + mapped.unindent_and_add(code_value.begin(), code_value.end()); file_ptr f = mapped.release(); if (f->source.empty()) return; // Nothing left to do here. The program is empty. + if (qbk_version_n >= 107u) state.start_callouts(); + parse_iterator first_(f->source.begin()); parse_iterator last_(f->source.end()); file_ptr saved_file = f; - boost::swap(actions.current_file, saved_file); + boost::swap(state.current_file, saved_file); // print the code with syntax coloring - str = syntax_highlight(first_, last_, actions, actions.source_mode); + std::string str = syntax_highlight(first_, last_, state, + source_mode, block); - boost::swap(actions.current_file, saved_file); - } - else { - parse_iterator first_(first); - str = syntax_highlight(first_, last, actions, actions.source_mode); - } + boost::swap(state.current_file, saved_file); - if (block) { - collector& output = inline_code ? actions.phrase : actions.out; + collector& output = inline_code ? state.phrase : state.out; // We must not place a \n after the <programlisting> tag // otherwise PDF output starts code blocks with a blank line: @@ -639,24 +755,31 @@ namespace quickbook output << "<programlisting>"; output << str; output << "</programlisting>\n"; + + if (qbk_version_n >= 107u) output << state.end_callouts(); } else { - actions.phrase << "<code>"; - actions.phrase << str; - actions.phrase << "</code>"; + parse_iterator first_(code_value.begin()); + parse_iterator last_(code_value.end()); + std::string str = syntax_highlight(first_, last_, state, + source_mode, block); + + state.phrase << "<code>"; + state.phrase << str; + state.phrase << "</code>"; } } void plain_char_action::operator()(char ch) const { - write_anchors(actions, phrase); + write_anchors(state, phrase); detail::print_char(ch, phrase.get()); } void plain_char_action::operator()(parse_iterator first, parse_iterator last) const { - write_anchors(actions, phrase); + write_anchors(state, phrase); while (first != last) detail::print_char(*first++, phrase.get()); @@ -664,7 +787,7 @@ namespace quickbook void escape_unicode_action::operator()(parse_iterator first, parse_iterator last) const { - write_anchors(actions, phrase); + write_anchors(state, phrase); while(first != last && *first == '0') ++first; @@ -701,9 +824,9 @@ namespace quickbook } } - void image_action(quickbook::actions& actions, value image) + void image_action(quickbook::state& state, value image) { - write_anchors(actions, actions.phrase); + write_anchors(state, state.phrase); // Note: attributes are never encoded as boostbook, if they're // encoded, it's just things like escapes. @@ -723,7 +846,7 @@ namespace quickbook { detail::outwarn(name.get_file(), name.get_position()) << "Duplicate image attribute: " - << detail::utf8(name.get_quickbook()) + << name.get_quickbook() << std::endl; } } @@ -748,10 +871,10 @@ namespace quickbook detail::outerr(attributes["fileref"].get_file(), attributes["fileref"].get_position()) : detail::outwarn(attributes["fileref"].get_file(), attributes["fileref"].get_position())) << "Image path isn't portable: '" - << detail::utf8(fileref) + << fileref << "'" << std::endl; - if (qbk_version_n >= 106u) ++actions.error_count; + if (qbk_version_n >= 106u) ++state.error_count; } boost::replace(fileref, '\\', '/'); @@ -814,10 +937,13 @@ namespace quickbook // Now load the SVG file: // std::string svg_text; - fs::ifstream fs(img); - char c; - while(fs.get(c) && fs.good()) - svg_text.push_back(c); + if (state.add_dependency(img)) { + fs::ifstream fs(img); + std::stringstream buffer; + buffer << fs.rdbuf(); + svg_text = buffer.str(); + } + // // Extract the svg header from the file: // @@ -853,31 +979,31 @@ namespace quickbook } } - actions.phrase << "<inlinemediaobject>"; + state.phrase << "<inlinemediaobject>"; - actions.phrase << "<imageobject><imagedata"; + state.phrase << "<imageobject><imagedata"; BOOST_FOREACH(attribute_map::value_type const& attr, attributes) { - actions.phrase << " " << attr.first << "=\""; - write_plain_text(actions.phrase.get(), attr.second); - actions.phrase << "\""; + state.phrase << " " << attr.first << "=\""; + write_plain_text(state.phrase.get(), attr.second); + state.phrase << "\""; } - actions.phrase << "></imagedata></imageobject>"; + state.phrase << "></imagedata></imageobject>"; // Add a textobject containing the alt tag from earlier. // This will be used for the alt tag in html. if (alt_text.check()) { - actions.phrase << "<textobject><phrase>"; - write_plain_text(actions.phrase.get(), alt_text); - actions.phrase << "</phrase></textobject>"; + state.phrase << "<textobject><phrase>"; + write_plain_text(state.phrase.get(), alt_text); + state.phrase << "</phrase></textobject>"; } - actions.phrase << "</inlinemediaobject>"; + state.phrase << "</inlinemediaobject>"; } - void macro_definition_action(quickbook::actions& actions, quickbook::value macro_definition) + void macro_definition_action(quickbook::state& state, quickbook::value macro_definition) { value_consumer values = macro_definition; std::string macro_id = values.consume().get_quickbook(); @@ -887,7 +1013,7 @@ namespace quickbook values.finish(); std::string* existing_macro = - boost::spirit::classic::find(actions.macro, macro_id.c_str()); + boost::spirit::classic::find(state.macro, macro_id.c_str()); quickbook::ignore_variable(&existing_macro); if (existing_macro) @@ -900,13 +1026,13 @@ namespace quickbook // return; } - actions.macro.add( + state.macro.add( macro_id.begin() , macro_id.end() , phrase); } - void template_body_action(quickbook::actions& actions, quickbook::value template_definition) + void template_body_action(quickbook::state& state, quickbook::value template_definition) { value_consumer values = template_definition; std::string identifier = values.consume().get_quickbook(); @@ -920,16 +1046,16 @@ namespace quickbook value body = values.consume(); BOOST_ASSERT(!values.check()); - if (!actions.templates.add( + if (!state.templates.add( template_symbol( identifier, template_values, body, - &actions.templates.top_scope()))) + &state.templates.top_scope()))) { detail::outwarn(body.get_file(), body.get_position()) - << "Template Redefinition: " << detail::utf8(identifier) << std::endl; - ++actions.error_count; + << "Template Redefinition: " << identifier << std::endl; + ++state.error_count; } } @@ -1050,7 +1176,7 @@ namespace quickbook , std::vector<std::string> const& params , template_scope const& scope , string_iterator first - , quickbook::actions& actions + , quickbook::state& state ) { std::vector<value>::const_iterator arg = args.begin(); @@ -1060,12 +1186,12 @@ namespace quickbook // Store each of the argument passed in as local templates: while (arg != args.end()) { - if (!actions.templates.add( + if (!state.templates.add( template_symbol(*tpl, empty_params, *arg, &scope))) { - detail::outerr(actions.current_file, first) + detail::outerr(state.current_file, first) << "Duplicate Symbol Found" << std::endl; - ++actions.error_count; + ++state.error_count; return std::make_pair(false, tpl); } ++arg; ++tpl; @@ -1075,47 +1201,50 @@ namespace quickbook bool parse_template( value const& content - , quickbook::actions& actions + , quickbook::state& state ) { - file_ptr saved_current_file = actions.current_file; + file_ptr saved_current_file = state.current_file; - actions.current_file = content.get_file(); + state.current_file = content.get_file(); string_ref source = content.get_quickbook(); parse_iterator first(source.begin()); parse_iterator last(source.end()); bool r = cl::parse(first, last, - content.get_tag() == template_tags::block ? - actions.grammar().block : - actions.grammar().inline_phrase + content.get_tag() == template_tags::phrase ? + state.grammar().inline_phrase : + state.grammar().block ).full; - boost::swap(actions.current_file, saved_current_file); + boost::swap(state.current_file, saved_current_file); return r; } } - void call_template(quickbook::actions& actions, + void call_template(quickbook::state& state, template_symbol const* symbol, std::vector<value> const& args, string_iterator first) { + bool is_block = symbol->content.get_tag() != template_tags::phrase; + // If this template contains already encoded text, then just // write it out, without going through any of the rigamarole. if (symbol->content.is_encoded()) { - if (symbol->content.get_tag() == template_tags::block) + if (is_block) { - actions.paragraph(); - actions.out << symbol->content.get_encoded(); + paragraph_action para(state); + para(); + state.out << symbol->content.get_encoded(); } else { - actions.phrase << symbol->content.get_encoded(); + state.phrase << symbol->content.get_encoded(); } return; @@ -1126,36 +1255,36 @@ namespace quickbook // // Note that for quickbook 1.4- this value is just ignored when the // arguments are expanded. - template_scope const& call_scope = actions.templates.top_scope(); + template_scope const& call_scope = state.templates.top_scope(); std::string block; std::string phrase; { - template_state state(actions); - actions.templates.start_template(symbol); + template_state save(state); + state.templates.start_template(symbol); qbk_version_n = symbol->content.get_file()->version(); - ++actions.template_depth; - if (actions.template_depth > actions.max_template_depth) + ++state.template_depth; + if (state.template_depth > state.max_template_depth) { - detail::outerr(actions.current_file, first) + detail::outerr(state.current_file, first) << "Infinite loop detected" << std::endl; - ++actions.error_count; + ++state.error_count; return; } // Store the current section level so that we can ensure that // [section] and [endsect] tags in the template are balanced. - actions.min_section_level = actions.ids.section_level(); + state.min_section_level = state.ids.section_level(); /////////////////////////////////// // Prepare the arguments as local templates bool get_arg_result; std::vector<std::string>::const_iterator tpl; boost::tie(get_arg_result, tpl) = - get_arguments(args, symbol->params, call_scope, first, actions); + get_arguments(args, symbol->params, call_scope, first, state); if (!get_arg_result) { @@ -1165,128 +1294,67 @@ namespace quickbook /////////////////////////////////// // parse the template body: - if (!parse_template(symbol->content, actions)) + if (!parse_template(symbol->content, state)) { - detail::outerr(actions.current_file, first) + detail::outerr(state.current_file, first) << "Expanding " - << (symbol->content.get_tag() == template_tags::block ? "block" : "phrase") - << " template: " << detail::utf8(symbol->identifier) << std::endl + << (is_block ? "block" : "phrase") + << " template: " << symbol->identifier << std::endl << std::endl << "------------------begin------------------" << std::endl - << detail::utf8(symbol->content.get_quickbook()) + << symbol->content.get_quickbook() << "------------------end--------------------" << std::endl << std::endl; - ++actions.error_count; + ++state.error_count; return; } - if (actions.ids.section_level() != actions.min_section_level) + if (state.ids.section_level() != state.min_section_level) { - detail::outerr(actions.current_file, first) + detail::outerr(state.current_file, first) << "Mismatched sections in template " - << detail::utf8(symbol->identifier) + << symbol->identifier << std::endl; - ++actions.error_count; + ++state.error_count; return; } - actions.out.swap(block); - actions.phrase.swap(phrase); + state.out.swap(block); + state.phrase.swap(phrase); } - if(symbol->content.get_tag() == template_tags::block || !block.empty()) { - actions.paragraph(); // For paragraphs before the template call. - actions.out << block; - actions.phrase << phrase; - actions.paragraph(); + if(is_block || !block.empty()) { + paragraph_action para(state); + para(); // For paragraphs before the template call. + state.out << block; + state.phrase << phrase; + para(); } else { - actions.phrase << phrase; + state.phrase << phrase; } } - void call_code_snippet(quickbook::actions& actions, + void call_code_snippet(quickbook::state& state, template_symbol const* symbol, string_iterator first) { - value_consumer values = symbol->content; - value content = values.consume(template_tags::block); - value callouts = values.consume(); - values.finish(); - - std::vector<std::string> callout_ids; + assert(symbol->params.size() == 0); std::vector<value> args; - unsigned int size = symbol->params.size(); - std::string callout_base("c"); - - for(unsigned int i = 0; i < size; ++i) - { - std::string callout_id1 = actions.ids.add_id(callout_base, id_category::numbered); - std::string callout_id2 = actions.ids.add_id(callout_base, id_category::numbered); - - std::string code; - code += "<co id=\"" + callout_id1 + "\" "; - code += "linkends=\"" + callout_id2 + "\" />"; - - args.push_back(encoded_value(code, template_tags::phrase)); - callout_ids.push_back(callout_id1); - callout_ids.push_back(callout_id2); - } // Create a fake symbol for call_template template_symbol t( symbol->identifier, symbol->params, - content, + symbol->content, symbol->lexical_parent); - call_template(actions, &t, args, first); - - std::string block; - - if(!callouts.empty()) - { - block += "<calloutlist>"; - int i = 0; - BOOST_FOREACH(value c, callouts) - { - std::string callout_id1 = callout_ids[i++]; - std::string callout_id2 = callout_ids[i++]; - - std::string callout_value; - { - template_state state(actions); - ++actions.template_depth; - - bool r = parse_template(c, actions); - - if(!r) - { - detail::outerr(c.get_file(), c.get_position()) - << "Expanding callout." << std::endl - << "------------------begin------------------" << std::endl - << detail::utf8(c.get_quickbook()) - << std::endl - << "------------------end--------------------" << std::endl - ; - ++actions.error_count; - return; - } - - actions.out.swap(callout_value); - } - - block += "<callout arearefs=\"" + callout_id1 + "\" "; - block += "id=\"" + callout_id2 + "\">"; - block += callout_value; - block += "</callout>"; - } - block += "</calloutlist>"; - } - actions.out << block; + state.start_callouts(); + call_template(state, &t, args, first); + state.out << state.end_callouts(); } - void do_template_action(quickbook::actions& actions, value template_list, + void do_template_action(quickbook::state& state, value template_list, string_iterator first) { // Get the arguments @@ -1306,7 +1374,7 @@ namespace quickbook values.finish(); - template_symbol const* symbol = actions.templates.find(identifier); + template_symbol const* symbol = state.templates.find(identifier); BOOST_ASSERT(symbol); // Deal with escaped templates. @@ -1315,19 +1383,19 @@ namespace quickbook { if (!args.empty()) { - detail::outerr(actions.current_file, first) + detail::outerr(state.current_file, first) << "Arguments for escaped template." <<std::endl; - ++actions.error_count; + ++state.error_count; } if (symbol->content.is_encoded()) { - actions.phrase << symbol->content.get_encoded(); + state.phrase << symbol->content.get_encoded(); } else { - actions.phrase << symbol->content.get_quickbook(); + state.phrase << symbol->content.get_quickbook(); /* @@ -1339,7 +1407,7 @@ namespace quickbook quickbook::detail::markup escape_markup = detail::get_markup(phrase_tags::escape); - actions.phrase + state.phrase << escape_markup.pre << symbol->content.get_quickbook() << escape_markup.post @@ -1359,11 +1427,11 @@ namespace quickbook case template_tags::phrase: // Break the arguments for a template - break_arguments(args, symbol->params, actions.current_file->path); + break_arguments(args, symbol->params, state.current_file->path); if (args.size() != symbol->params.size()) { - detail::outerr(actions.current_file, first) + detail::outerr(state.current_file, first) << "Invalid number of arguments passed. Expecting: " << symbol->params.size() << " argument(s), got: " @@ -1371,26 +1439,26 @@ namespace quickbook << " argument(s) instead." << std::endl; - ++actions.error_count; + ++state.error_count; return; } - call_template(actions, symbol, args, first); + call_template(state, symbol, args, first); break; case template_tags::snippet: if (!args.empty()) { - detail::outerr(actions.current_file, first) + detail::outerr(state.current_file, first) << "Arguments for code snippet." <<std::endl; - ++actions.error_count; + ++state.error_count; args.clear(); } - call_code_snippet(actions, symbol, first); + call_code_snippet(state, symbol, first); break; default: @@ -1398,9 +1466,9 @@ namespace quickbook } } - void link_action(quickbook::actions& actions, value link) + void link_action(quickbook::state& state, value link) { - write_anchors(actions, actions.phrase); + write_anchors(state, state.phrase); detail::markup markup = detail::get_markup(link.get_tag()); @@ -1414,57 +1482,57 @@ namespace quickbook std::string dst = dst_value.is_encoded() ? dst_value.get_encoded() : dst_value.get_quickbook(); - actions.phrase << markup.pre; - detail::print_string(dst, actions.phrase.get()); - actions.phrase << "\">"; + state.phrase << markup.pre; + detail::print_string(dst, state.phrase.get()); + state.phrase << "\">"; if (content.empty()) - detail::print_string(dst, actions.phrase.get()); + detail::print_string(dst, state.phrase.get()); else - actions.phrase << content.get_encoded(); + state.phrase << content.get_encoded(); - actions.phrase << markup.post; + state.phrase << markup.post; } - void variable_list_action(quickbook::actions& actions, value variable_list) + void variable_list_action(quickbook::state& state, value variable_list) { - write_anchors(actions, actions.out); + write_anchors(state, state.out); value_consumer values = variable_list; std::string title = values.consume(table_tags::title).get_quickbook(); - actions.out << "<variablelist>\n"; + state.out << "<variablelist>\n"; - actions.out << "<title>"; - detail::print_string(title, actions.out.get()); - actions.out << "</title>\n"; + state.out << "<title>"; + detail::print_string(title, state.out.get()); + state.out << "</title>\n"; BOOST_FOREACH(value_consumer entry, values) { - actions.out << "<varlistentry>"; + state.out << "<varlistentry>"; if(entry.check()) { - actions.out << "<term>"; - actions.out << entry.consume().get_encoded(); - actions.out << "</term>"; + state.out << "<term>"; + state.out << entry.consume().get_encoded(); + state.out << "</term>"; } if(entry.check()) { - actions.out << "<listitem>"; - BOOST_FOREACH(value phrase, entry) actions.out << phrase.get_encoded(); - actions.out << "</listitem>"; + state.out << "<listitem>"; + BOOST_FOREACH(value phrase, entry) state.out << phrase.get_encoded(); + state.out << "</listitem>"; } - actions.out << "</varlistentry>\n"; + state.out << "</varlistentry>\n"; } - actions.out << "</variablelist>\n"; + state.out << "</variablelist>\n"; values.finish(); } - void table_action(quickbook::actions& actions, value table) + void table_action(quickbook::state& state, value table) { - write_anchors(actions, actions.out); + write_anchors(state, state.out); value_consumer values = table; @@ -1478,14 +1546,14 @@ namespace quickbook std::string table_id; if (!element_id.empty()) { - table_id = actions.ids.add_id(element_id, id_category::explicit_id); + table_id = state.ids.add_id(element_id, id_category::explicit_id); } else if (has_title) { - if (actions.ids.compatibility_version() >= 105) { - table_id = actions.ids.add_id(detail::make_identifier(title.get_quickbook()), id_category::generated); + if (state.ids.compatibility_version() >= 105) { + table_id = state.ids.add_id(detail::make_identifier(title.get_quickbook()), id_category::generated); } else { - table_id = actions.ids.add_id("t", id_category::numbered); + table_id = state.ids.add_id("t", id_category::numbered); } } @@ -1503,64 +1571,64 @@ namespace quickbook if (has_title) { - actions.out << "<table frame=\"all\""; + state.out << "<table frame=\"all\""; if(!table_id.empty()) - actions.out << " id=\"" << table_id << "\""; - actions.out << ">\n"; - actions.out << "<title>"; + state.out << " id=\"" << table_id << "\""; + state.out << ">\n"; + state.out << "<title>"; if (qbk_version_n < 106u) { - detail::print_string(title.get_quickbook(), actions.out.get()); + detail::print_string(title.get_quickbook(), state.out.get()); } else { - actions.out << title.get_encoded(); + state.out << title.get_encoded(); } - actions.out << "</title>"; + state.out << "</title>"; } else { - actions.out << "<informaltable frame=\"all\""; + state.out << "<informaltable frame=\"all\""; if(!table_id.empty()) - actions.out << " id=\"" << table_id << "\""; - actions.out << ">\n"; + state.out << " id=\"" << table_id << "\""; + state.out << ">\n"; } - actions.out << "<tgroup cols=\"" << span_count << "\">\n"; + state.out << "<tgroup cols=\"" << span_count << "\">\n"; if (row_count > 1) { - actions.out << "<thead>" << "<row>"; + state.out << "<thead>" << "<row>"; BOOST_FOREACH(value cell, values.consume()) { - actions.out << "<entry>" << cell.get_encoded() << "</entry>"; + state.out << "<entry>" << cell.get_encoded() << "</entry>"; } - actions.out << "</row>\n" << "</thead>\n"; + state.out << "</row>\n" << "</thead>\n"; } - actions.out << "<tbody>\n"; + state.out << "<tbody>\n"; BOOST_FOREACH(value row, values) { - actions.out << "<row>"; + state.out << "<row>"; BOOST_FOREACH(value cell, row) { - actions.out << "<entry>" << cell.get_encoded() << "</entry>"; + state.out << "<entry>" << cell.get_encoded() << "</entry>"; } - actions.out << "</row>\n"; + state.out << "</row>\n"; } values.finish(); - actions.out << "</tbody>\n" - << "</tgroup>\n"; + state.out << "</tbody>\n" + << "</tgroup>\n"; if (has_title) { - actions.out << "</table>\n"; + state.out << "</table>\n"; } else { - actions.out << "</informaltable>\n"; + state.out << "</informaltable>\n"; } } - void begin_section_action(quickbook::actions& actions, value begin_section_list) + void begin_section_action(quickbook::state& state, value begin_section_list) { value_consumer values = begin_section_list; @@ -1568,7 +1636,7 @@ namespace quickbook value content = values.consume(); values.finish(); - std::string full_id = actions.ids.begin_section( + std::string full_id = state.ids.begin_section( !element_id.empty() ? element_id.get_quickbook() : detail::make_identifier(content.get_quickbook()), @@ -1576,48 +1644,48 @@ namespace quickbook id_category::explicit_section_id : id_category::generated_section); - actions.out << "\n<section id=\"" << full_id << "\">\n"; - actions.out << "<title>"; + state.out << "\n<section id=\"" << full_id << "\">\n"; + state.out << "<title>"; - write_anchors(actions, actions.out); + write_anchors(state, state.out); - if (self_linked_headers && actions.ids.compatibility_version() >= 103) + if (self_linked_headers && state.ids.compatibility_version() >= 103) { - actions.out << "<link linkend=\"" << full_id << "\">" + state.out << "<link linkend=\"" << full_id << "\">" << content.get_encoded() << "</link>" ; } else { - actions.out << content.get_encoded(); + state.out << content.get_encoded(); } - actions.out << "</title>\n"; + state.out << "</title>\n"; } - void end_section_action(quickbook::actions& actions, value end_section, string_iterator first) + void end_section_action(quickbook::state& state, value end_section, string_iterator first) { - write_anchors(actions, actions.out); + write_anchors(state, state.out); - if (actions.ids.section_level() <= actions.min_section_level) + if (state.ids.section_level() <= state.min_section_level) { - file_position const pos = actions.current_file->position_of(first); + file_position const pos = state.current_file->position_of(first); - detail::outerr(actions.current_file->path, pos.line) + detail::outerr(state.current_file->path, pos.line) << "Mismatched [endsect] near column " << pos.column << ".\n"; - ++actions.error_count; + ++state.error_count; return; } - actions.out << "</section>"; - actions.ids.end_section(); + state.out << "</section>"; + state.ids.end_section(); } void element_id_warning_action::operator()(parse_iterator first, parse_iterator) const { - detail::outwarn(actions.current_file, first.base()) << "Empty id.\n"; + detail::outwarn(state.current_file, first.base()) << "Empty id.\n"; } // Not a general purpose normalization function, just @@ -1695,57 +1763,84 @@ namespace quickbook return result; } - fs::path check_path(value const& path, quickbook::actions& actions) + struct path_details { + // Will possibly add 'url' and 'glob' to this list later: + enum path_type { path }; + + std::string value; + path_type type; + + path_details(std::string const& value, path_type type) : + value(value), type(type) + { + } + }; + + path_details check_path(value const& path, quickbook::state& state) { - std::string path_text = path.is_encoded() ? path.get_encoded() : - path.get_quickbook(); + // Paths are encoded for quickbook 1.6+ and also xmlbase + // values (technically xmlbase is a 1.6 feature, but that + // isn't enforced as it's backwards compatible). + // + // Counter-intuitively: encoded == plain text here. + + std::string path_text = qbk_version_n >= 106u || path.is_encoded() ? + path.get_encoded() : path.get_quickbook(); if(path_text.find('\\') != std::string::npos) { - (qbk_version_n >= 106u ? - detail::outerr(path.get_file(), path.get_position()) : - detail::outwarn(path.get_file(), path.get_position())) - << "Path isn't portable: '" - << detail::utf8(path_text) + quickbook::detail::ostream* err; + + if (qbk_version_n >= 106u) { + err = &detail::outerr(path.get_file(), path.get_position()); + ++state.error_count; + } + else { + err = &detail::outwarn(path.get_file(), path.get_position()); + } + + *err << "Path isn't portable: '" + << path_text << "'" << std::endl; - if (qbk_version_n >= 106u) ++actions.error_count; + + boost::replace(path_text, '\\', '/'); } - - boost::replace(path_text, '\\', '/'); - - return detail::generic_to_path(path_text); + + return path_details(path_text, path_details::path); } - xinclude_path calculate_xinclude_path(value const& p, quickbook::actions& actions) + xinclude_path calculate_xinclude_path(value const& p, quickbook::state& state) { - fs::path path = check_path(p, actions); + path_details details = check_path(p, state); + + fs::path path = detail::generic_to_path(details.value); fs::path full_path = path; // If the path is relative if (!path.has_root_directory()) { // Resolve the path from the current file - full_path = actions.current_file->path.parent_path() / path; + full_path = state.current_file->path.parent_path() / path; // Then calculate relative to the current xinclude_base. - path = path_difference(actions.xinclude_base, full_path); + path = path_difference(state.xinclude_base, full_path); } return xinclude_path(full_path, detail::escape_uri(detail::path_to_generic(path))); } - void xinclude_action(quickbook::actions& actions, value xinclude) + void xinclude_action(quickbook::state& state, value xinclude) { - write_anchors(actions, actions.out); + write_anchors(state, state.out); value_consumer values = xinclude; - xinclude_path x = calculate_xinclude_path(values.consume(), actions); + xinclude_path x = calculate_xinclude_path(values.consume(), state); values.finish(); - actions.out << "\n<xi:include href=\""; - detail::print_string(x.uri, actions.out.get()); - actions.out << "\" />\n"; + state.out << "\n<xi:include href=\""; + detail::print_string(x.uri, state.out.get()); + state.out << "\" />\n"; } namespace @@ -1757,41 +1852,67 @@ namespace quickbook fs::path filename; fs::path filename_relative; + + bool operator < (include_search_return const & other) const + { + if (filename_relative < other.filename_relative) return true; + else if (other.filename_relative < filename_relative) return false; + else return filename < other.filename; + } }; - include_search_return include_search(fs::path const& path, - quickbook::actions const& actions) + std::set<include_search_return> include_search(path_details const& details, + quickbook::state& state, string_iterator pos) { - fs::path current = actions.current_file->path.parent_path(); + std::set<include_search_return> result; + + fs::path path = detail::generic_to_path(details.value); // If the path is relative, try and resolve it. if (!path.has_root_directory() && !path.has_root_name()) { + fs::path local_path = + state.current_file->path.parent_path() / path; + // See if it can be found locally first. - if (fs::exists(current / path)) + if (state.add_dependency(local_path)) { - return include_search_return( - current / path, - actions.filename_relative.parent_path() / path); + result.insert(include_search_return( + local_path, + state.filename_relative.parent_path() / path)); + return result; } - // Search in each of the include path locations. BOOST_FOREACH(fs::path full, include_path) { full /= path; - if (fs::exists(full)) + + if (state.add_dependency(full)) { - return include_search_return(full, path); + result.insert(include_search_return(full, path)); + return result; } } } + else + { + if (state.add_dependency(path)) { + result.insert(include_search_return(path, path)); + return result; + } + } + + detail::outerr(state.current_file, pos) + << "Unable to find file: " + << details.value + << std::endl; + ++state.error_count; - return include_search_return(path, - actions.filename_relative.parent_path() / path); + return result; } } - void load_quickbook(quickbook::actions& actions, + void load_quickbook(quickbook::state& state, include_search_return const& paths, value::tag_type load_type, value const& include_doc_id = value()) @@ -1810,32 +1931,32 @@ namespace quickbook // // For old versions of quickbook, templates aren't scoped by the // file. - file_state state(actions, + file_state save(state, load_type == block_tags::import ? file_state::scope_output : qbk_version_n >= 106u ? file_state::scope_callables : file_state::scope_macros); - actions.current_file = load(paths.filename); // Throws load_error - actions.filename_relative = paths.filename_relative; - actions.imported = (load_type == block_tags::import); + state.current_file = load(paths.filename); // Throws load_error + state.filename_relative = paths.filename_relative; + state.imported = (load_type == block_tags::import); // update the __FILENAME__ macro - *boost::spirit::classic::find(actions.macro, "__FILENAME__") - = detail::path_to_generic(actions.filename_relative); + *boost::spirit::classic::find(state.macro, "__FILENAME__") + = detail::path_to_generic(state.filename_relative); // parse the file - quickbook::parse_file(actions, include_doc_id, true); + quickbook::parse_file(state, include_doc_id, true); // Don't restore source_mode on older versions. - if (keep_inner_source_mode) state.source_mode = actions.source_mode; + if (keep_inner_source_mode) save.source_mode = state.source_mode; } // restore the __FILENAME__ macro - *boost::spirit::classic::find(actions.macro, "__FILENAME__") - = detail::path_to_generic(actions.filename_relative); + *boost::spirit::classic::find(state.macro, "__FILENAME__") + = detail::path_to_generic(state.filename_relative); } - void load_source_file(quickbook::actions& actions, + void load_source_file(quickbook::state& state, include_search_return const& paths, value::tag_type load_type, string_iterator first, @@ -1847,12 +1968,12 @@ namespace quickbook std::string ext = paths.filename.extension().generic_string(); std::vector<template_symbol> storage; // Throws load_error - actions.error_count += + state.error_count += load_snippets(paths.filename, storage, ext, load_type); if (load_type == block_tags::include) { - actions.templates.push(); + state.templates.push(); } BOOST_FOREACH(template_symbol& ts, storage) @@ -1860,12 +1981,12 @@ namespace quickbook std::string tname = ts.identifier; if (tname != "!") { - ts.lexical_parent = &actions.templates.top_scope(); - if (!actions.templates.add(ts)) + ts.lexical_parent = &state.templates.top_scope(); + if (!state.templates.add(ts)) { detail::outerr(ts.content.get_file(), ts.content.get_position()) - << "Template Redefinition: " << detail::utf8(tname) << std::endl; - ++actions.error_count; + << "Template Redefinition: " << tname << std::endl; + ++state.error_count; } } } @@ -1878,71 +1999,77 @@ namespace quickbook if (tname == "!") { - ts.lexical_parent = &actions.templates.top_scope(); - call_code_snippet(actions, &ts, first); + ts.lexical_parent = &state.templates.top_scope(); + call_code_snippet(state, &ts, first); } } - actions.templates.pop(); + state.templates.pop(); } } - void include_action(quickbook::actions& actions, value include, string_iterator first) + void include_action(quickbook::state& state, value include, string_iterator first) { - write_anchors(actions, actions.out); + write_anchors(state, state.out); value_consumer values = include; value include_doc_id = values.optional_consume(general_tags::include_id); - include_search_return paths = include_search( - check_path(values.consume(), actions), actions); + path_details details = check_path(values.consume(), state); values.finish(); - try { - if (qbk_version_n >= 106) - { - if (actions.imported && include.get_tag() == block_tags::include) - return; - - std::string ext = paths.filename.extension().generic_string(); - - if (ext == ".qbk" || ext == ".quickbook") + std::set<include_search_return> search = include_search(details, state, first); + std::set<include_search_return>::iterator i = search.begin(); + std::set<include_search_return>::iterator e = search.end(); + for (; i != e; ++i) + { + include_search_return const & paths = *i; + try { + if (qbk_version_n >= 106) { - load_quickbook(actions, paths, include.get_tag(), include_doc_id); + if (state.imported && include.get_tag() == block_tags::include) + return; + + std::string ext = paths.filename.extension().generic_string(); + + if (ext == ".qbk" || ext == ".quickbook") + { + load_quickbook(state, paths, include.get_tag(), include_doc_id); + } + else + { + load_source_file(state, paths, include.get_tag(), first, include_doc_id); + } } else { - load_source_file(actions, paths, include.get_tag(), first, include_doc_id); + if (include.get_tag() == block_tags::include) + { + load_quickbook(state, paths, include.get_tag(), include_doc_id); + } + else + { + load_source_file(state, paths, include.get_tag(), first, include_doc_id); + } } } - else - { - if (include.get_tag() == block_tags::include) - { - load_quickbook(actions, paths, include.get_tag(), include_doc_id); - } - else - { - load_source_file(actions, paths, include.get_tag(), first, include_doc_id); - } + catch (load_error& e) { + ++state.error_count; + + detail::outerr(state.current_file, first) + << "Loading file " + << paths.filename + << ": " + << e.what() + << std::endl; } } - catch (load_error& e) { - ++actions.error_count; - - detail::outerr(actions.current_file, first) - << "Loading file " - << paths.filename - << ": " - << detail::utf8(e.what()) - << std::endl; - } } bool to_value_scoped_action::start(value::tag_type t) { - actions.out.push(); - actions.phrase.push(); - actions.anchors.swap(saved_anchors); + state.out.push(); + state.phrase.push(); + state.anchors.swap(saved_anchors); tag = t; return true; @@ -1952,27 +2079,28 @@ namespace quickbook { std::string value; - if (!actions.out.str().empty()) + if (!state.out.str().empty()) { - actions.paragraph(); - write_anchors(actions, actions.out); - actions.out.swap(value); + paragraph_action para(state); + para(); // For paragraphs before the template call. + write_anchors(state, state.out); + state.out.swap(value); } else { - write_anchors(actions, actions.phrase); - actions.phrase.swap(value); + write_anchors(state, state.phrase); + state.phrase.swap(value); } - actions.values.builder.insert(encoded_qbk_value( - actions.current_file, first.base(), last.base(), value, tag)); + state.values.builder.insert(encoded_qbk_value( + state.current_file, first.base(), last.base(), value, tag)); } void to_value_scoped_action::cleanup() { - actions.phrase.pop(); - actions.out.pop(); - actions.anchors.swap(saved_anchors); + state.phrase.pop(); + state.out.pop(); + state.anchors.swap(saved_anchors); } } diff --git a/tools/quickbook/src/actions.hpp b/tools/quickbook/src/actions.hpp index 4f67aec09b..5a93cf949a 100644 --- a/tools/quickbook/src/actions.hpp +++ b/tools/quickbook/src/actions.hpp @@ -13,46 +13,33 @@ #include <string> #include <vector> #include "fwd.hpp" -#include "template_stack.hpp" #include "utils.hpp" #include "values.hpp" #include "scoped.hpp" -#include "symbols.hpp" #include <boost/spirit/include/classic_parser.hpp> namespace quickbook { namespace cl = boost::spirit::classic; - extern unsigned qbk_version_n; // qbk_major_version * 100 + qbk_minor_version - struct quickbook_range : cl::parser<quickbook_range> { - quickbook_range(unsigned min_, unsigned max_) - : min_(min_), max_(max_) {} + quickbook_range(unsigned lower, unsigned upper) + : lower(lower), upper(upper) {} + + bool in_range() const; template <typename ScannerT> typename cl::parser_result<quickbook_range, ScannerT>::type parse(ScannerT const& scan) const { - if (qbk_version_n >= min_ && qbk_version_n < max_) - { - return scan.empty_match(); - } - else - { - return scan.no_match(); - } + return in_range() ? scan.empty_match() : scan.no_match(); } - unsigned min_, max_; + unsigned lower, upper; }; - inline quickbook_range qbk_since(unsigned min_) { - return quickbook_range(min_, 999); - } - - inline quickbook_range qbk_before(unsigned max_) { - return quickbook_range(0, max_); + inline quickbook_range qbk_ver(unsigned lower, unsigned upper = 999u) { + return quickbook_range(lower, upper); } // Throws load_error @@ -61,31 +48,32 @@ namespace quickbook std::string syntax_highlight( parse_iterator first, parse_iterator last, - actions& escape_actions, - std::string const& source_mode); + quickbook::state& state, + std::string const& source_mode, + bool is_block); struct xinclude_path { - xinclude_path(fs::path& path, std::string const& uri) : + xinclude_path(fs::path const& path, std::string const& uri) : path(path), uri(uri) {} fs::path path; std::string uri; }; - xinclude_path calculate_xinclude_path(value const&, quickbook::actions&); + xinclude_path calculate_xinclude_path(value const&, quickbook::state&); struct error_message_action { // Prints an error message to std::cerr - error_message_action(quickbook::actions& actions, std::string const& m) - : actions(actions) + error_message_action(quickbook::state& state, std::string const& m) + : state(state) , message(m) {} void operator()(parse_iterator, parse_iterator) const; - quickbook::actions& actions; + quickbook::state& state; std::string message; }; @@ -93,27 +81,27 @@ namespace quickbook { // Prints an error message to std::cerr - error_action(quickbook::actions& actions) - : actions(actions) {} + error_action(quickbook::state& state) + : state(state) {} void operator()(parse_iterator first, parse_iterator last) const; error_message_action operator()(std::string const& message) { - return error_message_action(actions, message); + return error_message_action(state, message); } - quickbook::actions& actions; + quickbook::state& state; }; struct element_action { - element_action(quickbook::actions& actions) - : actions(actions) {} + element_action(quickbook::state& state) + : state(state) {} void operator()(parse_iterator, parse_iterator) const; - quickbook::actions& actions; + quickbook::state& state; }; struct paragraph_action @@ -122,13 +110,13 @@ namespace quickbook // doesn't output the paragraph if it's only whitespace. paragraph_action( - quickbook::actions& actions) - : actions(actions) {} + quickbook::state& state) + : state(state) {} void operator()() const; void operator()(parse_iterator, parse_iterator) const { (*this)(); } - quickbook::actions& actions; + quickbook::state& state; }; struct list_item_action @@ -137,24 +125,24 @@ namespace quickbook // doesn't output the paragraph if it's only whitespace. list_item_action( - quickbook::actions& actions) - : actions(actions) {} + quickbook::state& state) + : state(state) {} void operator()() const; void operator()(parse_iterator, parse_iterator) const { (*this)(); } - quickbook::actions& actions; + quickbook::state& state; }; struct phrase_end_action { - phrase_end_action(quickbook::actions& actions) : - actions(actions) {} + phrase_end_action(quickbook::state& state) : + state(state) {} void operator()() const; void operator()(parse_iterator, parse_iterator) const { (*this)(); } - quickbook::actions& actions; + quickbook::state& state; }; struct simple_phrase_action @@ -163,43 +151,40 @@ namespace quickbook simple_phrase_action( collector& out - , quickbook::actions& actions) + , quickbook::state& state) : out(out) - , actions(actions) {} + , state(state) {} void operator()(char) const; collector& out; - quickbook::actions& actions; + quickbook::state& state; }; struct cond_phrase_push : scoped_action_base { - cond_phrase_push(quickbook::actions& x) - : actions(x) {} + cond_phrase_push(quickbook::state& x) + : state(x) {} bool start(); void cleanup(); - quickbook::actions& actions; + quickbook::state& state; bool saved_conditional; std::vector<std::string> anchors; }; - extern char const* quickbook_get_date; - extern char const* quickbook_get_time; - struct do_macro_action { // Handles macro substitutions - do_macro_action(collector& phrase, quickbook::actions& actions) + do_macro_action(collector& phrase, quickbook::state& state) : phrase(phrase) - , actions(actions) {} + , state(state) {} void operator()(std::string const& str) const; collector& phrase; - quickbook::actions& actions; + quickbook::state& state; }; struct raw_char_action @@ -220,83 +205,63 @@ namespace quickbook // Prints a single plain char. // Converts '<' to "<"... etc See utils.hpp - plain_char_action(collector& phrase, quickbook::actions& actions) + plain_char_action(collector& phrase, quickbook::state& state) : phrase(phrase) - , actions(actions) {} + , state(state) {} void operator()(char ch) const; void operator()(parse_iterator first, parse_iterator last) const; collector& phrase; - quickbook::actions& actions; + quickbook::state& state; }; struct escape_unicode_action { - escape_unicode_action(collector& phrase, quickbook::actions& actions) + escape_unicode_action(collector& phrase, quickbook::state& state) : phrase(phrase) - , actions(actions) {} + , state(state) {} void operator()(parse_iterator first, parse_iterator last) const; collector& phrase; - quickbook::actions& actions; - }; - - struct code_action - { - enum code_type { block, inline_block, inline_ }; - - // Does the actual syntax highlighing of code - - code_action( - code_type type - , quickbook::actions& actions) - : type(type) - , actions(actions) - { - } - - void operator()(parse_iterator first, parse_iterator last) const; - - code_type type; - quickbook::actions& actions; + quickbook::state& state; }; struct break_action { - break_action(collector& phrase, quickbook::actions& actions) - : phrase(phrase), actions(actions) {} + break_action(collector& phrase, quickbook::state& state) + : phrase(phrase), state(state) {} void operator()(parse_iterator f, parse_iterator) const; collector& phrase; - quickbook::actions& actions; + quickbook::state& state; }; struct element_id_warning_action { - element_id_warning_action(quickbook::actions& actions_) - : actions(actions_) {} + element_id_warning_action(quickbook::state& state_) + : state(state_) {} void operator()(parse_iterator first, parse_iterator last) const; - quickbook::actions& actions; + quickbook::state& state; }; // Returns the doc_type, or an empty string if there isn't one. - std::string pre(quickbook::actions& actions, parse_iterator pos, value include_doc_id, bool nested_file); - void post(quickbook::actions& actions, std::string const& doc_type); + std::string pre(quickbook::state& state, parse_iterator pos, value include_doc_id, bool nested_file); + void post(quickbook::state& state, std::string const& doc_type); struct to_value_scoped_action : scoped_action_base { - to_value_scoped_action(quickbook::actions& actions) - : actions(actions) {} + to_value_scoped_action(quickbook::state& state) + : state(state) {} bool start(value::tag_type = value::default_tag); void success(parse_iterator, parse_iterator); void cleanup(); - quickbook::actions& actions; + quickbook::state& state; std::vector<std::string> saved_anchors; value::tag_type tag; }; diff --git a/tools/quickbook/src/actions_class.cpp b/tools/quickbook/src/actions_class.cpp deleted file mode 100644 index d94706c91a..0000000000 --- a/tools/quickbook/src/actions_class.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/*============================================================================= - Copyright (c) 2002 2004 2006 Joel de Guzman - Copyright (c) 2004 Eric Niebler - Copyright (c) 2005 Thomas Guest - http://spirit.sourceforge.net/ - - Use, modification and distribution is subject to the Boost Software - License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) -=============================================================================*/ -#include "actions_class.hpp" -#include "actions_state.hpp" -#include "quickbook.hpp" -#include "grammar.hpp" -#include "input_path.hpp" - -#if (defined(BOOST_MSVC) && (BOOST_MSVC <= 1310)) -#pragma warning(disable:4355) -#endif - -namespace quickbook -{ - actions::actions(fs::path const& filein_, fs::path const& xinclude_base_, - string_stream& out_, id_manager& ids) - : grammar_() - - , xinclude_base(xinclude_base_) - - , templates() - , error_count(0) - , anchors() - , warned_about_breaks(false) - , conditional(true) - , ids(ids) - - , imported(false) - , macro() - , source_mode("c++") - , current_file(0) - , filename_relative(filein_.filename()) - - , template_depth(0) - , min_section_level(1) - - , out(out_) - , phrase() - , values(¤t_file) - - , to_value(*this) - , scoped_cond_phrase(*this) - - , element(*this) - , error(*this) - , code(code_action::block, *this) - , code_block(code_action::inline_block, *this) - , inline_code(code_action::inline_, *this) - , paragraph(*this) - , list_item(*this) - , phrase_end(*this) - , raw_char(phrase) - , plain_char(phrase, *this) - , escape_unicode(phrase, *this) - - , simple_markup(phrase, *this) - - , break_(phrase, *this) - , do_macro(phrase, *this) - - , element_id_warning(*this) - { - // add the predefined macros - macro.add - ("__DATE__", std::string(quickbook_get_date)) - ("__TIME__", std::string(quickbook_get_time)) - ("__FILENAME__", detail::path_to_generic(filename_relative)) - ; - - boost::scoped_ptr<quickbook_grammar> g( - new quickbook_grammar(*this)); - grammar_.swap(g); - } - - quickbook_grammar& actions::grammar() const { - return *grammar_; - } - - file_state::file_state(actions& a, scope_flags scope) - : a(a) - , scope(scope) - , qbk_version(qbk_version_n) - , imported(a.imported) - , current_file(a.current_file) - , filename_relative(a.filename_relative) - , xinclude_base(a.xinclude_base) - , source_mode(a.source_mode) - , macro() - { - if (scope & scope_macros) macro = a.macro; - if (scope & scope_templates) a.templates.push(); - if (scope & scope_output) { - a.out.push(); - a.phrase.push(); - } - a.values.builder.save(); - } - - file_state::~file_state() - { - a.values.builder.restore(); - boost::swap(qbk_version_n, qbk_version); - boost::swap(a.imported, imported); - boost::swap(a.current_file, current_file); - boost::swap(a.filename_relative, filename_relative); - boost::swap(a.xinclude_base, xinclude_base); - boost::swap(a.source_mode, source_mode); - if (scope & scope_output) { - a.out.pop(); - a.phrase.pop(); - } - if (scope & scope_templates) a.templates.pop(); - if (scope & scope_macros) a.macro = macro; - } - - template_state::template_state(actions& a) - : file_state(a, file_state::scope_all) - , template_depth(a.template_depth) - , min_section_level(a.min_section_level) - { - } - - template_state::~template_state() - { - boost::swap(a.template_depth, template_depth); - boost::swap(a.min_section_level, min_section_level); - } -} diff --git a/tools/quickbook/src/block_element_grammar.cpp b/tools/quickbook/src/block_element_grammar.cpp index f188e1379f..1f5d5daec4 100644 --- a/tools/quickbook/src/block_element_grammar.cpp +++ b/tools/quickbook/src/block_element_grammar.cpp @@ -9,7 +9,8 @@ =============================================================================*/ #include "utils.hpp" -#include "actions_class.hpp" +#include "state.hpp" +#include "actions.hpp" #include "grammar_impl.hpp" #include "block_tags.hpp" #include "template_tags.hpp" @@ -43,20 +44,26 @@ namespace quickbook block_element_grammar_local& local = cleanup_.add( new block_element_grammar_local); + // Actions + error_action error(state); + element_id_warning_action element_id_warning(state); + raw_char_action raw_char(state.phrase); + scoped_parser<to_value_scoped_action> to_value(state); + local.element_id = !( ':' - >> ( !(qbk_since(105u) >> space) - >> (+(cl::alnum_p | '_')) [actions.values.entry(ph::arg1, ph::arg2, general_tags::element_id)] - | cl::eps_p [actions.element_id_warning] + >> ( !(qbk_ver(105u) >> space) + >> (+(cl::alnum_p | '_')) [state.values.entry(ph::arg1, ph::arg2, general_tags::element_id)] + | cl::eps_p [element_id_warning] ) ) ; local.element_id_1_5 = - !(qbk_since(105u) >> local.element_id); + !(qbk_ver(105u) >> local.element_id); local.element_id_1_6 = - !(qbk_since(106u) >> local.element_id); + !(qbk_ver(106u) >> local.element_id); elements.add ("section", element_info(element_info::block, &local.begin_section, block_tags::begin_section)) @@ -110,10 +117,10 @@ namespace quickbook ; local.preformatted = - ( qbk_before(106) >> space - | qbk_since(106) >> blank >> !eol + ( qbk_ver(0, 106) >> space + | qbk_ver(106) >> blank >> !eol ) - >> actions.to_value() + >> to_value() [ inside_preformatted ] @@ -125,7 +132,7 @@ namespace quickbook local.def_macro = space - >> macro_identifier [actions.values.entry(ph::arg1, ph::arg2)] + >> macro_identifier [state.values.entry(ph::arg1, ph::arg2)] >> blank >> local.inner_phrase ; @@ -144,20 +151,20 @@ namespace quickbook local.template_ = space - >> local.template_id [actions.values.entry(ph::arg1, ph::arg2)] - >> actions.values.list()[ + >> local.template_id [state.values.entry(ph::arg1, ph::arg2)] + >> state.values.list()[ !( space >> '[' >> *( space - >> local.template_id [actions.values.entry(ph::arg1, ph::arg2)] + >> local.template_id [state.values.entry(ph::arg1, ph::arg2)] ) >> space >> ']' ) ] >> ( cl::eps_p(*cl::blank_p >> cl::eol_p) - >> local.template_body [actions.values.entry(ph::arg1, ph::arg2, template_tags::block)] - | local.template_body [actions.values.entry(ph::arg1, ph::arg2, template_tags::phrase)] + >> local.template_body [state.values.entry(ph::arg1, ph::arg2, template_tags::block)] + | local.template_body [state.values.entry(ph::arg1, ph::arg2, template_tags::phrase)] ) ; @@ -180,17 +187,17 @@ namespace quickbook local.varlistentry = space >> cl::ch_p('[') - >> actions.values.list() + >> state.values.list() [ ( local.varlistterm >> ( +local.cell - | cl::eps_p [actions.error] + | cl::eps_p [error] ) >> cl::ch_p(']') >> space ) - | cl::eps_p [actions.error] + | cl::eps_p [error] ] ; @@ -200,7 +207,7 @@ namespace quickbook >> local.inner_phrase >> ( cl::ch_p(']') >> space - | cl::eps_p [actions.error] + | cl::eps_p [error] ) ; @@ -224,22 +231,22 @@ namespace quickbook >> ( ( - actions.values.list(table_tags::row) + state.values.list(table_tags::row) [ *local.cell ] >> cl::ch_p(']') >> space ) - | cl::eps_p [actions.error] + | cl::eps_p [error] ) ; local.table_title = - qbk_before(106) - >> (*(cl::anychar_p - eol)) [actions.values.entry(ph::arg1, ph::arg2, table_tags::title)] + qbk_ver(0, 106) + >> (*(cl::anychar_p - eol)) [state.values.entry(ph::arg1, ph::arg2, table_tags::title)] >> (+eol) - | qbk_since(106) - >> actions.to_value(table_tags::title) + | qbk_ver(106) + >> to_value(table_tags::title) [ table_title_phrase ] @@ -259,7 +266,7 @@ namespace quickbook >> ( local.inner_block >> cl::ch_p(']') >> space - | cl::eps_p [actions.error] + | cl::eps_p [error] ) ; @@ -285,33 +292,33 @@ namespace quickbook !( ':' >> (*((cl::alnum_p | '_') - cl::space_p)) - [actions.values.entry(ph::arg1, ph::arg2, general_tags::include_id)] + [state.values.entry(ph::arg1, ph::arg2, general_tags::include_id)] >> space ) >> local.include_filename ; local.include_filename = - qbk_before(106u) - >> (*(cl::anychar_p - phrase_end)) [actions.values.entry(ph::arg1, ph::arg2)] - | qbk_since(106u) - >> actions.to_value() + qbk_ver(0, 106u) + >> (*(cl::anychar_p - phrase_end)) [state.values.entry(ph::arg1, ph::arg2)] + | qbk_ver(106u) + >> to_value() [ *( raw_escape | (cl::anychar_p - phrase_end) - [actions.raw_char] + [raw_char] ) ] ; local.inner_block = - actions.to_value() + to_value() [ inside_paragraph ] ; local.inner_phrase = - actions.to_value() + to_value() [ paragraph_phrase ] diff --git a/tools/quickbook/src/code_snippet.cpp b/tools/quickbook/src/code_snippet.cpp index 8d9484cce2..4c63a3ba0e 100644 --- a/tools/quickbook/src/code_snippet.cpp +++ b/tools/quickbook/src/code_snippet.cpp @@ -16,6 +16,7 @@ #include "block_tags.hpp" #include "template_stack.hpp" #include "actions.hpp" +#include "state.hpp" #include "values.hpp" #include "files.hpp" #include "input_path.hpp" @@ -31,13 +32,13 @@ namespace quickbook char const* source_type) : last_code_pos(source_file->source.begin()) , in_code(false) - , callout_id(0) , snippet_stack() , storage(storage) , source_file(source_file) , source_type(source_type) , error_count(0) { + source_file->is_code_snippets = true; content.start(source_file); } @@ -48,7 +49,6 @@ namespace quickbook void start_snippet_impl(std::string const&, string_iterator); void end_snippet(string_iterator first, string_iterator last); void end_snippet_impl(string_iterator); - void callout(string_iterator first, string_iterator last); void end_file(string_iterator, string_iterator); void append_code(string_iterator first, string_iterator last); @@ -56,26 +56,22 @@ namespace quickbook struct snippet_data { - snippet_data(std::string const& id, int callout_base_id) + snippet_data(std::string const& id) : id(id) - , callout_base_id(callout_base_id) , start_code(false) {} std::string id; - int callout_base_id; bool start_code; std::string::const_iterator source_pos; mapped_file_builder::pos start_pos; - value_builder callouts; boost::shared_ptr<snippet_data> next; }; - void push_snippet_data(std::string const& id, int callout_base_id, + void push_snippet_data(std::string const& id, std::string::const_iterator pos) { - boost::shared_ptr<snippet_data> new_snippet( - new snippet_data(id, callout_base_id)); + boost::shared_ptr<snippet_data> new_snippet(new snippet_data(id)); new_snippet->next = snippet_stack; snippet_stack = new_snippet; snippet_stack->start_code = in_code; @@ -95,7 +91,6 @@ namespace quickbook std::string::const_iterator mark_begin, mark_end; std::string::const_iterator last_code_pos; bool in_code; - int callout_id; boost::shared_ptr<snippet_data> snippet_stack; std::vector<template_symbol>& storage; file_ptr source_file; @@ -240,8 +235,6 @@ namespace quickbook | escaped_comment [boost::bind(&actions_type::escaped_comment, &actions, _1, _2)] | ignore [boost::bind(&actions_type::append_code, &actions, _1, _2)] | pass_thru_comment [boost::bind(&actions_type::pass_thru, &actions, _1, _2)] - | line_callout [boost::bind(&actions_type::callout, &actions, _1, _2)] - | inline_callout [boost::bind(&actions_type::callout, &actions, _1, _2)] | cl::anychar_p ; @@ -287,23 +280,6 @@ namespace quickbook "/*[*/" ; - inline_callout - = cl::confix_p( - "/*<" >> *cl::space_p, - (*cl::anychar_p) [boost::bind(&actions_type::mark, &actions, _1, _2)], - ">*/" - ) - ; - - line_callout - = cl::confix_p( - "/*<<" >> *cl::space_p, - (*cl::anychar_p) [boost::bind(&actions_type::mark, &actions, _1, _2)], - ">>*/" - ) - >> *cl::space_p - ; - ignore = cl::confix_p( *cl::blank_p >> "//<-", @@ -354,7 +330,7 @@ namespace quickbook cl::rule<Scanner> start_, identifier, code_elements, start_snippet, end_snippet, - escaped_comment, pass_thru_comment, inline_callout, line_callout, ignore; + escaped_comment, pass_thru_comment, ignore; cl::rule<Scanner> const& start() const { return start_; } @@ -447,27 +423,6 @@ namespace quickbook content.add(mark_begin, mark_end); } - void code_snippet_actions::callout(string_iterator first, string_iterator last) - { - if(!snippet_stack) return; - append_code(first, last); - - if (!in_code) - { - content.add("\n\n", first); - content.add(source_type, first); - content.add("```\n", first); - in_code = true; - } - - content.add( - "``[[callout" + boost::lexical_cast<std::string>(callout_id) + "]]``", - first); - - snippet_stack->callouts.insert(qbk_value(source_file, mark_begin, mark_end, template_tags::block)); - ++callout_id; - } - void code_snippet_actions::escaped_comment(string_iterator first, string_iterator last) { append_code(first, last); @@ -529,7 +484,7 @@ namespace quickbook if (qbk_version_n >= 106u) { detail::outerr(source_file->path) << "Unclosed snippet '" - << detail::utf8(snippet_stack->id) + << snippet_stack->id << "'" << std::endl; ++error_count; @@ -537,7 +492,7 @@ namespace quickbook else { detail::outwarn(source_file->path) << "Unclosed snippet '" - << detail::utf8(snippet_stack->id) + << snippet_stack->id << "'" << std::endl; } @@ -549,7 +504,7 @@ namespace quickbook void code_snippet_actions::start_snippet_impl(std::string const& id, string_iterator position) { - push_snippet_data(id, callout_id, position); + push_snippet_data(id, position); } void code_snippet_actions::end_snippet_impl(string_iterator position) @@ -557,7 +512,6 @@ namespace quickbook assert(snippet_stack); boost::shared_ptr<snippet_data> snippet = pop_snippet_data(); - value callouts = snippet->callouts.release(); mapped_file_builder f; f.start(source_file); @@ -572,29 +526,11 @@ namespace quickbook } std::vector<std::string> params; - int i = 0; - for(value::iterator it = callouts.begin(); it != callouts.end(); ++it) - { - params.push_back("[callout" + boost::lexical_cast<std::string>(snippet->callout_base_id + i) + "]"); - ++i; - } file_ptr body = f.release(); - value_builder builder; - builder.set_tag(template_tags::snippet); - builder.insert(qbk_value(body, body->source.begin(), body->source.end(), - template_tags::block)); - builder.insert(callouts); - - template_symbol symbol(snippet->id, params, builder.release()); - storage.push_back(symbol); - - // Copy the snippet's callouts to its parent - - if(snippet_stack) - { - snippet_stack->callouts.extend(callouts); - } + storage.push_back(template_symbol(snippet->id, params, + qbk_value(body, body->source.begin(), body->source.end(), + template_tags::snippet))); } } diff --git a/tools/quickbook/src/doc_info_actions.cpp b/tools/quickbook/src/doc_info_actions.cpp index e23466fd3d..42ee961832 100644 --- a/tools/quickbook/src/doc_info_actions.cpp +++ b/tools/quickbook/src/doc_info_actions.cpp @@ -12,12 +12,13 @@ #include <boost/bind.hpp> #include <boost/algorithm/string/join.hpp> #include <boost/foreach.hpp> -#include <boost/filesystem/v3/operations.hpp> +#include <boost/filesystem/operations.hpp> #include "quickbook.hpp" #include "utils.hpp" #include "files.hpp" #include "input_path.hpp" -#include "actions_class.hpp" +#include "state.hpp" +#include "actions.hpp" #include "doc_info_tags.hpp" #include "id_manager.hpp" @@ -75,7 +76,7 @@ namespace quickbook } // Any number of attributes, so stuff them into a vector. - std::vector<value> consume_multiple_lists(value_consumer& c, value::tag_type tag) + std::vector<value> consume_multiple_values(value_consumer& c, value::tag_type tag) { std::vector<value> values; @@ -86,7 +87,7 @@ namespace quickbook return values; } - unsigned get_version(quickbook::actions& actions, bool using_docinfo, + unsigned get_version(quickbook::state& state, bool using_docinfo, value version) { unsigned result = 0; @@ -103,15 +104,15 @@ namespace quickbook result = ((unsigned) major_verison * 100) + (unsigned) minor_verison; - if(result < 100 || result > 106) + if(result < 100 || result > 107) { - detail::outerr(actions.current_file->path) + detail::outerr(state.current_file->path) << "Unknown version: " << major_verison << "." << minor_verison << std::endl; - ++actions.error_count; + ++state.error_count; } } } @@ -119,7 +120,7 @@ namespace quickbook return result; } - std::string pre(quickbook::actions& actions, parse_iterator pos, + std::string pre(quickbook::state& state, parse_iterator pos, value include_doc_id, bool nested_file) { // The doc_info in the file has been parsed. Here's what we'll do @@ -128,7 +129,7 @@ namespace quickbook // If there isn't a doc info block, then values will be empty, so most // of the following code won't actually do anything. - value_consumer values = actions.values.release(); + value_consumer values = state.values.release(); // Skip over invalid attributes @@ -148,15 +149,15 @@ namespace quickbook { if (!nested_file) { - detail::outerr(actions.current_file, pos.base()) + detail::outerr(state.current_file, pos.base()) << "No doc_info block." << std::endl; - ++actions.error_count; + ++state.error_count; // Create a fake document info block in order to continue. doc_type = "article"; - doc_title = qbk_value(actions.current_file, + doc_title = qbk_value(state.current_file, pos.base(), pos.base(), doc_info_tags::type); use_doc_info = true; @@ -165,31 +166,33 @@ namespace quickbook std::vector<std::string> duplicates; + std::vector<value> escaped_attributes = consume_multiple_values(values, doc_info_tags::escaped_attribute); + value qbk_version = consume_list(values, doc_attributes::qbk_version, &duplicates); value compatibility_mode = consume_list(values, doc_attributes::compatibility_mode, &duplicates); - consume_multiple_lists(values, doc_attributes::source_mode); + consume_multiple_values(values, doc_attributes::source_mode); value id = consume_value_in_list(values, doc_info_attributes::id, &duplicates); value dirname = consume_value_in_list(values, doc_info_attributes::dirname, &duplicates); value last_revision = consume_value_in_list(values, doc_info_attributes::last_revision, &duplicates); value purpose = consume_value_in_list(values, doc_info_attributes::purpose, &duplicates); - std::vector<value> categories = consume_multiple_lists(values, doc_info_attributes::category); + std::vector<value> categories = consume_multiple_values(values, doc_info_attributes::category); value lang = consume_value_in_list(values, doc_info_attributes::lang, &duplicates); value version = consume_value_in_list(values, doc_info_attributes::version, &duplicates); - std::vector<value> authors = consume_multiple_lists(values, doc_info_attributes::authors); - std::vector<value> copyrights = consume_multiple_lists(values, doc_info_attributes::copyright); + std::vector<value> authors = consume_multiple_values(values, doc_info_attributes::authors); + std::vector<value> copyrights = consume_multiple_values(values, doc_info_attributes::copyright); value license = consume_value_in_list(values, doc_info_attributes::license, &duplicates); - std::vector<value> biblioids = consume_multiple_lists(values, doc_info_attributes::biblioid); + std::vector<value> biblioids = consume_multiple_values(values, doc_info_attributes::biblioid); value xmlbase = consume_value_in_list(values, doc_info_attributes::xmlbase, &duplicates); values.finish(); if(!duplicates.empty()) { - detail::outwarn(actions.current_file->path) + detail::outwarn(state.current_file->path) << (duplicates.size() > 1 ? "Duplicate attributes" : "Duplicate attribute") - << ":" << detail::utf8(boost::algorithm::join(duplicates, ", ")) + << ":" << boost::algorithm::join(duplicates, ", ") << "\n" ; } @@ -203,12 +206,13 @@ namespace quickbook // Quickbook version - unsigned new_version = get_version(actions, use_doc_info, qbk_version); + unsigned new_version = get_version(state, use_doc_info, qbk_version); - if (new_version != qbk_version_n && new_version == 106) + if (new_version != qbk_version_n && new_version >= 106) { - detail::outwarn(actions.current_file->path) - << "Quickbook 1.6 is still under development and is " + detail::outwarn(state.current_file->path) + << "Quickbook " << (new_version / 100) << "." << (new_version % 100) + << " is still under development and is " "likely to change in the future." << std::endl; } @@ -218,34 +222,34 @@ namespace quickbook else if (use_doc_info) { // hard code quickbook version to v1.1 qbk_version_n = 101; - detail::outwarn(actions.current_file, pos.base()) + detail::outwarn(state.current_file, pos.base()) << "Quickbook version undefined. " "Version 1.1 is assumed" << std::endl; } - actions.current_file->version(qbk_version_n); + state.current_file->version(qbk_version_n); // Compatibility Version unsigned compatibility_version = - get_version(actions, use_doc_info, compatibility_mode); + get_version(state, use_doc_info, compatibility_mode); if (!compatibility_version) { compatibility_version = use_doc_info ? - qbk_version_n : actions.ids.compatibility_version(); + qbk_version_n : state.ids.compatibility_version(); } // Start file, finish here if not generating document info. if (!use_doc_info) { - actions.ids.start_file(compatibility_version, include_doc_id_, id_, + state.ids.start_file(compatibility_version, include_doc_id_, id_, doc_title); return ""; } std::string id_placeholder = - actions.ids.start_file_with_docinfo( + state.ids.start_file_with_docinfo( compatibility_version, include_doc_id_, id_, doc_title); // Make sure we really did have a document info block. @@ -258,22 +262,22 @@ namespace quickbook if (!xmlbase.empty()) { - xinclude_path x = calculate_xinclude_path(xmlbase, actions); + xinclude_path x = calculate_xinclude_path(xmlbase, state); if (!fs::is_directory(x.path)) { detail::outerr(xmlbase.get_file(), xmlbase.get_position()) << "xmlbase \"" - << detail::utf8(xmlbase.get_quickbook()) + << xmlbase.get_quickbook() << "\" isn't a directory." << std::endl; - ++actions.error_count; + ++state.error_count; } else { xmlbase_value = x.uri; - actions.xinclude_base = x.path; + state.xinclude_base = x.path; } } @@ -294,11 +298,11 @@ namespace quickbook if(!invalid_attributes.empty()) { - detail::outwarn(actions.current_file->path) + detail::outwarn(state.current_file->path) << (invalid_attributes.size() > 1 ? "Invalid attributes" : "Invalid attribute") - << " for '" << detail::utf8(doc_type) << " document info': " - << detail::utf8(boost::algorithm::join(invalid_attributes, ", ")) + << " for '" << doc_type << " document info': " + << boost::algorithm::join(invalid_attributes, ", ") << "\n" ; } @@ -308,7 +312,7 @@ namespace quickbook if (!nested_file) { - actions.out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + state.out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" << "<!DOCTYPE " << doc_type << " PUBLIC \"-//Boost//DTD BoostBook XML V1.0//EN\"\n" @@ -316,51 +320,51 @@ namespace quickbook ; } - actions.out << '<' << doc_type << "\n" + state.out << '<' << doc_type << "\n" << " id=\"" << id_placeholder << "\"\n"; if(!lang.empty()) { - actions.out << " lang=\"" + state.out << " lang=\"" << doc_info_output(lang, 106) << "\"\n"; } if(doc_type == "library" && !doc_title.empty()) { - actions.out << " name=\"" << doc_info_output(doc_title, 106) << "\"\n"; + state.out << " name=\"" << doc_info_output(doc_title, 106) << "\"\n"; } // Set defaults for dirname + last_revision if (!dirname.empty() || doc_type == "library") { - actions.out << " dirname=\""; + state.out << " dirname=\""; if (!dirname.empty()) { - actions.out << doc_info_output(dirname, 106); + state.out << doc_info_output(dirname, 106); } else if (!id_.empty()) { - actions.out << id_; + state.out << id_; } else if (!include_doc_id_.empty()) { - actions.out << include_doc_id_; + state.out << include_doc_id_; } else if (!doc_title.empty()) { - actions.out << detail::make_identifier(doc_title.get_quickbook()); + state.out << detail::make_identifier(doc_title.get_quickbook()); } else { - actions.out << "library"; + state.out << "library"; } - actions.out << "\"\n"; + state.out << "\"\n"; } - actions.out << " last-revision=\""; + state.out << " last-revision=\""; if (!last_revision.empty()) { - actions.out << doc_info_output(last_revision, 106); + state.out << doc_info_output(last_revision, 106); } else { @@ -375,19 +379,19 @@ namespace quickbook current_gm_time ); - actions.out << strdate; + state.out << strdate; } - actions.out << "\" \n"; + state.out << "\" \n"; if (!xmlbase.empty()) { - actions.out << " xml:base=\"" + state.out << " xml:base=\"" << xmlbase_value << "\"\n"; } - actions.out << " xmlns:xi=\"http://www.w3.org/2001/XInclude\">\n"; + state.out << " xmlns:xi=\"http://www.w3.org/2001/XInclude\">\n"; std::ostringstream tmp; @@ -429,9 +433,9 @@ namespace quickbook year_start; if (year_end < year_start) { - ++actions.error_count; + ++state.error_count; - detail::outerr(actions.current_file, copyright.begin()->get_position()) + detail::outerr(state.current_file, copyright.begin()->get_position()) << "Invalid year range: " << year_start << "-" @@ -456,7 +460,7 @@ namespace quickbook if (!license.empty()) { tmp << " <legalnotice id=\"" - << actions.ids.add_id("legal", id_category::generated) + << state.ids.add_id("legal", id_category::generated) << "\">\n" << " <para>\n" << " " << doc_info_output(license, 103) << "\n" @@ -502,14 +506,22 @@ namespace quickbook biblioid.finish(); } + BOOST_FOREACH(value escaped, escaped_attributes) + { + tmp << "<!--quickbook-escape-prefix-->" + << escaped.get_quickbook() + << "<!--quickbook-escape-postfix-->" + ; + } + if(doc_type != "library") { - write_document_title(actions.out, doc_title, version); + write_document_title(state.out, doc_title, version); } std::string docinfo = tmp.str(); if(!docinfo.empty()) { - actions.out << " <" << doc_type << "info>\n" + state.out << " <" << doc_type << "info>\n" << docinfo << " </" << doc_type << "info>\n" << "\n" @@ -517,31 +529,31 @@ namespace quickbook } if(doc_type == "library") { - write_document_title(actions.out, doc_title, version); + write_document_title(state.out, doc_title, version); } return doc_type; } - void post(quickbook::actions& actions, std::string const& doc_type) + void post(quickbook::state& state, std::string const& doc_type) { // We've finished generating our output. Here's what we'll do // *after* everything else. // Close any open sections. - if (!doc_type.empty() && actions.ids.section_level() > 1) { - detail::outwarn(actions.current_file->path) + if (!doc_type.empty() && state.ids.section_level() > 1) { + detail::outwarn(state.current_file->path) << "Missing [endsect] detected at end of file." << std::endl; - while(actions.ids.section_level() > 1) { - actions.out << "</section>"; - actions.ids.end_section(); + while(state.ids.section_level() > 1) { + state.out << "</section>"; + state.ids.end_section(); } } - actions.ids.end_file(); - if (!doc_type.empty()) actions.out << "\n</" << doc_type << ">\n\n"; + state.ids.end_file(); + if (!doc_type.empty()) state.out << "\n</" << doc_type << ">\n\n"; } static void write_document_title(collector& out, value const& title, value const& version) diff --git a/tools/quickbook/src/doc_info_grammar.cpp b/tools/quickbook/src/doc_info_grammar.cpp index 26418eec48..862d0ce57a 100644 --- a/tools/quickbook/src/doc_info_grammar.cpp +++ b/tools/quickbook/src/doc_info_grammar.cpp @@ -19,7 +19,8 @@ #include <boost/spirit/include/phoenix1_primitives.hpp> #include <boost/spirit/include/phoenix1_operators.hpp> #include "grammar_impl.hpp" -#include "actions_class.hpp" +#include "state.hpp" +#include "actions.hpp" #include "doc_info_tags.hpp" #include "phrase_tags.hpp" @@ -69,6 +70,7 @@ namespace quickbook cl::rule<scanner> doc_info_block, doc_attribute, doc_info_attribute, + doc_info_escaped_attributes, doc_title, doc_simple, doc_phrase, doc_fallback, doc_authors, doc_author, doc_copyright, doc_copyright_holder, @@ -113,6 +115,11 @@ namespace quickbook BOOST_FOREACH(value::tag_type t, doc_info_attributes::tags()) { local.doc_info_attributes.add(doc_info_attributes::name(t), t); } + + // Actions + error_action error(state); + plain_char_action plain_char(state.phrase, state); + scoped_parser<to_value_scoped_action> to_value(state); doc_info_details = space [ph::var(local.source_mode_unset) = true] @@ -126,9 +133,9 @@ namespace quickbook '[' >> space >> (local.doc_types >> cl::eps_p) - [actions.values.entry(ph::arg1, ph::arg2, doc_info_tags::type)] + [state.values.entry(ph::arg1, ph::arg2, doc_info_tags::type)] >> hard_space - >> actions.to_value(doc_info_tags::title) + >> to_value(doc_info_tags::title) [ *( ~cl::eps_p(blank >> (cl::ch_p('[') | ']' | cl::eol_p)) >> local.char_ ) @@ -137,15 +144,18 @@ namespace quickbook >> blank ] >> space - >> !(qbk_since(106u) >> cl::eps_p(ph::var(local.source_mode_unset)) - [cl::assign_a(actions.source_mode, "c++")] + >> !(qbk_ver(106u) >> cl::eps_p(ph::var(local.source_mode_unset)) + [cl::assign_a(state.source_mode, "c++")] ) - >> (*( local.doc_info_attribute - >> space - )) [actions.values.sort()] + >> ( *( ( local.doc_info_attribute + | local.doc_info_escaped_attributes + ) + >> space + ) + ) [state.values.sort()] >> ( ']' >> (+eol | cl::end_p) - | cl::eps_p [actions.error] + | cl::eps_p [error] ) ; @@ -154,8 +164,8 @@ namespace quickbook >> space >> local.doc_attributes [local.assign_attribute] >> hard_space - >> actions.values.list(ph::var(local.attribute_tag)) - [ cl::eps_p [actions.values.entry(ph::arg1, ph::arg2, doc_info_tags::before_docinfo)] + >> state.values.list(ph::var(local.attribute_tag)) + [ cl::eps_p [state.values.entry(ph::arg1, ph::arg2, doc_info_tags::before_docinfo)] >> local.attribute_rule ] >> space @@ -169,33 +179,41 @@ namespace quickbook [local.assign_attribute] | (+(cl::alnum_p | '_' | '-')) [local.fallback_attribute] - [actions.error("Unrecognized document attribute: '%s'.")] + [error("Unrecognized document attribute: '%s'.")] ) >> hard_space - >> actions.values.list(ph::var(local.attribute_tag)) + >> state.values.list(ph::var(local.attribute_tag)) [local.attribute_rule] >> space >> ']' ; - local.doc_fallback = actions.to_value() [ + local.doc_fallback = to_value() [ *(~cl::eps_p(']') >> local.char_) ]; + local.doc_info_escaped_attributes = + ("'''" >> !eol) + >> (*(cl::anychar_p - "'''")) [state.values.entry(ph::arg1, ph::arg2, doc_info_tags::escaped_attribute)] + >> ( cl::str_p("'''") + | cl::eps_p [error("Unclosed boostbook escape.")] + ) + ; + // Document Attributes local.quickbook_version = - cl::uint_p [actions.values.entry(ph::arg1)] + cl::uint_p [state.values.entry(ph::arg1)] >> '.' - >> uint2_t() [actions.values.entry(ph::arg1)] + >> uint2_t() [state.values.entry(ph::arg1)] ; local.attribute_rules[doc_attributes::qbk_version] = &local.quickbook_version; local.doc_compatibility_mode = - cl::uint_p [actions.values.entry(ph::arg1)] + cl::uint_p [state.values.entry(ph::arg1)] >> '.' - >> uint2_t() [actions.values.entry(ph::arg1)] + >> uint2_t() [state.values.entry(ph::arg1)] ; local.attribute_rules[doc_attributes::compatibility_mode] = &local.doc_compatibility_mode; @@ -205,7 +223,7 @@ namespace quickbook cl::str_p("c++") | "python" | "teletype" - ) [cl::assign_a(actions.source_mode)] + ) [cl::assign_a(state.source_mode)] [ph::var(local.source_mode_unset) = false] ; @@ -213,7 +231,7 @@ namespace quickbook // Document Info Attributes - local.doc_simple = actions.to_value() [*(~cl::eps_p(']') >> local.char_)]; + local.doc_simple = to_value() [*(~cl::eps_p(']') >> local.char_)]; local.attribute_rules[doc_info_attributes::version] = &local.doc_simple; local.attribute_rules[doc_info_attributes::id] = &local.doc_simple; local.attribute_rules[doc_info_attributes::dirname] = &local.doc_simple; @@ -232,18 +250,18 @@ namespace quickbook local.doc_copyright = *( +( local.doc_copyright_year - [actions.values.entry(ph::arg1, doc_info_tags::copyright_year)] + [state.values.entry(ph::arg1, doc_info_tags::copyright_year)] >> space >> !( '-' >> space >> local.doc_copyright_year - [actions.values.entry(ph::arg1, doc_info_tags::copyright_year_end)] + [state.values.entry(ph::arg1, doc_info_tags::copyright_year_end)] >> space ) >> !cl::ch_p(',') >> space ) - >> actions.to_value(doc_info_tags::copyright_name) [ local.doc_copyright_holder ] + >> to_value(doc_info_tags::copyright_name) [ local.doc_copyright_holder ] >> !cl::ch_p(',') >> space ) @@ -251,17 +269,17 @@ namespace quickbook local.attribute_rules[doc_info_attributes::copyright] = &local.doc_copyright; - local.doc_phrase = actions.to_value() [ nested_phrase ]; + local.doc_phrase = to_value() [ nested_phrase ]; local.attribute_rules[doc_info_attributes::purpose] = &local.doc_phrase; local.attribute_rules[doc_info_attributes::license] = &local.doc_phrase; local.doc_author = '[' >> space - >> actions.to_value(doc_info_tags::author_surname) + >> to_value(doc_info_tags::author_surname) [*(~cl::eps_p(',') >> local.char_)] >> ',' >> space - >> actions.to_value(doc_info_tags::author_first) + >> to_value(doc_info_tags::author_first) [*(~cl::eps_p(']') >> local.char_)] >> ']' ; @@ -276,14 +294,14 @@ namespace quickbook local.attribute_rules[doc_info_attributes::authors] = &local.doc_authors; local.doc_biblioid = - (+cl::alnum_p) [actions.values.entry(ph::arg1, ph::arg2, doc_info_tags::biblioid_class)] + (+cl::alnum_p) [state.values.entry(ph::arg1, ph::arg2, doc_info_tags::biblioid_class)] >> hard_space - >> actions.to_value(doc_info_tags::biblioid_value) + >> to_value(doc_info_tags::biblioid_value) [+(~cl::eps_p(']') >> local.char_)] ; local.attribute_rules[doc_info_attributes::biblioid] = &local.doc_biblioid; - local.char_ = escape | cl::anychar_p[actions.plain_char]; + local.char_ = escape | cl::anychar_p[plain_char]; } } diff --git a/tools/quickbook/src/doc_info_tags.hpp b/tools/quickbook/src/doc_info_tags.hpp index 4caea3317c..ccc69186cb 100644 --- a/tools/quickbook/src/doc_info_tags.hpp +++ b/tools/quickbook/src/doc_info_tags.hpp @@ -21,6 +21,7 @@ namespace quickbook (copyright_year)(copyright_year_end)(copyright_name) (license) (biblioid_class)(biblioid_value) + (escaped_attribute) ) QUICKBOOK_VALUE_NAMED_TAGS(doc_attributes, 0x440, diff --git a/tools/quickbook/src/files.cpp b/tools/quickbook/src/files.cpp index ce63c84eb2..f85b611623 100644 --- a/tools/quickbook/src/files.cpp +++ b/tools/quickbook/src/files.cpp @@ -8,10 +8,11 @@ http://www.boost.org/LICENSE_1_0.txt) =============================================================================*/ #include "files.hpp" -#include <boost/filesystem/v3/fstream.hpp> +#include <boost/filesystem/fstream.hpp> #include <boost/unordered_map.hpp> #include <boost/range/algorithm/upper_bound.hpp> #include <boost/range/algorithm/transform.hpp> +#include <boost/foreach.hpp> #include <fstream> #include <iterator> @@ -285,8 +286,9 @@ namespace quickbook struct mapped_file : file { mapped_file(file_ptr original) : - file(original->path, std::string(), original->version()), - original(original), mapped_sections() {} + file(*original, std::string()), + original(original), mapped_sections() + {} file_ptr original; std::vector<mapped_file_section> mapped_sections; diff --git a/tools/quickbook/src/files.hpp b/tools/quickbook/src/files.hpp index 1b0ef282b0..4f217e70cd 100644 --- a/tools/quickbook/src/files.hpp +++ b/tools/quickbook/src/files.hpp @@ -12,11 +12,10 @@ #define BOOST_QUICKBOOK_FILES_HPP #include <string> -#include <boost/filesystem/v3/path.hpp> +#include <boost/filesystem/path.hpp> #include <boost/intrusive_ptr.hpp> #include <stdexcept> #include <cassert> -#include "intrusive_base.hpp" namespace quickbook { @@ -34,20 +33,35 @@ namespace quickbook { int column; }; - struct file : intrusive_base<file> + struct file { + private: + // Non copyable + file& operator=(file const&); + file(file const&); + public: fs::path const path; std::string source; + bool is_code_snippets; private: unsigned qbk_version; + unsigned ref_count; public: file(fs::path const& path, std::string const& source, unsigned qbk_version) : - path(path), source(source), qbk_version(qbk_version) + path(path), source(source), is_code_snippets(false), + qbk_version(qbk_version), ref_count(0) {} - virtual ~file() {} + file(file const& f, std::string const& source) : + path(f.path), source(source), is_code_snippets(f.is_code_snippets), + qbk_version(f.qbk_version), ref_count(0) + {} + + virtual ~file() { + assert(!ref_count); + } unsigned version() const { assert(qbk_version); @@ -63,6 +77,11 @@ namespace quickbook { } virtual file_position position_of(std::string::const_iterator) const; + + friend void intrusive_ptr_add_ref(file* ptr) { ++ptr->ref_count; } + + friend void intrusive_ptr_release(file* ptr) + { if(--ptr->ref_count == 0) delete ptr; } }; // If version isn't supplied then it must be set later. diff --git a/tools/quickbook/src/fwd.hpp b/tools/quickbook/src/fwd.hpp index 7995c14097..7cccde8735 100644 --- a/tools/quickbook/src/fwd.hpp +++ b/tools/quickbook/src/fwd.hpp @@ -16,12 +16,13 @@ namespace quickbook { - struct actions; + struct state; struct quickbook_grammar; struct collector; struct id_manager; struct section_info; struct file; + struct template_symbol; typedef boost::intrusive_ptr<file> file_ptr; typedef std::string::const_iterator string_iterator; diff --git a/tools/quickbook/src/grammar.cpp b/tools/quickbook/src/grammar.cpp index a0e2e57887..8f244f18ac 100644 --- a/tools/quickbook/src/grammar.cpp +++ b/tools/quickbook/src/grammar.cpp @@ -13,8 +13,8 @@ namespace quickbook { - quickbook_grammar::quickbook_grammar(quickbook::actions& a) - : impl_(new impl(a)) + quickbook_grammar::quickbook_grammar(quickbook::state& s) + : impl_(new impl(s)) , command_line_macro(impl_->command_line, "command_line_macro") , inline_phrase(impl_->inline_phrase, "inline_phrase") , phrase(impl_->phrase_start, "phrase") @@ -27,8 +27,8 @@ namespace quickbook { } - quickbook_grammar::impl::impl(quickbook::actions& a) - : actions(a) + quickbook_grammar::impl::impl(quickbook::state& s) + : state(s) , cleanup_() { init_main(); diff --git a/tools/quickbook/src/grammar.hpp b/tools/quickbook/src/grammar.hpp index 73aae4a26c..54aaf2b3ea 100644 --- a/tools/quickbook/src/grammar.hpp +++ b/tools/quickbook/src/grammar.hpp @@ -62,7 +62,7 @@ namespace quickbook grammar block; grammar doc_info; - quickbook_grammar(quickbook::actions&); + quickbook_grammar(quickbook::state&); ~quickbook_grammar(); }; } diff --git a/tools/quickbook/src/grammar_impl.hpp b/tools/quickbook/src/grammar_impl.hpp index c968111b8c..090b399048 100644 --- a/tools/quickbook/src/grammar_impl.hpp +++ b/tools/quickbook/src/grammar_impl.hpp @@ -38,6 +38,7 @@ namespace quickbook in_block = phrase | maybe_block | nested_block | conditional_or_block | block, only_nested_block = nested_block, only_block = nested_block | conditional_or_block | block, + only_list_block = nested_block | conditional_or_block, only_contextual_block = maybe_block | nested_block | conditional_or_block | block }; @@ -59,7 +60,7 @@ namespace quickbook struct quickbook_grammar::impl { - quickbook::actions& actions; + quickbook::state& state; cleanup cleanup_; // Main Grammar @@ -73,6 +74,7 @@ namespace quickbook cl::rule<scanner> inside_preformatted; cl::rule<scanner> inside_paragraph; cl::rule<scanner> command_line; + cl::rule<scanner> attribute_value_1_7; cl::rule<scanner> escape; cl::rule<scanner> raw_escape; @@ -92,7 +94,7 @@ namespace quickbook // Doc Info cl::rule<scanner> doc_info_details; - impl(quickbook::actions&); + impl(quickbook::state&); private: diff --git a/tools/quickbook/src/id_manager.cpp b/tools/quickbook/src/id_manager.cpp index 32e537df71..3b2f601a11 100644 --- a/tools/quickbook/src/id_manager.cpp +++ b/tools/quickbook/src/id_manager.cpp @@ -9,8 +9,7 @@ #include "id_manager.hpp" #include "utils.hpp" #include "string_ref.hpp" -#include "intrusive_base.hpp" -#include <boost/intrusive_ptr.hpp> +#include <boost/make_shared.hpp> #include <boost/unordered_map.hpp> #include <boost/lexical_cast.hpp> #include <boost/range/algorithm.hpp> @@ -113,7 +112,7 @@ namespace quickbook struct id_state { - boost::intrusive_ptr<file_info> current_file; + boost::shared_ptr<file_info> current_file; std::deque<id_placeholder> placeholders; // Placeholder methods @@ -149,25 +148,25 @@ private: id_placeholder* add_id_to_section( std::string const& id, id_category category, - boost::intrusive_ptr<section_info> const& section); + boost::shared_ptr<section_info> const& section); id_placeholder* create_new_section( std::string const& id, id_category category); void switch_section(id_placeholder*); - void reswitch_sections(boost::intrusive_ptr<section_info> const&, - boost::intrusive_ptr<section_info> const&); + void reswitch_sections(boost::shared_ptr<section_info> const&, + boost::shared_ptr<section_info> const&); void restore_section(); }; - struct file_info : intrusive_base<file_info> + struct file_info { - boost::intrusive_ptr<file_info> parent; - boost::intrusive_ptr<doc_info> document; + boost::shared_ptr<file_info> parent; + boost::shared_ptr<doc_info> document; bool document_root; // !parent || document != parent->document unsigned compatibility_version; - boost::intrusive_ptr<section_info> switched_section; + boost::shared_ptr<section_info> switched_section; id_placeholder* original_placeholder; // The 1.1-1.5 document id would actually change per file due to @@ -175,15 +174,15 @@ private: // document title instead of the id. std::string doc_id_1_1; - file_info(boost::intrusive_ptr<file_info> const& parent, + file_info(boost::shared_ptr<file_info> const& parent, unsigned compatibility_version) : parent(parent), document(parent->document), document_root(false), compatibility_version(compatibility_version), switched_section(), original_placeholder() {} - file_info(boost::intrusive_ptr<file_info> const& parent, - boost::intrusive_ptr<doc_info> const& document, + file_info(boost::shared_ptr<file_info> const& parent, + boost::shared_ptr<doc_info> const& document, unsigned compatibility_version) : parent(parent), document(document), document_root(true), compatibility_version(compatibility_version), @@ -191,9 +190,9 @@ private: {} }; - struct doc_info : intrusive_base<doc_info> + struct doc_info { - boost::intrusive_ptr<section_info> current_section; + boost::shared_ptr<section_info> current_section; std::string last_title_1_1; std::string section_id_1_1; @@ -202,15 +201,15 @@ private: {} }; - struct section_info : intrusive_base<section_info> + struct section_info { - boost::intrusive_ptr<section_info> parent; + boost::shared_ptr<section_info> parent; unsigned compatibility_version; unsigned level; std::string id_1_1; id_placeholder* placeholder_1_6; - section_info(boost::intrusive_ptr<section_info> const& parent, + section_info(boost::shared_ptr<section_info> const& parent, unsigned compatibility_version, std::string const& id) : parent(parent), compatibility_version(compatibility_version), level(parent ? parent->level + 1 : 1), @@ -394,11 +393,11 @@ private: } void id_state::reswitch_sections( - boost::intrusive_ptr<section_info> const& popped_section, - boost::intrusive_ptr<section_info> const& parent_section) + boost::shared_ptr<section_info> const& popped_section, + boost::shared_ptr<section_info> const& parent_section) { - boost::intrusive_ptr<file_info> file = current_file; - boost::intrusive_ptr<file_info> first_switched_file; + boost::shared_ptr<file_info> file = current_file; + boost::shared_ptr<file_info> first_switched_file; for (;;) { if (file->switched_section == popped_section) @@ -436,15 +435,16 @@ private: { // Create new file - boost::intrusive_ptr<file_info> parent = current_file; + boost::shared_ptr<file_info> parent = current_file; if (document_root) { - current_file = new file_info(parent, new doc_info(), + current_file = boost::make_shared<file_info>(parent, + boost::make_shared<doc_info>(), compatibility_version); } else { current_file = - new file_info(parent, compatibility_version); + boost::make_shared<file_info>(parent, compatibility_version); } // Choose specified id to use. Prefer 'include_doc_id' (the id @@ -505,7 +505,7 @@ private: if (compatibility_version >= 106u && !initial_doc_id.empty()) { switch_section(add_id_to_section(initial_doc_id, id_category::explicit_section_id, - boost::intrusive_ptr<section_info>())); + boost::shared_ptr<section_info>())); } return 0; @@ -529,7 +529,7 @@ private: id_placeholder* id_state::add_id_to_section( std::string const& id, id_category category, - boost::intrusive_ptr<section_info> const& section) + boost::shared_ptr<section_info> const& section) { std::string id_part = id; @@ -583,11 +583,12 @@ private: std::string const& id, id_category category) { - boost::intrusive_ptr<section_info> parent = + boost::shared_ptr<section_info> parent = current_file->document->current_section; - boost::intrusive_ptr<section_info> new_section = - new section_info(parent, current_file->compatibility_version, id); + boost::shared_ptr<section_info> new_section = + boost::make_shared<section_info>(parent, + current_file->compatibility_version, id); id_placeholder* p; @@ -630,7 +631,7 @@ private: void id_state::end_section() { - boost::intrusive_ptr<section_info> popped_section = + boost::shared_ptr<section_info> popped_section = current_file->document->current_section; current_file->document->current_section = popped_section->parent; @@ -810,7 +811,7 @@ private: // Data used for generating placeholders that have duplicates. // - struct id_generation_data : intrusive_base<id_generation_data> + struct id_generation_data { id_generation_data(std::string const& src_id) : child_start(src_id.rfind('.') + 1), @@ -865,7 +866,7 @@ private: id_category category; // The highest priority category of the // placeholders that want to use this id. bool used; // Whether this id has been used. - boost::intrusive_ptr<id_generation_data> generation_data; + boost::shared_ptr<id_generation_data> generation_data; // If a duplicates are found, this is // created to generate new ids. // @@ -1036,7 +1037,8 @@ private: if (!p.data->generation_data) { - p.data->generation_data.reset(new id_generation_data(p.id)); + p.data->generation_data = + boost::make_shared<id_generation_data>(p.id); register_generation_data(p, ids); } diff --git a/tools/quickbook/src/input_path.cpp b/tools/quickbook/src/input_path.cpp index 4523ac6f22..9b6a87784d 100644 --- a/tools/quickbook/src/input_path.cpp +++ b/tools/quickbook/src/input_path.cpp @@ -122,7 +122,7 @@ namespace detail { return fs::path(static_cast<wchar_t*>(ptr)); } - stream_string path_to_stream(fs::path const& path) + ostream::string path_to_stream(fs::path const& path) { cygwin_conv_path_t flags = CCP_WIN_W_TO_POSIX | CCP_RELATIVE; @@ -145,12 +145,12 @@ namespace detail { } #if QUICKBOOK_WIDE_PATHS && !QUICKBOOK_WIDE_STREAMS - stream_string path_to_stream(fs::path const& path) + ostream::string path_to_stream(fs::path const& path) { return path.string(); } #else - stream_string path_to_stream(fs::path const& path) + ostream::string path_to_stream(fs::path const& path) { return path.native(); } @@ -166,21 +166,23 @@ namespace detail { if (_isatty(_fileno(stderr))) _setmode(_fileno(stderr), _O_U16TEXT); } - void write_utf8(ostream& out, std::string const& x) + void write_utf8(ostream::base_ostream& out, std::string const& x) { out << from_utf8(x); } ostream& out() { - return std::wcout; + static ostream x(std::wcout); + return x; } namespace { inline ostream& error_stream() { - return std::wcerr; + static ostream x(std::wcerr); + return x; } } @@ -190,21 +192,23 @@ namespace detail { { } - void write_utf8(ostream& out, std::string const& x) + void write_utf8(ostream::base_ostream& out, std::string const& x) { out << x; } ostream& out() { - return std::cout; + static ostream x(std::cout); + return x; } namespace { inline ostream& error_stream() { - return std::clog; + static ostream x(std::clog); + return x; } } @@ -254,4 +258,61 @@ namespace detail { { return outwarn(f->path, f->position_of(pos).line); } + + ostream& ostream::operator<<(char c) { + assert(c > 0 && c <= 127); + base << c; + return *this; + } + + inline bool check_ascii(char const* x) { + for(;*x;++x) if(*x <= 0 || *x > 127) return false; + return true; + } + + ostream& ostream::operator<<(char const* x) { + assert(check_ascii(x)); + base << x; + return *this; + } + + ostream& ostream::operator<<(std::string const& x) { + write_utf8(base, x); + return *this; + } + + ostream& ostream::operator<<(int x) { + base << x; + return *this; + } + + ostream& ostream::operator<<(unsigned int x) { + base << x; + return *this; + } + + ostream& ostream::operator<<(long x) { + base << x; + return *this; + } + + ostream& ostream::operator<<(unsigned long x) { + base << x; + return *this; + } + + ostream& ostream::operator<<(fs::path const& x) { + base << path_to_stream(x); + return *this; + } + + ostream& ostream::operator<<(base_ostream& (*x)(base_ostream&)) { + base << x; + return *this; + } + + ostream& ostream::operator<<(base_ios& (*x)(base_ios&)) { + base << x; + return *this; + } }} diff --git a/tools/quickbook/src/input_path.hpp b/tools/quickbook/src/input_path.hpp index a23474d3e1..a9b55f6b2c 100644 --- a/tools/quickbook/src/input_path.hpp +++ b/tools/quickbook/src/input_path.hpp @@ -10,7 +10,7 @@ #define BOOST_QUICKBOOK_DETAIL_INPUT_PATH_HPP #include <boost/config.hpp> -#include <boost/filesystem/v3/path.hpp> +#include <boost/filesystem/path.hpp> #include <string> #include <stdexcept> #include <iostream> @@ -66,17 +66,47 @@ namespace quickbook typedef std::string input_string; #endif + // A light wrapper around C++'s streams that gets things right + // in the quickbook context. + // + // This is far from perfect but it fixes some issues. + struct ostream + { #if QUICKBOOK_WIDE_STREAMS - typedef std::wostream ostream; - typedef std::wstring stream_string; + typedef std::wostream base_ostream; + typedef std::wios base_ios; + typedef std::wstring string; #else - typedef std::ostream ostream; - typedef std::string stream_string; + typedef std::ostream base_ostream; + typedef std::ios base_ios; + typedef std::string string; #endif + base_ostream& base; + + explicit ostream(base_ostream& x) : base(x) {} + + // C strings should always be ascii. + ostream& operator<<(char); + ostream& operator<<(char const*); + + // std::string should be UTF-8 (what a mess!) + ostream& operator<<(std::string const&); + + // Other value types. + ostream& operator<<(int x); + ostream& operator<<(unsigned int x); + ostream& operator<<(long x); + ostream& operator<<(unsigned long x); + ostream& operator<<(fs::path const&); + + // Modifiers + ostream& operator<<(base_ostream& (*)(base_ostream&)); + ostream& operator<<(base_ios& (*)(base_ios&)); + }; + std::string input_to_utf8(input_string const&); fs::path input_to_path(input_string const&); - stream_string path_to_stream(fs::path const&); std::string path_to_generic(fs::path const&); fs::path generic_to_path(std::string const&); @@ -94,29 +124,6 @@ namespace quickbook ostream& outwarn(fs::path const& file, int line = -1); ostream& outerr(file_ptr const&, string_iterator); ostream& outwarn(file_ptr const&, string_iterator); - - struct utf8_proxy - { - std::string value; - - explicit utf8_proxy(std::string const& v) : value(v) {} - }; - - void write_utf8(ostream& out, std::string const&); - - inline ostream& operator<<(ostream& out, utf8_proxy const& p) { - write_utf8(out, p.value); - return out; - } - - inline utf8_proxy utf8(std::string const& value) { - return utf8_proxy(value); - } - - template <typename It> - inline utf8_proxy utf8(It begin, It end) { - return utf8_proxy(std::string(begin, end)); - } } } diff --git a/tools/quickbook/src/intrusive_base.hpp b/tools/quickbook/src/intrusive_base.hpp deleted file mode 100644 index 702c13d0b9..0000000000 --- a/tools/quickbook/src/intrusive_base.hpp +++ /dev/null @@ -1,36 +0,0 @@ -/*============================================================================= - Copyright (c) 2011 Daniel James - - Use, modification and distribution is subject to the Boost Software - License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) -=============================================================================*/ - -#if !defined(BOOST_QUICKBOOK_INTRUSIVE_BASE_HPP) -#define BOOST_QUICKBOOK_INTRUSIVE_BASE_HPP - -namespace quickbook -{ - // - // instructive_base - // - - template <typename T> - struct intrusive_base - { - intrusive_base() : ref_count_(0) {} - intrusive_base(intrusive_base const&) : ref_count_(0) {} - intrusive_base& operator=(intrusive_base const&) { return *this; } - ~intrusive_base() { assert(!ref_count_); } - - friend void intrusive_ptr_add_ref(T* ptr) - { ++ptr->ref_count_; } - - friend void intrusive_ptr_release(T* ptr) - { if(--ptr->ref_count_ == 0) delete ptr; } - private: - unsigned ref_count_; - }; -} - -#endif diff --git a/tools/quickbook/src/main_grammar.cpp b/tools/quickbook/src/main_grammar.cpp index 1ec2ff9ca8..74dbecea76 100644 --- a/tools/quickbook/src/main_grammar.cpp +++ b/tools/quickbook/src/main_grammar.cpp @@ -9,7 +9,8 @@ =============================================================================*/ #include "grammar_impl.hpp" -#include "actions_class.hpp" +#include "state.hpp" +#include "actions.hpp" #include "utils.hpp" #include "template_tags.hpp" #include "block_tags.hpp" @@ -27,8 +28,6 @@ #include <boost/range/algorithm/find_first_of.hpp> #include <boost/range/as_literal.hpp> -#include <iostream> - namespace quickbook { namespace cl = boost::spirit::classic; @@ -91,44 +90,6 @@ namespace quickbook string_iterator last); void clear_stack(); - struct process_element_impl : scoped_action_base { - process_element_impl(main_grammar_local& l) - : l(l) {} - - bool start() - { - if (!(l.info.type & l.element.context()) || - qbk_version_n < l.info.qbk_version) - return false; - - info_ = l.info; - - if (info_.type != element_info::phrase && - info_.type != element_info::maybe_block) - l.actions_.paragraph(); - - l.actions_.values.builder.reset(); - - return true; - } - - template <typename ResultT, typename ScannerT> - bool result(ResultT result, ScannerT const& scan) - { - if (result || info_.type & element_info::in_phrase) - return result; - - l.actions_.error(scan.first, scan.first); - return true; - } - - void success(parse_iterator, parse_iterator) { l.element_type = info_.type; } - void failure() { l.element_type = element_info::nothing; } - - main_grammar_local& l; - element_info info_; - }; - struct in_list_impl { main_grammar_local& l; @@ -216,53 +177,167 @@ namespace quickbook element_info info; element_info::type_enum element_type; - // actions - quickbook::actions& actions_; - member_action<main_grammar_local> check_indentation; - member_action<main_grammar_local> check_code_block; - member_action<main_grammar_local> start_blocks; - member_action<main_grammar_local> end_blocks; - in_list_impl in_list; - scoped_parser<process_element_impl> process_element; - scoped_parser<set_no_eols_scoped> scoped_no_eols; + // state + quickbook::state& state_; //////////////////////////////////////////////////////////////////////// // Local constructor - main_grammar_local(quickbook::actions& actions) + main_grammar_local(quickbook::state& state) : list_stack() , list_indent(0) , no_eols(true) - , actions_(actions) - , check_indentation(*this, &main_grammar_local::check_indentation_impl) - , check_code_block(*this, &main_grammar_local::check_indentation_impl) - , start_blocks(*this, &main_grammar_local::start_blocks_impl) - , end_blocks(*this, &main_grammar_local::end_blocks_impl) - , in_list(*this) - , process_element(*this) - , scoped_no_eols(*this) + , state_(state) {} }; + struct process_element_impl : scoped_action_base { + process_element_impl(main_grammar_local& l) + : l(l) {} + + bool start() + { + if (!(l.info.type & l.element.context()) || + qbk_version_n < l.info.qbk_version) + return false; + + info_ = l.info; + + if (!l.list_stack.empty() && !l.list_stack.top().root && + info_.type == element_info::block) + { + // If in a list and the element is a block, end the list. + list_item_action list_item(l.state_); + list_item(); + l.clear_stack(); + } + else if (info_.type != element_info::phrase && + info_.type != element_info::maybe_block) + { + paragraph_action para(l.state_); + para(); + } + + assert(l.state_.values.builder.empty()); + + if (!l.state_.source_mode_next.empty() && + info_.type != element_info::maybe_block) + { + l.state_.source_mode.swap(saved_source_mode_); + l.state_.source_mode = l.state_.source_mode_next.get_quickbook(); + l.state_.source_mode_next = value(); + } + + return true; + } + + template <typename ResultT, typename ScannerT> + bool result(ResultT result, ScannerT const& scan) + { + if (result || info_.type & element_info::in_phrase) + return result; + + error_action error(l.state_); + error(scan.first, scan.first); + return true; + } + + void success(parse_iterator, parse_iterator) { l.element_type = info_.type; } + void failure() { l.element_type = element_info::nothing; } + + void cleanup() { + if (!saved_source_mode_.empty()) + l.state_.source_mode.swap(saved_source_mode_); + } + + main_grammar_local& l; + element_info info_; + std::string saved_source_mode_; + }; + + struct set_no_eols_scoped : scoped_action_base + { + set_no_eols_scoped(main_grammar_local& l) + : l(l) {} + + bool start() { + saved_no_eols = l.no_eols; + l.no_eols = false; + + return true; + } + + void cleanup() { + l.no_eols = saved_no_eols; + } + + main_grammar_local& l; + bool saved_no_eols; + }; + + struct in_list_impl { + main_grammar_local& l; + + in_list_impl(main_grammar_local& l) : + l(l) {} + + bool operator()() const { + return !l.list_stack.top().root; + } + }; + //////////////////////////////////////////////////////////////////////////// // Local grammar void quickbook_grammar::impl::init_main() { main_grammar_local& local = cleanup_.add( - new main_grammar_local(actions)); + new main_grammar_local(state)); + + // Global Actions + element_action element(state); + paragraph_action paragraph(state); + list_item_action list_item(state); + + phrase_end_action end_phrase(state); + raw_char_action raw_char(state.phrase); + plain_char_action plain_char(state.phrase, state); + escape_unicode_action escape_unicode(state.phrase, state); + + simple_phrase_action simple_markup(state.phrase, state); + + break_action break_(state.phrase, state); + do_macro_action do_macro(state.phrase, state); + + error_action error(state); + element_id_warning_action element_id_warning(state); + + scoped_parser<to_value_scoped_action> to_value(state); + + // Local Actions + scoped_parser<process_element_impl> process_element(local); + scoped_parser<set_no_eols_scoped> scoped_no_eols(local); + in_list_impl in_list(local); + member_action<main_grammar_local> check_indentation(local, + &main_grammar_local::check_indentation_impl); + member_action<main_grammar_local> check_code_block(local, + &main_grammar_local::check_code_block_impl); + member_action<main_grammar_local> start_blocks(local, + &main_grammar_local::start_blocks_impl); + member_action<main_grammar_local> end_blocks(local, + &main_grammar_local::end_blocks_impl); // phrase/phrase_start is used for an entirely self-contained // phrase. For example, any remaining anchors are written out // at the end instead of being saved for any following content. phrase_start = - inline_phrase [actions.phrase_end] + inline_phrase [end_phrase] ; // nested_phrase is used for a phrase nested inside square // brackets. nested_phrase = - actions.values.save() + state.values.save() [ *( ~cl::eps_p(']') >> local.common(element_info::in_phrase) ) @@ -272,7 +347,7 @@ namespace quickbook // paragraph_phrase is like a nested_phrase but is also terminated // by a paragraph end. paragraph_phrase = - actions.values.save() + state.values.save() [ *( ~cl::eps_p(phrase_end) >> local.common(element_info::in_phrase) ) @@ -282,7 +357,7 @@ namespace quickbook // extended_phrase is like a paragraph_phrase but allows some block // elements. extended_phrase = - actions.values.save() + state.values.save() [ *( ~cl::eps_p(phrase_end) >> local.common(element_info::in_conditional) ) @@ -294,13 +369,13 @@ namespace quickbook // is expanding a template, which is parsed separately but // is part of the paragraph that contains it. inline_phrase = - actions.values.save() + state.values.save() [ *local.common(element_info::in_phrase) ] ; table_title_phrase = - actions.values.save() + state.values.save() [ *( ~cl::eps_p(space >> (']' | '[' >> space >> '[')) >> local.common(element_info::in_phrase) ) @@ -308,15 +383,15 @@ namespace quickbook ; inside_preformatted = - local.scoped_no_eols() + scoped_no_eols() [ paragraph_phrase ] ; // Top level blocks block_start = - (*eol) [local.start_blocks] - >> (*local.top_level) [local.end_blocks] + (*eol) [start_blocks] + >> (*local.top_level) [end_blocks] ; local.top_level = @@ -337,7 +412,7 @@ namespace quickbook ( *cl::blank_p >> !( (cl::ch_p('*') | '#') >> *cl::blank_p) - ) [local.check_indentation] + ) [check_indentation] ; local.paragraph = @@ -346,7 +421,7 @@ namespace quickbook >> *( cl::eps_p(local.paragraph.still_in_block) >> local.paragraph_item(element_info::only_block) ) - >> cl::eps_p [actions.paragraph] + >> cl::eps_p [paragraph] ; local.paragraph_item = @@ -361,9 +436,13 @@ namespace quickbook >> (cl::ch_p('*') | '#') >> (*cl::blank_p) [local.list.still_in_block = true] >> *( cl::eps_p(local.list.still_in_block) - >> local.list_item(element_info::only_block) + >> ( qbk_ver(106u) >> local.list_item(element_info::only_block) + | qbk_ver(0, 106u) >> local.list_item(element_info::only_list_block) + ) ) - >> cl::eps_p [actions.list_item] + // TODO: This is sometimes called in the wrong place. Currently + // harmless. + >> cl::eps_p [list_item] ; local.list_item = @@ -379,7 +458,7 @@ namespace quickbook ( *cl::blank_p >> ( cl::eol_p | cl::end_p - | cl::eps_p(local.in_list) >> (cl::ch_p('*') | '#') + | cl::eps_p(in_list) >> (cl::ch_p('*') | '#') ) ) >> *eol @@ -387,25 +466,25 @@ namespace quickbook // Blocks contains within an element, e.g. a table cell or a footnote. inside_paragraph = - actions.values.save() - [ *( local.paragraph_separator [actions.paragraph] + state.values.save() + [ *( local.paragraph_separator [paragraph] >> *eol | ~cl::eps_p(']') >> local.common(element_info::in_nested_block) ) - ] [actions.paragraph] + ] [paragraph] ; local.hr = cl::str_p("----") - >> actions.values.list(block_tags::hr) - [ ( qbk_since(106u) + >> state.values.list(block_tags::hr) + [ ( qbk_ver(106u) >> *(line_comment | (cl::anychar_p - (cl::eol_p | '[' | ']'))) - | qbk_before(106u) + | qbk_ver(0, 106u) >> *(line_comment | (cl::anychar_p - (cl::eol_p | "[/"))) ) >> *eol - ] [actions.element] + ] [element] ; local.element @@ -415,27 +494,28 @@ namespace quickbook | elements [ph::var(local.info) = ph::arg1] >> (cl::eps_p - (cl::alnum_p | '_')) ) - >> local.process_element() - [ actions.values.list(ph::var(local.info.tag)) + >> process_element() + [ state.values.list(ph::var(local.info.tag)) [ cl::lazy_p(*ph::var(local.info.rule)) >> space >> ']' - ] [actions.element] + ] [element] ] ; local.code = - ( - local.code_line + state.values.list(code_tags::code_block) + [( local.code_line >> *(*local.blank_line >> local.code_line) - ) [actions.code] + ) [state.values.entry(ph::arg1, ph::arg2)] + ] [element] >> *eol ; local.code_line = ( *cl::blank_p >> ~cl::eps_p(cl::eol_p) - ) [local.check_code_block] + ) [check_code_block] >> cl::eps_p(ph::var(local.block_type) == block_types::code) >> *(cl::anychar_p - cl::eol_p) >> (cl::eol_p | cl::end_p) @@ -455,61 +535,61 @@ namespace quickbook | local.simple_markup | escape | comment - | qbk_since(106u) >> local.square_brackets - | cl::space_p [actions.raw_char] - | cl::anychar_p [actions.plain_char] + | qbk_ver(106u) >> local.square_brackets + | cl::space_p [raw_char] + | cl::anychar_p [plain_char] ; local.square_brackets = - ( cl::ch_p('[') [actions.plain_char] + ( cl::ch_p('[') [plain_char] >> paragraph_phrase - >> ( cl::ch_p(']') [actions.plain_char] - | cl::eps_p [actions.error("Missing close bracket")] + >> ( cl::ch_p(']') [plain_char] + | cl::eps_p [error("Missing close bracket")] ) - | cl::ch_p(']') [actions.plain_char] - >> cl::eps_p [actions.error("Mismatched close bracket")] + | cl::ch_p(']') [plain_char] + >> cl::eps_p [error("Mismatched close bracket")] ) ; local.macro = cl::eps_p - ( ( actions.macro + ( ( state.macro >> ~cl::eps_p(cl::alpha_p | '_') // must not be followed by alpha or underscore ) & macro_identifier // must be a valid macro for the current version ) - >> actions.macro [actions.do_macro] + >> state.macro [do_macro] ; local.template_ = ( '[' >> space - >> actions.values.list(template_tags::template_) - [ !cl::str_p("`") [actions.values.entry(ph::arg1, ph::arg2, template_tags::escape)] + >> state.values.list(template_tags::template_) + [ !cl::str_p("`") [state.values.entry(ph::arg1, ph::arg2, template_tags::escape)] >> ( cl::eps_p(cl::punct_p) - >> actions.templates.scope [actions.values.entry(ph::arg1, ph::arg2, template_tags::identifier)] - | actions.templates.scope [actions.values.entry(ph::arg1, ph::arg2, template_tags::identifier)] + >> state.templates.scope [state.values.entry(ph::arg1, ph::arg2, template_tags::identifier)] + | state.templates.scope [state.values.entry(ph::arg1, ph::arg2, template_tags::identifier)] >> cl::eps_p(hard_space) ) >> space >> !local.template_args >> ']' ] - ) [actions.element] + ) [element] ; local.template_args = - qbk_since(105u) >> local.template_args_1_5 - | qbk_before(105u) >> local.template_args_1_4 + qbk_ver(105u) >> local.template_args_1_5 + | qbk_ver(0, 105u) >> local.template_args_1_4 ; local.template_args_1_4 = local.template_arg_1_4 >> *(".." >> local.template_arg_1_4); local.template_arg_1_4 = ( cl::eps_p(*cl::blank_p >> cl::eol_p) - >> local.template_inner_arg_1_4 [actions.values.entry(ph::arg1, ph::arg2, template_tags::block)] - | local.template_inner_arg_1_4 [actions.values.entry(ph::arg1, ph::arg2, template_tags::phrase)] + >> local.template_inner_arg_1_4 [state.values.entry(ph::arg1, ph::arg2, template_tags::block)] + | local.template_inner_arg_1_4 [state.values.entry(ph::arg1, ph::arg2, template_tags::phrase)] ) ; @@ -525,8 +605,8 @@ namespace quickbook local.template_arg_1_5 = ( cl::eps_p(*cl::blank_p >> cl::eol_p) - >> local.template_arg_1_5_content [actions.values.entry(ph::arg1, ph::arg2, template_tags::block)] - | local.template_arg_1_5_content [actions.values.entry(ph::arg1, ph::arg2, template_tags::phrase)] + >> local.template_arg_1_5_content [state.values.entry(ph::arg1, ph::arg2, template_tags::block)] + | local.template_arg_1_5_content [state.values.entry(ph::arg1, ph::arg2, template_tags::phrase)] ) ; @@ -548,48 +628,55 @@ namespace quickbook >> "br" >> space >> ']' - ) [actions.break_] + ) [break_] ; local.inline_code = - '`' >> - ( + '`' >> state.values.list(code_tags::inline_code) + [( *(cl::anychar_p - ( '`' | (cl::eol_p >> *cl::blank_p >> cl::eol_p) // Make sure that we don't go ) // past a single block ) >> cl::eps_p('`') - ) [actions.inline_code] + ) [state.values.entry(ph::arg1, ph::arg2)] >> '`' + ] [element] ; local.code_block = "```" >> ~cl::eps_p("`") - >> *(*cl::blank_p >> cl::eol_p) - >> ( *( "````" >> *cl::ch_p('`') - | ( cl::anychar_p - - (*cl::space_p >> "```" >> ~cl::eps_p("`")) - ) - ) - >> !(*cl::blank_p >> cl::eol_p) - ) [actions.code_block] - >> ( *cl::space_p >> "```" - | cl::eps_p [actions.error("Unfinished code block")] + >> ( state.values.list(code_tags::inline_code_block) + [ *(*cl::blank_p >> cl::eol_p) + >> ( *( "````" >> *cl::ch_p('`') + | ( cl::anychar_p + - (*cl::space_p >> "```" >> ~cl::eps_p("`")) + ) + ) + >> !(*cl::blank_p >> cl::eol_p) + ) [state.values.entry(ph::arg1, ph::arg2)] + >> (*cl::space_p >> "```") + ] [element] + | cl::eps_p [error("Unfinished code block")] + >> *cl::anychar_p ) | "``" >> ~cl::eps_p("`") - >> *(*cl::blank_p >> cl::eol_p) - >> ( *( "```" >> *cl::ch_p('`') - | ( cl::anychar_p - - (*cl::space_p >> "``" >> ~cl::eps_p("`")) - ) - ) - >> !(*cl::blank_p >> cl::eol_p) - ) [actions.code_block] - >> ( *cl::space_p >> "``" - | cl::eps_p [actions.error("Unfinished code block")] + >> ( state.values.list(code_tags::inline_code_block) + [ *(*cl::blank_p >> cl::eol_p) + >> ( *( "```" >> *cl::ch_p('`') + | ( cl::anychar_p + - (*cl::space_p >> "``" >> ~cl::eps_p("`")) + ) + ) + >> !(*cl::blank_p >> cl::eol_p) + ) [state.values.entry(ph::arg1, ph::arg2)] + >> (*cl::space_p >> "``") + ] [element] + | cl::eps_p [error("Unfinished code block")] + >> *cl::anychar_p ) ; @@ -606,22 +693,22 @@ namespace quickbook // by space or punctuation or the // mark character or a the start. ] - >> actions.values.save() + >> state.values.save() [ - actions.to_value() + to_value() [ - cl::eps_p((actions.macro & macro_identifier) >> local.simple_markup_end) - >> actions.macro [actions.do_macro] + cl::eps_p((state.macro & macro_identifier) >> local.simple_markup_end) + >> state.macro [do_macro] | ~cl::eps_p(cl::f_ch_p(local.simple_markup.mark)) >> +( ~cl::eps_p ( lookback [~cl::f_ch_p(local.simple_markup.mark)] >> local.simple_markup_end ) - >> cl::anychar_p [actions.plain_char] + >> cl::anychar_p [plain_char] ) ] >> cl::f_ch_p(local.simple_markup.mark) - [actions.simple_markup] + [simple_markup] ] ; @@ -643,37 +730,58 @@ namespace quickbook ; escape = - cl::str_p("\\n") [actions.break_] + cl::str_p("\\n") [break_] | cl::str_p("\\ ") // ignore an escaped space - | '\\' >> cl::punct_p [actions.plain_char] + | '\\' >> cl::punct_p [plain_char] | "\\u" >> cl::repeat_p(4) [cl::chset<>("0-9a-fA-F")] - [actions.escape_unicode] + [escape_unicode] | "\\U" >> cl::repeat_p(8) [cl::chset<>("0-9a-fA-F")] - [actions.escape_unicode] + [escape_unicode] | ("'''" >> !eol) - >> actions.values.save() - [ (*(cl::anychar_p - "'''")) [actions.values.entry(ph::arg1, ph::arg2, phrase_tags::escape)] + >> state.values.save() + [ (*(cl::anychar_p - "'''")) [state.values.entry(ph::arg1, ph::arg2, phrase_tags::escape)] >> ( cl::str_p("'''") - | cl::eps_p [actions.error("Unclosed boostbook escape.")] - ) [actions.element] + | cl::eps_p [error("Unclosed boostbook escape.")] + ) [element] ] ; raw_escape = - cl::str_p("\\n") [actions.error("Newlines invalid here.")] + cl::str_p("\\n") [error("Newlines invalid here.")] | cl::str_p("\\ ") // ignore an escaped space - | '\\' >> cl::punct_p [actions.raw_char] + | '\\' >> cl::punct_p [raw_char] | "\\u" >> cl::repeat_p(4) [cl::chset<>("0-9a-fA-F")] - [actions.escape_unicode] + [escape_unicode] | "\\U" >> cl::repeat_p(8) [cl::chset<>("0-9a-fA-F")] - [actions.escape_unicode] - | ('\\' >> cl::anychar_p) [actions.error("Invalid escape.")] - [actions.raw_char] - | ("'''" >> !eol) [actions.error("Boostbook escape invalid here.")] + [escape_unicode] + | ('\\' >> cl::anychar_p) [error("Invalid escape.")] + [raw_char] + | ("'''" >> !eol) [error("Boostbook escape invalid here.")] >> (*(cl::anychar_p - "'''")) >> ( cl::str_p("'''") - | cl::eps_p [actions.error("Unclosed boostbook escape.")] - ) [actions.element] + | cl::eps_p [error("Unclosed boostbook escape.")] + ) [element] + ; + + attribute_value_1_7 = + *( ~cl::eps_p(']' | cl::space_p | comment) + >> ( cl::eps_p + ( cl::ch_p('[') + >> space + >> ( cl::eps_p(cl::punct_p) + >> elements + | elements + >> (cl::eps_p - (cl::alnum_p | '_')) + ) + ) [error("Elements not allowed in attribute values.")] + >> local.square_brackets + | local.template_ + | cl::eps_p(cl::ch_p('[')) [error("Unmatched template in attribute value.")] + >> local.square_brackets + | raw_escape + | cl::anychar_p [raw_char] + ) + ) ; // @@ -681,22 +789,22 @@ namespace quickbook // command_line = - actions.values.list(block_tags::macro_definition) + state.values.list(block_tags::macro_definition) [ *cl::space_p >> local.command_line_macro_identifier - [actions.values.entry(ph::arg1, ph::arg2)] + [state.values.entry(ph::arg1, ph::arg2)] >> *cl::space_p >> !( '=' >> *cl::space_p - >> actions.to_value() [ inline_phrase ] + >> to_value() [ inline_phrase ] >> *cl::space_p ) >> cl::end_p - ] [actions.element] + ] [element] ; local.command_line_macro_identifier = - qbk_since(106u) + qbk_ver(106u) >> +(cl::anychar_p - (cl::space_p | '[' | '\\' | ']' | '=')) | +(cl::anychar_p - (cl::space_p | ']' | '=')) ; @@ -745,9 +853,9 @@ namespace quickbook ; macro_identifier = - qbk_since(106u) + qbk_ver(106u) >> +(cl::anychar_p - (cl::space_p | '[' | '\\' | ']')) - | qbk_before(106u) + | qbk_ver(0, 106u) >> +(cl::anychar_p - (cl::space_p | ']')) ; } @@ -819,8 +927,8 @@ namespace quickbook else { while (!list_stack.top().root && new_indent < list_stack.top().indent) { - actions_.end_list_item(); - actions_.end_list(list_stack.top().mark); + state_.end_list_item(); + state_.end_list(list_stack.top().mark); list_stack.pop(); list_indent = list_stack.top().indent; } @@ -853,8 +961,8 @@ namespace quickbook new_indent > list_stack.top().indent); if (new_indent <= list_stack.top().indent2) { - actions_.end_list_item(); - actions_.end_list(save.mark); + state_.end_list_item(); + state_.end_list(save.mark); list_indent = list_stack.top().indent; } else { @@ -889,44 +997,44 @@ namespace quickbook if (list_stack.top().root || new_indent > list_indent) { list_stack.push(list_stack_item(mark, new_indent, new_indent2)); - actions_.start_list(mark); + state_.start_list(mark); } else if (new_indent == list_indent) { - actions_.end_list_item(); + state_.end_list_item(); } else { // This should never reach root, since the first list // has indentation 0. while(!list_stack.top().root && new_indent < list_stack.top().indent) { - actions_.end_list_item(); - actions_.end_list(list_stack.top().mark); + state_.end_list_item(); + state_.end_list(list_stack.top().mark); list_stack.pop(); } - actions_.end_list_item(); + state_.end_list_item(); } list_indent = new_indent; if (mark != list_stack.top().mark) { - detail::outerr(actions_.current_file, first) + detail::outerr(state_.current_file, first) << "Illegal change of list style.\n"; - detail::outwarn(actions_.current_file, first) + detail::outwarn(state_.current_file, first) << "Ignoring change of list style." << std::endl; - ++actions_.error_count; + ++state_.error_count; } - actions_.start_list_item(); + state_.start_list_item(); block_type = block_types::list; } void main_grammar_local::clear_stack() { while (!list_stack.top().root) { - actions_.end_list_item(); - actions_.end_list(list_stack.top().mark); + state_.end_list_item(); + state_.end_list(list_stack.top().mark); list_stack.pop(); } } diff --git a/tools/quickbook/src/parsers.hpp b/tools/quickbook/src/parsers.hpp index 19d385de5e..c1c18803a5 100644 --- a/tools/quickbook/src/parsers.hpp +++ b/tools/quickbook/src/parsers.hpp @@ -17,6 +17,7 @@ #include <boost/spirit/include/phoenix1_primitives.hpp> #include <boost/spirit/include/phoenix1_tuples.hpp> #include <boost/spirit/include/phoenix1_binders.hpp> +#include "fwd.hpp" namespace quickbook { namespace cl = boost::spirit::classic; @@ -252,6 +253,48 @@ namespace quickbook { }; lookback_gen const lookback = lookback_gen(); + + /////////////////////////////////////////////////////////////////////////// + // + // UTF-8 code point + // + // Very crude, it doesn't check that the code point is in any way valid. + // Just looks for the beginning of the next character. This is just for + // implementing some crude fixes, rather than full unicode support. I'm + // sure experts would be appalled. + // + /////////////////////////////////////////////////////////////////////////// + + struct u8_codepoint_parser : public cl::parser<u8_codepoint_parser> + { + typedef u8_codepoint_parser self_t; + + template <typename Scanner> + struct result + { + typedef cl::match<> type; + }; + + template <typename Scanner> + typename result<Scanner>::type parse(Scanner const& scan) const + { + typedef typename Scanner::iterator_t iterator_t; + + if (scan.at_end()) return scan.no_match(); + + iterator_t save(scan.first); + + do { + ++scan.first; + } while (!scan.at_end() && + ((unsigned char) *scan.first & 0xc0) == 0x80); + + return scan.create_match(scan.first.base() - save.base(), + cl::nil_t(), save, scan.first); + } + }; + + u8_codepoint_parser const u8_codepoint_p = u8_codepoint_parser(); } #endif // BOOST_QUICKBOOK_SCOPED_BLOCK_HPP diff --git a/tools/quickbook/src/phrase_element_grammar.cpp b/tools/quickbook/src/phrase_element_grammar.cpp index 7a4e3c0a09..b287d63621 100644 --- a/tools/quickbook/src/phrase_element_grammar.cpp +++ b/tools/quickbook/src/phrase_element_grammar.cpp @@ -9,7 +9,8 @@ =============================================================================*/ #include "grammar_impl.hpp" -#include "actions_class.hpp" +#include "state.hpp" +#include "actions.hpp" #include "utils.hpp" #include "phrase_tags.hpp" #include <boost/spirit/include/classic_core.hpp> @@ -27,7 +28,7 @@ namespace quickbook { cl::rule<scanner> image, anchor, link, empty, cond_phrase, inner_phrase, - role + role, source_mode ; }; @@ -36,15 +37,19 @@ namespace quickbook phrase_element_grammar_local& local = cleanup_.add( new phrase_element_grammar_local); + error_action error(state); + raw_char_action raw_char(state.phrase); + scoped_parser<cond_phrase_push> scoped_cond_phrase(state); + scoped_parser<to_value_scoped_action> to_value(state); + elements.add ("?", element_info(element_info::phrase, &local.cond_phrase)) ; local.cond_phrase = blank - >> macro_identifier [actions.values.entry(ph::arg1, ph::arg2)] - >> actions.scoped_cond_phrase() - [extended_phrase] + >> macro_identifier [state.values.entry(ph::arg1, ph::arg2)] + >> scoped_cond_phrase() [extended_phrase] ; elements.add @@ -54,37 +59,37 @@ namespace quickbook // Note that the attribute values here are encoded in plain text not // boostbook. local.image = - qbk_since(105u) + qbk_ver(105u) >> blank - >> ( qbk_before(106u) + >> ( qbk_ver(0, 106u) >> (+( *cl::space_p >> +(cl::anychar_p - (cl::space_p | phrase_end | '[')) - )) [actions.values.entry(ph::arg1, ph::arg2)] - | qbk_since(106u) - >> actions.to_value() + )) [state.values.entry(ph::arg1, ph::arg2)] + | qbk_ver(106u) + >> to_value() [ +( raw_escape | (+cl::space_p >> ~cl::eps_p(phrase_end | '[')) - [actions.raw_char] + [raw_char] | (cl::anychar_p - (cl::space_p | phrase_end | '[')) - [actions.raw_char] + [raw_char] ) ] ) >> hard_space - >> *actions.values.list() + >> *state.values.list() [ '[' >> (*(cl::alnum_p | '_')) - [actions.values.entry(ph::arg1, ph::arg2)] + [state.values.entry(ph::arg1, ph::arg2)] >> space - >> ( qbk_before(106u) + >> ( qbk_ver(0, 106u) >> (*(cl::anychar_p - (phrase_end | '['))) - [actions.values.entry(ph::arg1, ph::arg2)] - | qbk_since(106u) - >> actions.to_value() + [state.values.entry(ph::arg1, ph::arg2)] + | qbk_ver(106u) + >> to_value() [ *( raw_escape | (cl::anychar_p - (phrase_end | '[')) - [actions.raw_char] + [raw_char] ) ] ) @@ -92,9 +97,9 @@ namespace quickbook >> space ] >> cl::eps_p(']') - | qbk_before(105u) + | qbk_ver(0, 105u) >> blank - >> (*(cl::anychar_p - phrase_end)) [actions.values.entry(ph::arg1, ph::arg2)] + >> (*(cl::anychar_p - phrase_end)) [state.values.entry(ph::arg1, ph::arg2)] >> cl::eps_p(']') ; @@ -113,16 +118,21 @@ namespace quickbook local.link = space - >> ( qbk_before(106u) + >> ( qbk_ver(0, 106u) >> (*(cl::anychar_p - (']' | space))) - [actions.values.entry(ph::arg1, ph::arg2)] - | qbk_since(106u) - >> actions.to_value() + [state.values.entry(ph::arg1, ph::arg2)] + | qbk_ver(106u, 107u) + >> to_value() [ *( raw_escape - | (cl::anychar_p - (']' | space)) - [actions.raw_char] + | (cl::anychar_p - (cl::ch_p('[') | ']' | space)) + [raw_char] ) ] + >> !( ~cl::eps_p(comment) + >> cl::eps_p('[') [error("Open bracket in link value.")] + ) + | qbk_ver(107u) + >> to_value() [attribute_value_1_7] ) >> hard_space >> local.inner_phrase @@ -134,13 +144,13 @@ namespace quickbook local.anchor = blank - >> ( qbk_before(106u) - >> (*(cl::anychar_p - phrase_end)) [actions.values.entry(ph::arg1, ph::arg2)] - | qbk_since(106u) - >> actions.to_value() + >> ( qbk_ver(0, 106u) + >> (*(cl::anychar_p - phrase_end)) [state.values.entry(ph::arg1, ph::arg2)] + | qbk_ver(106u) + >> to_value() [ *( raw_escape | (cl::anychar_p - phrase_end) - [actions.raw_char] + [raw_char] ) ] ) @@ -157,6 +167,15 @@ namespace quickbook ("footnote", element_info(element_info::phrase, &local.inner_phrase, phrase_tags::footnote)) ; + elements.add("!", element_info(element_info::maybe_block, &local.source_mode, code_tags::next_source_mode, 107u)) + ; + + local.source_mode = + ( cl::str_p("c++") + | "python" + | "teletype" + ) [state.values.entry(ph::arg1, ph::arg2)]; + elements.add ("c++", element_info(element_info::phrase, &local.empty, source_mode_tags::cpp)) ("python", element_info(element_info::phrase, &local.empty, source_mode_tags::python)) @@ -169,7 +188,7 @@ namespace quickbook local.role = space - >> (+(cl::alnum_p | '_')) [actions.values.entry(ph::arg1, ph::arg2)] + >> (+(cl::alnum_p | '_')) [state.values.entry(ph::arg1, ph::arg2)] >> hard_space >> local.inner_phrase ; @@ -178,7 +197,7 @@ namespace quickbook local.inner_phrase = blank - >> actions.to_value() [ paragraph_phrase ] + >> to_value() [ paragraph_phrase ] ; } } diff --git a/tools/quickbook/src/phrase_tags.hpp b/tools/quickbook/src/phrase_tags.hpp index bf9b754b6c..f4bba91653 100644 --- a/tools/quickbook/src/phrase_tags.hpp +++ b/tools/quickbook/src/phrase_tags.hpp @@ -30,6 +30,13 @@ namespace quickbook ((python)("python")) ((teletype)("teletype")) ) + + QUICKBOOK_VALUE_TAGS(code_tags, 0x560, + (code_block) + (inline_code) + (inline_code_block) + (next_source_mode) + ) } #endif diff --git a/tools/quickbook/src/quickbook.cpp b/tools/quickbook/src/quickbook.cpp index fc197b58c7..5a359ed3e1 100644 --- a/tools/quickbook/src/quickbook.cpp +++ b/tools/quickbook/src/quickbook.cpp @@ -9,19 +9,21 @@ =============================================================================*/ #include "grammar.hpp" #include "quickbook.hpp" -#include "actions_class.hpp" +#include "state.hpp" +#include "actions.hpp" #include "post_process.hpp" #include "utils.hpp" #include "files.hpp" #include "input_path.hpp" #include "id_manager.hpp" #include <boost/program_options.hpp> -#include <boost/filesystem/v3/path.hpp> -#include <boost/filesystem/v3/operations.hpp> -#include <boost/filesystem/v3/fstream.hpp> +#include <boost/filesystem/path.hpp> +#include <boost/filesystem/operations.hpp> +#include <boost/filesystem/fstream.hpp> #include <boost/range/algorithm.hpp> #include <boost/ref.hpp> #include <boost/version.hpp> +#include <boost/foreach.hpp> #include <stdexcept> #include <vector> @@ -36,7 +38,7 @@ #pragma warning(disable:4355) #endif -#define QUICKBOOK_VERSION "Quickbook Version 1.5.7" +#define QUICKBOOK_VERSION "Quickbook Version 1.5.8" namespace quickbook { @@ -52,7 +54,7 @@ namespace quickbook std::vector<std::string> preset_defines; fs::path image_location; - static void set_macros(actions& actor) + static void set_macros(quickbook::state& state) { for(std::vector<std::string>::const_iterator it = preset_defines.begin(), @@ -63,15 +65,15 @@ namespace quickbook parse_iterator last(it->end()); cl::parse_info<parse_iterator> info = - cl::parse(first, last, actor.grammar().command_line_macro); + cl::parse(first, last, state.grammar().command_line_macro); if (!info.full) { detail::outerr() << "Error parsing command line definition: '" - << detail::utf8(*it) + << *it << "'" << std::endl; - ++actor.error_count; + ++state.error_count; } } } @@ -81,29 +83,29 @@ namespace quickbook // Parse a file // /////////////////////////////////////////////////////////////////////////// - void parse_file(actions& actor, value include_doc_id, bool nested_file) + void parse_file(quickbook::state& state, value include_doc_id, bool nested_file) { - parse_iterator first(actor.current_file->source.begin()); - parse_iterator last(actor.current_file->source.end()); + parse_iterator first(state.current_file->source.begin()); + parse_iterator last(state.current_file->source.end()); - cl::parse_info<parse_iterator> info = cl::parse(first, last, actor.grammar().doc_info); + cl::parse_info<parse_iterator> info = cl::parse(first, last, state.grammar().doc_info); assert(info.hit); - if (!actor.error_count) + if (!state.error_count) { parse_iterator pos = info.stop; - std::string doc_type = pre(actor, pos, include_doc_id, nested_file); + std::string doc_type = pre(state, pos, include_doc_id, nested_file); - info = cl::parse(info.hit ? info.stop : first, last, actor.grammar().block); + info = cl::parse(info.hit ? info.stop : first, last, state.grammar().block); - post(actor, doc_type); + post(state, doc_type); if (!info.full) { - file_position const& pos = actor.current_file->position_of(info.stop.base()); - detail::outerr(actor.current_file->path, pos.line) + file_position const& pos = state.current_file->position_of(info.stop.base()); + detail::outerr(state.current_file->path, pos.line) << "Syntax Error near column " << pos.column << ".\n"; - ++actor.error_count; + ++state.error_count; } } } @@ -112,6 +114,8 @@ namespace quickbook parse_document( fs::path const& filein_ , fs::path const& fileout_ + , fs::path const& deps_out_ + , fs::path const& locations_out_ , fs::path const& xinclude_base_ , int indent , int linewidth @@ -123,28 +127,52 @@ namespace quickbook int result = 0; try { - actions actor(filein_, xinclude_base_, buffer, ids); - set_macros(actor); + quickbook::state state(filein_, xinclude_base_, buffer, ids); + set_macros(state); - if (actor.error_count == 0) { - actor.current_file = load(filein_); // Throws load_error + if (state.error_count == 0) { + state.add_dependency(filein_); + state.current_file = load(filein_); // Throws load_error - parse_file(actor); + parse_file(state); - if(actor.error_count) { + if(state.error_count) { detail::outerr() - << "Error count: " << actor.error_count << ".\n"; + << "Error count: " << state.error_count << ".\n"; } } - result = actor.error_count ? 1 : 0; + result = state.error_count ? 1 : 0; + + if (!deps_out_.empty()) + { + fs::ofstream out(deps_out_); + BOOST_FOREACH(quickbook::state::dependency_list::value_type + const& d, state.dependencies) + { + if (d.second) { + out << detail::path_to_generic(d.first) << std::endl; + } + } + } + + if (!locations_out_.empty()) + { + fs::ofstream out(locations_out_); + BOOST_FOREACH(quickbook::state::dependency_list::value_type + const& d, state.dependencies) + { + out << (d.second ? "+ " : "- ") + << detail::path_to_generic(d.first) << std::endl; + } + } } catch (load_error& e) { - detail::outerr(filein_) << detail::utf8(e.what()) << std::endl; + detail::outerr(filein_) << e.what() << std::endl; result = 1; } - if (result == 0) + if (!fileout_.empty() && result == 0) { std::string stage2 = ids.replace_placeholders(buffer.str()); @@ -244,6 +272,7 @@ main(int argc, char* argv[]) ("linewidth", PO_VALUE<int>(), "line width") ("input-file", PO_VALUE<input_string>(), "input file") ("output-file", PO_VALUE<input_string>(), "output file") + ("output-deps", PO_VALUE<input_string>(), "output dependency file") ("debug", "debug mode (for developers)") ("ms-errors", "use Microsoft Visual Studio style error & warn message format") ("include-path,I", PO_VALUE< std::vector<input_string> >(), "include path") @@ -258,6 +287,10 @@ main(int argc, char* argv[]) ("xinclude-base", PO_VALUE<input_string>(), "Generate xincludes as if generating for this target " "directory.") + ("output-checked-locations", PO_VALUE<input_string>(), + "Writes a file listing all the file locations that were " + "checked, starting with '+' if they were found, or '-' " + "if they weren't.") ; all.add(desc).add(hidden); @@ -306,8 +339,7 @@ main(int argc, char* argv[]) std::ostringstream description_text; description_text << desc; - quickbook::detail::out() - << quickbook::detail::utf8(description_text.str()) << "\n"; + quickbook::detail::out() << description_text.str() << "\n"; return 0; } @@ -320,7 +352,7 @@ main(int argc, char* argv[]) quickbook::detail::out() << QUICKBOOK_VERSION << " (Boost " - << quickbook::detail::utf8(boost_version) + << boost_version << ")" << std::endl; return 0; @@ -388,18 +420,36 @@ main(int argc, char* argv[]) fs::path filein = quickbook::detail::input_to_path( vm["input-file"].as<input_string>()); fs::path fileout; + fs::path deps_out; + fs::path locations_out; + + bool default_output = true; + + if (vm.count("output-deps")) + { + deps_out = quickbook::detail::input_to_path( + vm["output-deps"].as<input_string>()); + default_output = false; + } + + if (vm.count("output-checked-locations")) + { + locations_out = quickbook::detail::input_to_path( + vm["output-checked-locations"].as<input_string>()); + default_output = false; + } if (vm.count("output-file")) { fileout = quickbook::detail::input_to_path( vm["output-file"].as<input_string>()); } - else + else if (default_output) { fileout = filein; fileout.replace_extension(".xml"); } - + fs::path xinclude_base; if (vm.count("xinclude-base")) { @@ -432,12 +482,16 @@ main(int argc, char* argv[]) quickbook::image_location = filein.parent_path() / "html"; } - quickbook::detail::out() << "Generating Output File: " - << quickbook::detail::path_to_stream(fileout) - << std::endl; + if (!fileout.empty()) { + quickbook::detail::out() << "Generating Output File: " + << fileout + << std::endl; + } if (!error_count) - error_count += quickbook::parse_document(filein, fileout, xinclude_base, indent, linewidth, pretty_print); + error_count += quickbook::parse_document( + filein, fileout, deps_out, locations_out, + xinclude_base, indent, linewidth, pretty_print); if (expect_errors) { @@ -455,14 +509,14 @@ main(int argc, char* argv[]) description_text << desc; quickbook::detail::outerr() << "No filename given\n\n" - << quickbook::detail::utf8(description_text.str()) << std::endl; + << description_text.str() << std::endl; return 1; } } catch(std::exception& e) { - quickbook::detail::outerr() << quickbook::detail::utf8(e.what()) << "\n"; + quickbook::detail::outerr() << e.what() << "\n"; return 1; } diff --git a/tools/quickbook/src/quickbook.hpp b/tools/quickbook/src/quickbook.hpp index 265bc7ee53..27d07a4125 100644 --- a/tools/quickbook/src/quickbook.hpp +++ b/tools/quickbook/src/quickbook.hpp @@ -15,7 +15,7 @@ #include <time.h> #include <vector> #include <string> -#include <boost/filesystem/v3/path.hpp> +#include <boost/filesystem/path.hpp> #include "fwd.hpp" #include "values.hpp" @@ -31,7 +31,7 @@ namespace quickbook extern std::vector<std::string> preset_defines; extern fs::path image_location; - void parse_file(actions& actor, + void parse_file(quickbook::state& state, value include_doc_id = value(), bool nested_file = false); // Some initialisation methods diff --git a/tools/quickbook/src/state.cpp b/tools/quickbook/src/state.cpp new file mode 100644 index 0000000000..d16200d626 --- /dev/null +++ b/tools/quickbook/src/state.cpp @@ -0,0 +1,160 @@ +/*============================================================================= + Copyright (c) 2002 2004 2006 Joel de Guzman + Copyright (c) 2004 Eric Niebler + Copyright (c) 2005 Thomas Guest + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to the Boost Software + License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#include "state.hpp" +#include "state_save.hpp" +#include "quickbook.hpp" +#include "grammar.hpp" +#include "input_path.hpp" +#include <boost/filesystem/operations.hpp> + +#if (defined(BOOST_MSVC) && (BOOST_MSVC <= 1310)) +#pragma warning(disable:4355) +#endif + +namespace quickbook +{ + char const* quickbook_get_date = "__quickbook_get_date__"; + char const* quickbook_get_time = "__quickbook_get_time__"; + + unsigned qbk_version_n = 0; // qbk_major_version * 100 + qbk_minor_version + + state::state(fs::path const& filein_, fs::path const& xinclude_base_, + string_stream& out_, id_manager& ids) + : grammar_() + + , xinclude_base(xinclude_base_) + + , templates() + , error_count(0) + , anchors() + , warned_about_breaks(false) + , conditional(true) + , ids(ids) + , callouts() + , callout_depth(0) + + , imported(false) + , macro() + , source_mode("c++") + , source_mode_next() + , current_file(0) + , filename_relative(filein_.filename()) + + , template_depth(0) + , min_section_level(1) + + , out(out_) + , phrase() + , values(¤t_file) + { + // add the predefined macros + macro.add + ("__DATE__", std::string(quickbook_get_date)) + ("__TIME__", std::string(quickbook_get_time)) + ("__FILENAME__", detail::path_to_generic(filename_relative)) + ; + + boost::scoped_ptr<quickbook_grammar> g( + new quickbook_grammar(*this)); + grammar_.swap(g); + } + + quickbook_grammar& state::grammar() const { + return *grammar_; + } + + bool state::add_dependency(fs::path const& f) { + fs::path p = fs::absolute(f); + bool found = fs::exists(fs::status(p)); + + // Pop path sections from path until we find an existing + // path, adjusting for any dot path sections. + fs::path extra; + int parent_count = 0; + while (!fs::exists(fs::status(p))) { + fs::path name = p.filename(); + p = p.parent_path(); + if (name == "..") { + ++parent_count; + } + else if (name == ".") { + } + else if (parent_count) { + --parent_count; + } + else { + extra = name / extra; + } + } + + // If there are any left over ".." sections, then add them + // on to the end of the real path, and trust Boost.Filesystem + // to sort them out. + while (parent_count) { + p = p / ".."; + --parent_count; + } + + p = fs::canonical(p) / extra; + dependencies[p] |= found; + return found; + } + + file_state::file_state(quickbook::state& state, scope_flags scope) + : state(state) + , scope(scope) + , qbk_version(qbk_version_n) + , imported(state.imported) + , current_file(state.current_file) + , filename_relative(state.filename_relative) + , xinclude_base(state.xinclude_base) + , source_mode(state.source_mode) + , macro() + { + if (scope & scope_macros) macro = state.macro; + if (scope & scope_templates) state.templates.push(); + if (scope & scope_output) { + state.out.push(); + state.phrase.push(); + } + state.values.builder.save(); + } + + file_state::~file_state() + { + state.values.builder.restore(); + boost::swap(qbk_version_n, qbk_version); + boost::swap(state.imported, imported); + boost::swap(state.current_file, current_file); + boost::swap(state.filename_relative, filename_relative); + boost::swap(state.xinclude_base, xinclude_base); + boost::swap(state.source_mode, source_mode); + if (scope & scope_output) { + state.out.pop(); + state.phrase.pop(); + } + if (scope & scope_templates) state.templates.pop(); + if (scope & scope_macros) state.macro = macro; + } + + template_state::template_state(quickbook::state& state) + : file_state(state, file_state::scope_all) + , template_depth(state.template_depth) + , min_section_level(state.min_section_level) + { + } + + template_state::~template_state() + { + boost::swap(state.template_depth, template_depth); + boost::swap(state.min_section_level, min_section_level); + } +} diff --git a/tools/quickbook/src/actions_class.hpp b/tools/quickbook/src/state.hpp index 979c3ccf67..b750904588 100644 --- a/tools/quickbook/src/actions_class.hpp +++ b/tools/quickbook/src/state.hpp @@ -10,20 +10,22 @@ #if !defined(BOOST_SPIRIT_ACTIONS_CLASS_HPP) #define BOOST_SPIRIT_ACTIONS_CLASS_HPP +#include <map> #include <boost/scoped_ptr.hpp> -#include "actions.hpp" #include "parsers.hpp" #include "values_parse.hpp" #include "collector.hpp" +#include "template_stack.hpp" +#include "symbols.hpp" namespace quickbook { namespace cl = boost::spirit::classic; namespace fs = boost::filesystem; - struct actions + struct state { - actions(fs::path const& filein_, fs::path const& xinclude_base, string_stream& out_, + state(fs::path const& filein_, fs::path const& xinclude_base, string_stream& out_, id_manager&); private: @@ -35,9 +37,10 @@ namespace quickbook /////////////////////////////////////////////////////////////////////////// typedef std::vector<std::string> string_list; + typedef std::map<fs::path, bool> dependency_list; static int const max_template_depth = 100; - + // global state fs::path xinclude_base; template_stack templates; @@ -46,12 +49,16 @@ namespace quickbook bool warned_about_breaks; bool conditional; id_manager& ids; + value_builder callouts; // callouts are global as + int callout_depth; // they don't nest. + dependency_list dependencies; // state saved for files and templates. bool imported; string_symbols macro; std::string source_mode; - file_ptr current_file; + value source_mode_next; + file_ptr current_file; fs::path filename_relative; // for the __FILENAME__ macro. // (relative to the original file // or include path). @@ -71,37 +78,23 @@ namespace quickbook // actions /////////////////////////////////////////////////////////////////////////// + // Call this before loading any file so that it will be included in the + // list of dependencies. Returns true if file exists. + bool add_dependency(fs::path const&); + void start_list(char mark); void end_list(char mark); void start_list_item(); void end_list_item(); - scoped_parser<to_value_scoped_action> - to_value; - scoped_parser<cond_phrase_push> - scoped_cond_phrase; - - element_action element; - error_action error; - - code_action code; - code_action code_block; - code_action inline_code; - paragraph_action paragraph; - list_item_action list_item; - phrase_end_action phrase_end; - raw_char_action raw_char; - plain_char_action plain_char; - escape_unicode_action escape_unicode; - - simple_phrase_action simple_markup; - - break_action break_; - do_macro_action do_macro; - - element_id_warning_action element_id_warning; + void start_callouts(); + std::string add_callout(value); + std::string end_callouts(); }; + + extern unsigned qbk_version_n; // qbk_major_version * 100 + qbk_minor_version + extern char const* quickbook_get_date; + extern char const* quickbook_get_time; } #endif // BOOST_SPIRIT_ACTIONS_CLASS_HPP - diff --git a/tools/quickbook/src/actions_state.hpp b/tools/quickbook/src/state_save.hpp index aefa7f99da..f8b53e7c8e 100644 --- a/tools/quickbook/src/actions_state.hpp +++ b/tools/quickbook/src/state_save.hpp @@ -10,13 +10,13 @@ #if !defined(BOOST_SPIRIT_ACTIONS_STATE_HPP) #define BOOST_SPIRIT_ACTIONS_STATE_HPP -#include "actions_class.hpp" +#include "state.hpp" namespace quickbook { // State savers // - // Defined in actions_class.cpp + // Defined in state.cpp struct file_state { @@ -29,10 +29,10 @@ namespace quickbook scope_all = scope_callables + scope_output }; - explicit file_state(actions&, scope_flags); + explicit file_state(quickbook::state&, scope_flags); ~file_state(); - quickbook::actions& a; + quickbook::state& state; scope_flags scope; unsigned qbk_version; bool imported; @@ -49,7 +49,7 @@ namespace quickbook struct template_state : file_state { - explicit template_state(actions&); + explicit template_state(quickbook::state&); ~template_state(); int template_depth; diff --git a/tools/quickbook/src/string_ref.cpp b/tools/quickbook/src/string_ref.cpp index b4775576da..6c33df1260 100644 --- a/tools/quickbook/src/string_ref.cpp +++ b/tools/quickbook/src/string_ref.cpp @@ -9,10 +9,17 @@ #include "string_ref.hpp" #include <boost/range/algorithm/equal.hpp> #include <boost/range/algorithm/lexicographical_compare.hpp> +#include <boost/utility/swap.hpp> #include <ostream> namespace quickbook { + void string_ref::swap(string_ref& x) + { + boost::swap(begin_, x.begin_); + boost::swap(end_, x.end_); + } + bool operator==(string_ref const& x, string_ref const& y) { return boost::equal(x, y); diff --git a/tools/quickbook/src/string_ref.hpp b/tools/quickbook/src/string_ref.hpp index b712006790..ffb95bf71d 100644 --- a/tools/quickbook/src/string_ref.hpp +++ b/tools/quickbook/src/string_ref.hpp @@ -37,6 +37,12 @@ namespace quickbook explicit string_ref(std::string const& x) : begin_(x.begin()), end_(x.end()) {} + void swap(string_ref&); + + void clear() { + begin_ = end_ = iterator(); + } + operator std::string() const { return std::string(begin_, end_); } @@ -73,6 +79,11 @@ namespace quickbook { return x > string_ref(y); } + + inline void swap(string_ref& x, string_ref& y) + { + x.swap(y); + } } #endif diff --git a/tools/quickbook/src/syntax_highlight.cpp b/tools/quickbook/src/syntax_highlight.cpp index 2e790f5bb1..e618c07dd6 100644 --- a/tools/quickbook/src/syntax_highlight.cpp +++ b/tools/quickbook/src/syntax_highlight.cpp @@ -14,7 +14,9 @@ #include <boost/spirit/include/classic_loops.hpp> #include "grammar.hpp" #include "grammar_impl.hpp" // Just for context stuff. Should move? -#include "actions_class.hpp" +#include "state.hpp" +#include "actions.hpp" +#include "utils.hpp" #include "files.hpp" #include "input_path.hpp" @@ -22,102 +24,100 @@ namespace quickbook { namespace cl = boost::spirit::classic; - // quickbook::actions is used in a few places here, as 'escape_actions'. - // It's named differently to distinguish it from the syntax highlighting - // actions, declared below. - - // Syntax Highlight Actions - - struct span + template <typename T, typename Value> + struct member_action_value { - // Decorates c++ code fragments + typedef void(T::*member_function)(Value); - span(char const* name, collector& out) - : name(name), out(out) {} + T& l; + member_function mf; - void operator()(parse_iterator first, parse_iterator last) const; + member_action_value(T& l, member_function mf) : l(l), mf(mf) {} - char const* name; - collector& out; + void operator()(Value v) const { + (l.*mf)(v); + } }; - struct span_start + template <typename T> + struct member_action { - span_start(char const* name, collector& out) - : name(name), out(out) {} + typedef void(T::*member_function)(parse_iterator, parse_iterator); - void operator()(parse_iterator first, parse_iterator last) const; + T& l; + member_function mf; - char const* name; - collector& out; - }; + member_action(T& l, member_function mf) : l(l), mf(mf) {} - struct span_end - { - span_end(collector& out) - : out(out) {} - - void operator()(parse_iterator first, parse_iterator last) const; - - collector& out; + void operator()(parse_iterator first, parse_iterator last) const { + (l.*mf)(first, last); + } }; - struct unexpected_char + template <typename T, typename Arg1> + struct member_action1 { - // Handles unexpected chars in c++ syntax + typedef void(T::*member_function)(parse_iterator, parse_iterator, Arg1); - unexpected_char( - collector& out - , quickbook::actions& escape_actions) - : out(out) - , escape_actions(escape_actions) {} + T& l; + member_function mf; - void operator()(parse_iterator first, parse_iterator last) const; - - collector& out; - quickbook::actions& escape_actions; - }; + member_action1(T& l, member_function mf) : l(l), mf(mf) {} - struct plain_char - { - // Prints a single plain char. - // Converts '<' to "<"... etc See utils.hpp + struct impl + { + member_action1 a; + Arg1 value; - plain_char(collector& out) - : out(out) {} + impl(member_action1& a, Arg1 value) : + a(a), value(value) + {} - void operator()(char ch) const; - void operator()(parse_iterator first, parse_iterator last) const; + void operator()(parse_iterator first, parse_iterator last) const { + (a.l.*a.mf)(first, last, value); + } + }; - collector& out; + impl operator()(Arg1 a1) { + return impl(*this, a1); + } }; - struct pre_escape_back - { - // Escapes back from code to quickbook (Pre) - - pre_escape_back(actions& escape_actions) - : escape_actions(escape_actions) {} - - void operator()(parse_iterator first, parse_iterator last) const; - - actions& escape_actions; - }; + // Syntax Highlight Actions - struct post_escape_back + struct syntax_highlight_actions { - // Escapes back from code to quickbook (Post) - - post_escape_back(collector& out, actions& escape_actions) - : out(out), escape_actions(escape_actions) {} - - void operator()(parse_iterator first, parse_iterator last) const; - - collector& out; - actions& escape_actions; + quickbook::collector out; + quickbook::state& state; + do_macro_action do_macro_impl; + + // State + bool support_callouts; + string_ref marked_text; + + syntax_highlight_actions(quickbook::state& state, bool is_block) : + out(), state(state), + do_macro_impl(out, state), + support_callouts(is_block && (qbk_version_n >= 107u || + state.current_file->is_code_snippets)), + marked_text() + {} + + void span(parse_iterator, parse_iterator, char const*); + void span_start(parse_iterator, parse_iterator, char const*); + void span_end(parse_iterator, parse_iterator); + void unexpected_char(parse_iterator, parse_iterator); + void plain_char(parse_iterator, parse_iterator); + void pre_escape_back(parse_iterator, parse_iterator); + void post_escape_back(parse_iterator, parse_iterator); + void do_macro(std::string const&); + + void mark_text(parse_iterator, parse_iterator); + void callout(parse_iterator, parse_iterator); }; - void span::operator()(parse_iterator first, parse_iterator last) const + void syntax_highlight_actions::span(parse_iterator first, + parse_iterator last, char const* name) { out << "<phrase role=\"" << name << "\">"; while (first != last) @@ -125,27 +125,30 @@ namespace quickbook out << "</phrase>"; } - void span_start::operator()(parse_iterator first, parse_iterator last) const + void syntax_highlight_actions::span_start(parse_iterator first, + parse_iterator last, char const* name) { out << "<phrase role=\"" << name << "\">"; while (first != last) detail::print_char(*first++, out.get()); } - void span_end::operator()(parse_iterator first, parse_iterator last) const + void syntax_highlight_actions::span_end(parse_iterator first, + parse_iterator last) { while (first != last) detail::print_char(*first++, out.get()); out << "</phrase>"; } - void unexpected_char::operator()(parse_iterator first, parse_iterator last) const + void syntax_highlight_actions::unexpected_char(parse_iterator first, + parse_iterator last) { - file_position const pos = escape_actions.current_file->position_of(first.base()); + file_position const pos = state.current_file->position_of(first.base()); - detail::outwarn(escape_actions.current_file->path, pos.line) + detail::outwarn(state.current_file->path, pos.line) << "in column:" << pos.column - << ", unexpected character: " << detail::utf8(first, last) + << ", unexpected character: " << std::string(first.base(), last.base()) << "\n"; // print out an unexpected character @@ -155,26 +158,42 @@ namespace quickbook out << "</phrase>"; } - void plain_char::operator()(char ch) const + void syntax_highlight_actions::plain_char(parse_iterator first, + parse_iterator last) { - detail::print_char(ch, out.get()); + while (first != last) + detail::print_char(*first++, out.get()); } - void plain_char::operator()(parse_iterator first, parse_iterator last) const + void syntax_highlight_actions::pre_escape_back(parse_iterator, + parse_iterator) { - while (first != last) - detail::print_char(*first++, out.get()); + state.phrase.push(); // save the stream + } + + void syntax_highlight_actions::post_escape_back(parse_iterator, + parse_iterator) + { + out << state.phrase.str(); + state.phrase.pop(); // restore the stream + } + + void syntax_highlight_actions::do_macro(std::string const& v) + { + do_macro_impl(v); } - void pre_escape_back::operator()(parse_iterator, parse_iterator) const + void syntax_highlight_actions::mark_text(parse_iterator first, + parse_iterator last) { - escape_actions.phrase.push(); // save the stream + marked_text = string_ref(first.base(), last.base()); } - void post_escape_back::operator()(parse_iterator, parse_iterator) const + void syntax_highlight_actions::callout(parse_iterator, parse_iterator) { - out << escape_actions.phrase.str(); - escape_actions.phrase.pop(); // restore the stream + out << state.add_callout(qbk_value(state.current_file, + marked_text.begin(), marked_text.end())); + marked_text.clear(); } // Syntax @@ -225,45 +244,63 @@ namespace quickbook } // Grammar for C++ highlighting - struct cpp_highlight - : public cl::grammar<cpp_highlight> + struct cpp_highlight : public cl::grammar<cpp_highlight> { - cpp_highlight(collector& out, actions& escape_actions) - : out(out), escape_actions(escape_actions) {} + cpp_highlight(syntax_highlight_actions& actions) + : actions(actions) {} template <typename Scanner> struct definition { definition(cpp_highlight const& self) - : g(self.escape_actions.grammar()) + : g(self.actions.state.grammar()) { + member_action1<syntax_highlight_actions, char const*> + span(self.actions, &syntax_highlight_actions::span), + span_start(self.actions, &syntax_highlight_actions::span_start); + member_action<syntax_highlight_actions> + span_end(self.actions, &syntax_highlight_actions::span_end), + unexpected_char(self.actions, &syntax_highlight_actions::unexpected_char), + plain_char(self.actions, &syntax_highlight_actions::plain_char), + pre_escape_back(self.actions, &syntax_highlight_actions::pre_escape_back), + post_escape_back(self.actions, &syntax_highlight_actions::post_escape_back), + mark_text(self.actions, &syntax_highlight_actions::mark_text), + callout(self.actions, &syntax_highlight_actions::callout); + member_action_value<syntax_highlight_actions, std::string const&> + do_macro(self.actions, &syntax_highlight_actions::do_macro); + error_action error(self.actions.state); + program = - *( (+cl::space_p) [plain_char(self.out)] + *( (+cl::space_p) [plain_char] | macro | escape - | preprocessor [span("preprocessor", self.out)] + | preprocessor [span("preprocessor")] + | cl::eps_p(ph::var(self.actions.support_callouts)) + >> ( line_callout [callout] + | inline_callout [callout] + ) | comment - | keyword [span("keyword", self.out)] - | identifier [span("identifier", self.out)] - | special [span("special", self.out)] - | string_ [span("string", self.out)] - | char_ [span("char", self.out)] - | number [span("number", self.out)] - | cl::repeat_p(1)[cl::anychar_p] - [unexpected_char(self.out, self.escape_actions)] + | keyword [span("keyword")] + | identifier [span("identifier")] + | special [span("special")] + | string_ [span("string")] + | char_ [span("char")] + | number [span("number")] + | u8_codepoint_p [unexpected_char] ) ; macro = // must not be followed by alpha or underscore - cl::eps_p(self.escape_actions.macro + cl::eps_p(self.actions.state.macro >> (cl::eps_p - (cl::alpha_p | '_'))) - >> self.escape_actions.macro [do_macro_action(self.out, self.escape_actions)] + >> self.actions.state.macro + [do_macro] ; escape = - cl::str_p("``") [pre_escape_back(self.escape_actions)] + cl::str_p("``") [pre_escape_back] >> ( ( @@ -275,29 +312,46 @@ namespace quickbook ) | ( - cl::eps_p [self.escape_actions.error] + cl::eps_p [error] >> *cl::anychar_p ) - ) [post_escape_back(self.out, self.escape_actions)] + ) [post_escape_back] ; preprocessor = '#' >> *cl::space_p >> ((cl::alpha_p | '_') >> *(cl::alnum_p | '_')) ; + inline_callout + = cl::confix_p( + "/*<" >> *cl::space_p, + (*cl::anychar_p) [mark_text], + ">*/" + ) + ; + + line_callout + = cl::confix_p( + "/*<<" >> *cl::space_p, + (*cl::anychar_p) [mark_text], + ">>*/" + ) + >> *cl::space_p + ; + comment - = cl::str_p("//") [span_start("comment", self.out)] + = cl::str_p("//") [span_start("comment")] >> *( escape | (+(cl::anychar_p - (cl::eol_p | "``"))) - [plain_char(self.out)] + [plain_char] ) - >> cl::eps_p [span_end(self.out)] - | cl::str_p("/*") [span_start("comment", self.out)] + >> cl::eps_p [span_end] + | cl::str_p("/*") [span_start("comment")] >> *( escape | (+(cl::anychar_p - (cl::str_p("*/") | "``"))) - [plain_char(self.out)] + [plain_char] ) - >> (!cl::str_p("*/")) [span_end(self.out)] + >> (!cl::str_p("*/")) [span_end] ; keyword @@ -308,7 +362,7 @@ namespace quickbook = +cl::chset_p("~!%^&*()+={[}]:;,<.>?/|\\-") ; - string_char = ('\\' >> cl::anychar_p) | (cl::anychar_p - '\\'); + string_char = ('\\' >> u8_codepoint_p) | (cl::anychar_p - '\\'); string_ = !cl::as_lower_d['l'] >> cl::confix_p('"', *string_char, '"') @@ -333,7 +387,9 @@ namespace quickbook } cl::rule<Scanner> - program, macro, preprocessor, comment, special, string_, + program, macro, preprocessor, + inline_callout, line_callout, comment, + special, string_, char_, number, identifier, keyword, escape, string_char; @@ -343,50 +399,63 @@ namespace quickbook start() const { return program; } }; - collector& out; - actions& escape_actions; + syntax_highlight_actions& actions; }; // Grammar for Python highlighting // See also: The Python Reference Manual // http://docs.python.org/ref/ref.html - struct python_highlight - : public cl::grammar<python_highlight> + struct python_highlight : public cl::grammar<python_highlight> { - python_highlight(collector& out, actions& escape_actions) - : out(out), escape_actions(escape_actions) {} + python_highlight(syntax_highlight_actions& actions) + : actions(actions) {} template <typename Scanner> struct definition { definition(python_highlight const& self) - : g(self.escape_actions.grammar()) + : g(self.actions.state.grammar()) { + member_action1<syntax_highlight_actions, char const*> + span(self.actions, &syntax_highlight_actions::span), + span_start(self.actions, &syntax_highlight_actions::span_start); + member_action<syntax_highlight_actions> + span_end(self.actions, &syntax_highlight_actions::span_end), + unexpected_char(self.actions, &syntax_highlight_actions::unexpected_char), + plain_char(self.actions, &syntax_highlight_actions::plain_char), + pre_escape_back(self.actions, &syntax_highlight_actions::pre_escape_back), + post_escape_back(self.actions, &syntax_highlight_actions::post_escape_back), + mark_text(self.actions, &syntax_highlight_actions::mark_text), + callout(self.actions, &syntax_highlight_actions::callout); + member_action_value<syntax_highlight_actions, std::string const&> + do_macro(self.actions, &syntax_highlight_actions::do_macro); + error_action error(self.actions.state); + program = - *( (+cl::space_p) [plain_char(self.out)] + *( (+cl::space_p) [plain_char] | macro | escape | comment - | keyword [span("keyword", self.out)] - | identifier [span("identifier", self.out)] - | special [span("special", self.out)] - | string_ [span("string", self.out)] - | number [span("number", self.out)] - | cl::repeat_p(1)[cl::anychar_p] - [unexpected_char(self.out, self.escape_actions)] + | keyword [span("keyword")] + | identifier [span("identifier")] + | special [span("special")] + | string_ [span("string")] + | number [span("number")] + | u8_codepoint_p [unexpected_char] ) ; macro = // must not be followed by alpha or underscore - cl::eps_p(self.escape_actions.macro + cl::eps_p(self.actions.state.macro >> (cl::eps_p - (cl::alpha_p | '_'))) - >> self.escape_actions.macro [do_macro_action(self.out, self.escape_actions)] + >> self.actions.state.macro + [do_macro] ; escape = - cl::str_p("``") [pre_escape_back(self.escape_actions)] + cl::str_p("``") [pre_escape_back] >> ( ( @@ -398,19 +467,19 @@ namespace quickbook ) | ( - cl::eps_p [self.escape_actions.error] + cl::eps_p [error] >> *cl::anychar_p ) - ) [post_escape_back(self.out, self.escape_actions)] + ) [post_escape_back] ; comment - = cl::str_p("#") [span_start("comment", self.out)] + = cl::str_p("#") [span_start("comment")] >> *( escape | (+(cl::anychar_p - (cl::eol_p | "``"))) - [plain_char(self.out)] + [plain_char] ) - >> cl::eps_p [span_end(self.out)] + >> cl::eps_p [span_end] ; keyword @@ -429,7 +498,7 @@ namespace quickbook = ! string_prefix >> (long_string | short_string) ; - string_char = ('\\' >> cl::anychar_p) | (cl::anychar_p - '\\'); + string_char = ('\\' >> u8_codepoint_p) | (cl::anychar_p - '\\'); short_string = cl::confix_p('\'', * string_char, '\'') | @@ -468,40 +537,47 @@ namespace quickbook start() const { return program; } }; - collector& out; - actions& escape_actions; + syntax_highlight_actions& actions; }; // Grammar for plain text (no actual highlighting) - struct teletype_highlight - : public cl::grammar<teletype_highlight> + struct teletype_highlight : public cl::grammar<teletype_highlight> { - teletype_highlight(collector& out, actions& escape_actions) - : out(out), escape_actions(escape_actions) {} + teletype_highlight(syntax_highlight_actions& actions) + : actions(actions) {} template <typename Scanner> struct definition { definition(teletype_highlight const& self) - : g(self.escape_actions.grammar()) + : g(self.actions.state.grammar()) { + member_action<syntax_highlight_actions> + plain_char(self.actions, &syntax_highlight_actions::plain_char), + pre_escape_back(self.actions, &syntax_highlight_actions::pre_escape_back), + post_escape_back(self.actions, &syntax_highlight_actions::post_escape_back); + member_action_value<syntax_highlight_actions, std::string const&> + do_macro(self.actions, &syntax_highlight_actions::do_macro); + error_action error(self.actions.state); + program = *( macro | escape - | cl::repeat_p(1)[cl::anychar_p] [plain_char(self.out)] + | u8_codepoint_p [plain_char] ) ; macro = // must not be followed by alpha or underscore - cl::eps_p(self.escape_actions.macro + cl::eps_p(self.actions.state.macro >> (cl::eps_p - (cl::alpha_p | '_'))) - >> self.escape_actions.macro [do_macro_action(self.out, self.escape_actions)] + >> self.actions.state.macro + [do_macro] ; escape = - cl::str_p("``") [pre_escape_back(self.escape_actions)] + cl::str_p("``") [pre_escape_back] >> ( ( @@ -513,10 +589,10 @@ namespace quickbook ) | ( - cl::eps_p [self.escape_actions.error] + cl::eps_p [error] >> *cl::anychar_p ) - ) [post_escape_back(self.out, self.escape_actions)] + ) [post_escape_back] ; } @@ -528,32 +604,32 @@ namespace quickbook start() const { return program; } }; - collector& out; - actions& escape_actions; + syntax_highlight_actions& actions; }; std::string syntax_highlight( parse_iterator first, parse_iterator last, - actions& escape_actions, - std::string const& source_mode) + quickbook::state& state, + std::string const& source_mode, + bool is_block) { - quickbook::collector temp; + syntax_highlight_actions syn_actions(state, is_block); // print the code with syntax coloring if (source_mode == "c++") { - cpp_highlight cpp_p(temp, escape_actions); + cpp_highlight cpp_p(syn_actions); boost::spirit::classic::parse(first, last, cpp_p); } else if (source_mode == "python") { - python_highlight python_p(temp, escape_actions); + python_highlight python_p(syn_actions); boost::spirit::classic::parse(first, last, python_p); } else if (source_mode == "teletype") { - teletype_highlight teletype_p(temp, escape_actions); + teletype_highlight teletype_p(syn_actions); boost::spirit::classic::parse(first, last, teletype_p); } else @@ -562,7 +638,7 @@ namespace quickbook } std::string str; - temp.swap(str); + syn_actions.out.swap(str); return str; } diff --git a/tools/quickbook/src/utils.cpp b/tools/quickbook/src/utils.cpp index 0defe6d182..3a5ee42e4d 100644 --- a/tools/quickbook/src/utils.cpp +++ b/tools/quickbook/src/utils.cpp @@ -62,23 +62,4 @@ namespace quickbook { namespace detail } return uri; } - - file_type get_file_type(std::string const& extension) - { - static std::map<std::string, file_type> ftypes; - if (ftypes.empty()) - { - // init the map of types - ftypes["cpp"] = cpp_file; - ftypes["hpp"] = cpp_file; - ftypes["h"] = cpp_file; - ftypes["c"] = cpp_file; - ftypes["cxx"] = cpp_file; - ftypes["hxx"] = cpp_file; - ftypes["ipp"] = cpp_file; - ftypes["py"] = python_file; - } - return ftypes[extension]; - } - }} diff --git a/tools/quickbook/src/utils.hpp b/tools/quickbook/src/utils.hpp index e7afa05e1b..9170f81043 100644 --- a/tools/quickbook/src/utils.hpp +++ b/tools/quickbook/src/utils.hpp @@ -33,17 +33,6 @@ namespace quickbook { namespace detail { } std::string escape_uri(std::string uri); - - // given a file extension, return the type of the source file - // we'll have an internal database for known file types. - - enum file_type - { - cpp_file - , python_file - }; - - file_type get_file_type(std::string const& extension); }} #endif // BOOST_SPIRIT_QUICKBOOK_UTILS_HPP diff --git a/tools/quickbook/src/values.cpp b/tools/quickbook/src/values.cpp index 7c3521d50b..904cc8b38f 100644 --- a/tools/quickbook/src/values.cpp +++ b/tools/quickbook/src/values.cpp @@ -765,6 +765,11 @@ namespace quickbook back_ = merge_sort(&head_); assert(*back_ == &value_list_end_impl::instance); } + + bool value_list_builder::empty() const + { + return head_ == &value_list_end_impl::instance; + } } ////////////////////////////////////////////////////////////////////////// @@ -799,16 +804,6 @@ namespace quickbook return value(new detail::value_list_impl(current, list_tag)); } - void value_builder::reset() { - detail::value_list_builder new_builder; - current.swap(new_builder); - list_tag = value::default_tag; - } - - void value_builder::set_tag(value::tag_type tag) { - list_tag = tag; - } - void value_builder::insert(value const& item) { current.append(item.value_); } @@ -822,9 +817,8 @@ namespace quickbook } void value_builder::start_list(value::tag_type tag) { - value::tag_type saved_tag = tag; save(); - list_tag = saved_tag; + list_tag = tag; } void value_builder::finish_list() { @@ -842,6 +836,11 @@ namespace quickbook current.sort(); } + bool value_builder::empty() const + { + return current.empty(); + } + //////////////////////////////////////////////////////////////////////////// // Iterator diff --git a/tools/quickbook/src/values.hpp b/tools/quickbook/src/values.hpp index 2380b0d5dc..d637ea2adb 100644 --- a/tools/quickbook/src/values.hpp +++ b/tools/quickbook/src/values.hpp @@ -211,6 +211,8 @@ namespace quickbook void append(value_node*); void sort(); + + bool empty() const; private: value_node* head_; value_node** back_; @@ -269,8 +271,6 @@ namespace quickbook value release(); - void reset(); - void set_tag(value::tag_type); void insert(value const&); void extend(value const&); @@ -279,6 +279,8 @@ namespace quickbook void clear_list(); void sort_list(); + bool empty() const; + private: detail::value_list_builder current; value::tag_type list_tag; diff --git a/tools/quickbook/test/Jamfile.v2 b/tools/quickbook/test/Jamfile.v2 index fca35b5be4..900b4758a2 100644 --- a/tools/quickbook/test/Jamfile.v2 +++ b/tools/quickbook/test/Jamfile.v2 @@ -26,6 +26,7 @@ test-suite quickbook.test : [ quickbook-test anchor-1_6 ] [ quickbook-test blocks-1_5 ] [ quickbook-test callouts-1_5 ] + [ quickbook-test callouts-1_7 ] [ quickbook-test code-1_1 ] [ quickbook-test code-1_5 ] [ quickbook-test code_cpp-1_5 ] @@ -34,6 +35,7 @@ test-suite quickbook.test : [ quickbook-error-test code_python_mismatched_escape-1_4-fail ] [ quickbook-test code_snippet-1_1 ] [ quickbook-test code_teletype-1_5 ] + [ quickbook-error-test code_unclosed_block-1_6-fail ] [ quickbook-test command_line_macro-1_1 : : : <quickbook-test-define>__macro__=*bold* <quickbook-test-define>__empty__ ] @@ -65,6 +67,7 @@ test-suite quickbook.test : [ quickbook-error-test include_win_path-1_6-fail ] [ quickbook-test link-1_1 ] [ quickbook-test link-1_6 ] + [ quickbook-test link-1_7 ] [ quickbook-test list_test-1_5 ] [ quickbook-test list_test-1_6 ] [ quickbook-test macro-1_5 ] @@ -82,6 +85,7 @@ test-suite quickbook.test : [ quickbook-test section-1_5-unclosed ] [ quickbook-test section-1_5 ] [ quickbook-test simple_markup-1_5 ] + [ quickbook-test source_mode-1_7 ] [ quickbook-test svg-1_1 ] [ quickbook-test table-1_3 ] [ quickbook-test table-1_5 ] @@ -106,7 +110,7 @@ test-suite quickbook.test : [ quickbook-error-test variablelist-1_5-fail ] [ quickbook-test variablelist-1_5 ] [ quickbook-error-test version-0_1-fail ] - [ quickbook-error-test version-1_7-fail ] + [ quickbook-error-test version-1_8-fail ] [ quickbook-error-test version-2_0-fail ] [ quickbook-test xml_escape-1_2 ] [ quickbook-test xml_escape-1_5 ] diff --git a/tools/quickbook/test/callouts-1_7.gold b/tools/quickbook/test/callouts-1_7.gold new file mode 100644 index 0000000000..5cf0dc59ef --- /dev/null +++ b/tools/quickbook/test/callouts-1_7.gold @@ -0,0 +1,247 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE article PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd"> +<article id="callout_tests" last-revision="DEBUG MODE Date: 2000/12/20 12:00:00 $" + xmlns:xi="http://www.w3.org/2001/XInclude"> + <title>Callout Tests</title> + <para> + Example 1: + </para> + <para> + Now we can define a function that simulates an ordinary six-sided die. + </para> +<programlisting><phrase role="keyword">int</phrase> <phrase role="identifier">roll_die</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase> + <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int</phrase><phrase role="special"><></phrase> <phrase role="identifier">dist</phrase><phrase role="special">(</phrase><phrase role="number">1</phrase><phrase role="special">,</phrase> <phrase role="number">6</phrase><phrase role="special">);</phrase> <co id="callout_tests.c0" linkends="callout_tests.c1" /> +<phrase role="special">}</phrase> +</programlisting> + <calloutlist> + <callout arearefs="callout_tests.c0" id="callout_tests.c1"> + <para> + create a uniform_int distribution + </para> + </callout> + </calloutlist> + <para> + Example 2: + </para> +<programlisting><phrase role="keyword">int</phrase> <phrase role="identifier">roll_die</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase> + <co id="callout_tests.c2" linkends="callout_tests.c3" /><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">variate_generator</phrase><phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">mt19937</phrase><phrase role="special">&,</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int</phrase><phrase role="special"><></phrase> <phrase role="special">></phrase> <phrase role="identifier">die</phrase><phrase role="special">(</phrase><phrase role="identifier">gen</phrase><phrase role="special">,</phrase> <phrase role="identifier">dist</phrase><phrase role="special">);</phrase> +<phrase role="special">}</phrase> +</programlisting> + <calloutlist> + <callout arearefs="callout_tests.c2" id="callout_tests.c3"> + <important> + <para> + test + </para> + </important> + </callout> + </calloutlist> + <para> + Example 3: + </para> +<programlisting><phrase role="keyword">int</phrase> <phrase role="identifier">roll_die</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase> + <co id="callout_tests.c4" linkends="callout_tests.c5" /><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">variate_generator</phrase><phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">mt19937</phrase><phrase role="special">&,</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int</phrase><phrase role="special"><></phrase> <phrase role="special">></phrase> <phrase role="identifier">die</phrase><phrase role="special">(</phrase><phrase role="identifier">gen</phrase><phrase role="special">,</phrase> <phrase role="identifier">dist</phrase><phrase role="special">);</phrase> +<phrase role="special">}</phrase> +</programlisting> + <calloutlist> + <callout arearefs="callout_tests.c4" id="callout_tests.c5"> + <important> + <para> + test + </para> + </important> + </callout> + </calloutlist> + <para> + Example 3 (again!): + </para> +<programlisting><phrase role="keyword">int</phrase> <phrase role="identifier">roll_die</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase> + <co id="callout_tests.c6" linkends="callout_tests.c7" /><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">variate_generator</phrase><phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">mt19937</phrase><phrase role="special">&,</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int</phrase><phrase role="special"><></phrase> <phrase role="special">></phrase> <phrase role="identifier">die</phrase><phrase role="special">(</phrase><phrase role="identifier">gen</phrase><phrase role="special">,</phrase> <phrase role="identifier">dist</phrase><phrase role="special">);</phrase> +<phrase role="special">}</phrase> +</programlisting> + <calloutlist> + <callout arearefs="callout_tests.c6" id="callout_tests.c7"> + <important> + <para> + test + </para> + </important> + </callout> + </calloutlist> + <para> + Example 4: + </para> +<programlisting><phrase role="keyword">int</phrase> <phrase role="identifier">roll_die</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase> + <co id="callout_tests.c8" linkends="callout_tests.c9" /><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">variate_generator</phrase><phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">mt19937</phrase><phrase role="special">&,</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int</phrase><phrase role="special"><></phrase> <phrase role="special">></phrase> <phrase role="identifier">die</phrase><phrase role="special">(</phrase><phrase role="identifier">gen</phrase><phrase role="special">,</phrase> <phrase role="identifier">dist</phrase><phrase role="special">);</phrase> + <co id="callout_tests.c10" linkends="callout_tests.c11" /><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int</phrase><phrase role="special"><></phrase> <phrase role="identifier">dist</phrase><phrase role="special">(</phrase><phrase role="number">1</phrase><phrase role="special">,</phrase> <phrase role="number">6</phrase><phrase role="special">);</phrase> <co id="callout_tests.c12" linkends="callout_tests.c13" /> +<phrase role="special">}</phrase> +</programlisting> + <calloutlist> + <callout arearefs="callout_tests.c8" id="callout_tests.c9"> + <para> + callout 1 + </para> + </callout> + <callout arearefs="callout_tests.c10" id="callout_tests.c11"> + <para> + callout 2 + </para> + </callout> + <callout arearefs="callout_tests.c12" id="callout_tests.c13"> + <para> + create a uniform_int distribution + </para> + </callout> + </calloutlist> +<programlisting><co id="callout_tests.c14" linkends="callout_tests.c15" /><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int</phrase><phrase role="special"><></phrase> <phrase role="identifier">dist</phrase><phrase role="special">(</phrase><phrase role="number">1</phrase><phrase role="special">,</phrase> <phrase role="number">6</phrase><phrase role="special">);</phrase> <co id="callout_tests.c16" linkends="callout_tests.c17" /> +</programlisting> + <calloutlist> + <callout arearefs="callout_tests.c14" id="callout_tests.c15"> + <para> + callout 2 + </para> + </callout> + <callout arearefs="callout_tests.c16" id="callout_tests.c17"> + <para> + create a uniform_int distribution + </para> + </callout> + </calloutlist> + <section id="callout_tests.test_section"> + <title><link linkend="callout_tests.test_section">Try callouts in a section</link></title> + <para> + Example 1: + </para> + <para> + Now we can define a function that simulates an ordinary six-sided die. + </para> +<programlisting><phrase role="keyword">int</phrase> <phrase role="identifier">roll_die</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase> + <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int</phrase><phrase role="special"><></phrase> <phrase role="identifier">dist</phrase><phrase role="special">(</phrase><phrase role="number">1</phrase><phrase role="special">,</phrase> <phrase role="number">6</phrase><phrase role="special">);</phrase> <co id="callout_tests.test_section.c0" linkends="callout_tests.test_section.c1" /> +<phrase role="special">}</phrase> +</programlisting> + <calloutlist> + <callout arearefs="callout_tests.test_section.c0" id="callout_tests.test_section.c1"> + <para> + create a uniform_int distribution + </para> + </callout> + </calloutlist> + <para> + Example 2: + </para> +<programlisting><phrase role="keyword">int</phrase> <phrase role="identifier">roll_die</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase> + <co id="callout_tests.test_section.c2" linkends="callout_tests.test_section.c3" /><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">variate_generator</phrase><phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">mt19937</phrase><phrase role="special">&,</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int</phrase><phrase role="special"><></phrase> <phrase role="special">></phrase> <phrase role="identifier">die</phrase><phrase role="special">(</phrase><phrase role="identifier">gen</phrase><phrase role="special">,</phrase> <phrase role="identifier">dist</phrase><phrase role="special">);</phrase> +<phrase role="special">}</phrase> +</programlisting> + <calloutlist> + <callout arearefs="callout_tests.test_section.c2" id="callout_tests.test_section.c3"> + <important> + <para> + test + </para> + </important> + </callout> + </calloutlist> + <para> + Example 3: + </para> +<programlisting><phrase role="keyword">int</phrase> <phrase role="identifier">roll_die</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase> + <co id="callout_tests.test_section.c4" linkends="callout_tests.test_section.c5" /><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">variate_generator</phrase><phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">mt19937</phrase><phrase role="special">&,</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int</phrase><phrase role="special"><></phrase> <phrase role="special">></phrase> <phrase role="identifier">die</phrase><phrase role="special">(</phrase><phrase role="identifier">gen</phrase><phrase role="special">,</phrase> <phrase role="identifier">dist</phrase><phrase role="special">);</phrase> +<phrase role="special">}</phrase> +</programlisting> + <calloutlist> + <callout arearefs="callout_tests.test_section.c4" id="callout_tests.test_section.c5"> + <important> + <para> + test + </para> + </important> + </callout> + </calloutlist> + <para> + Example 3 (again!): + </para> +<programlisting><phrase role="keyword">int</phrase> <phrase role="identifier">roll_die</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase> + <co id="callout_tests.test_section.c6" linkends="callout_tests.test_section.c7" /><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">variate_generator</phrase><phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">mt19937</phrase><phrase role="special">&,</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int</phrase><phrase role="special"><></phrase> <phrase role="special">></phrase> <phrase role="identifier">die</phrase><phrase role="special">(</phrase><phrase role="identifier">gen</phrase><phrase role="special">,</phrase> <phrase role="identifier">dist</phrase><phrase role="special">);</phrase> +<phrase role="special">}</phrase> +</programlisting> + <calloutlist> + <callout arearefs="callout_tests.test_section.c6" id="callout_tests.test_section.c7"> + <important> + <para> + test + </para> + </important> + </callout> + </calloutlist> + <para> + Example 4: + </para> +<programlisting><phrase role="keyword">int</phrase> <phrase role="identifier">roll_die</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase> + <co id="callout_tests.test_section.c8" linkends="callout_tests.test_section.c9" /><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">variate_generator</phrase><phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">mt19937</phrase><phrase role="special">&,</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int</phrase><phrase role="special"><></phrase> <phrase role="special">></phrase> <phrase role="identifier">die</phrase><phrase role="special">(</phrase><phrase role="identifier">gen</phrase><phrase role="special">,</phrase> <phrase role="identifier">dist</phrase><phrase role="special">);</phrase> + <co id="callout_tests.test_section.c10" linkends="callout_tests.test_section.c11" /><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int</phrase><phrase role="special"><></phrase> <phrase role="identifier">dist</phrase><phrase role="special">(</phrase><phrase role="number">1</phrase><phrase role="special">,</phrase> <phrase role="number">6</phrase><phrase role="special">);</phrase> <co id="callout_tests.test_section.c12" linkends="callout_tests.test_section.c13" /> +<phrase role="special">}</phrase> +</programlisting> + <calloutlist> + <callout arearefs="callout_tests.test_section.c8" id="callout_tests.test_section.c9"> + <para> + callout 1 + </para> + </callout> + <callout arearefs="callout_tests.test_section.c10" id="callout_tests.test_section.c11"> + <para> + callout 2 + </para> + </callout> + <callout arearefs="callout_tests.test_section.c12" id="callout_tests.test_section.c13"> + <para> + create a uniform_int distribution + </para> + </callout> + </calloutlist> +<programlisting><co id="callout_tests.test_section.c14" linkends="callout_tests.test_section.c15" /><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int</phrase><phrase role="special"><></phrase> <phrase role="identifier">dist</phrase><phrase role="special">(</phrase><phrase role="number">1</phrase><phrase role="special">,</phrase> <phrase role="number">6</phrase><phrase role="special">);</phrase> <co id="callout_tests.test_section.c16" linkends="callout_tests.test_section.c17" /> +</programlisting> + <calloutlist> + <callout arearefs="callout_tests.test_section.c14" id="callout_tests.test_section.c15"> + <para> + callout 2 + </para> + </callout> + <callout arearefs="callout_tests.test_section.c16" id="callout_tests.test_section.c17"> + <para> + create a uniform_int distribution + </para> + </callout> + </calloutlist> + </section> + <section id="callout_tests.blocks"> + <title><link linkend="callout_tests.blocks">Callouts in code blocks</link></title> +<programlisting><phrase role="keyword">int</phrase> <phrase role="identifier">roll_die</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase> + <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int</phrase><phrase role="special"><></phrase> <phrase role="identifier">dist</phrase><phrase role="special">(</phrase><phrase role="number">1</phrase><phrase role="special">,</phrase> <phrase role="number">6</phrase><phrase role="special">);</phrase> <co id="callout_tests.blocks.c0" linkends="callout_tests.blocks.c1" /> +<phrase role="special">}</phrase> +</programlisting> + <calloutlist> + <callout arearefs="callout_tests.blocks.c0" id="callout_tests.blocks.c1"> + <para> + create a uniform_int distribution + </para> + </callout> + </calloutlist> +<programlisting><phrase role="keyword">int</phrase> <phrase role="identifier">roll_die</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase> + <co id="callout_tests.blocks.c2" linkends="callout_tests.blocks.c3" /><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">variate_generator</phrase><phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">mt19937</phrase><phrase role="special">&,</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int</phrase><phrase role="special"><></phrase> <phrase role="special">></phrase> <phrase role="identifier">die</phrase><phrase role="special">(</phrase><phrase role="identifier">gen</phrase><phrase role="special">,</phrase> <phrase role="identifier">dist</phrase><phrase role="special">);</phrase> +<phrase role="special">}</phrase> +</programlisting> + <calloutlist> + <callout arearefs="callout_tests.blocks.c2" id="callout_tests.blocks.c3"> + <important> + <para> + test + </para> + </important> + </callout> + </calloutlist> + <para> + <code><phrase role="comment">/*< This shouldn't be a callout >*/</phrase></code> + </para> + </section> +</article> diff --git a/tools/quickbook/test/callouts-1_7.quickbook b/tools/quickbook/test/callouts-1_7.quickbook new file mode 100644 index 0000000000..fd3d9ee8b8 --- /dev/null +++ b/tools/quickbook/test/callouts-1_7.quickbook @@ -0,0 +1,68 @@ +[article Callout Tests + [quickbook 1.7] +] + +[import callouts.cpp] + +Example 1: + +[example1] + +Example 2: + +[example2] + +Example 3: + +[example3] + +Example 3 (again!): + +[example3] + +Example 4: + +[example4] +[example4a] + +[section:test_section Try callouts in a section] + +Example 1: + +[example1] + +Example 2: + +[example2] + +Example 3: + +[example3] + +Example 3 (again!): + +[example3] + +Example 4: + +[example4] +[example4a] + +[endsect] + +[section:blocks Callouts in code blocks] + + int roll_die() { + boost::uniform_int<> dist(1, 6); /*< create a uniform_int distribution >*/ + } + +``` +int roll_die() { + /*<< [important test] >>*/ + boost::variate_generator<boost::mt19937&, boost::uniform_int<> > die(gen, dist); +} +``` + +`/*< This shouldn't be a callout >*/` + +[endsect]
\ No newline at end of file diff --git a/tools/quickbook/test/code_unclosed_block-1_6-fail.quickbook b/tools/quickbook/test/code_unclosed_block-1_6-fail.quickbook new file mode 100644 index 0000000000..f02887c440 --- /dev/null +++ b/tools/quickbook/test/code_unclosed_block-1_6-fail.quickbook @@ -0,0 +1,4 @@ +[article Odd code markup. [quickbook 1.6] ] + +`` +int main() {} diff --git a/tools/quickbook/test/doc-info/Jamfile.v2 b/tools/quickbook/test/doc-info/Jamfile.v2 index f7d262c050..9d4913b81c 100644 --- a/tools/quickbook/test/doc-info/Jamfile.v2 +++ b/tools/quickbook/test/doc-info/Jamfile.v2 @@ -16,6 +16,8 @@ test-suite quickbook.test : [ quickbook-test author1 ] [ quickbook-test author2 ] [ quickbook-test empty-attributes ] + [ quickbook-test escaped_attributes1-1_7 ] + [ quickbook-test escaped_attributes2-1_7 ] [ quickbook-test duplicates-1.1 ] [ quickbook-test duplicates-1.5 ] [ quickbook-test source-mode-1.4 ] diff --git a/tools/quickbook/test/doc-info/escaped_attributes1-1_7.gold b/tools/quickbook/test/doc-info/escaped_attributes1-1_7.gold new file mode 100644 index 0000000000..b6425d910e --- /dev/null +++ b/tools/quickbook/test/doc-info/escaped_attributes1-1_7.gold @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd"> +<library id="escaped_name" name="Escaped name" dirname="escaped_name" last-revision="DEBUG MODE Date: 2000/12/20 12:00:00 $" + xmlns:xi="http://www.w3.org/2001/XInclude"> + <libraryinfo> + <copyright> + <year>1325</year> <holder>John Doe</holder> + </copyright> + <librarycategory name="category:test"></librarycategory> <author> + <firstname>John</firstname> + <surname>Doe</surname> + <email>john.doe@example.com</email> +</author> + </libraryinfo> + <title>Escaped name</title> +</library> diff --git a/tools/quickbook/test/doc-info/escaped_attributes1-1_7.quickbook b/tools/quickbook/test/doc-info/escaped_attributes1-1_7.quickbook new file mode 100644 index 0000000000..e701613751 --- /dev/null +++ b/tools/quickbook/test/doc-info/escaped_attributes1-1_7.quickbook @@ -0,0 +1,11 @@ +[library Escaped name +[quickbook 1.7] +[copyright 1325 John Doe] +'''<author> + <firstname>John</firstname> + <surname>Doe</surname> + <email>john.doe@example.com</email> +</author>''' +[category test] +] + diff --git a/tools/quickbook/test/doc-info/escaped_attributes2-1_7.gold b/tools/quickbook/test/doc-info/escaped_attributes2-1_7.gold new file mode 100644 index 0000000000..259111ac43 --- /dev/null +++ b/tools/quickbook/test/doc-info/escaped_attributes2-1_7.gold @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE article PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd"> +<article id="multiple_escaped_attributes" last-revision="DEBUG MODE Date: 2000/12/20 12:00:00 $" + xmlns:xi="http://www.w3.org/2001/XInclude"> + <title>Multiple escaped attributes</title> + <articleinfo> + <author> + <firstname>John</firstname> + <surname>Doe</surname> + <email>john.doe@example.com</email> +</author><orgname>Acme Corporation</orgname></articleinfo> +</article> diff --git a/tools/quickbook/test/doc-info/escaped_attributes2-1_7.quickbook b/tools/quickbook/test/doc-info/escaped_attributes2-1_7.quickbook new file mode 100644 index 0000000000..70676f8a16 --- /dev/null +++ b/tools/quickbook/test/doc-info/escaped_attributes2-1_7.quickbook @@ -0,0 +1,10 @@ +[article Multiple escaped attributes +[quickbook 1.7] +'''<author> + <firstname>John</firstname> + <surname>Doe</surname> + <email>john.doe@example.com</email> +</author>''' +'''<orgname>Acme Corporation</orgname>''' +] + diff --git a/tools/quickbook/test/link-1_7.gold b/tools/quickbook/test/link-1_7.gold new file mode 100644 index 0000000000..f3eec12e74 --- /dev/null +++ b/tools/quickbook/test/link-1_7.gold @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE article PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd"> +<article id="link_tests" last-revision="DEBUG MODE Date: 2000/12/20 12:00:00 $" xmlns:xi="http://www.w3.org/2001/XInclude"> + <title>Link tests</title> + <section id="link_tests.different_types_of_links"> + <title><link linkend="link_tests.different_types_of_links">Different types of + links</link></title> + <para> + <ulink url="http://www.boost.org/">http://www.boost.org/</ulink> <ulink url="http://www.boost.org/">Boost</ulink> + <link linkend="link-id">link-id</link> <link linkend="link-id">Link Text</link> + <anchor id="link-id"/><functionname alt="foo">foo</functionname> <functionname + alt="foo">link text</functionname> <classname alt="foo">foo</classname> <classname + alt="foo">link text</classname> <methodname alt="foo">foo</methodname> <methodname + alt="foo">link text</methodname> <enumname alt="foo">foo</enumname> <enumname + alt="foo">link text</enumname> <macroname alt="foo">foo</macroname> <macroname + alt="foo">link text</macroname> <headername alt="foo">foo</headername> <headername + alt="foo">link text</headername> <conceptname alt="foo">foo</conceptname> + <conceptname alt="foo">link text</conceptname> <globalname alt="foo">foo</globalname> + <globalname alt="foo">link text</globalname> + </para> + <para> + <link linkend="link">description</link> + </para> + <para> + <link linkend="link[Hello]">description</link> + </para> + </section> + <section id="link_tests.side_by_side_links"> + <title><link linkend="link_tests.side_by_side_links">Side-by-side links</link></title> + <para> + <link linkend="x">x</link> and <link linkend="y">y</link> are two distinct + links, which should be separated by whitespace when they appear together as + in <link linkend="x">x</link> <link linkend="y">y</link>. Also in <link linkend="x">x</link> + <link linkend="y">y</link>, and in <link linkend="x">x</link> <link linkend="y">y</link> + as well. + </para> + </section> + <section id="link_tests.templates_is_links"> + <title><link linkend="link_tests.templates_is_links">Templates is links....</link></title> + <para> + <link linkend="blah.x2">Templated link?</link> + </para> + </section> +</article> diff --git a/tools/quickbook/test/link-1_7.quickbook b/tools/quickbook/test/link-1_7.quickbook new file mode 100644 index 0000000000..8e146b9706 --- /dev/null +++ b/tools/quickbook/test/link-1_7.quickbook @@ -0,0 +1,52 @@ +[article Link tests +[quickbook 1.7] +] + +[section Different types of links] + +[@http://www.boost.org/] +[@ http://www.boost.org/ Boost] +[link link-id] +[link link-id Link Text] +[#link-id] +[funcref foo] +[funcref foo link text] +[classref foo] +[classref foo link text] +[memberref foo] +[memberref foo link text] +[enumref foo] +[enumref foo link text] +[macroref foo] +[macroref foo link text] +[headerref foo] +[headerref foo link text] +[conceptref foo] +[conceptref foo link text] +[globalref foo] +[globalref foo link text] + +[link link[/ comment]description] + +[link link\[Hello\] description] + + +[endsect] + +[section Side-by-side links] + +[link x] and [link y] are two distinct links, which should be separated by +whitespace when they appear together as in [link x] [link y]. Also in [link x] +[link y], and in +[link x] +[link y] +as well. + +[endsect] + +[section Templates is links....] + +[template thing[]x] +[link blah.[thing]2 Templated link?] + +[endsect] diff --git a/tools/quickbook/test/list_test-1_5.gold b/tools/quickbook/test/list_test-1_5.gold index a1b44d829e..4d25aa7cce 100644 --- a/tools/quickbook/test/list_test-1_5.gold +++ b/tools/quickbook/test/list_test-1_5.gold @@ -383,4 +383,20 @@ </listitem> </itemizedlist> </section> + <section id="list_test.list_immediately_following_markup_2"> + <title><link linkend="list_test.list_immediately_following_markup_2">List immediately + following markup 2</link></title> + <itemizedlist> + <listitem> + <simpara> + One [section Nested section] + </simpara> + </listitem> + <listitem> + <simpara> + Two [endsect] + </simpara> + </listitem> + </itemizedlist> + </section> </article> diff --git a/tools/quickbook/test/list_test-1_5.quickbook b/tools/quickbook/test/list_test-1_5.quickbook index ab78e6f588..64b391a614 100644 --- a/tools/quickbook/test/list_test-1_5.quickbook +++ b/tools/quickbook/test/list_test-1_5.quickbook @@ -98,3 +98,11 @@ Don't end list with comment 2: * Three [endsect] + +[section List immediately following markup 2] +* One +[section Nested section] +* Two +[endsect] + +[endsect] diff --git a/tools/quickbook/test/list_test-1_6.gold b/tools/quickbook/test/list_test-1_6.gold index 223509a590..f0055257ab 100644 --- a/tools/quickbook/test/list_test-1_6.gold +++ b/tools/quickbook/test/list_test-1_6.gold @@ -420,6 +420,28 @@ </listitem> </itemizedlist> </section> + <section id="list_test.list_immediately_following_mark0"> + <title><link linkend="list_test.list_immediately_following_mark0">List immediately + following markup 2</link></title> + <itemizedlist> + <listitem> + <simpara> + One + </simpara> + </listitem> + </itemizedlist> + <section id="list_test.list_immediately_following_mark0.nested_section"> + <title><link linkend="list_test.list_immediately_following_mark0.nested_section">Nested + section</link></title> + <itemizedlist> + <listitem> + <simpara> + Two + </simpara> + </listitem> + </itemizedlist> + </section> + </section> <section id="list_test.paragraphs_in_list_items"> <title><link linkend="list_test.paragraphs_in_list_items">Paragraphs in list items</link></title> @@ -473,4 +495,32 @@ </listitem> </itemizedlist> </section> + <section id="list_test.indented_code_blocks_in_lists"> + <title><link linkend="list_test.indented_code_blocks_in_lists">Indented code + blocks in lists</link></title> + <itemizedlist> + <listitem> + <simpara> + A +<programlisting><phrase role="identifier">B</phrase> +</programlisting> + <para> + C + </para> + </simpara> + </listitem> + <listitem> + <simpara> + D +<programlisting><phrase role="identifier">E</phrase> +</programlisting> + </simpara> + </listitem> + <listitem> + <simpara> + F + </simpara> + </listitem> + </itemizedlist> + </section> </article> diff --git a/tools/quickbook/test/list_test-1_6.quickbook b/tools/quickbook/test/list_test-1_6.quickbook index fd01b389d5..dbba74258e 100644 --- a/tools/quickbook/test/list_test-1_6.quickbook +++ b/tools/quickbook/test/list_test-1_6.quickbook @@ -103,6 +103,13 @@ Don't end list with comment 2: [endsect] +[section List immediately following markup 2] +* One +[section Nested section] +* Two +[endsect] +[endsect] + [section Paragraphs in list items] * A1 @@ -125,4 +132,16 @@ Don't end list with comment 2: D2 -[endsect]
\ No newline at end of file +[endsect] + +[section Indented code blocks in lists] + +* A + + B + C +* D + + E +* F +[endsect] diff --git a/tools/quickbook/test/python/include_path.qbk b/tools/quickbook/test/python/include_path.qbk new file mode 100644 index 0000000000..c9a4dcd981 --- /dev/null +++ b/tools/quickbook/test/python/include_path.qbk @@ -0,0 +1,4 @@ +[quickbook 1.5] +[article Include Path] +[include a.qbk] +[include b.qbk] diff --git a/tools/quickbook/test/python/include_path_deps.txt b/tools/quickbook/test/python/include_path_deps.txt new file mode 100644 index 0000000000..994d776ee6 --- /dev/null +++ b/tools/quickbook/test/python/include_path_deps.txt @@ -0,0 +1,3 @@ +include_path.qbk +sub1/a.qbk +sub2/b.qbk diff --git a/tools/quickbook/test/python/include_path_locs.txt b/tools/quickbook/test/python/include_path_locs.txt new file mode 100644 index 0000000000..aaffb8d13f --- /dev/null +++ b/tools/quickbook/test/python/include_path_locs.txt @@ -0,0 +1,6 @@ ++ include_path.qbk +- a.qbk ++ sub1/a.qbk +- b.qbk +- sub1/b.qbk ++ sub2/b.qbk diff --git a/tools/quickbook/test/python/missing_relative.qbk b/tools/quickbook/test/python/missing_relative.qbk new file mode 100644 index 0000000000..8fdc0ee049 --- /dev/null +++ b/tools/quickbook/test/python/missing_relative.qbk @@ -0,0 +1,6 @@ +[quickbook 1.5] +[article Missing Relative] + +[include ../missing.qbk] +[include missing-dir/x.qbk] +[include missing-dir/../../x.qbk] diff --git a/tools/quickbook/test/python/missing_relative_deps.txt b/tools/quickbook/test/python/missing_relative_deps.txt new file mode 100644 index 0000000000..a9de670365 --- /dev/null +++ b/tools/quickbook/test/python/missing_relative_deps.txt @@ -0,0 +1 @@ +missing_relative.qbk diff --git a/tools/quickbook/test/python/missing_relative_locs.txt b/tools/quickbook/test/python/missing_relative_locs.txt new file mode 100644 index 0000000000..69b51f28f4 --- /dev/null +++ b/tools/quickbook/test/python/missing_relative_locs.txt @@ -0,0 +1,4 @@ ++ missing_relative.qbk +- ../missing.qbk +- missing-dir/x.qbk +- missing-dir/../../x.qbk diff --git a/tools/quickbook/test/python/output-deps.py b/tools/quickbook/test/python/output-deps.py new file mode 100644 index 0000000000..7b77c27d84 --- /dev/null +++ b/tools/quickbook/test/python/output-deps.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python + +import sys, os, subprocess, tempfile, re + +def main(args, directory): + if len(args) != 1: + print "Usage: output-deps.py quickbook-command" + exit(1) + quickbook_command = args[0] + + failures = 0 + failures += run_quickbook(quickbook_command, 'svg_missing.qbk', + deps_gold = 'svg_missing_deps.txt') + failures += run_quickbook(quickbook_command, 'svg_missing.qbk', + locations_gold = 'svg_missing_locs.txt') + failures += run_quickbook(quickbook_command, 'missing_relative.qbk', + deps_gold = 'missing_relative_deps.txt', + locations_gold = 'missing_relative_locs.txt') + failures += run_quickbook(quickbook_command, 'include_path.qbk', + deps_gold = 'include_path_deps.txt', + locations_gold = 'include_path_locs.txt', + input_path = ['sub1', 'sub2']) + + if failures == 0: + print "Success" + else: + print "Failures:",failures + exit(failures) + +def run_quickbook(quickbook_command, filename, output_gold = None, + deps_gold = None, locations_gold = None, input_path = []): + failures = 0 + + command = [quickbook_command, '--debug', filename] + + output_filename = None + if output_gold: + output_filename = temp_filename('.qbk') + command.extend(['--output-file', output_filename]) + + deps_filename = None + if deps_gold: + deps_filename = temp_filename('.txt') + command.extend(['--output-deps', deps_filename]) + + locations_filename = None + if locations_gold: + locations_filename = temp_filename('.txt') + command.extend(['--output-checked-locations', locations_filename]) + + try: + for path in input_path: + command.extend(['-I', path]) + print 'Running: ' + ' '.join(command) + print + exit_code = subprocess.call(command) + print + success = not exit_code + + if output_filename: + output = load_file(output_filename) + else: + output = None + + if deps_filename: + deps = load_dependencies(deps_filename) + else: + deps = None + + if locations_filename: + locations = load_locations(locations_filename) + else: + locations = None + finally: + if output_filename: os.unlink(output_filename) + if deps_filename: os.unlink(deps_filename) + + if deps_gold: + gold = load_dependencies(deps_gold, adjust_paths = True) + if deps != gold: + failures = failures + 1 + print "Dependencies don't match:" + print "Gold:", gold + print "Result:", deps + print + + if locations_gold: + gold = load_locations(locations_gold, adjust_paths = True) + if locations != gold: + failures = failures + 1 + print "Dependencies don't match:" + print "Gold:", gold + print "Result:", locations + print + + if output_gold: + gold = load_file(output_gold) + if gold != output: + failures = failures + 1 + print "Output doesn't match:" + print + print gold + print + print output + print + + return failures + +def load_dependencies(filename, adjust_paths = False): + dependencies = set() + f = open(filename, 'r') + for path in f: + if adjust_paths: + path = os.path.realpath(path) + if path in dependencies: + raise Exception("Duplicate path (%1s) in %2s" % (path, filename)) + dependencies.add(path) + return dependencies + +def load_locations(filename, adjust_paths = False): + line_matcher = re.compile("^([+-]) (.*)$") + dependencies = {} + f = open(filename, 'r') + for line in f: + m = line_matcher.match(line) + if not m: + raise Exception("Invalid dependency file: %1s" % filename) + found = m.group(1) == '+' + path = m.group(2) + if adjust_paths: + path = os.path.realpath(path) + if path in dependencies: + raise Exception("Duplicate path (%1s) in %2s" % (path, filename)) + dependencies[path] = found + return dependencies + +def temp_filename(extension): + file = tempfile.mkstemp(suffix = extension) + os.close(file[0]) + return file[1] + +def load_file(filename): + f = open(filename, 'r') + try: + return f.read() + finally: + f.close() + + return None + +main(sys.argv[1:], os.path.dirname(sys.argv[0])) diff --git a/tools/quickbook/test/python/sub1/a.qbk b/tools/quickbook/test/python/sub1/a.qbk new file mode 100644 index 0000000000..7898192261 --- /dev/null +++ b/tools/quickbook/test/python/sub1/a.qbk @@ -0,0 +1 @@ +a diff --git a/tools/quickbook/test/python/sub2/b.qbk b/tools/quickbook/test/python/sub2/b.qbk new file mode 100644 index 0000000000..6178079822 --- /dev/null +++ b/tools/quickbook/test/python/sub2/b.qbk @@ -0,0 +1 @@ +b diff --git a/tools/quickbook/test/python/svg_missing.qbk b/tools/quickbook/test/python/svg_missing.qbk new file mode 100644 index 0000000000..2b25c2f3b6 --- /dev/null +++ b/tools/quickbook/test/python/svg_missing.qbk @@ -0,0 +1,3 @@ +[article Dependencies for missing svg] + +[$missing.svg] diff --git a/tools/quickbook/test/python/svg_missing_deps.txt b/tools/quickbook/test/python/svg_missing_deps.txt new file mode 100644 index 0000000000..25d1c0e502 --- /dev/null +++ b/tools/quickbook/test/python/svg_missing_deps.txt @@ -0,0 +1 @@ +svg_missing.qbk diff --git a/tools/quickbook/test/python/svg_missing_locs.txt b/tools/quickbook/test/python/svg_missing_locs.txt new file mode 100644 index 0000000000..379d4142f0 --- /dev/null +++ b/tools/quickbook/test/python/svg_missing_locs.txt @@ -0,0 +1,2 @@ +- html/missing.svg ++ svg_missing.qbk diff --git a/tools/quickbook/test/source_mode-1_7.gold b/tools/quickbook/test/source_mode-1_7.gold new file mode 100644 index 0000000000..e40bae8608 --- /dev/null +++ b/tools/quickbook/test/source_mode-1_7.gold @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE article PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd"> +<article id="source_mode_test" last-revision="DEBUG MODE Date: 2000/12/20 12:00:00 $" + xmlns:xi="http://www.w3.org/2001/XInclude"> + <title>Source Mode Test</title> + <informaltable frame="all"> + <tgroup cols="2"> + <tbody> + <row> + <entry> +<programlisting><phrase role="keyword">int</phrase> <phrase role="identifier">main</phrase><phrase role="special">()</phrase> <phrase role="special">{}</phrase></programlisting> + </entry> + <entry> +<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">foo</phrase><phrase role="special">()</phrase> <phrase role="special">{}</phrase></programlisting> + </entry> + </row> + </tbody> + </tgroup> + </informaltable> +<programlisting>Plain text...</programlisting> + <para> + <code><phrase role="keyword">int</phrase> <phrase role="identifier">main</phrase><phrase + role="special">()</phrase> <phrase role="special">{}</phrase></code> but <code>plain + text</code>. + </para> + <itemizedlist> + <listitem> + <simpara> + Sadly this doesn't work. + </simpara> + </listitem> + <listitem> + <simpara> + <code>int main() {}</code> + </simpara> + </listitem> + </itemizedlist> +</article> diff --git a/tools/quickbook/test/source_mode-1_7.quickbook b/tools/quickbook/test/source_mode-1_7.quickbook new file mode 100644 index 0000000000..f5b9ee37fe --- /dev/null +++ b/tools/quickbook/test/source_mode-1_7.quickbook @@ -0,0 +1,12 @@ +[quickbook 1.7] +[source-mode teletype] +[article Source Mode Test] + +[!c++][table [[``int main() {}``][``void foo() {}``]]] +``Plain text...`` + +[!c++]`int main() {}` but `plain text`. + +[!c++] +* Sadly this doesn't work. +* `int main() {}` diff --git a/tools/quickbook/test/unit/Jamfile.v2 b/tools/quickbook/test/unit/Jamfile.v2 index ea60b90404..0b583b796b 100644 --- a/tools/quickbook/test/unit/Jamfile.v2 +++ b/tools/quickbook/test/unit/Jamfile.v2 @@ -13,6 +13,11 @@ project quickbook-unit-tests <include>../../src <warnings>all <library>/boost//filesystem + <toolset>gcc:<cflags>-g0 + <toolset>darwin:<cflags>-g0 + <toolset>msvc:<cflags>/wd4709 + <toolset>gcc:<define>BOOST_DETAIL_CONTAINER_FWD + <toolset>darwin:<define>BOOST_DETAIL_CONTAINER_FWD ; run values_test.cpp ../../src/values.cpp ../../src/files.cpp ../../src/string_ref.cpp ; @@ -20,4 +25,4 @@ run post_process_test.cpp ../../src/post_process.cpp ; # Copied from spirit run symbols_tests.cpp ; -run symbols_find_null.cpp ;
\ No newline at end of file +run symbols_find_null.cpp ; diff --git a/tools/quickbook/test/version-1_7-fail.quickbook b/tools/quickbook/test/version-1_8-fail.quickbook index 9820b7435c..4311034ba7 100644 --- a/tools/quickbook/test/version-1_7-fail.quickbook +++ b/tools/quickbook/test/version-1_8-fail.quickbook @@ -1,5 +1,5 @@ [article Future version of quickbook - [quickbook 1.7] + [quickbook 1.8] ] This should fail...
\ No newline at end of file |