-SUBDIRS = src
+SUBDIRS = src doc
ACLOCAL_AMFLAGS = -I m4
AC_MSG_ERROR([Install libboost-program-options-dev (or similar)])
])
-AC_CHECK_LIB(boost_regex, main, [],[
- AC_MSG_NOTICE([boost regex library not found.])
- AC_MSG_ERROR([Install libboost-regex-dev (or similar)])
-])
-
AC_CHECK_HEADER(boost/test/auto_unit_test.hpp,,[
AC_MSG_NOTICE([boost test unit header not found.])
AC_MSG_ERROR([Install libboost-test-dev (or similar)])
if test -z "$YAZPPLIB"; then
AC_MSG_ERROR([YAZ++ development libraries missing])
fi
-##YAZ_DOC
+YAZ_DOC
## libxslt checks
AC_SUBST(XSLT_LIBS)
Makefile
src/Makefile
src/Jamfile
+ doc/Makefile
+ doc/metaproxy.xml
+ doc/print.dsl
+ doc/html.dsl
+ doc/tkl.xsl
])
AC_OUTPUT
-## $Id: Makefile.am,v 1.1 2006-02-02 18:22:47 mike Exp $
+## $Id: Makefile.am,v 1.2 2006-03-16 12:03:39 adam Exp $
docdir=$(datadir)/doc/@PACKAGE@
-SUPPORTFILES = \
- yp2html.dsl \
- yp2php.dsl \
- yp2print.dsl \
- tkl.xsl \
- xml.dcl
-
-XMLFILES = yp2.xml.in
-
-HTMLFILES = yp2.html
+SUPPORTFILES = html.dsl print.dsl tkl.xsl xml.dcl
+XMLFILES = metaproxy.xml.in book.xml
+MAINXML = metaproxy.xml
+HTMLFILES = metaproxy.html
PNGFILES=
EPSFILES=
REFFILES=
-doc_DATA = $(HTMLFILES) yp2.pdf $(PNGFILES)
+doc_DATA = $(HTMLFILES) metaproxy.pdf $(PNGFILES)
man_MANS = $(MANFILES)
EXTRA_DIST = $(XMLFILES) $(SUPPORTFILES) $(REFFILES) \
$(doc_DATA) $(EPSFILES) $(man_MANS) $(REFFILES)
$(HTMLFILES): $(XMLFILES)
- jade -E14 -D $(srcdir) -d yp2html.dsl -t sgml $(srcdir)/xml.dcl yp2.xml
-
-yp2.php: $(XMLFILES)
- jade -E14 -D $(srcdir) -d yp2php.dsl -t sgml $(srcdir)/xml.dcl yp2.xml
+ jade -E14 -D $(srcdir) -d html.dsl -t sgml $(srcdir)/xml.dcl $(MAINXML)
-yp2.pdf: $(XMLFILES)
+metaproxy.pdf: $(XMLFILES)
for i in $(PNGFILES); do \
if test ! -f $$i; then ln -s $(srcdir)/$$i .; fi; \
done
- jade -E14 -D $(srcdir) -d yp2print.dsl -t tex $(srcdir)/xml.dcl yp2.xml
- pdfjadetex yp2.tex >/dev/null
- pdfjadetex yp2.tex >/dev/null
- pdfjadetex yp2.tex >/dev/null
+ jade -E14 -D $(srcdir) -d print.dsl -t tex $(srcdir)/xml.dcl $(MAINXML)
+ pdfjadetex metaproxy.tex >/dev/null
+ pdfjadetex metaproxy.tex >/dev/null
+ pdfjadetex metaproxy.tex >/dev/null
index.tkl: $(XMLFILES) tkl.xsl
- xsltproc tkl.xsl yp2.xml
+ xsltproc tkl.xsl $(MAINXML)
clean-data-hook:
rm -f [0-9]* *.bak
--- /dev/null
+<!-- $Id: book.xml,v 1.1 2006-03-16 12:03:39 adam Exp $ -->
+ <bookinfo>
+ <title>Metaproxy - User's Guide and Reference</title>
+ <author>
+ <firstname>Mike</firstname><surname>Taylor</surname>
+ </author>
+ <copyright>
+ <year>2006</year>
+ <holder>Index Data</holder>
+ </copyright>
+ <abstract>
+ <simpara>
+ ###
+ Metaproxy is ... in need of description :-)
+ </simpara>
+ </abstract>
+ </bookinfo>
+
+
+
+ <chapter id="introduction">
+ <title>Introduction</title>
+
+
+ <section>
+ <title>Overview</title>
+ <para>
+ <ulink url="http://indexdata.dk/metaproxy/">Metaproxy</ulink>
+ is ..
+ </para>
+ <para>
+ ### We should probably consider saying a little more by way of
+ introduction.
+ </para>
+ </section>
+ </chapter>
+
+
+
+ <chapter id="filters">
+ <title>Filters</title>
+
+
+ <section>
+ <title>Introductory notes</title>
+ <para>
+ It's useful to think of Metaproxy as an interpreter providing a small
+ number of primitives and operations, but operating on a very
+ complex data type, namely the ``package''.
+ </para>
+ <para>
+ A package represents a Z39.50 or SRW/U request (whether for Init,
+ Search, Scan, etc.) together with information about where it came
+ from. Packages are created by front-end filters such as
+ <literal>frontend_net</literal> (see below), which reads them from
+ the network; other front-end filters are possible. They then pass
+ along a route consisting of a sequence of filters, each of which
+ transforms the package and may also have side-effects such as
+ generating logging. Eventually, the route will yield a response,
+ which is sent back to the origin.
+ </para>
+ <para>
+ There are many kinds of filter: some that are defined statically
+ as part of Metaproxy, and other that may be provided by third parties
+ and dynamically loaded. They all conform to the same simple API
+ of essentially two methods: <function>configure()</function> is
+ called at startup time, and is passed a DOM tree representing that
+ part of the configuration file that pertains to this filter
+ instance: it is expected to walk that tree extracting relevant
+ information; and <function>process()</function> is called every
+ time the filter has to processes a package.
+ </para>
+ <para>
+ While all filters provide the same API, there are different modes
+ of functionality. Some filters are sources: they create
+ packages
+ (<literal>frontend_net</literal>);
+ others are sinks: they consume packages and return a result
+ (<literal>z3950_client</literal>,
+ <literal>backend_test</literal>,
+ <literal>http_file</literal>);
+ the others are true filters, that read, process and pass on the
+ packages they are fed
+ (<literal>auth_simple</literal>,
+ <literal>log</literal>,
+ <literal>multi</literal>,
+ <literal>session_shared</literal>,
+ <literal>template</literal>,
+ <literal>virt_db</literal>).
+ </para>
+ </section>
+
+
+ <section>
+ <title>Individual filters</title>
+ <para>
+ The filters are here named by the string that is used as the
+ <literal>type</literal> attribute of a
+ <literal><filter></literal> element in the configuration
+ file to request them, with the name of the class that implements
+ them in parentheses.
+ </para>
+
+ <section>
+ <title><literal>auth_simple</literal>
+ (mp::filter::AuthSimple)</title>
+ <para>
+ Simple authentication and authorisation. The configuration
+ specifies the name of a file that is the user register, which
+ lists <varname>username</varname>:<varname>password</varname>
+ pairs, one per line, colon separated. When a session begins, it
+ is rejected unless username and passsword are supplied, and match
+ a pair in the register.
+ </para>
+ <para>
+ ### discuss authorisation phase
+ </para>
+ </section>
+
+ <section>
+ <title><literal>backend_test</literal>
+ (mp::filter::Backend_test)</title>
+ <para>
+ A sink that provides dummy responses in the manner of the
+ <literal>yaz-ztest</literal> Z39.50 server. This is useful only
+ for testing.
+ </para>
+ </section>
+
+ <section>
+ <title><literal>frontend_net</literal>
+ (mp::filter::FrontendNet)</title>
+ <para>
+ A source that accepts Z39.50 and SRW connections from a port
+ specified in the configuration, reads protocol units, and
+ feeds them into the next filter, eventually returning the
+ result to the origin.
+ </para>
+ </section>
+
+ <section>
+ <title><literal>http_file</literal>
+ (mp::filter::HttpFile)</title>
+ <para>
+ A sink that returns the contents of files from the local
+ filesystem in response to HTTP requests. (Yes, Virginia, this
+ does mean that Metaproxy is also a Web-server in its spare time. So
+ far it does not contain either an email-reader or a Lisp
+ interpreter, but that day is surely coming.)
+ </para>
+ </section>
+
+ <section>
+ <title><literal>log</literal>
+ (mp::filter::Log)</title>
+ <para>
+ Writes logging information to standard output, and passes on
+ the package unchanged.
+ </para>
+ </section>
+
+ <section>
+ <title><literal>multi</literal>
+ (mp::filter::Multi)</title>
+ <para>
+ Performs multicast searching. See the extended discussion of
+ multi-database searching below.
+ </para>
+ </section>
+
+ <section>
+ <title><literal>session_shared</literal>
+ (mp::filter::SessionShared)</title>
+ <para>
+ When this is finished, it will implement global sharing of
+ result sets (i.e. between threads and therefore between
+ clients), but it's not yet done.
+ </para>
+ </section>
+
+ <section>
+ <title><literal>template</literal>
+ (mp::filter::Template)</title>
+ <para>
+ Does nothing at all, merely passing the packet on. (Maybe it
+ should be called <literal>nop</literal> or
+ <literal>passthrough</literal>?) This exists not to be used, but
+ to be copied - to become the skeleton of new filters as they are
+ written.
+ </para>
+ </section>
+
+ <section>
+ <title><literal>virt_db</literal>
+ (mp::filter::Virt_db)</title>
+ <para>
+ Performs virtual database selection. See the extended discussion
+ of virtual databases below.
+ </para>
+ </section>
+
+ <section>
+ <title><literal>z3950_client</literal>
+ (mp::filter::Z3950Client)</title>
+ <para>
+ Performs Z39.50 searching and retrieval by proxying the
+ packages that are passed to it. Init requests are sent to the
+ address specified in the <literal>VAL_PROXY</literal> otherInfo
+ attached to the request: this may have been specified by client,
+ or generated by a <literal>virt_db</literal> filter earlier in
+ the route. Subsequent requests are sent to the same address,
+ which is remembered at Init time in a Session object.
+ </para>
+ </section>
+ </section>
+
+
+ <section>
+ <title>Future directions</title>
+ <para>
+ Some other filters that do not yet exist, but which would be
+ useful, are briefly described. These may be added in future
+ releases.
+ </para>
+
+ <variablelist>
+ <varlistentry>
+ <term><literal>frontend_cli</literal> (source)</term>
+ <listitem>
+ <para>
+ Command-line interface for generating requests.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>srw2z3950</literal> (filter)</term>
+ <listitem>
+ <para>
+ Translate SRW requests into Z39.50 requests.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>srw_client</literal> (sink)</term>
+ <listitem>
+ <para>
+ SRW searching and retrieval.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>sru_client</literal> (sink)</term>
+ <listitem>
+ <para>
+ SRU searching and retrieval.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>opensearch_client</literal> (sink)</term>
+ <listitem>
+ <para>
+ A9 OpenSearch searching and retrieval.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ </chapter>
+
+
+
+ <chapter id="configuration">
+ <title>Configuration: the Metaproxy configuration file format</title>
+
+
+ <section>
+ <title>Introductory notes</title>
+ <para>
+ If Metaproxy is an interpreter providing operations on packages, then
+ its configuration file can be thought of as a program for that
+ interpreter. Configuration is by means of a single file, the name
+ of which is supplied as the sole command-line argument to the
+ <command>yp2</command> program.
+ </para>
+ <para>
+ The configuration files are written in XML. (But that's just an
+ implementation detail - they could just as well have been written
+ in YAML or Lisp-like S-expressions, or in a custom syntax.)
+ </para>
+ <para>
+ Since XML has been chosen, an XML schema,
+ <filename>config.xsd</filename>, is provided for validating
+ configuration files. This file is supplied in the
+ <filename>etc</filename> directory of the Metaproxy distribution. It
+ can be used by (among other tools) the <command>xmllint</command>
+ program supplied as part of the <literal>libxml2</literal>
+ distribution:
+ </para>
+ <screen>
+ xmllint --noout --schema etc/config.xsd my-config-file.xml
+ </screen>
+ <para>
+ (A recent version of <literal>libxml2</literal> is required, as
+ support for XML Schemas is a relatively recent addition.)
+ </para>
+ </section>
+
+ <section>
+ <title>Overview of XML structure</title>
+ <para>
+ All elements and attributes are in the namespace
+ <ulink url="http://indexdata.dk/yp2/config/1"/>.
+ This is most easily achieved by setting the default namespace on
+ the top-level element, as here:
+ </para>
+ <screen>
+ <yp2 xmlns="http://indexdata.dk/yp2/config/1">
+ </screen>
+ <para>
+ The top-level element is <yp2>. This contains a
+ <start> element, a <filters> element and a
+ <routes> element, in that order. <filters> is
+ optional; the other two are mandatory. All three are
+ non-repeatable.
+ </para>
+ <para>
+ The <start> element is empty, but carries a
+ <literal>route</literal> attribute, whose value is the name of
+ route at which to start running - analogouse to the name of the
+ start production in a formal grammar.
+ </para>
+ <para>
+ If present, <filters> contains zero or more <filter>
+ elements; filters carry a <literal>type</literal> attribute and
+ contain various elements that provide suitable configuration for
+ filters of that type. The filter-specific elements are described
+ below. Filters defined in this part of the file must carry an
+ <literal>id</literal> attribute so that they can be referenced
+ from elsewhere.
+ </para>
+ <para>
+ <routes> contains one or more <route> elements, each
+ of which must carry an <literal>id</literal> element. One of the
+ routes must have the ID value that was specified as the start
+ route in the <start> element's <literal>route</literal>
+ attribute. Each route contains zero or more <filter>
+ elements. These are of two types. They may be empty, but carry a
+ <literal>refid</literal> attribute whose value is the same as the
+ <literal>id</literal> of a filter previously defined in the
+ <filters> section. Alternatively, a route within a filter
+ may omit the <literal>refid</literal> attribute, but contain
+ configuration elements similar to those used for filters defined
+ in the <filters> section.
+ </para>
+ </section>
+
+
+ <section>
+ <title>Filter configuration</title>
+ <para>
+ All <filter> elements have in common that they must carry a
+ <literal>type</literal> attribute whose value is one of the
+ supported ones, listed in the schema file and discussed below. In
+ additional, <filters>s occurring the <filters> section
+ must have an <literal>id</literal> attribute, and those occurring
+ within a route must have either a <literal>refid</literal>
+ attribute referencing a previously defined filter or contain its
+ own configuration information.
+ </para>
+ <para>
+ In general, each filter recognises different configuration
+ elements within its element, as each filter has different
+ functionality. These are as follows:
+ </para>
+
+ <section>
+ <title><literal>auth_simple</literal></title>
+ <screen>
+ <filter type="auth_simple">
+ <userRegister>../etc/example.simple-auth</userRegister>
+ </filter>
+ </screen>
+ </section>
+
+ <section>
+ <title><literal>backend_test</literal></title>
+ <screen>
+ <filter type="backend_test"/>
+ </screen>
+ </section>
+
+ <section>
+ <title><literal>frontend_net</literal></title>
+ <screen>
+ <filter type="frontend_net">
+ <threads>10</threads>
+ <port>@:9000</port>
+ </filter>
+ </screen>
+ </section>
+
+ <section>
+ <title><literal>http_file</literal></title>
+ <screen>
+ <filter type="http_file">
+ <mimetypes>/etc/mime.types</mimetypes>
+ <area>
+ <documentroot>.</documentroot>
+ <prefix>/etc</prefix>
+ </area>
+ </filter>
+ </screen>
+ </section>
+
+ <section>
+ <title><literal>log</literal></title>
+ <screen>
+ <filter type="log">
+ <message>B</message>
+ </filter>
+ </screen>
+ </section>
+
+ <section>
+ <title><literal>multi</literal></title>
+ <screen>
+ <filter type="multi"/>
+ </screen>
+ </section>
+
+ <section>
+ <title><literal>session_shared</literal></title>
+ <screen>
+ <filter type="session_shared">
+ ### Not yet defined
+ </filter>
+ </screen>
+ </section>
+
+ <section>
+ <title><literal>template</literal></title>
+ <screen>
+ <filter type="template"/>
+ </screen>
+ </section>
+
+ <section>
+ <title><literal>virt_db</literal></title>
+ <screen>
+ <filter type="virt_db">
+ <virtual>
+ <database>loc</database>
+ <target>z3950.loc.gov:7090/voyager</target>
+ </virtual>
+ <virtual>
+ <database>idgils</database>
+ <target>indexdata.dk/gils</target>
+ </virtual>
+ </filter>
+ </screen>
+ </section>
+
+ <section>
+ <title><literal>z3950_client</literal></title>
+ <screen>
+ <filter type="z3950_client">
+ <timeout>30</timeout>
+ </filter>
+ </screen>
+ </section>
+ </section>
+ </chapter>
+
+
+
+ <chapter id="multidb">
+ <title>Virtual database as multi-database searching</title>
+
+
+ <section>
+ <title>Introductory notes</title>
+ <para>
+ Two of Metaproxy's filters are concerned with multiple-database
+ operations. Of these, <literal>virt_db</literal> can work alone
+ to control the routing of searches to one of a number of servers,
+ while <literal>multi</literal> can work with the output of
+ <literal>virt_db</literal> to perform multicast searching, merging
+ the results into a unified result-set. The interaction between
+ these two filters is necessarily complex, reflecting the real
+ complexity of multicast searching in a protocol such as Z39.50
+ that separates initialisation from searching, with the database to
+ search known only during the latter operation.
+ </para>
+ <para>
+ ### Much, much more to say!
+ </para>
+ </section>
+ </chapter>
+
+
+
+ <chapter id="classes">
+ <title>Classes in the Metaproxy source code</title>
+
+
+ <section>
+ <title>Introductory notes</title>
+ <para>
+ <emphasis>Stop! Do not read this!</emphasis>
+ You won't enjoy it at all.
+ </para>
+ <para>
+ This chapter contains documentation of the Metaproxy source code, and is
+ of interest only to maintainers and developers. If you need to
+ change Metaproxy's behaviour or write a new filter, then you will most
+ likely find this chapter helpful. Otherwise it's a waste of your
+ good time. Seriously: go and watch a film or something.
+ <citetitle>This is Spinal Tap</citetitle> is particularly good.
+ </para>
+ <para>
+ Still here? OK, let's continue.
+ </para>
+ <para>
+ In general, classes seem to be named big-endianly, so that
+ <literal>FactoryFilter</literal> is not a filter that filters
+ factories, but a factory that produces filters; and
+ <literal>FactoryStatic</literal> is a factory for the statically
+ registered filters (as opposed to those that are dynamically
+ loaded).
+ </para>
+ </section>
+
+ <section>
+ <title>Individual classes</title>
+ <para>
+ The classes making up the Metaproxy application are here listed by
+ class-name, with the names of the source files that define them in
+ parentheses.
+ </para>
+
+ <section>
+ <title><literal>mp::FactoryFilter</literal>
+ (<filename>factory_filter.cpp</filename>)</title>
+ <para>
+ A factory class that exists primarily to provide the
+ <literal>create()</literal> method, which takes the name of a
+ filter class as its argument and returns a new filter of that
+ type. To enable this, the factory must first be populated by
+ calling <literal>add_creator()</literal> for static filters (this
+ is done by the <literal>FactoryStatic</literal> class, see below)
+ and <literal>add_creator_dyn()</literal> for filters loaded
+ dynamically.
+ </para>
+ </section>
+
+ <section>
+ <title><literal>mp::FactoryStatic</literal>
+ (<filename>factory_static.cpp</filename>)</title>
+ <para>
+ A subclass of <literal>FactoryFilter</literal> which is
+ responsible for registering all the statically defined filter
+ types. It does this by knowing about all those filters'
+ structures, which are listed in its constructor. Merely
+ instantiating this class registers all the static classes. It is
+ for the benefit of this class that <literal>struct
+ yp2_filter_struct</literal> exists, and that all the filter
+ classes provide a static object of that type.
+ </para>
+ </section>
+
+ <section>
+ <title><literal>mp::filter::Base</literal>
+ (<filename>filter.cpp</filename>)</title>
+ <para>
+ The virtual base class of all filters. The filter API is, on the
+ surface at least, extremely simple: two methods.
+ <literal>configure()</literal> is passed a DOM tree representing
+ that part of the configuration file that pertains to this filter
+ instance, and is expected to walk that tree extracting relevant
+ information. And <literal>process()</literal> processes a
+ package (see below). That surface simplicitly is a bit
+ misleading, as <literal>process()</literal> needs to know a lot
+ about the <literal>Package</literal> class in order to do
+ anything useful.
+ </para>
+ </section>
+
+ <section>
+ <title><literal>mp::filter::AuthSimple</literal>,
+ <literal>Backend_test</literal>, etc.
+ (<filename>filter_auth_simple.cpp</filename>,
+ <filename>filter_backend_test.cpp</filename>, etc.)</title>
+ <para>
+ Individual filters. Each of these is implemented by a header and
+ a source file, named <filename>filter_*.hpp</filename> and
+ <filename>filter_*.cpp</filename> respectively. All the header
+ files should be pretty much identical, in that they declare the
+ class, including a private <literal>Rep</literal> class and a
+ member pointer to it, and the two public methods. The only extra
+ information in any filter header is additional private types and
+ members (which should really all be in the <literal>Rep</literal>
+ anyway) and private methods (which should also remain known only
+ to the source file, but C++'s brain-damaged design requires this
+ dirty laundry to be exhibited in public. Thanks, Bjarne!)
+ </para>
+ <para>
+ The source file for each filter needs to supply:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ A definition of the private <literal>Rep</literal> class.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Some boilerplate constructors and destructors.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ A <literal>configure()</literal> method that uses the
+ appropriate XML fragment.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Most important, the <literal>process()</literal> method that
+ does all the actual work.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title><literal>mp::Package</literal>
+ (<filename>package.cpp</filename>)</title>
+ <para>
+ Represents a package on its way through the series of filters
+ that make up a route. This is essentially a Z39.50 or SRU APDU
+ together with information about where it came from, which is
+ modified as it passes through the various filters.
+ </para>
+ </section>
+
+ <section>
+ <title><literal>mp::Pipe</literal>
+ (<filename>pipe.cpp</filename>)</title>
+ <para>
+ This class provides a compatibility layer so that we have an IPC
+ mechanism that works the same under Unix and Windows. It's not
+ particularly exciting.
+ </para>
+ </section>
+
+ <section>
+ <title><literal>mp::RouterChain</literal>
+ (<filename>router_chain.cpp</filename>)</title>
+ <para>
+ ###
+ </para>
+ </section>
+
+ <section>
+ <title><literal>mp::RouterFleXML</literal>
+ (<filename>router_flexml.cpp</filename>)</title>
+ <para>
+ ###
+ </para>
+ </section>
+
+ <section>
+ <title><literal>mp::Session</literal>
+ (<filename>session.cpp</filename>)</title>
+ <para>
+ ###
+ </para>
+ </section>
+
+ <section>
+ <title><literal>mp::ThreadPoolSocketObserver</literal>
+ (<filename>thread_pool_observer.cpp</filename>)</title>
+ <para>
+ ###
+ </para>
+ </section>
+
+ <section>
+ <title><literal>mp::util</literal>
+ (<filename>util.cpp</filename>)</title>
+ <para>
+ A namespace of various small utility functions and classes,
+ collected together for convenience. Most importantly, includes
+ the <literal>mp::util::odr</literal> class, a wrapper for YAZ's
+ ODR facilities.
+ </para>
+ </section>
+
+ <section>
+ <title><literal>mp::xml</literal>
+ (<filename>xmlutil.cpp</filename>)</title>
+ <para>
+ A namespace of various XML utility functions and classes,
+ collected together for convenience.
+ </para>
+ </section>
+ </section>
+
+
+ <section>
+ <title>Other Source Files</title>
+ <para>
+ In addition to the Metaproxy source files that define the classes
+ described above, there are a few additional files which are
+ briefly described here:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term><literal>metaproxy_prog.cpp</literal></term>
+ <listitem>
+ <para>
+ The main function of the <command>yp2</command> program.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>ex_router_flexml.cpp</literal></term>
+ <listitem>
+ <para>
+ Identical to <literal>metaproxy_prog.cpp</literal>: it's not clear why.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>test_*.cpp</literal></term>
+ <listitem>
+ <para>
+ Unit-tests for various modules.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>
+ ### Still to be described:
+ <literal>ex_filter_frontend_net.cpp</literal>,
+ <literal>filter_dl.cpp</literal>,
+ <literal>plainfile.cpp</literal>,
+ <literal>tstdl.cpp</literal>.
+ </para>
+
+
+ <!-- Epilogue -->
+ <para>
+ --
+ </para>
+ <screen>
+ <!-- This is just a lame way to get some vertical whitespace at
+ the end of the document -->
+
+
+
+
+ </screen>
+ </section>
+ </chapter>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:1
+sgml-indent-data:t
+sgml-parent-document:yp2.xml
+sgml-local-catalogs: nil
+sgml-namecase-general:t
+End:
+-->
--- /dev/null
+<!DOCTYPE style-sheet PUBLIC "-//James Clark//DTD DSSSL Style Sheet//EN" [
+<!ENTITY docbook.dsl SYSTEM "@DSSSL_DIR@/html/docbook.dsl"
+ CDATA DSSSL>
+]>
+<!--
+ $Id: html.dsl.in,v 1.1 2006-03-16 12:03:39 adam Exp $
+-->
+<style-sheet>
+<style-specification use="docbook">
+<style-specification-body>
+
+(define %use-id-as-filename% #t)
+(define %output-dir% "html")
+(define %html-ext% ".html")
+(define %shade-verbatim% #t)
+
+</style-specification-body>
+</style-specification>
+<external-specification id="docbook" document="docbook.dsl">
+</style-sheet>
+
+<!--
+Local Variables:
+mode: scheme
+End:
+-->
--- /dev/null
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "@DTD_DIR@/docbookx.dtd" [
+ <!ENTITY oslash "ø"> <!-- CIRCLED DIVISION SLASH -->
+ <!ENTITY book SYSTEM "book.xml">
+ <!ENTITY version "@VERSION@">
+]>
+<!-- $Id: metaproxy.xml.in,v 1.1 2006-03-16 12:03:39 adam Exp $ -->
+<book id="metaproxy">
+ &book;
+</book>
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:1
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-local-catalogs: nil
+sgml-namecase-general:t
+End:
+-->
--- /dev/null
+<!DOCTYPE style-sheet PUBLIC "-//James Clark//DTD DSSSL Style Sheet//EN" [
+<!ENTITY docbook.dsl SYSTEM "@DSSSL_DIR@/print/docbook.dsl"
+ CDATA DSSSL>
+]>
+<!--
+ $Id: print.dsl.in,v 1.1 2006-03-16 12:03:39 adam Exp $
+-->
+<style-sheet>
+<style-specification use="docbook">
+<style-specification-body>
+
+</style-specification-body>
+</style-specification>
+<external-specification id="docbook" document="docbook.dsl">
+</style-sheet>
+
+<!--
+Local Variables:
+mode: scheme
+End:
+-->
+++ /dev/null
-<?xml version="1.0" standalone="no"?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
- "@DTD_DIR@/docbookx.dtd" [
- <!ENTITY oslash "ø"> <!-- CIRCLED DIVISION SLASH -->
-]>
-<!-- $Id: yp2.xml.in,v 1.1 2006-02-02 18:22:47 mike Exp $ -->
-<book id="yp2">
- <bookinfo>
- <title>YP2 - User's Guide and Reference</title>
- <author>
- <firstname>Mike</firstname><surname>Taylor</surname>
- </author>
- <copyright>
- <year>2006</year>
- <holder>Index Data</holder>
- </copyright>
- <abstract>
- <simpara>
- ###
- YP2 is ... in need of description :-)
- </simpara>
- </abstract>
- </bookinfo>
-
-
-
- <chapter id="introduction">
- <title>Introduction</title>
-
-
- <section>
- <title>Overview</title>
- <para>
- <ulink url="http://indexdata.dk/yp2/">YP2</ulink>
- is extremely cool.
- </para>
- <para>
- ### We should probably consider saying a little more by way of
- introduction.
- </para>
- </section>
- </chapter>
-
-
-
- <chapter id="filters">
- <title>Filters</title>
-
-
- <section>
- <title>Introductory notes</title>
- <para>
- It's useful to think of YP2 as an interpreter providing a small
- number of primitives and operations, but operating on a very
- complex data type, namely the ``package''.
- </para>
- <para>
- A package represents a Z39.50 or SRW/U request (whether for Init,
- Search, Scan, etc.) together with information about where it came
- from. Packages are created by front-end filters such as
- <literal>frontend_net</literal> (see below), which reads them from
- the network; other front-end filters are possible. They then pass
- along a route consisting of a sequence of filters, each of which
- transforms the package and may also have side-effects such as
- generating logging. Eventually, the route will yield a response,
- which is sent back to the origin.
- </para>
- <para>
- There are many kinds of filter: some that are defined statically
- as part of YP2, and other that may be provided by third parties
- and dynamically loaded. They all conform to the same simple API
- of essentially two methods: <function>configure()</function> is
- called at startup time, and is passed a DOM tree representing that
- part of the configuration file that pertains to this filter
- instance: it is expected to walk that tree extracting relevant
- information; and <function>process()</function> is called every
- time the filter has to processes a package.
- </para>
- <para>
- While all filters provide the same API, there are different modes
- of functionality. Some filters are sources: they create
- packages
- (<literal>frontend_net</literal>);
- others are sinks: they consume packages and return a result
- (<literal>z3950_client</literal>,
- <literal>backend_test</literal>,
- <literal>http_file</literal>);
- the others are true filters, that read, process and pass on the
- packages they are fed
- (<literal>auth_simple</literal>,
- <literal>log</literal>,
- <literal>multi</literal>,
- <literal>session_shared</literal>,
- <literal>template</literal>,
- <literal>virt_db</literal>).
- </para>
- </section>
-
-
- <section>
- <title>Individual filters</title>
- <para>
- The filters are here named by the string that is used as the
- <literal>type</literal> attribute of a
- <literal><filter></literal> element in the configuration
- file to request them, with the name of the class that implements
- them in parentheses.
- </para>
-
- <section>
- <title><literal>auth_simple</literal>
- (yp2::filter::AuthSimple)</title>
- <para>
- Simple authentication and authorisation. The configuration
- specifies the name of a file that is the user register, which
- lists <varname>username</varname>:<varname>password</varname>
- pairs, one per line, colon separated. When a session begins, it
- is rejected unless username and passsword are supplied, and match
- a pair in the register.
- </para>
- <para>
- ### discuss authorisation phase
- </para>
- </section>
-
- <section>
- <title><literal>backend_test</literal>
- (yp2::filter::Backend_test)</title>
- <para>
- A sink that provides dummy responses in the manner of the
- <literal>yaz-ztest</literal> Z39.50 server. This is useful only
- for testing.
- </para>
- </section>
-
- <section>
- <title><literal>frontend_net</literal>
- (yp2::filter::FrontendNet)</title>
- <para>
- A source that accepts Z39.50 and SRW connections from a port
- specified in the configuration, reads protocol units, and
- feeds them into the next filter, eventually returning the
- result to the origin.
- </para>
- </section>
-
- <section>
- <title><literal>http_file</literal>
- (yp2::filter::HttpFile)</title>
- <para>
- A sink that returns the contents of files from the local
- filesystem in response to HTTP requests. (Yes, Virginia, this
- does mean that YP2 is also a Web-server in its spare time. So
- far it does not contain either an email-reader or a Lisp
- interpreter, but that day is surely coming.)
- </para>
- </section>
-
- <section>
- <title><literal>log</literal>
- (yp2::filter::Log)</title>
- <para>
- Writes logging information to standard output, and passes on
- the package unchanged.
- </para>
- </section>
-
- <section>
- <title><literal>multi</literal>
- (yp2::filter::Multi)</title>
- <para>
- Performs multicast searching. See the extended discussion of
- multi-database searching below.
- </para>
- </section>
-
- <section>
- <title><literal>session_shared</literal>
- (yp2::filter::SessionShared)</title>
- <para>
- When this is finished, it will implement global sharing of
- result sets (i.e. between threads and therefore between
- clients), but it's not yet done.
- </para>
- </section>
-
- <section>
- <title><literal>template</literal>
- (yp2::filter::Template)</title>
- <para>
- Does nothing at all, merely passing the packet on. (Maybe it
- should be called <literal>nop</literal> or
- <literal>passthrough</literal>?) This exists not to be used, but
- to be copied - to become the skeleton of new filters as they are
- written.
- </para>
- </section>
-
- <section>
- <title><literal>virt_db</literal>
- (yp2::filter::Virt_db)</title>
- <para>
- Performs virtual database selection. See the extended discussion
- of virtual databases below.
- </para>
- </section>
-
- <section>
- <title><literal>z3950_client</literal>
- (yp2::filter::Z3950Client)</title>
- <para>
- Performs Z39.50 searching and retrieval by proxying the
- packages that are passed to it. Init requests are sent to the
- address specified in the <literal>VAL_PROXY</literal> otherInfo
- attached to the request: this may have been specified by client,
- or generated by a <literal>virt_db</literal> filter earlier in
- the route. Subsequent requests are sent to the same address,
- which is remembered at Init time in a Session object.
- </para>
- </section>
- </section>
-
-
- <section>
- <title>Future directions</title>
- <para>
- Some other filters that do not yet exist, but which would be
- useful, are briefly described. These may be added in future
- releases.
- </para>
-
- <variablelist>
- <varlistentry>
- <term><literal>frontend_cli</literal> (source)</term>
- <listitem>
- <para>
- Command-line interface for generating requests.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>srw2z3950</literal> (filter)</term>
- <listitem>
- <para>
- Translate SRW requests into Z39.50 requests.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>srw_client</literal> (sink)</term>
- <listitem>
- <para>
- SRW searching and retrieval.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>sru_client</literal> (sink)</term>
- <listitem>
- <para>
- SRU searching and retrieval.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>opensearch_client</literal> (sink)</term>
- <listitem>
- <para>
- A9 OpenSearch searching and retrieval.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- </chapter>
-
-
-
- <chapter id="configuration">
- <title>Configuration: the YP2 configuration file format</title>
-
-
- <section>
- <title>Introductory notes</title>
- <para>
- If YP2 is an interpreter providing operations on packages, then
- its configuration file can be thought of as a program for that
- interpreter. Configuration is by means of a single file, the name
- of which is supplied as the sole command-line argument to the
- <command>yp2</command> program.
- </para>
- <para>
- The configuration files are written in XML. (But that's just an
- implementation detail - they could just as well have been written
- in YAML or Lisp-like S-expressions, or in a custom syntax.)
- </para>
- <para>
- Since XML has been chosen, an XML schema,
- <filename>config.xsd</filename>, is provided for validating
- configuration files. This file is supplied in the
- <filename>etc</filename> directory of the YP2 distribution. It
- can be used by (among other tools) the <command>xmllint</command>
- program supplied as part of the <literal>libxml2</literal>
- distribution:
- </para>
- <screen>
- xmllint --noout --schema etc/config.xsd my-config-file.xml
- </screen>
- <para>
- (A recent version of <literal>libxml2</literal> is required, as
- support for XML Schemas is a relatively recent addition.)
- </para>
- </section>
-
- <section>
- <title>Overview of XML structure</title>
- <para>
- All elements and attributes are in the namespace
- <ulink url="http://indexdata.dk/yp2/config/1"/>.
- This is most easily achieved by setting the default namespace on
- the top-level element, as here:
- </para>
- <screen>
- <yp2 xmlns="http://indexdata.dk/yp2/config/1">
- </screen>
- <para>
- The top-level element is <yp2>. This contains a
- <start> element, a <filters> element and a
- <routes> element, in that order. <filters> is
- optional; the other two are mandatory. All three are
- non-repeatable.
- </para>
- <para>
- The <start> element is empty, but carries a
- <literal>route</literal> attribute, whose value is the name of
- route at which to start running - analogouse to the name of the
- start production in a formal grammar.
- </para>
- <para>
- If present, <filters> contains zero or more <filter>
- elements; filters carry a <literal>type</literal> attribute and
- contain various elements that provide suitable configuration for
- filters of that type. The filter-specific elements are described
- below. Filters defined in this part of the file must carry an
- <literal>id</literal> attribute so that they can be referenced
- from elsewhere.
- </para>
- <para>
- <routes> contains one or more <route> elements, each
- of which must carry an <literal>id</literal> element. One of the
- routes must have the ID value that was specified as the start
- route in the <start> element's <literal>route</literal>
- attribute. Each route contains zero or more <filter>
- elements. These are of two types. They may be empty, but carry a
- <literal>refid</literal> attribute whose value is the same as the
- <literal>id</literal> of a filter previously defined in the
- <filters> section. Alternatively, a route within a filter
- may omit the <literal>refid</literal> attribute, but contain
- configuration elements similar to those used for filters defined
- in the <filters> section.
- </para>
- </section>
-
-
- <section>
- <title>Filter configuration</title>
- <para>
- All <filter> elements have in common that they must carry a
- <literal>type</literal> attribute whose value is one of the
- supported ones, listed in the schema file and discussed below. In
- additional, <filters>s occurring the <filters> section
- must have an <literal>id</literal> attribute, and those occurring
- within a route must have either a <literal>refid</literal>
- attribute referencing a previously defined filter or contain its
- own configuration information.
- </para>
- <para>
- In general, each filter recognises different configuration
- elements within its element, as each filter has different
- functionality. These are as follows:
- </para>
-
- <section>
- <title><literal>auth_simple</literal></title>
- <screen>
- <filter type="auth_simple">
- <userRegister>../etc/example.simple-auth</userRegister>
- </filter>
- </screen>
- </section>
-
- <section>
- <title><literal>backend_test</literal></title>
- <screen>
- <filter type="backend_test"/>
- </screen>
- </section>
-
- <section>
- <title><literal>frontend_net</literal></title>
- <screen>
- <filter type="frontend_net">
- <threads>10</threads>
- <port>@:9000</port>
- </filter>
- </screen>
- </section>
-
- <section>
- <title><literal>http_file</literal></title>
- <screen>
- <filter type="http_file">
- <mimetypes>/etc/mime.types</mimetypes>
- <area>
- <documentroot>.</documentroot>
- <prefix>/etc</prefix>
- </area>
- </filter>
- </screen>
- </section>
-
- <section>
- <title><literal>log</literal></title>
- <screen>
- <filter type="log">
- <message>B</message>
- </filter>
- </screen>
- </section>
-
- <section>
- <title><literal>multi</literal></title>
- <screen>
- <filter type="multi"/>
- </screen>
- </section>
-
- <section>
- <title><literal>session_shared</literal></title>
- <screen>
- <filter type="session_shared">
- ### Not yet defined
- </filter>
- </screen>
- </section>
-
- <section>
- <title><literal>template</literal></title>
- <screen>
- <filter type="template"/>
- </screen>
- </section>
-
- <section>
- <title><literal>virt_db</literal></title>
- <screen>
- <filter type="virt_db">
- <virtual>
- <database>loc</database>
- <target>z3950.loc.gov:7090/voyager</target>
- </virtual>
- <virtual>
- <database>idgils</database>
- <target>indexdata.dk/gils</target>
- </virtual>
- </filter>
- </screen>
- </section>
-
- <section>
- <title><literal>z3950_client</literal></title>
- <screen>
- <filter type="z3950_client">
- <timeout>30</timeout>
- </filter>
- </screen>
- </section>
- </section>
- </chapter>
-
-
-
- <chapter id="multidb">
- <title>Virtual database as multi-database searching</title>
-
-
- <section>
- <title>Introductory notes</title>
- <para>
- Two of YP2's filters are concerned with multiple-database
- operations. Of these, <literal>virt_db</literal> can work alone
- to control the routing of searches to one of a number of servers,
- while <literal>multi</literal> can work with the output of
- <literal>virt_db</literal> to perform multicast searching, merging
- the results into a unified result-set. The interaction between
- these two filters is necessarily complex, reflecting the real
- complexity of multicast searching in a protocol such as Z39.50
- that separates initialisation from searching, with the database to
- search known only during the latter operation.
- </para>
- <para>
- ### Much, much more to say!
- </para>
- </section>
- </chapter>
-
-
-
- <chapter id="classes">
- <title>Classes in the YP2 source code</title>
-
-
- <section>
- <title>Introductory notes</title>
- <para>
- <emphasis>Stop! Do not read this!</emphasis>
- You won't enjoy it at all.
- </para>
- <para>
- This chapter contains documentation of the YP2 source code, and is
- of interest only to maintainers and developers. If you need to
- change YP2's behaviour or write a new filter, then you will most
- likely find this chapter helpful. Otherwise it's a waste of your
- good time. Seriously: go and watch a film or something.
- <citetitle>This is Spinal Tap</citetitle> is particularly good.
- </para>
- <para>
- Still here? OK, let's continue.
- </para>
- <para>
- In general, classes seem to be named big-endianly, so that
- <literal>FactoryFilter</literal> is not a filter that filters
- factories, but a factory that produces filters; and
- <literal>FactoryStatic</literal> is a factory for the statically
- registered filters (as opposed to those that are dynamically
- loaded).
- </para>
- </section>
-
- <section>
- <title>Individual classes</title>
- <para>
- The classes making up the YP2 application are here listed by
- class-name, with the names of the source files that define them in
- parentheses.
- </para>
-
- <section>
- <title><literal>yp::FactoryFilter</literal>
- (<filename>factory_filter.cpp</filename>)</title>
- <para>
- A factory class that exists primarily to provide the
- <literal>create()</literal> method, which takes the name of a
- filter class as its argument and returns a new filter of that
- type. To enable this, the factory must first be populated by
- calling <literal>add_creator()</literal> for static filters (this
- is done by the <literal>FactoryStatic</literal> class, see below)
- and <literal>add_creator_dyn()</literal> for filters loaded
- dynamically.
- </para>
- </section>
-
- <section>
- <title><literal>yp2::FactoryStatic</literal>
- (<filename>factory_static.cpp</filename>)</title>
- <para>
- A subclass of <literal>FactoryFilter</literal> which is
- responsible for registering all the statically defined filter
- types. It does this by knowing about all those filters'
- structures, which are listed in its constructor. Merely
- instantiating this class registers all the static classes. It is
- for the benefit of this class that <literal>struct
- yp2_filter_struct</literal> exists, and that all the filter
- classes provide a static object of that type.
- </para>
- </section>
-
- <section>
- <title><literal>yp2::filter::Base</literal>
- (<filename>filter.cpp</filename>)</title>
- <para>
- The virtual base class of all filters. The filter API is, on the
- surface at least, extremely simple: two methods.
- <literal>configure()</literal> is passed a DOM tree representing
- that part of the configuration file that pertains to this filter
- instance, and is expected to walk that tree extracting relevant
- information. And <literal>process()</literal> processes a
- package (see below). That surface simplicitly is a bit
- misleading, as <literal>process()</literal> needs to know a lot
- about the <literal>Package</literal> class in order to do
- anything useful.
- </para>
- </section>
-
- <section>
- <title><literal>yp2::filter::AuthSimple</literal>,
- <literal>Backend_test</literal>, etc.
- (<filename>filter_auth_simple.cpp</filename>,
- <filename>filter_backend_test.cpp</filename>, etc.)</title>
- <para>
- Individual filters. Each of these is implemented by a header and
- a source file, named <filename>filter_*.hpp</filename> and
- <filename>filter_*.cpp</filename> respectively. All the header
- files should be pretty much identical, in that they declare the
- class, including a private <literal>Rep</literal> class and a
- member pointer to it, and the two public methods. The only extra
- information in any filter header is additional private types and
- members (which should really all be in the <literal>Rep</literal>
- anyway) and private methods (which should also remain known only
- to the source file, but C++'s brain-damaged design requires this
- dirty laundry to be exhibited in public. Thanks, Bjarne!)
- </para>
- <para>
- The source file for each filter needs to supply:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- A definition of the private <literal>Rep</literal> class.
- </para>
- </listitem>
- <listitem>
- <para>
- Some boilerplate constructors and destructors.
- </para>
- </listitem>
- <listitem>
- <para>
- A <literal>configure()</literal> method that uses the
- appropriate XML fragment.
- </para>
- </listitem>
- <listitem>
- <para>
- Most important, the <literal>process()</literal> method that
- does all the actual work.
- </para>
- </listitem>
- </itemizedlist>
- </section>
-
- <section>
- <title><literal>yp2::Package</literal>
- (<filename>package.cpp</filename>)</title>
- <para>
- Represents a package on its way through the series of filters
- that make up a route. This is essentially a Z39.50 or SRU APDU
- together with information about where it came from, which is
- modified as it passes through the various filters.
- </para>
- </section>
-
- <section>
- <title><literal>yp2::Pipe</literal>
- (<filename>pipe.cpp</filename>)</title>
- <para>
- This class provides a compatibility layer so that we have an IPC
- mechanism that works the same under Unix and Windows. It's not
- particularly exciting.
- </para>
- </section>
-
- <section>
- <title><literal>yp2::RouterChain</literal>
- (<filename>router_chain.cpp</filename>)</title>
- <para>
- ###
- </para>
- </section>
-
- <section>
- <title><literal>yp2::RouterFleXML</literal>
- (<filename>router_flexml.cpp</filename>)</title>
- <para>
- ###
- </para>
- </section>
-
- <section>
- <title><literal>yp2::Session</literal>
- (<filename>session.cpp</filename>)</title>
- <para>
- ###
- </para>
- </section>
-
- <section>
- <title><literal>yp2::ThreadPoolSocketObserver</literal>
- (<filename>thread_pool_observer.cpp</filename>)</title>
- <para>
- ###
- </para>
- </section>
-
- <section>
- <title><literal>yp2::util</literal>
- (<filename>util.cpp</filename>)</title>
- <para>
- A namespace of various small utility functions and classes,
- collected together for convenience. Most importantly, includes
- the <literal>yp2::util::odr</literal> class, a wrapper for YAZ's
- ODR facilities.
- </para>
- </section>
-
- <section>
- <title><literal>yp2::xml</literal>
- (<filename>xmlutil.cpp</filename>)</title>
- <para>
- A namespace of various XML utility functions and classes,
- collected together for convenience.
- </para>
- </section>
- </section>
-
-
- <section>
- <title>Other Source Files</title>
- <para>
- In addition to the YP2 source files that define the classes
- described above, there are a few additional files which are
- briefly described here:
- </para>
- <variablelist>
- <varlistentry>
- <term><literal>yp2_prog.cpp</literal></term>
- <listitem>
- <para>
- The main function of the <command>yp2</command> program.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>ex_router_flexml.cpp</literal></term>
- <listitem>
- <para>
- Identical to <literal>yp2_prog.cpp</literal>: it's not clear why.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>test_*.cpp</literal></term>
- <listitem>
- <para>
- Unit-tests for various modules.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- ### Still to be described:
- <literal>ex_filter_frontend_net.cpp</literal>,
- <literal>filter_dl.cpp</literal>,
- <literal>plainfile.cpp</literal>,
- <literal>tstdl.cpp</literal>.
- </para>
-
-
- <!-- Epilogue -->
- <para>
- --
- </para>
- <screen>
- <!-- This is just a lame way to get some vertical whitespace at
- the end of the document -->
-
-
-
-
- </screen>
- </section>
- </chapter>
-</book>
-
-<!-- Keep this comment at the end of the file
-Local variables:
-mode: sgml
-sgml-omittag:t
-sgml-shorttag:t
-sgml-minimize-attributes:nil
-sgml-always-quote-attributes:t
-sgml-indent-step:1
-sgml-indent-data:t
-sgml-parent-document:nil
-sgml-local-catalogs: nil
-sgml-namecase-general:t
-End:
--->
+++ /dev/null
-<!DOCTYPE style-sheet PUBLIC "-//James Clark//DTD DSSSL Style Sheet//EN" [
-<!ENTITY docbook.dsl SYSTEM "@DSSSL_DIR@/html/docbook.dsl"
- CDATA DSSSL>
-]>
-<!--
- $Id: yp2html.dsl.in,v 1.1 2006-02-02 18:22:47 mike Exp $
--->
-<style-sheet>
-<style-specification use="docbook">
-<style-specification-body>
-
-(define %use-id-as-filename% #t)
-(define %output-dir% "html")
-(define %html-ext% ".html")
-(define %shade-verbatim% #t)
-
-</style-specification-body>
-</style-specification>
-<external-specification id="docbook" document="docbook.dsl">
-</style-sheet>
-
-<!--
-Local Variables:
-mode: scheme
-End:
--->
+++ /dev/null
-<!DOCTYPE style-sheet PUBLIC "-//James Clark//DTD DSSSL Style Sheet//EN" [
-<!ENTITY docbook.dsl SYSTEM "@DSSSL_DIR@/html/docbook.dsl"
- CDATA DSSSL>
-]>
-<!--
- $Id: yp2php.dsl.in,v 1.1 2006-02-02 18:22:47 mike Exp $
--->
-<style-sheet>
-<style-specification use="docbook">
-<style-specification-body>
-
-(define %use-id-as-filename% #t)
-(define %output-dir% "php")
-(define %html-ext% ".php")
-(define %shade-verbatim% #t)
-
-(define newline "\U-000D")
-
-(define (html-document title-sosofo body-sosofo)
- (let* (;; Let's look these up once, so that we can avoid calculating
- ;; them over and over again.
- (prev (prev-chunk-element))
- (next (next-chunk-element))
- (prevm (prev-major-component-chunk-element))
- (nextm (next-major-component-chunk-element))
- (navlist (list prev next prevm nextm))
-
- ;; Let's make it possible to control the output even in the
- ;; nochunks case. Note: in the nochunks case, (chunk?) will
- ;; return #t for only the root element.
- (make-entity? (and (or (not nochunks) rootchunk)
- (chunk?)))
-
- (make-head? (or make-entity?
- (and nochunks
- (node-list=? (current-node)
- (sgml-root-element)))))
- (doc-sosofo
- (if make-head?
- (make sequence
- (make formatting-instruction data:
- (string-append "<" "?php "
- newline
- "require \"../../id_common.inc\";"
- newline
- "id_header(\""
- )
- )
- title-sosofo
- (make formatting-instruction data:
- (string-append "\");"
- newline
- "?" ">"
- )
- )
- (header-navigation (current-node) navlist)
- body-sosofo
- (footer-navigation (current-node) navlist)
- (make formatting-instruction data:
- (string-append "<" "?php id_footer() ?>")
- )
- )
- body-sosofo
- )
- )
- )
- (if make-entity?
- (make entity
- system-id: (html-entity-file (html-file))
- (if %html-pubid%
- (make document-type
- name: "HTML"
- public-id: %html-pubid%)
- (empty-sosofo))
- doc-sosofo)
- (if (node-list=? (current-node) (sgml-root-element))
- (make sequence
- (if %html-pubid%
- (make document-type
- name: "HTML"
- public-id: %html-pubid%)
- (empty-sosofo))
- doc-sosofo)
- doc-sosofo)
- )
- )
- )
-
-</style-specification-body>
-</style-specification>
-<external-specification id="docbook" document="docbook.dsl">
-</style-sheet>
-
-<!--
-Local Variables:
-mode: scheme
-End:
--->
+++ /dev/null
-<!DOCTYPE style-sheet PUBLIC "-//James Clark//DTD DSSSL Style Sheet//EN" [
-<!ENTITY docbook.dsl SYSTEM "@DSSSL_DIR@/print/docbook.dsl"
- CDATA DSSSL>
-]>
-<!--
- $Id: yp2print.dsl.in,v 1.1 2006-02-02 18:22:47 mike Exp $
--->
-<style-sheet>
-<style-specification use="docbook">
-<style-specification-body>
-
-</style-specification-body>
-</style-specification>
-<external-specification id="docbook" document="docbook.dsl">
-</style-sheet>
-
-<!--
-Local Variables:
-mode: scheme
-End:
--->