diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 new file mode 100644 index 0000000..cebf785 --- /dev/null +++ b/doc/Jamfile.v2 @@ -0,0 +1,73 @@ +# Copyright John Maddock 2005. Use, modification, and distribution are +# 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) + +using quickbook ; + +path-constant images_location : html ; + +xml auto_index : auto_index.qbk ; +boostbook standalone + : + auto_index + : + # Path for links to Boost: + #boost.root=../../../../../../../trunk + # Path for libraries index: + boost.libraries=$(boost-root)/libs/libraries.htm + # Use the main Boost stylesheet: + html.stylesheet=boostbook.css + + # Some general style settings: + table.footnote.number.format=1 + footnote.number.format=1 + + # HTML options first: + # Use graphics not text for navigation: + navig.graphics=1 + # How far down we chunk nested sections, basically all of them: + chunk.section.depth=10 + # Don't put the first section on the same page as the TOC: + chunk.first.sections=1 + # How far down sections get TOC's + toc.section.depth=10 + # Max depth in each TOC: + toc.max.depth=4 + # How far down we go with TOC's + generate.section.toc.level=10 + # Index on type: + index.on.type=1 + + #root.filename="sf_dist_and_tools" + #graphicsize.extension=1 + #use.extensions=1 + + # PDF Options: + # TOC Generation: this is needed for FOP-0.9 and later: + fop1.extensions=0 + pdf:xep.extensions=1 + # TOC generation: this is needed for FOP 0.2, but must not be set to zero for FOP-0.9! + pdf:fop.extensions=0 + # No indent on body text: + pdf:body.start.indent=0pt + # Margin size: + pdf:page.margin.inner=0.5in + # Margin size: + pdf:page.margin.outer=0.5in + # Paper type = A4 + pdf:paper.type=A4 + # Yes, we want graphics for admonishments: + admon.graphics=1 + # Set this one for PDF generation *only*: + # default pnd graphics are awful in PDF form, + # better use SVG's instead: + pdf:admon.graphics.extension=".svg" + pdf:use.role.for.mediaobject=1 + pdf:preferred.mediaobject.role=print + pdf:img.src.path=$(images_location)/ + pdf:admon.graphics.path=$(images_location)/images/ + pdf:draft.mode="no" + ; + + + diff --git a/doc/auto_index.qbk b/doc/auto_index.qbk new file mode 100644 index 0000000..5f7ecb7 --- /dev/null +++ b/doc/auto_index.qbk @@ -0,0 +1,77 @@ +[article AutoIndex + [quickbook 1.4] + [copyright 2008 John Maddock] + [license + Distributed under 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]) + ] + [authors [Maddock, John]] + [/last-revision $Date: 2008-11-04 17:11:53 +0000 (Tue, 04 Nov 2008) $] +] + +[section:overview Overview] + +AutoIndex is a tool for taking the grunt work out of indexing a +Quickbook\/Boostbook\/Docbook document that describes C/C++ code. + +Traditionally, in order to index a Docbook document you would +have to manually add a large amount of `` markup: +in fact one `` for each occurance of each term to be +indexed. + +Instead AutoIndex will scan one or more C/C++ header files +and extract all the ['function], ['class], ['macro] and ['typedef] +names that are defined by those headers, and then insert the +``'s into the XML document for you. + +AutoIndex creates index entries as follows - for each occurance of +each search term, it creates two index entries - one has the search term +as the primary index key and the title of the section it appears in as +a subterm, the other has the section title as the main index entry and the +search term as the subentry. Thus the user has two chances to find what their +looking for, based upon either the section name or the ['function], ['class], ['macro] +or ['typedef] name. + +So for example in Boost.Math the class name `students_t_distribution` has a primary +entry that lists all sections it appears in: + +[$../students_t_eg_1.png] + +Then those sections also have primary entries, which list all the search terms those +sections contain: + +[$../students_t_eg_2.png] + +Of course these automated index entries may not be quite +what you're looking for: often you'll get a few spurious entries, a few missing entries, +and a few entries where the section name used as an index entry is less than ideal. +So AutoIndex provides some powerful regular expression based rules that allow you +to add, remove, constrain, or rewrite entries. Normally just a few lines in +AutoIndex's script file are enough to tailor the output to match the authors +expectations. + +AutoIndex also supports multiple indexes (as does Docbook), and since it knows +which search terms are ['function], ['class], ['macro] or ['typedef] names, it +can add the necessary attritubes to the XML so that you can have separate +indexes for each of these different types. These specialised indexes only contain +entries for the ['function], ['class], ['macro] or ['typedef] names, ['section +names] are never used as primary index terms here, unlike the main "include everything" +index. + +Finally, while the Docbook XSL stylesheets create nice indexes complete with page +numbers for PDF output, the HTML indexes look a lot less good, as these use +section titles in place of page numbers... but as AutoIndex uses section titles +as index entries this leads to a lot of repetition, so as an alternative AutoIndex +can be instructed to construct the index itself. This is faster than using +the XSL stylesheets, and now each index entry is a hyperlink to the +approprate section: + +[$../students_t_eg_3.png] + +With internal index generation there is also a helpful navigation bar +at the start of each Index: + +[$../students_t_eg_4.png] + +[endsect] diff --git a/doc/html/autoindex/overview.html b/doc/html/autoindex/overview.html new file mode 100644 index 0000000..6ec80d5 --- /dev/null +++ b/doc/html/autoindex/overview.html @@ -0,0 +1,116 @@ + + + +Overview + + + + + + + + + + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
+PrevUpHome +
+
+ +

+ AutoIndex is a tool for taking the grunt work out of indexing a Quickbook/Boostbook/Docbook + document that describes C/C++ code. +

+

+ Traditionally, in order to index a Docbook document you would have to manually + add a large amount of <indexterm> markup: in fact one <indexterm> + for each occurance of each term to be indexed. +

+

+ Instead AutoIndex will scan one or more C/C++ header files and extract all + the function, class, macro + and typedef names that are defined by those headers, and + then insert the <indexterm>'s into the XML document for you. +

+

+ AutoIndex creates index entries as follows - for each occurance of each search + term, it creates two index entries - one has the search term as the primary + index key and the title of the section it appears in as a subterm, the other + has the section title as the main index entry and the search term as the subentry. + Thus the user has two chances to find what their looking for, based upon either + the section name or the function, class, + macro or typedef name. +

+

+ So for example in Boost.Math the class name students_t_distribution + has a primary entry that lists all sections it appears in: +

+

+ students_t_eg_1 +

+

+ Then those sections also have primary entries, which list all the search terms + those sections contain: +

+

+ students_t_eg_2 +

+

