Emacs indent of XML-documentation. Only minor changes in contents.
authorAdam Dickmeiss <adam@indexdata.dk>
Thu, 19 Jul 2001 23:29:40 +0000 (23:29 +0000)
committerAdam Dickmeiss <adam@indexdata.dk>
Thu, 19 Jul 2001 23:29:40 +0000 (23:29 +0000)
doc/asn.xml
doc/comstack.xml
doc/frontend.xml
doc/future.xml
doc/indexdata.xml
doc/installation.xml
doc/introduction.xml
doc/license.xml
doc/odr.xml
doc/tools.xml
doc/yaz.xml

index ed7dda4..e126267 100644 (file)
-<!-- $Header: /home/cvsroot/yaz/doc/asn.xml,v 1.3 2001-07-19 16:53:02 adam Exp $ -->
-<chapter><title>The ASN Module</title>
-<sect1><title>Introduction</title>
-<para>
-The &asn; module provides you with a set of C struct definitions for the
-various PDUs of the protocol, as well as for the complex types
-appearing within the PDUs. For the primitive data types, the C
-representation often takes the form of an ordinary C language type,
-such as <literal>int</literal>. For ASN.1 constructs that have no direct
-representation in C, such as general octet strings and bit strings,
-the &odr; module (see section <link linkend="odr">The ODR Module</link>)
-provides auxiliary definitions.
-</para>
-</sect1>
-<sect1><title>Preparing PDUs</title>
-
-<para>
-A structure representing a complex ASN.1 type doesn't in itself contain the
-members of that type. Instead, the structure contains
-<emphasis>pointers</emphasis> to the members of the type.
-This is necessary, in part, to allow a mechanism for specifying which
-of the optional structure (SEQUENCE) members are present, and which
-are not. It follows that you will need to somehow provide space for
-the individual members of the structure, and set the pointers to
-refer to the members.
-</para>
-<para>
-The conversion routines don't care how you allocate and maintain your
-C structures - they just follow the pointers that you provide.
-Depending on the complexity of your application, and your personal
-taste, there are at least three different approaches that you may take
-when you allocate the structures.
-</para>
-
-<para>
-You can use static or automatic local variables in the function that
-prepares the PDU. This is a simple approach, and it provides the most
-efficient form of memory management. While it works well for flat
-PDUs like the InitReqest, it will generally not be sufficient for say,
-the generation of an arbitrarily complex RPN query structure.
-</para>
-<para>
-You can individually create the structure and its members using the
-<function>malloc(2)</function> function. If you want to ensure that
-the data is freed when it is no longer needed, you will have to
-define a function that individually releases each member of a
-structure before freeing the structure itself.
-</para>
-<para>
-You can use the <function>odr_malloc()</function> function (see section 
-<link linkend="odr-use">Using ODR</link> for details). When you use
-<function>odr_malloc()</function>, you can release all of the
-allocated data in a single operation, independent of any pointers and
-relations between the data. <function>odr_malloc()</function> is based on a
-&quot;nibble-memory&quot;
-scheme, in which large portions of memory are allocated, and then
-gradually handed out with each call to <function>odr_malloc()</function>.
-The next time you call <function>odr_reset()</function>, all of the
-memory allocated since the last call is recycled for future use (actually,
-it is placed on a free-list).
-</para>
-<para>
-You can combine all of the methods described here. This will often be
-the most practical approach. For instance, you might use
-<function>odr_malloc()</function> to allocate an entire structure and
-some of its elements, while you leave other elements pointing to global
-or per-session default variables.
-</para>
-
-<para>
-The &asn; module provides an important aid in creating new PDUs. For
-each of the PDU types (say, <function>Z_InitRequest</function>), a
-function is provided that allocates and initializes an instance of
-that PDU type for you. In the case of the InitRequest, the function is
-simply named <function>zget_InitRequest()</function>, and it sets up
-reasonable default value for all of the mandatory members. The optional
-members are generally initialized to null pointers. This last aspect
-is very important: it ensures that if the PDU definitions are
-extended after you finish your implementation (to accommodate
-new versions of the protocol, say), you won't get into trouble with
-uninitialized pointers in your structures. The functions use
-<function>odr_malloc()</function> to
-allocate the PDUs and its members, so you can free everything again with a
-single call to <function>odr_reset()</function>. We strongly recommend
-that you use the <literal>zget_*</literal>
-functions whenever you are preparing a PDU (in a C++ API, the
-<literal>zget_</literal>
-functions would probably be promoted to constructors for the
-individual types).
-</para>
-<para>
-The prototype for the individual PDU types generally look like this:
-</para>
-<synopsis>
-  Z_&lt;type> *zget_&lt;type>(ODR o);
-</synopsis>
-
-<para>
-eg.:
-</para>
-
-<synopsis>
-  Z_InitRequest *zget_InitRequest(ODR o);
-</synopsis>
-
-<para>
-The &odr; handle should generally be your encoding stream, but it needn't be.
-</para>
-<para>
-As well as the individual PDU functions, a function <function>
-zget_APDU()</function> is
-provided, which allocates a toplevel Z-APDU of the type requested:
-</para>
-
-<synopsis>
-  Z_APDU *zget_APDU(ODR o, int which);
-</synopsis>
-
-<para>
-The <varname>which</varname> parameter is (of course) the discriminator
-belonging to the <varname>Z_APDU</varname> <literal>CHOICE</literal> type.
-All of the interface described here is provided by the &asn; module, and
-you access it through the <filename>proto.h</filename> header file.
-
-</para>
-</sect1>
-<sect1><title id="oid">Object Identifiers</title>
-<para>
-When you refer to object identifiers in your application, you need to
-be aware that SR and Z39.50 use two different set of OIDs to refer to
-the same objects. To handle this easily, &yaz; provides a utility module
-to &asn; which provides an internal representation of the OIDs used in
-both protocols. Each oid is described by a structure:
-</para>
-
-<screen>
+<!-- $Id: asn.xml,v 1.4 2001-07-19 23:29:40 adam Exp $ -->
+ <chapter><title>The ASN Module</title>
+  <sect1><title>Introduction</title>
+   <para>
+    The &asn; module provides you with a set of C struct definitions for the
+    various PDUs of the protocol, as well as for the complex types
+    appearing within the PDUs. For the primitive data types, the C
+    representation often takes the form of an ordinary C language type,
+    such as <literal>int</literal>. For ASN.1 constructs that have no direct
+    representation in C, such as general octet strings and bit strings,
+    the &odr; module (see section <link linkend="odr">The ODR Module</link>)
+    provides auxiliary definitions.
+   </para>
+  </sect1>
+  <sect1><title>Preparing PDUs</title>
+
+   <para>
+    A structure representing a complex ASN.1 type doesn't in itself contain the
+    members of that type. Instead, the structure contains
+    <emphasis>pointers</emphasis> to the members of the type.
+    This is necessary, in part, to allow a mechanism for specifying which
+    of the optional structure (SEQUENCE) members are present, and which
+    are not. It follows that you will need to somehow provide space for
+    the individual members of the structure, and set the pointers to
+    refer to the members.
+   </para>
+   <para>
+    The conversion routines don't care how you allocate and maintain your
+    C structures - they just follow the pointers that you provide.
+    Depending on the complexity of your application, and your personal
+    taste, there are at least three different approaches that you may take
+    when you allocate the structures.
+   </para>
+
+   <para>
+    You can use static or automatic local variables in the function that
+    prepares the PDU. This is a simple approach, and it provides the most
+    efficient form of memory management. While it works well for flat
+    PDUs like the InitReqest, it will generally not be sufficient for say,
+    the generation of an arbitrarily complex RPN query structure.
+   </para>
+   <para>
+    You can individually create the structure and its members using the
+    <function>malloc(2)</function> function. If you want to ensure that
+    the data is freed when it is no longer needed, you will have to
+    define a function that individually releases each member of a
+    structure before freeing the structure itself.
+   </para>
+   <para>
+    You can use the <function>odr_malloc()</function> function (see section 
+    <link linkend="odr-use">Using ODR</link> for details). When you use
+    <function>odr_malloc()</function>, you can release all of the
+    allocated data in a single operation, independent of any pointers and
+    relations between the data. <function>odr_malloc()</function> is based on a
+    &quot;nibble-memory&quot;
+    scheme, in which large portions of memory are allocated, and then
+    gradually handed out with each call to <function>odr_malloc()</function>.
+    The next time you call <function>odr_reset()</function>, all of the
+    memory allocated since the last call is recycled for future use (actually,
+    it is placed on a free-list).
+   </para>
+   <para>
+    You can combine all of the methods described here. This will often be
+    the most practical approach. For instance, you might use
+    <function>odr_malloc()</function> to allocate an entire structure and
+    some of its elements, while you leave other elements pointing to global
+    or per-session default variables.
+   </para>
+
+   <para>
+    The &asn; module provides an important aid in creating new PDUs. For
+    each of the PDU types (say, <function>Z_InitRequest</function>), a
+    function is provided that allocates and initializes an instance of
+    that PDU type for you. In the case of the InitRequest, the function is
+    simply named <function>zget_InitRequest()</function>, and it sets up
+    reasonable default value for all of the mandatory members. The optional
+    members are generally initialized to null pointers. This last aspect
+    is very important: it ensures that if the PDU definitions are
+    extended after you finish your implementation (to accommodate
+    new versions of the protocol, say), you won't get into trouble with
+    uninitialized pointers in your structures. The functions use
+    <function>odr_malloc()</function> to
+    allocate the PDUs and its members, so you can free everything again with a
+    single call to <function>odr_reset()</function>. We strongly recommend
+    that you use the <literal>zget_*</literal>
+    functions whenever you are preparing a PDU (in a C++ API, the
+    <literal>zget_</literal>
+    functions would probably be promoted to constructors for the
+    individual types).
+   </para>
+   <para>
+    The prototype for the individual PDU types generally look like this:
+   </para>
+   <synopsis>
+    Z_&lt;type> *zget_&lt;type>(ODR o);
+   </synopsis>
+
+   <para>
+    eg.:
+   </para>
+
+   <synopsis>
+    Z_InitRequest *zget_InitRequest(ODR o);
+   </synopsis>
+
+   <para>
+    The &odr; handle should generally be your encoding stream, but it needn't be.
+   </para>
+   <para>
+    As well as the individual PDU functions, a function <function>
+     zget_APDU()</function> is
+    provided, which allocates a toplevel Z-APDU of the type requested:
+   </para>
+
+   <synopsis>
+    Z_APDU *zget_APDU(ODR o, int which);
+   </synopsis>
+
+   <para>
+    The <varname>which</varname> parameter is (of course) the discriminator
+    belonging to the <varname>Z_APDU</varname> <literal>CHOICE</literal> type.
+    All of the interface described here is provided by the &asn; module, and
+    you access it through the <filename>proto.h</filename> header file.
+
+   </para>
+  </sect1>
+  <sect1><title id="oid">Object Identifiers</title>
+   <para>
+    When you refer to object identifiers in your application, you need to
+    be aware that SR and Z39.50 use two different set of OIDs to refer to
+    the same objects. To handle this easily, &yaz; provides a utility module
+    to &asn; which provides an internal representation of the OIDs used in
+    both protocols. Each oid is described by a structure:
+   </para>
+
+   <screen>
 typedef struct oident
 {
     enum oid_proto proto;
@@ -142,63 +142,63 @@ typedef struct oident
     int oidsuffix[OID_SIZE];
     char *desc;
 } oident;
-</screen>
+   </screen>
 
-<para>
-The <literal>proto</literal> field can be set to either
-<literal>PROTO_SR</literal> or <literal>PROTO_Z3950</literal>.
-The <literal>class</literal> might be, say,
-<literal>CLASS_RECSYN</literal>, and the <literal>value</literal> might be
-<literal>VAL_USMARC</literal> for the USMARC record format. Functions
-</para>
+   <para>
+    The <literal>proto</literal> field can be set to either
+    <literal>PROTO_SR</literal> or <literal>PROTO_Z3950</literal>.
+    The <literal>class</literal> might be, say,
+    <literal>CLASS_RECSYN</literal>, and the <literal>value</literal> might be
+    <literal>VAL_USMARC</literal> for the USMARC record format. Functions
+   </para>
 
-<screen>
+   <screen>
 int *oid_ent_to_oid(struct oident *ent, int *dst);
 struct oident *oid_getentbyoid(int *o);
-</screen>
-
-<para>
-are provided to map between object identifiers and database entries.
-If you store a member of the <literal>oid_proto</literal> type in
-your association state information, it's a simple matter, at runtime,
-to generate the correct OID when you need it. For decoding, you can
-simply ignore the proto field, or if you're strict, you can verify
-that your peer is using the OID family from the correct protocol.
-The <literal>desc</literal> field is a short, human-readable name
-for the PDU, useful mainly for diagnostic output.
-</para>
-
-<note>
-<para>
-The old function <function>oid_getoidbyent</function> still exists but is
-not thread safe. Use <function>oid_ent_to_oid</function> instead
-and pass an array of size <literal>OID_SIZE</literal>.
-</para>
-</note>
-
-<note>
-<para>
-Plans are underway to merge the two protocols into a single
-definition, with one set of object identifiers. When this happens, the
-oid module will no longer be required to support protocol
-independence, but it should still be useful as a simple OID database.
-</para>
-</note>
-
-</sect1>
-<sect1><title>EXTERNAL Data</title>
-
-<para>
-In order to achieve extensibility and adaptability to different
-application domains, the new version of the protocol defines many
-structures outside of the main ASN.1 specification, referencing them
-through ASN.1 EXTERNAL constructs. To simplify the construction and access
-to the externally referenced data, the &asn; module defines a
-specialized version of the EXTERNAL construct, called
-<literal>Z_External</literal>.It is defined thus:
-</para>
-
-<screen>
+   </screen>
+
+   <para>
+    are provided to map between object identifiers and database entries.
+    If you store a member of the <literal>oid_proto</literal> type in
+    your association state information, it's a simple matter, at runtime,
+    to generate the correct OID when you need it. For decoding, you can
+    simply ignore the proto field, or if you're strict, you can verify
+    that your peer is using the OID family from the correct protocol.
+    The <literal>desc</literal> field is a short, human-readable name
+    for the PDU, useful mainly for diagnostic output.
+   </para>
+
+   <note>
+    <para>
+     The old function <function>oid_getoidbyent</function> still exists but is
+     not thread safe. Use <function>oid_ent_to_oid</function> instead
+     and pass an array of size <literal>OID_SIZE</literal>.
+    </para>
+   </note>
+
+   <note>
+    <para>
+     Plans are underway to merge the two protocols into a single
+     definition, with one set of object identifiers. When this happens, the
+     oid module will no longer be required to support protocol
+     independence, but it should still be useful as a simple OID database.
+    </para>
+   </note>
+
+  </sect1>
+  <sect1><title>EXTERNAL Data</title>
+
+   <para>
+    In order to achieve extensibility and adaptability to different
+    application domains, the new version of the protocol defines many
+    structures outside of the main ASN.1 specification, referencing them
+    through ASN.1 EXTERNAL constructs. To simplify the construction and access
+    to the externally referenced data, the &asn; module defines a
+    specialized version of the EXTERNAL construct, called
+    <literal>Z_External</literal>.It is defined thus:
+   </para>
+
+   <screen>
 typedef struct Z_External
 {
     Odr_oid *direct_reference;
@@ -206,527 +206,544 @@ typedef struct Z_External
     char *descriptor;
     enum
     {
-       /* Generic types */
-       Z_External_single = 0,
-       Z_External_octet,
-       Z_External_arbitrary,
+        /* Generic types */
+        Z_External_single = 0,
+        Z_External_octet,
+        Z_External_arbitrary,
 
-       /* Specific types */
-       Z_External_SUTRS,
-       Z_External_explainRecord,
-       Z_External_resourceReport1,
-       Z_External_resourceReport2
+        /* Specific types */
+        Z_External_SUTRS,
+        Z_External_explainRecord,
+        Z_External_resourceReport1,
+        Z_External_resourceReport2
 
-       ...
+    ...
 
     } which;
     union
     {
-       /* Generic types */
-       Odr_any *single_ASN1_type;
-       Odr_oct *octet_aligned;
-       Odr_bitmask *arbitrary;
+        /* Generic types */
+        Odr_any *single_ASN1_type;
+        Odr_oct *octet_aligned;
+        Odr_bitmask *arbitrary;
 
-       /* Specific types */
-       Z_SUTRS *sutrs;
-       Z_ExplainRecord *explainRecord;
-       Z_ResourceReport1 *resourceReport1;
-       Z_ResourceReport2 *resourceReport2;
+        /* Specific types */
+        Z_SUTRS *sutrs;
+        Z_ExplainRecord *explainRecord;
+        Z_ResourceReport1 *resourceReport1;
+        Z_ResourceReport2 *resourceReport2;
 
-       ...
+        ...
 
     } u;
 } Z_External;
-</screen>
-
-<para>
-When decoding, the &asn; module will attempt to determine which
-syntax describes the data by looking at the reference fields
-(currently only the direct-reference). For ASN.1 structured data, you
-need only consult the <literal>which</literal> field to determine the type of
-data. You can the access  the data directly through the union. When
-constructing data for encoding, you set the union pointer to point to
-the data, and set the <literal>which</literal> field accordingly.
-Remember also to set the direct (or indirect) reference to the correct
-OID for the data type.
-For non-ASN.1 data such as MARC records, use the
-<literal>octet_aligned</literal> arm of the union.
-</para>
-
-<para>
-Some servers return ASN.1 structured data values (eg. database
-records) as BER-encoded records placed in the <literal>octet-aligned</literal>
-branch of the EXTERNAL CHOICE. The ASN-module will <emphasis>not</emphasis>
-automatically decode these records. To help you decode the records in
-the application, the function
-</para>
-
-<screen>
-Z_ext_typeent *z_ext_gettypebyref(oid_value ref);
-</screen>
-
-<para>
-Can be used to retrieve information about the known, external data
-types. The function return a pointer to a static area, or NULL, if no
-match for the given direct reference is found. The
-<literal>Z_ext_typeent</literal>
-is defined as:
-</para>
-
-<screen>
+   </screen>
+
+   <para>
+    When decoding, the &asn; module will attempt to determine which
+    syntax describes the data by looking at the reference fields
+    (currently only the direct-reference). For ASN.1 structured data, you
+    need only consult the <literal>which</literal> field to determine the
+    type of data. You can the access  the data directly through the union.
+    When constructing data for encoding, you set the union pointer to point
+    to the data, and set the <literal>which</literal> field accordingly.
+    Remember also to set the direct (or indirect) reference to the correct
+    OID for the data type.
+    For non-ASN.1 data such as MARC records, use the
+    <literal>octet_aligned</literal> arm of the union.
+   </para>
+
+   <para>
+    Some servers return ASN.1 structured data values (eg. database
+    records) as BER-encoded records placed in the
+    <literal>octet-aligned</literal> branch of the EXTERNAL CHOICE.
+    The ASN-module will <emphasis>not</emphasis> automatically decode
+    these records. To help you decode the records in the application, the
+    function
+   </para>
+
+   <screen>
+    Z_ext_typeent *z_ext_gettypebyref(oid_value ref);
+   </screen>
+
+   <para>
+    Can be used to retrieve information about the known, external data
+    types. The function return a pointer to a static area, or NULL, if no
+    match for the given direct reference is found. The
+    <literal>Z_ext_typeent</literal>
+    is defined as:
+   </para>
+
+   <screen>
 typedef struct Z_ext_typeent
 {
     oid_value dref;    /* the direct-reference OID value. */
     int what;          /* discriminator value for the external CHOICE */
     Odr_fun fun;       /* decoder function */
 } Z_ext_typeent;
-</screen>
-
-<para>
-The <literal>what</literal> member contains the <literal>Z_External</literal>
-union discriminator value for the given type: For the SUTRS record
-syntax, the value would be <literal>Z_External_sutrs</literal>.
-The <literal>fun</literal> member contains a pointer to the
-function which encodes/decodes the given type. Again, for the SUTRS
-record syntax, the value of <literal>fun</literal> would be
-<literal>z_SUTRS</literal> (a function pointer).
-</para>
-
-<para>
-If you receive an EXTERNAL which contains an octet-string value that
-you suspect of being an ASN.1-structured data value, you can use
-<literal>z_ext_gettypebyref</literal> to look for the provided
-direct-reference.
-If the return value is different from NULL, you can use the provided
-function to decode the BER string (see section <link linkend="odr-use">
-Using ODR</link>).
-</para>
-
-<para>
-If you want to <emphasis>send</emphasis> EXTERNALs containing
-ASN.1-structured values in the occtet-aligned branch of the CHOICE, this
-is possible too. However, on the encoding phase, it requires a somewhat
-involved juggling around of the various buffers involved.
-</para>
-<para>
-If you need to add new, externally defined data types, you must update
-the struct above, in the source file <filename>prt-ext.h</filename>, as
-well as the encoder/decoder in the file <filename>prt-ext.c</filename>.
-When changing the latter, remember to update both the <literal>arm</literal>
-arrary and the list <literal>type_table</literal>, which drives the CHOICE
-biasing that is necessary to tell the different, structured types apart
-on decoding.
-</para>
-
-<note>
-<para>
-Eventually, the EXTERNAL processing will most likely
-automatically insert the correct OIDs or indirect-refs. First,
-however, we need to determine how application-context management
-(specifically the presentation-context-list) should fit into the
-various modules.
-</para>
-</note>
-
-</sect1>
-<sect1><title>PDU Contents Table</title>
-
-<para>
-We include, for reference, a listing of the fields of each top-level
-PDU, as well as their default settings.
-</para>
-
-<table frame="top"><title>Default settings for PDU Initialize Request</title>
-<tgroup cols="3">
-<colspec colname="field"></colspec>
-<colspec colname="type"></colspec>
-<colspec colname="value"></colspec>
-<thead>
-<row>
-<entry>Field</entry>
-<entry>Type</entry>
-<entry>Default Value</entry>
-</row>
-</thead>
-<tbody>
-
-<row><entry>
-referenceId</entry><entry>Z_ReferenceId</entry><entry>NULL
-</entry></row>
-
-<row><entry>
-protocolVersion</entry><entry>Odr_bitmask</entry><entry>Empty bitmask
-</entry></row>
-
-<row><entry>
-options</entry><entry>Odr_bitmask</entry><entry>Empty bitmask
-</entry></row>
-
-<row><entry>
-preferredMessageSize</entry><entry>int</entry><entry>30*1024
-</entry></row>
-
-<row><entry>
-maximumRecordSize</entry><entry>int</entry><entry>30*1024
-</entry></row>
-
-<row><entry>
-idAuthentication</entry><entry>Z_IdAuthentication</entry><entry>NULL
-</entry></row>
-
-<row><entry>
-implementationId</entry><entry>char*</entry><entry>"YAZ (id=81)"
-</entry></row>
-
-<row><entry>
-implementationName</entry><entry>char*</entry><entry>"Index Data/YAZ"
-</entry></row>
-
-<row><entry>
-implementationVersion</entry><entry>char*</entry><entry>YAZ_VERSION
-</entry></row>
-
-<row><entry>
-userInformationField</entry><entry>Z_UserInformation</entry><entry>NULL
-</entry></row>
-
-<row><entry>
-otherInfo</entry><entry>Z_OtherInformation</entry><entry>NULL
-</entry></row>
-
-</tbody>
-</tgroup>
-</table>
-
-<table frame="top"><title>Default settings for PDU Initialize Response</title>
-<tgroup cols="3">
-<colspec colname="field"></colspec>
-<colspec colname="type"></colspec>
-<colspec colname="value"></colspec>
-<thead>
-<row>
-<entry>Field</entry>
-<entry>Type</entry>
-<entry>Default Value</entry>
-</row>
-</thead>
-<tbody>
-
-<row><entry>
-referenceId</entry><entry>Z_ReferenceId</entry><entry>NULL
-</entry></row>
-
-<row><entry>
-protocolVersion</entry><entry>Odr_bitmask</entry><entry>Empty bitmask
-</entry></row>
-
-<row><entry>
-options</entry><entry>Odr_bitmask</entry><entry>Empty bitmask
-</entry></row>
-
-<row><entry>
-preferredMessageSize</entry><entry>int</entry><entry>30*1024
-</entry></row>
-
-<row><entry>
-maximumRecordSize</entry><entry>int</entry><entry>30*1024
-</entry></row>
-
-<row><entry>
-result</entry><entry>bool_t</entry><entry>TRUE
-</entry></row>
-
-<row><entry>
-implementationId</entry><entry>char*</entry><entry>"YAZ (id=81)"
-</entry></row>
-
-<row><entry>
-implementationName</entry><entry>char*</entry><entry>"Index Data/YAZ"
-</entry></row>
-
-<row><entry>
-implementationVersion</entry><entry>char*</entry><entry>YAZ_VERSION
-</entry></row>
-
-<row><entry>
-userInformationField</entry><entry>Z_UserInformation</entry><entry>NULL
-</entry></row>
-
-<row><entry>
-otherInfo</entry><entry>Z_OtherInformation</entry><entry>NULL
-</entry></row>
-
-</tbody>
-</tgroup>
-</table>
-
-<table frame="top"><title>Default settings for PDU Search Request</title>
-<tgroup cols="3">
-<colspec colname="field"></colspec>
-<colspec colname="type"></colspec>
-<colspec colname="value"></colspec>
-<thead>
-<row>
-<entry>Field</entry>
-<entry>Type</entry>
-<entry>Default Value</entry>
-</row>
-</thead>
-<tbody>
-
-<row><entry>
-referenceId</entry><entry>Z_ReferenceId</entry><entry>NULL
-</entry></row>
-
-<row><entry>
-smallSetUpperBound</entry><entry>int</entry><entry>0
-</entry></row>
-
-<row><entry>
-largeSetLowerBound</entry><entry>int</entry><entry>1
-</entry></row>
-
-<row><entry>
-mediumSetPresentNumber</entry><entry>int</entry><entry>0
-</entry></row>
-
-<row><entry>
-replaceIndicator</entry><entry>bool_t</entry><entry>TRUE
-</entry></row>
-
-<row><entry>
-resultSetName</entry><entry>char *</entry><entry>"default"
-</entry></row>
-
-<row><entry>
-num_databaseNames</entry><entry>int</entry><entry>0
-</entry></row>
-
-<row><entry>
-databaseNames</entry><entry>char **</entry><entry>NULL
-</entry></row>
-
-<row><entry>
-smallSetElementSetNames</entry><entry>Z_ElementSetNames</entry><entry>NULL
-</entry></row>
-
-<row><entry>
-mediumSetElementSetNames</entry><entry>Z_ElementSetNames</entry><entry>NULL
-</entry></row>
-
-<row><entry>
-preferredRecordSyntax</entry><entry>Odr_oid</entry><entry>NULL
-</entry></row>
-
-<row><entry>
-query</entry><entry>Z_Query</entry><entry>NULL
-</entry></row>
-
-<row><entry>
-additionalSearchInfo</entry><entry>Z_OtherInformation</entry><entry>NULL
-</entry></row>
-
-<row><entry>
-otherInfo</entry><entry>Z_OtherInformation</entry><entry>NULL
-</entry></row>
-
-</tbody>
-</tgroup>
-</table>
-
-<screen>
-Z_SearchResponse
-----------------
-Field                        Type                Default value
-
-referenceId                  Z_ReferenceId       NULL
-resultCount                  int                 0
-numberOfRecordsReturned      int                 0
-nextResultSetPosition        int                 0
-searchStatus                 bool_t              TRUE
-resultSetStatus              int                 NULL
-presentStatus                int                 NULL
-records                      Z_Records           NULL
-additionalSearchInfo         Z_OtherInformation  NULL
-otherInfo                    Z_OtherInformation  NULL
-</screen>
-
-<screen>
-Z_PresentRequest
-----------------
-Field                        Type                Default value
-
-referenceId                  Z_ReferenceId       NULL
-resultSetId                  char*               "default"
-resultSetStartPoint          int                 1
-numberOfRecordsRequested     int                 10
-num_ranges                   int                 0
-additionalRanges             Z_Range             NULL
-recordComposition            Z_RecordComposition NULL
-preferredRecordSyntax        Odr_oid             NULL
-maxSegmentCount              int                 NULL
-maxRecordSize                int                 NULL
-maxSegmentSize               int                 NULL
-otherInfo                    Z_OtherInformation  NULL
-</screen>
-
-<screen>
-Z_PresentResponse
------------------
-Field                        Type                Default value
-
-referenceId                  Z_ReferenceId       NULL
-numberOfRecordsReturned      int                 0
-nextResultSetPosition        int                 0
-presentStatus                int                 Z_PRES_SUCCESS
-records                      Z_Records           NULL
-otherInfo                    Z_OtherInformation  NULL
-</screen>
-
-<screen>
-Z_DeleteResultSetRequest
-------------------------
-Field                        Type                Default value
-
-referenceId                  Z_ReferenceId       NULL
-deleteFunction               int                 Z_DeleteRequest_list
-num_ids                      int                 0
-resultSetList                char**              NULL
-otherInfo                    Z_OtherInformation  NULL
-</screen>
-
-<screen>
-Z_DeleteResultSetResponse
--------------------------
-Field                        Type                Default value
-
-referenceId                  Z_ReferenceId       NULL
-deleteOperationStatus        int                 Z_DeleteStatus_success
-num_statuses                 int                 0
-deleteListStatuses           Z_ListStatus**      NULL
-numberNotDeleted             int                 NULL
-num_bulkStatuses             int                 0
-bulkStatuses                 Z_ListStatus        NULL
-deleteMessage                char*               NULL
-otherInfo                    Z_OtherInformation  NULL
-</screen>
-
-<screen>
-Z_ScanRequest
--------------
-Field                        Type                Default value
-
-referenceId                  Z_ReferenceId       NULL
-num_databaseNames            int                 0
-databaseNames                char**              NULL
-attributeSet                 Odr_oid             NULL
-termListAndStartPoint        Z_AttributesPlus... NULL
-stepSize                     int                 NULL
-numberOfTermsRequested       int                 20
-preferredPositionInResponse  int                 NULL
-otherInfo                    Z_OtherInformation  NULL
-</screen>
-
-<screen>
-Z_ScanResponse
---------------
-Field                        Type                Default value
-
-referenceId                  Z_ReferenceId       NULL
-stepSize                     int                 NULL
-scanStatus                   int                 Z_Scan_success
-numberOfEntriesReturned      int                 0
-positionOfTerm               int                 NULL
-entries                      Z_ListEntris        NULL
-attributeSet                 Odr_oid             NULL
-otherInfo                    Z_OtherInformation  NULL
-</screen>
-
-<screen>
-Z_TriggerResourceControlRequest
--------------------------------
-Field                        Type                Default value
-
-referenceId                  Z_ReferenceId       NULL
-requestedAction              int                 Z_TriggerResourceCtrl_resou..
-prefResourceReportFormat     Odr_oid             NULL
-resultSetWanted              bool_t              NULL
-otherInfo                    Z_OtherInformation  NULL
-</screen>
-
-<screen>
-Z_ResourceControlRequest
-------------------------
-Field                        Type                Default value
-
-referenceId                  Z_ReferenceId       NULL
-suspendedFlag                bool_t              NULL
-resourceReport               Z_External          NULL
-partialResultsAvailable      int                 NULL
-responseRequired             bool_t              FALSE
-triggeredRequestFlag         bool_t              NULL
-otherInfo                    Z_OtherInformation  NULL
-</screen>
-
-<screen>
-Z_ResourceControlResponse
--------------------------
-Field                        Type                Default value
-
-referenceId                  Z_ReferenceId       NULL
-continueFlag                 bool_t              TRUE
-resultSetWanted              bool_t              NULL
-otherInfo                    Z_OtherInformation  NULL
-</screen>
-
-<screen>
-Z_AccessControlRequest
-----------------------
-Field                        Type                Default value
-
-referenceId                  Z_ReferenceId       NULL
-which                        enum                Z_AccessRequest_simpleForm;
-u                            union               NULL
-otherInfo                    Z_OtherInformation  NULL
-</screen>
-
-<screen>
-Z_AccessControlResponse
------------------------
-Field                        Type                Default value
-
-referenceId                  Z_ReferenceId       NULL
-which                        enum                Z_AccessResponse_simpleForm
-u                            union               NULL
-diagnostic                   Z_DiagRec           NULL
-otherInfo                    Z_OtherInformation  NULL
-</screen>
-
-<screen>
-Z_Segment
----------
-Field                        Type                Default value
-
-referenceId                  Z_ReferenceId       NULL
-numberOfRecordsReturned      int                 value=0
-num_segmentRecords           int                 0
-segmentRecords               Z_NamePlusRecord    NULL
-otherInfo                    Z_OtherInformation  NULL
-</screen>
-
-<screen>
-Z_Close
--------
-Field                        Type                Default value
-
-referenceId                  Z_ReferenceId       NULL
-closeReason                  int                 Z_Close_finished
-diagnosticInformation        char*               NULL
-resourceReportFormat         Odr_oid             NULL
-resourceFormat               Z_External          NULL
-otherInfo                    Z_OtherInformation  NULL
-
-</screen>
-
-</sect1>
-</chapter>
+   </screen>
+
+   <para>
+    The <literal>what</literal> member contains the
+    <literal>Z_External</literal> union discriminator value for the
+    given type: For the SUTRS record syntax, the value would be
+    <literal>Z_External_sutrs</literal>.
+    The <literal>fun</literal> member contains a pointer to the
+    function which encodes/decodes the given type. Again, for the SUTRS
+    record syntax, the value of <literal>fun</literal> would be
+    <literal>z_SUTRS</literal> (a function pointer).
+   </para>
+
+   <para>
+    If you receive an EXTERNAL which contains an octet-string value that
+    you suspect of being an ASN.1-structured data value, you can use
+    <literal>z_ext_gettypebyref</literal> to look for the provided
+    direct-reference.
+    If the return value is different from NULL, you can use the provided
+    function to decode the BER string (see section <link linkend="odr-use">
+     Using ODR</link>).
+   </para>
+
+   <para>
+    If you want to <emphasis>send</emphasis> EXTERNALs containing
+    ASN.1-structured values in the occtet-aligned branch of the CHOICE, this
+    is possible too. However, on the encoding phase, it requires a somewhat
+    involved juggling around of the various buffers involved.
+   </para>
+   <para>
+    If you need to add new, externally defined data types, you must update
+    the struct above, in the source file <filename>prt-ext.h</filename>, as
+    well as the encoder/decoder in the file <filename>prt-ext.c</filename>.
+    When changing the latter, remember to update both the <literal>arm</literal>
+    arrary and the list <literal>type_table</literal>, which drives the CHOICE
+    biasing that is necessary to tell the different, structured types apart
+    on decoding.
+   </para>
+
+   <note>
+    <para>
+     Eventually, the EXTERNAL processing will most likely
+     automatically insert the correct OIDs or indirect-refs. First,
+     however, we need to determine how application-context management
+     (specifically the presentation-context-list) should fit into the
+     various modules.
+    </para>
+   </note>
+
+  </sect1>
+  <sect1><title>PDU Contents Table</title>
+
+   <para>
+    We include, for reference, a listing of the fields of each top-level
+    PDU, as well as their default settings.
+   </para>
+
+   <table frame="top"><title>Default settings for PDU Initialize Request</title>
+    <tgroup cols="3">
+     <colspec colname="field"></colspec>
+     <colspec colname="type"></colspec>
+     <colspec colname="value"></colspec>
+     <thead>
+      <row>
+       <entry>Field</entry>
+       <entry>Type</entry>
+       <entry>Default Value</entry>
+      </row>
+     </thead>
+     <tbody>
+
+      <row><entry>
+       referenceId</entry><entry>Z_ReferenceId</entry><entry>NULL
+       </entry></row>
+
+      <row><entry>
+       protocolVersion</entry><entry>Odr_bitmask</entry><entry>Empty bitmask
+       </entry></row>
+
+      <row><entry>
+       options</entry><entry>Odr_bitmask</entry><entry>Empty bitmask
+       </entry></row>
+
+      <row><entry>
+       preferredMessageSize</entry><entry>int</entry><entry>30*1024
+       </entry></row>
+
+      <row><entry>
+       maximumRecordSize</entry><entry>int</entry><entry>30*1024
+       </entry></row>
+
+      <row><entry>
+       idAuthentication</entry><entry>Z_IdAuthentication</entry><entry>NULL
+       </entry></row>
+
+      <row><entry>
+       implementationId</entry><entry>char*</entry><entry>"YAZ (id=81)"
+       </entry></row>
+
+      <row><entry>
+       implementationName</entry><entry>char*</entry><entry>"Index Data/YAZ"
+       </entry></row>
+
+      <row><entry>
+       implementationVersion</entry><entry>char*</entry><entry>YAZ_VERSION
+       </entry></row>
+
+      <row><entry>
+       userInformationField</entry><entry>Z_UserInformation</entry><entry>NULL
+       </entry></row>
+
+      <row><entry>
+       otherInfo</entry><entry>Z_OtherInformation</entry><entry>NULL
+       </entry></row>
+
+     </tbody>
+    </tgroup>
+   </table>
+
+   <table frame="top"><title>Default settings for PDU Initialize Response</title>
+    <tgroup cols="3">
+     <colspec colname="field"></colspec>
+     <colspec colname="type"></colspec>
+     <colspec colname="value"></colspec>
+     <thead>
+      <row>
+       <entry>Field</entry>
+       <entry>Type</entry>
+       <entry>Default Value</entry>
+      </row>
+     </thead>
+     <tbody>
+
+      <row><entry>
+       referenceId</entry><entry>Z_ReferenceId</entry><entry>NULL
+       </entry></row>
+
+      <row><entry>
+       protocolVersion</entry><entry>Odr_bitmask</entry><entry>Empty bitmask
+       </entry></row>
+
+      <row><entry>
+       options</entry><entry>Odr_bitmask</entry><entry>Empty bitmask
+       </entry></row>
+
+      <row><entry>
+       preferredMessageSize</entry><entry>int</entry><entry>30*1024
+       </entry></row>
+
+      <row><entry>
+       maximumRecordSize</entry><entry>int</entry><entry>30*1024
+       </entry></row>
+
+      <row><entry>
+       result</entry><entry>bool_t</entry><entry>TRUE
+       </entry></row>
+
+      <row><entry>
+       implementationId</entry><entry>char*</entry><entry>"YAZ (id=81)"
+       </entry></row>
+
+      <row><entry>
+       implementationName</entry><entry>char*</entry><entry>"Index Data/YAZ"
+       </entry></row>
+
+      <row><entry>
+       implementationVersion</entry><entry>char*</entry><entry>YAZ_VERSION
+       </entry></row>
+
+      <row><entry>
+       userInformationField</entry><entry>Z_UserInformation</entry><entry>NULL
+       </entry></row>
+
+      <row><entry>
+       otherInfo</entry><entry>Z_OtherInformation</entry><entry>NULL
+       </entry></row>
+
+     </tbody>
+    </tgroup>
+   </table>
+
+   <table frame="top"><title>Default settings for PDU Search Request</title>
+    <tgroup cols="3">
+     <colspec colname="field"></colspec>
+     <colspec colname="type"></colspec>
+     <colspec colname="value"></colspec>
+     <thead>
+      <row>
+       <entry>Field</entry>
+       <entry>Type</entry>
+       <entry>Default Value</entry>
+      </row>
+     </thead>
+     <tbody>
+
+      <row><entry>
+       referenceId</entry><entry>Z_ReferenceId</entry><entry>NULL
+       </entry></row>
+
+      <row><entry>
+       smallSetUpperBound</entry><entry>int</entry><entry>0
+       </entry></row>
+
+      <row><entry>
+       largeSetLowerBound</entry><entry>int</entry><entry>1
+       </entry></row>
+
+      <row><entry>
+       mediumSetPresentNumber</entry><entry>int</entry><entry>0
+       </entry></row>
+
+      <row><entry>
+       replaceIndicator</entry><entry>bool_t</entry><entry>TRUE
+       </entry></row>
+
+      <row><entry>
+       resultSetName</entry><entry>char *</entry><entry>"default"
+       </entry></row>
+
+      <row><entry>
+       num_databaseNames</entry><entry>int</entry><entry>0
+       </entry></row>
+
+      <row><entry>
+       databaseNames</entry><entry>char **</entry><entry>NULL
+       </entry></row>
+
+      <row><entry>
+       smallSetElementSetNames</entry><entry>Z_ElementSetNames</entry><entry>NULL
+       </entry></row>
+
+      <row><entry>
+       mediumSetElementSetNames</entry><entry>Z_ElementSetNames</entry><entry>NULL
+       </entry></row>
+
+      <row><entry>
+       preferredRecordSyntax</entry><entry>Odr_oid</entry><entry>NULL
+       </entry></row>
+
+      <row><entry>
+       query</entry><entry>Z_Query</entry><entry>NULL
+       </entry></row>
+
+      <row><entry>
+       additionalSearchInfo</entry><entry>Z_OtherInformation</entry><entry>NULL
+       </entry></row>
+
+      <row><entry>
+       otherInfo</entry><entry>Z_OtherInformation</entry><entry>NULL
+       </entry></row>
+
+     </tbody>
+    </tgroup>
+   </table>
+
+   <screen>
+    Z_SearchResponse
+    ----------------
+    Field                        Type                Default value
+
+    referenceId                  Z_ReferenceId       NULL
+    resultCount                  int                 0
+    numberOfRecordsReturned      int                 0
+    nextResultSetPosition        int                 0
+    searchStatus                 bool_t              TRUE
+    resultSetStatus              int                 NULL
+    presentStatus                int                 NULL
+    records                      Z_Records           NULL
+    additionalSearchInfo         Z_OtherInformation  NULL
+    otherInfo                    Z_OtherInformation  NULL
+   </screen>
+
+   <screen>
+    Z_PresentRequest
+    ----------------
+    Field                        Type                Default value
+
+    referenceId                  Z_ReferenceId       NULL
+    resultSetId                  char*               "default"
+    resultSetStartPoint          int                 1
+    numberOfRecordsRequested     int                 10
+    num_ranges                   int                 0
+    additionalRanges             Z_Range             NULL
+    recordComposition            Z_RecordComposition NULL
+    preferredRecordSyntax        Odr_oid             NULL
+    maxSegmentCount              int                 NULL
+    maxRecordSize                int                 NULL
+    maxSegmentSize               int                 NULL
+    otherInfo                    Z_OtherInformation  NULL
+   </screen>
+
+   <screen>
+    Z_PresentResponse
+    -----------------
+    Field                        Type                Default value
+
+    referenceId                  Z_ReferenceId       NULL
+    numberOfRecordsReturned      int                 0
+    nextResultSetPosition        int                 0
+    presentStatus                int                 Z_PRES_SUCCESS
+    records                      Z_Records           NULL
+    otherInfo                    Z_OtherInformation  NULL
+   </screen>
+
+   <screen>
+    Z_DeleteResultSetRequest
+    ------------------------
+    Field                        Type                Default value
+
+    referenceId                  Z_ReferenceId       NULL
+    deleteFunction               int                 Z_DeleteRequest_list
+    num_ids                      int                 0
+    resultSetList                char**              NULL
+    otherInfo                    Z_OtherInformation  NULL
+   </screen>
+
+   <screen>
+    Z_DeleteResultSetResponse
+    -------------------------
+    Field                        Type                Default value
+
+    referenceId                  Z_ReferenceId       NULL
+    deleteOperationStatus        int                 Z_DeleteStatus_success
+    num_statuses                 int                 0
+    deleteListStatuses           Z_ListStatus**      NULL
+    numberNotDeleted             int                 NULL
+    num_bulkStatuses             int                 0
+    bulkStatuses                 Z_ListStatus        NULL
+    deleteMessage                char*               NULL
+    otherInfo                    Z_OtherInformation  NULL
+   </screen>
+
+   <screen>
+    Z_ScanRequest
+    -------------
+    Field                        Type                Default value
+
+    referenceId                  Z_ReferenceId       NULL
+    num_databaseNames            int                 0
+    databaseNames                char**              NULL
+    attributeSet                 Odr_oid             NULL
+    termListAndStartPoint        Z_AttributesPlus... NULL
+    stepSize                     int                 NULL
+    numberOfTermsRequested       int                 20
+    preferredPositionInResponse  int                 NULL
+    otherInfo                    Z_OtherInformation  NULL
+   </screen>
+
+   <screen>
+    Z_ScanResponse
+    --------------
+    Field                        Type                Default value
+
+    referenceId                  Z_ReferenceId       NULL
+    stepSize                     int                 NULL
+    scanStatus                   int                 Z_Scan_success
+    numberOfEntriesReturned      int                 0
+    positionOfTerm               int                 NULL
+    entries                      Z_ListEntris        NULL
+    attributeSet                 Odr_oid             NULL
+    otherInfo                    Z_OtherInformation  NULL
+   </screen>
+
+   <screen>
+    Z_TriggerResourceControlRequest
+    -------------------------------
+    Field                        Type                Default value
+
+    referenceId                  Z_ReferenceId       NULL
+    requestedAction              int                 Z_TriggerResourceCtrl_resou..
+    prefResourceReportFormat     Odr_oid             NULL
+    resultSetWanted              bool_t              NULL
+    otherInfo                    Z_OtherInformation  NULL
+   </screen>
+
+   <screen>
+    Z_ResourceControlRequest
+    ------------------------
+    Field                        Type                Default value
+
+    referenceId                  Z_ReferenceId       NULL
+    suspendedFlag                bool_t              NULL
+    resourceReport               Z_External          NULL
+    partialResultsAvailable      int                 NULL
+    responseRequired             bool_t              FALSE
+    triggeredRequestFlag         bool_t              NULL
+    otherInfo                    Z_OtherInformation  NULL
+   </screen>
+
+   <screen>
+    Z_ResourceControlResponse
+    -------------------------
+    Field                        Type                Default value
+
+    referenceId                  Z_ReferenceId       NULL
+    continueFlag                 bool_t              TRUE
+    resultSetWanted              bool_t              NULL
+    otherInfo                    Z_OtherInformation  NULL
+   </screen>
+
+   <screen>
+    Z_AccessControlRequest
+    ----------------------
+    Field                        Type                Default value
+
+    referenceId                  Z_ReferenceId       NULL
+    which                        enum                Z_AccessRequest_simpleForm;
+    u                            union               NULL
+    otherInfo                    Z_OtherInformation  NULL
+   </screen>
+
+   <screen>
+    Z_AccessControlResponse
+    -----------------------
+    Field                        Type                Default value
+
+    referenceId                  Z_ReferenceId       NULL
+    which                        enum                Z_AccessResponse_simpleForm
+    u                            union               NULL
+    diagnostic                   Z_DiagRec           NULL
+    otherInfo                    Z_OtherInformation  NULL
+   </screen>
+
+   <screen>
+    Z_Segment
+    ---------
+    Field                        Type                Default value
+
+    referenceId                  Z_ReferenceId       NULL
+    numberOfRecordsReturned      int                 value=0
+    num_segmentRecords           int                 0
+    segmentRecords               Z_NamePlusRecord    NULL
+    otherInfo                    Z_OtherInformation  NULL
+   </screen>
+
+   <screen>
+    Z_Close
+    -------
+    Field                        Type                Default value
+
+    referenceId                  Z_ReferenceId       NULL
+    closeReason                  int                 Z_Close_finished
+    diagnosticInformation        char*               NULL
+    resourceReportFormat         Odr_oid             NULL
+    resourceFormat               Z_External          NULL
+    otherInfo                    Z_OtherInformation  NULL
+
+   </screen>
+
+  </sect1>
+ </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: "yaz.xml"
+ sgml-local-catalogs: "../../docbook/docbook.cat"
+ sgml-namecase-general:t
+ End:
+ -->
index 7ecabfc..86b88f6 100644 (file)
@@ -1,9 +1,9 @@
-<!-- $Header: /home/cvsroot/yaz/doc/comstack.xml,v 1.1 2001-01-04 13:36:24 adam Exp $ -->
-<chapter><title id="comstack">The COMSTACK Module</title>
+<!-- $Id: comstack.xml,v 1.2 2001-07-19 23:29:40 adam Exp $ -->
+ <chapter><title id="comstack">The COMSTACK Module</title>
 
