Commit Jeroen Witmond's xml-to-text translator, and use it for the FAQ.
Less double maintenance, hoorah!



git-svn-id: svn://svn.valgrind.org/valgrind/trunk@4830 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/docs/Makefile.am b/docs/Makefile.am
index fee2b2a..b8307f0 100644
--- a/docs/Makefile.am
+++ b/docs/Makefile.am
@@ -7,7 +7,7 @@
 # Comment out the next line to skip building print docs.  The default
 # is not to skip building print docs.  Note, after changing it
 # you of course need to re-run configure to make it take effect.
-BUILD_ALL_DOCS=yes
+BUILD_ALL_DOCS=no
 
 ##-------------------------------------------------------------
 ## END OF HACK
@@ -44,18 +44,24 @@
 
 # stylesheet processor
 XSLTPROC       = xsltproc
-XSLTPROC_FLAGS = --nonet --xinclude 
+XSLTPROC_FLAGS = --xinclude 
 
 # stylesheets
 XSL_HTML_CHUNK_STYLE  = $(mylibdir)/vg-html-chunk.xsl
 XSL_HTML_SINGLE_STYLE = $(mylibdir)/vg-html-single.xsl
 XSL_FO_STYLE          = $(mylibdir)/vg-fo.xsl
 
-all-docs: html-docs print-docs
+all-docs: FAQ.txt html-docs print-docs
 
 valid:
 	$(XMLLINT) $(XMLLINT_FLAGS) $(myxmldir)/index.xml
 
+# The text version of the FAQ.
+FAQ.txt: $(myxmldir)/FAQ.xml $(myxmldir)/vg-entities.xml $(mylibdir)/*.xslt
+	$(XSLTPROC) $(XSLTPROC_FLAGS) $(mylibdir)/untag-inline.xslt $(myxmldir)/FAQ.xml | \
+	$(XSLTPROC) $(XSLTPROC_FLAGS) $(mylibdir)/docbook2text.xslt - > FAQ.txt
+	
+
 # chunked html
 html-docs:
 	@echo "Generating html files..."
@@ -113,14 +119,17 @@
 # This is done at 'make dist' time.  It builds the html and print docs
 # and copies them into the docs/ directory in the tarball.
  ifeq ($(BUILD_ALL_DOCS),yes)
-dist-hook: html-docs print-docs
+dist-hook: FAQ.txt html-docs print-docs
 	cp -r html $(distdir)
+	cp FAQ.txt $(distdir)/..
 	cp print/index.pdf $(distdir)
 	cp print/index.ps $(distdir)
  else
-dist-hook: html-docs
+dist-hook: FAQ.txt html-docs
+	cp FAQ.txt $(distdir)/..
 	cp -r html $(distdir)
  endif
 
 distclean-local:
 	rm -rf html print
+	rm -f $(top_builddir)/FAQ.txt
diff --git a/docs/README b/docs/README
index af8fa16..6f6b5e3 100644
--- a/docs/README
+++ b/docs/README
@@ -178,12 +178,6 @@
 - http://cvs.sourceforge.net/viewcvs.py/perl-xml/perl-xml-faq/
 
 
-TODO CRUCIAL:
--------------
-- Need to generate text FAQ from the valgrind/docs/xml/FAQ.xml (done at 'make
-  dist' time along with the HTML docs using the "dist-hook"), and remove the
-  old text FAQ which is in valgrind/.
-
 TODO LESS CRUCIAL:
 ------------------
 - add the HOWTO doc?
diff --git a/docs/lib/Makefile.am b/docs/lib/Makefile.am
index 627e39d..c589900 100644
--- a/docs/lib/Makefile.am
+++ b/docs/lib/Makefile.am
@@ -1,6 +1,16 @@
 EXTRA_DIST = \
+	README_XML2TXT.txt \
+	copy.xslt \
+	text.justify.xslt \
+	docbook2text.xslt \
+	text.wrap.xslt \
+	str.dup.xslt \
+	untag-inline.xslt \
+	str.find-last.xslt \
 	vg-common.xsl \
 	vg-fo.xsl \
 	vg-html-chunk.xsl \
 	vg-html-single.xsl \
 	vg_basic.css
+
+	
diff --git a/docs/lib/README_XML2TXT.txt b/docs/lib/README_XML2TXT.txt
new file mode 100644
index 0000000..3d70bec
--- /dev/null
+++ b/docs/lib/README_XML2TXT.txt
@@ -0,0 +1,59 @@
+README.txt file for the FAQ.xml to FAQ.txt transformer.
+=======================================================
+
+In valgrind-3.1.SVN, file docs/README contains, under the heading
+"TODO CRUCIAL", the item "Need to generate text FAQ from the
+valgrind/docs/xml/FAQ.xml (done at 'make dist' time along with the
+HTML docs using the 'dist-hook'), and remove the old text FAQ which is
+in valgrind/."  This is an attempt to resolve this item using xsltproc
+and a number of xml style sheets. It is a hack in the sense that it
+does not support all of docbook, but only the subset currently used by
+file docs/xml/FAQ.xml.
+
+The transformation is done in two stages:
+
+1. Inline elements (literal, computeroutput and ulink) are replaced
+   with the corresponding text by stylesheet untag-inline.xslt. This
+   stylesheet uses copy.xslt to handle the non-inline elements.
+
+2. The actual formatting is done by stylesheet docbook2text.xslt. It
+   uses stylesheets str.dup.xslt, str.find-last.xslt,
+   text.justify.xslt and text.wrap.xslt to handle the formatting of
+   the text into a column with the approproate width and indentation.
+
+Stylesheets untag-inline.xslt and docbook2text.xslt are original
+work. Stylesheets copy.xslt, str.dup.xslt, str.find-last.xslt,
+text.justify.xslt and text.wrap.xslt are copied with some adaptations
+from the examples supplied with the XSLT Cookbook by Sal Mangano, (C)
+2003 O'Reilly & Associates, ISBN 0-596-00372-2. The O'Reilly Policy on
+Re-Use of Code Examples from Books
+<http://www.oreilly.com/pub/a/oreilly/ask_tim/2001/codepolicy.html>
+allows the use of these style sheets in valgrind for this purpose.
+
+The tarball contains:
+
+- File README.txt (this file).
+
+- the stylesheets copy.xslt, docbook2text.xslt, str.dup.xslt,
+  str.find-last.xslt, text.justify.xslt, text.wrap.xslt and
+  untag-inline.xslt.
+
+- File faq.txt.patch adds the generation of FAQ.txt to file
+  docs/Makefile.am. It is based on the assumptions that
+  * file FAQ.txt will be generated in directory docs.
+  * the stylesheets will be stored in directory docs/lib.
+  If a different output width is required (e.g. 80), you can use
+  command 
+    $(XSLTPROC) $(XSLTPROC_FLAGS) $(libdir)/untag-inline.xslt $(xmldir)/FAQ.xml | \
+    $(XSLTPROC) $(XSLTPROC_FLAGS) --stringparam width 80 $(libdir)/docbook2text.xslt - > FAQ.txt
+
+- File FAQ.txt as generated on my system (Debian 3.1).
+
+Software used:
+xsltproc was compiled against libxml 20616, libxslt 10112 and libexslt 810
+libxslt 10112 was compiled against libxml 20616
+libexslt 810 was compiled against libxml 20616
+
+
+Copyright 2005 Jeroen N. Witmond, jnw@xs4all.nl
+GNU GENERAL PUBLIC LICENSE Version 2, June 1991 applies.
diff --git a/docs/lib/copy.xslt b/docs/lib/copy.xslt
new file mode 100644
index 0000000..b2c565d
--- /dev/null
+++ b/docs/lib/copy.xslt
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+<!-- This file was copied with some adaptations from the examples
+supplied with the XSLT Cookbook by Sal Mangano, (C) 2003 O'Reilly &
+Associates, ISBN 0-596-00372-2. -->
+
+<xsl:output method="xml"/>
+
+<xsl:template match="/ | node() | @* | comment() | processing-instruction()">
+  <xsl:copy>
+    <xsl:apply-templates select="node() | @*"/>
+  </xsl:copy>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/docs/lib/docbook2text.xslt b/docs/lib/docbook2text.xslt
new file mode 100644
index 0000000..becc862
--- /dev/null
+++ b/docs/lib/docbook2text.xslt
@@ -0,0 +1,317 @@
+<?xml version="1.0" encoding="UTF-8"?> <!-- -*- sgml -*- -->
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:text="http://www.ora.com/XSLTCookbook/namespaces/text"
+  xmlns:str="http://www.ora.com/XSLTCookbook/namespaces/strings">
+
+<xsl:include href="text.wrap.xslt"/>
+
+<xsl:strip-space elements="*"/>
+<xsl:preserve-space elements="screen programlisting"/>
+<xsl:output method="text"/>
+
+<!-- Transform a subset of docbook/xml into plain text. This -->
+<!-- stylesheet assumes that all elements that are to be formatted -->
+<!-- inline already have been handled by untag-inline.xslt. -->
+
+<!-- Maximum number of characters on one line. --> 
+<xsl:param name="width" select="72"/>
+
+<!-- This stylesheet uses two named templates. The template named -->
+<!-- "header" writes its input, followed by a line of '~'s of -->
+<!-- the same length. The template named "ruler" produces a line of -->
+<!-- $width '-'s. They are implemented at the bottom of this file. -->
+
+<xsl:template match="/">
+  <!-- Title 'page' stuff. -->
+  <xsl:call-template name="header">
+    <xsl:with-param name="input" select="book/title"/>
+  </xsl:call-template>
+
+  <xsl:call-template name="header">
+    <xsl:with-param name="input" select="book/bookinfo/releaseinfo"/>
+  </xsl:call-template>
+  <xsl:text>&#xa;</xsl:text>
+
+  <!-- List of sections. -->
+  <xsl:text>Table of Contents&#xa;</xsl:text>
+  <xsl:apply-templates select="book/sect1" mode="toc"/>
+  <xsl:text>&#xa;</xsl:text>
+
+  <!-- Contents. -->
+  <xsl:apply-templates select="book/sect1"/>
+</xsl:template>
+
+<xsl:template match="sect1" mode="toc">
+  <xsl:value-of select="position()"/>
+  <xsl:text>. </xsl:text>
+  <xsl:value-of select="title"/>
+  <xsl:text>&#xa;</xsl:text>
+</xsl:template>
+
+<!-- Processing of the contents starts here. -->
+
+<xsl:template match="sect1">
+  <!-- The FAQ contains two types of sect1: those containing a
+    qandaset (actually an unspecified number), and those containing a
+    sequence of paras. To get the number of blank lines right, these
+    must be treated separately. -->
+
+  <xsl:variable name="sectno" select="position()"/>
+
+  <xsl:call-template name="ruler"/>
+  <xsl:value-of select="$sectno"/>
+  <xsl:text>. </xsl:text>
+  <xsl:value-of select="title"/>
+  <xsl:text>&#xa;</xsl:text>
+  <xsl:call-template name="ruler"/>
+  <xsl:text>&#xa;</xsl:text>
+
+  <xsl:choose>
+    <xsl:when test="qandaset">
+      <xsl:apply-templates select="qandaset|para">
+        <xsl:with-param name="sectno" select="$sectno"/>
+      </xsl:apply-templates>
+    </xsl:when>
+
+    <xsl:when test="para">
+      <xsl:for-each select="para|screen|programlisting|itemizedlist|orderedlist">
+        <xsl:apply-templates select="."/>
+
+        <xsl:if test="position() != last()">
+            <xsl:text>&#xa;</xsl:text>
+        </xsl:if>
+      </xsl:for-each>
+    </xsl:when>
+
+    <!-- Oops. sect1 contains elements we do not yet handle. -->
+    <xsl:otherwise>
+      <xsl:message>template match="sect1": Encountered
+      &lt;<xsl:value-of select="name(.)"/>&gt;.</xsl:message>
+    </xsl:otherwise>
+  </xsl:choose>
+
+  <xsl:text>&#xa;</xsl:text>
+</xsl:template>
+
+<xsl:template match="qandaset">
+  <xsl:param name="sectno"/>
+
+  <xsl:apply-templates select="qandaentry">
+    <xsl:with-param name="sectno" select="$sectno"/>
+  </xsl:apply-templates>
+</xsl:template>
+
+<xsl:template match="qandaentry">
+  <xsl:param name="sectno"/>
+
+  <xsl:variable name="questno" select="position()"/>
+
+  <xsl:variable name="prefix">
+    <xsl:value-of select="$sectno"/>
+    <xsl:text>.</xsl:text>
+    <xsl:value-of select="$questno"/>
+    <xsl:text>. </xsl:text>
+  </xsl:variable>
+  <xsl:variable name="prefix-length" select="string-length($prefix)"/>
+
+  <xsl:if test="$questno > 1">
+    <xsl:text>&#xa;</xsl:text>
+    <xsl:call-template name="ruler"/>
+    <xsl:text>&#xa;</xsl:text>
+  </xsl:if>
+
+  <xsl:apply-templates select="question">
+    <xsl:with-param name="prefix" select="$prefix"/>
+    <xsl:with-param name="indent" select="$prefix-length"/>
+  </xsl:apply-templates>
+
+  <xsl:text>&#xa;</xsl:text>
+
+  <xsl:apply-templates select="answer"/>
+</xsl:template>
+
+<xsl:template match="question">
+  <xsl:param name="prefix"/>
+  <xsl:param name="indent" select="0"/>
+
+  <xsl:for-each select="para|screen|programlisting">
+    <xsl:choose>
+      <xsl:when test="position() = 1 and $prefix">
+        <xsl:value-of select="$prefix"/>
+        <xsl:apply-templates select=".">
+          <xsl:with-param name="indent" select="$indent"/>
+          <xsl:with-param name="dofirst" select="0"/>
+        </xsl:apply-templates>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:apply-templates select=".">
+          <xsl:with-param name="indent" select="$indent"/>
+        </xsl:apply-templates>
+      </xsl:otherwise>
+    </xsl:choose>
+
+    <xsl:if test="position() != last()">
+        <xsl:text>&#xa;</xsl:text>
+    </xsl:if>
+  </xsl:for-each>
+</xsl:template>
+
+<xsl:template match="answer">
+  <xsl:param name="indent" select="0"/>
+
+  <xsl:for-each select="para|screen|programlisting|itemizedlist|orderedlist">
+    <xsl:apply-templates select=".">
+      <xsl:with-param name="indent" select="$indent"/>
+    </xsl:apply-templates>
+
+    <xsl:if test="position() != last()">
+        <xsl:text>&#xa;</xsl:text>
+    </xsl:if>
+  </xsl:for-each>
+</xsl:template>
+
+<xsl:template match="para">
+  <xsl:param name="indent" select="0"/>
+  <xsl:param name="dofirst" select="1"/>
+
+  <xsl:for-each select="node()">
+    <xsl:choose>
+      <!-- Lists and blocks as children. -->
+      <xsl:when test="self::screen|self::programlisting|
+		      self::itemizedlist|self::orderedlist">
+        <xsl:apply-templates select=".">
+          <xsl:with-param name="indent" select="$indent"/>
+        </xsl:apply-templates>
+
+        <xsl:if test="position() != last()">
+            <xsl:text>&#xa;</xsl:text>
+        </xsl:if>
+      </xsl:when>
+
+      <!-- Text. Inline elements have been flattened by
+           untag-inline.xslt. -->
+      <xsl:when test="self::text()">
+        <xsl:choose>
+          <xsl:when test="position() = 1 and $dofirst = 0">
+            <xsl:apply-templates select="." mode="text:wrap">
+              <xsl:with-param name="width" select="$width"/>
+              <xsl:with-param name="indent" select="$indent"/>
+              <xsl:with-param name="dofirst" select="0"/>
+            </xsl:apply-templates>
+          </xsl:when>
+          <xsl:otherwise>
+            <xsl:apply-templates select="." mode="text:wrap">
+              <xsl:with-param name="width" select="$width"/>
+              <xsl:with-param name="indent" select="$indent"/>
+            </xsl:apply-templates>
+          </xsl:otherwise>
+        </xsl:choose>
+      </xsl:when>
+
+      <!-- Oops. para contains elements we do not yet handle. -->
+      <xsl:otherwise>
+        <xsl:message>template match="para": Encountered
+        &lt;<xsl:value-of select="name(.)"/>&gt;.</xsl:message>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:for-each>
+</xsl:template>
+
+<xsl:template match="screen|programlisting">
+  <xsl:param name="indent" select="0"/>
+  <xsl:param name="dofirst" select="1"/><!-- ignored. -->
+
+  <xsl:variable name="myindent" select=" $indent + 2 " />
+
+  <xsl:apply-templates select="." mode="text:dump">
+    <xsl:with-param name="input" select="text()"/>
+    <xsl:with-param name="indent" select="$myindent"/>
+  </xsl:apply-templates>
+</xsl:template>
+
+<xsl:template match="itemizedlist">
+  <xsl:param name="indent" select="0"/>
+
+  <xsl:variable name="prefix" select=" '* ' "/>
+  <xsl:variable name="prefix-length" select="string-length($prefix)"/>
+
+  <xsl:for-each select="listitem">
+    <xsl:apply-templates select=".">
+      <xsl:with-param name="prefix" select="$prefix"/>
+      <xsl:with-param name="indent" select="$prefix-length"/>
+    </xsl:apply-templates>
+
+    <xsl:if test="position() != last()">
+        <xsl:text>&#xa;</xsl:text>
+    </xsl:if>
+  </xsl:for-each>
+</xsl:template>
+
+<xsl:template match="orderedlist">
+  <xsl:param name="indent" select="0"/>
+
+  <xsl:for-each select="listitem">
+    <xsl:variable name="prefix">
+      <xsl:value-of select="position()"/>
+      <xsl:text>. </xsl:text>
+    </xsl:variable>
+    <xsl:variable name="prefix-length" select="string-length($prefix)"/>
+
+    <xsl:apply-templates select=".">
+      <xsl:with-param name="prefix" select="$prefix"/>
+      <xsl:with-param name="indent" select="$prefix-length"/>
+    </xsl:apply-templates>
+
+    <xsl:if test="position() != last()">
+        <xsl:text>&#xa;</xsl:text>
+    </xsl:if>
+  </xsl:for-each>
+</xsl:template>
+
+<xsl:template match="listitem">
+  <xsl:param name="prefix"/>
+  <xsl:param name="indent" select="0"/>
+
+  <xsl:for-each select="para|screen|programlisting">
+    <xsl:choose>
+      <xsl:when test="position() = 1 and $prefix">
+        <xsl:value-of select="$prefix"/>
+        <xsl:apply-templates select=".">
+          <xsl:with-param name="indent" select="$indent"/>
+          <xsl:with-param name="dofirst" select="0"/>
+        </xsl:apply-templates>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:apply-templates select=".">
+          <xsl:with-param name="indent" select="$indent"/>
+        </xsl:apply-templates>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:for-each>
+</xsl:template>
+
+<!-- Named utility templates. -->
+
+<xsl:template name="header">
+  <xsl:param name="input" select="0"/>
+  <xsl:variable name="input-length" select="string-length($input)"/>
+
+  <xsl:value-of select="$input"/>
+  <xsl:text>&#xa;</xsl:text>
+
+  <xsl:call-template name="str:dup">
+    <xsl:with-param name="input" select=" '~' "/>
+    <xsl:with-param name="count" select="$input-length"/>
+  </xsl:call-template>
+  <xsl:text>&#xa;</xsl:text>
+</xsl:template>
+
+<xsl:template name="ruler">
+  <xsl:call-template name="str:dup">
+    <xsl:with-param name="input" select=" '-' "/>
+    <xsl:with-param name="count" select="$width"/>
+  </xsl:call-template>
+  <xsl:text>&#xa;</xsl:text>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/docs/lib/str.dup.xslt b/docs/lib/str.dup.xslt
new file mode 100644
index 0000000..564b342
--- /dev/null
+++ b/docs/lib/str.dup.xslt
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:str="http://www.ora.com/XSLTCookbook/namespaces/strings">
+
+<!-- This file was copied with some adaptations from the examples
+supplied with the XSLT Cookbook by Sal Mangano, (C) 2003 O'Reilly &
+Associates, ISBN 0-596-00372-2. -->
+
+  <xsl:template name="str:dup">
+    <xsl:param name="input"/>
+    <xsl:param name="count" select="1"/>
+
+    <xsl:choose>
+      <xsl:when test="not($count) or not($input)"/>
+      <xsl:when test="$count = 1">
+        <xsl:value-of select="$input"/>
+      </xsl:when>
+      <xsl:otherwise>
+        <!-- If $count is odd append an extra copy of input -->
+        <xsl:if test="$count mod 2">
+          <xsl:value-of select="$input"/>
+        </xsl:if>
+        <!-- Recursively apply template after doubling input and 
+			halving count -->
+        <xsl:call-template name="str:dup">
+          <xsl:with-param name="input" select="concat($input,$input)"/>
+          <xsl:with-param name="count" select="floor($count div 2)"/>
+        </xsl:call-template>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+</xsl:stylesheet>
diff --git a/docs/lib/str.find-last.xslt b/docs/lib/str.find-last.xslt
new file mode 100644
index 0000000..2700fd3
--- /dev/null
+++ b/docs/lib/str.find-last.xslt
@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" id="str.find-last"
+  xmlns:str="http://www.ora.com/XSLTCookbook/namespaces/strings" extension-element-prefixes="str">
+
+<!-- This file was copied with some adaptations from the examples
+supplied with the XSLT Cookbook by Sal Mangano, (C) 2003 O'Reilly &
+Associates, ISBN 0-596-00372-2. -->
+
+<xsl:template name="str:substring-before-last"> 
+  <xsl:param name="input"/>
+  <xsl:param name="substr"/>
+  
+  <xsl:if test="$substr and contains($input, $substr)">
+    <xsl:variable name="temp" select="substring-after($input, $substr)" />
+    <xsl:value-of select="substring-before($input, $substr)" />
+    <xsl:if test="contains($temp, $substr)">
+      <xsl:value-of select="$substr" />
+      <xsl:call-template name="str:substring-before-last">
+        <xsl:with-param name="input" select="$temp" />
+        <xsl:with-param name="substr" select="$substr" />
+      </xsl:call-template>
+    </xsl:if>
+  </xsl:if>
+  
+</xsl:template>
+
+
+<xsl:template name="str:substring-after-last">
+  <xsl:param name="input"/>
+  <xsl:param name="substr"/>
+  
+  <!-- Extract the string which comes after the first occurence -->
+  <xsl:variable name="temp" select="substring-after($input,$substr)"/>
+  
+  <xsl:choose>
+  	<xsl:when test="$substr and contains($temp,$substr)">
+  		<xsl:call-template name="str:substring-after-last">
+  			<xsl:with-param name="input" select="$temp"/>
+  			<xsl:with-param name="substr" select="$substr"/>
+  		</xsl:call-template>
+  	</xsl:when>
+  	<xsl:otherwise>
+  		<xsl:value-of select="$temp"/>
+  	</xsl:otherwise>
+  </xsl:choose>
+</xsl:template> 
+
+
+<xsl:template match="xsl:stylesheet[@id='str.find-last'] | xsl:include[@href='str.find-last.xslt'] " >
+<tests>
+
+<!-- before -->
+	<test name="str:substring-before-last with no occurences of yes">
+	<xsl:call-template name="str:substring-before-last">
+		<xsl:with-param name="input" select=" 'No occurences' "/>
+		<xsl:with-param name="substr" select=" 'yes' "/>
+	</xsl:call-template>
+	</test>
+	
+	<test name="str:substring-before-last starts with yes">
+	<xsl:call-template name="str:substring-before-last">
+		<xsl:with-param name="input" select=" 'yes occurences' "/>
+		<xsl:with-param name="substr" select=" 'yes' "/>
+	</xsl:call-template>
+	</test>
+
+	<test name="str:substring-before-last starts with yes and ends with yes">
+	<xsl:call-template name="str:substring-before-last">
+		<xsl:with-param name="input" select=" 'yes occurences yes' "/>
+		<xsl:with-param name="substr" select=" 'yes' "/>
+	</xsl:call-template>
+	</test>
+
+	<test name="str:substring-before-last 3 yes">
+	<xsl:call-template name="str:substring-before-last">
+		<xsl:with-param name="input" select=" 'yesyesyes' "/>
+		<xsl:with-param name="substr" select=" 'yes' "/>
+	</xsl:call-template>
+	</test>
+	<test name="str:substring-before-last empty input">
+	<xsl:call-template name="str:substring-before-last">
+		<xsl:with-param name="substr" select=" 'yes' "/>
+	</xsl:call-template>
+	</test>
+	
+	<test name="str:substring-before-last empty search">
+	<xsl:call-template name="str:substring-before-last">
+		<xsl:with-param name="input" select=" 'No occurences' "/>
+	</xsl:call-template>
+
+	</test>
+
+	<test name="str:substring-before-last large">
+	<xsl:call-template name="str:substring-before-last">
+		<xsl:with-param name="input" select=" 'yesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyesyes' "/>
+		<xsl:with-param name="substr" select=" 'yes' "/>
+	</xsl:call-template>
+
+
+	</test>
+
+<!-- after -->
+
+	<test name="str:substring-after-last with no occurences of yes">
+	<xsl:call-template name="str:substring-after-last">
+		<xsl:with-param name="input" select=" 'No occurences' "/>
+		<xsl:with-param name="substr" select=" 'yes' "/>
+	</xsl:call-template>
+	</test>
+	
+	<test name="str:substring-after-last starts with yes">
+	<xsl:call-template name="str:substring-after-last">
+		<xsl:with-param name="input" select=" 'yes occurences' "/>
+		<xsl:with-param name="substr" select=" 'yes' "/>
+	</xsl:call-template>
+	</test>
+
+	<test name="str:substring-after-last starts with yes and ends with yes">
+	<xsl:call-template name="str:substring-after-last">
+		<xsl:with-param name="input" select=" 'yes occurences yes' "/>
+		<xsl:with-param name="substr" select=" 'yes' "/>
+	</xsl:call-template>
+	</test>
+
+	<test name="str:substring-after-last 3 yes">
+	<xsl:call-template name="str:substring-after-last">
+		<xsl:with-param name="input" select=" 'yesyesyes' "/>
+		<xsl:with-param name="substr" select=" 'yes' "/>
+	</xsl:call-template>
+	</test>
+
+	<test name="str:substring-after-last 3 yes then no">
+	<xsl:call-template name="str:substring-after-last">
+		<xsl:with-param name="input" select=" 'yesyesyesno' "/>
+		<xsl:with-param name="substr" select=" 'yes' "/>
+	</xsl:call-template>
+	</test>
+	
+	<test name="str:substring-after-last empty input">
+	<xsl:call-template name="str:substring-after-last">
+		<xsl:with-param name="substr" select=" 'yes' "/>
+	</xsl:call-template>
+	</test>
+	
+	<test name="str:substring-after-last empty search">
+	<xsl:call-template name="str:substring-after-last">
+		<xsl:with-param name="input" select=" 'No occurences' "/>
+	</xsl:call-template>
+
+	</test>
+
+</tests>
+</xsl:template>
+
+ <xsl:template match="text()"/>
+  
+</xsl:stylesheet>
diff --git a/docs/lib/text.justify.xslt b/docs/lib/text.justify.xslt
new file mode 100644
index 0000000..a6a8992
--- /dev/null
+++ b/docs/lib/text.justify.xslt
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:str="http://www.ora.com/XSLTCookbook/namespaces/strings"
+  xmlns:text="http://www.ora.com/XSLTCookbook/namespaces/text" extension-element-prefixes="text">
+
+<!-- This file was copied with some adaptations from the examples
+supplied with the XSLT Cookbook by Sal Mangano, (C) 2003 O'Reilly &
+Associates, ISBN 0-596-00372-2. -->
+
+<xsl:include href="str.dup.xslt"/>
+
+<xsl:template name="text:justify">
+  <xsl:param name="value" /> 
+  <xsl:param name="width" select="10"/>
+  <xsl:param name="align" select=" 'left' "/>
+
+  <!-- Truncate if too long -->  
+  <xsl:variable name="output" select="substring($value,1,$width)"/>
+  
+  <xsl:choose>
+    <xsl:when test="$align = 'left'">
+      <xsl:value-of select="$output"/>
+      <xsl:call-template name="str:dup">
+        <xsl:with-param name="input" select=" ' ' "/>
+        <xsl:with-param name="count" select="$width - string-length($output)"/>
+      </xsl:call-template>
+    </xsl:when>
+    <xsl:when test="$align = 'right'">
+      <xsl:call-template name="str:dup">
+        <xsl:with-param name="input" select=" ' ' "/>
+        <xsl:with-param name="count" select="$width - string-length($output)"/>
+      </xsl:call-template>
+      <xsl:value-of select="$output"/>
+    </xsl:when>
+    <xsl:when test="$align = 'center'">
+      <xsl:call-template name="str:dup">
+        <xsl:with-param name="input" select=" ' ' "/>
+        <xsl:with-param name="count" select="floor(($width - string-length($output)) div 2)"/>
+      </xsl:call-template>
+      <xsl:value-of select="$output"/>
+      <xsl:call-template name="str:dup">
+        <xsl:with-param name="input" select=" ' ' "/>
+        <xsl:with-param name="count" select="ceiling(($width - string-length($output)) div 2)"/>
+      </xsl:call-template>
+    </xsl:when>
+    <xsl:otherwise>INVALID ALIGN</xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/docs/lib/text.wrap.xslt b/docs/lib/text.wrap.xslt
new file mode 100644
index 0000000..e77819e
--- /dev/null
+++ b/docs/lib/text.wrap.xslt
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" id="text.wrap"
+  xmlns:str="http://www.ora.com/XSLTCookbook/namespaces/strings" 
+  xmlns:text="http://www.ora.com/XSLTCookbook/namespaces/text" exclude-result-prefixes="text">
+
+<!-- This file was copied with some adaptations from the examples
+supplied with the XSLT Cookbook by Sal Mangano, (C) 2003 O'Reilly &
+Associates, ISBN 0-596-00372-2. -->
+
+<xsl:include href="str.find-last.xslt"/>
+<xsl:include href="text.justify.xslt"/>
+
+<xsl:template match="node() | @*" mode="text:wrap" name="text:wrap">
+  <xsl:param name="input" select="normalize-space()"/> 
+  <xsl:param name="width" select="70"/>
+  <xsl:param name="indent" select="0"/>
+  <xsl:param name="dofirst" select="1"/>
+  <xsl:param name="align" select=" 'left' "/>
+
+  <xsl:variable name="effective" select="$width - $indent"/>
+
+  <xsl:if test="$input">
+    <xsl:variable name="line">
+      <xsl:choose>
+        <xsl:when test="string-length($input) > $effective">
+          <xsl:variable name="candidate-line" select="substring($input,1,$effective)"/>
+          <xsl:choose>
+            <xsl:when test="contains($candidate-line,' ')">
+              <xsl:call-template name="str:substring-before-last">
+                  <xsl:with-param name="input" select="$candidate-line"/>
+                  <xsl:with-param name="substr" select=" ' ' "/>
+              </xsl:call-template>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="$candidate-line"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of select="$input"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+  
+    <xsl:if test="$line">
+      <xsl:if test="$dofirst">
+        <xsl:call-template name="str:dup">
+          <xsl:with-param name="input" select=" ' ' "/>
+          <xsl:with-param name="count" select="$indent"/>
+        </xsl:call-template>
+      </xsl:if>
+
+      <xsl:call-template name="text:justify">
+        <xsl:with-param name="value" select="$line"/>
+        <xsl:with-param name="width" select="$effective"/>
+        <xsl:with-param name="align" select="$align"/>
+      </xsl:call-template>
+      <xsl:text>&#xa;</xsl:text>
+    </xsl:if>  
+
+    <xsl:call-template name="text:wrap">
+      <xsl:with-param name="input" select="substring($input, string-length($line) + 2)"/>
+      <xsl:with-param name="width" select="$width"/>
+      <xsl:with-param name="indent" select="$indent"/>
+      <xsl:with-param name="align" select="$align"/>
+    </xsl:call-template>
+  </xsl:if>
+</xsl:template>
+
+<xsl:template match="node() | @*" mode="text:dump" name="text:dump">
+  <xsl:param name="input" select="text()"/>
+  <xsl:param name="indent" select="0"/>
+
+  <xsl:if test="$input">
+    <xsl:variable name="line">
+      <xsl:choose>
+        <xsl:when test="contains($input, '&#xA;')">
+          <xsl:value-of select="substring-before($input, '&#xA;')"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of select="$input"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+  
+    <xsl:if test="$line">
+      <xsl:call-template name="str:dup">
+        <xsl:with-param name="input" select=" ' ' "/>
+        <xsl:with-param name="count" select="$indent"/>
+      </xsl:call-template>
+      <xsl:value-of select="$line"/>
+      <xsl:text>&#xa;</xsl:text>
+    </xsl:if>
+
+    <xsl:call-template name="text:dump">
+      <xsl:with-param name="input" select="substring-after($input, '&#xA;')"/>
+      <xsl:with-param name="indent" select="$indent"/>
+    </xsl:call-template>
+  </xsl:if>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/docs/lib/untag-inline.xslt b/docs/lib/untag-inline.xslt
new file mode 100644
index 0000000..ea553a5
--- /dev/null
+++ b/docs/lib/untag-inline.xslt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?> <!-- -*- sgml -*- -->
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+<xsl:include href="copy.xslt"/>
+
+<xsl:strip-space elements="*"/>
+
+<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
+
+<!-- Preprocess a docbook/xml file, replacing elements that are to be -->
+<!-- formatted inline with the corresponding text.  -->
+
+<xsl:template match="literal|computeroutput">
+  <xsl:value-of select="text()"/>
+</xsl:template>
+
+<xsl:template match="ulink">
+  <xsl:variable name="url" select="normalize-space(@url)"/>
+  <xsl:variable name="text" select="normalize-space(text())"/>
+
+  <xsl:if test="$text and $text != $url">
+    <xsl:text>'</xsl:text><xsl:value-of select="$text"/><xsl:text>' </xsl:text>
+  </xsl:if>
+  <xsl:text>&lt;</xsl:text><xsl:value-of select="$url"/><xsl:text>&gt;</xsl:text>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/docs/xml/FAQ.xml b/docs/xml/FAQ.xml
index f8b8c12..25f44b0 100644
--- a/docs/xml/FAQ.xml
+++ b/docs/xml/FAQ.xml
@@ -305,21 +305,27 @@
 
   <para>Some example sub-traces:</para>
 
-  <para>With debug information and unstripped (best):</para>
+   <itemizedlist>
+     <listitem>
+       <para>With debug information and unstripped (best):</para>
 <programlisting>
 Invalid write of size 1
    at 0x80483BF: really (malloc1.c:20)
    by 0x8048370: main (malloc1.c:9)
 </programlisting>
+     </listitem>
 
-  <para>With no debug information, unstripped:</para>
+     <listitem>
+       <para>With no debug information, unstripped:</para>
 <programlisting>
 Invalid write of size 1
    at 0x80483BF: really (in /auto/homes/njn25/grind/head5/a.out)
    by 0x8048370: main (in /auto/homes/njn25/grind/head5/a.out)
 </programlisting>
+     </listitem>
 
-  <para>With no debug information, stripped:</para>
+     <listitem>
+       <para>With no debug information, stripped:</para>
 <programlisting>
 Invalid write of size 1
    at 0x80483BF: (within /auto/homes/njn25/grind/head5/a.out)
@@ -327,17 +333,20 @@
    by 0x42015703: __libc_start_main (in /lib/tls/libc-2.3.2.so)
    by 0x80482CC: (within /auto/homes/njn25/grind/head5/a.out)
 </programlisting>
+     </listitem>
 
-  <para>With debug information and -fomit-frame-pointer:</para>
+     <listitem>
+       <para>With debug information and -fomit-frame-pointer:</para>
 <programlisting>
 Invalid write of size 1
    at 0x80483C4: really (malloc1.c:20)
    by 0x42015703: __libc_start_main (in /lib/tls/libc-2.3.2.so)
    by 0x80482CC: ??? (start.S:81)
 </programlisting>
+     </listitem>
 
-  <para>A leak error message involving an unloaded shared object:</para>
-
+     <listitem>
+      <para>A leak error message involving an unloaded shared object:</para>
 <programlisting>
 84 bytes in 1 blocks are possibly lost in loss record 488 of 713
    at 0x1B9036DA: operator new(unsigned) (vg_replace_malloc.c:132)
@@ -346,6 +355,8 @@
    by 0x1D65E007: ???
    by 0x8049EE6: main (main.cpp:24)
 </programlisting>
+     </listitem>
+   </itemizedlist>
 
  </answer>
 </qandaentry>