+ Of course these automated index entries may not be quite what you're looking + for: often you'll get a few spurious entries, a few missing entries, and a + few entries where the section name used as an index entry is less than ideal. + So AutoIndex provides some powerful regular expression based rules that allow + you to add, remove, constrain, or rewrite entries. +

+

+ AutoIndex also supports multiple indexes (as does Docbook), and since it knows + which search terms are function, class, + macro or typedef names, it can add + the necessary attritubes to the XML so that you can have separate indexes for + each of these different types. These specialised indexes only contain entries + for the function, class, macro + or typedef names, section names are + never used as primary index terms here, unlike the main "include everything" + index. +

+

+ Finally, while the Docbook XSL stylesheets create nice indexes complete with + page numbers for PDF output, the HTML indexes look a lot less good, as these + use section titles in place of page numbers... but as AutoIndex uses section + titles as index entries this leads to a lot of repetition, so as an alternative + AutoIndex can be instructed to construct the index itself. This is faster than + using the XSL stylesheets, and now each index entry is a hyperlink to the approprate + section: +

+

+ students_t_eg_3 +

+

+ There is also a navigation bar at the start of each Index: +

+

+ students_t_eg_4 +

+
+ + + +
+
+
+PrevUpHome +
+ + diff --git a/doc/html/boostbook.css b/doc/html/boostbook.css new file mode 100644 index 0000000..36093cb --- /dev/null +++ b/doc/html/boostbook.css @@ -0,0 +1,538 @@ +/*============================================================================= + Copyright (c) 2004 Joel de Guzman + 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) + + New syntax color Paul A. Bristow 8 Jun 2007 +=============================================================================*/ + +/*============================================================================= + Body defaults +=============================================================================*/ + + body + { + margin: 1em; + font-family: sans-serif; + } + +/*============================================================================= + Paragraphs +=============================================================================*/ + + p + { + text-align: left; + font-size: 10pt; + line-height: 1.15; + } + +/*============================================================================= + Program listings +=============================================================================*/ + + /* Code on paragraphs */ + p tt.computeroutput + { + font-size: 9pt; + } + + pre.synopsis + { + font-size: 90%; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + .programlisting, + .screen + { + font-size: 9pt; + display: block; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + /* Program listings in tables don't get borders */ + td .programlisting, + td .screen + { + margin: 0pc 0pc 0pc 0pc; + padding: 0pc 0pc 0pc 0pc; + } + +/*============================================================================= + Headings +=============================================================================*/ + + h1, h2, h3, h4, h5, h6 + { + text-align: left; + margin: 1em 0em 0.5em 0em; + font-weight: bold; + } + + h1 { font: 140% } + h2 { font: bold 140% } + h3 { font: bold 130% } + h4 { font: bold 120% } + h5 { font: italic 110% } + h6 { font: italic 100% } + + /* Top page titles */ + title, + h1.title, + h2.title + h3.title, + h4.title, + h5.title, + h6.title, + .refentrytitle + { + font-weight: bold; + margin-bottom: 1pc; + } + + h1.title { font-size: 140% } + h2.title { font-size: 140% } + h3.title { font-size: 130% } + h4.title { font-size: 120% } + h5.title { font-size: 110% } + h6.title { font-size: 100% } + + .section h1 + { + margin: 0em 0em 0.5em 0em; + font-size: 140%; + } + + .section h2 { font-size: 140% } + .section h3 { font-size: 130% } + .section h4 { font-size: 120% } + .section h5 { font-size: 110% } + .section h6 { font-size: 100% } + + /* Code on titles */ + h1 tt.computeroutput { font-size: 140% } + h2 tt.computeroutput { font-size: 140% } + h3 tt.computeroutput { font-size: 130% } + h4 tt.computeroutput { font-size: 120% } + h5 tt.computeroutput { font-size: 110% } + h6 tt.computeroutput { font-size: 100% } + +/*============================================================================= + Author +=============================================================================*/ + + h3.author + { + font-size: 100% + } + +/*============================================================================= + Lists +=============================================================================*/ + + li + { + font-size: 10pt; + line-height: 1.3; + } + + /* Unordered lists */ + ul + { + text-align: left; + } + + /* Ordered lists */ + ol + { + text-align: left; + } + +/*============================================================================= + Links +=============================================================================*/ + + a + { + text-decoration: none; /* no underline */ + } + + a:hover + { + text-decoration: underline; + } + +/*============================================================================= + Spirit style navigation +=============================================================================*/ + + .spirit-nav + { + text-align: right; + } + + .spirit-nav a + { + color: white; + padding-left: 0.5em; + } + + .spirit-nav img + { + border-width: 0px; + } + +/*============================================================================= + Table of contents +=============================================================================*/ + + .toc + { + margin: 1pc 4% 0pc 4%; + padding: 0.1pc 1pc 0.1pc 1pc; + font-size: 80%; + line-height: 1.15; + } + + .boost-toc + { + float: right; + padding: 0.5pc; + } + +/*============================================================================= + Tables +=============================================================================*/ + + .table-title, + div.table p.title + { + margin-left: 4%; + padding-right: 0.5em; + padding-left: 0.5em; + } + + .informaltable table, + .table table + { + width: 92%; + margin-left: 4%; + margin-right: 4%; + } + + div.informaltable table, + div.table table + { + padding: 4px; + } + + /* Table Cells */ + div.informaltable table tr td, + div.table table tr td + { + padding: 0.5em; + text-align: left; + font-size: 9pt; + } + + div.informaltable table tr th, + div.table table tr th + { + padding: 0.5em 0.5em 0.5em 0.5em; + border: 1pt solid white; + font-size: 80%; + } + +/*============================================================================= + Blurbs +=============================================================================*/ + + div.note, + div.tip, + div.important, + div.caution, + div.warning, + p.blurb + { + font-size: 9pt; /* A little bit smaller than the main text */ + line-height: 1.2; + display: block; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + p.blurb img + { + padding: 1pt; + } + +/*============================================================================= + Variable Lists +=============================================================================*/ + + /* Make the terms in definition lists bold */ + div.variablelist dl dt, + span.term + { + font-weight: bold; + font-size: 10pt; + } + + div.variablelist table tbody tr td + { + text-align: left; + vertical-align: top; + padding: 0em 2em 0em 0em; + font-size: 10pt; + margin: 0em 0em 0.5em 0em; + line-height: 1; + } + + div.variablelist dl dt + { + margin-bottom: 0.2em; + } + + div.variablelist dl dd + { + margin: 0em 0em 0.5em 2em; + font-size: 10pt; + } + + div.variablelist table tbody tr td p, + div.variablelist dl dd p + { + margin: 0em 0em 0.5em 0em; + line-height: 1; + } + +/*============================================================================= + Misc +=============================================================================*/ + + /* Title of books and articles in bibliographies */ + span.title + { + font-style: italic; + } + + span.underline + { + text-decoration: underline; + } + + span.strikethrough + { + text-decoration: line-through; + } + + /* Copyright, Legal Notice */ + div div.legalnotice p + { + text-align: left + } + +/*============================================================================= + Colors +=============================================================================*/ + + @media screen + { + /* Links */ + a + { + color: #005a9c; + } + + a:visited + { + color: #9c5a9c; + } + + h1 a, h2 a, h3 a, h4 a, h5 a, h6 a, + h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover, + h1 a:visited, h2 a:visited, h3 a:visited, h4 a:visited, h5 a:visited, h6 a:visited + { + text-decoration: none; /* no underline */ + color: #000000; + } + + /* New Syntax Highlighting + using Recognized color keyword names, for example: + http://www.w3.org/TR/SVG/types.html see section 4.2 + */ + .keyword { color: blue; } + .identifier { color: black; } + .special { color: magenta; } + .preprocessor { color: blueviolet; } + .char { color: teal; } + .comment { color: green; } + .string { color: teal; } + .number { color: red; } + .white_bkd { background-color: white; } + .dk_grey_bkd { background-color: dimgray; } + + /* Original Syntax Highlighting + .keyword { color: blue; } + .identifier { color: #000000; } + .special { color: #707070; } + .preprocessor { color: #402080; } + .char { color: teal; } + .comment { color: #800000; } + .string { color: teal; } + .number { color: teal; } + .white_bkd { background-color: #FFFFFF; } + .dk_grey_bkd { background-color: #999999; } + */ + /* Copyright, Legal Notice */ + .copyright + { + color: #666666; + font-size: small; + } + + div div.legalnotice p + { + color: #666666; + } + + /* Program listing */ + pre.synopsis + { + border: 1px solid #DCDCDC; + } + + .programlisting, + .screen + { + border: 1px solid #DCDCDC; + } + + td .programlisting, + td .screen + { + border: 0px solid #DCDCDC; + } + + /* Blurbs */ + div.note, + div.tip, + div.important, + div.caution, + div.warning, + p.blurb + { + border: 1px solid #DCDCDC; + } + + /* Table of contents */ + .toc + { + border: 1px solid #DCDCDC; + } + + /* Tables */ + div.informaltable table tr td, + div.table table tr td + { + border: 1px solid #DCDCDC; + } + + div.informaltable table tr th, + div.table table tr th + { + background-color: #F0F0F0; + border: 1px solid #DCDCDC; + } + + /* Misc */ + span.highlight + { + color: #00A000; + } + } + + @media print + { + /* Links */ + a + { + color: black; + } + + a:visited + { + color: black; + } + + .spirit-nav + { + display: none; + } + + /* Program listing */ + pre.synopsis + { + border: 1px solid gray; + } + + .programlisting, + .screen + { + border: 1px solid gray; + } + + td .programlisting, + td .screen + { + border: 0px solid #DCDCDC; + } + + /* Table of contents */ + .toc + { + border: 1px solid gray; + } + + .informaltable table, + .table table + { + border: 1px solid gray; + border-collapse: collapse; + } + + /* Tables */ + div.informaltable table tr td, + div.table table tr td + { + border: 1px solid gray; + } + + div.informaltable table tr th, + div.table table tr th + { + border: 1px solid gray; + } + + /* Misc */ + span.highlight + { + font-weight: bold; + } + } + +/*============================================================================= + Images +=============================================================================*/ + + span.inlinemediaobject img + { + vertical-align: middle; + } + diff --git a/doc/html/images/blank.png b/doc/html/images/blank.png new file mode 100644 index 0000000..764bf4f Binary files /dev/null and b/doc/html/images/blank.png differ diff --git a/doc/html/images/caution.png b/doc/html/images/caution.png new file mode 100644 index 0000000..5b7809c Binary files /dev/null and b/doc/html/images/caution.png differ diff --git a/doc/html/images/caution.svg b/doc/html/images/caution.svg new file mode 100644 index 0000000..4bd586a --- /dev/null +++ b/doc/html/images/caution.svg @@ -0,0 +1,68 @@ + + + + + + Attenzione + + + + pulsante + + + + + Open Clip Art Library + + + + + Architetto Francesco Rollandin + + + + + Architetto Francesco Rollandin + + + + image/svg+xml + + + en + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/html/images/draft.png b/doc/html/images/draft.png new file mode 100644 index 0000000..0084708 Binary files /dev/null and b/doc/html/images/draft.png differ diff --git a/doc/html/images/home.png b/doc/html/images/home.png new file mode 100644 index 0000000..5584aac Binary files /dev/null and b/doc/html/images/home.png differ diff --git a/doc/html/images/home.svg b/doc/html/images/home.svg new file mode 100644 index 0000000..e803a31 --- /dev/null +++ b/doc/html/images/home.svg @@ -0,0 +1,26 @@ + + + + + + + + +]> + + + + + + + + + + + + + + diff --git a/doc/html/images/important.png b/doc/html/images/important.png new file mode 100644 index 0000000..12c90f6 Binary files /dev/null and b/doc/html/images/important.png differ diff --git a/doc/html/images/important.svg b/doc/html/images/important.svg new file mode 100644 index 0000000..dd84f3f --- /dev/null +++ b/doc/html/images/important.svg @@ -0,0 +1,25 @@ + + + + + + + + +]> + + + + + + + + + + + + + + + diff --git a/doc/html/images/next.png b/doc/html/images/next.png new file mode 100644 index 0000000..59800b4 Binary files /dev/null and b/doc/html/images/next.png differ diff --git a/doc/html/images/next.svg b/doc/html/images/next.svg new file mode 100644 index 0000000..75fa83e --- /dev/null +++ b/doc/html/images/next.svg @@ -0,0 +1,19 @@ + + + + + + +]> + + + + + + + + + + + diff --git a/doc/html/images/next_disabled.png b/doc/html/images/next_disabled.png new file mode 100644 index 0000000..10a8c59 Binary files /dev/null and b/doc/html/images/next_disabled.png differ diff --git a/doc/html/images/note.png b/doc/html/images/note.png new file mode 100644 index 0000000..d0c3c64 Binary files /dev/null and b/doc/html/images/note.png differ diff --git a/doc/html/images/note.svg b/doc/html/images/note.svg new file mode 100644 index 0000000..648299d --- /dev/null +++ b/doc/html/images/note.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + +]> + + + + + + + + + + + + + + + + + + + diff --git a/doc/html/images/prev.png b/doc/html/images/prev.png new file mode 100644 index 0000000..d88a40f Binary files /dev/null and b/doc/html/images/prev.png differ diff --git a/doc/html/images/prev.svg b/doc/html/images/prev.svg new file mode 100644 index 0000000..6d88ffd --- /dev/null +++ b/doc/html/images/prev.svg @@ -0,0 +1,19 @@ + + + + + + +]> + + + + + + + + + + + diff --git a/doc/html/images/prev_disabled.png b/doc/html/images/prev_disabled.png new file mode 100644 index 0000000..ab3c17e Binary files /dev/null and b/doc/html/images/prev_disabled.png differ diff --git a/doc/html/images/tip.png b/doc/html/images/tip.png new file mode 100644 index 0000000..5c4aab3 Binary files /dev/null and b/doc/html/images/tip.png differ diff --git a/doc/html/images/tip.svg b/doc/html/images/tip.svg new file mode 100644 index 0000000..cd437a5 --- /dev/null +++ b/doc/html/images/tip.svg @@ -0,0 +1,84 @@ + + + + + + lamp + + + + office + + lamp + + + + + Open Clip Art Library + + + + + Sergio Luiz Araujo Silva + + + + + Public Domain + + + set 2005 + image/svg+xml + + + en + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/html/images/toc-blank.png b/doc/html/images/toc-blank.png new file mode 100644 index 0000000..6ffad17 Binary files /dev/null and b/doc/html/images/toc-blank.png differ diff --git a/doc/html/images/toc-minus.png b/doc/html/images/toc-minus.png new file mode 100644 index 0000000..abbb020 Binary files /dev/null and b/doc/html/images/toc-minus.png differ diff --git a/doc/html/images/toc-plus.png b/doc/html/images/toc-plus.png new file mode 100644 index 0000000..941312c Binary files /dev/null and b/doc/html/images/toc-plus.png differ diff --git a/doc/html/images/up.png b/doc/html/images/up.png new file mode 100644 index 0000000..17d9c3e Binary files /dev/null and b/doc/html/images/up.png differ diff --git a/doc/html/images/up.svg b/doc/html/images/up.svg new file mode 100644 index 0000000..d31aa9c --- /dev/null +++ b/doc/html/images/up.svg @@ -0,0 +1,19 @@ + + + + + + +]> + + + + + + + + + + + diff --git a/doc/html/images/up_disabled.png b/doc/html/images/up_disabled.png new file mode 100644 index 0000000..e22bc87 Binary files /dev/null and b/doc/html/images/up_disabled.png differ diff --git a/doc/html/images/warning.png b/doc/html/images/warning.png new file mode 100644 index 0000000..1c33db8 Binary files /dev/null and b/doc/html/images/warning.png differ diff --git a/doc/html/images/warning.svg b/doc/html/images/warning.svg new file mode 100644 index 0000000..fc8d748 --- /dev/null +++ b/doc/html/images/warning.svg @@ -0,0 +1,23 @@ + + + + + + + + +]> + + + + + + + + + + + + + diff --git a/doc/html/index.html b/doc/html/index.html new file mode 100644 index 0000000..473e007 --- /dev/null +++ b/doc/html/index.html @@ -0,0 +1,51 @@ + + + +AutoIndex + + + + + + + + + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
Next
+
+
+
+

+AutoIndex

+

+John Maddock +

+
+
+

+ Distributed under 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) +

+
+
+
+
+
+

Table of Contents

+
Overview
+
+
+ + + +

Last revised: November 20, 2008 at 18:04:26 GMT

+
+
Next
+ + diff --git a/doc/html/reference.css b/doc/html/reference.css new file mode 100644 index 0000000..be4e64c --- /dev/null +++ b/doc/html/reference.css @@ -0,0 +1,5 @@ +PRE.synopsis { + background-color: #e0ffff; + border: thin solid blue; + padding: 1em +} diff --git a/doc/students_t_eg_1.png b/doc/students_t_eg_1.png new file mode 100644 index 0000000..485f1f1 Binary files /dev/null and b/doc/students_t_eg_1.png differ diff --git a/doc/students_t_eg_2.png b/doc/students_t_eg_2.png new file mode 100644 index 0000000..8149dcb Binary files /dev/null and b/doc/students_t_eg_2.png differ diff --git a/doc/students_t_eg_3.png b/doc/students_t_eg_3.png new file mode 100644 index 0000000..6fa55c1 Binary files /dev/null and b/doc/students_t_eg_3.png differ diff --git a/doc/students_t_eg_4.png b/doc/students_t_eg_4.png new file mode 100644 index 0000000..6f651ec Binary files /dev/null and b/doc/students_t_eg_4.png differ diff --git a/src/auto_index.cpp b/src/auto_index.cpp new file mode 100644 index 0000000..adbee5b --- /dev/null +++ b/src/auto_index.cpp @@ -0,0 +1,804 @@ + +#include "tiny_xml.hpp" +#include +#include +#include +#include +#include +#include +#include + +int help() +{ + return 1; +} + +void eat_whitespace(std::istream & is) +{ + char c = is.peek(); + while(std::isspace(c)) + { + is.get(c); + c = is.peek(); + } +} + +void eat_block(std::string& result, std::istream & is) +{ + // + // everything until we get to a closing '>': + // + char c; + while(is.get(c) && c != '>') + { + result += c; + if(c == '\\') + { + is.get(c); + result += c; + } + } + result += c; +} + +std::string get_header(std::istream & is) +{ + // + // We need to get any leading index_terms; +std::set > found_terms; +bool no_duplicates = false; + +struct index_entry; +typedef boost::shared_ptr index_entry_ptr; +bool operator < (const index_entry_ptr& a, const index_entry_ptr& b); +typedef std::set index_entry_set; + +std::string make_upper_key(const std::string& s) +{ + std::string result; + for(std::string::const_iterator i = s.begin(); i != s.end(); ++i) + result.append(1, std::toupper(*i)); + return result; +} + +struct index_entry +{ + std::string key; + std::string sort_key; + std::string id; + std::string category; + index_entry_set sub_keys; + + index_entry(){} + index_entry(const std::string& k) : key(k) { sort_key = make_upper_key(key); } + index_entry(const std::string& k, const std::string& i) : key(k), id(i) { sort_key = make_upper_key(key); } + index_entry(const std::string& k, const std::string& i, const std::string& c) : key(k), id(i), category(c) { sort_key = make_upper_key(key); } +}; + +index_entry_set index_entries; + +bool operator < (const index_entry_ptr& a, const index_entry_ptr& b) +{ + return a->sort_key < b->sort_key; +} + +boost::tiny_xml::element_list indexes; + +struct id_rewrite_rule +{ + bool base_on_id; + boost::regex id; + std::string new_name; + + id_rewrite_rule(const std::string& i, const std::string& n, bool b) + : base_on_id(b), id(i), new_name(n) {} +}; +std::list id_rewrite_list; + +bool internal_indexes = false; + +struct node_id +{ + const std::string* id; + node_id* prev; +}; + +struct title_info +{ + std::string title; + title_info* prev; +}; + +const std::string* find_attr(boost::tiny_xml::element_ptr node, const char* name) +{ + for(boost::tiny_xml::attribute_list::const_iterator i = node->attributes.begin(); + i != node->attributes.end(); ++i) + { + if(i->name == name) + return &(i->value); + } + return 0; +} + +const std::string* get_current_block_id(node_id const* id) +{ + while((id->id == 0) && (id->prev)) + id = id->prev; + return id->id; +} + +const std::string& get_current_block_title(title_info const* id) +{ + while((id->title.size() == 0) && (id->prev)) + id = id->prev; + return id->title; +} + +std::string get_consolidated_content(boost::tiny_xml::element_ptr node) +{ + std::string result(node->content); + for(boost::tiny_xml::element_list::const_iterator i = node->elements.begin(); + i != node->elements.end(); ++i) + { + result += " "; + result += get_consolidated_content(*i); + } + static const boost::regex e("(^[[:space:]]+)|([[:space:]]+)|([[:space:]]+$)"); + return regex_replace(result, e, "(?2 )", boost::regex_constants::format_all); +} + +std::string rewrite_title(const std::string& title, const std::string& id) +{ + for(std::list::const_iterator i = id_rewrite_list.begin(); i != id_rewrite_list.end(); ++i) + { + if(i->base_on_id) + { + if(regex_match(id, i->id)) + return i->new_name; + } + else + { + if(regex_match(title, i->id)) + return regex_replace(title, i->id, i->new_name); + } + } + return title; +} + +void process_node(boost::tiny_xml::element_ptr node, node_id* prev, title_info* pt, boost::tiny_xml::element_ptr parent_node = boost::tiny_xml::element_ptr()) +{ + node_id id = { 0, prev }; + id.id = find_attr(node, "id"); + title_info title = { "", pt}; + if(node->name == "title") + { + // + // This actually sets the title of the enclosing scope, + // not this tag itself: + // + title.prev->title = get_consolidated_content(node); + std::cout << "Indexing section: " << title.prev->title << std::endl; + } + else if(node->name == "index") + { + indexes.push_back(node); + } + + // + // Search content for items: + // + static const boost::regex space_re("[[:space:]]+"); + if((node->name == "") && node->content.size() && !regex_match(node->content, space_re)) + { + const std::string* pid = get_current_block_id(&id); + const std::string& rtitle = get_current_block_title(&title); + const std::string simple_title = rewrite_title(rtitle, *pid); + + for(std::multiset::const_iterator i = index_terms.begin(); + i != index_terms.end(); ++i) + { + if(regex_search(node->content, i->search_text)) + { + // + // We need to check to see if this term has already been indexed + // in this zone, in order to prevent duplicate entries: + // + std::pair item_index(*pid, i->term); + if(((no_duplicates == false) || (0 == found_terms.count(item_index))) + && (i->search_id.empty() || regex_search(*pid, i->search_id))) + { + found_terms.insert(item_index); + /* + std::cout << "\n " + << rtitle << "\n" + << " " << i->first << "\n" << std::endl; + std::cout << "\n " + << i->first << "\n" + << " " << rtitle << "\n" << std::endl; + */ + + if(internal_indexes == false) + { + boost::tiny_xml::element_ptr p(new boost::tiny_xml::element()); + p->name = "indexterm"; + boost::tiny_xml::element_ptr prim(new boost::tiny_xml::element()); + prim->name = "primary"; + prim->elements.push_front(boost::tiny_xml::element_ptr(new boost::tiny_xml::element())); + prim->elements.front()->content = simple_title; + p->elements.push_front(prim); + + boost::tiny_xml::element_ptr sec(new boost::tiny_xml::element()); + sec->name = "secondary"; + sec->elements.push_front(boost::tiny_xml::element_ptr(new boost::tiny_xml::element())); + sec->elements.front()->content = i->term; + p->elements.push_back(sec); + if(parent_node) + parent_node->elements.push_front(p); + } + index_entry_ptr item1(new index_entry(simple_title)); + index_entry_ptr item2(new index_entry(i->term, *pid)); + if(index_entries.find(item1) == index_entries.end()) + { + index_entries.insert(item1); + } + (**index_entries.find(item1)).sub_keys.insert(item2); + + if(internal_indexes == false) + { + boost::tiny_xml::element_ptr p2(new boost::tiny_xml::element()); + p2->name = "indexterm"; + if(i->category.size()) + { + p2->attributes.push_back(boost::tiny_xml::attribute("type", i->category)); + } + boost::tiny_xml::element_ptr prim2(new boost::tiny_xml::element()); + prim2->name = "primary"; + prim2->elements.push_front(boost::tiny_xml::element_ptr(new boost::tiny_xml::element())); + prim2->elements.front()->content = i->term; + p2->elements.push_front(prim2); + + boost::tiny_xml::element_ptr sec2(new boost::tiny_xml::element()); + sec2->name = "secondary"; + sec2->elements.push_front(boost::tiny_xml::element_ptr(new boost::tiny_xml::element())); + sec2->elements.front()->content = rtitle; + p2->elements.push_back(sec2); + if(parent_node) + parent_node->elements.push_front(p2); + } + index_entry_ptr item3(new index_entry(i->term)); + index_entry_ptr item4(new index_entry(rtitle, *pid)); + if(index_entries.find(item3) == index_entries.end()) + { + index_entries.insert(item3); + if(i->category.size()) + { + (**index_entries.find(item3)).category = i->category; + } + } + (**index_entries.find(item3)).sub_keys.insert(item4); + } + } + } + } + // + // Recurse through children: + // + for(boost::tiny_xml::element_list::const_iterator i = node->elements.begin(); + i != node->elements.end(); ++i) + { + process_node(*i, &id, &title, node); + } +} + +void process_nodes(boost::tiny_xml::element_ptr node) +{ + node_id id = { 0, }; + title_info t = { "", 0 }; + process_node(node, &id, &t); +} + +void load_file(std::string& s, std::istream& is) +{ + s.erase(); + if(is.bad()) return; + s.reserve(is.rdbuf()->in_avail()); + char c; + while(is.get(c)) + { + if(s.capacity() == s.size()) + s.reserve(s.capacity() * 3); + s.append(1, c); + } +} + +void scan_file(const char* file) +{ + static const boost::regex class_e( + // possibly leading whitespace: + "^[[:space:]]*" + // possible template declaration: + "(template[[:space:]]*<[^;:{]+>[[:space:]]*)?" + // class or struct: + "(class|struct)[[:space:]]*" + // leading declspec macros etc: + "(" + "\\<\\w+\\>" + "(" + "[[:blank:]]*\\([^)]*\\)" + ")?" + "[[:space:]]*" + ")*" + // the class name + "(\\<\\w*\\>)[[:space:]]*" + // template specialisation parameters + "(<[^;:{]+>)?[[:space:]]*" + // terminate in { or : + "(\\{|:[^;\\{()]*\\{)" + ); + std::string text; + std::ifstream is(file); + load_file(text, is); + { + boost::sregex_token_iterator i(text.begin(), text.end(), class_e, 5), j; + while(i != j) + { + index_info info; + info.term = i->str(); + info.search_text = "\\<" + i->str() + "\\>"; + info.category = "class_name"; + if(index_terms.count(info) == 0) + { + std::cout << "Indexing class " << info.term << std::endl; + index_terms.insert(info); + } + ++i; + } + } + + // + // Now typedefs: + // + { + static const boost::regex typedef_exp( + "typedef.+?(\\w+)\\s*;"); + boost::sregex_token_iterator i(text.begin(), text.end(), typedef_exp, 1), j; + while(i != j) + { + index_info info; + info.term = i->str(); + info.search_text = "\\<" + i->str() + "\\>"; + info.category = "typedef_name"; + if(index_terms.count(info) == 0) + { + std::cout << "Indexing typedef " << info.term << std::endl; + index_terms.insert(info); + } + ++i; + } + } + + // + // Now macros: + // + { + static const boost::regex e( + "^\\s*#\\s*define\\s+(\\w+)" + ); + boost::sregex_token_iterator i(text.begin(), text.end(), e, 1), j; + while(i != j) + { + index_info info; + info.term = i->str(); + info.search_text = "\\<" + i->str() + "\\>"; + info.category = "macro_name"; + if(index_terms.count(info) == 0) + { + std::cout << "Indexing macro " << info.term << std::endl; + index_terms.insert(info); + } + ++i; + } + } + // + // Now functions: + // + { + static const boost::regex e( + "\\w+\\s+(\\w+)\\s*\\([^\\)]*\\)\\s*\\{" + ); + boost::sregex_token_iterator i(text.begin(), text.end(), e, 1), j; + while(i != j) + { + index_info info; + info.term = i->str(); + info.search_text = "\\<" + i->str() + "\\>"; + info.category = "function_name"; + if(index_terms.count(info) == 0) + { + std::cout << "Indexing function " << info.term << std::endl; + index_terms.insert(info); + } + ++i; + } + } +} + +void scan_dir(const std::string& dir, const std::string& mask, bool recurse) +{ + using namespace boost::filesystem; + boost::regex e(mask); + directory_iterator i(dir), j; + + while(i != j) + { + if(regex_match(i->path().filename(), e)) + { + scan_file(i->path().directory_string().c_str()); + } + else if(recurse && is_directory(i->status())) + { + scan_dir(i->path().directory_string(), mask, recurse); + } + ++i; + } +} + +std::string unquote(const std::string& s) +{ + std::string result(s); + if((s.size() >= 2) && (*s.begin() == '\"') && (*s.rbegin() == '\"')) + { + result.erase(result.begin()); + result.erase(--result.end()); + } + return result; +} + +void process_script(const char* script) +{ + static const boost::regex scan_parser( + "!scan[[:space:]]+" + "([^\"[:space:]]+|\"(?:[^\"\\\\]|\\\\.)+\")" + ); + static const boost::regex scan_dir_parser( + "!scan-path[[:space:]]+" + "([^\"[:space:]]+|\"(?:[^\"\\\\]|\\\\.)+\")" + "[[:space:]]+" + "([^\"[:space:]]+|\"(?:[^\"\\\\]|\\\\.)+\")" + "(?:" + "[[:space:]]+" + "([^\"[:space:]]+|\"(?:[^\"\\\\]|\\\\.)+\")" + ")?" + ); + static const boost::regex entry_parser( + "([^\"[:space:]]+|\"(?:[^\"\\\\]|\\\\.)+\")" + "(?:" + "[[:space:]]+" + "([^\"[:space:]]+|\"(?:[^\"\\\\]|\\\\.)+\")" + "(?:" + "[[:space:]]+" + "([^\"[:space:]]+|\"(?:[^\"\\\\]|\\\\.)+\")" + "(?:" + "[[:space:]]+" + "([^\"[:space:]]+|\"(?:[^\"\\\\]|\\\\.)+\")" + ")?" + ")?" + ")?" + "[[:space:]]*"); + static const boost::regex rewrite_parser( + "!(rewrite-name|rewrite-id)\\s+" + "([^\"[:space:]]+|\"(?:[^\"\\\\]|\\\\.)+\")\\s+" + "([^\"[:space:]]+|\"(?:[^\"\\\\]|\\\\.)+\")" + ); + boost::smatch what; + std::string line; + std::ifstream is(script); + if(is.bad()) + { + std::cerr << "Could not open script " << script << std::endl; + return; + } + while(std::getline(is, line).good()) + { + if(regex_match(line, what, scan_parser)) + { + std::string f = unquote(what[1].str()); + scan_file(f.c_str()); + } + else if(regex_match(line, what, scan_dir_parser)) + { + std::string d = unquote(what[1].str()); + std::string m = unquote(what[2].str()); + bool r = unquote(what[3].str()) == "true"; + scan_dir(d, m, r); + } + else if(regex_match(line, what, rewrite_parser)) + { + bool id = what[1] == "rewrite-id"; + std::string a = unquote(what[2].str()); + std::string b = unquote(what[3].str()); + id_rewrite_list.push_back(id_rewrite_rule(a, b, id)); + } + else if(line.compare(0, 9, "!exclude ") == 0) + { + static const boost::regex delim("([^\"[:space:]]+|\"(?:[^\"\\\\]|\\\\.)+\")"); + boost::sregex_token_iterator i(line.begin() + 9, line.end(), delim, 0), j; + while(i != j) + { + index_info info; + info.term = unquote(*i); + index_terms.erase(info); + ++i; + } + } + else if(regex_match(line, what, entry_parser)) + { + // what[1] is the Index entry + // what[2] is the regex to search for (optional) + // what[3] is a section id that must be matched + // in order for the term to be indexed (optional) + // what[4] is the index category to place the term in (optional). + index_info info; + info.term = unquote(what.str(1)); + std::string s = unquote(what.str(2)); + if(s.size()) + info.search_text = boost::regex(s, boost::regex::icase|boost::regex::perl); + else + info.search_text = boost::regex("\\<" + what.str(1) + "\\>", boost::regex::icase|boost::regex::perl); + if(what[3].matched) + info.search_id = unquote(what.str(3)); + if(what[4].matched) + info.category = unquote(what.str(4)); + index_terms.insert(info); + } + } +} + +std::string get_next_index_id() +{ + static int index_id_count = 0; + std::stringstream s; + s << "idx_id_" << index_id_count; + ++index_id_count; + return s.str(); +} + +void generate_indexes() +{ + for(boost::tiny_xml::element_list::const_iterator i = indexes.begin(); i != indexes.end(); ++i) + { + boost::tiny_xml::element_ptr node = *i; + const std::string* category = find_attr(node, "type"); + bool has_title = false; + + for(boost::tiny_xml::element_list::const_iterator k = (*i)->elements.begin(); k != (*i)->elements.end(); ++k) + { + if((**k).name == "title") + { + has_title = true; + break; + } + } + + boost::tiny_xml::element_ptr navbar(new boost::tiny_xml::element()); + navbar->name = "simplelist"; + boost::tiny_xml::attribute attr; + attr.name = "type"; + attr.value = "horiz"; + navbar->attributes.push_back(attr); + node->elements.push_back(navbar); + + char last_c = 0; + boost::tiny_xml::element_ptr list(new boost::tiny_xml::element()); + list->name = "variablelist"; + boost::tiny_xml::element_ptr listentry; + boost::tiny_xml::element_ptr listitem; + boost::tiny_xml::element_ptr sublist; + node->elements.push_back(list); + + for(index_entry_set::const_iterator i = index_entries.begin(); i != index_entries.end(); ++i) + { + if((0 == category) || (category->size() == 0) || (category && (**i).category == *category)) + { + if(std::toupper((**i).key[0]) != last_c) + { + std::string id_name = get_next_index_id(); + last_c = std::toupper((**i).key[0]); + listentry.reset(new boost::tiny_xml::element()); + listentry->name = "varlistentry"; + boost::tiny_xml::attribute id; + id.name = "ID"; + id.value = id_name; + boost::tiny_xml::element_ptr term(new boost::tiny_xml::element()); + term->name = "term"; + term->content.assign(&last_c, 1); + listentry->elements.push_front(term); + list->elements.push_back(listentry); + listitem.reset(new boost::tiny_xml::element()); + listitem->name = "listitem"; + sublist.reset(new boost::tiny_xml::element()); + sublist->name = "variablelist"; + listitem->elements.push_back(sublist); + listentry->elements.push_back(listitem); + boost::tiny_xml::element_ptr nav(new boost::tiny_xml::element()); + nav->name = "member"; + boost::tiny_xml::element_ptr navlink(new boost::tiny_xml::element()); + navlink->name = "link"; + navlink->content = term->content; + boost::tiny_xml::attribute navid; + navid.name = "linkend"; + navid.value = id_name; + navlink->attributes.push_back(navid); + nav->elements.push_back(navlink); + navbar->elements.push_back(nav); + } + boost::tiny_xml::element_ptr subentry(new boost::tiny_xml::element()); + subentry->name = "varlistentry"; + boost::tiny_xml::element_ptr subterm(new boost::tiny_xml::element()); + subterm->name = "term"; + if((**i).id.empty()) + subterm->content = (**i).key; + else + { + boost::tiny_xml::element_ptr link(new boost::tiny_xml::element()); + link->name = "link"; + link->content = (**i).key; + boost::tiny_xml::attribute at; + at.name = "linkend"; + at.value = (**i).id; + link->attributes.push_back(at); + subterm->elements.push_back(link); + } + subentry->elements.push_back(subterm); + boost::tiny_xml::element_ptr subitem(new boost::tiny_xml::element()); + subitem->name = "listitem"; + subentry->elements.push_back(subitem); + sublist->elements.push_back(subentry); + + boost::tiny_xml::element_ptr secondary_list(new boost::tiny_xml::element()); + secondary_list->name = "simplelist"; + subitem->elements.push_back(secondary_list); + + for(index_entry_set::const_iterator k = (**i).sub_keys.begin(); k != (**i).sub_keys.end(); ++k) + { + boost::tiny_xml::element_ptr member(new boost::tiny_xml::element()); + member->name = "member"; + boost::tiny_xml::element_ptr para(new boost::tiny_xml::element()); + para->name = "para"; + if((**k).id.empty()) + para->content = (**k).key; + else + { + boost::tiny_xml::element_ptr link(new boost::tiny_xml::element()); + link->name = "link"; + boost::tiny_xml::attribute at; + at.name = "linkend"; + at.value = (**k).id; + link->attributes.push_back(at); + link->content = (**k).key; + para->elements.push_back(link); + } + member->elements.push_back(para); + secondary_list->elements.push_back(member); + } + } + } + node->name = "section"; + node->attributes.clear(); + if(!has_title) + { + boost::tiny_xml::element_ptr t(new boost::tiny_xml::element()); + t->name = "title"; + t->content = "Index"; + node->elements.push_front(t); + } + } +} + +std::string infile, outfile; + +int main(int argc, char* argv[]) +{ + if(argc < 2) + return help(); + + // + // Process arguments: + // + for(int i = 1; i < argc; ++i) + { + if(std::strncmp(argv[i], "in=", 3) == 0) + { + infile = argv[i] + 3; + } + else if(std::strncmp(argv[i], "out=", 4) == 0) + { + outfile = argv[i] + 4; + } + else if(std::strncmp(argv[i], "scan=", 5) == 0) + { + scan_file(argv[i] + 5); + } + else if(std::strncmp(argv[i], "script=", 7) == 0) + { + process_script(argv[i] + 7); + } + else if(std::strcmp(argv[i], "--no-duplicates") == 0) + { + no_duplicates = true; + } + else if(std::strcmp(argv[i], "--internal-index") == 0) + { + internal_indexes = true; + } + } + + if(infile.empty()) + { + return help(); + } + if(outfile.empty()) + { + return help(); + } + + std::ifstream is(infile.c_str()); + if(!is.good()) + { + std::cerr << "Unable to open XML data file " << argv[1] << std::endl; + return 1; + } + // + // We need to skip any leading "; + + std::cout << "Indexing " << index_terms.size() << " terms..." << std::endl; + + process_nodes(xml); + + if(internal_indexes) + generate_indexes(); + + std::ofstream os(outfile.c_str()); + os << header << std::endl; + boost::tiny_xml::write(*xml, os); + + return 0; +} diff --git a/src/tiny_xml.cpp b/src/tiny_xml.cpp new file mode 100644 index 0000000..c7326f0 --- /dev/null +++ b/src/tiny_xml.cpp @@ -0,0 +1,222 @@ +// tiny XML sub-set tools implementation -----------------------------------// + +// (C) Copyright Beman Dawes 2002. Distributed under 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 "tiny_xml.hpp" +#include +#include + +namespace +{ + + void eat_whitespace( char & c, std::istream & in ) + { + while ( c == ' ' || c == '\r' || c == '\n' || c == '\t' ) + in.get( c ); + } + + void eat_comment( char & c, std::istream & in ) + { + in.get(c); + if(c != '-') + throw std::string("Invalid comment in XML"); + in.get(c); + if(c != '-') + throw std::string("Invalid comment in XML"); + do{ + while(in.get(c) && (c != '-')); + in.get(c); + if(c != '-') + continue; + in.get(c); + if(c != '>') + continue; + else + break; + } + while(true); + } + + std::string get_name( char & c, std::istream & in ) + { + std::string result; + eat_whitespace( c, in ); + while ( std::strchr( + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-.:", c ) + != 0 ) + { + result += c; + if(!in.get( c )) + throw std::string("xml: unexpected eof"); + } + return result; + } + + void eat_delim( char & c, std::istream & in, + char delim, const std::string & msg ) + { + eat_whitespace( c, in ); + if ( c != delim ) + throw std::string("xml syntax error, expected ") + delim + + " (" + msg + ")"; + in.get( c ); + } + + std::string get_value( char & c, std::istream & in ) + { + std::string result; + while ( c != '\"' ) + { + result += c; + in.get( c ); + } + in.get( c ); + return result; + } + +} + +namespace boost +{ + namespace tiny_xml + { + + // parse -----------------------------------------------------------------// + + element_ptr parse( std::istream & in, const std::string & msg ) + { + char c = 0; // current character + element_ptr e( new element ); + + if(!in.get( c )) + throw std::string("xml: unexpected eof"); + if ( c == '<' ) + if(!in.get( c )) + throw std::string("xml: unexpected eof"); + + if(c == '!') + { + eat_comment(c, in); + return e; + } + + e->name = get_name( c, in ); + eat_whitespace( c, in ); + + // attributes + while ( (c != '>') && (c != '/') ) + { + attribute a; + a.name = get_name( c, in ); + + eat_delim( c, in, '=', msg ); + eat_delim( c, in, '\"', msg ); + + a.value = get_value( c, in ); + + e->attributes.push_back( a ); + eat_whitespace( c, in ); + } + if(c == '/') + { + if(!in.get( c )) // next after '/' + throw std::string("xml: unexpected eof"); + eat_whitespace( c, in ); + if(c != '>') + throw std::string("xml: unexpected /"); + return e; + } + if(!in.get( c )) // next after '>' + throw std::string("xml: unexpected eof"); + + //eat_whitespace( c, in ); + + do{ + // sub-elements + while ( c == '<' ) + { + if ( in.peek() == '/' ) + break; + e->elements.push_back( parse( in, msg ) ); + in.get( c ); // next after '>' + //eat_whitespace( c, in ); + } + if (( in.peek() == '/' ) && (c == '<')) + break; + + // content + if ( (c != '<') ) + { + element_ptr sub( new element ); + while ( c != '<' ) + { + sub->content += c; + if(!in.get( c )) + throw std::string("xml: unexpected eof"); + } + e->elements.push_back( sub ); + } + + assert( c == '<' ); + if( in.peek() == '/' ) + break; + }while(true); + + in.get(c); + eat_delim( c, in, '/', msg ); + std::string end_name( get_name( c, in ) ); + if ( e->name != end_name ) + throw std::string("xml syntax error: beginning name ") + + e->name + " did not match end name " + end_name + + " (" + msg + ")"; + + eat_delim( c, in, '>', msg ); + if(c != '>') + { + // we've eaten one character past the >, put it back: + if(!in.putback(c)) + throw std::string("Unable to put back character"); + } + return e; + } + + // write ---------------------------------------------------------------// + + void write( const element & e, std::ostream & out ) + { + if(e.name.size()) + { + out << "<" << e.name; + if ( !e.attributes.empty() ) + { + for( attribute_list::const_iterator itr = e.attributes.begin(); + itr != e.attributes.end(); ++itr ) + { + out << " " << itr->name << "=\"" << itr->value << "\""; + } + } + out << ">"; + } + if ( !e.elements.empty() ) + { + for( element_list::const_iterator itr = e.elements.begin(); + itr != e.elements.end(); ++itr ) + { + write( **itr, out ); + } + } + if ( !e.content.empty() ) + { + out << e.content; + } + if(e.name.size()) + { + out << ""; + } + } + + } // namespace tiny_xml +} // namespace boost + diff --git a/src/tiny_xml.hpp b/src/tiny_xml.hpp new file mode 100644 index 0000000..ee33946 --- /dev/null +++ b/src/tiny_xml.hpp @@ -0,0 +1,70 @@ +// tiny XML sub-set tools --------------------------------------------------// + +// (C) Copyright Beman Dawes 2002. Distributed under 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) + +// Provides self-contained tools for this XML sub-set: +// +// element ::= { "<" name { name "=" "\"" value "\"" } ">" +// {element} [contents] "" } +// +// The point of "self-contained" is to minimize tool-chain dependencies. + +#ifndef BOOST_TINY_XML_H +#define BOOST_TINY_XML_H + +#include "boost/smart_ptr.hpp" // for shared_ptr +#include "boost/utility.hpp" // for noncopyable +#include +#include +#include + +namespace boost +{ + namespace tiny_xml + { + class element; + struct attribute + { + std::string name; + std::string value; + + attribute(){} + attribute( const std::string & name, const std::string & value ) + : name(name), value(value) {} + }; + typedef boost::shared_ptr< element > element_ptr; + typedef std::list< element_ptr > element_list; + typedef std::list< attribute > attribute_list; + + class element + : private boost::noncopyable // because deep copy sematics would be required + { + public: + std::string name; + attribute_list attributes; + element_list elements; + std::string content; + + element() {} + explicit element( const std::string & name ) : name(name) {} + }; + + element_ptr parse( std::istream & in, const std::string & msg ); + // Precondition: stream positioned at either the initial "<" + // or the first character after the initial "<". + // Postcondition: stream positioned at the first character after final + // ">" (or eof). + // Returns: an element_ptr to an element representing the parsed stream. + // Throws: std::string on syntax error. msg appended to what() string. + + void write( const element & e, std::ostream & out ); + + } +} + +#endif // BOOST_TINY_XML_H + + +