-<sect1><title>Synopsis (blocking mode)</title>
+  <sect1><title>Synopsis (blocking mode)</title>
 
-<programlisting>
+   <programlisting>
 
 COMSTACK *stack;
 char *buf = 0;
@@ -48,692 +48,691 @@ if (!length_incoming) {
 cs_close(stack);
 if (buf)
     free(buf);
+    
+   </programlisting>
+
+  </sect1>
+  <sect1><title>Introduction</title>
+
+   <para>
+    The &comstack;
+    subsystem provides a transparent interface to different types of transport
+    stacks for the exchange of BER-encoded data. At present, the
+    RFC1729 method (BER over TCP/IP), and Peter Furniss' XTImOSI
+    stack are supported, but others may be added in time. The philosophy of the
+    module is to provide a simple interface by hiding unused options and
+    facilities of the underlying libraries. This is always done at the risk
+    of losing generality, and it may prove that the interface will need
+    extension later on.
+   </para>
+
+   <para>
+    The interface is implemented in such a fashion that only the
+    sub-layers constructed to the transport methods that you wish to
+    use in your application are linked in.
+   </para>
+
+   <para>
+    You will note that even though simplicity was a goal in the design,
+    the interface is still orders of magnitudes more complex than the
+    transport systems found in many other packages. One reason is that
+    the interface needs to support the somewhat different requirements of
+    the different lower-layer communications stacks; another important reason is
+    that the interface seeks to provide a more or less industrial-strength
+    approach to asynchronous event-handling. When no function is allowed
+    to block, things get more complex - particularly on the server
+    side. We urge you to have a look at the demonstration client and server
+    provided with the package. They are meant to be easily readable and
+    instructive, while still being at least moderately useful.
+   </para>
+
+  </sect1>
+  <sect1><title>Common Functions</title>
+
+   <sect2><title>Managing Endpoints</title>
+
+    <synopsis>
+     COMSTACK cs_create(CS_TYPE type, int blocking, int protocol);
+    </synopsis>
+
+    <para>
+     Creates an instance of the protocol stack - a communications endpoint.
+     The <literal>type</literal> parameter determines the mode of communication.
+     At present, the values
+     <literal>tcpip_type</literal>
+     and
+     <literal>mosi_type</literal>
+     are recognized. The function returns a null-pointer if a system error
+     occurs. The <literal>blocking</literal> parameter should be one if you wish
+     the association to operate in blocking mode, zero otherwise. The
+     <literal>protocol</literal> field should be one of
+     <literal>PROTO_SR</literal> or <literal>PROTO_Z3950</literal>.
+    </para>
+
+
+    <synopsis>
+     int cs_close(COMSTACK handle);
+    </synopsis>
+
+    <para>
+     Closes the connection (as elegantly as the lower layers will permit),
+     and releases the resouces pointed to by the
+     <literal>handle</literal>
+     parameter. The
+     <literal>handle</literal>
+     should not be referenced again after this call.
+    </para>
+
+    <note>
+     <para>
+      We really need a soft disconnect, don't we?
+     </para>
+    </note>
+   </sect2>
+
+   <sect2><title>Data Exchange</title>
+
+    <synopsis>
+     int cs_put(COMSTACK handle, char *buf, int len);
+    </synopsis>
+
+    <para>
+     Sends
+     <literal>buf</literal>
+     down the wire. In blocking mode, this function will return only when a
+     full buffer has been written, or an error has occurred. In nonblocking
+     mode, it's possible that the function will be unable to send the full
+     buffer at once, which will be indicated by a return value of 1. The
+     function will keep track of the number of octets already written; you
+     should call it repeatedly with the same values of <literal>buf</literal>
+     and <literal>len</literal>, until the buffer has been transmitted.
+     When a full buffer has been sent, the function will return 0 for
+     success. -1 indicates an error condition (see below).
+    </para>
+
+    <synopsis>
+     int cs_get(COMSTACK handle, char **buf, int *size);
+    </synopsis>
+
+    <para>
+     Receives a PDU from the peer. Returns the number of bytes
+     read. In nonblocking mode, it is possible that not all of the packet can be
+     read at once. In this case, the function returns 1. To simplify the
+     interface, the function is
+     responsible for managing the size of the buffer. It will be reallocated
+     if necessary to contain large packages, and will sometimes be moved
+     around internally by the subsystem when partial packages are read. Before
+     calling
+     <function>cs_get</function>
+     for the fist time, the buffer can be initialized to the null pointer,
+     and the length should also be set to 0 - cs_get will perform a
+     <function>malloc(2)</function>
+     on the buffer for you. When a full buffer has been read, the size of
+     the package is returned (which will always be greater than 1). -1
+     indicates an error condition.
+    </para>
+
+    <para>
+     See also the <function>cs_more()</function> function below.
+    </para>
+
+    <synopsis>
+     int cs_more(COMSTACK handle);
+    </synopsis>
+
+    <para>
+     The <function>cs_more()</function> function should be used in conjunction
+     with <function>cs_get</function> and
+     <function>select(2)</function>.
+     The <function>cs_get()</function> function will sometimes
+     (notably in the TCP/IP mode) read more than a single protocol package
+     off the network. When this happens, the extra package is stored
+     by the subsystem. After callig <function>cs_get()</function>, and before
+     waiting for more input, You should always call
+     <function>cs_more()</function>
+     to check if there's a full protocol package already read. If
+     <function>cs_more()</function>
+     returns 1,
+     <function>cs_get()</function>
+     can be used to immediately fetch the new package. For the
+     mOSI
+     subsystem, the function should always return 0, but if you want your
+     stuff to be protocol independent, you should use it.
+    </para>
+
+    <note>
+     <para>
+      The <function>cs_more()</function>
+      function is required because the RFC1729-method
+      does not provide a way of separating individual PDUs, short of
+      partially decoding the BER. Some other implementations will carefully
+      nibble at the packet by calling
+      <function>read(2)</function>
+      several times. This was felt to be too inefficient (or at least
+      clumsy) - hence the call for this extra function.
+     </para>
+    </note>
+
+    <synopsis>
+     int cs_look(COMSTACK handle);
+    </synopsis>
+
+    <para>
+     This function is useful when you're operating in nonblocking
+     mode. Call it when
+     <function>select(2)</function>
+     tells you there's something happening on the line. It returns one of
+     the following values:
+    </para>
+
+    <variablelist>
+     <varlistentry><term>CS_NONE</term><listitem><para>
+       No event is pending. The data found on the line was not a complete package.
+       </para></listitem></varlistentry>
+
+     <varlistentry><term>CS_CONNECT</term><listitem><para>
+       A response to your connect request has been received. Call
+       <function>cs_rcvconnect</function>
+       to process the event and to finalize the connection establishment.
+       </para></listitem></varlistentry>
+
+     <varlistentry><term>CS_DISCON</term><listitem><para>
+       The other side has closed the connection (or maybe sent a disconnect
+       request - but do we care? Maybe later). Call
+       <function>cs_close</function> to close your end of the association as well.
+       </para></listitem></varlistentry>
+
+     <varlistentry><term>CS_LISTEN</term><listitem><para>
+       A connect request has been received. Call <function>cs_listen</function>
+       to process the event.
+       </para></listitem></varlistentry>
+
+     <varlistentry><term>CS_DATA</term><listitem><para>
+       There's data to be found on the line. Call <function>cs_get</function>
+       to get it.
+       </para></listitem></varlistentry>
+    </variablelist>
+
+    <note>
+     <para>
+      You should be aware that even if
+      <function>cs_look()</function>
+      tells you that there's an event event pending, the corresponding
+      function may still return and tell you there was nothing to be found.
+      This means that only part of a package was available for reading. The
+      same event will show up again, when more data has arrived.
+     </para>
+    </note>
+
+    <synopsis>
+     int cs_fileno(COMSTACK h);
+    </synopsis>
+
+    <para>
+     Returns the file descriptor of the association. Use this when
+     file-level operations on the endpoint are required
+     (<function>select(2)</function> operations, specifically).
+    </para>
+   </sect2>
+
+  </sect1>
+
+  <sect1><title>Client Side</title>
+
+   <synopsis>
+    int cs_connect(COMSTACK handle, void *address);
+   </synopsis>
+
+   <para>
+    Initiate a connection with the target at <literal>address</literal>
+    (more onaddresses below). The function will return 0 on success, and 1 if
+    the operation does not complete immediately (this will only
+    happen on a nonblocking endpoint). In this case, use
+    <function>cs_rcvconnect</function> to complete the operation,
+    when <function>select(2)</function> reports input pending on the
+    association.
+   </para>
+
+   <synopsis>
+    int cs_rcvconnect(COMSTACK handle);
+   </synopsis>
+
+   <para>
+    Complete a connect operation initiated by <function>cs_connect()</function>.
+    It will return 0 on success; 1 if the operation has not yet completed (in
+    this case, call the function again later); -1 if an error has occured.
+   </para>
+
+  </sect1>
+
+  <sect1><title>Server Side</title>
+
+   <para>
+    To establish a server under the <application>inetd</application> server, you
+    can use
+   </para>
+
+   <synopsis>
+    COMSTACK cs_createbysocket(int socket, CS_TYPE type, int blocking,
+    int protocol);
+   </synopsis>
+
+   <para>
+    The <literal>socket</literal> parameter is an established socket (when
+    your application is invoked from <application>inetd</application>, the
+    socket will typically be 0.
+    The following parameters are identical to the ones for
+    <function>cs_create</function>.
+   </para>
+
+   <synopsis>
+    int cs_bind(COMSTACK handle, void *address, int mode)
+   </synopsis>
+
+   <para>
+    Binds a local address to the endpoint. Read about addresses below. The
+    <literal>mode</literal> parameter should be either
+    <literal>CS_CLIENT</literal> or <literal>CS_SERVER</literal>.
+   </para>
+
+   <synopsis>
+    int cs_listen(COMSTACK handle, char *addr, int *addrlen);
+   </synopsis>
+
+   <para>
+    Call this to process incoming events on an endpoint that has been
+    bound in listening mode. It will return 0 to indicate that the connect
+    request has been received, 1 to signal a partial reception, and -1 to
+    indicate an error condition.
+   </para>
+
+   <synopsis>
+    COMSTACK cs_accept(COMSTACK handle);
+   </synopsis>
+
+   <para>
+    This finalises the server-side association establishment, after
+    cs_listen has completed successfully. It returns a new connection
+    endpoint, which represents the new association. The application will
+    typically wish to fork off a process to handle the association at this
+    point, and continue listen for new connections on the old
+    <literal>handle</literal>.
+   </para>
+
+   <para>
+    You can use the call
+   </para>
+
+   <synopsis>
+    char *cs_addrstr(COMSTACK);
+   </synopsis>
+
+   <para>
+    on an established connection to retrieve the hostname of the remote host.
+   </para>
+
+   <note>
+    <para>You may need to use this function with some care if your
+     name server service is slow or unreliable
+    </para>
+   </note>
+
+  </sect1>
+  <sect1><title>Addresses</title>
+
+   <para>
+    The low-level format of the addresses are different depending on the
+    mode of communication you have chosen. A function is provided by each
+    of the lower layers to map a user-friendly string-form address to the
+    binary form required by the lower layers.
+   </para>
+
+   <synopsis>
+    struct sockaddr_in *tcpip_strtoaddr(char *str);
+
+    struct netbuf *mosi_strtoaddr(char *str);
+   </synopsis>
+
+   <para>
+    The format for TCP/IP addresses is straightforward:
+   </para>
+
+   <synopsis>
+    &lt;host> &lsqb; ':' &lt;portnum> &rsqb;
+   </synopsis>
+
+   <para>
+    The <literal>hostname</literal> can be either a domain name or an IP address.
+    The port number, if omitted, defaults to 210.
+   </para>
+
+   <para>
+    For OSI, the format is
+   </para>
+
+   <synopsis>
+    &lsqb; &lt;t-selector> '/' &rsqb; &lt;host> &lsqb; ':' &lt;port> &rsqb;
+   </synopsis>
+
+   <para>
+    The transport selector is given as an even number of hex digits.
+   </para>
+
+   <para>
+    You'll note that the address format for the OSI mode are just a subset
+    of full presentation addresses. We use presentation addresses because
+    xtimosi doesn't, in itself, allow access to the X.500 Directory
+    service. We use a limited form, because we haven't yet come across an
+    implementation that used more of the elements of a full p-address. It
+    is a fairly simple matter to add the rest of the elements to the
+    address format as needed, however: Xtimosi <emphasis>does</emphasis>
+    support the full P-address structure.
+   </para>
+
+   <para>
+    In both transport modes, the special hostname &quot;@&quot; is mapped
+    to any local address (the manifest constant <literal>INADDR_ANY</literal>).
+    It is used to establish local listening endpoints in the server role.
+   </para>
+
+   <para>
+    When a connection has been established, you can use
+   </para>
+
+   <synopsis>
+    char cs_addrstr(COMSTACK h);
+   </synopsis>
+
+   <para>
+    to retrieve the host name of the peer system. The function returns a pointer
+    to a static area, which is overwritten on the next call to the function.
+   </para>
+
+   <note>
+    <para>
+     We have left the issue of X.500 name-to-address mapping open, for the
+     moment. It would be a simple matter to provide a table-based mapping,
+     if desired. Alternately, we could use the X.500 client-function that
+     is provided with the ISODE (although this would defeat some of the
+     purpose of using ThinOSI in the first place. We have been told that it
+     should be within the realm of the possible to implement a lightweight
+     implementation of the necessary X.500 client capabilities on top of
+     ThinOSI. This would be the ideal solution, we feel. On the other hand, it
+     still remains to be seen just what role the Directory will play in a world
+     populated by ThinOSI and other pragmatic solutions.
+    </para>
+   </note>
+
+  </sect1>
+
+  <sect1><title>Diagnostics</title>
+
+   <para>
+    All functions return -1 if an error occurs. Typically, the functions
+    will return 0 on success, but the data exchange functions
+    (<function>cs_get</function>, <function>cs_put</function>,
+    <function>cs_more</function>) follow special rules. Consult their
+    descriptions.
+   </para>
+
+   <para>
+    When a function (including the data exchange functions) reports an
+    error condition, use the function
+    <function>cs_errno()</function> to determine the cause of the
+    problem. The function
+   </para>
+
+   <synopsis>
+    void cs_perror(COMSTACK handle char *message);
+   </synopsis>
+
+   <para>
+    works like <function>perror(2)</function> and prints the
+    <literal>message</literal> argument, along with a system message, to
+    <literal>stderr</literal>. Use the character array
+   </para>
+
+   <synopsis>
+    extern const char *cs_errlist&lsqb;&rsqb;;
+   </synopsis>
+
+   <para>
+    to get hold of the message, if you want to process it differently.
+    The function
+   </para>
+
+   <synopsis>
+    const char *cs_stackerr(COMSTACK handle);
+   </synopsis>
+
+   <para>
+    Returns an error message from the lower layer, if one has been
+    provided.
+   </para>
+  </sect1>
+
+  <sect1><title>Enabling OSI Communication</title>
+
+   <sect2><title>Installing Xtimosi</title>
+    <para>
+     Although you will have to download Peter Furniss' XTI/mOSI
+     implementation for yourself, we've tried to make the integration as
+     simple as possible.
+    </para>
+
+    <para>
+     The latest version of xtimosi will generally be under
+    </para>
+
+    <screen>
+     ftp://pluto.ulcc.ac.uk/ulcc/thinosi/xtimosi/
+    </screen>
+
+    <para>
+     When you have downloaded and unpacked the archive, it will (we assume)
+     have created a directory called <literal>xtimosi</literal>.
+     We suggest that you place this directory <emphasis>in the same
+      directory</emphasis> where you unpacked the &yaz;
+     distribution. This way, you shouldn't have to fiddle with the
+     makefiles of &yaz; beyond uncommenting a few lines.
+    </para>
+
+    <para>
+     Go to <literal>xtimosi/src</literal>, and type &quot;make libmosi.a/&quot;.
+     This should generally create the library, ready to use.
+    </para>
+
+    <note>
+     <para>
+      The currently available release of xtimosi has some inherent
+      problems that make it disfunction on certain platforms - eg. the
+      Digital OSF/1 workstations. It is supposedly primarily a
+      compiler problem, and we hope to see a release that is generally
+      portable. While we can't guarantee that it can be brought to work
+      on your platform, we'll be happy to talk to you about problems
+      that you might see, and relay information to the author of the
+      software. There are some signs that the <application>gcc</application>
+      compiler is more likely to produce a fully functional library, but this
+      hasn't been verified (we think that the problem is limited to the use
+      of hexadecimal escape-codes used in strings, which are silently
+      ignored by some compilers).
+     </para>
+     <para>
+      A problem has been encountered in the communication with
+      ISODE-based applications. If the ISODE presentation-user calls
+      <function>PReadRequest()</function> with a timeout value different
+      from <literal>OK</literal> or <literal>NOTOK</literal>,
+      he will get an immediate TIMEOUT abort when receiving large (&gt;2041
+      bytes, which is the SPDU-size that the ISODE likes to work with) packages
+      from an xtimosi-based implementation (probably most
+      other implementations as well, in fact). It seems to be a flaw in the
+      ISODE API, and the workaround (for ISODE users) is to either not
+      use an explicit timeout (switching to either blocking or
+      nonblocking mode), or to check that the timer really has expired
+      before closing the connection.
+     </para>
+    </note>
+
+    <para>
+     The next step in the installation is to modify the makefile in the toplevel
+     &yaz;
+     directory. The place to change is in the top of the file, and is
+     clearly marked with a comment.
+    </para>
+
+    <para>
+     Now run <literal>make</literal> in the &yaz; toplevel directory (do a
+     <literal>make clean</literal> first, if the system has been previously
+     made without OSI support). Use the &yaz;
+     <application>yaz-ztest</application> and <application>yaz-client</application>
+     demo programs to verify that OSI communication works OK. Then, you can go
+     ahead and try to talk to other implementations.
+    </para>
+
+    <note>
+     <para>
+      Our interoperability experience is limited to version
+      7 of the Nordic SR-Nett package, which has had several
+      protocol errors fixed from the earlier releases. If you have
+      problems or successes in interoperating with other
+      implementations, we'd be glad to hear about it, or to help
+      you make things work, as our resources allow.
+     </para>
+    </note>
+
+    <para>
+     If you write your own applications based on &yaz;, and you wish to
+     include OSI support, the procedure is equally simple. You should
+     include the <filename>xmosi.h</filename> header file in addition to
+     <filename>comstack.h</filename>. <filename>xmosi.h</filename>
+     will define the manifest constant <literal>mosi_type</literal>, which you
+     should pass to the <function>cs_create()</function> function. In
+     addition, you should use the function <function>mosi_strtoaddr()</function>
+     rather than <function>tcpip_strtoaddr()</function> when you need to
+     prepare an address.
+    </para>
+
+    <para>
+     When you link your application, you should include (after the
+     <filename>libyaz.a</filename> library) the <literal>libmosi.a</literal>
+     library, and the <filename>librfc.a</filename> library provided with
+     &yaz; (for OSI transport).
+    </para>
+    <para>
+     As always, it can be very useful, if not essential, to have a look at the
+     example applications to see how things are done.
+    </para>
+
+   </sect2>
+   <sect2><title>OSI Transport</title>
+
+    <para>
+     Xtimosi requires an implementation of the OSI transport service under
+     the X/OPEN XTI API. We provide an implementation of the RFC1006
+     encapsulation of OSI/TP0 in TCP/IP (through the Berkeley Sockets API),
+     as an independent part of &yaz; (it's found under the
+     <filename>rfc1006</filename> directory).
+     If you have access to an OSI transport provider under XTI,
+     you should be able to make that work too, although it may require
+     tinkering with the <function>mosi_strtoaddr()</function> function.
+    </para>
+   </sect2>
+
+   <sect2><title>Presentation Context Management</title>
+
+    <para>
+     To simplify the implementation, we use Peter Furniss' alternative (PRF)
+     option format
+     for the Control of the presentation negotiation phase. This format
+     is enabled by default when you
+     compile xtimosi.
+    </para>
+
+    <para>
+     The current version of &yaz; does <emphasis>not</emphasis> support
+     presentation-layer negotiation of response record formats. The primary
+     reason is that we have had access to no other SR or Z39.50
+     implementations over OSI that used this
+     method. Secondarily, we believe that the EXPLAIN facility is a superior
+     mechanism for relaying target capabilities in this respect. This is not to
+     say that we have no intentions of supporting presentation context
+     negotiation - we have just hitherto given it a lower priority than other
+     aspects of the protocol.
+    </para>
+    <para>
+     One thing is certain: The addition of this capability to &yaz; should
+     have only a minimal impact on existing applications, and on the
+     interface to the software in general. Most likely, we will add an extra
+     layer of interface to the processing of EXPLAIN records, which will
+     convert back and forth between <literal>oident</literal> records (see
+     section <link linkend="oid">Object Identifiers</link>) and direct or
+     indirect references, given the current association setup. Implementations
+     based on any of the higher-level interfaces will most likely not have to
+     be changed at all.
+    </para>
+   </sect2>
+  </sect1>
+  <sect1><title>Summary and Synopsis</title>
+
+     <synopsis>
+    #include &lt;comstack.h>
+     
+    #include &lt;tcpip.h>      /* this is for TCP/IP support   */
+    #include &lt;xmosi.h>      /* and this is for mOSI support */
+     
+    COMSTACK cs_create(CS_TYPE type, int blocking, int protocol);
+     
+    COMSTACK cs_createbysocket(int s, CS_TYPE type, int blocking,
+                               int protocol);
+     
+    int cs_bind(COMSTACK handle, int mode);
+     
+    int cs_connect(COMSTACK handle, void *address);
+     
+    int cs_rcvconnect(COMSTACK handle);
+     
+    int cs_listen(COMSTACK handle);
+
+    COMSTACK cs_accept(COMSTACK handle);
+
+    int cs_put(COMSTACK handle, char *buf, int len);
+
+    int cs_get(COMSTACK handle, char **buf, int *size);
+
+    int cs_more(COMSTACK handle);
+
+    int cs_close(COMSTACK handle);
+
+    int cs_look(COMSTACK handle);
+
+    struct sockaddr_in *tcpip_strtoaddr(char *str);
+
+    struct netbuf *mosi_strtoaddr(char *str);
+
+    extern int cs_errno;
+
+    void cs_perror(COMSTACK handle char *message);
+
+    const char *cs_stackerr(COMSTACK handle);
+
+    extern const char *cs_errlist[];
+   </synopsis>
+  </sect1>
+
+ </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: "yaz.xml"
+ sgml-local-catalogs: "../../docbook/docbook.cat"
+ sgml-namecase-general:t
+ End:
+ -->
 
-</programlisting>
-
-</sect1>
-<sect1><title>Introduction</title>
-
-<para>
-The &comstack;
-subsystem provides a transparent interface to different types of transport
-stacks for the exchange of BER-encoded data. At present, the
-RFC1729 method (BER over TCP/IP), and Peter Furniss' XTImOSI
-stack are supported, but others may be added in time. The philosophy of the
-module is to provide a simple interface by hiding unused options and
-facilities of the underlying libraries. This is always done at the risk
-of losing generality, and it may prove that the interface will need
-extension later on.
-</para>
-
-<para>
-The interface is implemented in such a fashion that only the
-sub-layers constructed to the transport methods that you wish to
-use in your application are linked in.
-</para>
-
-<para>
-You will note that even though simplicity was a goal in the design,
-the interface is still orders of magnitudes more complex than the
-transport systems found in many other packages. One reason is that
-the interface needs to support the somewhat different requirements of
-the different lower-layer communications stacks; another important reason is
-that the interface seeks to provide a more or less industrial-strength
-approach to asynchronous event-handling. When no function is allowed
-to block, things get more complex - particularly on the server
-side. We urge you to have a look at the demonstration client and server
-provided with the package. They are meant to be easily readable and
-instructive, while still being at least moderately useful.
-</para>
-
-</sect1>
-<sect1><title>Common Functions</title>
-
-<sect2><title>Managing Endpoints</title>
-
-<synopsis>
-  COMSTACK cs_create(CS_TYPE type, int blocking, int protocol);
-</synopsis>
-
-<para>
-Creates an instance of the protocol stack - a communications endpoint.
-The <literal>type</literal> parameter determines the mode of communication.
-At present, the values
-<literal>tcpip_type</literal>
-and
-<literal>mosi_type</literal>
-are recognized. The function returns a null-pointer if a system error
-occurs. The <literal>blocking</literal> parameter should be one if you wish
-the association to operate in blocking mode, zero otherwise. The
-<literal>protocol</literal> field should be one of
-<literal>PROTO_SR</literal> or <literal>PROTO_Z3950</literal>.
-</para>
-
-
-<synopsis>
-int cs_close(COMSTACK handle);
-</synopsis>
-
-<para>
-Closes the connection (as elegantly as the lower layers will permit),
-and releases the resouces pointed to by the
-<literal>handle</literal>
-parameter. The
-<literal>handle</literal>
-should not be referenced again after this call.
-</para>
-
-<note>
-<para>
-We really need a soft disconnect, don't we?
-</para>
-</note>
-</sect2>
-
-<sect2><title>Data Exchange</title>
-
-<synopsis>
-  (COMSTACK handle, char *buf, int len);
-</synopsis>
-
-<para>
-Sends
-<literal>buf</literal>
-down the wire. In blocking mode, this function will return only when a
-full buffer has been written, or an error has occurred. In nonblocking
-mode, it's possible that the function will be unable to send the full
-buffer at once, which will be indicated by a return value of 1. The
-function will keep track of the number of octets already written; you
-should call it repeatedly with the same values of <literal>buf</literal>
-and <literal>len</literal>, until the buffer has been transmitted.
-When a full buffer has been sent, the function will return 0 for
-success. -1 indicates an error condition (see below).
-</para>
-
-<synopsis>
-  int cs_get(COMSTACK handle, char **buf, int *size);
-</synopsis>
-
-<para>
-Receives a PDU from the peer. Returns the number of bytes
-read. In nonblocking mode, it is possible that not all of the packet can be
-read at once. In this case, the function returns 1. To simplify the
-interface, the function is
-responsible for managing the size of the buffer. It will be reallocated
-if necessary to contain large packages, and will sometimes be moved
-around internally by the subsystem when partial packages are read. Before
-calling
-<function>cs_get</function>
-for the fist time, the buffer can be initialized to the null pointer,
-and the length should also be set to 0 - cs_get will perform a
-<function>malloc(2)</function>
-on the buffer for you. When a full buffer has been read, the size of
-the package is returned (which will always be greater than 1). -1
-indicates an error condition.
-</para>
-
-<para>
-See also the <function>cs_more()</function> function below.
-</para>
-
-<synopsis>
-  int cs_more(COMSTACK handle);
-</synopsis>
-
-<para>
-The <function>cs_more()</function> function should be used in conjunction
-with <function>cs_get</function> and
-<function>select(2)</function>.
-The <function>cs_get()</function> function will sometimes
-(notably in the TCP/IP mode) read more than a single protocol package
-off the network. When this happens, the extra package is stored
-by the subsystem. After callig <function>cs_get()</function>, and before
-waiting for more input, You should always call
-<function>cs_more()</function>
-to check if there's a full protocol package already read. If
-<function>cs_more()</function>
-returns 1,
-<function>cs_get()</function>
-can be used to immediately fetch the new package. For the
-mOSI
-subsystem, the function should always return 0, but if you want your
-stuff to be protocol independent, you should use it.
-</para>
-
-<note>
-<para>
-The <function>cs_more()</function>
-function is required because the RFC1729-method
-does not provide a way of separating individual PDUs, short of
-partially decoding the BER. Some other implementations will carefully
-nibble at the packet by calling
-<function>read(2)</function>
-several times. This was felt to be too inefficient (or at least
-clumsy) - hence the call for this extra function.
-</para>
-</note>
-
-<synopsis>
-  int cs_look(COMSTACK handle);
-</synopsis>
-
-<para>
-This function is useful when you're operating in nonblocking
-mode. Call it when
-<function>select(2)</function>
-tells you there's something happening on the line. It returns one of
-the following values:
-</para>
-
-<variablelist>
-<varlistentry><term>CS_NONE</term><listitem><para>
-No event is pending. The data found on the line was not a complete package.
-</para></listitem></varlistentry>
-
-<varlistentry><term>CS_CONNECT</term><listitem><para>
-A response to your connect request has been received. Call
-<function>cs_rcvconnect</function>
-to process the event and to finalize the connection establishment.
-</para></listitem></varlistentry>
-
-<varlistentry><term>CS_DISCON</term><listitem><para>
-The other side has closed the connection (or maybe sent a disconnect
-request - but do we care? Maybe later). Call
-<function>cs_close</function> to close your end of the association as well.
-</para></listitem></varlistentry>
-
-<varlistentry><term>CS_LISTEN</term><listitem><para>
-A connect request has been received. Call <function>cs_listen</function>
-to process the event.
-</para></listitem></varlistentry>
-
-<varlistentry><term>CS_DATA</term><listitem><para>
-There's data to be found on the line. Call <function>cs_get</function>
-to get it.
-</para></listitem></varlistentry>
-</variablelist>
-
-<note>
-<para>
-You should be aware that even if
-<function>cs_look()</function>
-tells you that there's an event event pending, the corresponding
-function may still return and tell you there was nothing to be found.
-This means that only part of a package was available for reading. The
-same event will show up again, when more data has arrived.
-</para>
-</note>
-
-<synopsis>
-  int cs_fileno(COMSTACK h);
-</synopsis>
-
-<para>
-Returns the file descriptor of the association. Use this when
-file-level operations on the endpoint are required
-(<function>select(2)</function> operations, specifically).
-</para>
-</sect2>
-
-</sect1>
-
-<sect1><title>Client Side</title>
-
-<synopsis>
-  int cs_connect(COMSTACK handle, void *address);
-</synopsis>
-
-<para>
-Initiate a connection with the target at <literal>address</literal>
-(more onaddresses below). The function will return 0 on success, and 1 if
-the operation does not complete immediately (this will only
-happen on a nonblocking endpoint). In this case, use
-<function>cs_rcvconnect</function> to complete the operation,
-when <function>select(2)</function> reports input pending on the
-association.
-</para>
-
-<synopsis>
-  int cs_rcvconnect(COMSTACK handle);
-</synopsis>
-
-<para>
-Complete a connect operation initiated by <function>cs_connect()</function>.
-It will return 0 on success; 1 if the operation has not yet completed (in
-this case, call the function again later); -1 if an error has occured.
-</para>
-
-</sect1>
-
-<sect1><title>Server Side</title>
-
-<para>
-To establish a server under the <application>inetd</application> server, you
-can use
-</para>
-
-<synopsis>
-  COMSTACK cs_createbysocket(int socket, CS_TYPE type, int blocking,
-                             int protocol);
-</synopsis>
-
-<para>
-The <literal>socket</literal> parameter is an established socket (when
-your application is invoked from <application>inetd</application>, the
-socket will typically be 0.
-The following parameters are identical to the ones for
-<function>cs_create</function>.
-</para>
-
-<synopsis>
-  int cs_bind(COMSTACK handle, void *address, int mode)
-</synopsis>
-
-<para>
-Binds a local address to the endpoint. Read about addresses below. The
-<literal>mode</literal> parameter should be either
-<literal>CS_CLIENT</literal> or <literal>CS_SERVER</literal>.
-</para>
-
-<synopsis>
-  int cs_listen(COMSTACK handle, char *addr, int *addrlen);
-</synopsis>
-
-<para>
-Call this to process incoming events on an endpoint that has been
-bound in listening mode. It will return 0 to indicate that the connect
-request has been received, 1 to signal a partial reception, and -1 to
-indicate an error condition.
-</para>
-
-<synopsis>
-  COMSTACK cs_accept(COMSTACK handle);
-</synopsis>
-
-<para>
-This finalises the server-side association establishment, after
-cs_listen has completed successfully. It returns a new connection
-endpoint, which represents the new association. The application will
-typically wish to fork off a process to handle the association at this
-point, and continue listen for new connections on the old
-<literal>handle</literal>.
-</para>
-
-<para>
-You can use the call
-</para>
-
-<synopsis>
-  char *cs_addrstr(COMSTACK);
-</synopsis>
-
-<para>
-on an established connection to retrieve the hostname of the remote host.
-</para>
-
-<note>
-<para>You may need to use this function with some care if your
-name server service is slow or unreliable
-</para>
-</note>
-
-</sect1>
-<sect1><title>Addresses</title>
-
-<para>
-The low-level format of the addresses are different depending on the
-mode of communication you have chosen. A function is provided by each
-of the lower layers to map a user-friendly string-form address to the
-binary form required by the lower layers.
-</para>
-
-<synopsis>
-  struct sockaddr_in *tcpip_strtoaddr(char *str);
-
-  struct netbuf *mosi_strtoaddr(char *str);
-</synopsis>
-
-<para>
-The format for TCP/IP addresses is straightforward:
-</para>
-
-<synopsis>
-&lt;host> &lsqb; ':' &lt;portnum> &rsqb;
-</synopsis>
-
-<para>
-The <literal>hostname</literal> can be either a domain name or an IP address.
-The port number, if omitted, defaults to 210.
-</para>
-
-<para>
-For OSI, the format is
-</para>
-
-<synopsis>
-&lsqb; &lt;t-selector> '/' &rsqb; &lt;host> &lsqb; ':' &lt;port> &rsqb;
-</synopsis>
-
-<para>
-The transport selector is given as an even number of hex digits.
-</para>
-
-<para>
-You'll note that the address format for the OSI mode are just a subset
-of full presentation addresses. We use presentation addresses because
-xtimosi doesn't, in itself, allow access to the X.500 Directory
-service. We use a limited form, because we haven't yet come across an
-implementation that used more of the elements of a full p-address. It
-is a fairly simple matter to add the rest of the elements to the
-address format as needed, however: Xtimosi <emphasis>does</emphasis>
-support the full P-address structure.
-</para>
-
-<para>
-In both transport modes, the special hostname &quot;@&quot; is mapped
-to any local address (the manifest constant <literal>INADDR_ANY</literal>).
-It is used to establish local listening endpoints in the server role.
-</para>
-
-<para>
-When a connection has been established, you can use
-</para>
-
-<synopsis>
-  char cs_addrstr(COMSTACK h);
-</synopsis>
-
-<para>
-to retrieve the host name of the peer system. The function returns a pointer
-to a static area, which is overwritten on the next call to the function.
-</para>
-
-<note>
-<para>
-We have left the issue of X.500 name-to-address mapping open, for the
-moment. It would be a simple matter to provide a table-based mapping,
-if desired. Alternately, we could use the X.500 client-function that
-is provided with the ISODE (although this would defeat some of the
-purpose of using ThinOSI in the first place. We have been told that it
-should be within the realm of the possible to implement a lightweight
-implementation of the necessary X.500 client capabilities on top of
-ThinOSI. This would be the ideal solution, we feel. On the other hand, it
-still remains to be seen just what role the Directory will play in a world
-populated by ThinOSI and other pragmatic solutions.
-</para>
-</note>
-
-</sect1>
-
-<sect1><title>Diagnostics</title>
-
-<para>
-All functions return -1 if an error occurs. Typically, the functions
-will return 0 on success, but the data exchange functions
-(<function>cs_get</function>, <function>cs_put</function>,
-<function>cs_more</function>) follow special rules. Consult their
-descriptions.
-</para>
-
-<para>
-When a function (including the data exchange functions) reports an
-error condition, use the function
-<function>cs_errno()</function> to determine the cause of the
-problem. The function
-</para>
-
-<synopsis>
-  void cs_perror(COMSTACK handle char *message);
-</synopsis>
-
-<para>
-works like <function>perror(2)</function> and prints the
-<literal>message</literal> argument, along with a system message, to
-<literal>stderr</literal>. Use the character array
-</para>
-
-<synopsis>
-  extern const char *cs_errlist&lsqb;&rsqb;;
-</synopsis>
-
-<para>
-to get hold of the message, if you want to process it differently.
-The function
-</para>
-
-<synopsis>
-  const char *cs_stackerr(COMSTACK handle);
-</synopsis>
-
-<para>
-Returns an error message from the lower layer, if one has been
-provided.
-</para>
-</sect1>
-
-<sect1><title>Enabling OSI Communication</title>
-
-<sect2><title>Installing Xtimosi</title>
-<para>
-Although you will have to download Peter Furniss' XTI/mOSI
-implementation for yourself, we've tried to make the integration as
-simple as possible.
-</para>
-
-<para>
-The latest version of xtimosi will generally be under
-</para>
-
-<screen>
-ftp://pluto.ulcc.ac.uk/ulcc/thinosi/xtimosi/
-</screen>
-
-<para>
-When you have downloaded and unpacked the archive, it will (we assume)
-have created a directory called <literal>xtimosi</literal>.
-We suggest that you place this directory <emphasis>in the same
-directory</emphasis> where you unpacked the &yaz;
-distribution. This way, you shouldn't have to fiddle with the
-makefiles of &yaz; beyond uncommenting a few lines.
-</para>
-
-<para>
-Go to <literal>xtimosi/src</literal>, and type &quot;make libmosi.a/&quot;.
-This should generally create the library, ready to use.
-</para>
-
-<note>
-<para>
-The currently available release of xtimosi has some inherent
-problems that make it disfunction on certain platforms - eg. the
-Digital OSF/1 workstations. It is supposedly primarily a
-compiler problem, and we hope to see a release that is generally
-portable. While we can't guarantee that it can be brought to work
-on your platform, we'll be happy to talk to you about problems
-that you might see, and relay information to the author of the
-software. There are some signs that the <application>gcc</application>
-compiler is more likely to produce a fully functional library, but this
-hasn't been verified (we think that the problem is limited to the use
-of hexadecimal escape-codes used in strings, which are silently
-ignored by some compilers).
-</para>
-<para>
-A problem has been encountered in the communication with
-ISODE-based applications. If the ISODE presentation-user calls
-<function>PReadRequest()</function> with a timeout value different
-from <literal>OK</literal> or <literal>NOTOK</literal>,
-he will get an immediate TIMEOUT abort when receiving large (&gt;2041
-bytes, which is the SPDU-size that the ISODE likes to work with) packages
-from an xtimosi-based implementation (probably most
-other implementations as well, in fact). It seems to be a flaw in the
-ISODE API, and the workaround (for ISODE users) is to either not
-use an explicit timeout (switching to either blocking or
-nonblocking mode), or to check that the timer really has expired
-before closing the connection.
-</para>
-</note>
-
-<para>
-The next step in the installation is to modify the makefile in the toplevel
-&yaz;
-directory. The place to change is in the top of the file, and is
-clearly marked with a comment.
-</para>
-
-<para>
-Now run <literal>make</literal> in the &yaz; toplevel directory (do a
-<literal>make clean</literal> first, if the system has been previously
-made without OSI support). Use the &yaz;
-<application>yaz-ztest</application> and <application>yaz-client</application>
-demo programs to verify that OSI communication works OK. Then, you can go
-ahead and try to talk to other implementations.
-</para>
-
-<note>
-<para>
-Our interoperability experience is limited to version
-7 of the Nordic SR-Nett package, which has had several
-protocol errors fixed from the earlier releases. If you have
-problems or successes in interoperating with other
-implementations, we'd be glad to hear about it, or to help
-you make things work, as our resources allow.
-</para>
-</note>
-
-<para>
-If you write your own applications based on &yaz;, and you wish to
-include OSI support, the procedure is equally simple. You should
-include the <filename>xmosi.h</filename> header file in addition to
-<filename>comstack.h</filename>. <filename>xmosi.h</filename>
-will define the manifest constant <literal>mosi_type</literal>, which you
-should pass to the <function>cs_create()</function> function. In
-addition, you should use the function <function>mosi_strtoaddr()</function>
-rather than <function>tcpip_strtoaddr()</function> when you need to
-prepare an address.
-</para>
-
-<para>
-When you link your application, you should include (after the
-<filename>libyaz.a</filename> library) the <literal>libmosi.a</literal>
-library, and the <filename>librfc.a</filename> library provided with
-&yaz; (for OSI transport).
-</para>
-<para>
-As always, it can be very useful, if not essential, to have a look at the
-example applications to see how things are done.
-</para>
-
-</sect2>
-<sect2><title>OSI Transport</title>
-
-<para>
-Xtimosi requires an implementation of the OSI transport service under
-the X/OPEN XTI API. We provide an implementation of the RFC1006
-encapsulation of OSI/TP0 in TCP/IP (through the Berkeley Sockets API),
-as an independent part of &yaz; (it's found under the
-<filename>rfc1006</filename> directory).
-If you have access to an OSI transport provider under XTI,
-you should be able to make that work too, although it may require
-tinkering with the <function>mosi_strtoaddr()</function> function.
-</para>
-</sect2>
-
-<sect2><title>Presentation Context Management</title>
-
-<para>
-To simplify the implementation, we use Peter Furniss' alternative (PRF)
-option format
-for the Control of the presentation negotiation phase. This format
-is enabled by default when you
-compile xtimosi.
-</para>
-
-<para>
-The current version of &yaz; does <emphasis>not</emphasis> support
-presentation-layer negotiation of response record formats. The primary
-reason is that we have had access to no other SR or Z39.50
-implementations over OSI that used this
-method. Secondarily, we believe that the EXPLAIN facility is a superior
-mechanism for relaying target capabilities in this respect. This is not to
-say that we have no intentions of supporting presentation context
-negotiation - we have just hitherto given it a lower priority than other
-aspects of the protocol.
-</para>
-<para>
-One thing is certain: The addition of this capability to &yaz; should
-have only a minimal impact on existing applications, and on the
-interface to the software in general. Most likely, we will add an extra
-layer of interface to the processing of EXPLAIN records, which will
-convert back and forth between <literal>oident</literal> records (see
-section <link linkend="oid">Object Identifiers</link>) and direct or
-indirect references, given the current association setup. Implementations
-based on any of the higher-level interfaces will most likely not have to
-be changed at all.
-</para>
-</sect2>
-</sect1>
-<sect1><title>Summary and Synopsis</title>
-
-<synopsis>
-#include &lt;comstack.h>
-
-#include &lt;tcpip.h>      /* this is for TCP/IP support   */
-#include &lt;xmosi.h>      /* and this is for mOSI support */
-
-COMSTACK cs_create(CS_TYPE type, int blocking, int protocol);
-
-COMSTACK cs_createbysocket(int s, CS_TYPE type, int blocking,
-                              int protocol);
-
-int cs_bind(COMSTACK handle, int mode);
-
-int cs_connect(COMSTACK handle, void *address);
-
-int cs_rcvconnect(COMSTACK handle);
-
-int cs_listen(COMSTACK handle);
-
-COMSTACK cs_accept(COMSTACK handle);
-
-int cs_put(COMSTACK handle, char *buf, int len);
-
-int cs_get(COMSTACK handle, char **buf, int *size);
-
-int cs_more(COMSTACK handle);
-
-int cs_close(COMSTACK handle);
-
-int cs_look(COMSTACK handle);
-
-struct sockaddr_in *tcpip_strtoaddr(char *str);
-
-struct netbuf *mosi_strtoaddr(char *str);
-
-extern int cs_errno;
-
-void cs_perror(COMSTACK handle char *message);
-
-const char *cs_stackerr(COMSTACK handle);
-
-extern const char *cs_errlist[];
-</synopsis>
-</sect1>
-
-</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:"yaz.xml"
-sgml-default-dtd-file:"yaz.ced"
-sgml-exposed-tags:nil
-sgml-local-catalogs:nil
-sgml-local-ecat-files:nil
-End:
--->
index 61d85af..bc6f978 100644 (file)
-<!-- $Header: /home/cvsroot/yaz/doc/frontend.xml,v 1.2 2001-07-19 12:46:57 adam Exp $ -->
-<chapter><title id="server">Making an IR Server for Your Database</title>
-
-<sect1><title>Introduction</title>
-
-<para>
-If you aren't into documentation, a good way to learn how the
-backend interface works is to look at the <filename>backend.h</filename>
-file. Then, look at the small dummy-server in
-<filename>ztest/ztest.c</filename>. Finally, you can have a look at
-the <filename>seshigh.c</filename> file, which is where most of the
-logic of the frontend server is located. The <filename>backend.h</filename>
-file also makes a good reference, once you've chewed your way through
-the prose of this file.
-</para>
-
-<para>
-If you have a database system that you would like to make available by
-means of Z39.50, &yaz; basically offers your two options. You
-can use the APIs provided by the &asn;, &odr;, and &comstack;
-modules to
-create and decode PDUs, and exchange them with a client.
-Using this low-level interface gives you access to all fields and
-options of the protocol, and you can construct your server as close
-to your existing database as you like.
-It is also a fairly involved process, requiring
-you to set up an event-handling mechanism, protocol state machine,
-etc. To simplify server implementation, we have implemented a compact
-and simple, but reasonably full-functioned server-frontend that will
-handle most of the protocol mechanics, while leaving you to
-concentrate on your database interface.
-</para>
-
-<note>
-<para>
-The backend interface was designed in anticipation of a specific
-integration task, while still attempting to achieve some degree of
-generality. We realise fully that there are points where the
-interface can be improved significantly. If you have specific
-functions or parameters that you think could be useful, send us a
-mail (or better, sign on to the mailing list referred to in the
-toplevel README file). We will try to fit good suggestions into future
-releases, to the extent that it can be done without requiring
-too many structural changes in existing applications.
-</para>
-</note>
-</sect1>
-
-<sect1><title>The Database Frontend</title>
-
-<para>
-We refer to this software as a generic database frontend. Your
-database system is the <emphasis>backend database</emphasis>, and the
-interface between the two is called the <emphasis>backend API</emphasis>.
-The backend API consists of a small number of function handlers and
-structure definitions. You are required to provide the
-<function>main()</function> routine for the server (which can be
-quite simple), as well as a set of handlers to match each of the prototypes.
-The interface functions that you write can use any mechanism you like
-to communicate with your database system: You might link the whole
-thing together with your database application and access it by
-function calls; you might use IPC to talk to a database server
-somewhere; or you might link with third-party software that handles
-the communication for you (like a commercial database client library).
-At any rate, the handlers will perform the tasks of:
-</para>
-
-<itemizedlist>
-
-<listitem><para>
-Initialization.
-</para></listitem>
-
-<listitem><para>
-Searching.
-</para></listitem>
-
-<listitem><para>
-Fetching records.
-</para></listitem>
-
-<listitem><para>
-Scanning the database index (optional - if you wish to implement SCAN).
-</para></listitem>
-
-<listitem><para>
-Extended Services (optional).
-</para></listitem>
-
-<listitem><para>
-Result-Set Delete (optional).
-</para></listitem>
-
-<listitem><para>
-Result-Set Sort (optional).
-</para></listitem>
-
-</itemizedlist>
-
-<para>
-(more functions will be added in time to support as much of
-Z39.50-1995 as possible).
-</para>
-
-</sect1>
-<sect1><title>The Backend API</title>
-
-<para>
-The headers files that you need to use the interface are in the
-<filename>include/yaz</filename> directory. They are called
-<filename>statserv.h</filename> and <filename>backend.h</filename>. They
-will include other files from the <filename>include/yaz</filename>
-directory, so you'll probably want to use the -I option of your
-compiler to tell it where to find the files. When you run
-<literal>make</literal> in the toplevel &yaz; directory,
-everything you need to create your server is put the
-<filename>lib/libyaz.a</filename> library.
-</para>
-</sect1>
-
-<sect1><title>Your main() Routine</title>
-
-<para>
-As mentioned, your <function>main()</function> routine can be quite brief.
-If you want to initialize global parameters, or read global configuration
-tables, this is the place to do it. At the end of the routine, you should
-call the function
-</para>
-
-<synopsis>
-int statserv_main(int argc, char **argv,
-          bend_initresult *(*bend_init)(bend_initrequest *r),
-          void (*bend_close)(void *handle));
-</synopsis>
-
-<para>
-The third and fourth arguments are pointers to handlers. Handler
-<function>bend_init</function> is called whenever the server receives
-an Initialize Request, so it serves as a Z39.50 session initializer. The
-<function>bend_close</function> handler is called when the session is
-closed.
-</para>
-
-<para>
-<function>statserv_main</function> will establish listening sockets
-according to the parameters given. When connection requests are received,
-the event handler will typically <function>fork()</function> and
-create a sub-process to handle a new connection.
-Alternatively the server may be setup to create threads for each connection.
-If you do use global variables and forking, you should be aware, then,
-that these cannot be shared between associations, unless you explicitly
-disable forking by command line parameters. 
-</para>
-
-<para>
-The server provides a mechanism for controlling some of its behavior
-without using command-line options. The function
-</para>
-
-<synopsis>
-statserv_options_block *statserv_getcontrol(void);
-</synopsis>
-
-<para>
-Will return a pointer to a <literal>struct statserv_options_block</literal>
-describing the current default settings of the server. The structure
-contains these elements:
-
-<variablelist>
-<varlistentry><term>int dynamic</term><listitem><para>
-A boolean value, which determines whether the server
-will fork on each incoming request (TRUE), or not (FALSE). Default is
-TRUE. This flag is only read by UNIX-based servers (WIN32 based servers
-doesn't fork).
-</para></listitem></varlistentry>
-
-<varlistentry><term>int threads</term><listitem><para>
-A boolean value, which determines whether the server
-will create a thread on each incoming request (TRUE), or not (FALSE).
-Default is FALSE. This flag is only read by UNIX-based servers that offer
-POSIX Threads support. WIN32-based servers always operate in threaded mode.
-</para></listitem></varlistentry>
-
-<varlistentry><term>int inetd</term><listitem><para>
-A boolean value, which determines whether the server
-will operates under a UNIX INET daemon (inetd). Default is FALSE.
-</para></listitem></varlistentry>
-
-<varlistentry><term>int loglevel</term><listitem><para>
-Set this by ORing the constants defined in
-<filename>include/yaz/yaz-log.h</filename>.
-</para></listitem></varlistentry>
-
-<varlistentry><term>char logfile&lsqb;ODR_MAXNAME+1&rsqb;</term>
-<listitem><para>File for diagnostic output (&quot;&quot;: stderr).
-</para></listitem></varlistentry>
-<varlistentry><term>char apdufile&lsqb;ODR_MAXNAME+1&rsqb;</term>
-<listitem><para>
-Name of file for logging incoming and outgoing APDUs (&quot;&quot;: don't
-log APDUs, &quot;-&quot;: <literal>stderr</literal>).
-</para></listitem></varlistentry>
-
-<varlistentry><term>char default_listen&lsqb;1024&rsqb;</term>
-<listitem><para>Same form as the command-line specification of
-listener address. &quot;&quot;: no default listener address.
-Default is to listen at &quot;tcp:@:9999&quot;. You can only
-specify one default listener address in this fashion.
-</para></listitem></varlistentry>
-
-<varlistentry><term>enum oid_proto default_proto;</term>
-<listitem><para>Either <literal>PROTO_SR</literal> or
-<literal>PROTO_Z3950</literal>. Default is <literal>PROTO_Z39_50</literal>.
-</para></listitem></varlistentry>
-<varlistentry><term>int idle_timeout;</term>
-<listitem><para>Maximum session idletime, in minutes. Zero indicates
-no (infinite) timeout. Default is 120 minutes.
-</para></listitem></varlistentry>
-
-<varlistentry><term>int maxrecordsize;</term>
-<listitem><para>Maximum permissible record (message) size. Default
-is 1Mb. This amount of memory will only be allocated if a client requests a
-very large amount of records in one operation (or a big record). Set it
-to a lower number
-if you are worried about resource consumption on your host system.
-</para></listitem></varlistentry>
-
-<varlistentry><term>char configname&lsqb;ODR_MAXNAME+1&rsqb;</term>
-<listitem><para>Passed to the backend when a new connection is received.
-</para></listitem></varlistentry>
-
-<varlistentry><term>char setuid&lsqb;ODR_MAXNAME+1&rsqb;</term>
-<listitem><para>Set user id to the user specified, after binding
-the listener addresses.
-</para></listitem></varlistentry>
-
-<varlistentry><term>void (*bend_start)(struct statserv_options_block *p)</term>
-<listitem><para>Pointer to function which is called after the command line
-options have been parsed - but before the server starts listening. For
-forked UNIX servers this handler is called in the mother process; for
-threaded servers this handler is called in the main thread. The default
-value of this pointer is NULL in which case it isn't invoked by the frontend
-server. When the server operates as an NT service this handler is called
-whenever the service is started. 
-</para></listitem></varlistentry>
-
-<varlistentry><term>void (*bend_stop)(struct statserv_options_block *p)</term>
-<listitem><para>Pointer to function which is called whenver the server
-has stopped listening for incoming connections. This function pointer
-has a default value of NULL in which case it isn't called.
-When the server operates as an NT service this handler is called
-whenever the service is stopped.
-</para></listitem></varlistentry>
-
-<varlistentry><term>void *handle</term>
-<listitem><para>User defined pointer (default value NULL).
-This is a per-server handle that can be used to specify "user-data".
-Do not confuse this with the session-handle as returned by bend_init.
-</para></listitem></varlistentry>
-
-</variablelist>
-</para>
-
-<para>
-The pointer returned by <literal>statserv_getcontrol</literal> points to
-a static area. You are allowed to change the contents of the structure,
-but the changes will not take effect before you call
-</para>
-
-<synopsis>
-void statserv_setcontrol(statserv_options_block *block);
-</synopsis>
-
-<note>
-<para>
-that you should generally update this structure before calling
-<function>statserv_main()</function>.
-</para>
-</note>
-</sect1>
-
-<sect1><title>The Backend Functions</title>
-
-<para>
-For each service of the protocol, the backend interface declares one or
-two functions. You are required to provide implementations of the
-functions representing the services that you wish to implement.
-</para>
-
-<sect2><title>Init</title>
-
-<synopsis>
-bend_initresult (*bend_init)(bend_initrequest *r);
-</synopsis>
-
-<para>
-This handler is called once for each new connection request, after
-a new process/thread has been created, and an Initialize Request has been
-received from the client. The pointer to the <function>bend_init</function>
-handler is passed in the call to <function>statserv_start</function>.
-</para>
-<para>
-Unlike previous versions of YAZ, the <function>bend_init</function> also
-serves as a handler that defines the Z39.50 services that the backend
-wish to support. Pointers to <emphasis>all</emphasis> service handlers,
-including search - and fetch must be specified here in this handler.
-</para>
-<para>
-The request  - and result structures are defined as
-</para>
-
-<synopsis>
+<!-- $Id: frontend.xml,v 1.3 2001-07-19 23:29:40 adam Exp $ -->
+ <chapter><title id="server">Making an IR Server for Your Database</title>
+
+  <sect1><title>Introduction</title>
+
+   <para>
+    If you aren't into documentation, a good way to learn how the
+    backend interface works is to look at the <filename>backend.h</filename>
+    file. Then, look at the small dummy-server in
+    <filename>ztest/ztest.c</filename>. Finally, you can have a look at
+    the <filename>seshigh.c</filename> file, which is where most of the
+    logic of the frontend server is located. The <filename>backend.h</filename>
+    file also makes a good reference, once you've chewed your way through
+    the prose of this file.
+   </para>
+
+   <para>
+    If you have a database system that you would like to make available by
+    means of Z39.50, &yaz; basically offers your two options. You
+    can use the APIs provided by the &asn;, &odr;, and &comstack;
+    modules to
+    create and decode PDUs, and exchange them with a client.
+    Using this low-level interface gives you access to all fields and
+    options of the protocol, and you can construct your server as close
+    to your existing database as you like.
+    It is also a fairly involved process, requiring
+    you to set up an event-handling mechanism, protocol state machine,
+    etc. To simplify server implementation, we have implemented a compact
+    and simple, but reasonably full-functioned server-frontend that will
+    handle most of the protocol mechanics, while leaving you to
+    concentrate on your database interface.
+   </para>
+
+   <note>
+    <para>
+     The backend interface was designed in anticipation of a specific
+     integration task, while still attempting to achieve some degree of
+     generality. We realise fully that there are points where the
+     interface can be improved significantly. If you have specific
+     functions or parameters that you think could be useful, send us a
+     mail (or better, sign on to the mailing list referred to in the
+     toplevel README file). We will try to fit good suggestions into future
+     releases, to the extent that it can be done without requiring
+     too many structural changes in existing applications.
+    </para>
+   </note>
+  </sect1>
+
+  <sect1><title>The Database Frontend</title>
+
+   <para>
+    We refer to this software as a generic database frontend. Your
+    database system is the <emphasis>backend database</emphasis>, and the
+    interface between the two is called the <emphasis>backend API</emphasis>.
+    The backend API consists of a small number of function handlers and
+    structure definitions. You are required to provide the
+    <function>main()</function> routine for the server (which can be
+    quite simple), as well as a set of handlers to match each of the prototypes.
+    The interface functions that you write can use any mechanism you like
+    to communicate with your database system: You might link the whole
+    thing together with your database application and access it by
+    function calls; you might use IPC to talk to a database server
+    somewhere; or you might link with third-party software that handles
+    the communication for you (like a commercial database client library).
+    At any rate, the handlers will perform the tasks of:
+   </para>
+
+   <itemizedlist>
+
+    <listitem><para>
+      Initialization.
+     </para></listitem>
+
+    <listitem><para>
+      Searching.
+     </para></listitem>
+
+    <listitem><para>
+      Fetching records.
+     </para></listitem>
+
+    <listitem><para>
+      Scanning the database index (optional - if you wish to implement SCAN).
+     </para></listitem>
+
+    <listitem><para>
+      Extended Services (optional).
+     </para></listitem>
+
+    <listitem><para>
+      Result-Set Delete (optional).
+     </para></listitem>
+
+    <listitem><para>
+      Result-Set Sort (optional).
+     </para></listitem>
+
+   </itemizedlist>
+
+   <para>
+    (more functions will be added in time to support as much of
+    Z39.50-1995 as possible).
+   </para>
+
+  </sect1>
+  <sect1><title>The Backend API</title>
+
+   <para>
+    The headers files that you need to use the interface are in the
+    <filename>include/yaz</filename> directory. They are called
+    <filename>statserv.h</filename> and <filename>backend.h</filename>. They
+    will include other files from the <filename>include/yaz</filename>
+    directory, so you'll probably want to use the -I option of your
+    compiler to tell it where to find the files. When you run
+    <literal>make</literal> in the toplevel &yaz; directory,
+    everything you need to create your server is put the
+    <filename>lib/libyaz.a</filename> library.
+   </para>
+  </sect1>
+
+  <sect1><title>Your main() Routine</title>
+
+   <para>
+    As mentioned, your <function>main()</function> routine can be quite brief.
+    If you want to initialize global parameters, or read global configuration
+    tables, this is the place to do it. At the end of the routine, you should
+    call the function
+   </para>
+
+   <synopsis>
+    int statserv_main(int argc, char **argv,
+    bend_initresult *(*bend_init)(bend_initrequest *r),
+    void (*bend_close)(void *handle));
+   </synopsis>
+
+   <para>
+    The third and fourth arguments are pointers to handlers. Handler
+    <function>bend_init</function> is called whenever the server receives
+    an Initialize Request, so it serves as a Z39.50 session initializer. The
+    <function>bend_close</function> handler is called when the session is
+    closed.
+   </para>
+
+   <para>
+    <function>statserv_main</function> will establish listening sockets
+    according to the parameters given. When connection requests are received,
+    the event handler will typically <function>fork()</function> and
+    create a sub-process to handle a new connection.
+    Alternatively the server may be setup to create threads for each connection.
+    If you do use global variables and forking, you should be aware, then,
+    that these cannot be shared between associations, unless you explicitly
+    disable forking by command line parameters. 
+   </para>
+
+   <para>
+    The server provides a mechanism for controlling some of its behavior
+    without using command-line options. The function
+   </para>
+
+   <synopsis>
+    statserv_options_block *statserv_getcontrol(void);
+   </synopsis>
+
+   <para>
+    Will return a pointer to a <literal>struct statserv_options_block</literal>
+    describing the current default settings of the server. The structure
+    contains these elements:
+
+    <variablelist>
+     <varlistentry><term>int dynamic</term><listitem><para>
+       A boolean value, which determines whether the server
+       will fork on each incoming request (TRUE), or not (FALSE). Default is
+       TRUE. This flag is only read by UNIX-based servers (WIN32 based servers
+       doesn't fork).
+       </para></listitem></varlistentry>
+
+     <varlistentry><term>int threads</term><listitem><para>
+       A boolean value, which determines whether the server
+       will create a thread on each incoming request (TRUE), or not (FALSE).
+       Default is FALSE. This flag is only read by UNIX-based servers that offer
+       POSIX Threads support. WIN32-based servers always operate in threaded mode.
+       </para></listitem></varlistentry>
+
+     <varlistentry><term>int inetd</term><listitem><para>
+       A boolean value, which determines whether the server
+       will operates under a UNIX INET daemon (inetd). Default is FALSE.
+       </para></listitem></varlistentry>
+
+     <varlistentry><term>int loglevel</term><listitem><para>
+       Set this by ORing the constants defined in
+       <filename>include/yaz/yaz-log.h</filename>.
+       </para></listitem></varlistentry>
+
+     <varlistentry><term>char logfile&lsqb;ODR_MAXNAME+1&rsqb;</term>
+      <listitem><para>File for diagnostic output (&quot;&quot;: stderr).
+       </para></listitem></varlistentry>
+     <varlistentry><term>char apdufile&lsqb;ODR_MAXNAME+1&rsqb;</term>
+      <listitem><para>
+       Name of file for logging incoming and outgoing APDUs (&quot;&quot;: don't
+       log APDUs, &quot;-&quot;: <literal>stderr</literal>).
+       </para></listitem></varlistentry>
+
+     <varlistentry><term>char default_listen&lsqb;1024&rsqb;</term>
+      <listitem><para>Same form as the command-line specification of
+       listener address. &quot;&quot;: no default listener address.
+       Default is to listen at &quot;tcp:@:9999&quot;. You can only
+       specify one default listener address in this fashion.
+       </para></listitem></varlistentry>
+
+     <varlistentry><term>enum oid_proto default_proto;</term>
+      <listitem><para>Either <literal>PROTO_SR</literal> or
+       <literal>PROTO_Z3950</literal>. Default is <literal>PROTO_Z39_50</literal>.
+       </para></listitem></varlistentry>
+     <varlistentry><term>int idle_timeout;</term>
+      <listitem><para>Maximum session idletime, in minutes. Zero indicates
+       no (infinite) timeout. Default is 120 minutes.
+       </para></listitem></varlistentry>
+
+     <varlistentry><term>int maxrecordsize;</term>
+      <listitem><para>Maximum permissible record (message) size. Default
+       is 1Mb. This amount of memory will only be allocated if a client requests a
+       very large amount of records in one operation (or a big record). Set it
+       to a lower number
+       if you are worried about resource consumption on your host system.
+       </para></listitem></varlistentry>
+
+     <varlistentry><term>char configname&lsqb;ODR_MAXNAME+1&rsqb;</term>
+      <listitem><para>Passed to the backend when a new connection is received.
+       </para></listitem></varlistentry>
+
+     <varlistentry><term>char setuid&lsqb;ODR_MAXNAME+1&rsqb;</term>
+      <listitem><para>Set user id to the user specified, after binding
+       the listener addresses.
+       </para></listitem></varlistentry>
+
+     <varlistentry>
+      <term>void (*bend_start)(struct statserv_options_block *p)</term>
+      <listitem><para>Pointer to function which is called after the
+       command line options have been parsed - but before the server
+       starts listening.
+       For forked UNIX servers this handler is called in the mother
+       process; for threaded servers this handler is called in the
+       main thread.
+       The default value of this pointer is NULL in which case it
+       isn't invoked by the frontend server.
+       When the server operates as an NT service this handler is called
+       whenever the service is started. 
+       </para></listitem></varlistentry>
+
+     <varlistentry>
+      <term>void (*bend_stop)(struct statserv_options_block *p)</term>
+      <listitem><para>Pointer to function which is called whenver the server
+       has stopped listening for incoming connections. This function pointer
+       has a default value of NULL in which case it isn't called.
+       When the server operates as an NT service this handler is called
+       whenever the service is stopped.
+       </para></listitem></varlistentry>
+
+     <varlistentry><term>void *handle</term>
+      <listitem><para>User defined pointer (default value NULL).
+       This is a per-server handle that can be used to specify "user-data".
+       Do not confuse this with the session-handle as returned by bend_init.
+       </para></listitem></varlistentry>
+
+    </variablelist>
+   </para>
+
+   <para>
+    The pointer returned by <literal>statserv_getcontrol</literal> points to
+    a static area. You are allowed to change the contents of the structure,
+    but the changes will not take effect before you call
+   </para>
+
+   <synopsis>
+    void statserv_setcontrol(statserv_options_block *block);
+   </synopsis>
+
+   <note>
+    <para>
+     that you should generally update this structure before calling
+     <function>statserv_main()</function>.
+    </para>
+   </note>
+  </sect1>
+
+  <sect1><title>The Backend Functions</title>
+
+   <para>
+    For each service of the protocol, the backend interface declares one or
+    two functions. You are required to provide implementations of the
+    functions representing the services that you wish to implement.
+   </para>
+
+   <sect2><title>Init</title>
+
+    <synopsis>
+     bend_initresult (*bend_init)(bend_initrequest *r);
+    </synopsis>
+
+    <para>
+     This handler is called once for each new connection request, after
+     a new process/thread has been created, and an Initialize Request has
+     been received from the client. The pointer to the
+     <function>bend_init</function> handler is passed in the call to
+     <function>statserv_start</function>.
+    </para>
+    <para>
+     Unlike previous versions of YAZ, the <function>bend_init</function> also
+     serves as a handler that defines the Z39.50 services that the backend
+     wish to support. Pointers to <emphasis>all</emphasis> service handlers,
+     including search - and fetch must be specified here in this handler.
+    </para>
+    <para>
+     The request  - and result structures are defined as
+    </para>
+
+    <synopsis>
 typedef struct bend_initrequest
 {
     Z_IdAuthentication *auth;
@@ -335,63 +341,63 @@ typedef struct bend_initresult
     char *errstring;   /* system error string or NULL */
     void *handle;      /* private handle to the backend module */
 } bend_initresult;
-</synopsis>
-
-<para>
-In general, the server frontend expects that the
-<literal>bend_*result</literal> pointer that you return is valid at
-least until the next call to a <literal>bend_* function</literal>.
-This applies to all of the functions described herein. The parameter
-structure passed to you in the call belongs to the server frontend, and
-you should not make assumptions about its contents after the current
-function call has completed. In other words, if you want to retain any
-of the contents of a request structure, you should copy them.
-</para>
-
-<para>
-The <literal>errcode</literal> should be zero if the initialization of
-the backend went well. Any other value will be interpreted as an error.
-The <literal>errstring</literal> isn't used in the current version, but one
-optin would be to stick it in the initResponse as a VisibleString.
-The <literal>handle</literal> is the most important parameter. It should
-be set to some value that uniquely identifies the current session to
-the backend implementation. It is used by the frontend server in any
-future calls to a backend function.
-The typical use is to set it to point to a dynamically allocated state
-structure that is private to your backend module.
-</para>
-
-<para>
-The <literal>auth</literal> member holds the authentication information
-part of the Z39.50 Initialize Request. Interpret this if your serves
-requires authentication. 
-</para>
-
-<para>
-The members <literal>peer_name</literal>,
-<literal>implementation_name</literal> and
-<literal>implementation_version</literal> holds DNS of client, name
-of client (Z39.50) implementation - and version.
-</para>
-
-<para>
-The <literal>bend_</literal> - members are set to NULL when
-<function>bend_init</function> is called. Modify the pointers by setting them
-to point to backend functions.
-</para>
-
-</sect2>
-
-<sect2><title>Search and retrieve</title>
-
-<para>We now describe the handlers that are required to support search -
-and retrieve. You must support two functions - one for seearch - and one
-for fetch (retrieval of one record). If desirable you can provide a
-third handler which is called when a present request is received which
-allows you to optimize retrieval of multiple-records.
-</para>
-
-<synopsis>
+    </synopsis>
+
+    <para>
+     In general, the server frontend expects that the
+     <literal>bend_*result</literal> pointer that you return is valid at
+     least until the next call to a <literal>bend_* function</literal>.
+     This applies to all of the functions described herein. The parameter
+     structure passed to you in the call belongs to the server frontend, and
+     you should not make assumptions about its contents after the current
+     function call has completed. In other words, if you want to retain any
+     of the contents of a request structure, you should copy them.
+    </para>
+
+    <para>
+     The <literal>errcode</literal> should be zero if the initialization of
+     the backend went well. Any other value will be interpreted as an error.
+     The <literal>errstring</literal> isn't used in the current version, but
+     one option would be to stick it in the initResponse as a VisibleString.
+     The <literal>handle</literal> is the most important parameter. It should
+     be set to some value that uniquely identifies the current session to
+     the backend implementation. It is used by the frontend server in any
+     future calls to a backend function.
+     The typical use is to set it to point to a dynamically allocated state
+     structure that is private to your backend module.
+    </para>
+
+    <para>
+     The <literal>auth</literal> member holds the authentication information
+     part of the Z39.50 Initialize Request. Interpret this if your serves
+     requires authentication. 
+    </para>
+
+    <para>
+     The members <literal>peer_name</literal>,
+     <literal>implementation_name</literal> and
+     <literal>implementation_version</literal> holds DNS of client, name
+     of client (Z39.50) implementation - and version.
+    </para>
+
+    <para>
+     The <literal>bend_</literal> - members are set to NULL when
+     <function>bend_init</function> is called. Modify the pointers by
+     setting them to point to backend functions.
+    </para>
+
+   </sect2>
+
+   <sect2><title>Search and retrieve</title>
+
+    <para>We now describe the handlers that are required to support search -
+     and retrieve. You must support two functions - one for seearch - and one
+     for fetch (retrieval of one record). If desirable you can provide a
+     third handler which is called when a present request is received which
+     allows you to optimize retrieval of multiple-records.
+    </para>
+
+    <synopsis>
 int (*bend_search) (void *handle, bend_search_rr *rr);
 
 typedef struct {
@@ -413,43 +419,43 @@ typedef struct {
     char *errstring;           /* system error string or NULL */
 } bend_search_rr;
 
-</synopsis>
-
-<para>
-The <function>bend_search</function> handler is a fairly close
-approximation of a protocol Search Request - and Response PDUs
-The <literal>setname</literal> is the resultSetName from the protocol.
-You are required to establish a mapping between the set name and whatever
-your backend database likes to use.
-Similarly, the <literal>replace_set</literal> is a boolean value
-corresponding to the resultSetIndicator field in the protocol.
-<literal>num_bases/basenames</literal> is a length of/array of character
-pointers to the database names provided by the client.
-The <literal>query</literal> is the full query structure as defined in the
-protocol ASN.1 specification.
-It can be either of the possible query types, and it's up to you to
-determine if you can handle the provided query type.
-Rather than reproduce the C interface here, we'll refer you to the
-structure definitions in the file
-<filename>include/yaz/z-core.h</filename>. If you want to look at the
-attributeSetId OID of the RPN query, you can either match it against
-your own internal tables, or you can use the
-<literal>oid_getentbyoid</literal> function provided by &yaz;.
-</para>
-
-<para>
-The structure contains a number of hits, and an
-<literal>errcode/errstring</literal> pair. If an error occurs
-during the search, or if you're unhappy with the request, you should
-set the errcode to a value from the BIB-1 diagnostic set. The value
-will then be returned to the user in a nonsurrogate diagnostic record
-in the response. The <literal>errstring</literal>, if provided, will
-go in the addinfo field. Look at the protocol definition for the
-defined error codes, and the suggested uses of the addinfo field.
-</para>
-
-
-<synopsis>
+    </synopsis>
+
+    <para>
+     The <function>bend_search</function> handler is a fairly close
+     approximation of a protocol Search Request - and Response PDUs
+     The <literal>setname</literal> is the resultSetName from the protocol.
+     You are required to establish a mapping between the set name and whatever
+     your backend database likes to use.
+     Similarly, the <literal>replace_set</literal> is a boolean value
+     corresponding to the resultSetIndicator field in the protocol.
+     <literal>num_bases/basenames</literal> is a length of/array of character
+     pointers to the database names provided by the client.
+     The <literal>query</literal> is the full query structure as defined in the
+     protocol ASN.1 specification.
+     It can be either of the possible query types, and it's up to you to
+     determine if you can handle the provided query type.
+     Rather than reproduce the C interface here, we'll refer you to the
+     structure definitions in the file
+     <filename>include/yaz/z-core.h</filename>. If you want to look at the
+     attributeSetId OID of the RPN query, you can either match it against
+     your own internal tables, or you can use the
+     <literal>oid_getentbyoid</literal> function provided by &yaz;.
+    </para>
+
+    <para>
+     The structure contains a number of hits, and an
+     <literal>errcode/errstring</literal> pair. If an error occurs
+     during the search, or if you're unhappy with the request, you should
+     set the errcode to a value from the BIB-1 diagnostic set. The value
+     will then be returned to the user in a nonsurrogate diagnostic record
+     in the response. The <literal>errstring</literal>, if provided, will
+     go in the addinfo field. Look at the protocol definition for the
+     defined error codes, and the suggested uses of the addinfo field.
+    </para>
+
+
+    <synopsis>
 int (*bend_fetch) (void *handle, bend_fetch_rr *rr);
 
 typedef struct bend_fetch_rr {
@@ -472,67 +478,71 @@ typedef struct bend_fetch_rr {
     char *errstring;           /* system error string or NULL */
     int surrogate_flag;        /* surrogate diagnostic */
 } bend_fetch_rr;
-</synopsis>
-
-<para>
-The frontend server calls the <function>bend_fetch</function> handler when
-it needs database records to fulfill a Search Request or a Present Request.
-The <literal>setname</literal> is simply the name of the result set
-that holds the reference to the desired record.
-The <literal>number</literal> is the offset into the set (with 1
-being the first record in the set). The <literal>format</literal> field
-is the record format requested by the client (See section
-<link linkend="oid">Object Identifiers</link>). The value
-<literal>VAL_NONE</literal> indicates that the client did not
-request a specific format. The <literal>stream</literal> argument
-is an &odr; stream which should be used for
-allocating space for structured data records. The stream will be reset when
-all records have been assembled, and the response package has been transmitted.
-For unstructured data, the backend is responsible for maintaining a static
-or dynamic buffer for the record between calls.
-</para>
-
-<para>
-In the structure, the <literal>basename</literal> is the name of the
-database that holds the
-record. <literal>len</literal> is the length of the record returned, in
-bytes, and <literal>record</literal> is a pointer to the record.
-<literal>Last_in_set</literal> should be nonzero only if the record
-returned is the last one in the given result set. <literal>errcode</literal>
-and <literal>errstring</literal>, if given, will be
-interpreted as a global error pertaining to the set, and will be returned
-in a non-surrogate-diagnostic. If you wish to return the error as a
-surrogate-diagnostic (local error) you can do this by setting
-<literal>surrogate_flag</literal> to 1 also.
-</para>
-
-<para>
-If the <literal>len</literal> field has the value -1, then
-<literal>record</literal> is assumed to point to a constructed data
-type. The <literal>format</literal> field will be used to determine
-which encoder should be used to serialize the data.
-</para>
-
-<note>
-<para>
-If your backend generates structured records, it should use
-<function>odr_malloc()</function> on the provided stream for allocating
-data: This allows the frontend server to keep track of the record sizes.
-</para>
-</note>
-
-<para>
-The <literal>format</literal> field is mapped to an object identifier
-in the direct reference of the resulting EXTERNAL representation of the record.
-</para>
-
-<note>
-<para>
-The current version of &yaz; only supports the direct reference mode.
-</para>
-</note>
-
-<synopsis>
+    </synopsis>
+
+    <para>
+     The frontend server calls the <function>bend_fetch</function> handler
+     when it needs database records to fulfill a Search Request or a Present
+     Request.
+     The <literal>setname</literal> is simply the name of the result set
+     that holds the reference to the desired record.
+     The <literal>number</literal> is the offset into the set (with 1
+     being the first record in the set). The <literal>format</literal> field
+     is the record format requested by the client (See section
+     <link linkend="oid">Object Identifiers</link>). The value
+     <literal>VAL_NONE</literal> indicates that the client did not
+     request a specific format. The <literal>stream</literal> argument
+     is an &odr; stream which should be used for
+     allocating space for structured data records.
+     The stream will be reset when all records have been assembled, and
+     the response package has been transmitted.
+     For unstructured data, the backend is responsible for maintaining a static
+     or dynamic buffer for the record between calls.
+    </para>
+
+    <para>
+     In the structure, the <literal>basename</literal> is the name of the
+     database that holds the
+     record. <literal>len</literal> is the length of the record returned, in
+     bytes, and <literal>record</literal> is a pointer to the record.
+     <literal>Last_in_set</literal> should be nonzero only if the record
+     returned is the last one in the given result set.
+     <literal>errcode</literal> and <literal>errstring</literal>, if
+     given, will be interpreted as a global error pertaining to the
+     set, and will be returned in a non-surrogate-diagnostic.
+     If you wish to return the error as a surrogate-diagnostic
+     (local error) you can do this by setting
+     <literal>surrogate_flag</literal> to 1 also.
+    </para>
+
+    <para>
+     If the <literal>len</literal> field has the value -1, then
+     <literal>record</literal> is assumed to point to a constructed data
+     type. The <literal>format</literal> field will be used to determine
+     which encoder should be used to serialize the data.
+    </para>
+
+    <note>
+     <para>
+      If your backend generates structured records, it should use
+      <function>odr_malloc()</function> on the provided stream for allocating
+      data: This allows the frontend server to keep track of the record sizes.
+     </para>
+    </note>
+
+    <para>
+     The <literal>format</literal> field is mapped to an object identifier
+     in the direct reference of the resulting EXTERNAL representation
+     of the record.
+    </para>
+
+    <note>
+     <para>
+      The current version of &yaz; only supports the direct reference mode.
+     </para>
+    </note>
+
+    <synopsis>
 int (*bend_present) (void *handle, bend_present_rr *rr);
 
 typedef struct {
@@ -551,33 +561,33 @@ typedef struct {
     int errcode;               /* 0==OK */
     char *errstring;           /* system error string or NULL */
 } bend_present_rr;
-</synopsis>
-
-<para>
-The <function>bend_present</function> handler is called when
-the server receives a Present Request. The <literal>setname</literal>,
-<literal>start</literal> and <literal>number</literal> is the
-name of the result set - start position - and number of records to
-be retrieved respectively. <literal>format</literal> and
-<literal>comp</literal> is the preferred transfer syntax and element
-specifications of the present request.
-</para>
-<para>
-Note that this is handler serves as a supplement for
-<function>bend_fetch</function> and need not to be defined in order to
-support search - and retrieve. 
-</para>
-
-</sect2>
-
-<sect2><title>Delete</title>
-
-<para>
-For backends that supports delete of a result set only one handler
-must be defined.
-</para>
-
-<synopsis>
+    </synopsis>
+
+    <para>
+     The <function>bend_present</function> handler is called when
+     the server receives a Present Request. The <literal>setname</literal>,
+     <literal>start</literal> and <literal>number</literal> is the
+     name of the result set - start position - and number of records to
+     be retrieved respectively. <literal>format</literal> and
+     <literal>comp</literal> is the preferred transfer syntax and element
+     specifications of the present request.
+    </para>
+    <para>
+     Note that this is handler serves as a supplement for
+     <function>bend_fetch</function> and need not to be defined in order to
+     support search - and retrieve. 
+    </para>
+
+   </sect2>
+
+   <sect2><title>Delete</title>
+
+    <para>
+     For backends that supports delete of a result set only one handler
+     must be defined.
+    </para>
+
+    <synopsis>
 int (*bend_delete)(void *handle, bend_delete_rr *rr);
 
 typedef struct bend_delete_rr {
@@ -590,28 +600,28 @@ typedef struct bend_delete_rr {
     ODR stream;
     ODR print; 
 } bend_delete_rr;
-</synopsis>
+    </synopsis>
 
-<note>
-<para>
-The delete set function definition is rather primitive, mostly because we
-have had no practical need for it as of yet. If someone wants
-to provide a full delete service, we'd be happy to add the
-extra parameters that are required. Are there clients out there
-that will actually delete sets they no longer need?
-</para>
-</note>
+    <note>
+     <para>
+      The delete set function definition is rather primitive, mostly because we
+      have had no practical need for it as of yet. If someone wants
+      to provide a full delete service, we'd be happy to add the
+      extra parameters that are required. Are there clients out there
+      that will actually delete sets they no longer need?
+     </para>
+    </note>
 
-</sect2>
+   </sect2>
 
-<sect2><title>scan</title>
+   <sect2><title>scan</title>
 
-<para>
-For servers that wish to offer the scan service one handler
-must be defined.
-</para>
+    <para>
+     For servers that wish to offer the scan service one handler
+     must be defined.
+    </para>
 
-<synopsis>
+    <synopsis>
 int (*bend_delete)(void *handle, bend_delete_rr *rr);
 
 typedef enum {
@@ -637,172 +647,188 @@ typedef struct bend_scan_rr {
     int errcode;
     char *errstring;
 } bend_scan_rr;
-</synopsis>
-</sect2>
-</sect1>
-
-<sect1><title>Application Invocation</title>
-
-<para>
-The finished application has the following
-invocation syntax (by way of <function>statserv_main()</function>):
-</para>
-
-<synopsis>
-<replaceable>appname</replaceable> &lsqb;-szSiTu -a <replaceable>apdufile</replaceable> -l <replaceable>logfile</replaceable> -v <replaceable>loglevel</replaceable> -c <replaceable>config</replaceable>&rsqb;
-&lsqb;listener ...&rsqb;
-</synopsis>
-
-<para>
-The options are
-
-<variablelist>
-
-<varlistentry><term>-a <replaceable>file</replaceable></term>
- <listitem><para>
-Specify a file for dumping PDUs (for diagnostic purposes).
-The special name &quot;-&quot; sends output to <literal>stderr</literal>.
-</para></listitem></varlistentry>
-
-<varlistentry><term>-S</term>
- <listitem><para>
-Don't fork or make threads on connection requests. This is good for
-debugging, but not recommended for real operation: Although the server is
-asynchronous and non-blocking, it can be nice to keep a software
-malfunction (okay then, a crash) from affecting all current users.
-</para></listitem></varlistentry>
-
-<varlistentry><term>-T</term>
-<listitem><para>
-Operate the server in threaded mode. The server creates a thread
-for each connection rather than a fork a process. Only available
-on UNIX systems that offers POSIX threads.
-</para></listitem></varlistentry>
-
-<varlistentry><term>-s</term>
-<listitem><para>
-Use the SR protocol (obsolete).
-</para></listitem></varlistentry>
-
-<varlistentry><term>-z</term>
-<listitem><para>
-Use the Z39.50 protocol (default). These two options complement
-each other. You can use both multiple times on the same command
-line, between listener-specifications (see below). This way, you
-can set up the server to listen for connections in both protocols
-concurrently, on different local ports.
-</para></listitem></varlistentry>
-
-<varlistentry><term>-l <replaceable>file</replaceable></term>
-<listitem><para>The logfile.
-</para></listitem></varlistentry>
-
-<varlistentry><term>-c <replaceable>config</replaceable></term>
-<listitem><para>A user option that serves as a specifier for some
-sort of configuration, e.g. a filename.
-The argument to this option is transferred to member
-<literal>configname</literal>of the <literal>statserv_options_block</literal>.
-</para></listitem></varlistentry>
-
-<varlistentry><term>-v <replaceable>level</replaceable></term>
-<listitem><para>
-The log level. Use a comma-separated list of members of the set
-{fatal,debug,warn,log,all,none}.
-</para></listitem></varlistentry>
-
-<varlistentry><term>-u <replaceable>userid</replaceable></term>
-<listitem><para>
-Set user ID. Sets the real UID of the server process to that of the
-given user. It's useful if you aren't comfortable with having the
-server run as root, but you need to start it as such to bind a
-privileged port.
-</para></listitem></varlistentry>
-
-<varlistentry><term>-w <replaceable>dir</replaceable></term>
-<listitem><para>
-Working directory.
-</para></listitem></varlistentry>
-
-<varlistentry><term>-i</term>
-<listitem><para>
-Use this when running from the <application>inetd</application> server.
-</para></listitem></varlistentry>
-
-<varlistentry><term>-t <replaceable>minutes</replaceable></term>
-<listitem><para>
-Idle session timeout, in minutes.
-</para></listitem></varlistentry>
-
-<varlistentry><term>-k <replaceable>size</replaceable></term>
-<listitem><para>
-Maximum record size/message size, in kilobytes.
-</para></listitem></varlistentry>
-
-
-</variablelist>
-</para>
-
-<para>
-A listener specification consists of a transport mode followed by a
-colon (:) followed by a listener address. The transport mode is
-either <literal>osi</literal> or <literal>tcp</literal>.
-</para>
-
-<para>
-For TCP, an address has the form
-</para>
-
-<synopsis>
-  hostname | IP-number &lsqb;: portnumber&rsqb;
-</synopsis>
-
-<para>
-The port number defaults to 210 (standard Z39.50 port).
-</para>
-
-<para>
-For osi, the address form is
-</para>
-
-<synopsis>
-  &lsqb;t-selector /&rsqb; hostname | IP-number &lsqb;: portnumber&rsqb;
-</synopsis>
-
-<para>
-The transport selector is given as a string of hex digits (with an even
-number of digits). The default port number is 102 (RFC1006 port).
-</para>
-
-<para>
-Examples
-</para>
-
-<screen>
-  tcp:dranet.dra.com
-
-  osi:0402/dbserver.osiworld.com:3000
-</screen>
-
-<para>
-In both cases, the special hostname &quot;@&quot; is mapped to
-the address INADDR_ANY, which causes the server to listen on any local
-interface. To start the server listening on the registered ports for
-Z39.50 and SR over OSI/RFC1006, and to drop root privileges once the
-ports are bound, execute the server like this (from a root shell):
-</para>
-
-<screen>
-  my-server -u daemon tcp:@ -s osi:@
-</screen>
-
-<para>
-You can replace <literal>daemon</literal> with another user, eg. your
-own account, or a dedicated IR server account.
-<literal>my-server</literal> should be the name of your
-server application. You can test the procedure with the
-<application>yaz-ztest</application> application.
-</para>
-
-</sect1>
-</chapter>
-
+    </synopsis>
+   </sect2>
+  </sect1>
+
+  <sect1><title>Application Invocation</title>
+
+   <para>
+    The finished application has the following
+    invocation syntax (by way of <function>statserv_main()</function>):
+   </para>
+
+   <synopsis>
+    <replaceable>appname</replaceable> &lsqb;-szSiTu -a <replaceable>apdufile</replaceable> -l <replaceable>logfile</replaceable> -v <replaceable>loglevel</replaceable> -c <replaceable>config</replaceable>&rsqb;
+    &lsqb;listener ...&rsqb;
+   </synopsis>
+
+   <para>
+    The options are
+
+    <variablelist>
+
+     <varlistentry><term>-a <replaceable>file</replaceable></term>
+      <listitem><para>
+       Specify a file for dumping PDUs (for diagnostic purposes).
+       The special name &quot;-&quot; sends output to
+       <literal>stderr</literal>.
+       </para></listitem></varlistentry>
+
+     <varlistentry><term>-S</term>
+      <listitem><para>
+       Don't fork or make threads on connection requests. This is good for
+       debugging, but not recommended for real operation: Although the
+       server is asynchronous and non-blocking, it can be nice to keep
+       a software malfunction (okay then, a crash) from affecting all
+       current users.
+       </para></listitem></varlistentry>
+
+     <varlistentry><term>-T</term>
+      <listitem><para>
+       Operate the server in threaded mode. The server creates a thread
+       for each connection rather than a fork a process. Only available
+       on UNIX systems that offers POSIX threads.
+       </para></listitem></varlistentry>
+
+     <varlistentry><term>-s</term>
+      <listitem><para>
+       Use the SR protocol (obsolete).
+       </para></listitem></varlistentry>
+
+     <varlistentry><term>-z</term>
+      <listitem><para>
+       Use the Z39.50 protocol (default). These two options complement
+       each other. You can use both multiple times on the same command
+       line, between listener-specifications (see below). This way, you
+       can set up the server to listen for connections in both protocols
+       concurrently, on different local ports.
+       </para></listitem></varlistentry>
+
+     <varlistentry><term>-l <replaceable>file</replaceable></term>
+      <listitem><para>The logfile.
+       </para></listitem></varlistentry>
+
+     <varlistentry><term>-c <replaceable>config</replaceable></term>
+      <listitem><para>A user option that serves as a specifier for some
+       sort of configuration, e.g. a filename.
+       The argument to this option is transferred to member
+       <literal>configname</literal>of the
+       <literal>statserv_options_block</literal>.
+       </para></listitem></varlistentry>
+
+     <varlistentry><term>-v <replaceable>level</replaceable></term>
+      <listitem><para>
+       The log level. Use a comma-separated list of members of the set
+       {fatal,debug,warn,log,all,none}.
+       </para></listitem></varlistentry>
+
+     <varlistentry><term>-u <replaceable>userid</replaceable></term>
+      <listitem><para>
+       Set user ID. Sets the real UID of the server process to that of the
+       given user. It's useful if you aren't comfortable with having the
+       server run as root, but you need to start it as such to bind a
+       privileged port.
+       </para></listitem></varlistentry>
+
+     <varlistentry><term>-w <replaceable>dir</replaceable></term>
+      <listitem><para>
+       Working directory.
+       </para></listitem></varlistentry>
+
+     <varlistentry><term>-i</term>
+      <listitem><para>
+       Use this when running from the <application>inetd</application> server.
+       </para></listitem></varlistentry>
+
+     <varlistentry><term>-t <replaceable>minutes</replaceable></term>
+      <listitem><para>
+       Idle session timeout, in minutes.
+       </para></listitem></varlistentry>
+
+     <varlistentry><term>-k <replaceable>size</replaceable></term>
+      <listitem><para>
+       Maximum record size/message size, in kilobytes.
+       </para></listitem></varlistentry>
+
+    </variablelist>
+   </para>
+
+   <para>
+    A listener specification consists of a transport mode followed by a
+    colon (:) followed by a listener address. The transport mode is
+    either <literal>osi</literal> or <literal>tcp</literal>.
+   </para>
+
+   <para>
+    For TCP, an address has the form
+   </para>
+
+   <synopsis>
+    hostname | IP-number &lsqb;: portnumber&rsqb;
+   </synopsis>
+
+   <para>
+    The port number defaults to 210 (standard Z39.50 port).
+   </para>
+
+   <para>
+    For osi, the address form is
+   </para>
+
+   <synopsis>
+    &lsqb;t-selector /&rsqb; hostname | IP-number &lsqb;: portnumber&rsqb;
+   </synopsis>
+
+   <para>
+    The transport selector is given as a string of hex digits (with an even
+    number of digits). The default port number is 102 (RFC1006 port).
+   </para>
+
+   <para>
+    Examples
+   </para>
+
+   <screen>
+    tcp:dranet.dra.com
+
+    osi:0402/dbserver.osiworld.com:3000
+   </screen>
+
+   <para>
+    In both cases, the special hostname &quot;@&quot; is mapped to
+    the address INADDR_ANY, which causes the server to listen on any local
+    interface. To start the server listening on the registered ports for
+    Z39.50 and SR over OSI/RFC1006, and to drop root privileges once the
+    ports are bound, execute the server like this (from a root shell):
+   </para>
+
+   <screen>
+    my-server -u daemon tcp:@ -s osi:@
+   </screen>
+
+   <para>
+    You can replace <literal>daemon</literal> with another user, eg. your
+    own account, or a dedicated IR server account.
+    <literal>my-server</literal> should be the name of your
+    server application. You can test the procedure with the
+    <application>yaz-ztest</application> application.
+   </para>
+
+  </sect1>
+ </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: "yaz.xml"
+ sgml-local-catalogs: "../../docbook/docbook.cat"
+ sgml-namecase-general:t
+ End:
+ -->
index c40a3c1..391f35e 100644 (file)
@@ -1,31 +1,46 @@
-<!-- $Header: /home/cvsroot/yaz/doc/future.xml,v 1.1 2001-01-04 13:36:24 adam Exp $ -->
-<chapter><title>Future Directions</title>
+<!-- $Id: future.xml,v 1.2 2001-07-19 23:29:40 adam Exp $ -->
+ <chapter><title>Future Directions</title>
 
-<para>
-We have a new and better version of the frontend server on the drawing
-board. Resources and external commitments will govern when we'll be
-able to do something real with it. Fetures should include greater
-flexibility, greter support for access/resource control, and easy
-support for Explain (possibly with Zebra as an extra database engine).
-</para>
+  <para>
+   We have a new and better version of the frontend server on the drawing
+   board. Resources and external commitments will govern when we'll be
+   able to do something real with it. Fetures should include greater
+   flexibility, greter support for access/resource control, and easy
+   support for Explain (possibly with Zebra as an extra database engine).
+  </para>
 
-<para>
-We now support all PDUs of Z39.50-1995. If there is one of the
-supporting structures that you need but can't find in the prt*.h
-files, send us a note; it may be on its way.
-</para>
+  <para>
+   We now support all PDUs of Z39.50-1995. If there is one of the
+   supporting structures that you need but can't find in the prt*.h
+   files, send us a note; it may be on its way.
+  </para>
 
-<para>
-The 'retrieval' module needs to be finalized and documented. We think
-it can form a useful resource for people dealing with complex record
-structures, but for now, you'll mostly have to chew through the code
-yourself to make use of it. Not acceptable.
-</para>
+  <para>
+   The 'retrieval' module needs to be finalized and documented. We think
+   it can form a useful resource for people dealing with complex record
+   structures, but for now, you'll mostly have to chew through the code
+   yourself to make use of it. Not acceptable.
+  </para>
 
-<para>
-Other than that, YAZ generally moves in the directions which appear to
-make the most people happy (including ourselves, as prime users of the
-software). If there's something you'd like to see in here, then drop
-us a note and let's see what we can come up with.
-</para>
-</chapter>
\ No newline at end of file
+  <para>
+   Other than that, YAZ generally moves in the directions which appear to
+   make the most people happy (including ourselves, as prime users of the
+   software). If there's something you'd like to see in here, then drop
+   us a note and let's see what we can come up with.
+  </para>
+ </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: "yaz.xml"
+ sgml-local-catalogs: "../../docbook/docbook.cat"
+ sgml-namecase-general:t
+ End:
+ -->
index 7095474..29fd69b 100644 (file)
@@ -1,49 +1,63 @@
-<!-- $Header: /home/cvsroot/yaz/doc/indexdata.xml,v 1.1 2001-01-04 13:36:24 adam Exp $ -->
-<appendix><title>About Index Data</title>
+<!-- $Id: indexdata.xml,v 1.2 2001-07-19 23:29:40 adam Exp $ -->
+ <appendix><title>About Index Data</title>
 
-<para>
-Index Data is a consulting and software-development enterprise that
-specialises in library and information management systems. Our
-interests and expertise span a broad range of related fields, and one
-of our primary, long-term objectives is the development of a powerful
-information management
-system with open network interfaces and hypermedia capabilities.
-</para><para>
-We make this software available free of charge, on a fairly unrestrictive
-license; as a service to the networking community, and to further the
-development of quality software for open network communication.
-</para><para>
-We'll be happy to answer questions about the software, and about ourselves
-in general.
-</para>
-<para>
-<address>
-Index Data Aps
-<street>K&oslash;bmagergade 43</street>
-<postcode>1150 Copenhagen K</postcode>
-<country>Denmark</country>
-Phone <phone>+45 3341 0100</phone>
-Fax <fax>+45 3341 0101</fax>
-Email <email>info@indexdata.dk</email>
-</address>
+  <para>
+   Index Data is a consulting and software-development enterprise that
+   specialises in library and information management systems. Our
+   interests and expertise span a broad range of related fields, and one
+   of our primary, long-term objectives is the development of a powerful
+   information management
+   system with open network interfaces and hypermedia capabilities.
+  </para><para>
+   We make this software available free of charge, on a fairly unrestrictive
+   license; as a service to the networking community, and to further the
+   development of quality software for open network communication.
+  </para><para>
+   We'll be happy to answer questions about the software, and about ourselves
+   in general.
+  </para>
+  <para>
+   <address>
+    Index Data Aps
+    <street>K&oslash;bmagergade 43</street>
+    <postcode>1150 Copenhagen K</postcode>
+    <country>Denmark</country>
+    Phone <phone>+45 3341 0100</phone>
+    Fax <fax>+45 3341 0101</fax>
+    Email <email>info@indexdata.dk</email>
+   </address>
 
-</para>
-<para>
+  </para>
+  <para>
 
-The Hacker's Jargon File has the following to say about the
-use of the
-prefix &quot;YA&quot; in the name of a software product.
-</para>
-<para>
-<citation>
-Yet Another. adj. 1. Of your own work: A
-humorous allusion often used in titles to acknowledge that the
-topic is not original, though the content is.  As in &quot;Yet Another
-AI Group&quot; or &quot;Yet Another Simulated Annealing Algorithm&quot;.
-2. Of
-others' work: Describes something of which there are already far
-too many.
-</citation>
+   The Hacker's Jargon File has the following to say about the
+   use of the
+   prefix &quot;YA&quot; in the name of a software product.
+  </para>
+  <para>
+   <citation>
+    Yet Another. adj. 1. Of your own work: A
+    humorous allusion often used in titles to acknowledge that the
+    topic is not original, though the content is.  As in &quot;Yet Another
+    AI Group&quot; or &quot;Yet Another Simulated Annealing Algorithm&quot;.
+    2. Of
+    others' work: Describes something of which there are already far
+    too many.
+   </citation>
 
-</para>
-</appendix>
+  </para>
+ </appendix>
+ <!-- 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: "yaz.xml"
+ sgml-local-catalogs: "../../docbook/docbook.cat"
+ sgml-namecase-general:t
+ End:
+ -->
index cbd4abd..6d5c09f 100644 (file)
-<!-- $Header: /home/cvsroot/yaz/doc/installation.xml,v 1.1 2001-01-04 13:36:24 adam Exp $ -->
-<chapter><title>Compilation and Installation</title>
-
-<para>
-The latest version of the software will generally be found at
-</para>
-<para>
-<ulink url="http://ftp.indexdata.dk/pub/yaz/">
-http://ftp.indexdata.dk/pub/yaz/</ulink>
-</para>
-<para>
-We have tried our best to keep the software portable, and on many
-platforms, you should be able to compile everything with little or no changes.
-So far, the software has been ported
-to the following platforms with little or no difficulties.
-
-<itemizedlist>
-<listitem><para>Unix systems</para>
-<itemizedlist>
-<listitem><para>HP/UX</para></listitem>
-<listitem><para>SunOS/Solaris</para></listitem>
-<listitem><para>DEC Unix</para></listitem>
-<listitem><para>Linux</para></listitem>
-<listitem><para>IBM AIX</para></listitem>
-<listitem><para>Data General DG/UX (with some CFLAGS tinkering)
-</para></listitem>
-<listitem><para>SGI/IRIX</para></listitem>
-<listitem><para>DDE Supermax</para></listitem>
-</itemizedlist></listitem>
-<listitem><para>Non-unix systems</para>
-<itemizedlist>
-<listitem><para>Apple Macintosh (using the Codewarrior programming
-environment and the GUSI socket libraries)</para></listitem>
-<listitem><para>MS Windows 95/98/NT/W2K (Win32)</para></listitem>
-<listitem><para>IBM AS/400</para></listitem>
-</itemizedlist></listitem>
-</itemizedlist>
-
-</para>
-<para>
-If you move the software to other platforms, we'd be grateful if you'd
-let us know about it. If you run into difficulties, we will try to help if we
-can, and if you solve the problems, we would be happy to
-include your fixes in the next release. So far, we have mostly avoided
-&num;ifdefs for individual platforms, and we'd like to keep it that
-way as far as it makes sense.
-</para>
-
-<para>
-We maintain a mailing-list for the purpose of announcing new releases and
-bug-fixes, as well as general discussion. Subscribe by sending mail to
-<ulink url="mailto:yaz-request@indexdata.dk">yaz-request@indexdata.dk</ulink>.
-General questions and problems can be directed at 
-<ulink url="mailto:yaz-help@indexdata.dk">yaz-help@indexdata.dk</ulink>, or
-the address given at the top of this document.
-</para>
-
-<sect1><title>UNIX</title>
-
-<para>
-Note that if your system doesn't have a native ANSI C compiler, you may
-have to acquire one separately. We recommend gcc.
-</para>
-<para>
-For UNIX we use GNU configure to create Makefiles for &yaz;.
-Generally it should be sufficient to run configure without options:
-</para>
-
-<screen>
-  ./configure
-</screen>
-
-<para>
-The configure script attempts to use use the C compiler specified by
-the <literal>CC</literal> environment variable. If not set, GNU C will be
-used if it is available. The <literal>CFLAGS</literal> environment variable
-holds options to be passed to the C compiler. If you're using
-Bourne-compatible shell you may pass something like this to use a
-particular C compiler with optimization enabled:
-</para>
-
-<screen>
-  CC=/opt/ccs/bin/cc CFLAGS=-O ./configure
-</screen>
-
-<para>
-To customize &yaz; the configure script also accepts a set of options.
-The most important are:
-
-<variablelist>
-<varlistentry><term><literal>--prefix </literal>path</term>
-<listitem><para>Specifies installation prefix. This is
-only needed if you run <literal>make install</literal> later to perform a
-"system" installation. The prefix is <literal>/usr/local</literal> if not
-specified.
-</para></listitem>
-</varlistentry>
-<varlistentry>
-<term><literal>--enable-comp </literal></term>
-<listitem><para> &yaz; will be built using the ASN.1 compiler for &yaz;
-(default). If you wish to use the old decoders (in sub directory asn)
-use <literal>--disable-comp</literal> instead.
-</para></listitem>
-</varlistentry>
-<varlistentry><term><literal>--enable-threads</literal></term>
-<listitem><para>&yaz; will be built using POSIX threads.
-Specifically, <constant>_REENTRANT</constant> will be defined during
-compilation.
-</para></listitem>
-</varlistentry>
-</variablelist>
-
-</para>
-<para>
-When configured, build the software by typing:
-<screen>
-  make
-</screen>
-
-</para>
-
-<para>
-The following files are generated by the make process:
-<variablelist>
-<varlistentry><term><filename>lib/libyaz.a</filename></term>
-<listitem><para>
-The &yaz; programmers' library.
-</para></listitem></varlistentry>
-
-<varlistentry><term><filename>ztest/yaz-ztest</filename></term>
-<listitem><para>A test Z39.50 server.
-</para></listitem></varlistentry>
-
-<varlistentry><term><filename>client/yaz-client</filename></term>
-<listitem><para>A command mode Z39.50 client.
-</para></listitem></varlistentry>
-
-<varlistentry><term><filename>yaz-config</filename></term>
-<listitem><para>A Bourne-shell script that holds build
-settings for &yaz;.
-</para></listitem></varlistentry>
-
-<varlistentry><term><filename>yaz-comp</filename></term>
-<listitem><para>The ASN.1 compiler for &yaz;. Requires the
-Tcl Shell, <application>tclsh</application>, in current path to work.
-</para></listitem></varlistentry>
-</variablelist>
-
-</para>
-
-<para>
-If you wish to install &yaz; in system directories such as 
-<filename>/usr/local/bin</filename>,
-<filename>/usr/local/lib</filename> you can type:
-</para>
-
-<screen>
-  make install
-</screen>
-
-<para>
-You probably need to have root access in order to perform this.
-You must specify the <literal>--prefix</literal> option for configure if
-you wish to install &yaz; in other directories than the default 
-<filename>/usr/local/</filename>.
-</para>
-
-<para>
-If you wish to perform an un-installation of &yaz; use:
-</para>
-
-<screen>
-  make uninstall
-</screen>
-
-<para>
-This will only work if you haven't reconfigured &yaz; (and therefore
-changed installation prefix). Note that uninstall will not
-remove directories created by make install, e.g.
-<filename>/usr/local/include/yaz</filename>.
-</para>
-
-</sect1>
-<sect1><title>WIN32</title>
-
-<para>
-&yaz; is shipped with "makefiles" for the NMAKE tool that comes
-with Visual C++.
-
-Start an MS-DOS prompt and switch the sub directory <filename>WIN</filename>
-where the file <filename>makefile</filename> is located. Customize the
-installation by editing the <filename>makefile</filename> file (for example
-by using notepad).
-
-The following summarises the most important settings in that file:
-
-<table frame="top"><title>WIN32 makefile settings</title>
-<tgroup cols="2">
-<thead>
-<row>
-<entry>Setting</entry>
-<entry>Description</entry>
-</row>
-</thead>
-<tbody>
-
-<row>
-<entry><literal>NEW_Z3950</literal></entry>
-<entry> If 1, the auto-generated decoder/encoders
-for Z39.50 as written by the ASN.1 compiler will be used. If 0, the old
-decoders for Z39.50 will be used. Note, when 1, the setting TCL should
-point to the Tcl shell on your system.
-</entry>
-</row>
-
-<row>
-<entry><literal>DEBUG</literal></entry>
-<entry> If set to 1, the software is
-compiled with debugging libraries. If set to 0, the software
-is compiled with release (non-debugging) libraries.
-</entry>
-</row>
-
-<row>
-<entry><literal>TCL</literal></entry>
-<entry> Specifies the name of the Tcl shell (EXE-file).
-You do not need setting this or installing Tcl unless you wish
-to change or add ASN.1 for &yaz;.
-</entry>
-</row>
-
-</tbody>
-</tgroup>
-</table>
-
-</para>
-<para>
-When satisfied with the settings in the makefile type
-<screen>
-  nmake
-</screen>
-</para>
-<para>
-The following files are generated upon successful compilation:
-
-<variablelist>
-<varlistentry><term><filename>bin/yaz.dll</filename></term>
-<listitem><para>
-the multi-threaded &yaz; DLL.
-</para></listitem></varlistentry>
-
-<varlistentry><term><filename>bin/yaz-ztest.exe</filename></term>
-<listitem><para>
-A console Z39.50 client application.
-</para></listitem></varlistentry>
-
-<varlistentry><term><filename>bin/yaz-ztest.exe</filename></term>
-<listitem><para>
-A console Z39.50 multi threaded server.
-</para></listitem></varlistentry>
-
-</variablelist>
-
-</para>
-</sect1>
-</chapter>
-
+<!-- $Id: installation.xml,v 1.2 2001-07-19 23:29:40 adam Exp $ -->
+ <chapter><title>Compilation and Installation</title>
+  
+  <para>
+   The latest version of the software will generally be found at
+  </para>
+  <para>
+   <ulink url="http://ftp.indexdata.dk/pub/yaz/">
+    http://ftp.indexdata.dk/pub/yaz/</ulink>
+  </para>
+  <para>
+   We have tried our best to keep the software portable, and on many
+   platforms, you should be able to compile everything with little or
+   no changes.
+   So far, the software has been ported to the following platforms with
+   little or no difficulties.
+   
+   <itemizedlist>
+    <listitem><para>Unix systems</para>
+     <itemizedlist>
+      <listitem><para>HP/UX</para></listitem>
+      <listitem><para>SunOS/Solaris</para></listitem>
+      <listitem><para>DEC Unix</para></listitem>
+      <listitem><para>Linux</para></listitem>
+      <listitem><para>IBM AIX</para></listitem>
+      <listitem><para>Data General DG/UX (with some CFLAGS tinkering)
+       </para></listitem>
+      <listitem><para>SGI/IRIX</para></listitem>
+      <listitem><para>DDE Supermax</para></listitem>
+     </itemizedlist></listitem>
+    <listitem><para>Non-unix systems</para>
+     <itemizedlist>
+      <listitem><para>Apple Macintosh (using the Codewarrior programming
+       environment and the GUSI socket libraries)</para></listitem>
+      <listitem><para>MS Windows 95/98/NT/W2K (Win32)</para></listitem>
+      <listitem><para>IBM AS/400</para></listitem>
+     </itemizedlist></listitem>
+   </itemizedlist>
+   
+  </para>
+  <para>
+   If you move the software to other platforms, we'd be grateful if you'd
+   let us know about it. If you run into difficulties, we will try to help
+   if we can, and if you solve the problems, we would be happy to include
+   your fixes in the next release. So far, we have mostly avoided
+   &num;ifdefs for individual platforms, and we'd like to keep it that
+   way as far as it makes sense.
+  </para>
+  
+  <para>
+   We maintain a mailing-list for the purpose of announcing new releases and
+   bug-fixes, as well as general discussion. Subscribe by sending mail to
+   <ulink url="mailto:yaz-request@indexdata.dk">
+    yaz-request@indexdata.dk
+   </ulink>.
+   General questions and problems can be directed at 
+   <ulink url="mailto:yaz-help@indexdata.dk">
+    yaz-help@indexdata.dk
+   </ulink>, or the address given at the top of this document.
+  </para>
+  
+  <sect1><title>UNIX</title>
+   
+   <para>
+    Note that if your system doesn't have a native ANSI C compiler, you may
+    have to acquire one separately. We recommend gcc.
+   </para>
+   <para>
+    For UNIX we use GNU configure to create Makefiles for &yaz;.
+    Generally it should be sufficient to run configure without options:
+   </para>
+   
+   <screen>
+    ./configure
+   </screen>
+   
+   <para>
+    The configure script attempts to use use the C compiler specified by
+    the <literal>CC</literal> environment variable. If not set, GNU C will be
+    used if it is available. The <literal>CFLAGS</literal> environment
+    variable holds options to be passed to the C compiler. If you're using
+    Bourne-compatible shell you may pass something like this to use a
+    particular C compiler with optimization enabled:
+   </para>
+   
+   <screen>
+    CC=/opt/ccs/bin/cc CFLAGS=-O ./configure
+   </screen>
+   
+   <para>
+    To customize &yaz; the configure script also accepts a set of options.
+    The most important are:
+    
+    <variablelist>
+     <varlistentry><term><literal>--prefix </literal>path</term>
+      <listitem><para>Specifies installation prefix. This is
+       only needed if you run <literal>make install</literal> later to
+       perform a "system" installation. The prefix is
+       <literal>/usr/local</literal> if not specified.
+       </para></listitem>
+     </varlistentry>
+     <varlistentry>
+      <term><literal>--enable-comp </literal></term>
+      <listitem><para> &yaz; will be built using the ASN.1 compiler for &yaz;
+       (default). If you wish to use the old decoders (in sub directory asn)
+       use <literal>--disable-comp</literal> instead.
+       </para></listitem>
+     </varlistentry>
+     <varlistentry><term><literal>--enable-threads</literal></term>
+      <listitem><para>&yaz; will be built using POSIX threads.
+       Specifically, <constant>_REENTRANT</constant> will be defined during
+       compilation.
+       </para></listitem>
+     </varlistentry>
+    </variablelist>
+    
+   </para>
+   <para>
+    When configured, build the software by typing:
+    <screen>
+     make
+    </screen>
+    
+   </para>
+   
+   <para>
+    The following files are generated by the make process:
+    <variablelist>
+     <varlistentry><term><filename>lib/libyaz.a</filename></term>
+      <listitem><para>
+       The &yaz; programmers' library.
+       </para></listitem></varlistentry>
+     
+     <varlistentry><term><filename>ztest/yaz-ztest</filename></term>
+      <listitem><para>A test Z39.50 server.
+       </para></listitem></varlistentry>
+     
+     <varlistentry><term><filename>client/yaz-client</filename></term>
+      <listitem><para>A command mode Z39.50 client.
+       </para></listitem></varlistentry>
+     
+     <varlistentry><term><filename>yaz-config</filename></term>
+      <listitem><para>A Bourne-shell script that holds build
+       settings for &yaz;.
+       </para></listitem></varlistentry>
+     
+     <varlistentry><term><filename>yaz-comp</filename></term>
+      <listitem><para>The ASN.1 compiler for &yaz;. Requires the
+       Tcl Shell, <application>tclsh</application>, in current path to work.
+       </para></listitem></varlistentry>
+    </variablelist>
+    
+   </para>
+   
+   <para>
+    If you wish to install &yaz; in system directories such as 
+    <filename>/usr/local/bin</filename>,
+    <filename>/usr/local/lib</filename> you can type:
+   </para>
+   
+   <screen>
+    make install
+   </screen>
+   
+   <para>
+    You probably need to have root access in order to perform this.
+    You must specify the <literal>--prefix</literal> option for configure if
+    you wish to install &yaz; in other directories than the default 
+    <filename>/usr/local/</filename>.
+   </para>
+   
+   <para>
+    If you wish to perform an un-installation of &yaz; use:
+   </para>
+   
+   <screen>
+    make uninstall
+   </screen>
+   
+   <para>
+    This will only work if you haven't reconfigured &yaz; (and therefore
+    changed installation prefix). Note that uninstall will not
+    remove directories created by make install, e.g.
+    <filename>/usr/local/include/yaz</filename>.
+   </para>
+   
+  </sect1>
+  <sect1><title>WIN32</title>
+   
+   <para>
+    &yaz; is shipped with "makefiles" for the NMAKE tool that comes
+    with Visual C++.
+    
+    Start an MS-DOS prompt and switch the sub directory
+    <filename>WIN</filename> where the file <filename>makefile</filename>
+    is located. Customize the installation by editing the
+    <filename>makefile</filename> file (for example by using notepad).
+    
+    The following summarises the most important settings in that file:
+    
+    <table frame="top"><title>WIN32 makefile settings</title>
+     <tgroup cols="2">
+      <thead>
+       <row>
+       <entry>Setting</entry>
+       <entry>Description</entry>
+       </row>
+      </thead>
+      <tbody>
+       
+       <row>
+       <entry><literal>NEW_Z3950</literal></entry>
+       <entry> If 1, the auto-generated decoder/encoders
+        for Z39.50 as written by the ASN.1 compiler will be used. If 0,
+        the old decoders for Z39.50 will be used. Note, when 1, the
+        setting TCL should point to the Tcl shell on your system.
+       </entry>
+       </row>
+       
+       <row>
+       <entry><literal>DEBUG</literal></entry>
+       <entry> If set to 1, the software is
+        compiled with debugging libraries. If set to 0, the software
+        is compiled with release (non-debugging) libraries.
+       </entry>
+       </row>
+       
+       <row>
+       <entry><literal>TCL</literal></entry>
+       <entry> Specifies the name of the Tcl shell (EXE-file).
+        You do not need setting this or installing Tcl unless you wish
+        to change or add ASN.1 for &yaz;.
+       </entry>
+       </row>
+       
+      </tbody>
+     </tgroup>
+    </table>
+    
+   </para>
+   <para>
+    When satisfied with the settings in the makefile type
+    <screen>
+     nmake
+    </screen>
+   </para>
+   <para>
+    The following files are generated upon successful compilation:
+    
+    <variablelist>
+     <varlistentry><term><filename>bin/yaz.dll</filename></term>
+      <listitem><para>
+       the multi-threaded &yaz; DLL.
+       </para></listitem></varlistentry>
+     
+     <varlistentry><term><filename>bin/yaz-ztest.exe</filename></term>
+      <listitem><para>
+       A console Z39.50 client application.
+       </para></listitem></varlistentry>
+     
+     <varlistentry><term><filename>bin/yaz-ztest.exe</filename></term>
+      <listitem><para>
+       A console Z39.50 multi threaded server.
+       </para></listitem></varlistentry>
+     
+    </variablelist>
+    
+   </para>
+  </sect1>
+ </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: "yaz.xml"
+ sgml-local-catalogs: "../../docbook/docbook.cat"
+ sgml-namecase-general:t
+ End:
+ -->
\ No newline at end of file
index 5cc082e..785bc82 100644 (file)
-<!-- $Header: /home/cvsroot/yaz/doc/introduction.xml,v 1.1 2001-01-04 13:36:24 adam Exp $ -->
-<chapter><title>Introduction</title>
+<!-- $Id: introduction.xml,v 1.2 2001-07-19 23:29:40 adam Exp $ -->
+ <chapter><title>Introduction</title>
+  
+  <para>
+   The &yaz; toolkit offers several different levels of access to the
+   Z39.50 and SR protocols. The level that you need to use depends on
+   your requirements, and the role (server or client) that you
+   want to implement.
+  </para><para>
+   The basic level, which is independent of the role, consists of three
+   primary interfaces:
+   
+   <itemizedlist>
+    <listitem><para>&asn;, which provides a C representation of the Z39.50/SR
+      protocol packages (PDUs).
+     </para></listitem>
+    <listitem><para>&odr;, which encodes and decodes the packages according
+      to the BER specification.
+     </para></listitem>
+    <listitem><para>&comstack;, which exchanges the encoded packages with
+      a peer process over a network.
+     </para></listitem>
+   </itemizedlist>
+   
+   The &asn; module represents the ASN.1 definition of
+   the SR/Z39.50 protocol. It establishes a set of type and
+   structure definitions, with one structure for each of the top-level
+   PDUs, and one structure or type for each of the contained ASN.1 types.
+   For primitive types, or other types that are defined by the ASN.1
+   standard itself (such as the EXTERNAL type), the C representation is
+   provided by the &odr; (Open Data Representation) subsystem.
+  </para>
+  <para>
+    &odr; is a basic mechanism for representing an
+   ASN.1 type in the C programming language, and for implementing BER
+   encoders and decoders for values of that type. The types defined in
+   the &asn; module generally have the prefix <literal>Z_</literal>, and
+   a suffix corresponding to the name of the type in the ASN.1
+   specification of the protocol (generally Z39.50-1995). In the case of
+   base types (those originating in the ASN.1 standard itself), the prefix
+   <literal>Odr_</literal> is sometimes seen. Either way, look for
+   the actual definition in either <filename>proto.h</filename> (for the types
+   from the protocol), <filename>odr.h</filename> (for the primitive ASN.1
+   types, or <filename>odr_use.h</filename> (for the ASN.1
+   <emphasis>useful</emphasis> types). The &asn; library also
+   provides functions (which are, in turn, defined using &odr;
+   primitives) for encoding and decoding data values. Their general form is
 
-<para>
-The &yaz; toolkit offers several different levels of access to the
-Z39.50 and SR protocols. The level that you need to use depends on
-your requirements, and the role (server or client) that you
-want to implement.
-</para><para>
-The basic level, which is independent of the role, consists of three
-primary interfaces:
+   <synopsis>
+    int z_xxx(ODR o, Z_xxx **p, int optional, const char *name);
+   </synopsis>
+   (note the lower-case &quot;z&quot; in the function name)
+  </para>
 
-<itemizedlist>
-<listitem><para>&asn;, which provides a C representation of the Z39.50/SR
-protocol packages (PDUs).
-</para></listitem>
-<listitem><para>&odr;, which encodes and decodes the packages according
-to the BER specification.
-</para></listitem>
-<listitem><para>&comstack;, which exchanges the encoded packages with
-a peer process over a network.
-</para></listitem>
-</itemizedlist>
+  <note>
+   <para>
+    If you are using the premade definitions of the &asn; module, and you
+    are not adding new protocol of your own, the only parts of &odr; that you
+    need to worry about are documented in section 
+    <link linkend="odr-use">Using ODR</link>.
+   </para>
+  </note>
 
-The &asn; module represents the ASN.1 definition of
-the SR/Z39.50 protocol. It establishes a set of type and
-structure definitions, with one structure for each of the top-level
-PDUs, and one structure or type for each of the contained ASN.1 types.
-For primitive types, or other types that are defined by the ASN.1
-standard itself (such as the EXTERNAL type), the C representation is provided
-by the &odr; (Open Data Representation) subsystem.
-</para>
-<para>
-&odr; is a basic mechanism for representing an
-ASN.1 type in the C programming language, and for implementing BER
-encoders and decoders for values of that type. The types defined in
-the &asn; module generally have the prefix <literal>Z_</literal>, and a suffix
-corresponding to the name of the type in the ASN.1
-specification of the protocol (generally Z39.50-1995). In the case of
-base types (those originating in the ASN.1 standard itself), the prefix
-<literal>Odr_</literal> is sometimes seen. Either way, look for
-the actual definition in either <filename>proto.h</filename> (for the types
-from the protocol), <filename>odr.h</filename> (for the primitive ASN.1
-types, or <filename>odr_use.h</filename> (for the ASN.1
-<emphasis>useful</emphasis> types). The &asn; library also
-provides functions (which are, in turn, defined using &odr;
-primitives) for encoding and decoding data values. Their general form is
+  <para>
+   When you have created a BER-encoded buffer, you can use the &comstack;
+   subsystem to transmit (or receive) data over the network. The &comstack;
+   module provides simple functions for establishing a connection
+   (passively or actively, depending on the role of your application),
+   and for exchanging BER-encoded PDUs over that connection. When you
+   create a connection endpoint, you need to specify what transport to
+   use (OSI or TCP/IP), and which protocol you want to use (SR or
+   Z39.50). For the remainer of the connection's lifetime, you don't have
+   to worry about the underlying transport protocol at all - the &comstack;
+   will ensure that the correct mechanism is used.
+  </para>
+  <para>
+   We call the combined interfaces to &odr;, &asn;, and &comstack; the service
+   level API. It's the API that most closely models the Z39.50/SR
+   service/protocol definition, and it provides unlimited access to all
+   fields and facilities of the protocol definitions.
+  </para>
+  <para>
+   The reason that the &yaz; service-level API is a conglomerate of the
+   APIs from three different submodules is twofold. First, we wanted to allow
+   the user a choice of different options for each major task. For instance,
+   if you don't like the protocol API provided by &odr;/&asn;, you
+   can use SNACC or BERUtils instead, and still have the benefits of the
+   transparent transport approach of the &comstack; module. Secondly,
+   we realise that you may have to fit the toolkit into an existing
+   event-processing structure, in a way that
+   is incompatible with the &comstack; interface or some other part of &yaz;.
+  </para>
+ </chapter>
 
-<synopsis>
-int z_xxx(ODR o, Z_xxx **p, int optional, const char *name);
-</synopsis>
-(note the lower-case &quot;z&quot; in the function name)
-</para>
-
-<note>
-<para>
-If you are using the premade definitions of the &asn; module, and you
-are not adding new protocol of your own, the only parts of &odr; that you
-need to worry about are documented in section 
-<link linkend="odr-use">Using ODR</link>.
-</para>
-</note>
-
-<para>
-When you have created a BER-encoded buffer, you can use the &comstack;
-subsystem to transmit (or receive) data over the network. The &comstack;
-module provides simple functions for establishing a connection
-(passively or actively, depending on the role of your application),
-and for exchanging BER-encoded PDUs over that connection. When you
-create a connection endpoint, you need to specify what transport to
-use (OSI or TCP/IP), and which protocol you want to use (SR or
-Z39.50). For the remainer of the connection's lifetime, you don't have
-to worry about the underlying transport protocol at all - the &comstack;
-will ensure that the correct mechanism is used.
-</para>
-<para>
-We call the combined interfaces to &odr;, &asn;, and &comstack; the service
-level API. It's the API that most closely models the Z39.50/SR
-service/protocol definition, and it provides unlimited access to all
-fields and facilities of the protocol definitions.
-</para>
-<para>
-The reason that the &yaz; service-level API is a conglomerate of the
-APIs from three different submodules is twofold. First, we wanted to allow the
-user a choice of different options for each major task. For instance,
-if you don't like the protocol API provided by &odr;/&asn;, you
-can use SNACC or BERUtils instead, and still have the benefits of the
-transparent transport approach of the &comstack; module. Secondly,
-we realise that you may have to fit the toolkit into an existing
-event-processing structure, in a way that
-is incompatible with the &comstack; interface or some other part of &yaz;.
-</para>
-</chapter>
\ No newline at end of file
+ <!-- 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:"yaz.xml"
+ sgml-local-catalogs: "../../docbook/docbook.cat"
+ sgml-namecase-general:t
+ End:
+ -->
index 92ca04e..e07567d 100644 (file)
-<!-- $Header: /home/cvsroot/yaz/doc/license.xml,v 1.2 2001-01-04 14:03:42 adam Exp $ -->
-<appendix><title>License</title>
-
-<sect1><title>Index Data Copyright</title>
-
-<para>
-Copyright &copy; 1995-2001 Index Data.
-</para>
-
-<para>
-Permission to use, copy, modify, distribute, and sell this software and
-its documentation, in whole or in part, for any purpose, is hereby granted,
-provided that:
-</para>
-
-<para>
-1. This copyright and permission notice appear in all copies of the
-software and its documentation. Notices of copyright or attribution
-which appear at the beginning of any file must remain unchanged.
-</para>
-
-<para>
-2. The names of Index Data or the individual authors may not be used to
-endorse or promote products derived from this software without specific
-prior written permission.
-</para>
-
-<para>
-THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
-EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
-WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
-IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
-INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
-WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
-NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
-LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
-OF THIS SOFTWARE.
-</para>
-</sect1>
-<sect1><title>Additional Copyright Statements</title>
-
-<para>
-The optional CCL query language interpreter is covered by the following
-license:
-</para>
-
-<para>
-Copyright &copy; 1995, the EUROPAGATE consortium (see below).
-</para>
-
-<literallayout>
-The EUROPAGATE consortium members are:
-   University College Dublin
-   Danmarks Teknologiske Videnscenter
-   An Chomhairle Leabharlanna
-   Consejo Superior de Investigaciones Cientificas
-</literallayout>
-
-<para>
-Permission to use, copy, modify, distribute, and sell this software and
-its documentation, in whole or in part, for any purpose, is hereby granted,
-provided that:
-</para>
-
-<para>
-1. This copyright and permission notice appear in all copies of the
-software and its documentation. Notices of copyright or attribution
-which appear at the beginning of any file must remain unchanged.
-</para>
-
-<para>
-2. The names of EUROPAGATE or the project partners may not be used to
-endorse or promote products derived from this software without specific
-prior written permission.
-</para>
-
-<para>
-3. Users of this software (implementors and gateway operators) agree to
-inform the EUROPAGATE consortium of their use of the software. This
-information will be used to evaluate the EUROPAGATE project and the
-software, and to plan further developments. The consortium may use
-the information in later publications.
-</para>
-
-<para>
-4. Users of this software agree to make their best efforts, when
-documenting their use of the software, to acknowledge the EUROPAGATE
-consortium, and the role played by the software in their work.
-</para>
-
-<para>
-THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
-EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
-WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
-IN NO EVENT SHALL THE EUROPAGATE CONSORTIUM OR ITS MEMBERS BE LIABLE
-FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF
-ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
-OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND
-ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
-USE OR PERFORMANCE OF THIS SOFTWARE.
-</para>
-</sect1>
-</appendix>
\ No newline at end of file
+<!-- $Id: license.xml,v 1.3 2001-07-19 23:29:40 adam Exp $ -->
+ <appendix><title>License</title>
+
+  <sect1><title>Index Data Copyright</title>
+
+   <para>
+    Copyright &copy; 1995-2001 Index Data.
+   </para>
+
+   <para>
+    Permission to use, copy, modify, distribute, and sell this software and
+    its documentation, in whole or in part, for any purpose, is hereby granted,
+    provided that:
+   </para>
+
+   <para>
+    1. This copyright and permission notice appear in all copies of the
+    software and its documentation. Notices of copyright or attribution
+    which appear at the beginning of any file must remain unchanged.
+   </para>
+
+   <para>
+    2. The names of Index Data or the individual authors may not be used to
+    endorse or promote products derived from this software without specific
+    prior written permission.
+   </para>
+
+   <para>
+    THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+    EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+    WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+    IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+    INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+    NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+    LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+    OF THIS SOFTWARE.
+   </para>
+  </sect1>
+  <sect1><title>Additional Copyright Statements</title>
+
+   <para>
+    The optional CCL query language interpreter is covered by the following
+    license:
+   </para>
+
+   <para>
+    Copyright &copy; 1995, the EUROPAGATE consortium (see below).
+   </para>
+
+   <literallayout>
+    The EUROPAGATE consortium members are:
+    University College Dublin
+    Danmarks Teknologiske Videnscenter
+    An Chomhairle Leabharlanna
+    Consejo Superior de Investigaciones Cientificas
+   </literallayout>
+
+   <para>
+    Permission to use, copy, modify, distribute, and sell this software and
+    its documentation, in whole or in part, for any purpose, is hereby granted,
+    provided that:
+   </para>
+
+   <para>
+    1. This copyright and permission notice appear in all copies of the
+    software and its documentation. Notices of copyright or attribution
+    which appear at the beginning of any file must remain unchanged.
+   </para>
+
+   <para>
+    2. The names of EUROPAGATE or the project partners may not be used to
+    endorse or promote products derived from this software without specific
+    prior written permission.
+   </para>
+
+   <para>
+    3. Users of this software (implementors and gateway operators) agree to
+    inform the EUROPAGATE consortium of their use of the software. This
+    information will be used to evaluate the EUROPAGATE project and the
+    software, and to plan further developments. The consortium may use
+    the information in later publications.
+   </para>
+
+   <para>
+    4. Users of this software agree to make their best efforts, when
+    documenting their use of the software, to acknowledge the EUROPAGATE
+    consortium, and the role played by the software in their work.
+   </para>
+
+   <para>
+    THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+    EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+    WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+    IN NO EVENT SHALL THE EUROPAGATE CONSORTIUM OR ITS MEMBERS BE LIABLE
+    FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF
+    ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+    OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND
+    ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+    USE OR PERFORMANCE OF THIS SOFTWARE.
+   </para>
+  </sect1>
+ </appendix>
+
+ <!-- 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: "yaz.xml"
+ sgml-local-catalogs: "../../docbook/docbook.cat"
+ sgml-namecase-general:t
+ End:
+ -->
index 87af9f8..de0b3ca 100644 (file)
-<!-- $Header: /home/cvsroot/yaz/doc/odr.xml,v 1.1 2001-01-04 13:36:24 adam Exp $ -->
-<chapter><title id="odr">The ODR Module</title>
-
-<sect1><title>Introduction</title>
-
-<para>
-&odr; is the BER-encoding/decoding subsystem of &yaz;. Care as been taken
-to isolate &odr; from the rest of the package - specifically from the
-transport interface. &odr; may be used in any context where basic
-ASN.1/BER representations are used.
-</para>
-
-<para>
-If you are only interested in writing a Z39.50 implementation based on
-the PDUs that are already provided with &yaz;, you only need to concern
-yourself with the section on managing ODR streams (section
-<link linkend="odr-use">Using ODR</link>). Only if you need to
-implement ASN.1 beyond that which has been provided, should you
-worry about the second half of the documentation
-(section <link linkend="odr-prog">Programming with ODR</link>).
-If you use one of the higher-level interfaces, you can skip this
-section entirely.
-</para>
-
-<para>
-This is important, so we'll repeat it for emphasis: <emphasis>You do not
-need to read section <link linkend="odr-prog">Programming with ODR</link> to
-implement Z39.50 with &yaz;.</emphasis>
-</para>
-
-<para>
-If you need a part of the protocol that isn't already in &yaz;, you
-should contact the authors before going to work on it yourself: We
-might already be working on it. Conversely, if you implement a useful
-part of the protocol before us, we'd be happy to include it in a
-future release.
-</para>
-
-</sect1>
-<sect1><title id="odr-use">Using ODR</title>
-
-<sect2><title>ODR Streams</title>
-
-<para>
-Conceptually, the ODR stream is the source of encoded data in the
-decoding mode; when encoding, it is the receptacle for the encoded
-data. Before you can use an ODR stream it must be allocated. This is
-done with the function
-</para>
-
-<synopsis>
-  ODR odr_createmem(int direction);
-</synopsis>
-
-<para>
-The <function>odr_createmem()</function> function takes as argument one
-of three manifest constants: <literal>ODR_ENCODE</literal>,
-<literal>ODR_DECODE</literal>, or <literal>ODR_PRINT</literal>.
-An &odr; stream can be in only one mode - it is not possible to change
-its mode once it's selected. Typically, your program will allocate
-at least two ODR streams - one for decoding, and one for encoding.
-</para>
-
-<para>
-When you're done with the stream, you can use
-</para>
-
-<synopsis>
-  void odr_destroy(ODR o);
-</synopsis>
-
-<para>
-to release the resources allocated for the stream.
-</para>
-</sect2>
-
-<sect2><title id="memory">Memory Management</title>
-
-<para>
-Two forms of memory management take place in the &odr; system. The first
-one, which has to do with allocating little bits of memory (sometimes
-quite large bits of memory, actually) when a protocol package is
-decoded, and turned into a complex of interlinked structures. This
-section deals with this system, and how you can use it for your own
-purposes. The next section deals with the memory management which is
-required when encoding data - to make sure that a large enough buffer is
-available to hold the fully encoded PDU.
-</para>
-
-<para>
-The &odr; module has its own memory management system, which is
-used whenever memory is required. Specifically, it is used to allocate
-space for data when decoding incoming PDUs. You can use the memory
-system for your own purposes, by using the function
-</para>
-
-<synopsis>
-void *odr_malloc(ODR o, int size);
-</synopsis>
-
-<para>
-You can't use the normal <function>free(2)</function> routine to free
-memory allocated by this function, and &odr; doesn't provide a parallel
-function. Instead, you can call
-</para>
-
-<synopsis>
-  void odr_reset(ODR o, int size);
-</synopsis>
-
-<para>
-when you are done with the
-memory: Everything allocated since the last call to
-<function>odr_reset()</function> is released.
-The <function>odr_reset()</function> call is also required to clear
-up an error condition on a stream.
-</para>
-
-<para>
-The function
-</para>
-
-<synopsis>
-  int odr_total(ODR o);
-</synopsis>
-
-<para>
-returns the number of bytes allocated on the stream since the last call to
-<function>odr_reset()</function>.
-</para>
-
-<para>
-The memory subsystem of &odr; is fairly efficient at allocating and
-releasing little bits of memory. Rather than managing the individual,
-small bits of space, the system maintains a freelist of larger chunks
-of memory, which are handed out in small bits. This scheme is
-generally known as a <emphasis>nibble memory</emphasis> system.
-It is very useful for maintaing short-lived constructions such
-as protocol PDUs.
-</para>
-
-<para>
-If you want to retain a bit of memory beyond the next call to
-<function>odr_reset()</function>, you can use the function
-</para>
-
-<synopsis>
-  ODR_MEM odr_extract_mem(ODR o);
-</synopsis>
-
-<para>
-This function will give you control of the memory recently allocated
-on the ODR stream. The memory will live (past calls to
-<function>odr_reset()</function>), until you call the function
-</para>
-
-<synopsis>
-  void odr_release_mem(ODR_MEM p);
-</synopsis>
-
-<para>
-The opaque <literal>ODR_MEM</literal> handle has no other purpose than
-referencing the memory block for you until you want to release it.
-</para>
-
-<para>
-You can use <function>odr_extract_mem()</function> repeatedly between
-allocating data, to retain individual control of separate chunks of data.
-</para>
-
-</sect2>
-<sect2><title>Encoding and Decoding Data</title>
-
-<para>
-When encoding data, the ODR stream will write the encoded octet string
-in an internal buffer. To retrieve the data, use the function
-</para>
-
-<synopsis>
-  char *odr_getbuf(ODR o, int *len, int *size);
-</synopsis>
-
-<para>
-The integer pointed to by len is set to the length of the encoded
-data, and a pointer to that data is returned. <literal>*size</literal>
-is set to the size of the buffer (unless <literal>size</literal> is null,
-signalling that you are not interested in the size). The next call to
-a primitive function using the same &odr; stream will overwrite the
-data, unless a different buffer has been supplied using the call
-</para>
-
-<synopsis>
-  void odr_setbuf(ODR o, char *buf, int len, int can_grow);
-</synopsis>
-
-<para>
-which sets the encoding (or decoding) buffer used by <literal>o</literal> to
-<literal>buf</literal>, using the length <literal>len</literal>.
-Before a call to an encoding function, you can use
-<function>odr_setbuf()</function> to provide the stream with an encoding
-buffer of sufficient size (length). The <literal>can_grow</literal>
-parameter tells the encoding &odr; stream whether it is allowed to use
-<function>realloc(2)</function> to increase the size of the buffer when
-necessary. The default condition of a new encoding stream is equivalent
-to the results of calling
-</para>
-
-<synopsis>
-odr_setbuf(stream, 0, 0, 1);
-</synopsis>
-
-<para>
-In this case, the stream will allocate and reallocate memory as
-necessary. The stream reallocates memory by repeatedly doubling the
-size of the buffer - the result is that the buffer will typically
-reach its maximum, working size with only a small number of reallocation
-operations. The memory is freed by the stream when the latter is destroyed,
-unless it was assigned by the user with the <literal>can_grow</literal>
-parameter set to zero (in this case, you are expected to retain
-control of the memory yourself).
-</para>
-
-<para>
-To assume full control of an encoded buffer, you must first call
-<function>odr_getbuf()</function> to fetch the buffer and its length.
-Next, you should call <function>odr_setbuf()</function> to provide a
-different buffer (or a null pointer) to the stream. In the simplest
-case, you will reuse the same buffer over and over again, and you
-will just need to call <function>odr_getbuf()</function> after each
-encoding operation to get the length and address of the buffer.
-Note that the stream may reallocate the buffer during an encoding
-operation, so it is necessary to retrieve the correct address after
-each encoding operation.
-</para>
-
-<para>
-It is important to realise that the ODR stream will not release this
-memory when you call <function>odr_reset()</function>: It will
-merely update its internal pointers to prepare for the encoding of a
-new data value.
-When the stream is released by the <function>odr_destroy()</function>
-function, the memory given to it by <function>odr_setbuf</function> will
-be released <emphasis>only</emphasis> if the <literal>can_grow</literal>
-parameter to <function>odr_setbuf()</function> was nonzero. The
-<literal>can_grow</literal> parameter, in other words, is a way of
-signalling who is to own the buffer, you or the ODR stream. If you never call
-<function>odr_setbuf()</function> on your encoding stream, which is
-typically the case, the buffer allocated by the stream will belong to
-the stream by default.
-</para>
-
-<para>
-When you wish to decode data, you should first call
-<function>odr_setbuf()</function>, to tell the decoding stream
-where to find the encoded data, and how long the buffer is
-(the <literal>can_grow</literal> parameter is ignored by a decoding
-stream). After this, you can call the function corresponding to the
-data you wish to decode (eg, <function>odr_integer()</function> odr
-<function>z_APDU()</function>).
-</para>
-
-<para>
-Examples of encoding/decoding functions:
-</para>
-
-<synopsis>
-  int odr_integer(ODR o, int **p, int optional, const char *name);
-
-  int z_APDU(ODR o, Z_APDU **p, int optional, const char *name);
-</synopsis>
-
-<para>
-If the data is absent (or doesn't match the tag corresponding to the type),
-the return value will be either 0 or 1 depending on the
-<literal>optional</literal> flag. If <literal>optional</literal>
-is 0 and the data is absent, an error flag will be raised in the
-stream, and you'll need to call <function>odr_reset()</function> before
-you can use the stream again. If <literal>optional</literal> is
-nonzero, the pointer <emphasis>pointed</emphasis> to/ by <literal>p</literal>
-will be set to the null value, and the function will return 1.
-The <literal>name</literal> argument is used to pretty-print the
-tag in question. It may be set to <literal>NULL</literal> if
-pretty-printing is not desired.
-</para>
-
-<para>
-If the data value is found where it's expected, the pointer
-<emphasis>pointed to</emphasis> by the <literal>p</literal> argument
-will be set to point to the decoded type.
-The space for the type will be allocated and owned by the &odr; stream, and
-it will live until you call <function>odr_reset()</function> on the
-stream. You cannot use <function>free(2)</function> to release the memory.
-You can decode several data elements (by repeated calls to
-<function>odr_setbuf()</function> and your decoding function), and
-new memory will be allocated each time. When you do call 
-<function>odr_reset()</function>, everything decoded since the
-last call to <function>odr_reset()</function> will be released.
-</para>
-
-<para>
-The use of the double indirection can be a little confusing at first
-(its purpose will become clear later on, hopefully),
-so an example is in order. We'll encode an integer value, and
-immediately decode it again using a different stream. A useless, but
-informative operation.
-</para>
-
-<programlisting>
+<!-- $Id: odr.xml,v 1.2 2001-07-19 23:29:40 adam Exp $ -->
+ <chapter><title id="odr">The ODR Module</title>
+  
+  <sect1><title>Introduction</title>
+
+   <para>
+     &odr; is the BER-encoding/decoding subsystem of &yaz;. Care as been taken
+    to isolate &odr; from the rest of the package - specifically from the
+    transport interface. &odr; may be used in any context where basic
+    ASN.1/BER representations are used.
+   </para>
+
+   <para>
+    If you are only interested in writing a Z39.50 implementation based on
+    the PDUs that are already provided with &yaz;, you only need to concern
+    yourself with the section on managing ODR streams (section
+    <link linkend="odr-use">Using ODR</link>). Only if you need to
+    implement ASN.1 beyond that which has been provided, should you
+    worry about the second half of the documentation
+    (section <link linkend="odr-prog">Programming with ODR</link>).
+    If you use one of the higher-level interfaces, you can skip this
+    section entirely.
+   </para>
+
+   <para>
+    This is important, so we'll repeat it for emphasis: <emphasis>You do not
+     need to read section <link linkend="odr-prog">Programming with ODR</link> to
+     implement Z39.50 with &yaz;.</emphasis>
+   </para>
+
+   <para>
+    If you need a part of the protocol that isn't already in &yaz;, you
+    should contact the authors before going to work on it yourself: We
+    might already be working on it. Conversely, if you implement a useful
+    part of the protocol before us, we'd be happy to include it in a
+    future release.
+   </para>
+
+  </sect1>
+  <sect1><title id="odr-use">Using ODR</title>
+
+   <sect2><title>ODR Streams</title>
+
+    <para>
+     Conceptually, the ODR stream is the source of encoded data in the
+     decoding mode; when encoding, it is the receptacle for the encoded
+     data. Before you can use an ODR stream it must be allocated. This is
+     done with the function
+    </para>
+
+    <synopsis>
+     ODR odr_createmem(int direction);
+    </synopsis>
+
+    <para>
+     The <function>odr_createmem()</function> function takes as argument one
+     of three manifest constants: <literal>ODR_ENCODE</literal>,
+     <literal>ODR_DECODE</literal>, or <literal>ODR_PRINT</literal>.
+     An &odr; stream can be in only one mode - it is not possible to change
+     its mode once it's selected. Typically, your program will allocate
+     at least two ODR streams - one for decoding, and one for encoding.
+    </para>
+
+    <para>
+     When you're done with the stream, you can use
+    </para>
+
+    <synopsis>
+     void odr_destroy(ODR o);
+    </synopsis>
+
+    <para>
+     to release the resources allocated for the stream.
+    </para>
+   </sect2>
+
+   <sect2><title id="memory">Memory Management</title>
+
+    <para>
+     Two forms of memory management take place in the &odr; system. The first
+     one, which has to do with allocating little bits of memory (sometimes
+     quite large bits of memory, actually) when a protocol package is
+     decoded, and turned into a complex of interlinked structures. This
+     section deals with this system, and how you can use it for your own
+     purposes. The next section deals with the memory management which is
+     required when encoding data - to make sure that a large enough buffer is
+     available to hold the fully encoded PDU.
+    </para>
+
+    <para>
+     The &odr; module has its own memory management system, which is
+     used whenever memory is required. Specifically, it is used to allocate
+     space for data when decoding incoming PDUs. You can use the memory
+     system for your own purposes, by using the function
+    </para>
+
+    <synopsis>
+     void *odr_malloc(ODR o, int size);
+    </synopsis>
+
+    <para>
+     You can't use the normal <function>free(2)</function> routine to free
+     memory allocated by this function, and &odr; doesn't provide a parallel
+     function. Instead, you can call
+    </para>
+
+    <synopsis>
+     void odr_reset(ODR o, int size);
+    </synopsis>
+
+    <para>
+     when you are done with the
+     memory: Everything allocated since the last call to
+     <function>odr_reset()</function> is released.
+     The <function>odr_reset()</function> call is also required to clear
+     up an error condition on a stream.
+    </para>
+
+    <para>
+     The function
+    </para>
+
+    <synopsis>
+     int odr_total(ODR o);
+    </synopsis>
+
+    <para>
+     returns the number of bytes allocated on the stream since the last call to
+     <function>odr_reset()</function>.
+    </para>
+
+    <para>
+     The memory subsystem of &odr; is fairly efficient at allocating and
+     releasing little bits of memory. Rather than managing the individual,
+     small bits of space, the system maintains a freelist of larger chunks
+     of memory, which are handed out in small bits. This scheme is
+     generally known as a <emphasis>nibble memory</emphasis> system.
+     It is very useful for maintaing short-lived constructions such
+     as protocol PDUs.
+    </para>
+
+    <para>
+     If you want to retain a bit of memory beyond the next call to
+     <function>odr_reset()</function>, you can use the function
+    </para>
+
+    <synopsis>
+     ODR_MEM odr_extract_mem(ODR o);
+    </synopsis>
+
+    <para>
+     This function will give you control of the memory recently allocated
+     on the ODR stream. The memory will live (past calls to
+     <function>odr_reset()</function>), until you call the function
+    </para>
+
+    <synopsis>
+     void odr_release_mem(ODR_MEM p);
+    </synopsis>
+
+    <para>
+     The opaque <literal>ODR_MEM</literal> handle has no other purpose than
+     referencing the memory block for you until you want to release it.
+    </para>
+
+    <para>
+     You can use <function>odr_extract_mem()</function> repeatedly between
+     allocating data, to retain individual control of separate chunks of data.
+    </para>
+
+   </sect2>
+   <sect2><title>Encoding and Decoding Data</title>
+
+    <para>
+     When encoding data, the ODR stream will write the encoded octet string
+     in an internal buffer. To retrieve the data, use the function
+    </para>
+
+    <synopsis>
+     char *odr_getbuf(ODR o, int *len, int *size);
+    </synopsis>
+
+    <para>
+     The integer pointed to by len is set to the length of the encoded
+     data, and a pointer to that data is returned. <literal>*size</literal>
+     is set to the size of the buffer (unless <literal>size</literal> is null,
+     signalling that you are not interested in the size). The next call to
+     a primitive function using the same &odr; stream will overwrite the
+     data, unless a different buffer has been supplied using the call
+    </para>
+
+    <synopsis>
+     void odr_setbuf(ODR o, char *buf, int len, int can_grow);
+    </synopsis>
+
+    <para>
+     which sets the encoding (or decoding) buffer used by
+     <literal>o</literal> to <literal>buf</literal>, using the length
+     <literal>len</literal>.
+     Before a call to an encoding function, you can use
+     <function>odr_setbuf()</function> to provide the stream with an encoding
+     buffer of sufficient size (length). The <literal>can_grow</literal>
+     parameter tells the encoding &odr; stream whether it is allowed to use
+     <function>realloc(2)</function> to increase the size of the buffer when
+     necessary. The default condition of a new encoding stream is equivalent
+     to the results of calling
+    </para>
+
+    <synopsis>
+     odr_setbuf(stream, 0, 0, 1);
+    </synopsis>
+
+    <para>
+     In this case, the stream will allocate and reallocate memory as
+     necessary. The stream reallocates memory by repeatedly doubling the
+     size of the buffer - the result is that the buffer will typically
+     reach its maximum, working size with only a small number of reallocation
+     operations. The memory is freed by the stream when the latter is destroyed,
+     unless it was assigned by the user with the <literal>can_grow</literal>
+     parameter set to zero (in this case, you are expected to retain
+     control of the memory yourself).
+    </para>
+
+    <para>
+     To assume full control of an encoded buffer, you must first call
+     <function>odr_getbuf()</function> to fetch the buffer and its length.
+     Next, you should call <function>odr_setbuf()</function> to provide a
+     different buffer (or a null pointer) to the stream. In the simplest
+     case, you will reuse the same buffer over and over again, and you
+     will just need to call <function>odr_getbuf()</function> after each
+     encoding operation to get the length and address of the buffer.
+     Note that the stream may reallocate the buffer during an encoding
+     operation, so it is necessary to retrieve the correct address after
+     each encoding operation.
+    </para>
+
+    <para>
+     It is important to realise that the ODR stream will not release this
+     memory when you call <function>odr_reset()</function>: It will
+     merely update its internal pointers to prepare for the encoding of a
+     new data value.
+     When the stream is released by the <function>odr_destroy()</function>
+     function, the memory given to it by <function>odr_setbuf</function> will
+     be released <emphasis>only</emphasis> if the <literal>can_grow</literal>
+     parameter to <function>odr_setbuf()</function> was nonzero. The
+     <literal>can_grow</literal> parameter, in other words, is a way of
+     signalling who is to own the buffer, you or the ODR stream. If you never call
+     <function>odr_setbuf()</function> on your encoding stream, which is
+     typically the case, the buffer allocated by the stream will belong to
+     the stream by default.
+    </para>
+
+    <para>
+     When you wish to decode data, you should first call
+     <function>odr_setbuf()</function>, to tell the decoding stream
+     where to find the encoded data, and how long the buffer is
+     (the <literal>can_grow</literal> parameter is ignored by a decoding
+     stream). After this, you can call the function corresponding to the
+     data you wish to decode (eg, <function>odr_integer()</function> odr
+     <function>z_APDU()</function>).
+    </para>
+
+    <para>
+     Examples of encoding/decoding functions:
+    </para>
+
+    <synopsis>
+     int odr_integer(ODR o, int **p, int optional, const char *name);
+
+     int z_APDU(ODR o, Z_APDU **p, int optional, const char *name);
+    </synopsis>
+
+    <para>
+     If the data is absent (or doesn't match the tag corresponding to
+     the type), the return value will be either 0 or 1 depending on the
+     <literal>optional</literal> flag. If <literal>optional</literal>
+     is 0 and the data is absent, an error flag will be raised in the
+     stream, and you'll need to call <function>odr_reset()</function> before
+     you can use the stream again. If <literal>optional</literal> is
+     nonzero, the pointer <emphasis>pointed</emphasis> to/ by
+     <literal>p</literal> will be set to the null value, and the function
+     will return 1.
+     The <literal>name</literal> argument is used to pretty-print the
+     tag in question. It may be set to <literal>NULL</literal> if
+     pretty-printing is not desired.
+    </para>
+
+    <para>
+     If the data value is found where it's expected, the pointer
+     <emphasis>pointed to</emphasis> by the <literal>p</literal> argument
+     will be set to point to the decoded type.
+     The space for the type will be allocated and owned by the &odr;
+     stream, and it will live until you call
+     <function>odr_reset()</function> on the stream. You cannot use
+     <function>free(2)</function> to release the memory.
+     You can decode several data elements (by repeated calls to
+     <function>odr_setbuf()</function> and your decoding function), and
+     new memory will be allocated each time. When you do call 
+     <function>odr_reset()</function>, everything decoded since the
+     last call to <function>odr_reset()</function> will be released.
+    </para>
+
+    <para>
+     The use of the double indirection can be a little confusing at first
+     (its purpose will become clear later on, hopefully),
+     so an example is in order. We'll encode an integer value, and
+     immediately decode it again using a different stream. A useless, but
+     informative operation.
+    </para>
+
+    <programlisting>
+
 void do_nothing_useful(int value)
 {
     ODR encode, decode;
     int *valp, *resvalp;
     char *bufferp;
     int len;
-
+     
     /* allocate streams */
     if (!(encode = odr_createmem(ODR_ENCODE)))
-       return;
+        return;
     if (!(decode = odr_createmem(ODR_DECODE)))
-       return;
+        return;
 
     valp = &amp;value;
     if (odr_integer(encode, &amp;valp, 0, 0) == 0)
     {
-       printf("encoding went bad\n");
-       return;
+        printf("encoding went bad\n");
+        return;
     }
     bufferp = odr_getbuf(encode, &amp;len);
     printf("length of encoded data is &percnt;d\n", len);
@@ -332,8 +336,8 @@ void do_nothing_useful(int value)
     odr_setbuf(decode, bufferp, len);
     if (odr_integer(decode, &amp;resvalp, 0, 0) == 0)
     {
-       printf("decoding went bad\n");
-       return;
+        printf("decoding went bad\n");
+        return;
     }
     printf("the value is &percnt;d\n", *resvalp);
 
@@ -341,809 +345,817 @@ void do_nothing_useful(int value)
     odr_destroy(encode);
     odr_destroy(decode);
 }
-</programlisting>
-
-<para>
-This looks like a lot of work, offhand. In practice, the &odr; streams
-will typically be allocated once, in the beginning of your program (or at the
-beginning of a new network session), and the encoding and decoding
-will only take place in a few, isolated places in your program, so the
-overhead is quite manageable.
-</para>
-
-</sect2>
-
-<sect2><title>Diagnostics</title>
-
-<para>
-The encoding/decoding functions all return 0 when an error occurs.
-Until you call <function>odr_reset()</function>, you cannot use the
-stream again, and any function called will immediately return 0.
-</para>
-
-<para>
-To provide information to the programmer or administrator, the function
-</para>
-
-<synopsis>
-  void odr_perror(ODR o, char *message);
-</synopsis>
-
-<para>
-is provided, which prints the <literal>message</literal> argument to
-<literal>stderr</literal> along with an error message from the stream.
-</para>
+    </programlisting>
+
+    <para>
+     This looks like a lot of work, offhand. In practice, the &odr; streams
+     will typically be allocated once, in the beginning of your program
+     (or at the beginning of a new network session), and the encoding
+     and decoding will only take place in a few, isolated places in your
+     program, so the overhead is quite manageable.
+    </para>
+
+   </sect2>
+
+   <sect2><title>Diagnostics</title>
+
+    <para>
+     The encoding/decoding functions all return 0 when an error occurs.
+     Until you call <function>odr_reset()</function>, you cannot use the
+     stream again, and any function called will immediately return 0.
+    </para>
+
+    <para>
+     To provide information to the programmer or administrator, the function
+    </para>
+
+    <synopsis>
+     void odr_perror(ODR o, char *message);
+    </synopsis>
+
+    <para>
+     is provided, which prints the <literal>message</literal> argument to
+     <literal>stderr</literal> along with an error message from the stream.
+    </para>
 
-<para>
-You can also use the function
-</para>
+    <para>
+     You can also use the function
+    </para>
 
-<synopsis>
-  int odr_geterror(ODR o);
-</synopsis>
+    <synopsis>
+     int odr_geterror(ODR o);
+    </synopsis>
 
-<para>
-to get the current error number from the screen. The number will be
-one of these constants:
-</para>
+    <para>
+     to get the current error number from the screen. The number will be
+     one of these constants:
+    </para>
 
-<table frame="top"><title>ODR Error codes</title>
-<tgroup cols="2">
-<thead>
-<row>
-<entry>code</entry>
-<entry>Description</entry>
-</row>
-</thead>
-<tbody>
-<row>
-<entry>OMEMORY</entry><entry>Memory allocation failed.</entry>
-</row>
-
-<row>
-<entry>OSYSERR</entry><entry>A system- or library call has failed.
-The standard diagnostic variable <literal>errno</literal> should be
-examined to determine the actual error.</entry>
-</row>
-
-<row>
-<entry>OSPACE</entry><entry>No more space for encoding.
-This will only occur when the user has explicitly provided a
-buffer for an encoding stream without allowing the system to
-allocate more space.</entry>
-</row>
-
-<row>
-<entry>OREQUIRED</entry><entry>This is a common protocol error; A
-required data element was missing during encoding or decoding.</entry>
-</row>
-
-<row>
-<entry>OUNEXPECTED</entry><entry>An unexpected data element was
-found during decoding.</entry>
-</row>
-
-<row><entry>OOTHER</entry><entry>Other error. This is typically an
-indication of misuse of the &odr; system by the programmer, and also
-that the diagnostic system isn't as good as it should be, yet.</entry>
-</row>
-</tbody>
-</tgroup>
-</table>
-
-<para>
-The character string array
-</para>
-
-<synopsis>
-  char *odr_errlist&lsqb;&rsqb;
-</synopsis>
-
-<para>
-can be indexed by the error code to obtain a human-readable
-representation of the problem.
-</para>
-
-</sect2>
-<sect2><title>Summary and Synopsis</title>
-
-<synopsis>
-#include &lt;odr.h>
-
-ODR odr_createmem(int direction);
-
-void odr_destroy(ODR o);
-
-void odr_reset(ODR o);
-
-char *odr_getbuf(ODR o, int *len);
-
-void odr_setbuf(ODR o, char *buf, int len);
-
-void *odr_malloc(ODR o, int size);
-
-ODR_MEM odr_extract_mem(ODR o);
-
-void odr_release_mem(ODR_MEM r);
-
-int odr_geterror(ODR o);
-
-void odr_perror(char *message);
-
-extern char *odr_errlist[];
-</synopsis>
-
-</sect2>
-</sect1>
-
-<sect1><title id="odr-prog">Programming with ODR</title>
-
-<para>
-The API of &odr; is designed to reflect the structure of ASN.1, rather
-than BER itself. Future releases may be able to represent data in
-other external forms.
-</para>
-
-<para>
-The interface is based loosely on that of the Sun Microsystems XDR routines.
-Specifically, each function which corresponds to an ASN.1 primitive
-type has a dual function. Depending on the settings of the ODR
-stream which is supplied as a parameter, the function may be used
-either to encode or decode data. The functions that can be built
-using these primitive functions, to represent more complex datatypes, share
-this quality. The result is that you only have to enter the definition
-for a type once - and you have the functionality of encoding, decoding
-(and pretty-printing) all in one unit. The resulting C source code is
-quite compact, and is a pretty straightforward representation of the
-source ASN.1 specification. Although no ASN.1 compiler is supplied
-with &odr; at this time, it shouldn't be too difficult to write one, or
-perhaps even to adapt an existing compiler to output &odr; routines
-(not surprisingly, writing encoders/decoders using &odr; turns out
-to be boring work).
-</para>
-
-<para>
-In many cases, the model of the XDR functions works quite well in this
-role.
-In others, it is less elegant. Most of the hassle comes from the optional
-SEQUENCE memebers which don't exist in XDR.
-</para>
-
-<sect2><title>The Primitive ASN.1 Types</title>
-
-<para>
-ASN.1 defines a number of primitive types (many of which correspond
-roughly to primitive types in structured programming languages, such as C).
-</para>
-
-<sect3><title>INTEGER</title>
-
-<para>
-The &odr; function for encoding or decoding (or printing) the ASN.1
-INTEGER type looks like this:
-</para>
-
-<synopsis>
-  int odr_integer(ODR o, int **p, int optional, const char *name);
-</synopsis>
-
-<para>
-(we don't allow values that can't be contained in a C integer.)
-</para>
-
-<para>
-This form is typical of the primitive &odr; functions. They are named
-after the type of data that they encode or decode. They take an &odr;
-stream, an indirect reference to the type in question, and an
-<literal>optional</literal> flag (corresponding to the OPTIONAL keyword
-of ASN.1) as parameters. They all return an integer value of either one
-or zero.
-When you use the primitive functions to construct encoders for complex
-types of your own, you should follow this model as well. This
-ensures that your new types can be reused as elements in yet more
-complex types.
-</para>
-
-<para>
-The <literal>o</literal> parameter should obviously refer to a properly
-initialized &odr; stream of the right type (encoding/decoding/printing)
-for the operation that you wish to perform.
-</para>
-
-<para>
-When encoding or printing, the function first looks at
-<literal>* p</literal>. If <literal>* p</literal> (the pointer pointed
-to by <literal>p</literal>) is a null pointer, this is taken to mean that
-the data element is absent. If the <literal>optional</literal> parameter
-is nonzero, the function will return one (signifying success) without
-any further processing. If the <literal>optional</literal> is zero, an
-internal error flag is set in the &odr; stream, and the function will
-return 0. No further operations can be carried out on the stream without
-a call to the function <function>odr_reset()</function>.
-</para>
-
-<para>
-If <literal>*p</literal> is not a null pointer, it is expected to
-point to an instance of the data type. The data will be subjected to
-the encoding rules, and the result will be placed in the buffer held
-by the &odr; stream.
-</para>
-
-<para>
-The other ASN.1 primitives have similar functions that operate in
-similar manners:
-</para>
-</sect3>
-<sect3><title>BOOLEAN</title>
-
-<synopsis>
-  int odr_bool(ODR o, bool_t **p, int optional, const char *name);
-</synopsis>
-
-</sect3>
-<sect3><title>REAL</title>
-
-<para>
-Not defined.
-</para>
-
-</sect3>
-<sect3><title>NULL</title>
-
-<synopsis>
-  int odr_null(ODR o, bool_t **p, int optional, const char *name);
-</synopsis>
-
-<para>
-In this case, the value of **p is not important. If <literal>*p</literal>
-is different from the null pointer, the null value is present, otherwise
-it's absent.
-</para>
-
-</sect3>
-<sect3><title>OCTET STRING</title>
-
-<synopsis>
-  typedef struct odr_oct
-  {
-      unsigned char *buf;
-      int len;
-      int size;
-  } Odr_oct;
-
-  int odr_octetstring(ODR o, Odr_oct **p, int optional, const char *name);
-</synopsis>
-
-<para>
-The <literal>buf</literal> field should point to the character array
-that holds the octetstring. The <literal>len</literal> field holds the
-actual length, while the <literal>size</literal> field gives the size
-of the allocated array (not of interest to you, in most cases).
-The character array need not be null terminated.
-</para>
-
-<para>
-To make things a little easier, an alternative is given for string
-types that are not expected to contain embedded NULL characters (eg.
-VisibleString):
-</para>
-
-<synopsis>
-  int odr_cstring(ODR o, char **p, int optional, const char *name);
-</synopsis>
-
-<para>
-Which encoded or decodes between OCTETSTRING representations and
-null-terminates C strings.
-</para>
-
-<para>
-Functions are provided for the derived string types, eg:
-</para>
-
-<synopsis>
-  int odr_visiblestring(ODR o, char **p, int optional, const char *name);
-</synopsis>
-
-</sect3>
-<sect3><title>BIT STRING</title>
-
-<synopsis>
-  int odr_bitstring(ODR o, Odr_bitmask **p, int optional, const char *name);
-</synopsis>
-
-<para>
-The opaque type <literal>Odr_bitmask</literal> is only suitable for
-holding relatively brief bit strings, eg. for options fields, etc.
-The constant <literal>ODR_BITMASK_SIZE</literal> multiplied by 8
-gives the maximum possible number of bits.
-</para>
-
-<para>
-A set of macros are provided for manipulating the
-<literal>Odr_bitmask</literal> type:
-</para>
-
-<synopsis>
-  void ODR_MASK_ZERO(Odr_bitmask *b);
-
-  void ODR_MASK_SET(Odr_bitmask *b, int bitno);
-
-  void ODR_MASK_CLEAR(Odr_bitmask *b, int bitno);
-
-  int ODR_MASK_GET(Odr_bitmask *b, int bitno);
-</synopsis>
-
-<para>
-The functions are modelled after the manipulation functions that
-accompany the <literal>fd_set</literal> type used by the
-<function>select(2)</function> call.
-<literal>ODR_MASK_ZERO</literal> should always be called first on a
-new bitmask, to initialize the bits to zero.
-</para>
-</sect3>
-
-<sect3><title>OBJECT IDENTIFIER</title>
-
-<synopsis>
+    <table frame="top"><title>ODR Error codes</title>
+     <tgroup cols="2">
+      <thead>
+       <row>
+       <entry>code</entry>
+       <entry>Description</entry>
+       </row>
+      </thead>
+      <tbody>
+       <row>
+       <entry>OMEMORY</entry><entry>Memory allocation failed.</entry>
+       </row>
+
+       <row>
+       <entry>OSYSERR</entry><entry>A system- or library call has failed.
+        The standard diagnostic variable <literal>errno</literal> should be
+        examined to determine the actual error.</entry>
+       </row>
+
+       <row>
+       <entry>OSPACE</entry><entry>No more space for encoding.
+        This will only occur when the user has explicitly provided a
+        buffer for an encoding stream without allowing the system to
+        allocate more space.</entry>
+       </row>
+
+       <row>
+       <entry>OREQUIRED</entry><entry>This is a common protocol error; A
+        required data element was missing during encoding or decoding.</entry>
+       </row>
+
+       <row>
+       <entry>OUNEXPECTED</entry><entry>An unexpected data element was
+        found during decoding.</entry>
+       </row>
+
+       <row><entry>OOTHER</entry><entry>Other error. This is typically an
+        indication of misuse of the &odr; system by the programmer, and also
+        that the diagnostic system isn't as good as it should be, yet.</entry>
+       </row>
+      </tbody>
+     </tgroup>
+    </table>
+
+    <para>
+     The character string array
+    </para>
+
+    <synopsis>
+     char *odr_errlist&lsqb;&rsqb;
+    </synopsis>
+
+    <para>
+     can be indexed by the error code to obtain a human-readable
+     representation of the problem.
+    </para>
+
+   </sect2>
+   <sect2><title>Summary and Synopsis</title>
+
+    <synopsis>
+     #include &lt;odr.h>
+
+     ODR odr_createmem(int direction);
+
+     void odr_destroy(ODR o);
+
+     void odr_reset(ODR o);
+
+     char *odr_getbuf(ODR o, int *len);
+
+     void odr_setbuf(ODR o, char *buf, int len);
+
+     void *odr_malloc(ODR o, int size);
+
+     ODR_MEM odr_extract_mem(ODR o);
+
+     void odr_release_mem(ODR_MEM r);
+
+     int odr_geterror(ODR o);
+
+     void odr_perror(char *message);
+
+     extern char *odr_errlist[];
+    </synopsis>
+
+   </sect2>
+  </sect1>
+
+  <sect1><title id="odr-prog">Programming with ODR</title>
+
+   <para>
+    The API of &odr; is designed to reflect the structure of ASN.1, rather
+    than BER itself. Future releases may be able to represent data in
+    other external forms.
+   </para>
+
+   <para>
+    The interface is based loosely on that of the Sun Microsystems XDR routines.
+    Specifically, each function which corresponds to an ASN.1 primitive
+    type has a dual function. Depending on the settings of the ODR
+    stream which is supplied as a parameter, the function may be used
+    either to encode or decode data. The functions that can be built
+    using these primitive functions, to represent more complex datatypes, share
+    this quality. The result is that you only have to enter the definition
+    for a type once - and you have the functionality of encoding, decoding
+    (and pretty-printing) all in one unit. The resulting C source code is
+    quite compact, and is a pretty straightforward representation of the
+    source ASN.1 specification. Although no ASN.1 compiler is supplied
+    with &odr; at this time, it shouldn't be too difficult to write one, or
+    perhaps even to adapt an existing compiler to output &odr; routines
+    (not surprisingly, writing encoders/decoders using &odr; turns out
+    to be boring work).
+   </para>
+
+   <para>
+    In many cases, the model of the XDR functions works quite well in this
+    role.
+    In others, it is less elegant. Most of the hassle comes from the optional
+    SEQUENCE memebers which don't exist in XDR.
+   </para>
+
+   <sect2><title>The Primitive ASN.1 Types</title>
+
+    <para>
+     ASN.1 defines a number of primitive types (many of which correspond
+     roughly to primitive types in structured programming languages, such as C).
+    </para>
+
+    <sect3><title>INTEGER</title>
+
+     <para>
+      The &odr; function for encoding or decoding (or printing) the ASN.1
+      INTEGER type looks like this:
+     </para>
+
+     <synopsis>
+int odr_integer(ODR o, int **p, int optional, const char *name);
+     </synopsis>
+
+     <para>
+      (we don't allow values that can't be contained in a C integer.)
+     </para>
+
+     <para>
+      This form is typical of the primitive &odr; functions. They are named
+      after the type of data that they encode or decode. They take an &odr;
+      stream, an indirect reference to the type in question, and an
+      <literal>optional</literal> flag (corresponding to the OPTIONAL keyword
+      of ASN.1) as parameters. They all return an integer value of either one
+      or zero.
+      When you use the primitive functions to construct encoders for complex
+      types of your own, you should follow this model as well. This
+      ensures that your new types can be reused as elements in yet more
+      complex types.
+     </para>
+
+     <para>
+      The <literal>o</literal> parameter should obviously refer to a properly
+      initialized &odr; stream of the right type (encoding/decoding/printing)
+      for the operation that you wish to perform.
+     </para>
+
+     <para>
+      When encoding or printing, the function first looks at
+      <literal>* p</literal>. If <literal>* p</literal> (the pointer pointed
+      to by <literal>p</literal>) is a null pointer, this is taken to mean that
+      the data element is absent. If the <literal>optional</literal> parameter
+      is nonzero, the function will return one (signifying success) without
+      any further processing. If the <literal>optional</literal> is zero, an
+      internal error flag is set in the &odr; stream, and the function will
+      return 0. No further operations can be carried out on the stream without
+      a call to the function <function>odr_reset()</function>.
+     </para>
+
+     <para>
+      If <literal>*p</literal> is not a null pointer, it is expected to
+      point to an instance of the data type. The data will be subjected to
+      the encoding rules, and the result will be placed in the buffer held
+      by the &odr; stream.
+     </para>
+
+     <para>
+      The other ASN.1 primitives have similar functions that operate in
+      similar manners:
+     </para>
+    </sect3>
+    <sect3><title>BOOLEAN</title>
+
+     <synopsis>
+int odr_bool(ODR o, bool_t **p, int optional, const char *name);
+     </synopsis>
+
+    </sect3>
+    <sect3><title>REAL</title>
+
+     <para>
+      Not defined.
+     </para>
+
+    </sect3>
+    <sect3><title>NULL</title>
+
+     <synopsis>
+int odr_null(ODR o, bool_t **p, int optional, const char *name);
+     </synopsis>
+
+     <para>
+      In this case, the value of **p is not important. If <literal>*p</literal>
+      is different from the null pointer, the null value is present, otherwise
+      it's absent.
+     </para>
+
+    </sect3>
+    <sect3><title>OCTET STRING</title>
+
+     <synopsis>
+typedef struct odr_oct
+{
+    unsigned char *buf;
+    int len;
+    int size;
+} Odr_oct;
+
+int odr_octetstring(ODR o, Odr_oct **p, int optional,
+                    const char *name);
+     </synopsis>
+
+     <para>
+      The <literal>buf</literal> field should point to the character array
+      that holds the octetstring. The <literal>len</literal> field holds the
+      actual length, while the <literal>size</literal> field gives the size
+      of the allocated array (not of interest to you, in most cases).
+      The character array need not be null terminated.
+     </para>
+
+     <para>
+      To make things a little easier, an alternative is given for string
+      types that are not expected to contain embedded NULL characters (eg.
+      VisibleString):
+     </para>
+
+     <synopsis>
+      int odr_cstring(ODR o, char **p, int optional, const char *name);
+     </synopsis>
+
+     <para>
+      Which encoded or decodes between OCTETSTRING representations and
+      null-terminates C strings.
+     </para>
+
+     <para>
+      Functions are provided for the derived string types, eg:
+     </para>
+
+     <synopsis>
+int odr_visiblestring(ODR o, char **p, int optional,
+                      const char *name);
+     </synopsis>
+
+    </sect3>
+    <sect3><title>BIT STRING</title>
+
+     <synopsis>
+int odr_bitstring(ODR o, Odr_bitmask **p, int optional,
+                  const char *name);
+     </synopsis>
+
+     <para>
+      The opaque type <literal>Odr_bitmask</literal> is only suitable for
+      holding relatively brief bit strings, eg. for options fields, etc.
+      The constant <literal>ODR_BITMASK_SIZE</literal> multiplied by 8
+      gives the maximum possible number of bits.
+     </para>
+
+     <para>
+      A set of macros are provided for manipulating the
+      <literal>Odr_bitmask</literal> type:
+     </para>
+
+     <synopsis>
+void ODR_MASK_ZERO(Odr_bitmask *b);
+
+void ODR_MASK_SET(Odr_bitmask *b, int bitno);
+
+void ODR_MASK_CLEAR(Odr_bitmask *b, int bitno);
+
+int ODR_MASK_GET(Odr_bitmask *b, int bitno);
+     </synopsis>
+
+     <para>
+      The functions are modelled after the manipulation functions that
+      accompany the <literal>fd_set</literal> type used by the
+      <function>select(2)</function> call.
+      <literal>ODR_MASK_ZERO</literal> should always be called first on a
+      new bitmask, to initialize the bits to zero.
+     </para>
+    </sect3>
+
+    <sect3><title>OBJECT IDENTIFIER</title>
+
+     <synopsis>
 int odr_oid(ODR o, Odr_oid **p, int optional, const char *name);
-</synopsis>
-
-<para>
-The C OID represenation is simply an array of integers, terminated by
-the value -1 (the <literal>Odr_oid</literal> type is synonymous with
-the <literal>int</literal> type).
-We suggest that you use the OID database module (see section
-<link linkend="oid">Object Identifiers</link>) to handle object identifiers
-in your application.
-</para>
-
-</sect3>
-</sect2>
-<sect2><title id="tag-prim">Tagging Primitive Types</title>
-
-<para>
-The simplest way of tagging a type is to use the
-<function>odr_implicit_tag()</function> or 
-<function>odr_explicit_tag()</function> macros:
-</para>
-
-<synopsis>
-  int odr_implicit_tag(ODR o, Odr_fun fun, int class, int tag, int
-                       optional, const char *name);
-
-  int odr_explicit_tag(ODR o, Odr_fun fun, int class, int tag,
-                       int optional, const char *name);
-</synopsis>
-
-<para>
-To create a type derived from the integer type by implicit tagging, you
-might write:
-</para>
-
-<screen>
-  MyInt ::= &lsqb;210&rsqb; IMPLICIT INTEGER
-</screen>
-
-<para>
-In the &odr; system, this would be written like:
-</para>
-
-<screen>
+     </synopsis>
+
+     <para>
+      The C OID represenation is simply an array of integers, terminated by
+      the value -1 (the <literal>Odr_oid</literal> type is synonymous with
+      the <literal>int</literal> type).
+      We suggest that you use the OID database module (see section
+      <link linkend="oid">Object Identifiers</link>) to handle object identifiers
+      in your application.
+     </para>
+
+    </sect3>
+   </sect2>
+   <sect2><title id="tag-prim">Tagging Primitive Types</title>
+
+    <para>
+     The simplest way of tagging a type is to use the
+     <function>odr_implicit_tag()</function> or 
+     <function>odr_explicit_tag()</function> macros:
+    </para>
+
+    <synopsis>
+int odr_implicit_tag(ODR o, Odr_fun fun, int class, int tag,
+                     int optional, const char *name);
+
+int odr_explicit_tag(ODR o, Odr_fun fun, int class, int tag,
+                     int optional, const char *name);
+    </synopsis>
+
+    <para>
+     To create a type derived from the integer type by implicit tagging, you
+     might write:
+    </para>
+
+    <screen>
+     MyInt ::= &lsqb;210&rsqb; IMPLICIT INTEGER
+    </screen>
+
+    <para>
+     In the &odr; system, this would be written like:
+    </para>
+
+    <screen>
 int myInt(ODR o, int **p, int optional, const char *name)
 {
     return odr_implicit_tag(o, odr_integer, p,
-                   ODR_CONTEXT, 210, optional, name);
+                           ODR_CONTEXT, 210, optional, name);
 }
-</screen>
-
-<para>
-The function <function>myInt()</function> can then be used like any of
-the primitive functions provided by &odr;. Note that the behavior of
-<function>odr_explicit()</function>
-and <function>odr_implicit()</function> macros
-act exactly the same as the functions they are applied to - they
-respond to error conditions, etc, in the same manner - they
-simply have three extra parameters. The class parameter may
-take one of the values: <literal>ODR_CONTEXT</literal>,
-<literal>ODR_PRIVATE</literal>, <literal>ODR_UNIVERSAL</literal>, or
-<literal>/ODR_APPLICATION</literal>.
-</para>
-
-</sect2>
-<sect2><title>Constructed Types</title>
-
-<para>
-Constructed types are created by combining primitive types. The
-&odr; system only implements the SEQUENCE and SEQUENCE OF constructions
-(although adding the rest of the container types should be simple
-enough, if the need arises).
-</para>
-
-<para>
-For implementing SEQUENCEs, the functions
-</para>
-
-<synopsis>
-  int odr_sequence_begin(ODR o, void *p, int size, const char *name);
-  int odr_sequence_end(ODR o);
-</synopsis>
-
-<para>
-are provided.
-</para>
-
-<para>
-The <function>odr_sequence_begin()</function> function should be
-called in the beginning of a function that implements a SEQUENCE type.
-Its parameters are the &odr; stream, a pointer (to a pointer to the type
-you're implementing), and the <literal>size</literal> of the type
-(typically a C structure). On encoding, it returns 1 if
-<literal>* p</literal> is a null pointer. The <literal>size</literal>
-parameter is ignored. On decoding, it returns 1 if the type is found in
-the data stream. <literal>size</literal> bytes of memory are allocated,
-and <literal>*p</literal> is set to point to this space.
-<function>odr_sequence_end()</function> is called at the end of the
-complex function. Assume that a type is defined like this:
-</para>
-
-<screen>
-  MySequence ::= SEQUENCE {
-      intval INTEGER,
-      boolval BOOLEAN OPTIONAL }
-</screen>
+    </screen>
+
+    <para>
+     The function <function>myInt()</function> can then be used like any of
+     the primitive functions provided by &odr;. Note that the behavior of
+     <function>odr_explicit()</function>
+     and <function>odr_implicit()</function> macros
+     act exactly the same as the functions they are applied to - they
+     respond to error conditions, etc, in the same manner - they
+     simply have three extra parameters. The class parameter may
+     take one of the values: <literal>ODR_CONTEXT</literal>,
+     <literal>ODR_PRIVATE</literal>, <literal>ODR_UNIVERSAL</literal>, or
+     <literal>/ODR_APPLICATION</literal>.
+    </para>
+
+   </sect2>
+   <sect2><title>Constructed Types</title>
+
+    <para>
+     Constructed types are created by combining primitive types. The
+      &odr; system only implements the SEQUENCE and SEQUENCE OF constructions
+     (although adding the rest of the container types should be simple
+     enough, if the need arises).
+    </para>
+
+    <para>
+     For implementing SEQUENCEs, the functions
+    </para>
+
+    <synopsis>
+int odr_sequence_begin(ODR o, void *p, int size, const char *name);
+int odr_sequence_end(ODR o);
+    </synopsis>
+
+    <para>
+     are provided.
+    </para>
+
+    <para>
+     The <function>odr_sequence_begin()</function> function should be
+     called in the beginning of a function that implements a SEQUENCE type.
+     Its parameters are the &odr; stream, a pointer (to a pointer to the type
+     you're implementing), and the <literal>size</literal> of the type
+     (typically a C structure). On encoding, it returns 1 if
+     <literal>* p</literal> is a null pointer. The <literal>size</literal>
+     parameter is ignored. On decoding, it returns 1 if the type is found in
+     the data stream. <literal>size</literal> bytes of memory are allocated,
+     and <literal>*p</literal> is set to point to this space.
+     <function>odr_sequence_end()</function> is called at the end of the
+     complex function. Assume that a type is defined like this:
+    </para>
+
+    <screen>
+MySequence ::= SEQUENCE {
+     intval INTEGER,
+     boolval BOOLEAN OPTIONAL
+}
+    </screen>
 
-<para>
-The corresponding &odr; encoder/decoder function and the associated data
-structures could be written like this:
-</para>
+    <para>
+     The corresponding &odr; encoder/decoder function and the associated data
+     structures could be written like this:
+    </para>
 
-<screen>
-  typedef struct MySequence
-  {
+    <screen>
+typedef struct MySequence
+{
     int *intval;
     bool_t *boolval;
-  } MySequence;
-    
-  int mySequence(ODR o, MySequence **p, int optional, const char *name)
-  {
+} MySequence;
+     
+int mySequence(ODR o, MySequence **p, int optional, const char *name)
+{
     if (odr_sequence_begin(o, p, sizeof(**p), name) == 0)
         return optional &amp;&amp; odr_ok(o);
     return
         odr_integer(o, &amp;(*p)->intval, 0, "intval") &amp;&amp;
         odr_bool(o, &amp;(*p)->boolval, 1, "boolval") &amp;&amp;
         odr_sequence_end(o);
-  }
-</screen>
-
-<para>
-Note the 1 in the call to <function>odr_bool()</function>, to mark
-that the sequence member is optional.
-If either of the member types had been tagged, the macros
-<function>odr_implicit()</function> or <function>odr_explicit()</function>
-could have been used.
-The new function can be used exactly like the standard functions provided
-with &odr;. It will encode, decode or pretty-print a data value of the
-<literal>MySequence</literal> type. We like to name types with an
-initial capital, as done in ASN.1 definitions, and to name the
-corresponding function with the first character of the name in lower case.
-You could, of course, name your structures, types, and functions any way
-you please - as long as you're consistent, and your code is easily readable.
-<literal>odr_ok</literal> is just that - a predicate that returns the
-state of the stream. It is used to ensure that the behaviour of the new
-type is compatible with the interface of the primitive types.
-</para>
-
-</sect2>
-<sect2><title>Tagging Constructed Types</title>
-
-<note>
-<para>
-See section <link linkend="tag-prim">Tagging Primitive types</link>
-for information on how to tag the primitive types, as well as types
-that are already defined.
-</para>
-</note>
-
-<sect3><title>Implicit Tagging</title>
-
-<para>
-Assume the type above had been defined as
-</para>
-
-<screen>
-  MySequence ::= &lsqb;10&rsqb; IMPLICIT SEQUENCE {
-     intval INTEGER,
-     boolval BOOLEAN OPTIONAL }
-</screen>
-
-<para>
-You would implement this in &odr; by calling the function
-</para>
-
-<synopsis>
-  int odr_implicit_settag(ODR o, int class, int tag);
-</synopsis>
-
-<para>
-which overrides the tag of the type immediately following it. The
-macro <function>odr_implicit()</function> works by calling
-<function>odr_implicit_settag()</function> immediately
-before calling the function pointer argument.
-Your type function could look like this:
-</para>
-
-<screen>
-  int mySequence(ODR o, MySequence **p, int optional, const char *name)
-  {
+}
+
+    </screen>
+
+    <para>
+     Note the 1 in the call to <function>odr_bool()</function>, to mark
+     that the sequence member is optional.
+     If either of the member types had been tagged, the macros
+     <function>odr_implicit()</function> or <function>odr_explicit()</function>
+     could have been used.
+     The new function can be used exactly like the standard functions provided
+     with &odr;. It will encode, decode or pretty-print a data value of the
+     <literal>MySequence</literal> type. We like to name types with an
+     initial capital, as done in ASN.1 definitions, and to name the
+     corresponding function with the first character of the name in lower case.
+     You could, of course, name your structures, types, and functions any way
+     you please - as long as you're consistent, and your code is easily readable.
+     <literal>odr_ok</literal> is just that - a predicate that returns the
+     state of the stream. It is used to ensure that the behaviour of the new
+     type is compatible with the interface of the primitive types.
+    </para>
+
+   </sect2>
+   <sect2><title>Tagging Constructed Types</title>
+
+    <note>
+     <para>
+      See section <link linkend="tag-prim">Tagging Primitive types</link>
+      for information on how to tag the primitive types, as well as types
+      that are already defined.
+     </para>
+    </note>
+
+    <sect3><title>Implicit Tagging</title>
+
+     <para>
+      Assume the type above had been defined as
+     </para>
+
+     <screen>
+MySequence ::= &lsqb;10&rsqb; IMPLICIT SEQUENCE {
+      intval INTEGER,
+      boolval BOOLEAN OPTIONAL
+}
+     </screen>
+
+     <para>
+      You would implement this in &odr; by calling the function
+     </para>
+
+     <synopsis>
+int odr_implicit_settag(ODR o, int class, int tag);
+     </synopsis>
+
+     <para>
+      which overrides the tag of the type immediately following it. The
+      macro <function>odr_implicit()</function> works by calling
+      <function>odr_implicit_settag()</function> immediately
+      before calling the function pointer argument.
+      Your type function could look like this:
+     </para>
+
+     <screen>
+int mySequence(ODR o, MySequence **p, int optional, const char *name)
+{
     if (odr_implicit_settag(o, ODR_CONTEXT, 10) == 0 ||
         odr_sequence_begin(o, p, sizeof(**p), name) == 0)
         return optional &amp;&amp; odr_ok(o);
     return
         odr_integer(o, &amp;(*p)->intval, 0, "intval") &amp;&amp;
         odr_bool(o, &amp;(*p)->boolval, 1, "boolval") &amp;&amp;
-       odr_sequence_end(o);
+        odr_sequence_end(o);
 }
-</screen>
+     </screen>
 
-<para>
-The definition of the structure <literal>MySequence</literal> would be
-the same.
-</para>
-</sect3>
+     <para>
+      The definition of the structure <literal>MySequence</literal> would be
+      the same.
+     </para>
+    </sect3>
 
-<sect3><title>Explicit Tagging</title>
+    <sect3><title>Explicit Tagging</title>
 
-<para>
-Explicit tagging of constructed types is a little more complicated,
-since you are in effect adding a level of construction to the data.
-</para>
+     <para>
+      Explicit tagging of constructed types is a little more complicated,
+      since you are in effect adding a level of construction to the data.
+     </para>
 
-<para>
-Assume the definition:
-</para>
+     <para>
+      Assume the definition:
+     </para>
 
-<screen>
-  MySequence ::= &lsqb;10&rsqb; IMPLICIT SEQUENCE {
-      intval INTEGER,
-      boolval BOOLEAN OPTIONAL }
-</screen>
-
-<para>
-Since the new type has an extra level of construction, two new functions
-are needed to encapsulate the base type:
-</para>
-
-<synopsis>
-  int odr_constructed_begin(ODR o, void *p, int class, int tag,
-                            const char *name);
-
-  int odr_constructed_end(ODR o);
-</synopsis>
-
-<para>
-Assume that the IMPLICIT in the type definition above were replaced
-with EXPLICIT (or that the IMPLICIT keyword were simply deleted, which
-would be equivalent). The structure definition would look the same,
-but the function would look like this:
-</para>
-
-<screen>
-  int mySequence(ODR o, MySequence **p, int optional, const char *name)
-  {
+     <screen>
+MySequence ::= &lsqb;10&rsqb; IMPLICIT SEQUENCE {
+   intval INTEGER,
+   boolval BOOLEAN OPTIONAL
+}
+     </screen>
+
+     <para>
+      Since the new type has an extra level of construction, two new functions
+      are needed to encapsulate the base type:
+     </para>
+
+     <synopsis>
+      int odr_constructed_begin(ODR o, void *p, int class, int tag,
+      const char *name);
+
+      int odr_constructed_end(ODR o);
+     </synopsis>
+
+     <para>
+      Assume that the IMPLICIT in the type definition above were replaced
+      with EXPLICIT (or that the IMPLICIT keyword were simply deleted, which
+      would be equivalent). The structure definition would look the same,
+      but the function would look like this:
+     </para>
+
+     <screen>
+int mySequence(ODR o, MySequence **p, int optional, const char *name)
+{
     if (odr_constructed_begin(o, p, ODR_CONTEXT, 10, name) == 0)
         return optional &amp;&amp; odr_ok(o);
     if (o->direction == ODR_DECODE)
         *p = odr_malloc(o, sizeof(**p));
     if (odr_sequence_begin(o, p, sizeof(**p), 0) == 0)
     {
-      *p = 0; /* this is almost certainly a protocol error */
-      return 0;
+        *p = 0; /* this is almost certainly a protocol error */
+        return 0;
     }
     return
         odr_integer(o, &amp;(*p)->intval, 0, "intval") &amp;&amp;
         odr_bool(o, &amp;(*p)->boolval, 1, "boolval") &amp;&amp;
         odr_sequence_end(o) &amp;&amp;
         odr_constructed_end(o);
-  }
-</screen>
-
-<para>
-Notice that the interface here gets kind of nasty. The reason is
-simple: Explicitly tagged, constructed types are fairly rare in
-the protocols that we care about, so the
-aesthetic annoyance (not to mention the dangers of a cluttered
-interface) is less than the time that would be required to develop a
-better interface. Nevertheless, it is far from satisfying, and it's a
-point that will be worked on in the future. One option for you would
-be to simply apply the <function>odr_explicit()</function> macro to
-the first function, and not
-have to worry about <function>odr_constructed_*</function> yourself.
-Incidentally, as you might have guessed, the
-<function>odr_sequence_</function> functions are themselves
-implemented using the <function>/odr_constructed_</function> functions.
-</para>
-
-</sect3>
-</sect2>
-<sect2><title>SEQUENCE OF</title>
-
-<para>
-To handle sequences (arrays) of a apecific type, the function
-</para>
-
-<synopsis>
-  int odr_sequence_of(ODR o, int (*fun)(ODR o, void *p, int optional),
-                      void *p, int *num, const char *name);
-</synopsis>
-
-<para>
-The <literal>fun</literal> parameter is a pointer to the decoder/encoder
-function of the type. <literal>p</literal> is a pointer to an array of
-pointers to your type. <literal>num</literal> is the number of elements
-in the array.
-</para>
-
-<para>
-Assume a type
-</para>
-
-<screen>
-  MyArray ::= SEQUENCE OF INTEGER
-</screen>
-
-<para>
-The C representation might be
-</para>
-
-<screen>
-  typedef struct MyArray
-  {
+}
+     </screen>
+
+     <para>
+      Notice that the interface here gets kind of nasty. The reason is
+      simple: Explicitly tagged, constructed types are fairly rare in
+      the protocols that we care about, so the
+      aesthetic annoyance (not to mention the dangers of a cluttered
+      interface) is less than the time that would be required to develop a
+      better interface. Nevertheless, it is far from satisfying, and it's a
+      point that will be worked on in the future. One option for you would
+      be to simply apply the <function>odr_explicit()</function> macro to
+      the first function, and not
+      have to worry about <function>odr_constructed_*</function> yourself.
+      Incidentally, as you might have guessed, the
+      <function>odr_sequence_</function> functions are themselves
+      implemented using the <function>/odr_constructed_</function> functions.
+     </para>
+
+    </sect3>
+   </sect2>
+   <sect2><title>SEQUENCE OF</title>
+
+    <para>
+     To handle sequences (arrays) of a apecific type, the function
+    </para>
+
+    <synopsis>
+int odr_sequence_of(ODR o, int (*fun)(ODR o, void *p, int optional),
+                    void *p, int *num, const char *name);
+    </synopsis>
+
+    <para>
+     The <literal>fun</literal> parameter is a pointer to the decoder/encoder
+     function of the type. <literal>p</literal> is a pointer to an array of
+     pointers to your type. <literal>num</literal> is the number of elements
+     in the array.
+    </para>
+
+    <para>
+     Assume a type
+    </para>
+
+    <screen>
+MyArray ::= SEQUENCE OF INTEGER
+    </screen>
+
+    <para>
+     The C representation might be
+    </para>
+
+    <screen>
+typedef struct MyArray
+{
     int num_elements;
     int **elements;
-  } MyArray;
-</screen>
+} MyArray;
+    </screen>
 
-<para>
-And the function might look like
-</para>
+    <para>
+     And the function might look like
+    </para>
 
-<screen>
-  int myArray(ODR o, MyArray **p, int optional, const char *name)
-  {
+    <screen>
+int myArray(ODR o, MyArray **p, int optional, const char *name)
+{
     if (o->direction == ODR_DECODE)
         *p = odr_malloc(o, sizeof(**p));
     if (odr_sequence_of(o, odr_integer, &amp;(*p)->elements,
-       &amp;(*p)->num_elements, name))
-       return 1;
+        &amp;(*p)->num_elements, name))
+        return 1;
     *p = 0;
-    return optional &amp;&amp; odr_ok(o);
-  }
-</screen>
-
-</sect2>
-<sect2><title>CHOICE Types</title>
-
-<para>
-The choice type is used fairly often in some ASN.1 definitions, so
-some work has gone into streamlining its interface.
-</para>
-
-<para>
-CHOICE types are handled by the function:
-</para>
-
-<synopsis>
-  int odr_choice(ODR o, Odr_arm arm&lsqb;&rsqb;, void *p, void *whichp,
-                 const char *name);
-</synopsis>
-
-<para>
-The <literal>arm</literal> array is used to describe each of the possible
-types that the CHOICE type may assume. Internally in your application,
-the CHOICE type is represented as a discriminated union. That is, a C union
-accompanied by an integer (or enum) identifying the active 'arm' of
-the union. <literal>whichp</literal> is a pointer to the union
-discriminator. When encoding, it is examined to determine the current
-type. When decoding, it is set to reference the type that was found in
-the input stream.
-</para>
-
-<para>
-The Odr_arm type is defined thus:
-</para>
-
-<screen>
-  typedef struct odr_arm
-  {
+        return optional &amp;&amp; odr_ok(o);
+}
+    </screen>
+
+   </sect2>
+   <sect2><title>CHOICE Types</title>
+
+    <para>
+     The choice type is used fairly often in some ASN.1 definitions, so
+     some work has gone into streamlining its interface.
+    </para>
+
+    <para>
+     CHOICE types are handled by the function:
+    </para>
+
+    <synopsis>
+     int odr_choice(ODR o, Odr_arm arm&lsqb;&rsqb;, void *p, void *whichp,
+     const char *name);
+    </synopsis>
+
+    <para>
+     The <literal>arm</literal> array is used to describe each of the possible
+     types that the CHOICE type may assume. Internally in your application,
+     the CHOICE type is represented as a discriminated union. That is, a
+     C union accompanied by an integer (or enum) identifying the active
+     'arm' of the union.
+     <literal>whichp</literal> is a pointer to the union discriminator.
+     When encoding, it is examined to determine the current type.
+     When decoding, it is set to reference the type that was found in
+     the input stream.
+    </para>
+
+    <para>
+     The Odr_arm type is defined thus:
+    </para>
+
+    <screen>
+typedef struct odr_arm
+{
     int tagmode;
     int class;
     int tag;
     int which;
     Odr_fun fun;
     char *name;
-  } Odr_arm;
-</screen>
-
-<para>
-The interpretation of the fields are:
-</para>
-
-<variablelist>
-<varlistentry><term>tagmode</term>
- <listitem><para>Either <literal>ODR_IMPLICIT</literal>,
-<literal>ODR_EXPLICIT</literal>, or <literal>ODR_NONE</literal> (-1) to mark
-no tagging.</para></listitem>
-</varlistentry>
-
-<varlistentry><term>which</term>
- <listitem><para>The value of the discriminator that corresponds to
-this CHOICE element. Typically, it will be a &num;defined constant, or
-an enum member.</para></listitem>
-</varlistentry>
-
-<varlistentry><term>fun</term>
- <listitem><para>A pointer to a function that implements the type of
-the CHOICE member. It may be either a standard &odr; type or a type
-defined by yourself.</para></listitem>
-</varlistentry>
-
-<varlistentry><term>name</term>
- <listitem><para>Name of tag.</para></listitem>
-</varlistentry>
-</variablelist>
-
-<para>
-A handy way to prepare the array for use by the
-<function>odr_choice()</function> function is to
-define it as a static, initialized array in the beginning of your
-decoding/encoding function. Assume the type definition:
-</para>
-
-<screen>
-  MyChoice ::= CHOICE {
+} Odr_arm;
+    </screen>
+
+    <para>
+     The interpretation of the fields are:
+    </para>
+
+    <variablelist>
+     <varlistentry><term>tagmode</term>
+      <listitem><para>Either <literal>ODR_IMPLICIT</literal>,
+       <literal>ODR_EXPLICIT</literal>, or <literal>ODR_NONE</literal> (-1)
+       to mark no tagging.</para></listitem>
+     </varlistentry>
+
+     <varlistentry><term>which</term>
+      <listitem><para>The value of the discriminator that corresponds to
+       this CHOICE element. Typically, it will be a &num;defined constant, or
+       an enum member.</para></listitem>
+     </varlistentry>
+
+     <varlistentry><term>fun</term>
+      <listitem><para>A pointer to a function that implements the type of
+       the CHOICE member. It may be either a standard &odr; type or a type
+       defined by yourself.</para></listitem>
+     </varlistentry>
+
+     <varlistentry><term>name</term>
+      <listitem><para>Name of tag.</para></listitem>
+     </varlistentry>
+    </variablelist>
+
+    <para>
+     A handy way to prepare the array for use by the
+     <function>odr_choice()</function> function is to
+     define it as a static, initialized array in the beginning of your
+     decoding/encoding function. Assume the type definition:
+    </para>
+
+    <screen>
+MyChoice ::= CHOICE {
     untagged INTEGER,
     tagged   &lsqb;99&rsqb; IMPLICIT INTEGER,
     other    BOOLEAN
-  }
-</screen>
-
-<para>
-Your C type might look like
-</para>
-
-<screen>
-  typedef struct MyChoice
-  {
-      enum
-      {
-          MyChoice_untagged,
-          MyChoice_tagged,
-          MyChoice_other
-      } which;
-      union
-      {
-          int *untagged;
-          int *tagged;
-          bool_t *other;
-      } u;
-  };
-</screen>
-
-<para>
-And your function could look like this:
-</para>
-
-<screen>
+}
+    </screen>
+
+    <para>
+     Your C type might look like
+    </para>
+
+    <screen>
+typedef struct MyChoice
+{
+    enum
+    {
+        MyChoice_untagged,
+        MyChoice_tagged,
+        MyChoice_other
+    } which;
+    union
+    {
+        int *untagged;
+        int *tagged;
+        bool_t *other;
+    } u;
+};
+    </screen>
+
+    <para>
+     And your function could look like this:
+    </para>
+
+    <screen>
 int myChoice(ODR o, MyChoice **p, int optional, const char *name)
 {
     static Odr_arm arm&lsqb;&rsqb; =
     {
-        {-1, -1, -1, MyChoice_untagged, odr_integer, "untagged"},
-        {ODR_IMPLICIT, ODR_CONTEXT, 99, MyChoice_tagged, odr_integer,
-                                                            "tagged"},
-        {-1, -1, -1, MyChoice_other, odr_boolean, "other"},
-        {-1, -1, -1, -1, 0}
+      {-1, -1, -1, MyChoice_untagged, odr_integer, "untagged"},
+      {ODR_IMPLICIT, ODR_CONTEXT, 99, MyChoice_tagged, odr_integer,
+      "tagged"},
+      {-1, -1, -1, MyChoice_other, odr_boolean, "other"},
+      {-1, -1, -1, -1, 0}
     };
 
     if (o->direction == ODR_DECODE)
@@ -1154,71 +1166,86 @@ int myChoice(ODR o, MyChoice **p, int optional, const char *name)
     if (odr_choice(o, arm, &amp;(*p)->u, &amp;(*p)->which), name)
         return 1;
     *p = 0;
-    return optional &amp;&amp; odr_ok(o);
+        return optional &amp;&amp; odr_ok(o);
 }
-</screen>
-
-<para>
-In some cases (say, a non-optional choice which is a member of a sequence),
-you can "embed" the union and its discriminator in the structure
-belonging to the enclosing type, and you won't need to fiddle with
-memory allocation to create a separate structure to wrap the
-discriminator and union.
-</para>
-
-<para>
-The corresponding function is somewhat nicer in the Sun XDR interface.
-Most of the complexity of this interface comes from the possibility of
-declaring sequence elements (including CHOICEs) optional.
-</para>
-
-<para>
-The ASN.1 specifictions naturally requires that each member of a
-CHOICE have a distinct tag, so they can be told apart on decoding.
-Sometimes it can be useful to define a CHOICE that has multiple types
-that share the same tag. You'll need some other mechanism, perhaps
-keyed to the context of the CHOICE type. In effect, we would like to
-introduce a level of context-sensitiveness to our ASN.1 specification.
-When encoding an internal representation, we have no problem, as long
-as each CHOICE member has a distinct discriminator value. For
-decoding, we need a way to tell the choice function to look for a
-specific arm of the table. The function
-</para>
-
-<synopsis>
-  void odr_choice_bias(ODR o, int what);
-</synopsis>
-
-<para>
-provides this functionality. When called, it leaves a notice for the next
-call to <function>odr_choice()</function> to be called on the decoding
-stream <literal>o</literal> that only the <literal>arm</literal> entry with
-a <literal>which</literal> field equal to <literal>what</literal>
-should be tried.
-</para>
-
-<para>
-The most important application (perhaps the only one, really) is in
-the definition of application-specific EXTERNAL encoders/decoders
-which will automatically decode an ANY member given the direct or
-indirect reference.
-</para>
-
-</sect2>
-</sect1>
-
-<sect1><title>Debugging</title>
-
-<para>
-The protocol modules are suffering somewhat from a lack of diagnostic
-tools at the moment. Specifically ways to pretty-print PDUs that
-aren't recognized by the system. We'll include something to this end
-in a not-too-distant release. In the meantime, what we do when we get
-packages we don't understand is to compile the ODR module with
-<literal>ODR_DEBUG</literal> defined. This causes the module to dump tracing
-information as it processes data units. With this output and the
-protocol specification (Z39.50), it is generally fairly easy to see
-what goes wrong.
-</para>
-</sect1>
-</chapter>
+    </screen>
+
+    <para>
+     In some cases (say, a non-optional choice which is a member of a
+     sequence), you can "embed" the union and its discriminator in the
+structure
+     belonging to the enclosing type, and you won't need to fiddle with
+     memory allocation to create a separate structure to wrap the
+     discriminator and union.
+    </para>
+
+    <para>
+     The corresponding function is somewhat nicer in the Sun XDR interface.
+     Most of the complexity of this interface comes from the possibility of
+     declaring sequence elements (including CHOICEs) optional.
+    </para>
+
+    <para>
+     The ASN.1 specifictions naturally requires that each member of a
+     CHOICE have a distinct tag, so they can be told apart on decoding.
+     Sometimes it can be useful to define a CHOICE that has multiple types
+     that share the same tag. You'll need some other mechanism, perhaps
+     keyed to the context of the CHOICE type. In effect, we would like to
+     introduce a level of context-sensitiveness to our ASN.1 specification.
+     When encoding an internal representation, we have no problem, as long
+     as each CHOICE member has a distinct discriminator value. For
+     decoding, we need a way to tell the choice function to look for a
+     specific arm of the table. The function
+    </para>
+
+    <synopsis>
+     void odr_choice_bias(ODR o, int what);
+    </synopsis>
+
+    <para>
+     provides this functionality. When called, it leaves a notice for the next
+     call to <function>odr_choice()</function> to be called on the decoding
+     stream <literal>o</literal> that only the <literal>arm</literal> entry with
+     a <literal>which</literal> field equal to <literal>what</literal>
+     should be tried.
+    </para>
+
+    <para>
+     The most important application (perhaps the only one, really) is in
+     the definition of application-specific EXTERNAL encoders/decoders
+     which will automatically decode an ANY member given the direct or
+     indirect reference.
+    </para>
+
+   </sect2>
+  </sect1>
+
+  <sect1><title>Debugging</title>
+
+   <para>
+    The protocol modules are suffering somewhat from a lack of diagnostic
+    tools at the moment. Specifically ways to pretty-print PDUs that
+    aren't recognized by the system. We'll include something to this end
+    in a not-too-distant release. In the meantime, what we do when we get
+    packages we don't understand is to compile the ODR module with
+    <literal>ODR_DEBUG</literal> defined. This causes the module to dump tracing
+    information as it processes data units. With this output and the
+    protocol specification (Z39.50), it is generally fairly easy to see
+    what goes wrong.
+   </para>
+  </sect1>
+ </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: "yaz.xml"
+ sgml-local-catalogs: "../../docbook/docbook.cat"
+ sgml-namecase-general:t
+ End:
+ -->
index 8b3fe80..4b2a9a1 100644 (file)
-<!-- $Header: /home/cvsroot/yaz/doc/tools.xml,v 1.1 2001-01-04 13:36:25 adam Exp $ -->
-<chapter><title>Supporting Tools</title>
-
-<para>
-In support of the service API - primarily the ASN module, which
-provides the programmatic interface to the Z39.50 APDUs, YAZ contains
-a collection of tools that support the development of applications.
-</para>
-
-<sect1><title>Query Syntax Parsers</title>
-
-<para>
-Since the type-1 (RPN) query structure has no direct, useful string
-representation, every origin application needs to provide some form of
-mapping from a local query notation or representation to a
-<token>Z_RPNQuery</token> structure. Some programmers will prefer to
-construct the query manually, perhaps using <function>odr_malloc()</function>
-to simplify memory management. The &yaz; distribution includes two separate,
-query-generating tools that may be of use to you.
-</para>
-
-<sect2><title id="PQF">Prefix Query Format</title>
-
-<para>
-Since RPN or reverse polish notation is really just a fancy way of
-describing a suffix notation format (operator follows operands), it
-would seem that the confusion is total when we now introduce a prefix
-notation for RPN. The reason is one of simple laziness - it's somewhat
-simpler to interpret a prefix format, and this utility was designed
-for maximum simplicity, to provide a baseline representation for use
-in simple test applications and scripting environments (like Tcl). The
-demonstration client included with YAZ uses the PQF.
-</para>
-<para>
-The PQF is defined by the pquery module in the YAZ library. The
-<filename>pquery.h</filename> file provides the declaration of the functions
-</para>
-<screen>
+<!-- $Id: tools.xml,v 1.2 2001-07-19 23:29:40 adam Exp $ -->
+ <chapter><title>Supporting Tools</title>
+
+  <para>
+   In support of the service API - primarily the ASN module, which
+   provides the programmatic interface to the Z39.50 APDUs, YAZ contains
+   a collection of tools that support the development of applications.
+  </para>
+
+  <sect1><title>Query Syntax Parsers</title>
+
+   <para>
+    Since the type-1 (RPN) query structure has no direct, useful string
+    representation, every origin application needs to provide some form of
+    mapping from a local query notation or representation to a
+    <token>Z_RPNQuery</token> structure. Some programmers will prefer to
+    construct the query manually, perhaps using
+    <function>odr_malloc()</function> to simplify memory management.
+    The &yaz; distribution includes two separate, query-generating tools
+    that may be of use to you.
+   </para>
+
+   <sect2><title id="PQF">Prefix Query Format</title>
+
+    <para>
+     Since RPN or reverse polish notation is really just a fancy way of
+     describing a suffix notation format (operator follows operands), it
+     would seem that the confusion is total when we now introduce a prefix
+     notation for RPN. The reason is one of simple laziness - it's somewhat
+     simpler to interpret a prefix format, and this utility was designed
+     for maximum simplicity, to provide a baseline representation for use
+     in simple test applications and scripting environments (like Tcl). The
+     demonstration client included with YAZ uses the PQF.
+    </para>
+    <para>
+     The PQF is defined by the pquery module in the YAZ library. The
+     <filename>pquery.h</filename> file provides the declaration of the
+     functions
+    </para>
+    <screen>
 Z_RPNQuery *p_query_rpn (ODR o, oid_proto proto, const char *qbuf);
 
 Z_AttributesPlusTerm *p_query_scan (ODR o, oid_proto proto,
-      Odr_oid **attributeSetP, const char *qbuf);
+          Odr_oid **attributeSetP, const char *qbuf);
 
 int p_query_attset (const char *arg);
-</screen>
-<para>
-The function <function>p_query_rpn()</function> takes as arguments an
-&odr; stream (see section <link linkend="odr">The ODR Module</link>)
-to provide a memory source (the structure created is released on
-the next call to <function>odr_reset()</function> on the stream), a
-protocol identifier (one of the constants <token>PROTO_Z3950</token> and
-<token>PROTO_SR</token>), an attribute set
-reference, and finally a null-terminated string holding the query
-string.
-</para>
-<para>
-If the parse went well, <function>p_query_rpn()</function> returns a
-pointer to a <literal>Z_RPNQuery</literal> structure which can be
-placed directly into a <literal>Z_SearchRequest</literal>.
-</para>
-<para>
+    </screen>
+    <para>
+     The function <function>p_query_rpn()</function> takes as arguments an
+      &odr; stream (see section <link linkend="odr">The ODR Module</link>)
+     to provide a memory source (the structure created is released on
+     the next call to <function>odr_reset()</function> on the stream), a
+     protocol identifier (one of the constants <token>PROTO_Z3950</token> and
+     <token>PROTO_SR</token>), an attribute set
+     reference, and finally a null-terminated string holding the query
+     string.
+    </para>
+    <para>
+     If the parse went well, <function>p_query_rpn()</function> returns a
+     pointer to a <literal>Z_RPNQuery</literal> structure which can be
+     placed directly into a <literal>Z_SearchRequest</literal>.
+    </para>
+    <para>
 
-The <literal>p_query_attset</literal> specifies which attribute set to use if
-the query doesn't specify one by the <literal>@attrset</literal> operator.
-The <literal>p_query_attset</literal> returns 0 if the argument is a
-valid attribute set specifier; otherwise the function returns -1.
-</para>
+     The <literal>p_query_attset</literal> specifies which attribute set
+     to use if the query doesn't specify one by the
+     <literal>@attrset</literal> operator.
+     The <literal>p_query_attset</literal> returns 0 if the argument is a
+     valid attribute set specifier; otherwise the function returns -1.
+    </para>
 
-<para>
-The grammar of the PQF is as follows:
-</para>
+    <para>
+     The grammar of the PQF is as follows:
+    </para>
 
-<screen>
-Query ::= &lsqb; AttSet &rsqb; QueryStruct.
+    <screen>
+     Query ::= &lsqb; AttSet &rsqb; QueryStruct.
 
-AttSet ::= string.
+     AttSet ::= string.
 
-QueryStruct ::= { Attribute } Simple | Complex.
+     QueryStruct ::= { Attribute } Simple | Complex.
 
-Attribute ::= '@attr' AttributeType '=' AttributeValue.
+     Attribute ::= '@attr' AttributeType '=' AttributeValue.
 
-AttributeType ::= integer.
+     AttributeType ::= integer.
 
-AttributeValue ::= integer.
+     AttributeValue ::= integer.
 
-Complex ::= Operator QueryStruct QueryStruct.
+     Complex ::= Operator QueryStruct QueryStruct.
 
-Operator ::= '@and' | '@or' | '@not' | '@prox' Proximity.
+     Operator ::= '@and' | '@or' | '@not' | '@prox' Proximity.
 
-Simple ::= ResultSet | Term.
+     Simple ::= ResultSet | Term.
 
-ResultSet ::= '@set' string.
+     ResultSet ::= '@set' string.
 
-Term ::= string | '"' string '"'.
+     Term ::= string | '"' string '"'.
 
-Proximity ::= Exclusion Distance Ordered Relation WhichCode UnitCode.
+     Proximity ::= Exclusion Distance Ordered Relation WhichCode UnitCode.
 
-Exclusion ::= '1' | '0' | 'void'.
+     Exclusion ::= '1' | '0' | 'void'.
 
-Distance ::= integer.
+     Distance ::= integer.
 
-Ordered ::= '1' | '0'.
+     Ordered ::= '1' | '0'.
 
-Relation ::= integer.
+     Relation ::= integer.
 
-WhichCode ::= 'known' | 'private' | integer.
+     WhichCode ::= 'known' | 'private' | integer.
 
-UnitCode ::= integer.
-</screen>
+     UnitCode ::= integer.
+    </screen>
 
-<para>
-You will note that the syntax above is a fairly faithful
-representation of RPN, except for the Attibute, which has been
-moved a step away from the term, allowing you to associate one or more
-attributes with an entire query structure. The parser will
-automatically apply the given attributes to each term as required.
-</para>
+    <para>
+     You will note that the syntax above is a fairly faithful
+     representation of RPN, except for the Attibute, which has been
+     moved a step away from the term, allowing you to associate one or more
+     attributes with an entire query structure. The parser will
+     automatically apply the given attributes to each term as required.
+    </para>
 
-<para>
-The following are all examples of valid queries in the PQF.
-</para>
+    <para>
+     The following are all examples of valid queries in the PQF.
+    </para>
 
-<screen>
-dylan
+    <screen>
+     dylan
 
-"bob dylan"
+     "bob dylan"
 
-@or "dylan" "zimmerman"
+     @or "dylan" "zimmerman"
 
-@set Result-1
+     @set Result-1
 
-@or @and bob dylan @set Result-1
+     @or @and bob dylan @set Result-1
 
-@attr 4=1 @and @attr 1=1 "bob dylan" @attr 1=4 "slow train coming"
+     @attr 4=1 @and @attr 1=1 "bob dylan" @attr 1=4 "slow train coming"
 
-@attr 4=1 @attr 1=4 "self portrait"
+     @attr 4=1 @attr 1=4 "self portrait"
 
-@prox 0 3 1 2 k 2 dylan zimmerman
-</screen>
+     @prox 0 3 1 2 k 2 dylan zimmerman
+    </screen>
 
-</sect2>
-<sect2><title id="CCL">Common Command Language</title>
+   </sect2>
+   <sect2><title id="CCL">Common Command Language</title>
 
-<para>
-Not all users enjoy typing in prefix query structures and numerical
-attribute values, even in a minimalistic test client. In the library
-world, the more intuitive Common Command Language (or ISO 8777) has
-enjoyed some popularity - especially before the widespread
-availability of graphical interfaces. It is still useful in
-applications where you for some reason or other need to provide a
-symbolic language for expressing boolean query structures.
-</para>
+    <para>
+     Not all users enjoy typing in prefix query structures and numerical
+     attribute values, even in a minimalistic test client. In the library
+     world, the more intuitive Common Command Language (or ISO 8777) has
+     enjoyed some popularity - especially before the widespread
+     availability of graphical interfaces. It is still useful in
+     applications where you for some reason or other need to provide a
+     symbolic language for expressing boolean query structures.
+    </para>
 
-<para>
-The EUROPAGATE research project working under the Libraries programme
-of the European Commission's DG XIII has, amongst other useful tools,
-implemented a general-purpose CCL parser which produces an output
-structure that can be trivially converted to the internal RPN
-representation of YAZ (The <literal>Z_RPNQuery</literal> structure).
-Since the CCL utility - along with the rest of the software
-produced by EUROPAGATE - is made freely available on a liberal license, it
-is included as a supplement to YAZ.
-</para>
+    <para>
+     The EUROPAGATE research project working under the Libraries programme
+     of the European Commission's DG XIII has, amongst other useful tools,
+     implemented a general-purpose CCL parser which produces an output
+     structure that can be trivially converted to the internal RPN
+     representation of YAZ (The <literal>Z_RPNQuery</literal> structure).
+     Since the CCL utility - along with the rest of the software
+     produced by EUROPAGATE - is made freely available on a liberal license, it
+     is included as a supplement to YAZ.
+    </para>
 
-<sect3><title>CCL Syntax</title>
+    <sect3><title>CCL Syntax</title>
 
-<para>
-The CCL parser obeys the following grammar for the FIND argument.
-The syntax is annotated by in the lines prefixed by
-<literal>&dash;&dash;</literal>.
-</para>
+     <para>
+      The CCL parser obeys the following grammar for the FIND argument.
+      The syntax is annotated by in the lines prefixed by
+      <literal>&dash;&dash;</literal>.
+     </para>
 
-<screen>
-CCL-Find ::= CCL-Find Op Elements
-           | Elements.
+     <screen>
+      CCL-Find ::= CCL-Find Op Elements
+                | Elements.
 
-Op ::= "and" | "or" | "not"
--- The above means that Elements are separated by boolean operators.
+      Op ::= "and" | "or" | "not"
+      -- The above means that Elements are separated by boolean operators.
 
-Elements ::= '(' CCL-Find ')'
-           | Set
-           | Terms
-           | Qualifiers Relation Terms
-           | Qualifiers Relation '(' CCL-Find ')'
-           | Qualifiers '=' string '-' string
--- Elements is either a recursive definition, a result set reference, a
--- list of terms, qualifiers followed by terms, qualifiers followed
--- by a recursive definition or qualifiers in a range (lower - upper).
+      Elements ::= '(' CCL-Find ')'
+                | Set
+                | Terms
+                | Qualifiers Relation Terms
+                | Qualifiers Relation '(' CCL-Find ')'
+                | Qualifiers '=' string '-' string
+      -- Elements is either a recursive definition, a result set reference, a
+      -- list of terms, qualifiers followed by terms, qualifiers followed
+      -- by a recursive definition or qualifiers in a range (lower - upper).
 
-Set ::= 'set' = string
--- Reference to a result set
+      Set ::= 'set' = string
+      -- Reference to a result set
 
-Terms ::= Terms Prox Term
-        | Term
--- Proximity of terms.
-
-Term ::= Term string
-       | string
--- This basically means that a term may include a blank
-
-Qualifiers ::= Qualifiers ',' string
-             | string
--- Qualifiers is a list of strings separated by comma
-
-Relation ::= '=' | '>=' | '<=' | '<>' | '>' | '<'
--- Relational operators. This really doesn't follow the ISO8777
--- standard.
-
-Prox ::= '%' | '!'
--- Proximity operator
-
-</screen>
-
-<para>
-The following queries are all valid:
-</para>
-
-<screen>
-dylan
-
-"bob dylan"
-
-dylan or zimmerman
-
-set=1
-
-(dylan and bob) or set=1
-
-</screen>
-<para>
-Assuming that the qualifiers <literal>ti</literal>, <literal>au</literal>
-and <literal>date</literal> are defined we may use:
-</para>
-
-<screen>
-ti=self portrait
-
-au=(bob dylan and slow train coming)
-
-date>1980 and (ti=((self portrait)))
-
-</screen>
-
-</sect3>
-<sect3><title>CCL Qualifiers</title>
-
-<para>
-Qualifiers are used to direct the search to a particular searchable
-index, such as title (ti) and author indexes (au). The CCL standard
-itself doesn't specify a particular set of qualifiers, but it does
-suggest a few short-hand notations. You can customize the CCL parser
-to support a particular set of qualifiers to relect the current target
-profile. Traditionally, a qualifier would map to a particular
-use-attribute within the BIB-1 attribute set. However, you could also
-define qualifiers that would set, for example, the
-structure-attribute.
-</para>
-
-<para>
-Consider a scenario where the target support ranked searches in the
-title-index. In this case, the user could specify
-</para>
-
-<screen>>
-ti,ranked=knuth computer
-</screen>
-<para>
-and the <literal>ranked</literal> would map to structure=free-form-text
-(4=105) and the <literal>ti</literal> would map to title (1=4).
-</para>
-
-<para>
-A "profile" with a set predefined CCL qualifiers can be read from a
-file. The YAZ client reads its CCL qualifiers from a file named
-<filename>default.bib</filename>. Each line in the file has the form:
-</para>
-
-<para>
-<replaceable>qualifier-name</replaceable>  
-   <replaceable>type</replaceable>=<replaceable>val</replaceable> <replaceable>type</replaceable>=<replaceable>val</replaceable> ...
-</para>
-
-<para>
-where <replaceable>qualifier-name</replaceable> is the name of the
-qualifier to be used (eg. <literal>ti</literal>),
-<replaceable>type</replaceable> is a BIB-1 category type and
-<replaceable>val</replaceable> is the corresponding BIB-1 attribute value.
-The <replaceable>type</replaceable> can be either numeric or it may be
-either <literal>u</literal> (use), <literal>r</literal> (relation),
-<literal>p</literal> (position), <literal>s</literal> (structure),
-<literal>t</literal> (truncation) or <literal>c</literal> (completeness).
-The <replaceable>qualifier-name</replaceable> <literal>term</literal> has a
-special meaning. The types and values for this definition is used when
-<emphasis>no</emphasis> qualifiers are present.
-</para>
-
-<para>
-Consider the following definition:
-</para>
-
-<screen>
-ti       u=4 s=1
-au       u=1 s=1
-term     s=105
-</screen>
-<para>
-Two qualifiers are defined, <literal>ti</literal> and <literal>au</literal>.
-They both set the structure-attribute to phrase (1). <literal>ti</literal>
-sets the use-attribute to 4. <literal>au</literal> sets the use-attribute
-to 1. When no qualifiers are used in the query the structure-attribute is
-set to free-form-text (105).
-</para>
-
-</sect3>
-<sect3><title>CCL API</title>
-<para>
-All public definitions can be found in the header file
-<filename>ccl.h</filename>. A profile identifier is of type
-<literal>CCL_bibset</literal>. A profile must be created with the call to
-the function <function>ccl_qual_mk</function> which returns a profile
-handle of type <literal>CCL_bibset</literal>.
-</para>
-
-<para>
-To read a file containing qualifier definitions the function
-<function>ccl_qual_file</function> may be convenient. This function takes
-an already opened <literal>FILE</literal> handle pointer as argument
-along with a <literal>CCL_bibset</literal> handle.
-</para>
-
-<para>
-To parse a simple string with a FIND query use the function
-</para>
-<screen>
-  struct ccl_rpn_node *ccl_find_str (CCL_bibset bibset, const char *str,
-                                     int *error, int *pos);
-</screen>
-<para>
-which takes the CCL profile (<literal>bibset</literal>) and query
-(<literal>str</literal>) as input. Upon successful completion the RPN
-tree is returned. If an error eccur, such as a syntax error, the integer
-pointed to by <literal>error</literal> holds the error code and
-<literal>pos</literal> holds the offset inside query string in which
-the parsing failed.
-</para>
-
-<para>
-An english representation of the error may be obtained by calling
-the <literal>ccl_err_msg</literal> function. The error codes are listed in
-<filename>ccl.h</filename>.
-</para>
-
-<para>
-To convert the CCL RPN tree (type <literal>struct ccl_rpn_node *</literal>)
-to the Z_RPNQuery of YAZ the function <function>ccl_rpn_query</function>
-must be used. This function which is part of YAZ is implemented in
-<filename>yaz-ccl.c</filename>.
-After calling this function the CCL RPN tree is probably no longer
-needed. The <literal>ccl_rpn_delete</literal> destroys the CCL RPN tree.
-</para>
-
-<para>
-A CCL profile may be destroyed by calling the <function>ccl_qual_rm</function>
-function.
-</para>
-
-<para>
-The token names for the CCL operators may be changed by setting the
-globals (all type <literal>char *</literal>)
-<literal>ccl_token_and</literal>, <literal>ccl_token_or</literal>,
-<literal>ccl_token_not</literal> and <literal>ccl_token_set</literal>.
-An operator may have aliases, i.e. there may be more than one name for
-the operator. To do this, separate each alias with a space character.
-</para>
-</sect3>
-</sect2>
-</sect1>
-<sect1><title>Object Identifiers</title>
-
-<para>
-The basic YAZ representation of an OID is an array of integers,
-terminated with the value -1. The &odr; module provides two
-utility-functions to create and copy this type of data elements:
-</para>
-
-<screen>
-  Odr_oid *odr_getoidbystr(ODR o, char *str);
-</screen>
-
-<para>
-Creates an OID based on a string-based representation using dots (.)
-to separate elements in the OID.
-</para>
-
-<screen>
-Odr_oid *odr_oiddup(ODR odr, Odr_oid *o);
-</screen>
-
-<para>
-Creates a copy of the OID referenced by the <emphasis>o</emphasis> parameter.
-Both functions take an &odr; stream as parameter. This stream is used to
-allocate memory for the data elements, which is released on a
-subsequent call to <function>odr_reset()</function> on that stream.
-</para>
-
-<para>
-The OID module provides a higher-level representation of the
-family of object identifers which describe the Z39.50 protocol and its
-related objects. The definition of the module interface is given in
-the <filename>oid.h</filename> file.
-</para>
-
-<para>
-The interface is mainly based on the <literal>oident</literal> structure. The
-definition of this structure looks like this:
-</para>
-
-<screen>
+      Terms ::= Terms Prox Term
+             | Term
+      -- Proximity of terms.
+
+      Term ::= Term string
+            | string
+      -- This basically means that a term may include a blank
+
+      Qualifiers ::= Qualifiers ',' string
+                  | string
+      -- Qualifiers is a list of strings separated by comma
+
+      Relation ::= '=' | '>=' | '<=' | '<>' | '>' | '<'
+      -- Relational operators. This really doesn't follow the ISO8777
+      -- standard.
+
+      Prox ::= '%' | '!'
+      -- Proximity operator
+
+     </screen>
+
+     <para>
+      The following queries are all valid:
+     </para>
+
+     <screen>
+      dylan
+
+      "bob dylan"
+
+      dylan or zimmerman
+
+      set=1
+
+      (dylan and bob) or set=1
+
+     </screen>
+     <para>
+      Assuming that the qualifiers <literal>ti</literal>, <literal>au</literal>
+      and <literal>date</literal> are defined we may use:
+     </para>
+
+     <screen>
+      ti=self portrait
+
+      au=(bob dylan and slow train coming)
+
+      date>1980 and (ti=((self portrait)))
+
+     </screen>
+
+    </sect3>
+    <sect3><title>CCL Qualifiers</title>
+
+     <para>
+      Qualifiers are used to direct the search to a particular searchable
+      index, such as title (ti) and author indexes (au). The CCL standard
+      itself doesn't specify a particular set of qualifiers, but it does
+      suggest a few short-hand notations. You can customize the CCL parser
+      to support a particular set of qualifiers to relect the current target
+      profile. Traditionally, a qualifier would map to a particular
+      use-attribute within the BIB-1 attribute set. However, you could also
+      define qualifiers that would set, for example, the
+      structure-attribute.
+     </para>
+
+     <para>
+      Consider a scenario where the target support ranked searches in the
+      title-index. In this case, the user could specify
+     </para>
+
+     <screen>>
+      ti,ranked=knuth computer
+     </screen>
+     <para>
+      and the <literal>ranked</literal> would map to structure=free-form-text
+      (4=105) and the <literal>ti</literal> would map to title (1=4).
+     </para>
+
+     <para>
+      A "profile" with a set predefined CCL qualifiers can be read from a
+      file. The YAZ client reads its CCL qualifiers from a file named
+      <filename>default.bib</filename>. Each line in the file has the form:
+     </para>
+
+     <para>
+      <replaceable>qualifier-name</replaceable>  
+      <replaceable>type</replaceable>=<replaceable>val</replaceable>
+      <replaceable>type</replaceable>=<replaceable>val</replaceable> ...
+     </para>
+
+     <para>
+      where <replaceable>qualifier-name</replaceable> is the name of the
+      qualifier to be used (eg. <literal>ti</literal>),
+      <replaceable>type</replaceable> is a BIB-1 category type and
+      <replaceable>val</replaceable> is the corresponding BIB-1 attribute
+      value.
+      The <replaceable>type</replaceable> can be either numeric or it may be
+      either <literal>u</literal> (use), <literal>r</literal> (relation),
+      <literal>p</literal> (position), <literal>s</literal> (structure),
+      <literal>t</literal> (truncation) or <literal>c</literal> (completeness).
+      The <replaceable>qualifier-name</replaceable> <literal>term</literal>
+      has a special meaning.
+      The types and values for this definition is used when
+      <emphasis>no</emphasis> qualifiers are present.
+     </para>
+
+     <para>
+      Consider the following definition:
+     </para>
+
+     <screen>
+      ti       u=4 s=1
+      au       u=1 s=1
+      term     s=105
+     </screen>
+     <para>
+      Two qualifiers are defined, <literal>ti</literal> and
+      <literal>au</literal>.
+      They both set the structure-attribute to phrase (1).
+      <literal>ti</literal>
+      sets the use-attribute to 4. <literal>au</literal> sets the
+      use-attribute to 1.
+      When no qualifiers are used in the query the structure-attribute is
+      set to free-form-text (105).
+     </para>
+
+    </sect3>
+    <sect3><title>CCL API</title>
+     <para>
+      All public definitions can be found in the header file
+      <filename>ccl.h</filename>. A profile identifier is of type
+      <literal>CCL_bibset</literal>. A profile must be created with the call
+      to the function <function>ccl_qual_mk</function> which returns a profile
+      handle of type <literal>CCL_bibset</literal>.
+     </para>
+
+     <para>
+      To read a file containing qualifier definitions the function
+      <function>ccl_qual_file</function> may be convenient. This function
+      takes an already opened <literal>FILE</literal> handle pointer as
+      argument along with a <literal>CCL_bibset</literal> handle.
+     </para>
+
+     <para>
+      To parse a simple string with a FIND query use the function
+     </para>
+     <screen>
+      struct ccl_rpn_node *ccl_find_str (CCL_bibset bibset, const char *str,
+      int *error, int *pos);
+     </screen>
+     <para>
+      which takes the CCL profile (<literal>bibset</literal>) and query
+      (<literal>str</literal>) as input. Upon successful completion the RPN
+      tree is returned. If an error eccur, such as a syntax error, the integer
+      pointed to by <literal>error</literal> holds the error code and
+      <literal>pos</literal> holds the offset inside query string in which
+      the parsing failed.
+     </para>
+
+     <para>
+      An english representation of the error may be obtained by calling
+      the <literal>ccl_err_msg</literal> function. The error codes are
+      listed in <filename>ccl.h</filename>.
+     </para>
+
+     <para>
+      To convert the CCL RPN tree (type
+      <literal>struct ccl_rpn_node *</literal>)
+      to the Z_RPNQuery of YAZ the function <function>ccl_rpn_query</function>
+      must be used. This function which is part of YAZ is implemented in
+      <filename>yaz-ccl.c</filename>.
+      After calling this function the CCL RPN tree is probably no longer
+      needed. The <literal>ccl_rpn_delete</literal> destroys the CCL RPN tree.
+     </para>
+
+     <para>
+      A CCL profile may be destroyed by calling the
+      <function>ccl_qual_rm</function> function.
+     </para>
+
+     <para>
+      The token names for the CCL operators may be changed by setting the
+      globals (all type <literal>char *</literal>)
+      <literal>ccl_token_and</literal>, <literal>ccl_token_or</literal>,
+      <literal>ccl_token_not</literal> and <literal>ccl_token_set</literal>.
+      An operator may have aliases, i.e. there may be more than one name for
+      the operator. To do this, separate each alias with a space character.
+     </para>
+    </sect3>
+   </sect2>
+  </sect1>
+  <sect1><title>Object Identifiers</title>
+
+   <para>
+    The basic YAZ representation of an OID is an array of integers,
+    terminated with the value -1. The &odr; module provides two
+    utility-functions to create and copy this type of data elements:
+   </para>
+
+   <screen>
+    Odr_oid *odr_getoidbystr(ODR o, char *str);
+   </screen>
+
+   <para>
+    Creates an OID based on a string-based representation using dots (.)
+    to separate elements in the OID.
+   </para>
+
+   <screen>
+    Odr_oid *odr_oiddup(ODR odr, Odr_oid *o);
+   </screen>
+
+   <para>
+    Creates a copy of the OID referenced by the <emphasis>o</emphasis>
+    parameter.
+    Both functions take an &odr; stream as parameter. This stream is used to
+    allocate memory for the data elements, which is released on a
+    subsequent call to <function>odr_reset()</function> on that stream.
+   </para>
+
+   <para>
+    The OID module provides a higher-level representation of the
+    family of object identifers which describe the Z39.50 protocol and its
+    related objects. The definition of the module interface is given in
+    the <filename>oid.h</filename> file.
+   </para>
+
+   <para>
+    The interface is mainly based on the <literal>oident</literal> structure.
+    The definition of this structure looks like this:
+   </para>
+
+   <screen>
 typedef struct oident
 {
     oid_proto proto;
@@ -424,252 +435,269 @@ typedef struct oident
     int oidsuffix[OID_SIZE];
     char *desc;
 } oident;
-</screen>
-
-<para>
-The proto field takes one of the values
-</para>
-
-<screen>
-PROTO_Z3950
-PROTO_SR
-</screen>
-
-<para>
-If you don't care about talking to SR-based implementations (few
-exist, and they may become fewer still if and when the ISO SR and ANSI
-Z39.50 documents are merged into a single standard), you can ignore
-this field on incoming packages, and always set it to PROTO_Z3950
-for outgoing packages.
-</para>
-<para>
-
-The oclass field takes one of the values
-</para>
-
-<screen>
-CLASS_APPCTX
-CLASS_ABSYN
-CLASS_ATTSET
-CLASS_TRANSYN
-CLASS_DIAGSET
-CLASS_RECSYN
-CLASS_RESFORM
-CLASS_ACCFORM
-CLASS_EXTSERV
-CLASS_USERINFO
-CLASS_ELEMSPEC
-CLASS_VARSET
-CLASS_SCHEMA
-CLASS_TAGSET
-CLASS_GENERAL
-</screen>
-
-<para>
-corresponding to the OID classes defined by the Z39.50 standard.
-
-Finally, the value field takes one of the values
-</para>
-
-<screen>
-VAL_APDU
-VAL_BER
-VAL_BASIC_CTX
-VAL_BIB1
-VAL_EXP1
-VAL_EXT1
-VAL_CCL1
-VAL_GILS
-VAL_WAIS
-VAL_STAS
-VAL_DIAG1
-VAL_ISO2709
-VAL_UNIMARC
-VAL_INTERMARC
-VAL_CCF
-VAL_USMARC
-VAL_UKMARC
-VAL_NORMARC
-VAL_LIBRISMARC
-VAL_DANMARC
-VAL_FINMARC
-VAL_MAB
-VAL_CANMARC
-VAL_SBN
-VAL_PICAMARC
-VAL_AUSMARC
-VAL_IBERMARC
-VAL_EXPLAIN
-VAL_SUTRS
-VAL_OPAC
-VAL_SUMMARY
-VAL_GRS0
-VAL_GRS1
-VAL_EXTENDED
-VAL_RESOURCE1
-VAL_RESOURCE2
-VAL_PROMPT1
-VAL_DES1
-VAL_KRB1
-VAL_PRESSET
-VAL_PQUERY
-VAL_PCQUERY
-VAL_ITEMORDER
-VAL_DBUPDATE
-VAL_EXPORTSPEC
-VAL_EXPORTINV
-VAL_NONE
-VAL_SETM
-VAL_SETG
-VAL_VAR1
-VAL_ESPEC1
-</screen>
-
-<para>
-again, corresponding to the specific OIDs defined by the standard.
-</para>
-
-<para>
-The desc field contains a brief, mnemonic name for the OID in question.
-</para>
-
-<para>
-The function
-</para>
-
-<screen>
-  struct oident *oid_getentbyoid(int *o);
-</screen>
-
-<para>
-takes as argument an OID, and returns a pointer to a static area
-containing an <literal>oident</literal> structure. You typically use
-this function when you receive a PDU containing an OID, and you wish
-to branch out depending on the specific OID value.
-</para>
-
-<para>
-The function
-</para>
-
-<screen>
-  int *oid_ent_to_oid(struct oident *ent, int *dst);
-</screen>
-
-<para>
-Takes as argument an <literal>oident</literal> structure - in which
-the <literal>proto</literal>, <literal>oclass</literal>/, and
-<literal>value</literal> fields are assumed to be set correctly -
-and returns a pointer to a the buffer as given by <literal>dst</literal>
-containing the base
-representation of the corresponding OID. The function returns
-NULL and the array dst is unchanged if a mapping couldn't place.
-The array <literal>dst</literal> should be at least of size
-<literal>OID_SIZE</literal>.
-</para>
-<para>
-
-The <function>oid_ent_to_oid()</function> function can be used whenever
-you need to prepare a PDU containing one or more OIDs. The separation of
-the <literal>protocol</literal> element from the remainer of the
-OID-description makes it simple to write applications that can
-communicate with either Z39.50 or OSI SR-based applications.
-</para>
-
-<para>
-The function
-</para>
-
-<screen><
-  oid_value oid_getvalbyname(const char *name);
-</screen>
-
-<para>
-takes as argument a mnemonic OID name, and returns the
-<literal>/value</literal> field of the first entry in the database that 
-contains the given name in its <literal>desc</literal> field.
-</para>
-
-<para>
-Finally, the module provides the following utility functions, whose
-meaning should be obvious:
-</para>
-
-<screen>
-  void oid_oidcpy(int *t, int *s);
-  void oid_oidcat(int *t, int *s);
-  int oid_oidcmp(int *o1, int *o2);
-  int oid_oidlen(int *o);
-</screen>
-
-<note>
-<para>
-The OID module has been criticized - and perhaps rightly so
-- for needlessly abstracting the
-representation of OIDs. Other toolkits use a simple
-string-representation of OIDs with good results. In practice, we have
-found the interface comfortable and quick to work with, and it is a
-simple matter (for what it's worth) to create applications compatible with
-both ISO SR and Z39.50. Finally, the use of the <literal>/oident</literal>
-database is by no means mandatory. You can easily create your
-own system for representing OIDs, as long as it is compatible with the
-low-level integer-array representation of the ODR module.
-</para>
-</note>
-
-</sect1>
-
-<sect1><title>Nibble Memory</title>
-
-<para>
-Sometimes when you need to allocate and construct a large,
-interconnected complex of structures, it can be a bit of a pain to
-release the associated memory again. For the structures describing the
-Z39.50 PDUs and related structures, it is convenient to use the
-memory-management system of the &odr; subsystem (see
-<link linkend="odr-use">Using ODR</link>). However, in some circumstances
-where you might otherwise benefit from using a simple nibble memory
-management system, it may be impractical to use
-<function>odr_malloc()</function> and <function>odr_reset()</function>.
-For this purpose, the memory manager which also supports the &odr; streams
-is made available in the NMEM module. The external interface to this module is given in the <filename>nmem.h</filename> file.
-</para>
-
-<para>
-The following prototypes are given:
-</para>
-
-<screen>
-NMEM nmem_create(void);
-void nmem_destroy(NMEM n);
-void *nmem_malloc(NMEM n, int size);
-void nmem_reset(NMEM n);
-int nmem_total(NMEM n);
-void nmem_init(void);
-</screen>
-
-<para>
-The <function>nmem_create()</function> function returns a pointer to a
-memory control handle, which can be released again by
-<function>nmem_destroy()</function> when no longer needed.
-The function <function>nmem_malloc()</function> allocates a block of
-memory of the requested size. A call to <function>nmem_reset()</function> or
-<function>nmem_destroy()</function> will release all memory allocated on
-the handle since it was created (or since the last call to
-<function>nmem_reset()</function>. The function
-<function>nmem_total()</function> returns the number of bytes currently
-allocated on the handle.
-</para>
-
-<note>
-<para>
-The nibble memory pool is shared amonst threads. POSIX
-mutex'es and WIN32 Critical sections are introduced to keep the
-module thread safe. On WIN32 function <function>nmem_init()</function>
-initialises the Critical Section handle and should be called once before any
-other nmem function is used.
-</para>
-</note>
-
-</sect1>
-</chapter>
\ No newline at end of file
+   </screen>
+
+   <para>
+    The proto field takes one of the values
+   </para>
+
+   <screen>
+    PROTO_Z3950
+    PROTO_SR
+   </screen>
+
+   <para>
+    If you don't care about talking to SR-based implementations (few
+    exist, and they may become fewer still if and when the ISO SR and ANSI
+    Z39.50 documents are merged into a single standard), you can ignore
+    this field on incoming packages, and always set it to PROTO_Z3950
+    for outgoing packages.
+   </para>
+   <para>
+
+    The oclass field takes one of the values
+   </para>
+
+   <screen>
+    CLASS_APPCTX
+    CLASS_ABSYN
+    CLASS_ATTSET
+    CLASS_TRANSYN
+    CLASS_DIAGSET
+    CLASS_RECSYN
+    CLASS_RESFORM
+    CLASS_ACCFORM
+    CLASS_EXTSERV
+    CLASS_USERINFO
+    CLASS_ELEMSPEC
+    CLASS_VARSET
+    CLASS_SCHEMA
+    CLASS_TAGSET
+    CLASS_GENERAL
+   </screen>
+
+   <para>
+    corresponding to the OID classes defined by the Z39.50 standard.
+
+    Finally, the value field takes one of the values
+   </para>
+
+   <screen>
+    VAL_APDU
+    VAL_BER
+    VAL_BASIC_CTX
+    VAL_BIB1
+    VAL_EXP1
+    VAL_EXT1
+    VAL_CCL1
+    VAL_GILS
+    VAL_WAIS
+    VAL_STAS
+    VAL_DIAG1
+    VAL_ISO2709
+    VAL_UNIMARC
+    VAL_INTERMARC
+    VAL_CCF
+    VAL_USMARC
+    VAL_UKMARC
+    VAL_NORMARC
+    VAL_LIBRISMARC
+    VAL_DANMARC
+    VAL_FINMARC
+    VAL_MAB
+    VAL_CANMARC
+    VAL_SBN
+    VAL_PICAMARC
+    VAL_AUSMARC
+    VAL_IBERMARC
+    VAL_EXPLAIN
+    VAL_SUTRS
+    VAL_OPAC
+    VAL_SUMMARY
+    VAL_GRS0
+    VAL_GRS1
+    VAL_EXTENDED
+    VAL_RESOURCE1
+    VAL_RESOURCE2
+    VAL_PROMPT1
+    VAL_DES1
+    VAL_KRB1
+    VAL_PRESSET
+    VAL_PQUERY
+    VAL_PCQUERY
+    VAL_ITEMORDER
+    VAL_DBUPDATE
+    VAL_EXPORTSPEC
+    VAL_EXPORTINV
+    VAL_NONE
+    VAL_SETM
+    VAL_SETG
+    VAL_VAR1
+    VAL_ESPEC1
+   </screen>
+
+   <para>
+    again, corresponding to the specific OIDs defined by the standard.
+   </para>
+
+   <para>
+    The desc field contains a brief, mnemonic name for the OID in question.
+   </para>
+
+   <para>
+    The function
+   </para>
+
+   <screen>
+    struct oident *oid_getentbyoid(int *o);
+   </screen>
+
+   <para>
+    takes as argument an OID, and returns a pointer to a static area
+    containing an <literal>oident</literal> structure. You typically use
+    this function when you receive a PDU containing an OID, and you wish
+    to branch out depending on the specific OID value.
+   </para>
+
+   <para>
+    The function
+   </para>
+
+   <screen>
+    int *oid_ent_to_oid(struct oident *ent, int *dst);
+   </screen>
+
+   <para>
+    Takes as argument an <literal>oident</literal> structure - in which
+    the <literal>proto</literal>, <literal>oclass</literal>/, and
+    <literal>value</literal> fields are assumed to be set correctly -
+    and returns a pointer to a the buffer as given by <literal>dst</literal>
+    containing the base
+    representation of the corresponding OID. The function returns
+    NULL and the array dst is unchanged if a mapping couldn't place.
+    The array <literal>dst</literal> should be at least of size
+    <literal>OID_SIZE</literal>.
+   </para>
+   <para>
+
+    The <function>oid_ent_to_oid()</function> function can be used whenever
+    you need to prepare a PDU containing one or more OIDs. The separation of
+    the <literal>protocol</literal> element from the remainer of the
+    OID-description makes it simple to write applications that can
+    communicate with either Z39.50 or OSI SR-based applications.
+   </para>
+
+   <para>
+    The function
+   </para>
+
+   <screen><
+    oid_value oid_getvalbyname(const char *name);
+   </screen>
+
+   <para>
+    takes as argument a mnemonic OID name, and returns the
+    <literal>/value</literal> field of the first entry in the database that 
+    contains the given name in its <literal>desc</literal> field.
+   </para>
+
+   <para>
+    Finally, the module provides the following utility functions, whose
+    meaning should be obvious:
+   </para>
+
+   <screen>
+    void oid_oidcpy(int *t, int *s);
+    void oid_oidcat(int *t, int *s);
+    int oid_oidcmp(int *o1, int *o2);
+    int oid_oidlen(int *o);
+   </screen>
+
+   <note>
+    <para>
+     The OID module has been criticized - and perhaps rightly so
+     - for needlessly abstracting the
+     representation of OIDs. Other toolkits use a simple
+     string-representation of OIDs with good results. In practice, we have
+     found the interface comfortable and quick to work with, and it is a
+     simple matter (for what it's worth) to create applications compatible
+     with both ISO SR and Z39.50. Finally, the use of the
+     <literal>/oident</literal> database is by no means mandatory.
+     You can easily create your own system for representing OIDs, as long
+     as it is compatible with the low-level integer-array representation
+     of the ODR module.
+    </para>
+   </note>
+
+  </sect1>
+
+  <sect1><title>Nibble Memory</title>
+
+   <para>
+    Sometimes when you need to allocate and construct a large,
+    interconnected complex of structures, it can be a bit of a pain to
+    release the associated memory again. For the structures describing the
+    Z39.50 PDUs and related structures, it is convenient to use the
+    memory-management system of the &odr; subsystem (see
+    <link linkend="odr-use">Using ODR</link>). However, in some circumstances
+    where you might otherwise benefit from using a simple nibble memory
+    management system, it may be impractical to use
+    <function>odr_malloc()</function> and <function>odr_reset()</function>.
+    For this purpose, the memory manager which also supports the &odr;
+    streams is made available in the NMEM module. The external interface
+    to this module is given in the <filename>nmem.h</filename> file.
+   </para>
+
+   <para>
+    The following prototypes are given:
+   </para>
+
+   <screen>
+    NMEM nmem_create(void);
+    void nmem_destroy(NMEM n);
+    void *nmem_malloc(NMEM n, int size);
+    void nmem_reset(NMEM n);
+    int nmem_total(NMEM n);
+    void nmem_init(void);
+   </screen>
+
+   <para>
+    The <function>nmem_create()</function> function returns a pointer to a
+    memory control handle, which can be released again by
+    <function>nmem_destroy()</function> when no longer needed.
+    The function <function>nmem_malloc()</function> allocates a block of
+    memory of the requested size. A call to <function>nmem_reset()</function>
+    or <function>nmem_destroy()</function> will release all memory allocated
+    on the handle since it was created (or since the last call to
+    <function>nmem_reset()</function>. The function
+    <function>nmem_total()</function> returns the number of bytes currently
+    allocated on the handle.
+   </para>
+
+   <note>
+    <para>
+     The nibble memory pool is shared amonst threads. POSIX
+     mutex'es and WIN32 Critical sections are introduced to keep the
+     module thread safe. On WIN32 function <function>nmem_init()</function>
+     initialises the Critical Section handle and should be called once
+     before any other nmem function is used.
+    </para>
+   </note>
+
+  </sect1>
+ </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: "yaz.xml"
+ sgml-local-catalogs: "../../docbook/docbook.cat"
+ sgml-namecase-general:t
+ End:
+ -->
index 1710087..6b50fcf 100644 (file)
      <!ENTITY odr "<acronym>ODR</acronym>">
      <!ENTITY comstack "<acronym>COMSTACK</acronym>">
 ]>
-<!-- $Header: /home/cvsroot/yaz/doc/yaz.xml,v 1.2 2001-07-19 12:46:57 adam Exp $ -->
+<!-- $Id: yaz.xml,v 1.3 2001-07-19 23:29:40 adam Exp $ -->
 <book>
-<bookinfo>
-<title>YAZ User's Guide and Reference</title>
-<author><firstname>Sebastian</firstname><surname>Hammer</surname></author>
-<editor><firstname>Adam</firstname><surname>Dickmeiss</surname></editor>
-<copyright>
-<year>1995</year>
-<year>1996</year>
-<year>1997</year>
-<year>1998</year>
-<year>1999</year>
-<year>2000</year>
-<year>2001</year>
-<holder>Index Data</holder>
-</copyright>
-<abstract><simpara>
-This document is the programmer's guide and reference to the &yaz;
-package. &yaz; is a compact toolkit that provides access to the
-Z39.50 protocol, as well as a set of higher-level tools for
-implementing the server and client roles, respectively.
-The documentation can be used on its own, or as a reference when looking
-at the example applications provided with the package.
-</simpara></abstract>
-</bookinfo>
-
-&chap-introduction;
-&chap-installation;
-&chap-asn;
-&chap-tools;
-&chap-odr;
-&chap-comstack;
-&chap-frontend;
-&chap-future;
-&app-license;
-&app-indexdata;
+ <bookinfo>
+  <title>YAZ User's Guide and Reference</title>
+  <author><firstname>Sebastian</firstname><surname>Hammer</surname></author>
+  <editor><firstname>Adam</firstname><surname>Dickmeiss</surname></editor>
+  <copyright>
+   <year>1995</year>
+   <year>1996</year>
+   <year>1997</year>
+   <year>1998</year>
+   <year>1999</year>
+   <year>2000</year>
+   <year>2001</year>
+   <holder>Index Data</holder>
+  </copyright>
+  <abstract><simpara>
+    This document is the programmer's guide and reference to the &yaz;
+    package. &yaz; is a compact toolkit that provides access to the
+    Z39.50 protocol, as well as a set of higher-level tools for
+    implementing the server and client roles, respectively.
+    The documentation can be used on its own, or as a reference when looking
+    at the example applications provided with the package.
+   </simpara></abstract>
+ </bookinfo>
+ &chap-introduction;
+ &chap-installation;
+ &chap-asn;
+ &chap-tools;
+ &chap-odr;
+ &chap-comstack;
+ &chap-frontend;
+ &chap-future;
+ &app-license;
+ &app-indexdata;
 </book>
 
 <!-- Keep this comment at the end of the file
@@ -64,9 +64,6 @@ sgml-always-quote-attributes:t
 sgml-indent-step:1
 sgml-indent-data:t
 sgml-parent-document:nil
-sgml-default-dtd-file:"yaz.ced"
-sgml-exposed-tags:nil
-sgml-local-ecat-files:nil
 sgml-local-catalogs: "../../docbook/docbook.cat"
 sgml-namecase-general:t
 End: