-<!-- $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
-"nibble-memory"
-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_<type> *zget_<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
+ "nibble-memory"
+ 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_<type> *zget_<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;
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;
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:
+ -->
-<!-- $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;
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>
+ <host> [ ':' <portnum> ]
+ </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>
+ [ <t-selector> '/' ] <host> [ ':' <port> ]
+ </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 "@" 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[];
+ </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 "make libmosi.a/".
+ 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 (>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 <comstack.h>
+
+ #include <tcpip.h> /* this is for TCP/IP support */
+ #include <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>
-<host> [ ':' <portnum> ]
-</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>
-[ <t-selector> '/' ] <host> [ ':' <port> ]
-</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 "@" 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[];
-</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 "make libmosi.a/".
-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 (>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 <comstack.h>
-
-#include <tcpip.h> /* this is for TCP/IP support */
-#include <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:
--->
-<!-- $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[ODR_MAXNAME+1]</term>
-<listitem><para>File for diagnostic output ("": stderr).
-</para></listitem></varlistentry>
-<varlistentry><term>char apdufile[ODR_MAXNAME+1]</term>
-<listitem><para>
-Name of file for logging incoming and outgoing APDUs ("": don't
-log APDUs, "-": <literal>stderr</literal>).
-</para></listitem></varlistentry>
-
-<varlistentry><term>char default_listen[1024]</term>
-<listitem><para>Same form as the command-line specification of
-listener address. "": no default listener address.
-Default is to listen at "tcp:@:9999". 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[ODR_MAXNAME+1]</term>
-<listitem><para>Passed to the backend when a new connection is received.
-</para></listitem></varlistentry>
-
-<varlistentry><term>char setuid[ODR_MAXNAME+1]</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[ODR_MAXNAME+1]</term>
+ <listitem><para>File for diagnostic output ("": stderr).
+ </para></listitem></varlistentry>
+ <varlistentry><term>char apdufile[ODR_MAXNAME+1]</term>
+ <listitem><para>
+ Name of file for logging incoming and outgoing APDUs ("": don't
+ log APDUs, "-": <literal>stderr</literal>).
+ </para></listitem></varlistentry>
+
+ <varlistentry><term>char default_listen[1024]</term>
+ <listitem><para>Same form as the command-line specification of
+ listener address. "": no default listener address.
+ Default is to listen at "tcp:@:9999". 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[ODR_MAXNAME+1]</term>
+ <listitem><para>Passed to the backend when a new connection is received.
+ </para></listitem></varlistentry>
+
+ <varlistentry><term>char setuid[ODR_MAXNAME+1]</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;
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 {
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 {
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 {
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 {
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 {
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> [-szSiTu -a <replaceable>apdufile</replaceable> -l <replaceable>logfile</replaceable> -v <replaceable>loglevel</replaceable> -c <replaceable>config</replaceable>]
-[listener ...]
-</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 "-" 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 [: portnumber]
-</synopsis>
-
-<para>
-The port number defaults to 210 (standard Z39.50 port).
-</para>
-
-<para>
-For osi, the address form is
-</para>
-
-<synopsis>
- [t-selector /] hostname | IP-number [: portnumber]
-</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 "@" 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> [-szSiTu -a <replaceable>apdufile</replaceable> -l <replaceable>logfile</replaceable> -v <replaceable>loglevel</replaceable> -c <replaceable>config</replaceable>]
+ [listener ...]
+ </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 "-" 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 [: portnumber]
+ </synopsis>
+
+ <para>
+ The port number defaults to 210 (standard Z39.50 port).
+ </para>
+
+ <para>
+ For osi, the address form is
+ </para>
+
+ <synopsis>
+ [t-selector /] hostname | IP-number [: portnumber]
+ </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 "@" 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:
+ -->
-<!-- $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:
+ -->
-<!-- $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ø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ø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 "YA" 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 "Yet Another
-AI Group" or "Yet Another Simulated Annealing Algorithm".
-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 "YA" 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 "Yet Another
+ AI Group" or "Yet Another Simulated Annealing Algorithm".
+ 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:
+ -->
-<!-- $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
-#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
+ #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
-<!-- $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 "z" 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 "z" 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:
+ -->
-<!-- $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 © 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 © 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 © 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 © 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:
+ -->
-<!-- $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 = &value;
if (odr_integer(encode, &valp, 0, 0) == 0)
{
- printf("encoding went bad\n");
- return;
+ printf("encoding went bad\n");
+ return;
}
bufferp = odr_getbuf(encode, &len);
printf("length of encoded data is %d\n", len);
odr_setbuf(decode, bufferp, len);
if (odr_integer(decode, &resvalp, 0, 0) == 0)
{
- printf("decoding went bad\n");
- return;
+ printf("decoding went bad\n");
+ return;
}
printf("the value is %d\n", *resvalp);
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[]
-</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 <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[]
+ </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 <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 ::= [210] 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 ::= [210] 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 && odr_ok(o);
return
odr_integer(o, &(*p)->intval, 0, "intval") &&
odr_bool(o, &(*p)->boolval, 1, "boolval") &&
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 ::= [10] 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 ::= [10] 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 && odr_ok(o);
return
odr_integer(o, &(*p)->intval, 0, "intval") &&
odr_bool(o, &(*p)->boolval, 1, "boolval") &&
- 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 ::= [10] 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 ::= [10] 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 && 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, &(*p)->intval, 0, "intval") &&
odr_bool(o, &(*p)->boolval, 1, "boolval") &&
odr_sequence_end(o) &&
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, &(*p)->elements,
- &(*p)->num_elements, name))
- return 1;
+ &(*p)->num_elements, name))
+ return 1;
*p = 0;
- return optional && 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[], 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 && 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[], 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 #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 #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 [99] 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[] =
{
- {-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)
if (odr_choice(o, arm, &(*p)->u, &(*p)->which), name)
return 1;
*p = 0;
- return optional && odr_ok(o);
+ return optional && 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:
+ -->
-<!-- $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 ::= [ AttSet ] QueryStruct.
+ <screen>
+ Query ::= [ AttSet ] 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>‐‐</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>‐‐</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;
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:
+ -->
<!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
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: