Added XML Docbook documentation for YAZ - will eventually replace
authorAdam Dickmeiss <adam@indexdata.dk>
Thu, 4 Jan 2001 13:36:24 +0000 (13:36 +0000)
committerAdam Dickmeiss <adam@indexdata.dk>
Thu, 4 Jan 2001 13:36:24 +0000 (13:36 +0000)
the linuxdoc SGML doc.

15 files changed:
doc/Makefile.am
doc/Makefile.in
doc/asn.xml [new file with mode: 0644]
doc/comstack.xml [new file with mode: 0644]
doc/frontend.xml [new file with mode: 0644]
doc/future.xml [new file with mode: 0644]
doc/indexdata.xml [new file with mode: 0644]
doc/installation.xml [new file with mode: 0644]
doc/introduction.xml [new file with mode: 0644]
doc/license.xml [new file with mode: 0644]
doc/odr.xml [new file with mode: 0644]
doc/tools.xml [new file with mode: 0644]
doc/xml.dcl [new file with mode: 0644]
doc/yaz.rtf
doc/yaz.xml [new file with mode: 0644]

index 09110db..79b7bba 100644 (file)
@@ -1,4 +1,4 @@
-## $Id: Makefile.am,v 1.8 2000-06-08 13:40:14 adam Exp $
+## $Id: Makefile.am,v 1.9 2001-01-04 13:36:24 adam Exp $
 
 docdir=$(pkgdatadir)/doc
 
 
 docdir=$(pkgdatadir)/doc
 
@@ -26,3 +26,12 @@ profiles.ps: profiles.sgml
 
 yaz.html: yaz.sgml
        sgml2html yaz.sgml
 
 yaz.html: yaz.sgml
        sgml2html yaz.sgml
+
+XMLFILES=yaz.xml introduction.xml installation.xml indexdata.xml \
+  asn.xml tools.xml odr.xml comstack.xml frontend.xml license.xml future.xml
+
+book1.htm: $(XMLFILES)
+       jade -E14 -d ../../docbook/docbook/html/docbook.dsl -t sgml xml.dcl yaz.xml
+
+yaz.tex: $(XMLFILES)
+       jade -d ../../docbook/docbook/print/docbook.dsl -t tex xml.dcl yaz.xml
index a649db0..2363284 100644 (file)
@@ -87,6 +87,9 @@ doc_DATA = yaz.sgml profiles.sgml  yaz.txt yaz.ps profiles.txt profiles.ps yaz.h
 
 EXTRA_DIST = yaz.sgml profiles.sgml  yaz.txt yaz.ps profiles.txt profiles.ps yaz.html  yaz-1.html yaz-2.html yaz-3.html yaz-4.html yaz-5.html  yaz-6.html yaz-7.html yaz-8.html yaz-9.html
 
 
 EXTRA_DIST = yaz.sgml profiles.sgml  yaz.txt yaz.ps profiles.txt profiles.ps yaz.html  yaz-1.html yaz-2.html yaz-3.html yaz-4.html yaz-5.html  yaz-6.html yaz-7.html yaz-8.html yaz-9.html
 
+
+XMLFILES = yaz.xml introduction.xml installation.xml indexdata.xml   asn.xml tools.xml odr.xml comstack.xml frontend.xml license.xml future.xml
+
 mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
 CONFIG_CLEAN_FILES = 
 DATA =  $(doc_DATA)
 mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
 CONFIG_CLEAN_FILES = 
 DATA =  $(doc_DATA)
@@ -228,6 +231,12 @@ profiles.ps: profiles.sgml
 yaz.html: yaz.sgml
        sgml2html yaz.sgml
 
 yaz.html: yaz.sgml
        sgml2html yaz.sgml
 
+book1.htm: $(XMLFILES)
+       jade -E14 -d ../../docbook/docbook/html/docbook.dsl -t sgml xml.dcl yaz.xml
+
+yaz.tex: $(XMLFILES)
+       jade -d ../../docbook/docbook/print/docbook.dsl -t tex xml.dcl yaz.xml
+
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
 .NOEXPORT:
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
 .NOEXPORT:
diff --git a/doc/asn.xml b/doc/asn.xml
new file mode 100644 (file)
index 0000000..bafab6d
--- /dev/null
@@ -0,0 +1,637 @@
+<!-- $Header: /home/cvsroot/yaz/doc/asn.xml,v 1.1 2001-01-04 13:36:24 adam Exp $ -->
+<chapter><title>The ASN Module</title>
+<sect1><title>Introduction</title>
+<para>
+The &asn; module provides you with a set of C struct definitions for the
+various PDUs of the protocol, as well as for the complex types
+appearing within the PDUs. For the primitive data types, the C
+representation often takes the form of an ordinary C language type,
+such as <literal>int</literal>. For ASN.1 constructs that have no direct
+representation in C, such as general octet strings and bit strings,
+the &odr; module (see section <link linkend="odr">The ODR Module</link>)
+provides auxiliary definitions.
+</para>
+</sect1>
+<sect1><title>Preparing PDUs</title>
+
+<para>
+A structure representing a complex ASN.1 type doesn't in itself contain the
+members of that type. Instead, the structure contains
+<emphasis>pointers</emphasis> to the members of the type.
+This is necessary, in part, to allow a mechanism for specifying which
+of the optional structure (SEQUENCE) members are present, and which
+are not. It follows that you will need to somehow provide space for
+the individual members of the structure, and set the pointers to
+refer to the members.
+</para>
+<para>
+The conversion routines don't care how you allocate and maintain your
+C structures - they just follow the pointers that you provide.
+Depending on the complexity of your application, and your personal
+taste, there are at least three different approaches that you may take
+when you allocate the structures.
+</para>
+
+<para>
+You can use static or automatic local variables in the function that
+prepares the PDU. This is a simple approach, and it provides the most
+efficient form of memory management. While it works well for flat
+PDUs like the InitReqest, it will generally not be sufficient for say,
+the generation of an arbitrarily complex RPN query structure.
+</para>
+<para>
+You can individually create the structure and its members using the
+<function>malloc(2)</function> function. If you want to ensure that
+the data is freed when it is no longer needed, you will have to
+define a function that individually releases each member of a
+structure before freeing the structure itself.
+</para>
+<para>
+You can use the <function>odr_malloc()</function> function (see section 
+<link linkend="odr-use">Using ODR</link> for details). When you use
+<function>odr_malloc()</function>, you can release all of the
+allocated data in a single operation, independent of any pointers and
+relations between the data. <function>odr_malloc()</function> is based on a
+&quot;nibble-memory&quot;
+scheme, in which large portions of memory are allocated, and then
+gradually handed out with each call to <function>odr_malloc()</function>.
+The next time you call <function>odr_reset()</function>, all of the
+memory allocated since the last call is recycled for future use (actually,
+it is placed on a free-list).
+</para>
+<para>
+You can combine all of the methods described here. This will often be
+the most practical approach. For instance, you might use
+<function>odr_malloc()</function> to allocate an entire structure and
+some of its elements, while you leave other elements pointing to global
+or per-session default variables.
+</para>
+
+<para>
+The &asn; module provides an important aid in creating new PDUs. For
+each of the PDU types (say, <function>Z_InitRequest</function>), a
+function is provided that allocates and initializes an instance of
+that PDU type for you. In the case of the InitRequest, the function is
+simply named <function>zget_InitRequest()</function>, and it sets up
+reasonable default value for all of the mandatory members. The optional
+members are generally initialized to null pointers. This last aspect
+is very important: it ensures that if the PDU definitions are
+extended after you finish your implementation (to accommodate
+new versions of the protocol, say), you won't get into trouble with
+uninitialized pointers in your structures. The functions use
+<function>odr_malloc()</function> to
+allocate the PDUs and its members, so you can free everything again with a
+single call to <function>odr_reset()</function>. We strongly recommend
+that you use the <literal>zget_*</literal>
+functions whenever you are preparing a PDU (in a C++ API, the
+<literal>zget_</literal>
+functions would probably be promoted to constructors for the
+individual types).
+</para>
+<para>
+The prototype for the individual PDU types generally look like this:
+</para>
+<synopsis>
+  Z_&lt;type> *zget_&lt;type>(ODR o);
+</synopsis>
+
+<para>
+eg.:
+</para>
+
+<synopsis>
+  Z_InitRequest *zget_InitRequest(ODR o);
+</synopsis>
+
+<para>
+The &odr; handle should generally be your encoding stream, but it needn't be.
+</para>
+<para>
+As well as the individual PDU functions, a function <function>
+zget_APDU()</function> is
+provided, which allocates a toplevel Z-APDU of the type requested:
+</para>
+
+<synopsis>
+  Z_APDU *zget_APDU(ODR o, int which);
+</synopsis>
+
+<para>
+The <varname>which</varname> parameter is (of course) the discriminator
+belonging to the <varname>Z_APDU</varname> <literal>CHOICE</literal> type.
+All of the interface described here is provided by the &asn; module, and
+you access it through the <filename>proto.h</filename> header file.
+
+</para>
+</sect1>
+<sect1><title id="oid">Object Identifiers</title>
+<para>
+When you refer to object identifiers in your application, you need to
+be aware that SR and Z39.50 use two different set of OIDs to refer to
+the same objects. To handle this easily, &yaz; provides a utility module
+to &asn; which provides an internal representation of the OIDs used in
+both protocols. Each oid is described by a structure:
+</para>
+
+<screen>
+typedef struct oident
+{
+    enum oid_proto proto;
+    enum oid_class class;
+    enum oid_value value;
+    int oidsuffix[OID_SIZE];
+    char *desc;
+} oident;
+</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>
+
+<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>
+typedef struct Z_External
+{
+    Odr_oid *direct_reference;
+    int *indirect_reference;
+    char *descriptor;
+    enum
+    {
+       /* 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
+
+       ...
+
+    } which;
+    union
+    {
+       /* 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;
+
+       ...
+
+    } 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>
+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 Z39.50 PDU's</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 namest="field" nameend="value">Z_InitRequest</entry>
+</row>
+
+<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>
+
+</tbody>
+</tgroup>
+</table>
+
+<screen>
+Z_InitRequest
+-------------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+protocolVersion              Odr_bitmask         Empty bitmask
+options                      Odr_bitmask         Empty bitmask
+preferredMessageSize         int                 30*1024
+maximumRecordSize            int                 30*1024
+idAuthentication             Z_IdAuthentication  NULL
+implementationId             char*               "YAZ (id=81)"
+implementationName           char*               "Index Data/YAZ"
+implementationVersion        char*               YAZ_VERSION
+userInformationField         Z_UserInformation   NULL
+otherInfo                    Z_OtherInformation  NULL
+</screen>
+
+<screen>
+Z_InitResponse
+--------------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+protocolVersion              Odr_bitmask         Empty bitmask
+options                      Odr_bitmask         Empty bitmask
+preferredMessageSize         int                 30*1024
+maximumRecordSize            int                 30*1024
+result                       bool_t              TRUE
+implementationId             char*               "YAZ (id=81)"
+implementationName           char*               "Index Data/YAZ"
+implementationVersion        char*               YAZ_VERSION
+userInformationField         Z_UserInformat..    NULL
+otherInfo                    Z_OtherInformation  NULL
+</screen>
+
+<screen>
+Z_SearchRequest
+---------------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+smallSetUpperBound           int                 0
+largeSetLowerBound           int                 1
+mediumSetPresentNumber       int                 0
+replaceIndicator             bool_t              TRUE
+resultSetName                char*               "default"
+num_databaseNames            int                 0
+databaseNames                char**              NULL
+smallSetElementSetNames      Z_ElementSetNames   NULL
+mediumSetElementSetNames     Z_ElementSetNames   NULL
+preferredRecordSyntax        Odr_oid             NULL
+query                        Z_Query             NULL
+additionalSearchInfo         Z_OtherInformation  NULL
+otherInfo                    Z_OtherInformation  NULL
+</screen>
+
+<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>
diff --git a/doc/comstack.xml b/doc/comstack.xml
new file mode 100644 (file)
index 0000000..7ecabfc
--- /dev/null
@@ -0,0 +1,739 @@
+<!-- $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>
+
+<sect1><title>Synopsis (blocking mode)</title>
+
+<programlisting>
+
+COMSTACK *stack;
+char *buf = 0;
+int size = 0, length_incoming;
+char *protocol_package; 
+int protocol_package_length;
+char server_address[] = "myserver.com:2100";
+int status;
+
+stack = cs_create(tcpip_type, 1, PROTO_Z3950);
+if (!stack) {
+    perror("cs_create");  /* note use of perror() here since we have no stack yet */
+    exit(1);
+}
+
+status = cs_connect(stack, server_address);
+if (status != 0) {
+    cs_perror(stack, "cs_connect");
+    exit(1);
+}
+
+status = cs_put(stack, protocol_package, protocol_package_length);
+if (status) {
+    cs_perror(stack, "cs_put");
+    exit(1);
+}
+
+/* Now get a response */
+
+length_incoming = cs_get(stack, &amp;buf, &amp;size);
+if (!length_incoming) {
+    fprintf(stderr, "Connection closed\n");
+    exit(1);
+} else if (length_incoming < 0) {
+    cs_perror(stack, "cs_get");
+    exit(1);
+}
+
+/* Do stuff with buf here */
+
+/* clean up */
+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>
+  (COMSTACK handle, char *buf, int len);
+</synopsis>
+
+<para>
+Sends
+<literal>buf</literal>
+down the wire. In blocking mode, this function will return only when a
+full buffer has been written, or an error has occurred. In nonblocking
+mode, it's possible that the function will be unable to send the full
+buffer at once, which will be indicated by a return value of 1. The
+function will keep track of the number of octets already written; you
+should call it repeatedly with the same values of <literal>buf</literal>
+and <literal>len</literal>, until the buffer has been transmitted.
+When a full buffer has been sent, the function will return 0 for
+success. -1 indicates an error condition (see below).
+</para>
+
+<synopsis>
+  int cs_get(COMSTACK handle, char **buf, int *size);
+</synopsis>
+
+<para>
+Receives a PDU from the peer. Returns the number of bytes
+read. In nonblocking mode, it is possible that not all of the packet can be
+read at once. In this case, the function returns 1. To simplify the
+interface, the function is
+responsible for managing the size of the buffer. It will be reallocated
+if necessary to contain large packages, and will sometimes be moved
+around internally by the subsystem when partial packages are read. Before
+calling
+<function>cs_get</function>
+for the fist time, the buffer can be initialized to the null pointer,
+and the length should also be set to 0 - cs_get will perform a
+<function>malloc(2)</function>
+on the buffer for you. When a full buffer has been read, the size of
+the package is returned (which will always be greater than 1). -1
+indicates an error condition.
+</para>
+
+<para>
+See also the <function>cs_more()</function> function below.
+</para>
+
+<synopsis>
+  int cs_more(COMSTACK handle);
+</synopsis>
+
+<para>
+The <function>cs_more()</function> function should be used in conjunction
+with <function>cs_get</function> and
+<function>select(2)</function>.
+The <function>cs_get()</function> function will sometimes
+(notably in the TCP/IP mode) read more than a single protocol package
+off the network. When this happens, the extra package is stored
+by the subsystem. After callig <function>cs_get()</function>, and before
+waiting for more input, You should always call
+<function>cs_more()</function>
+to check if there's a full protocol package already read. If
+<function>cs_more()</function>
+returns 1,
+<function>cs_get()</function>
+can be used to immediately fetch the new package. For the
+mOSI
+subsystem, the function should always return 0, but if you want your
+stuff to be protocol independent, you should use it.
+</para>
+
+<note>
+<para>
+The <function>cs_more()</function>
+function is required because the RFC1729-method
+does not provide a way of separating individual PDUs, short of
+partially decoding the BER. Some other implementations will carefully
+nibble at the packet by calling
+<function>read(2)</function>
+several times. This was felt to be too inefficient (or at least
+clumsy) - hence the call for this extra function.
+</para>
+</note>
+
+<synopsis>
+  int cs_look(COMSTACK handle);
+</synopsis>
+
+<para>
+This function is useful when you're operating in nonblocking
+mode. Call it when
+<function>select(2)</function>
+tells you there's something happening on the line. It returns one of
+the following values:
+</para>
+
+<variablelist>
+<varlistentry><term>CS_NONE</term><listitem><para>
+No event is pending. The data found on the line was not a complete package.
+</para></listitem></varlistentry>
+
+<varlistentry><term>CS_CONNECT</term><listitem><para>
+A response to your connect request has been received. Call
+<function>cs_rcvconnect</function>
+to process the event and to finalize the connection establishment.
+</para></listitem></varlistentry>
+
+<varlistentry><term>CS_DISCON</term><listitem><para>
+The other side has closed the connection (or maybe sent a disconnect
+request - but do we care? Maybe later). Call
+<function>cs_close</function> to close your end of the association as well.
+</para></listitem></varlistentry>
+
+<varlistentry><term>CS_LISTEN</term><listitem><para>
+A connect request has been received. Call <function>cs_listen</function>
+to process the event.
+</para></listitem></varlistentry>
+
+<varlistentry><term>CS_DATA</term><listitem><para>
+There's data to be found on the line. Call <function>cs_get</function>
+to get it.
+</para></listitem></varlistentry>
+</variablelist>
+
+<note>
+<para>
+You should be aware that even if
+<function>cs_look()</function>
+tells you that there's an event event pending, the corresponding
+function may still return and tell you there was nothing to be found.
+This means that only part of a package was available for reading. The
+same event will show up again, when more data has arrived.
+</para>
+</note>
+
+<synopsis>
+  int cs_fileno(COMSTACK h);
+</synopsis>
+
+<para>
+Returns the file descriptor of the association. Use this when
+file-level operations on the endpoint are required
+(<function>select(2)</function> operations, specifically).
+</para>
+</sect2>
+
+</sect1>
+
+<sect1><title>Client Side</title>
+
+<synopsis>
+  int cs_connect(COMSTACK handle, void *address);
+</synopsis>
+
+<para>
+Initiate a connection with the target at <literal>address</literal>
+(more onaddresses below). The function will return 0 on success, and 1 if
+the operation does not complete immediately (this will only
+happen on a nonblocking endpoint). In this case, use
+<function>cs_rcvconnect</function> to complete the operation,
+when <function>select(2)</function> reports input pending on the
+association.
+</para>
+
+<synopsis>
+  int cs_rcvconnect(COMSTACK handle);
+</synopsis>
+
+<para>
+Complete a connect operation initiated by <function>cs_connect()</function>.
+It will return 0 on success; 1 if the operation has not yet completed (in
+this case, call the function again later); -1 if an error has occured.
+</para>
+
+</sect1>
+
+<sect1><title>Server Side</title>
+
+<para>
+To establish a server under the <application>inetd</application> server, you
+can use
+</para>
+
+<synopsis>
+  COMSTACK cs_createbysocket(int socket, CS_TYPE type, int blocking,
+                             int protocol);
+</synopsis>
+
+<para>
+The <literal>socket</literal> parameter is an established socket (when
+your application is invoked from <application>inetd</application>, the
+socket will typically be 0.
+The following parameters are identical to the ones for
+<function>cs_create</function>.
+</para>
+
+<synopsis>
+  int cs_bind(COMSTACK handle, void *address, int mode)
+</synopsis>
+
+<para>
+Binds a local address to the endpoint. Read about addresses below. The
+<literal>mode</literal> parameter should be either
+<literal>CS_CLIENT</literal> or <literal>CS_SERVER</literal>.
+</para>
+
+<synopsis>
+  int cs_listen(COMSTACK handle, char *addr, int *addrlen);
+</synopsis>
+
+<para>
+Call this to process incoming events on an endpoint that has been
+bound in listening mode. It will return 0 to indicate that the connect
+request has been received, 1 to signal a partial reception, and -1 to
+indicate an error condition.
+</para>
+
+<synopsis>
+  COMSTACK cs_accept(COMSTACK handle);
+</synopsis>
+
+<para>
+This finalises the server-side association establishment, after
+cs_listen has completed successfully. It returns a new connection
+endpoint, which represents the new association. The application will
+typically wish to fork off a process to handle the association at this
+point, and continue listen for new connections on the old
+<literal>handle</literal>.
+</para>
+
+<para>
+You can use the call
+</para>
+
+<synopsis>
+  char *cs_addrstr(COMSTACK);
+</synopsis>
+
+<para>
+on an established connection to retrieve the hostname of the remote host.
+</para>
+
+<note>
+<para>You may need to use this function with some care if your
+name server service is slow or unreliable
+</para>
+</note>
+
+</sect1>
+<sect1><title>Addresses</title>
+
+<para>
+The low-level format of the addresses are different depending on the
+mode of communication you have chosen. A function is provided by each
+of the lower layers to map a user-friendly string-form address to the
+binary form required by the lower layers.
+</para>
+
+<synopsis>
+  struct sockaddr_in *tcpip_strtoaddr(char *str);
+
+  struct netbuf *mosi_strtoaddr(char *str);
+</synopsis>
+
+<para>
+The format for TCP/IP addresses is straightforward:
+</para>
+
+<synopsis>
+&lt;host> &lsqb; ':' &lt;portnum> &rsqb;
+</synopsis>
+
+<para>
+The <literal>hostname</literal> can be either a domain name or an IP address.
+The port number, if omitted, defaults to 210.
+</para>
+
+<para>
+For OSI, the format is
+</para>
+
+<synopsis>
+&lsqb; &lt;t-selector> '/' &rsqb; &lt;host> &lsqb; ':' &lt;port> &rsqb;
+</synopsis>
+
+<para>
+The transport selector is given as an even number of hex digits.
+</para>
+
+<para>
+You'll note that the address format for the OSI mode are just a subset
+of full presentation addresses. We use presentation addresses because
+xtimosi doesn't, in itself, allow access to the X.500 Directory
+service. We use a limited form, because we haven't yet come across an
+implementation that used more of the elements of a full p-address. It
+is a fairly simple matter to add the rest of the elements to the
+address format as needed, however: Xtimosi <emphasis>does</emphasis>
+support the full P-address structure.
+</para>
+
+<para>
+In both transport modes, the special hostname &quot;@&quot; is mapped
+to any local address (the manifest constant <literal>INADDR_ANY</literal>).
+It is used to establish local listening endpoints in the server role.
+</para>
+
+<para>
+When a connection has been established, you can use
+</para>
+
+<synopsis>
+  char cs_addrstr(COMSTACK h);
+</synopsis>
+
+<para>
+to retrieve the host name of the peer system. The function returns a pointer
+to a static area, which is overwritten on the next call to the function.
+</para>
+
+<note>
+<para>
+We have left the issue of X.500 name-to-address mapping open, for the
+moment. It would be a simple matter to provide a table-based mapping,
+if desired. Alternately, we could use the X.500 client-function that
+is provided with the ISODE (although this would defeat some of the
+purpose of using ThinOSI in the first place. We have been told that it
+should be within the realm of the possible to implement a lightweight
+implementation of the necessary X.500 client capabilities on top of
+ThinOSI. This would be the ideal solution, we feel. On the other hand, it
+still remains to be seen just what role the Directory will play in a world
+populated by ThinOSI and other pragmatic solutions.
+</para>
+</note>
+
+</sect1>
+
+<sect1><title>Diagnostics</title>
+
+<para>
+All functions return -1 if an error occurs. Typically, the functions
+will return 0 on success, but the data exchange functions
+(<function>cs_get</function>, <function>cs_put</function>,
+<function>cs_more</function>) follow special rules. Consult their
+descriptions.
+</para>
+
+<para>
+When a function (including the data exchange functions) reports an
+error condition, use the function
+<function>cs_errno()</function> to determine the cause of the
+problem. The function
+</para>
+
+<synopsis>
+  void cs_perror(COMSTACK handle char *message);
+</synopsis>
+
+<para>
+works like <function>perror(2)</function> and prints the
+<literal>message</literal> argument, along with a system message, to
+<literal>stderr</literal>. Use the character array
+</para>
+
+<synopsis>
+  extern const char *cs_errlist&lsqb;&rsqb;;
+</synopsis>
+
+<para>
+to get hold of the message, if you want to process it differently.
+The function
+</para>
+
+<synopsis>
+  const char *cs_stackerr(COMSTACK handle);
+</synopsis>
+
+<para>
+Returns an error message from the lower layer, if one has been
+provided.
+</para>
+</sect1>
+
+<sect1><title>Enabling OSI Communication</title>
+
+<sect2><title>Installing Xtimosi</title>
+<para>
+Although you will have to download Peter Furniss' XTI/mOSI
+implementation for yourself, we've tried to make the integration as
+simple as possible.
+</para>
+
+<para>
+The latest version of xtimosi will generally be under
+</para>
+
+<screen>
+ftp://pluto.ulcc.ac.uk/ulcc/thinosi/xtimosi/
+</screen>
+
+<para>
+When you have downloaded and unpacked the archive, it will (we assume)
+have created a directory called <literal>xtimosi</literal>.
+We suggest that you place this directory <emphasis>in the same
+directory</emphasis> where you unpacked the &yaz;
+distribution. This way, you shouldn't have to fiddle with the
+makefiles of &yaz; beyond uncommenting a few lines.
+</para>
+
+<para>
+Go to <literal>xtimosi/src</literal>, and type &quot;make libmosi.a/&quot;.
+This should generally create the library, ready to use.
+</para>
+
+<note>
+<para>
+The currently available release of xtimosi has some inherent
+problems that make it disfunction on certain platforms - eg. the
+Digital OSF/1 workstations. It is supposedly primarily a
+compiler problem, and we hope to see a release that is generally
+portable. While we can't guarantee that it can be brought to work
+on your platform, we'll be happy to talk to you about problems
+that you might see, and relay information to the author of the
+software. There are some signs that the <application>gcc</application>
+compiler is more likely to produce a fully functional library, but this
+hasn't been verified (we think that the problem is limited to the use
+of hexadecimal escape-codes used in strings, which are silently
+ignored by some compilers).
+</para>
+<para>
+A problem has been encountered in the communication with
+ISODE-based applications. If the ISODE presentation-user calls
+<function>PReadRequest()</function> with a timeout value different
+from <literal>OK</literal> or <literal>NOTOK</literal>,
+he will get an immediate TIMEOUT abort when receiving large (&gt;2041
+bytes, which is the SPDU-size that the ISODE likes to work with) packages
+from an xtimosi-based implementation (probably most
+other implementations as well, in fact). It seems to be a flaw in the
+ISODE API, and the workaround (for ISODE users) is to either not
+use an explicit timeout (switching to either blocking or
+nonblocking mode), or to check that the timer really has expired
+before closing the connection.
+</para>
+</note>
+
+<para>
+The next step in the installation is to modify the makefile in the toplevel
+&yaz;
+directory. The place to change is in the top of the file, and is
+clearly marked with a comment.
+</para>
+
+<para>
+Now run <literal>make</literal> in the &yaz; toplevel directory (do a
+<literal>make clean</literal> first, if the system has been previously
+made without OSI support). Use the &yaz;
+<application>yaz-ztest</application> and <application>yaz-client</application>
+demo programs to verify that OSI communication works OK. Then, you can go
+ahead and try to talk to other implementations.
+</para>
+
+<note>
+<para>
+Our interoperability experience is limited to version
+7 of the Nordic SR-Nett package, which has had several
+protocol errors fixed from the earlier releases. If you have
+problems or successes in interoperating with other
+implementations, we'd be glad to hear about it, or to help
+you make things work, as our resources allow.
+</para>
+</note>
+
+<para>
+If you write your own applications based on &yaz;, and you wish to
+include OSI support, the procedure is equally simple. You should
+include the <filename>xmosi.h</filename> header file in addition to
+<filename>comstack.h</filename>. <filename>xmosi.h</filename>
+will define the manifest constant <literal>mosi_type</literal>, which you
+should pass to the <function>cs_create()</function> function. In
+addition, you should use the function <function>mosi_strtoaddr()</function>
+rather than <function>tcpip_strtoaddr()</function> when you need to
+prepare an address.
+</para>
+
+<para>
+When you link your application, you should include (after the
+<filename>libyaz.a</filename> library) the <literal>libmosi.a</literal>
+library, and the <filename>librfc.a</filename> library provided with
+&yaz; (for OSI transport).
+</para>
+<para>
+As always, it can be very useful, if not essential, to have a look at the
+example applications to see how things are done.
+</para>
+
+</sect2>
+<sect2><title>OSI Transport</title>
+
+<para>
+Xtimosi requires an implementation of the OSI transport service under
+the X/OPEN XTI API. We provide an implementation of the RFC1006
+encapsulation of OSI/TP0 in TCP/IP (through the Berkeley Sockets API),
+as an independent part of &yaz; (it's found under the
+<filename>rfc1006</filename> directory).
+If you have access to an OSI transport provider under XTI,
+you should be able to make that work too, although it may require
+tinkering with the <function>mosi_strtoaddr()</function> function.
+</para>
+</sect2>
+
+<sect2><title>Presentation Context Management</title>
+
+<para>
+To simplify the implementation, we use Peter Furniss' alternative (PRF)
+option format
+for the Control of the presentation negotiation phase. This format
+is enabled by default when you
+compile xtimosi.
+</para>
+
+<para>
+The current version of &yaz; does <emphasis>not</emphasis> support
+presentation-layer negotiation of response record formats. The primary
+reason is that we have had access to no other SR or Z39.50
+implementations over OSI that used this
+method. Secondarily, we believe that the EXPLAIN facility is a superior
+mechanism for relaying target capabilities in this respect. This is not to
+say that we have no intentions of supporting presentation context
+negotiation - we have just hitherto given it a lower priority than other
+aspects of the protocol.
+</para>
+<para>
+One thing is certain: The addition of this capability to &yaz; should
+have only a minimal impact on existing applications, and on the
+interface to the software in general. Most likely, we will add an extra
+layer of interface to the processing of EXPLAIN records, which will
+convert back and forth between <literal>oident</literal> records (see
+section <link linkend="oid">Object Identifiers</link>) and direct or
+indirect references, given the current association setup. Implementations
+based on any of the higher-level interfaces will most likely not have to
+be changed at all.
+</para>
+</sect2>
+</sect1>
+<sect1><title>Summary and Synopsis</title>
+
+<synopsis>
+#include &lt;comstack.h>
+
+#include &lt;tcpip.h>      /* this is for TCP/IP support   */
+#include &lt;xmosi.h>      /* and this is for mOSI support */
+
+COMSTACK cs_create(CS_TYPE type, int blocking, int protocol);
+
+COMSTACK cs_createbysocket(int s, CS_TYPE type, int blocking,
+                              int protocol);
+
+int cs_bind(COMSTACK handle, int mode);
+
+int cs_connect(COMSTACK handle, void *address);
+
+int cs_rcvconnect(COMSTACK handle);
+
+int cs_listen(COMSTACK handle);
+
+COMSTACK cs_accept(COMSTACK handle);
+
+int cs_put(COMSTACK handle, char *buf, int len);
+
+int cs_get(COMSTACK handle, char **buf, int *size);
+
+int cs_more(COMSTACK handle);
+
+int cs_close(COMSTACK handle);
+
+int cs_look(COMSTACK handle);
+
+struct sockaddr_in *tcpip_strtoaddr(char *str);
+
+struct netbuf *mosi_strtoaddr(char *str);
+
+extern int cs_errno;
+
+void cs_perror(COMSTACK handle char *message);
+
+const char *cs_stackerr(COMSTACK handle);
+
+extern const char *cs_errlist[];
+</synopsis>
+</sect1>
+
+</chapter>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:1
+sgml-indent-data:t
+sgml-parent-document:"yaz.xml"
+sgml-default-dtd-file:"yaz.ced"
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/frontend.xml b/doc/frontend.xml
new file mode 100644 (file)
index 0000000..9383455
--- /dev/null
@@ -0,0 +1,713 @@
+<!-- $Header: /home/cvsroot/yaz/doc/frontend.xml,v 1.1 2001-01-04 13:36:24 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>server/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/SR, &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 prototypes and
+structure definitions. You are required to provide the
+<function>main()</function> routine for the server (which can be
+quite simple), as well as functions 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 functions 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 (if you wish to implement SCAN).
+</para></listitem>
+
+</itemizedlist>
+
+<para>
+(more functions will be added in time to support as much of
+Z39.50-1995 as possible).
+</para>
+
+<para>
+Because the model where pipes or sockets are used to access the backend
+database is a fairly common one, we have added a mechanism that allows this
+communication to take place asynchronously. In this mode, the frontend
+server doesn't have to block while the backend database is processing
+a request, but can wait for additional PDUs from the client.
+</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);
+</synopsis>
+
+<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> to handle the
+new request. If you do use global variables, you should be aware, then,
+that these cannot be shared between associations, unless you explicitly
+disallow forking by command line parameters (we advise against this for
+any purposes except debugging, as a crash or hang in the server process
+will affect all users currently signed on to the server).
+</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.
+</para></listitem></varlistentry>
+<varlistentry><term>int loglevel</term><listitem><para>
+Set this by ORing the constants defined in
+<filename>include/yaz/yaz-log.h</filename>.
+</para></listitem></varlistentry>
+<varlistentry><term>char logfile&lsqb;ODR_MAXNAME+1&rsqb;</term>
+<listitem><para>File for diagnostic output (&quot;&quot;: stderr).
+</para></listitem></varlistentry>
+<varlistentry><term>char apdufile&lsqb;ODR_MAXNAME+1&rsqb;</term>
+<listitem><para>
+Name of file for logging incoming and outgoing APDUs (&quot;&quot;: don't
+log APDUs, &quot;-&quot;: <literal>stderr</literal>).
+</para></listitem></varlistentry>
+<varlistentry><term>char default_listen&lsqb;1024&rsqb;</term>
+<listitem><para>Same form as the command-line specification of
+listener address. &quot;&quot;: no default listener address.
+Default is to listen at &quot;tcp:@:9999&quot;. You can only
+specify one default listener address in this fashion.
+</para></listitem></varlistentry>
+<varlistentry><term>enum oid_proto default_proto;</term>
+<listitem><para>Either <literal>PROTO_SR</literal> or
+<literal>PROTO_Z3950</literal>. Default is <literal>PROTO_Z39_50</literal>.
+</para></listitem></varlistentry>
+<varlistentry><term>int idle_timeout;</term>
+<listitem><para>Maximum session idletime, in minutes. Zero indicates
+no (infinite) timeout. Default is 120 minutes.
+</para></listitem></varlistentry>
+<varlistentry><term>int maxrecordsize;</term>
+<listitem><para>Maximum permissible record (message) size. Default
+is 1Mb. This amount of memory will only be allocated if a client requests a
+very large amount of records in one operation (or a big record). Set it
+to a lower number
+if you are worried about resource consumption on your host system.
+</para></listitem></varlistentry>
+<varlistentry><term>char configname&lsqb;ODR_MAXNAME+1&rsqb;</term>
+<listitem><para>Passed to the backend when a new connection is received.
+</para></listitem></varlistentry>
+<varlistentry><term>char setuid&lsqb;ODR_MAXNAME+1&rsqb;</term>
+<listitem><para>Set user id to the user specified, after binding
+the listener addresses.
+</para></listitem></varlistentry>
+</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>
+
+<synopsis>
+  bend_initresult *bend_init(bend_initrequest *r);
+</synopsis>
+
+<para>
+This function is called once for each new connection request, after
+a new process has been forked, and an initRequest has been received
+from the client. The parameter and result structures are defined as
+</para>
+
+<synopsis>
+typedef struct bend_initrequest
+{
+    char *configname;
+} bend_initrequest;
+
+typedef struct bend_initresult
+{
+    int errcode;       /* 0==OK */
+    char *errstring;   /* system error string or NULL */
+    void *handle;      /* private handle to the backend module */
+} bend_initresult;
+</synopsis>
+
+<para>
+The <literal>configname</literal> of <literal>bend_initrequest</literal>
+is currently always set to &quot;default-config&quot;. We haven't had
+use for putting anything special in the initrequest yet, but something
+might go there if the need arises (account/password info would be obvious).
+</para>
+
+<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>
+
+<synopsis>
+bend_searchresult *bend_search(void *handle, bend_searchrequest *r,
+                               int *fd);
+bend_searchresult *bend_searchresponse(void *handle);
+
+typedef struct bend_searchrequest
+{
+    char *setname;       /* name to give to this set */
+    int replace_set;     /* replace set, if it already exists */
+    int num_bases;       /* number of databases in list */
+    char **basenames;    /* databases to search */
+    Z_Query *query;      /* query structure */
+} bend_searchrequest;
+
+typedef struct bend_searchresult
+{
+    int hits;            /* number of hits */
+    int errcode;         /* 0==OK */
+    char *errstring;     /* system error string or NULL */
+} bend_searchresult;
+</synopsis>
+
+<para>
+The first thing to notice about the search request interface (as well
+as all of the following requests), is that it consists of two separate
+functions. The idea is to provide a simple facility for
+asynchronous communication with the backend server. When a
+searchrequest comes in, the server frontend will fill out the
+<function>bend_searchrequest</function> tructure, and call the
+<function>bend_search</function> function/. The <literal>fd</literal>
+argument will point to an integer variable. If you are able to do
+asynchronous I/O with your database server, you should set
+<literal>*fd</literal> to the file descriptor you use for the
+communication, and return a null pointer.
+The server frontend will then <function>select()</function> on the
+<literal>*fd</literal>, and will call
+<function>bend_searchresult</function> when it sees that data is available.
+If you don't support asynchronous I/O, you should return a pointer to the
+<function>bend_searchresult</function> immediately, and leave 
+<literal>*fd</literal> untouched. This construction is common to
+all of the <function>bend_</function> functions (except 
+<function>bend_init</function>). Note that you can choose to support
+this facility in none, any, or all of the <function>bend_</function>
+functions, and you can respond differently on each request at run-time.
+The server frontend will adapt accordingly.
+</para>
+
+<para>
+The <function>bend_searchrequest</function> is a fairly close
+approximation of a protocol searchRequest PDU. 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/proto.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 result 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>
+bend_fetchresult *bend_fetch(void *handle, bend_fetchrequest *r,
+                             int *fd);
+bend_fetchresult *bend_fetchresponse(void *handle);
+
+typedef struct bend_fetchrequest
+{
+    char *setname;       /* set name */
+    int number;          /* record number */
+    oid_value format;
+} bend_fetchrequest;
+
+typedef struct bend_fetchresult
+{
+    char *basename;      /* name of database that provided record */
+    int len;             /* length of record */
+    char *record;        /* record */
+    int last_in_set;     /* is it?  */
+    oid_value format;
+    int errcode;         /* 0==success */
+    char *errstring;     /* system error string or NULL */
+} bend_fetchresult;
+</synopsis>
+
+<note>
+<para>
+The <function>bend_fetchresponse()</function> function is not yet supported
+in this version of the software. Your implementation of
+<function>bend_fetch()</function> should always return a pointer to a
+<literal>bend_fetchresult</literal>.
+</para>
+</note>
+
+<para>
+The frontend server calls <function>bend_fetch</function> when it needs
+database records to fulfill a searchRequest or a presentRequest.
+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 result 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 currently be
+interpreted as a global error pertaining to the set, and will be returned in a
+nonSurrogateDiagnostic.
+</para>
+
+<note>
+<para>
+This is silly. Add a flag to say which is which.
+</para>
+</note>
+
+<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>
+bend_deleteresult *bend_delete(void *handle, bend_deleterequest *r,
+                               int *fd);
+bend_deleteresult *bend_deleteresponse(void *handle);
+
+typedef struct bend_deleterequest
+{
+    char *setname;
+} bend_deleterequest;
+
+typedef struct bend_deleteresult
+{
+    int errcode;         /* 0==success */
+    char *errstring;     /* system error string or NULL */
+} bend_deleteresult;
+</synopsis>
+
+<note>
+<para>
+The &quot;delete&quot; function is not yet supported in this version of
+the software.
+</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>
+
+<synopsis>
+bend_scanresult *bend_scan(void *handle, bend_scanrequest *r,
+    int *fd);
+bend_scanresult *bend_scanresponse(void *handle);
+
+typedef struct bend_scanrequest
+{
+    int num_bases;      /* number of elements in databaselist */
+    char **basenames;   /* databases to search */
+    Z_AttributesPlusTerm *term;
+    int term_position;  /* desired index of term in result list */
+    int num_entries;    /* number of entries requested */
+} bend_scanrequest;
+
+typedef struct bend_scanresult
+{
+    int num_entries;
+    struct scan_entry
+    {
+       char *term;
+       int occurrences;
+    } *entries;
+    int term_position;
+    enum
+    {
+       BEND_SCAN_SUCCESS,
+       BEND_SCAN_PARTIAL
+    } status;
+    int errcode;
+    char *errstring;
+} bend_scanresult;
+</synopsis>
+
+<note>
+<para>
+The <function>bend_scanresponse()</function> function is not yet supported
+in this version of the software. Your implementation of
+<function>bend_scan()</function> should always return a pointer to a
+<literal>bend_scanresult</literal>.
+</para>
+</note>
+</sect1>
+
+<sect1><title>Application Invocation</title>
+
+<para>
+The finished application has the following
+invocation syntax (by way of <function>statserv_main()</function>):
+</para>
+
+<synopsis>
+appname &lsqb;-szSu -a apdufile -l logfile -v loglevel&rsqb;
+&lsqb;listener ...&rsqb;
+</synopsis>
+
+<para>
+The options are
+
+<variablelist>
+
+<varlistentry><term>-a <replaceable>file</replaceable></term>
+ <listitem><para>
+Specify a file for dumping PDUs (for diagnostic purposes).
+The special name &quot;-&quot; sends output to <literal>stderr</literal>.
+</para></listitem></varlistentry>
+
+<varlistentry><term>-S</term>
+ <listitem><para>
+Don't fork 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>-s</term>
+<listitem><para>
+Use the SR protocol.
+</para></listitem></varlistentry>
+
+<varlistentry><term>-z</term>
+<listitem><para>
+Use the Z39.50 protocol (default). These two options complement
+eachother. 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>-v <replaceable>level</replaceable></term>
+<listitem><para>
+The log level. Use a comma-separated list of members of the set
+{fatal,debug,warn,log,all,none}.
+</para></listitem></varlistentry>
+
+<varlistentry><term>-u <replaceable>userid</replaceable></term>
+<listitem><para>
+Set user ID. Sets the real UID of the server process to that of the
+given user. It's useful if you aren't comfortable with having the
+server run as root, but you need to start it as such to bind a
+privileged port.
+</para></listitem></varlistentry>
+
+<varlistentry><term>-w <replaceable>dir</replaceable></term>
+<listitem><para>
+Working directory.
+</para></listitem></varlistentry>
+
+<varlistentry><term>-i</term>
+<listitem><para>
+Use this when running from the <application>inetd</application> server.
+</para></listitem></varlistentry>
+
+<varlistentry><term>-t <replaceable>minutes</replaceable></term>
+<listitem><para>
+Idle session timeout, in minutes.
+</para></listitem></varlistentry>
+
+<varlistentry><term>-k <replaceable>size</replaceable></term>
+<listitem><para>
+Maximum record size/message size, in kilobytes.
+</para></listitem></varlistentry>
+
+</variablelist>
+</para>
+
+<para>
+A listener specification consists of a transport mode followed by a
+colon (:) followed by a listener address. The transport mode is
+either <literal>osi</literal> or <literal>tcp</literal>.
+</para>
+
+<para>
+For TCP, an address has the form
+</para>
+
+<synopsis>
+  hostname | IP-number &lsqb;: portnumber&rsqb;
+</synopsis>
+
+<para>
+The port number defaults to 210 (standard Z39.50 port).
+</para>
+
+<para>
+For osi, the address form is
+</para>
+
+<synopsis>
+  &lsqb;t-selector /&rsqb; hostname | IP-number &lsqb;: portnumber&rsqb;
+</synopsis>
+
+<para>
+The transport selector is given as a string of hex digits (with an even
+number of digits). The default port number is 102 (RFC1006 port).
+</para>
+
+<para>
+Examples
+</para>
+
+<screen>
+  tcp:dranet.dra.com
+
+  osi:0402/dbserver.osiworld.com:3000
+</screen>
+
+<para>
+In both cases, the special hostname &quot;@&quot; is mapped to
+the address INADDR_ANY, which causes the server to listen on any local
+interface. To start the server listening on the registered ports for
+Z39.50 and SR over OSI/RFC1006, and to drop root privileges once the
+ports are bound, execute the server like this (from a root shell):
+</para>
+
+<screen>
+  my-server -u daemon tcp:@ -s osi:@
+</screen>
+
+<para>
+You can replace <literal>daemon</literal> with another user, eg. your
+own account, or a dedicated IR server account.
+<literal>my-server</literal> should be the name of your
+server application. You can test the procedure with the
+<application>yaz-ztest</application> application.
+</para>
+
+</sect1>
+<sect1><title>Summary and Synopsis</title>
+
+<synopsis>
+#include &lt;backend.h>
+
+bend_initresult *bend_init(bend_initrequest *r);
+
+bend_searchresult *bend_search(void *handle, bend_searchrequest *r,
+                                 int *fd);
+
+bend_searchresult *bend_searchresponse(void *handle);
+
+bend_fetchresult *bend_fetch(void *handle, bend_fetchrequest *r,
+                               int *fd);
+
+bend_fetchresult *bend_fetchresponse(void *handle);
+
+bend_scanresult *bend_scan(void *handle, bend_scanrequest *r, int *fd);
+
+bend_scanresult *bend_scanresponse(void *handle);
+
+bend_deleteresult *bend_delete(void *handle, bend_deleterequest *r,
+                                  int *fd);
+
+bend_deleteresult *bend_deleteresponse(void *handle);
+
+void bend_close(void *handle);
+</synopsis>
+</sect1>
+</chapter>
+
diff --git a/doc/future.xml b/doc/future.xml
new file mode 100644 (file)
index 0000000..c40a3c1
--- /dev/null
@@ -0,0 +1,31 @@
+<!-- $Header: /home/cvsroot/yaz/doc/future.xml,v 1.1 2001-01-04 13:36:24 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 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>
+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
diff --git a/doc/indexdata.xml b/doc/indexdata.xml
new file mode 100644 (file)
index 0000000..7095474
--- /dev/null
@@ -0,0 +1,49 @@
+<!-- $Header: /home/cvsroot/yaz/doc/indexdata.xml,v 1.1 2001-01-04 13:36:24 adam Exp $ -->
+<appendix><title>About Index Data</title>
+
+<para>
+Index Data is a consulting and software-development enterprise that
+specialises in library and information management systems. Our
+interests and expertise span a broad range of related fields, and one
+of our primary, long-term objectives is the development of a powerful
+information management
+system with open network interfaces and hypermedia capabilities.
+</para><para>
+We make this software available free of charge, on a fairly unrestrictive
+license; as a service to the networking community, and to further the
+development of quality software for open network communication.
+</para><para>
+We'll be happy to answer questions about the software, and about ourselves
+in general.
+</para>
+<para>
+<address>
+Index Data Aps
+<street>K&oslash;bmagergade 43</street>
+<postcode>1150 Copenhagen K</postcode>
+<country>Denmark</country>
+Phone <phone>+45 3341 0100</phone>
+Fax <fax>+45 3341 0101</fax>
+Email <email>info@indexdata.dk</email>
+</address>
+
+</para>
+<para>
+
+The Hacker's Jargon File has the following to say about the
+use of the
+prefix &quot;YA&quot; in the name of a software product.
+</para>
+<para>
+<citation>
+Yet Another. adj. 1. Of your own work: A
+humorous allusion often used in titles to acknowledge that the
+topic is not original, though the content is.  As in &quot;Yet Another
+AI Group&quot; or &quot;Yet Another Simulated Annealing Algorithm&quot;.
+2. Of
+others' work: Describes something of which there are already far
+too many.
+</citation>
+
+</para>
+</appendix>
diff --git a/doc/installation.xml b/doc/installation.xml
new file mode 100644 (file)
index 0000000..cbd4abd
--- /dev/null
@@ -0,0 +1,267 @@
+<!-- $Header: /home/cvsroot/yaz/doc/installation.xml,v 1.1 2001-01-04 13:36:24 adam Exp $ -->
+<chapter><title>Compilation and Installation</title>
+
+<para>
+The latest version of the software will generally be found at
+</para>
+<para>
+<ulink url="http://ftp.indexdata.dk/pub/yaz/">
+http://ftp.indexdata.dk/pub/yaz/</ulink>
+</para>
+<para>
+We have tried our best to keep the software portable, and on many
+platforms, you should be able to compile everything with little or no changes.
+So far, the software has been ported
+to the following platforms with little or no difficulties.
+
+<itemizedlist>
+<listitem><para>Unix systems</para>
+<itemizedlist>
+<listitem><para>HP/UX</para></listitem>
+<listitem><para>SunOS/Solaris</para></listitem>
+<listitem><para>DEC Unix</para></listitem>
+<listitem><para>Linux</para></listitem>
+<listitem><para>IBM AIX</para></listitem>
+<listitem><para>Data General DG/UX (with some CFLAGS tinkering)
+</para></listitem>
+<listitem><para>SGI/IRIX</para></listitem>
+<listitem><para>DDE Supermax</para></listitem>
+</itemizedlist></listitem>
+<listitem><para>Non-unix systems</para>
+<itemizedlist>
+<listitem><para>Apple Macintosh (using the Codewarrior programming
+environment and the GUSI socket libraries)</para></listitem>
+<listitem><para>MS Windows 95/98/NT/W2K (Win32)</para></listitem>
+<listitem><para>IBM AS/400</para></listitem>
+</itemizedlist></listitem>
+</itemizedlist>
+
+</para>
+<para>
+If you move the software to other platforms, we'd be grateful if you'd
+let us know about it. If you run into difficulties, we will try to help if we
+can, and if you solve the problems, we would be happy to
+include your fixes in the next release. So far, we have mostly avoided
+&num;ifdefs for individual platforms, and we'd like to keep it that
+way as far as it makes sense.
+</para>
+
+<para>
+We maintain a mailing-list for the purpose of announcing new releases and
+bug-fixes, as well as general discussion. Subscribe by sending mail to
+<ulink url="mailto:yaz-request@indexdata.dk">yaz-request@indexdata.dk</ulink>.
+General questions and problems can be directed at 
+<ulink url="mailto:yaz-help@indexdata.dk">yaz-help@indexdata.dk</ulink>, or
+the address given at the top of this document.
+</para>
+
+<sect1><title>UNIX</title>
+
+<para>
+Note that if your system doesn't have a native ANSI C compiler, you may
+have to acquire one separately. We recommend gcc.
+</para>
+<para>
+For UNIX we use GNU configure to create Makefiles for &yaz;.
+Generally it should be sufficient to run configure without options:
+</para>
+
+<screen>
+  ./configure
+</screen>
+
+<para>
+The configure script attempts to use use the C compiler specified by
+the <literal>CC</literal> environment variable. If not set, GNU C will be
+used if it is available. The <literal>CFLAGS</literal> environment variable
+holds options to be passed to the C compiler. If you're using
+Bourne-compatible shell you may pass something like this to use a
+particular C compiler with optimization enabled:
+</para>
+
+<screen>
+  CC=/opt/ccs/bin/cc CFLAGS=-O ./configure
+</screen>
+
+<para>
+To customize &yaz; the configure script also accepts a set of options.
+The most important are:
+
+<variablelist>
+<varlistentry><term><literal>--prefix </literal>path</term>
+<listitem><para>Specifies installation prefix. This is
+only needed if you run <literal>make install</literal> later to perform a
+"system" installation. The prefix is <literal>/usr/local</literal> if not
+specified.
+</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><literal>--enable-comp </literal></term>
+<listitem><para> &yaz; will be built using the ASN.1 compiler for &yaz;
+(default). If you wish to use the old decoders (in sub directory asn)
+use <literal>--disable-comp</literal> instead.
+</para></listitem>
+</varlistentry>
+<varlistentry><term><literal>--enable-threads</literal></term>
+<listitem><para>&yaz; will be built using POSIX threads.
+Specifically, <constant>_REENTRANT</constant> will be defined during
+compilation.
+</para></listitem>
+</varlistentry>
+</variablelist>
+
+</para>
+<para>
+When configured, build the software by typing:
+<screen>
+  make
+</screen>
+
+</para>
+
+<para>
+The following files are generated by the make process:
+<variablelist>
+<varlistentry><term><filename>lib/libyaz.a</filename></term>
+<listitem><para>
+The &yaz; programmers' library.
+</para></listitem></varlistentry>
+
+<varlistentry><term><filename>ztest/yaz-ztest</filename></term>
+<listitem><para>A test Z39.50 server.
+</para></listitem></varlistentry>
+
+<varlistentry><term><filename>client/yaz-client</filename></term>
+<listitem><para>A command mode Z39.50 client.
+</para></listitem></varlistentry>
+
+<varlistentry><term><filename>yaz-config</filename></term>
+<listitem><para>A Bourne-shell script that holds build
+settings for &yaz;.
+</para></listitem></varlistentry>
+
+<varlistentry><term><filename>yaz-comp</filename></term>
+<listitem><para>The ASN.1 compiler for &yaz;. Requires the
+Tcl Shell, <application>tclsh</application>, in current path to work.
+</para></listitem></varlistentry>
+</variablelist>
+
+</para>
+
+<para>
+If you wish to install &yaz; in system directories such as 
+<filename>/usr/local/bin</filename>,
+<filename>/usr/local/lib</filename> you can type:
+</para>
+
+<screen>
+  make install
+</screen>
+
+<para>
+You probably need to have root access in order to perform this.
+You must specify the <literal>--prefix</literal> option for configure if
+you wish to install &yaz; in other directories than the default 
+<filename>/usr/local/</filename>.
+</para>
+
+<para>
+If you wish to perform an un-installation of &yaz; use:
+</para>
+
+<screen>
+  make uninstall
+</screen>
+
+<para>
+This will only work if you haven't reconfigured &yaz; (and therefore
+changed installation prefix). Note that uninstall will not
+remove directories created by make install, e.g.
+<filename>/usr/local/include/yaz</filename>.
+</para>
+
+</sect1>
+<sect1><title>WIN32</title>
+
+<para>
+&yaz; is shipped with "makefiles" for the NMAKE tool that comes
+with Visual C++.
+
+Start an MS-DOS prompt and switch the sub directory <filename>WIN</filename>
+where the file <filename>makefile</filename> is located. Customize the
+installation by editing the <filename>makefile</filename> file (for example
+by using notepad).
+
+The following summarises the most important settings in that file:
+
+<table frame="top"><title>WIN32 makefile settings</title>
+<tgroup cols="2">
+<thead>
+<row>
+<entry>Setting</entry>
+<entry>Description</entry>
+</row>
+</thead>
+<tbody>
+
+<row>
+<entry><literal>NEW_Z3950</literal></entry>
+<entry> If 1, the auto-generated decoder/encoders
+for Z39.50 as written by the ASN.1 compiler will be used. If 0, the old
+decoders for Z39.50 will be used. Note, when 1, the setting TCL should
+point to the Tcl shell on your system.
+</entry>
+</row>
+
+<row>
+<entry><literal>DEBUG</literal></entry>
+<entry> If set to 1, the software is
+compiled with debugging libraries. If set to 0, the software
+is compiled with release (non-debugging) libraries.
+</entry>
+</row>
+
+<row>
+<entry><literal>TCL</literal></entry>
+<entry> Specifies the name of the Tcl shell (EXE-file).
+You do not need setting this or installing Tcl unless you wish
+to change or add ASN.1 for &yaz;.
+</entry>
+</row>
+
+</tbody>
+</tgroup>
+</table>
+
+</para>
+<para>
+When satisfied with the settings in the makefile type
+<screen>
+  nmake
+</screen>
+</para>
+<para>
+The following files are generated upon successful compilation:
+
+<variablelist>
+<varlistentry><term><filename>bin/yaz.dll</filename></term>
+<listitem><para>
+the multi-threaded &yaz; DLL.
+</para></listitem></varlistentry>
+
+<varlistentry><term><filename>bin/yaz-ztest.exe</filename></term>
+<listitem><para>
+A console Z39.50 client application.
+</para></listitem></varlistentry>
+
+<varlistentry><term><filename>bin/yaz-ztest.exe</filename></term>
+<listitem><para>
+A console Z39.50 multi threaded server.
+</para></listitem></varlistentry>
+
+</variablelist>
+
+</para>
+</sect1>
+</chapter>
+
diff --git a/doc/introduction.xml b/doc/introduction.xml
new file mode 100644 (file)
index 0000000..5cc082e
--- /dev/null
@@ -0,0 +1,93 @@
+<!-- $Header: /home/cvsroot/yaz/doc/introduction.xml,v 1.1 2001-01-04 13:36:24 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
+
+<synopsis>
+int z_xxx(ODR o, Z_xxx **p, int optional, const char *name);
+</synopsis>
+(note the lower-case &quot;z&quot; in the function name)
+</para>
+
+<note>
+<para>
+If you are using the premade definitions of the &asn; module, and you
+are not adding new protocol of your own, the only parts of &odr; that you
+need to worry about are documented in section 
+<link linkend="odr-use">Using ODR</link>.
+</para>
+</note>
+
+<para>
+When you have created a BER-encoded buffer, you can use the &comstack;
+subsystem to transmit (or receive) data over the network. The &comstack;
+module provides simple functions for establishing a connection
+(passively or actively, depending on the role of your application),
+and for exchanging BER-encoded PDUs over that connection. When you
+create a connection endpoint, you need to specify what transport to
+use (OSI or TCP/IP), and which protocol you want to use (SR or
+Z39.50). For the remainer of the connection's lifetime, you don't have
+to worry about the underlying transport protocol at all - the &comstack;
+will ensure that the correct mechanism is used.
+</para>
+<para>
+We call the combined interfaces to &odr;, &asn;, and &comstack; the service
+level API. It's the API that most closely models the Z39.50/SR
+service/protocol definition, and it provides unlimited access to all
+fields and facilities of the protocol definitions.
+</para>
+<para>
+The reason that the &yaz; service-level API is a conglomerate of the
+APIs from three different submodules is twofold. First, we wanted to allow the
+user a choice of different options for each major task. For instance,
+if you don't like the protocol API provided by &odr;/&asn;, you
+can use SNACC or BERUtils instead, and still have the benefits of the
+transparent transport approach of the &comstack; module. Secondly,
+we realise that you may have to fit the toolkit into an existing
+event-processing structure, in a way that
+is incompatible with the &comstack; interface or some other part of &yaz;.
+</para>
+</chapter>
\ No newline at end of file
diff --git a/doc/license.xml b/doc/license.xml
new file mode 100644 (file)
index 0000000..e0ec39d
--- /dev/null
@@ -0,0 +1,103 @@
+<!-- $Header: /home/cvsroot/yaz/doc/license.xml,v 1.1 2001-01-04 13:36:24 adam Exp $ -->
+<appendix><title>License</title>
+
+<sect1><title>Index Data Copyright</title>
+
+<para>
+Copyright &copy; 1995-2000 Index Data.
+</para>
+
+<para>
+Permission to use, copy, modify, distribute, and sell this software and
+its documentation, in whole or in part, for any purpose, is hereby granted,
+provided that:
+</para>
+
+<para>
+1. This copyright and permission notice appear in all copies of the
+software and its documentation. Notices of copyright or attribution
+which appear at the beginning of any file must remain unchanged.
+</para>
+
+<para>
+2. The names of Index Data or the individual authors may not be used to
+endorse or promote products derived from this software without specific
+prior written permission.
+</para>
+
+<para>
+THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+OF THIS SOFTWARE.
+</para>
+</sect1>
+<sect1><title>Additional Copyright Statements</title>
+
+<para>
+The optional CCL query language interpreter is covered by the following
+license:
+</para>
+
+<para>
+Copyright &copy; 1995, the EUROPAGATE consortium (see below).
+</para>
+
+<literallayout>
+The EUROPAGATE consortium members are:
+   University College Dublin
+   Danmarks Teknologiske Videnscenter
+   An Chomhairle Leabharlanna
+   Consejo Superior de Investigaciones Cientificas
+</literallayout>
+
+<para>
+Permission to use, copy, modify, distribute, and sell this software and
+its documentation, in whole or in part, for any purpose, is hereby granted,
+provided that:
+</para>
+
+<para>
+1. This copyright and permission notice appear in all copies of the
+software and its documentation. Notices of copyright or attribution
+which appear at the beginning of any file must remain unchanged.
+</para>
+
+<para>
+2. The names of EUROPAGATE or the project partners may not be used to
+endorse or promote products derived from this software without specific
+prior written permission.
+</para>
+
+<para>
+3. Users of this software (implementors and gateway operators) agree to
+inform the EUROPAGATE consortium of their use of the software. This
+information will be used to evaluate the EUROPAGATE project and the
+software, and to plan further developments. The consortium may use
+the information in later publications.
+</para>
+
+<para>
+4. Users of this software agree to make their best efforts, when
+documenting their use of the software, to acknowledge the EUROPAGATE
+consortium, and the role played by the software in their work.
+</para>
+
+<para>
+THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+IN NO EVENT SHALL THE EUROPAGATE CONSORTIUM OR ITS MEMBERS BE LIABLE
+FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF
+ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND
+ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+USE OR PERFORMANCE OF THIS SOFTWARE.
+</para>
+</sect1>
+</appendix>
\ No newline at end of file
diff --git a/doc/odr.xml b/doc/odr.xml
new file mode 100644 (file)
index 0000000..87af9f8
--- /dev/null
@@ -0,0 +1,1224 @@
+<!-- $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>
+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;
+    if (!(decode = odr_createmem(ODR_DECODE)))
+       return;
+
+    valp = &amp;value;
+    if (odr_integer(encode, &amp;valp, 0, 0) == 0)
+    {
+       printf("encoding went bad\n");
+       return;
+    }
+    bufferp = odr_getbuf(encode, &amp;len);
+    printf("length of encoded data is &percnt;d\n", len);
+
+    /* now let's decode the thing again */
+    odr_setbuf(decode, bufferp, len);
+    if (odr_integer(decode, &amp;resvalp, 0, 0) == 0)
+    {
+       printf("decoding went bad\n");
+       return;
+    }
+    printf("the value is &percnt;d\n", *resvalp);
+
+    /* clean up */
+    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>
+
+<para>
+You can also use the function
+</para>
+
+<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>
+
+<table frame="top"><title>ODR Error codes</title>
+<tgroup cols="2">
+<thead>
+<row>
+<entry>code</entry>
+<entry>Description</entry>
+</row>
+</thead>
+<tbody>
+<row>
+<entry>OMEMORY</entry><entry>Memory allocation failed.</entry>
+</row>
+
+<row>
+<entry>OSYSERR</entry><entry>A system- or library call has failed.
+The standard diagnostic variable <literal>errno</literal> should be
+examined to determine the actual error.</entry>
+</row>
+
+<row>
+<entry>OSPACE</entry><entry>No more space for encoding.
+This will only occur when the user has explicitly provided a
+buffer for an encoding stream without allowing the system to
+allocate more space.</entry>
+</row>
+
+<row>
+<entry>OREQUIRED</entry><entry>This is a common protocol error; A
+required data element was missing during encoding or decoding.</entry>
+</row>
+
+<row>
+<entry>OUNEXPECTED</entry><entry>An unexpected data element was
+found during decoding.</entry>
+</row>
+
+<row><entry>OOTHER</entry><entry>Other error. This is typically an
+indication of misuse of the &odr; system by the programmer, and also
+that the diagnostic system isn't as good as it should be, yet.</entry>
+</row>
+</tbody>
+</tgroup>
+</table>
+
+<para>
+The character string array
+</para>
+
+<synopsis>
+  char *odr_errlist&lsqb;&rsqb;
+</synopsis>
+
+<para>
+can be indexed by the error code to obtain a human-readable
+representation of the problem.
+</para>
+
+</sect2>
+<sect2><title>Summary and Synopsis</title>
+
+<synopsis>
+#include &lt;odr.h>
+
+ODR odr_createmem(int direction);
+
+void odr_destroy(ODR o);
+
+void odr_reset(ODR o);
+
+char *odr_getbuf(ODR o, int *len);
+
+void odr_setbuf(ODR o, char *buf, int len);
+
+void *odr_malloc(ODR o, int size);
+
+ODR_MEM odr_extract_mem(ODR o);
+
+void odr_release_mem(ODR_MEM r);
+
+int odr_geterror(ODR o);
+
+void odr_perror(char *message);
+
+extern char *odr_errlist[];
+</synopsis>
+
+</sect2>
+</sect1>
+
+<sect1><title id="odr-prog">Programming with ODR</title>
+
+<para>
+The API of &odr; is designed to reflect the structure of ASN.1, rather
+than BER itself. Future releases may be able to represent data in
+other external forms.
+</para>
+
+<para>
+The interface is based loosely on that of the Sun Microsystems XDR routines.
+Specifically, each function which corresponds to an ASN.1 primitive
+type has a dual function. Depending on the settings of the ODR
+stream which is supplied as a parameter, the function may be used
+either to encode or decode data. The functions that can be built
+using these primitive functions, to represent more complex datatypes, share
+this quality. The result is that you only have to enter the definition
+for a type once - and you have the functionality of encoding, decoding
+(and pretty-printing) all in one unit. The resulting C source code is
+quite compact, and is a pretty straightforward representation of the
+source ASN.1 specification. Although no ASN.1 compiler is supplied
+with &odr; at this time, it shouldn't be too difficult to write one, or
+perhaps even to adapt an existing compiler to output &odr; routines
+(not surprisingly, writing encoders/decoders using &odr; turns out
+to be boring work).
+</para>
+
+<para>
+In many cases, the model of the XDR functions works quite well in this
+role.
+In others, it is less elegant. Most of the hassle comes from the optional
+SEQUENCE memebers which don't exist in XDR.
+</para>
+
+<sect2><title>The Primitive ASN.1 Types</title>
+
+<para>
+ASN.1 defines a number of primitive types (many of which correspond
+roughly to primitive types in structured programming languages, such as C).
+</para>
+
+<sect3><title>INTEGER</title>
+
+<para>
+The &odr; function for encoding or decoding (or printing) the ASN.1
+INTEGER type looks like this:
+</para>
+
+<synopsis>
+  int odr_integer(ODR o, int **p, int optional, const char *name);
+</synopsis>
+
+<para>
+(we don't allow values that can't be contained in a C integer.)
+</para>
+
+<para>
+This form is typical of the primitive &odr; functions. They are named
+after the type of data that they encode or decode. They take an &odr;
+stream, an indirect reference to the type in question, and an
+<literal>optional</literal> flag (corresponding to the OPTIONAL keyword
+of ASN.1) as parameters. They all return an integer value of either one
+or zero.
+When you use the primitive functions to construct encoders for complex
+types of your own, you should follow this model as well. This
+ensures that your new types can be reused as elements in yet more
+complex types.
+</para>
+
+<para>
+The <literal>o</literal> parameter should obviously refer to a properly
+initialized &odr; stream of the right type (encoding/decoding/printing)
+for the operation that you wish to perform.
+</para>
+
+<para>
+When encoding or printing, the function first looks at
+<literal>* p</literal>. If <literal>* p</literal> (the pointer pointed
+to by <literal>p</literal>) is a null pointer, this is taken to mean that
+the data element is absent. If the <literal>optional</literal> parameter
+is nonzero, the function will return one (signifying success) without
+any further processing. If the <literal>optional</literal> is zero, an
+internal error flag is set in the &odr; stream, and the function will
+return 0. No further operations can be carried out on the stream without
+a call to the function <function>odr_reset()</function>.
+</para>
+
+<para>
+If <literal>*p</literal> is not a null pointer, it is expected to
+point to an instance of the data type. The data will be subjected to
+the encoding rules, and the result will be placed in the buffer held
+by the &odr; stream.
+</para>
+
+<para>
+The other ASN.1 primitives have similar functions that operate in
+similar manners:
+</para>
+</sect3>
+<sect3><title>BOOLEAN</title>
+
+<synopsis>
+  int odr_bool(ODR o, bool_t **p, int optional, const char *name);
+</synopsis>
+
+</sect3>
+<sect3><title>REAL</title>
+
+<para>
+Not defined.
+</para>
+
+</sect3>
+<sect3><title>NULL</title>
+
+<synopsis>
+  int odr_null(ODR o, bool_t **p, int optional, const char *name);
+</synopsis>
+
+<para>
+In this case, the value of **p is not important. If <literal>*p</literal>
+is different from the null pointer, the null value is present, otherwise
+it's absent.
+</para>
+
+</sect3>
+<sect3><title>OCTET STRING</title>
+
+<synopsis>
+  typedef struct odr_oct
+  {
+      unsigned char *buf;
+      int len;
+      int size;
+  } Odr_oct;
+
+  int odr_octetstring(ODR o, Odr_oct **p, int optional, const char *name);
+</synopsis>
+
+<para>
+The <literal>buf</literal> field should point to the character array
+that holds the octetstring. The <literal>len</literal> field holds the
+actual length, while the <literal>size</literal> field gives the size
+of the allocated array (not of interest to you, in most cases).
+The character array need not be null terminated.
+</para>
+
+<para>
+To make things a little easier, an alternative is given for string
+types that are not expected to contain embedded NULL characters (eg.
+VisibleString):
+</para>
+
+<synopsis>
+  int odr_cstring(ODR o, char **p, int optional, const char *name);
+</synopsis>
+
+<para>
+Which encoded or decodes between OCTETSTRING representations and
+null-terminates C strings.
+</para>
+
+<para>
+Functions are provided for the derived string types, eg:
+</para>
+
+<synopsis>
+  int odr_visiblestring(ODR o, char **p, int optional, const char *name);
+</synopsis>
+
+</sect3>
+<sect3><title>BIT STRING</title>
+
+<synopsis>
+  int odr_bitstring(ODR o, Odr_bitmask **p, int optional, const char *name);
+</synopsis>
+
+<para>
+The opaque type <literal>Odr_bitmask</literal> is only suitable for
+holding relatively brief bit strings, eg. for options fields, etc.
+The constant <literal>ODR_BITMASK_SIZE</literal> multiplied by 8
+gives the maximum possible number of bits.
+</para>
+
+<para>
+A set of macros are provided for manipulating the
+<literal>Odr_bitmask</literal> type:
+</para>
+
+<synopsis>
+  void ODR_MASK_ZERO(Odr_bitmask *b);
+
+  void ODR_MASK_SET(Odr_bitmask *b, int bitno);
+
+  void ODR_MASK_CLEAR(Odr_bitmask *b, int bitno);
+
+  int ODR_MASK_GET(Odr_bitmask *b, int bitno);
+</synopsis>
+
+<para>
+The functions are modelled after the manipulation functions that
+accompany the <literal>fd_set</literal> type used by the
+<function>select(2)</function> call.
+<literal>ODR_MASK_ZERO</literal> should always be called first on a
+new bitmask, to initialize the bits to zero.
+</para>
+</sect3>
+
+<sect3><title>OBJECT IDENTIFIER</title>
+
+<synopsis>
+int odr_oid(ODR o, Odr_oid **p, int optional, const char *name);
+</synopsis>
+
+<para>
+The C OID represenation is simply an array of integers, terminated by
+the value -1 (the <literal>Odr_oid</literal> type is synonymous with
+the <literal>int</literal> type).
+We suggest that you use the OID database module (see section
+<link linkend="oid">Object Identifiers</link>) to handle object identifiers
+in your application.
+</para>
+
+</sect3>
+</sect2>
+<sect2><title id="tag-prim">Tagging Primitive Types</title>
+
+<para>
+The simplest way of tagging a type is to use the
+<function>odr_implicit_tag()</function> or 
+<function>odr_explicit_tag()</function> macros:
+</para>
+
+<synopsis>
+  int odr_implicit_tag(ODR o, Odr_fun fun, int class, int tag, int
+                       optional, const char *name);
+
+  int odr_explicit_tag(ODR o, Odr_fun fun, int class, int tag,
+                       int optional, const char *name);
+</synopsis>
+
+<para>
+To create a type derived from the integer type by implicit tagging, you
+might write:
+</para>
+
+<screen>
+  MyInt ::= &lsqb;210&rsqb; IMPLICIT INTEGER
+</screen>
+
+<para>
+In the &odr; system, this would be written like:
+</para>
+
+<screen>
+int myInt(ODR o, int **p, int optional, const char *name)
+{
+    return odr_implicit_tag(o, odr_integer, p,
+                   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>
+
+<para>
+The corresponding &odr; encoder/decoder function and the associated data
+structures could be written like this:
+</para>
+
+<screen>
+  typedef struct MySequence
+  {
+    int *intval;
+    bool_t *boolval;
+  } MySequence;
+    
+  int mySequence(ODR o, MySequence **p, int optional, const char *name)
+  {
+    if (odr_sequence_begin(o, p, sizeof(**p), name) == 0)
+        return optional &amp;&amp; odr_ok(o);
+    return
+        odr_integer(o, &amp;(*p)->intval, 0, "intval") &amp;&amp;
+        odr_bool(o, &amp;(*p)->boolval, 1, "boolval") &amp;&amp;
+        odr_sequence_end(o);
+  }
+</screen>
+
+<para>
+Note the 1 in the call to <function>odr_bool()</function>, to mark
+that the sequence member is optional.
+If either of the member types had been tagged, the macros
+<function>odr_implicit()</function> or <function>odr_explicit()</function>
+could have been used.
+The new function can be used exactly like the standard functions provided
+with &odr;. It will encode, decode or pretty-print a data value of the
+<literal>MySequence</literal> type. We like to name types with an
+initial capital, as done in ASN.1 definitions, and to name the
+corresponding function with the first character of the name in lower case.
+You could, of course, name your structures, types, and functions any way
+you please - as long as you're consistent, and your code is easily readable.
+<literal>odr_ok</literal> is just that - a predicate that returns the
+state of the stream. It is used to ensure that the behaviour of the new
+type is compatible with the interface of the primitive types.
+</para>
+
+</sect2>
+<sect2><title>Tagging Constructed Types</title>
+
+<note>
+<para>
+See section <link linkend="tag-prim">Tagging Primitive types</link>
+for information on how to tag the primitive types, as well as types
+that are already defined.
+</para>
+</note>
+
+<sect3><title>Implicit Tagging</title>
+
+<para>
+Assume the type above had been defined as
+</para>
+
+<screen>
+  MySequence ::= &lsqb;10&rsqb; IMPLICIT SEQUENCE {
+     intval INTEGER,
+     boolval BOOLEAN OPTIONAL }
+</screen>
+
+<para>
+You would implement this in &odr; by calling the function
+</para>
+
+<synopsis>
+  int odr_implicit_settag(ODR o, int class, int tag);
+</synopsis>
+
+<para>
+which overrides the tag of the type immediately following it. The
+macro <function>odr_implicit()</function> works by calling
+<function>odr_implicit_settag()</function> immediately
+before calling the function pointer argument.
+Your type function could look like this:
+</para>
+
+<screen>
+  int mySequence(ODR o, MySequence **p, int optional, const char *name)
+  {
+    if (odr_implicit_settag(o, ODR_CONTEXT, 10) == 0 ||
+        odr_sequence_begin(o, p, sizeof(**p), name) == 0)
+        return optional &amp;&amp; odr_ok(o);
+    return
+        odr_integer(o, &amp;(*p)->intval, 0, "intval") &amp;&amp;
+        odr_bool(o, &amp;(*p)->boolval, 1, "boolval") &amp;&amp;
+       odr_sequence_end(o);
+}
+</screen>
+
+<para>
+The definition of the structure <literal>MySequence</literal> would be
+the same.
+</para>
+</sect3>
+
+<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>
+Assume the definition:
+</para>
+
+<screen>
+  MySequence ::= &lsqb;10&rsqb; IMPLICIT SEQUENCE {
+      intval INTEGER,
+      boolval BOOLEAN OPTIONAL }
+</screen>
+
+<para>
+Since the new type has an extra level of construction, two new functions
+are needed to encapsulate the base type:
+</para>
+
+<synopsis>
+  int odr_constructed_begin(ODR o, void *p, int class, int tag,
+                            const char *name);
+
+  int odr_constructed_end(ODR o);
+</synopsis>
+
+<para>
+Assume that the IMPLICIT in the type definition above were replaced
+with EXPLICIT (or that the IMPLICIT keyword were simply deleted, which
+would be equivalent). The structure definition would look the same,
+but the function would look like this:
+</para>
+
+<screen>
+  int mySequence(ODR o, MySequence **p, int optional, const char *name)
+  {
+    if (odr_constructed_begin(o, p, ODR_CONTEXT, 10, name) == 0)
+        return optional &amp;&amp; odr_ok(o);
+    if (o->direction == ODR_DECODE)
+        *p = odr_malloc(o, sizeof(**p));
+    if (odr_sequence_begin(o, p, sizeof(**p), 0) == 0)
+    {
+      *p = 0; /* this is almost certainly a protocol error */
+      return 0;
+    }
+    return
+        odr_integer(o, &amp;(*p)->intval, 0, "intval") &amp;&amp;
+        odr_bool(o, &amp;(*p)->boolval, 1, "boolval") &amp;&amp;
+        odr_sequence_end(o) &amp;&amp;
+        odr_constructed_end(o);
+  }
+</screen>
+
+<para>
+Notice that the interface here gets kind of nasty. The reason is
+simple: Explicitly tagged, constructed types are fairly rare in
+the protocols that we care about, so the
+aesthetic annoyance (not to mention the dangers of a cluttered
+interface) is less than the time that would be required to develop a
+better interface. Nevertheless, it is far from satisfying, and it's a
+point that will be worked on in the future. One option for you would
+be to simply apply the <function>odr_explicit()</function> macro to
+the first function, and not
+have to worry about <function>odr_constructed_*</function> yourself.
+Incidentally, as you might have guessed, the
+<function>odr_sequence_</function> functions are themselves
+implemented using the <function>/odr_constructed_</function> functions.
+</para>
+
+</sect3>
+</sect2>
+<sect2><title>SEQUENCE OF</title>
+
+<para>
+To handle sequences (arrays) of a apecific type, the function
+</para>
+
+<synopsis>
+  int odr_sequence_of(ODR o, int (*fun)(ODR o, void *p, int optional),
+                      void *p, int *num, const char *name);
+</synopsis>
+
+<para>
+The <literal>fun</literal> parameter is a pointer to the decoder/encoder
+function of the type. <literal>p</literal> is a pointer to an array of
+pointers to your type. <literal>num</literal> is the number of elements
+in the array.
+</para>
+
+<para>
+Assume a type
+</para>
+
+<screen>
+  MyArray ::= SEQUENCE OF INTEGER
+</screen>
+
+<para>
+The C representation might be
+</para>
+
+<screen>
+  typedef struct MyArray
+  {
+    int num_elements;
+    int **elements;
+  } MyArray;
+</screen>
+
+<para>
+And the function might look like
+</para>
+
+<screen>
+  int myArray(ODR o, MyArray **p, int optional, const char *name)
+  {
+    if (o->direction == ODR_DECODE)
+        *p = odr_malloc(o, sizeof(**p));
+    if (odr_sequence_of(o, odr_integer, &amp;(*p)->elements,
+       &amp;(*p)->num_elements, name))
+       return 1;
+    *p = 0;
+    return optional &amp;&amp; odr_ok(o);
+  }
+</screen>
+
+</sect2>
+<sect2><title>CHOICE Types</title>
+
+<para>
+The choice type is used fairly often in some ASN.1 definitions, so
+some work has gone into streamlining its interface.
+</para>
+
+<para>
+CHOICE types are handled by the function:
+</para>
+
+<synopsis>
+  int odr_choice(ODR o, Odr_arm arm&lsqb;&rsqb;, void *p, void *whichp,
+                 const char *name);
+</synopsis>
+
+<para>
+The <literal>arm</literal> array is used to describe each of the possible
+types that the CHOICE type may assume. Internally in your application,
+the CHOICE type is represented as a discriminated union. That is, a C union
+accompanied by an integer (or enum) identifying the active 'arm' of
+the union. <literal>whichp</literal> is a pointer to the union
+discriminator. When encoding, it is examined to determine the current
+type. When decoding, it is set to reference the type that was found in
+the input stream.
+</para>
+
+<para>
+The Odr_arm type is defined thus:
+</para>
+
+<screen>
+  typedef struct odr_arm
+  {
+    int tagmode;
+    int class;
+    int tag;
+    int which;
+    Odr_fun fun;
+    char *name;
+  } Odr_arm;
+</screen>
+
+<para>
+The interpretation of the fields are:
+</para>
+
+<variablelist>
+<varlistentry><term>tagmode</term>
+ <listitem><para>Either <literal>ODR_IMPLICIT</literal>,
+<literal>ODR_EXPLICIT</literal>, or <literal>ODR_NONE</literal> (-1) to mark
+no tagging.</para></listitem>
+</varlistentry>
+
+<varlistentry><term>which</term>
+ <listitem><para>The value of the discriminator that corresponds to
+this CHOICE element. Typically, it will be a &num;defined constant, or
+an enum member.</para></listitem>
+</varlistentry>
+
+<varlistentry><term>fun</term>
+ <listitem><para>A pointer to a function that implements the type of
+the CHOICE member. It may be either a standard &odr; type or a type
+defined by yourself.</para></listitem>
+</varlistentry>
+
+<varlistentry><term>name</term>
+ <listitem><para>Name of tag.</para></listitem>
+</varlistentry>
+</variablelist>
+
+<para>
+A handy way to prepare the array for use by the
+<function>odr_choice()</function> function is to
+define it as a static, initialized array in the beginning of your
+decoding/encoding function. Assume the type definition:
+</para>
+
+<screen>
+  MyChoice ::= CHOICE {
+    untagged INTEGER,
+    tagged   &lsqb;99&rsqb; IMPLICIT INTEGER,
+    other    BOOLEAN
+  }
+</screen>
+
+<para>
+Your C type might look like
+</para>
+
+<screen>
+  typedef struct MyChoice
+  {
+      enum
+      {
+          MyChoice_untagged,
+          MyChoice_tagged,
+          MyChoice_other
+      } which;
+      union
+      {
+          int *untagged;
+          int *tagged;
+          bool_t *other;
+      } u;
+  };
+</screen>
+
+<para>
+And your function could look like this:
+</para>
+
+<screen>
+int myChoice(ODR o, MyChoice **p, int optional, const char *name)
+{
+    static Odr_arm arm&lsqb;&rsqb; =
+    {
+        {-1, -1, -1, MyChoice_untagged, odr_integer, "untagged"},
+        {ODR_IMPLICIT, ODR_CONTEXT, 99, MyChoice_tagged, odr_integer,
+                                                            "tagged"},
+        {-1, -1, -1, MyChoice_other, odr_boolean, "other"},
+        {-1, -1, -1, -1, 0}
+    };
+
+    if (o->direction == ODR_DECODE)
+        *p = odr_malloc(o, sizeof(**p);
+    else if (!*p)
+        return optional &amp;&amp; odr_ok(o);
+
+    if (odr_choice(o, arm, &amp;(*p)->u, &amp;(*p)->which), name)
+        return 1;
+    *p = 0;
+    return optional &amp;&amp; odr_ok(o);
+}
+</screen>
+
+<para>
+In some cases (say, a non-optional choice which is a member of a sequence),
+you can "embed" the union and its discriminator in the structure
+belonging to the enclosing type, and you won't need to fiddle with
+memory allocation to create a separate structure to wrap the
+discriminator and union.
+</para>
+
+<para>
+The corresponding function is somewhat nicer in the Sun XDR interface.
+Most of the complexity of this interface comes from the possibility of
+declaring sequence elements (including CHOICEs) optional.
+</para>
+
+<para>
+The ASN.1 specifictions naturally requires that each member of a
+CHOICE have a distinct tag, so they can be told apart on decoding.
+Sometimes it can be useful to define a CHOICE that has multiple types
+that share the same tag. You'll need some other mechanism, perhaps
+keyed to the context of the CHOICE type. In effect, we would like to
+introduce a level of context-sensitiveness to our ASN.1 specification.
+When encoding an internal representation, we have no problem, as long
+as each CHOICE member has a distinct discriminator value. For
+decoding, we need a way to tell the choice function to look for a
+specific arm of the table. The function
+</para>
+
+<synopsis>
+  void odr_choice_bias(ODR o, int what);
+</synopsis>
+
+<para>
+provides this functionality. When called, it leaves a notice for the next
+call to <function>odr_choice()</function> to be called on the decoding
+stream <literal>o</literal> that only the <literal>arm</literal> entry with
+a <literal>which</literal> field equal to <literal>what</literal>
+should be tried.
+</para>
+
+<para>
+The most important application (perhaps the only one, really) is in
+the definition of application-specific EXTERNAL encoders/decoders
+which will automatically decode an ANY member given the direct or
+indirect reference.
+</para>
+
+</sect2>
+</sect1>
+
+<sect1><title>Debugging</title>
+
+<para>
+The protocol modules are suffering somewhat from a lack of diagnostic
+tools at the moment. Specifically ways to pretty-print PDUs that
+aren't recognized by the system. We'll include something to this end
+in a not-too-distant release. In the meantime, what we do when we get
+packages we don't understand is to compile the ODR module with
+<literal>ODR_DEBUG</literal> defined. This causes the module to dump tracing
+information as it processes data units. With this output and the
+protocol specification (Z39.50), it is generally fairly easy to see
+what goes wrong.
+</para>
+</sect1>
+</chapter>
diff --git a/doc/tools.xml b/doc/tools.xml
new file mode 100644 (file)
index 0000000..8b3fe80
--- /dev/null
@@ -0,0 +1,675 @@
+<!-- $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>
+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);
+
+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>
+
+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>
+
+<screen>
+Query ::= &lsqb; AttSet &rsqb; QueryStruct.
+
+AttSet ::= string.
+
+QueryStruct ::= { Attribute } Simple | Complex.
+
+Attribute ::= '@attr' AttributeType '=' AttributeValue.
+
+AttributeType ::= integer.
+
+AttributeValue ::= integer.
+
+Complex ::= Operator QueryStruct QueryStruct.
+
+Operator ::= '@and' | '@or' | '@not' | '@prox' Proximity.
+
+Simple ::= ResultSet | Term.
+
+ResultSet ::= '@set' string.
+
+Term ::= string | '"' string '"'.
+
+Proximity ::= Exclusion Distance Ordered Relation WhichCode UnitCode.
+
+Exclusion ::= '1' | '0' | 'void'.
+
+Distance ::= integer.
+
+Ordered ::= '1' | '0'.
+
+Relation ::= integer.
+
+WhichCode ::= 'known' | 'private' | integer.
+
+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>
+The following are all examples of valid queries in the PQF.
+</para>
+
+<screen>
+dylan
+
+"bob dylan"
+
+@or "dylan" "zimmerman"
+
+@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 @attr 1=4 "self portrait"
+
+@prox 0 3 1 2 k 2 dylan zimmerman
+</screen>
+
+</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>
+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>
+
+<para>
+The CCL parser obeys the following grammar for the FIND argument.
+The syntax is annotated by in the lines prefixed by
+<literal>&dash;&dash;</literal>.
+</para>
+
+<screen>
+CCL-Find ::= CCL-Find Op Elements
+           | Elements.
+
+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).
+
+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>
+typedef struct oident
+{
+    oid_proto proto;
+    oid_class oclass;
+    oid_value value;
+    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
diff --git a/doc/xml.dcl b/doc/xml.dcl
new file mode 100644 (file)
index 0000000..fed2103
--- /dev/null
@@ -0,0 +1,179 @@
+<!SGML -- SGML Declaration for valid XML documents --
+     "ISO 8879:1986 (WWW)"
+
+     CHARSET
+         BASESET
+             "ISO Registration Number 176//CHARSET
+             ISO/IEC 10646-1:1993 UCS-4 with implementation 
+             level 3//ESC 2/5 2/15 4/6"
+         DESCSET
+                0       9       UNUSED
+                9       2       9
+                11      2       UNUSED
+                13      1       13
+                14      18      UNUSED
+                32      95      32
+                127     1       UNUSED
+                128     32      UNUSED
+             -- use this instead of the official declaration because SP only
+                supports 16-bit characters --
+                160     65374   160
+                65534   2       UNUSED 
+             -- 55296   2048    UNUSED
+                57344   8190    57344
+                65534   2       UNUSED
+                65536   1048576 65536 --
+     CAPACITY NONE
+
+     SCOPE DOCUMENT
+
+     SYNTAX
+         SHUNCHAR NONE
+         BASESET "ISO Registration Number 176//CHARSET
+                 ISO/IEC 10646-1:1993 UCS-4 with implementation 
+                 level 3//ESC 2/5 2/15 4/6"
+         DESCSET
+             0 1114112 0
+         FUNCTION
+             RE    13
+             RS    10
+             SPACE 32
+             TAB   SEPCHAR 9
+
+         NAMING
+             LCNMSTRT ""
+             UCNMSTRT ""
+             NAMESTRT
+                 58 95 192-214 216-246 248-305 308-318 321-328
+                 330-382 384-451 461-496 500-501 506-535 592-680
+                 699-705 902 904-906 908 910-929 931-974 976-982
+                 986 988 990 992 994-1011 1025-1036 1038-1103
+                 1105-1116 1118-1153 1168-1220 1223-1224
+                 1227-1228 1232-1259 1262-1269 1272-1273
+                 1329-1366 1369 1377-1414 1488-1514 1520-1522
+                 1569-1594 1601-1610 1649-1719 1722-1726
+                 1728-1742 1744-1747 1749 1765-1766 2309-2361
+                 2365 2392-2401 2437-2444 2447-2448 2451-2472
+                 2474-2480 2482 2486-2489 2524-2525 2527-2529
+                 2544-2545 2565-2570 2575-2576 2579-2600
+                 2602-2608 2610-2611 2613-2614 2616-2617
+                 2649-2652 2654 2674-2676 2693-2699 2701
+                 2703-2705 2707-2728 2730-2736 2738-2739
+                 2741-2745 2749 2784 2821-2828 2831-2832
+                 2835-2856 2858-2864 2866-2867 2870-2873 2877
+                 2908-2909 2911-2913 2949-2954 2958-2960
+                 2962-2965 2969-2970 2972 2974-2975 2979-2980
+                 2984-2986 2990-2997 2999-3001 3077-3084
+                 3086-3088 3090-3112 3114-3123 3125-3129
+                 3168-3169 3205-3212 3214-3216 3218-3240
+                 3242-3251 3253-3257 3294 3296-3297 3333-3340
+                 3342-3344 3346-3368 3370-3385 3424-3425
+                 3585-3630 3632 3634-3635 3648-3653 3713-3714
+                 3716 3719-3720 3722 3725 3732-3735 3737-3743
+                 3745-3747 3749 3751 3754-3755 3757-3758 3760
+                 3762-3763 3773 3776-3780 3904-3911 3913-3945
+                 4256-4293 4304-4342 4352 4354-4355 4357-4359
+                 4361 4363-4364 4366-4370 4412 4414 4416 4428
+                 4430 4432 4436-4437 4441 4447-4449 4451 4453
+                 4455 4457 4461-4462 4466-4467 4469 4510 4520
+                 4523 4526-4527 4535-4536 4538 4540-4546 4587
+                 4592 4601 7680-7835 7840-7929 7936-7957
+                 7960-7965 7968-8005 8008-8013 8016-8023 8025
+                 8027 8029 8031-8061 8064-8116 8118-8124 8126
+                 8130-8132 8134-8140 8144-8147 8150-8155
+                 8160-8172 8178-8180 8182-8188 8486 8490-8491
+                 8494 8576-8578 12295 12321-12329 12353-12436
+                 12449-12538 12549-12588 19968-40869 44032-55203
+
+             LCNMCHAR ""
+             UCNMCHAR ""
+             NAMECHAR
+                 45-46 183 720-721 768-837 864-865 903 1155-1158
+                 1425-1441 1443-1465 1467-1469 1471 1473-1474
+                 1476 1600 1611-1618 1632-1641 1648 1750-1764
+                 1767-1768 1770-1773 1776-1785 2305-2307 2364
+                 2366-2381 2385-2388 2402-2403 2406-2415
+                 2433-2435 2492 2494-2500 2503-2504 2507-2509
+                 2519 2530-2531 2534-2543 2562 2620 2622-2626
+                 2631-2632 2635-2637 2662-2673 2689-2691 2748
+                 2750-2757 2759-2761 2763-2765 2790-2799
+                 2817-2819 2876 2878-2883 2887-2888 2891-2893
+                 2902-2903 2918-2927 2946-2947 3006-3010
+                 3014-3016 3018-3021 3031 3047-3055 3073-3075
+                 3134-3140 3142-3144 3146-3149 3157-3158
+                 3174-3183 3202-3203 3262-3268 3270-3272
+                 3274-3277 3285-3286 3302-3311 3330-3331
+                 3390-3395 3398-3400 3402-3405 3415 3430-3439
+                 3633 3636-3642 3654-3662 3664-3673 3761
+                 3764-3769 3771-3772 3782 3784-3789 3792-3801
+                 3864-3865 3872-3881 3893 3895 3897 3902-3903
+                 3953-3972 3974-3979 3984-3989 3991 3993-4013
+                 4017-4023 4025 8400-8412 8417 12293 12330-12335
+                 12337-12341 12441-12442 12445-12446 12540-12542
+
+             NAMECASE
+                 GENERAL NO
+                 ENTITY  NO
+
+         DELIM
+             GENERAL SGMLREF
+             HCRO "&#38;#x" -- 38 is the number for ampersand --
+             NESTC "/"
+             NET ">"
+             PIC "?>"
+             SHORTREF NONE
+
+         NAMES
+             SGMLREF
+
+         QUANTITY NONE
+
+         ENTITIES
+             "amp" 38
+             "lt" 60
+             "gt" 62
+             "quot" 34
+             "apos" 39
+
+     FEATURES
+         MINIMIZE
+             DATATAG NO
+             OMITTAG NO
+             RANK NO
+             SHORTTAG
+                 STARTTAG
+                     EMPTY NO
+                     UNCLOSED NO 
+                     NETENABL IMMEDNET
+                 ENDTAG
+                     EMPTY NO 
+                     UNCLOSED NO
+                 ATTRIB
+                     DEFAULT YES
+                     OMITNAME NO
+                     VALUE NO
+             EMPTYNRM YES
+             IMPLYDEF
+                 ATTLIST NO
+                 DOCTYPE NO
+                 ELEMENT NO
+                 ENTITY NO
+                 NOTATION NO
+         LINK
+             SIMPLE NO
+             IMPLICIT NO
+             EXPLICIT NO
+         OTHER
+             CONCUR NO
+             SUBDOC NO
+             FORMAL NO
+             URN NO
+             KEEPRSRE YES
+             VALIDITY TYPE
+             ENTITIES
+                 REF ANY
+                 INTEGRAL YES
+     APPINFO NONE
+     SEEALSO "ISO 8879:1986//NOTATION
+             Extensible Markup Language (XML) 1.0//EN"
+>
index c2bf7b0..e599245 100644 (file)
-{\rtf1\ansi\ansicpg1252\uc1 \deff0\deflang1033\deflangfe1033{\fonttbl{\f0\froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f1\fswiss\fcharset0\fprq2{\*\panose 020b0604020202020204}Arial;}\r
-{\f2\fmodern\fcharset0\fprq1{\*\panose 02070309020205020404}Courier New;}{\f3\froman\fcharset2\fprq2{\*\panose 05050102010706020507}Symbol;}{\f4\froman\fcharset0\fprq2{\*\panose 00000000000000000000}Times;}\r
-{\f5\fswiss\fcharset0\fprq2{\*\panose 00000000000000000000}Helvetica;}{\f6\froman\fcharset0\fprq2{\*\panose 00000000000000000000}Courier;}{\f7\fswiss\fcharset0\fprq2{\*\panose 00000000000000000000}Geneva;}\r
-{\f8\froman\fcharset0\fprq2{\*\panose 00000000000000000000}Tms Rmn;}{\f9\fswiss\fcharset0\fprq2{\*\panose 00000000000000000000}Helv;}{\f10\froman\fcharset0\fprq2{\*\panose 00000000000000000000}MS Serif;}\r
-{\f11\fswiss\fcharset0\fprq2{\*\panose 00000000000000000000}MS Sans Serif;}{\f12\froman\fcharset0\fprq2{\*\panose 00000000000000000000}New York;}{\f13\fswiss\fcharset0\fprq2{\*\panose 00000000000000000000}System;}\r
-{\f14\fnil\fcharset2\fprq2{\*\panose 05000000000000000000}Wingdings;}{\f15\fswiss\fcharset0\fprq2{\*\panose 020b0604030504040204}Tahoma;}{\f16\fnil\fcharset2\fprq2{\*\panose 00000000000000000000}Marlett;}\r
-{\f17\froman\fcharset0\fprq2{\*\panose 02040602050305030304}Book Antiqua;}{\f18\fswiss\fcharset0\fprq2{\*\panose 020b0502020202020204}Century Gothic;}{\f19\fscript\fcharset0\fprq2{\*\panose 03010101010201010101}Monotype Corsiva;}\r
-{\f20\froman\fcharset0\fprq2{\*\panose 02040604050505020304}Century Schoolbook;}{\f21\froman\fcharset2\fprq2{\*\panose 05050102010205020202}MT Extra;}{\f22\fdecor\fcharset0\fprq2{\*\panose 04020705040a02060702}Algerian;}\r
-{\f23\fswiss\fcharset0\fprq2{\*\panose 020f0704030504030204}Arial Rounded MT Bold;}{\f24\fdecor\fcharset0\fprq2{\*\panose 04030b070d0b02020403}Braggadocio;}{\f25\fswiss\fcharset0\fprq2{\*\panose 020b0903060703020204}Britannic Bold;}\r
-{\f26\fscript\fcharset0\fprq2{\*\panose 03060802040406070304}Brush Script MT;}{\f27\fdecor\fcharset0\fprq2{\*\panose 04020805060202030203}Colonna MT;}{\f28\fdecor\fcharset0\fprq2{\*\panose 04020505020e03040504}Desdemona;}\r
-{\f29\froman\fcharset0\fprq2{\*\panose 0204060206030a020304}Footlight MT Light;}{\f30\fdecor\fcharset0\fprq2{\*\panose 040307050d0c02020703}Kino MT;}{\f31\froman\fcharset0\fprq2{\*\panose 020a0a07050505020404}Wide Latin;}\r
-{\f32\fscript\fcharset0\fprq2{\*\panose 03020802060602070202}Matura MT Script Capitals;}{\f33\fdecor\fcharset0\fprq2{\*\panose 040506030a0602020202}Playbill;}{\f34\fscript\fcharset0\fprq2{\*\panose 03010500030000090005}Brush Script;}\r
-{\f35\fswiss\fcharset0\fprq2{\*\panose 020b0502020104020203}Gill Sans;}{\f36\fmodern\fcharset0\fprq1{\*\panose 02000009000000000000}Letter Gothic;}{\f37\froman\fcharset0\fprq2{\*\panose 02020602050400010903}Perpetua;}\r
-{\f38\fswiss\fcharset0\fprq2{\*\panose 020e0602050203020203}Lydian;}{\f39\fswiss\fcharset0\fprq2{\*\panose 020b0803020103020203}News Gothic;}{\f40\fswiss\fcharset0\fprq2{\*\panose 020b0606020003020203}News Gothic Condensed;}\r
-{\f41\froman\fcharset0\fprq2{\*\panose 02040a02080005020203}Photina Casual Black;}{\f42\fswiss\fcharset0\fprq2{\*\panose 020b0506020202030204}Arial Narrow;}{\f43\froman\fcharset0\fprq2{\*\panose 02050604050505020204}Bookman Old Style;}\r
-{\f44\fnil\fcharset2\fprq2{\*\panose 01010601010101010101}Monotype Sorts;}{\f45\fswiss\fcharset0\fprq2{\*\panose 020b0806030902050204}Impact;}{\f46\fswiss\fcharset0\fprq2{\*\panose 020b0a04020102020204}Arial Black;}\r
-{\f47\froman\fcharset0\fprq2{\*\panose 02020404030301010803}Garamond;}{\f48\fswiss\fcharset0\fprq2{\*\panose 00000000000000000000}AvantGarde;}{\f49\froman\fcharset0\fprq2{\*\panose 00000000000000000000}Bookman;}\r
-{\f50\fswiss\fcharset0\fprq2{\*\panose 00000000000000000000}Helvetica-Narrow;}{\f51\froman\fcharset0\fprq2{\*\panose 00000000000000000000}NewCenturySchlbk;}{\f52\froman\fcharset0\fprq2{\*\panose 00000000000000000000}Palatino;}\r
-{\f53\froman\fcharset0\fprq2{\*\panose 00000000000000000000}ZapfChancery;}{\f54\fdecor\fcharset0\fprq2{\*\panose 00000000000000000000}ZapfDingbats;}{\f145\fswiss\fcharset238\fprq2 Tahoma CE;}{\f146\fswiss\fcharset204\fprq2 Tahoma Cyr;}\r
-{\f148\fswiss\fcharset161\fprq2 Tahoma Greek;}{\f149\fswiss\fcharset162\fprq2 Tahoma Tur;}{\f150\fswiss\fcharset186\fprq2 Tahoma Baltic;}{\f307\fswiss\fcharset238\fprq2 Arial Narrow CE;}{\f308\fswiss\fcharset204\fprq2 Arial Narrow Cyr;}\r
-{\f310\fswiss\fcharset161\fprq2 Arial Narrow Greek;}{\f311\fswiss\fcharset162\fprq2 Arial Narrow Tur;}{\f312\fswiss\fcharset186\fprq2 Arial Narrow Baltic;}{\f313\froman\fcharset238\fprq2 Bookman Old Style CE;}\r
-{\f314\froman\fcharset204\fprq2 Bookman Old Style Cyr;}{\f316\froman\fcharset161\fprq2 Bookman Old Style Greek;}{\f317\froman\fcharset162\fprq2 Bookman Old Style Tur;}{\f318\froman\fcharset186\fprq2 Bookman Old Style Baltic;}\r
-{\f325\fswiss\fcharset238\fprq2 Impact CE;}{\f326\fswiss\fcharset204\fprq2 Impact Cyr;}{\f328\fswiss\fcharset161\fprq2 Impact Greek;}{\f329\fswiss\fcharset162\fprq2 Impact Tur;}{\f330\fswiss\fcharset186\fprq2 Impact Baltic;}\r
-{\f331\fswiss\fcharset238\fprq2 Arial Black CE;}{\f332\fswiss\fcharset204\fprq2 Arial Black Cyr;}{\f334\fswiss\fcharset161\fprq2 Arial Black Greek;}{\f335\fswiss\fcharset162\fprq2 Arial Black Tur;}{\f336\fswiss\fcharset186\fprq2 Arial Black Baltic;}\r
-{\f337\froman\fcharset238\fprq2 Garamond CE;}{\f338\froman\fcharset204\fprq2 Garamond Cyr;}{\f340\froman\fcharset161\fprq2 Garamond Greek;}{\f341\froman\fcharset162\fprq2 Garamond Tur;}{\f342\froman\fcharset186\fprq2 Garamond Baltic;}}\r
-{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\r
-\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;}{\stylesheet{\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 \snext0 Normal;}{\r
-\s1\qc\sb100\sa100\keepn\nowidctlpar\outlinelevel0\adjustright \b\f1\lang2057 \sbasedon0 \snext0 heading 1;}{\s2\qj\sb240\sa60\keepn\nowidctlpar\adjustright \b\i\f1\lang2057 \sbasedon0 \snext0 heading 2;}{\r
-\s3\qc\sb100\sa100\keepn\nowidctlpar\outlinelevel2\adjustright \f1\fs32\lang2057 \sbasedon0 \snext0 heading 3;}{\*\cs10 \additive Default Paragraph Font;}{\s15\qj\nowidctlpar\adjustright \fs22\lang2057 \sbasedon0 \snext16 Definition Term;}{\r
-\s16\qj\li360\nowidctlpar\adjustright \fs22\lang2057 \sbasedon0 \snext15 Definition List;}{\*\cs17 \additive \i Definition;}{\s18\qj\sb100\sa100\keepn\nowidctlpar\outlinelevel1\adjustright \b\fs48\lang2057\kerning36 \sbasedon0 \snext0 H1;}{\r
-\s19\qj\sb100\sa100\keepn\nowidctlpar\outlinelevel2\adjustright \b\fs36\lang2057 \sbasedon0 \snext0 H2;}{\s20\qj\sb100\sa100\keepn\nowidctlpar\outlinelevel3\adjustright \b\fs28\lang2057 \sbasedon0 \snext0 H3;}{\r
-\s21\qj\sb100\sa100\keepn\nowidctlpar\outlinelevel4\adjustright \b\fs22\lang2057 \sbasedon0 \snext0 H4;}{\s22\qj\sb100\sa100\keepn\nowidctlpar\outlinelevel5\adjustright \b\fs20\lang2057 \sbasedon0 \snext0 H5;}{\r
-\s23\qj\sb100\sa100\keepn\nowidctlpar\outlinelevel6\adjustright \b\fs16\lang2057 \sbasedon0 \snext0 H6;}{\s24\qj\nowidctlpar\adjustright \i\fs22\lang2057 \sbasedon0 \snext0 Address;}{\s25\qj\li360\ri360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 \r
-\sbasedon0 \snext25 Blockquote;}{\*\cs26 \additive \i CITE;}{\*\cs27 \additive \f2\fs20 CODE;}{\*\cs28 \additive \i \sbasedon10 Emphasis;}{\*\cs29 \additive \ul\cf2 \sbasedon10 Hyperlink;}{\*\cs30 \additive \ul\cf12 \sbasedon10 FollowedHyperlink;}{\*\r
-\cs31 \additive \b\f2\fs20 Keyboard;}{\s32\qj\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631\tx9590\adjustright \f2\fs20\lang2057 \sbasedon0 \snext32 Preformatted;}{\s33\qc\nowidctlpar\brdrt\brdrdb\brdrw5\brdrcf1 \r
-\adjustright \v\f1\fs16\lang2057 \snext0 \shidden z-Bottom of Form;}{\s34\qc\nowidctlpar\brdrb\brdrdb\brdrw5\brdrcf1 \adjustright \v\f1\fs16\lang2057 \snext0 \shidden z-Top of Form;}{\*\cs35 \additive \f2 Sample;}{\*\cs36 \additive \b \sbasedon10 Strong;}\r
-{\*\cs37 \additive \f2\fs20 Typewriter;}{\*\cs38 \additive \i Variable;}{\*\cs39 \additive \v\cf6 HTML Markup;}{\*\cs40 \additive \v Comment;}{\s41\qj\li567\ri567\sb100\sa100\nowidctlpar\brdrt\brdrs\brdrw10\brsp20 \brdrl\brdrs\brdrw10\brsp80 \brdrb\r
-\brdrs\brdrw10\brsp20 \brdrr\brdrs\brdrw10\brsp80 \adjustright \fs22\lang2057 \sbasedon0 \snext41 Block Text;}{\s42\sb120\sa120\nowidctlpar\adjustright \b\caps\fs20\lang2057 \sbasedon0 \snext0 \sautoupd toc 1;}{\s43\li220\nowidctlpar\adjustright \r
-\scaps\fs20\lang2057 \sbasedon0 \snext0 \sautoupd toc 2;}{\s44\li440\nowidctlpar\adjustright \i\fs20\lang2057 \sbasedon0 \snext0 \sautoupd toc 3;}{\s45\li660\nowidctlpar\adjustright \fs18\lang2057 \sbasedon0 \snext0 \sautoupd toc 4;}{\r
-\s46\li880\nowidctlpar\adjustright \fs18\lang2057 \sbasedon0 \snext0 \sautoupd toc 5;}{\s47\li1100\nowidctlpar\adjustright \fs18\lang2057 \sbasedon0 \snext0 \sautoupd toc 6;}{\s48\li1320\nowidctlpar\adjustright \fs18\lang2057 \sbasedon0 \snext0 \sautoupd \r
-toc 7;}{\s49\li1540\nowidctlpar\adjustright \fs18\lang2057 \sbasedon0 \snext0 \sautoupd toc 8;}{\s50\li1760\nowidctlpar\adjustright \fs18\lang2057 \sbasedon0 \snext0 \sautoupd toc 9;}{\s51\qc\sb100\sa100\nowidctlpar\adjustright \f1\fs48\lang2057 \r
-\sbasedon0 \snext51 Title;}{\s52\qc\sb100\sa100\keepn\nowidctlpar\outlinelevel2\adjustright \f1\fs32\lang2057 \sbasedon3 \snext52 Company name;}{\s53\qj\sb100\sa100\nowidctlpar\tqc\tx4153\tqr\tx8306\adjustright \fs22\lang2057 \sbasedon0 \snext53 header;}{\r
-\s54\qj\sb100\sa100\nowidctlpar\tqc\tx4153\tqr\tx8306\adjustright \fs22\lang2057 \sbasedon0 \snext54 footer;}{\*\cs55 \additive \sbasedon10 page number;}}{\*\listtable{\list\listtemplateid-1\listsimple{\listlevel\levelnfc0\leveljc0\levelfollow0\r
-\levelstartat0\levelspace0\levelindent0{\leveltext\'01*;}{\levelnumbers;}}{\listname ;}\listid-2}{\list\listtemplateid134807567\listsimple{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\r
-\'02\'00.;}{\levelnumbers\'01;}\fbias0 \fi-360\li360\jclisttab\tx360 }{\listname ;}\listid1104880785}}{\*\listoverridetable{\listoverride\listid-2\listoverridecount1{\lfolevel\listoverrideformat{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat0\r
-\levelold\levelspace0\levelindent360{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720 }}\ls1}{\listoverride\listid-2\listoverridecount1{\lfolevel\listoverrideformat{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat0\levelold\r
-\levelspace0\levelindent360{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720 }}\ls2}{\listoverride\listid-2\listoverridecount1{\lfolevel\listoverrideformat{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat0\levelold\levelspace0\r
-\levelindent360{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720 }}\ls3}{\listoverride\listid-2\listoverridecount1{\lfolevel\listoverrideformat{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat0\levelold\levelspace0\levelindent360\r
-{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720 }}\ls4}{\listoverride\listid1104880785\listoverridecount0\ls5}}{\*\revtbl {Unknown;}}{\info{\title YAZ User's Guide and Reference: Introduction}{\author Sebastian Hammer}{\operator Sebastian Hammer}\r
-{\creatim\yr1997\mo9\dy17\hr11\min49}{\revtim\yr1997\mo9\dy17\hr14\min14}{\version5}{\edmins26}{\nofpages49}{\nofwords16640}{\nofchars94849}{\*\company Index Data}{\nofcharsws116481}{\vern71}}\r
-\paperw11906\paperh16838\margl1273\margr1273\margt1417\margb1134 \widowctrl\ftnbj\aenddoc\hyphcaps0\viewkind1\viewscale100 \fet0\sectd \linex0\headery1440\footery1440\colsx709\titlepg\sectdefaultcl {\footer \pard\plain \r
-\s54\qc\ri360\sb100\sa100\nowidctlpar\tqc\tx4153\tqr\tx8306\adjustright \fs22\lang2057 {\cs55 - }{\field{\*\fldinst {\cs55 PAGE  }}{\fldrslt {\cs55\lang1024 34}}}{\cs55  -}{\cs55\v \'00}{\r
-\par }}{\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang{\pntxta )}}\r
-{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl8\r
-\pnlcltr\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}\pard\plain \s51\qc\sb100\sa100\nowidctlpar\adjustright \f1\fs48\lang2057 {{\*\bkmkstart s1}YAZ User's Guide and Reference\r
-\r
-\par }\pard\plain \qc\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {YAZ version 1.4\r
-\par }\pard\plain \s51\qc\sb100\sa100\nowidctlpar\adjustright \f1\fs48\lang2057 {\fs40 Index Data\r
-\par }\pard\plain \qc\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\r
-\par }\pard\plain \s41\qj\li567\ri567\sb100\sa100\nowidctlpar\brdrt\brdrs\brdrw10\brsp20 \brdrl\brdrs\brdrw10\brsp80 \brdrb\brdrs\brdrw10\brsp20 \brdrr\brdrs\brdrw10\brsp80 \adjustright \fs22\lang2057 {\cs28\i This document is the programmer's guide and re\r
-ference to the YAZ package. YAZ is a compact toolkit that provides access to the Z39.50/SR 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 refer\r
-ence when looking at the example applications provided with the package.}{\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\r
-\par }\pard\plain \s44\li440\nowidctlpar\tqr\tldot\tx9350\adjustright \i\fs20\lang2057 {\field\fldedit{\*\fldinst { TOC \\o "1-3" }}{\fldrslt {\lang1024 1. Introduction\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132415 \\h }{\lang1024 {\*\datafield \r
-08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400310035000000}}}{\fldrslt {\lang1024 2}}}{\lang1024 \r
-\par 2. Compilation and Installation\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132416 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400310036000000}}}{\fldrslt {\r
-\lang1024 3}}}{\lang1024 \r
-\par 3. The ASN Module\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132417 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400310037000000}}}{\fldrslt {\lang1024 4}}}{\r
-\lang1024 \r
-\par 3.1 Introduction\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132418 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400310038000000}}}{\fldrslt {\lang1024 4}}}{\r
-\lang1024 \r
-\par 3.2 Preparing PDUs\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132419 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400310039000000}}}{\fldrslt {\lang1024 4}}}{\r
-\lang1024 \r
-\par 3.3 Object Identifiers\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132420 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400320030000000}}}{\fldrslt {\lang1024 5}}}{\r
-\lang1024 \r
-\par 3.4 EXTERNAL Data\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132421 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400320031000000}}}{\fldrslt {\lang1024 6}}}{\r
-\lang1024 \r
-\par 3.5 PDU Contents Table\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132422 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400320032000000}}}{\fldrslt {\lang1024 7}}}{\r
-\lang1024 \r
-\par 4. Supporting Tools\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132423 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400320033000000}}}{\fldrslt {\lang1024 11}}}{\r
-\lang1024 \r
-\par 4.1 Query Syntax Parsers\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132424 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400320034000000}}}{\fldrslt {\lang1024 11}\r
-}}{\lang1024 \r
-\par 4.2 Object Identifiers\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132425 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400320035000000}}}{\fldrslt {\lang1024 16}}}{\r
-\lang1024 \r
-\par 4.3 Nibble Memory\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132426 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400320036000000}}}{\fldrslt {\lang1024 18}}}{\r
-\lang1024 \r
-\par 5. The ODR Module\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132427 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400320037000000}}}{\fldrslt {\lang1024 19}}}{\r
-\lang1024 \r
-\par 5.1 Introduction\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132428 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400320038000000}}}{\fldrslt {\lang1024 19}}}{\r
-\lang1024 \r
-\par 5.2 Using ODR\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132429 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400320039000000}}}{\fldrslt {\lang1024 19}}}{\r
-\lang1024 \r
-\par 5.3 Programming with ODR\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132430 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400330030000000}}}{\fldrslt {\lang1024 24}\r
-}}{\lang1024 \r
-\par 5.4 Debugging\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132431 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400330031000000}}}{\fldrslt {\lang1024 32}}}{\r
-\lang1024 \r
-\par 6. The COMSTACK Module\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132432 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400330032000000}}}{\fldrslt {\lang1024 32}}}{\r
-\lang1024 \r
-\par 6.1 Introduction\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132433 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400330033000000}}}{\fldrslt {\lang1024 32}}}{\r
-\lang1024 \r
-\par 6.2 Common Functions\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132434 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400330034000000}}}{\fldrslt {\lang1024 32}}}{\r
-\lang1024 \r
-\par 6.3 Client Side\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132435 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400330035000000}}}{\fldrslt {\lang1024 34}}}{\r
-\lang1024 \r
-\par 6.4 Server Side\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132436 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400330036000000}}}{\fldrslt {\lang1024 34}}}{\r
-\lang1024 \r
-\par 6.5 Addresses\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132437 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400330037000000}}}{\fldrslt {\lang1024 35}}}{\r
-\lang1024 \r
-\par 6.6 Diagnostics\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132438 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400330038000000}}}{\fldrslt {\lang1024 36}}}{\r
-\lang1024 \r
-\par 6.7 Enabling OSI Communication\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132439 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400330039000000}}}{\fldrslt {\r
-\lang1024 36}}}{\lang1024 \r
-\par 6.8 Summary and Synopsis\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132440 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400340030000000}}}{\fldrslt {\lang1024 38}\r
-}}{\lang1024 \r
-\par 7. Making an IR Interface for Your Database with YAZ\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132441 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400340031000000\r
-}}}{\fldrslt {\lang1024 38}}}{\lang1024 \r
-\par 7.1 Introduction\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132442 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400340032000000}}}{\fldrslt {\lang1024 38}}}{\r
-\lang1024 \r
-\par 7.2 The Database Frontend\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132443 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400340033000000}}}{\fldrslt {\lang1024 39}\r
-}}{\lang1024 \r
-\par 7.3 The Backend API\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132444 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400340034000000}}}{\fldrslt {\lang1024 39}}}{\r
-\lang1024 \r
-\par 7.4 Your main() Routine\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132445 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400340035000000}}}{\fldrslt {\lang1024 40}}}\r
-{\lang1024 \r
-\par 7.5 The Backend Functions\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132446 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400340036000000}}}{\fldrslt {\lang1024 41}\r
-}}{\lang1024 \r
-\par 7.6 Application Invocation\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132447 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400340037000000}}}{\fldrslt {\lang1024 44\r
-}}}{\lang1024 \r
-\par 7.7 Summary and Synopsis\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132448 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400340038000000}}}{\fldrslt {\lang1024 46}\r
-}}{\lang1024 \r
-\par 8. Future Directions\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132449 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400340039000000}}}{\fldrslt {\lang1024 46}}}{\r
-\lang1024 \r
-\par 9. License\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132450 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400350030000000}}}{\fldrslt {\lang1024 47}}}{\lang1024 \r
-\r
-\par 9.1 Index Data Copyright\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132451 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400350031000000}}}{\fldrslt {\lang1024 47}\r
-}}{\lang1024 \r
-\par 9.2 Additional Copyright Statements\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132452 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400350032000000}}}{\fldrslt {\r
-\lang1024 47}}}{\lang1024 \r
-\par 10. About Index Data\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132453 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400350033000000}}}{\fldrslt {\lang1024 48}}}{\r
-\lang1024 \r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 }}\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\r
-\par \r
-\par {\*\bkmkstart _Toc399132415}{\pntext\pard\plain\s19 \b\fs36 \hich\af0\dbch\af0\loch\f0 1.\tab}}\pard\plain \s19\qj\fi-360\li360\sb100\sa100\keepn\nowidctlpar\jclisttab\tx360{\*\pn \pnlvlbody\ilvl0\ls5\pnrnot0\pndec\pnstart1\pnindent360\pnhang{\pntxta .}}\r
-\ls5\outlinelevel2\adjustright \b\fs36\lang2057 {Introduction{\*\bkmkend s1}{\*\bkmkend _Toc399132415}\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {The }{\i Hacker's Jargon File}{ has the following to say about the use of the prefix "YA" in the name of a software product.\r
-\par }{\i 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 A\r
-nother AI Group" or "Yet Another Simulated Annealing Algorithm". 2. Of others' work: Describes something of which there are already far too many. }{\r
-\par The }{\b 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.\r
-\par The basic level, which is independent of the role, consists of three primary interfaces:\r
-\par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li720\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls1\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls1\adjustright {\b ASN}{\r
-, which provides a C representation of the Z39.50/SR protocol packages (PDUs). \r
-\par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li720\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls1\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls1\adjustright {\b ODR}{\r
-, which encodes and decodes the packages according to the BER specification. \r
-\par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li720\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls1\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls1\adjustright {\b COMSTACK}{\r
-, which exchanges the encoded packages with a peer process over a network. \r
-\par }\pard \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {The ASN module represents the ASN.1 definition of the SR/Z39.50 \r
-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 standar\r
-d itself (such as the EXTERNAL type), the C representation is provided by the }{\b ODR}{ (Open Data Representation) subsystem.\r
-\par }{\b 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 }{\b ASN}{ module generally have the prefix }{\cs27\f2\fs20 Z_}{\r
-, 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 }{\cs27\f2\fs20 Odr_}{\r
- is sometimes seen. Either way, look for the actual definition in either }{\cs27\f2\fs20 proto.h}{ (for the types from the protocol), }{\cs27\f2\fs20 odr.h}{ (for the primitive ASN.1 types, or }{\cs27\f2\fs20 odr_use.h}{ (for the ASN.1 }{\i useful}{\r
- types). The }{\b ASN}{ library also provides functions (which are, in turn, defined using }{\b ODR}{ primitives) for encoding and decoding data values. Their general form is\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par int z_xxx(ODR o, Z_xxx **p, int optional);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {(note the lower-case "z" in the function name)\r
-\par }{\i NOTE: If you are using the premade definitions of the }{\b\i ASN}{\i  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 }{\field{\*\fldinst {\i \r
-HYPERLINK "yaz-5.html" \\l "odr-use"}{\i\fs20 {\*\datafield \r
-08d0c9ea79f9bace118c8200aa004ba90b02000000090000000303000000000000c00000000000004600000b00000059415a2d352e48544d4c00ffffadde00000000000000000000000000000000000000001a000000140000000300790061007a002d0035002e00680074006d006c00080000006f00640072002d00750073\r
-00650000000000000000000000}}}{\fldrslt {\cs29\i\ul\cf2 Using ODR}}}{\i .}{\r
-\par When you have created a BER-encoded buffer, you can use the }{\b COMSTACK}{ subsystem to transmit (or receive) data over the network. The }{\b COMSTACK}{ module provides simple func\r
-tions 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/\r
-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 }{\b COMSTACK}{ will ensure that the correct mechanism is used.\r
-\par We call the combined interfaces to }{\b ODR}{, }{\b ASN}{, and }{\b COMSTACK}{\r
- 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.\r
-\par The reason that the }{\b YAZ}{\r
- 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 }{\b ODR}{/}{\r
-\b ASN}{, you can use SNACC or BERUtils instead, and still have the benefits of the transparent transport approach of the }{\b COMSTACK}{\r
- 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 }{\b COMSTACK}{ interface or some other part of }{\b YAZ}{.\r
-\par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart s2}{\*\bkmkstart _Toc399132416}2. Compilation and Installation{\*\bkmkend s2}{\*\bkmkend _Toc399132416}\r
-\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The latest version of the software will generally be found at\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par ftp://ftp.indexdata.dk/index/yaz/\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {If you can't get through to this server, try the mirror site at\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par ftp://ftp.funet.fi/pub/doc/library/z3950/yaz/\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
-When you unpack the distribution archive, it will create a directory which contains the top-level makefile as well as subdirectories for each of the modules.\r
-\par Generally, it should be sufficient to run }{\cs27\f2\fs20 make}{\r
- in this directory. 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. You may need to update the main makefile to tell the demo applications wher\r
-e to find the socket library, etc., and in some cases you'll need to jiggle the include files a bit. So far, the software has been ported to the following platforms with little or no difficulties.\r
-\par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li720\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls1\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls1\adjustright {Unix systems \r
-\par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li1440\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls1\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls1\adjustright {HP/UX \r
-\par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li1440\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls1\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls1\adjustright {SunOS/Solaris \r
-\par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li1440\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls1\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls1\adjustright {DEC Unix \r
-\par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li1440\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls1\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls1\adjustright {Linux \r
-\par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li1440\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls1\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls1\adjustright {IBM AIX \r
-\par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li1440\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls1\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls1\adjustright {Data General DG/UX (with some CFLAGS tinkering) \r
-\r
-\par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li1440\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls1\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls1\adjustright {SGI/IRIX \r
-\par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li1440\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls1\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls1\adjustright {DDE Supermax \r
-\par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li720\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls1\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls1\adjustright {Non-unix systems \r
-\par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li1440\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls1\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls1\adjustright {\r
-Apple Macintosh (using the Codewarrior programming environment and the GUSI socket libraries) \r
-\par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li1440\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls1\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls1\adjustright {MS Windows 95/NT (Win32) \r
-\par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li1440\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls1\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls1\adjustright {IBM AS/400 \r
-\par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li1440\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls1\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls1\adjustright {Digital VAX/VMS and AXP/OpenVMS\r
-\par }\pard \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {Note that if your system doesn't have a native ANSI C compiler, you may have to acquire one separately. We recommend gcc.\r
-\par If you move the software to other platforms, we'd be grateful if you'd let us know abou\r
-t 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 w\r
-ay as far as it makes sense.\r
-\par 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 }{\cs27\f2\fs20 yaz-request@index.ping.dk}{. General questions and problems can be directed at }{\r
-\cs27\f2\fs20 yaz-help@index.ping.dk}{, or the address given at the top of this document.\r
-\par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {\b0\fs24 {\*\bkmkstart s3}\r
-\par }{{\*\bkmkstart _Toc399132417}3. The ASN Module{\*\bkmkend s3}{\*\bkmkend _Toc399132417}\r
-\par {\*\bkmkstart ss3_1}{\*\bkmkstart _Toc399132418}3.1 Introduction{\*\bkmkend ss3_1}{\*\bkmkend _Toc399132418}\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The }{\b ASN}{ module provides you with a set of C struct definitions for the various PDUs of\r
- 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 }{\cs27\f2\fs20 int}{\r
-. For ASN.1 constructs that have no direct representation in C, such as general octet strings and bit strings, the }{\b ODR}{ module (see section }{\field{\*\fldinst {HYPERLINK "yaz-5.html" \\l "odr"}{\fs20 {\*\datafield \r
-08d0c9ea79f9bace118c8200aa004ba90b02000000090000000303000000000000c00000000000004600000b00000079617a2d352e68746d6c00ffffadde000000000000000000000000000000000000000000000000040000006f006400720000000000}}}{\fldrslt {\cs29\ul\cf2 ODR}}}{\r
-) provides auxiliary definitions.\r
-\par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss3_2}{\*\bkmkstart _Toc399132419}3.2 Preparing PDUs{\*\bkmkend ss3_2}{\*\bkmkend _Toc399132419}\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {A structure representing a complex ASN.1 type doesn't in itself contain the members of that type. Instead, the structure contains }{\i pointers\r
-}{ 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.\r
- 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.\r
-\par The conversion routines don't care how you allocate and maintain your C structures - they just follow the poi\r
-nters 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.\r
-\par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li720\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls2\adjustright {\r
-You can use static or automatic local variables in the fu\r
-nction 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 com\r
-plex RPN query structure. \r
-\par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li720\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls2\adjustright {\r
-You can individually create the structure and its members using the }{\cs27\f2\fs20 malloc}{(2) 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 eac\r
-h member of a structure before freeing the structure itself. \r
-\par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li720\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls2\adjustright {You can use the }{\cs27\f2\fs20 odr_malloc()}{\r
- function (see section }{\field{\*\fldinst {HYPERLINK "yaz-5.html" \\l "odr-use"}{\fs20 {\*\datafield \r
-08d0c9ea79f9bace118c8200aa004ba90b02000000090000000303000000000000c00000000000004600000b00000079617a2d352e68746d6c00ffffadde000000000000000000000000000000000000000000000000080000006f00640072002d0075007300650000000000}}}{\fldrslt {\cs29\ul\cf2 Using ODR}}}\r
-{ for details). When you use }{\cs27\f2\fs20 odr_malloc()}{, you can release all of the allocated data in a single operation, independent of any pointers and relations between the data. }{\cs27\f2\fs20 odr_malloc()}{\r
- is based on a "nibble-memory" scheme, in which large portions of memory are allocated, and then gradually handed out with each call to }{\cs27\f2\fs20 odr_malloc()}{. The next time you call }{\cs27\f2\fs20 odr_reset()}{\r
-, all of the memory allocated since the last call is recycled for future use (actually, it is placed on a free-list). \r
-\par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li720\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls2\adjustright {\r
-You can combine all of the methods described here. This will often be the most practical approach. For instance, you might use }{\cs27\f2\fs20 odr_malloc()}{\r
- to allocate an entire structure and some of its elements, while you leave other elements pointing to global or per-session default variables. \r
-\par }\pard \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {The }{\b ASN}{ module provides an important aid in creating new PDUs. For each of the PDU types (say, }{\cs27\f2\fs20 Z_InitRequest}{\r
-), 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 }{\cs27\f2\fs20 zget_Initrequest()}{\r
-, and it sets up reasonable default value for all of the mandatory \r
-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 \r
-won't get into trouble with uninitialized pointers in your structures. The functions use }{\cs27\f2\fs20 odr_malloc()}{ to allocate the PDUs and its members, so you can free everything again with a single call to }{\cs27\f2\fs20 odr_reset()}{\r
-. We strongly recommend that you use the }{\cs27\f2\fs20 zget_*}{ functions whenever you are preparing a PDU (in a C++ API, the }{\cs27\f2\fs20 zget_}{ functions would probably be promoted to constructors for the individual types).\r
-\par The prototype for the individual PDU types generally look like this:\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par Z_<type> *zget_<type>(ODR o);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {eg.:\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par Z_InitRequest *zget_InitRequest(ODR o);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The }{\b ODR}{ handle should generally be your encoding stream, but it needn't be.\r
-\par As well as the individual PDU functions, a function }{\cs27\f2\fs20 zget_APDU()}{ is provided, which allocates a toplevel Z-APDU of the type requested:\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par Z_APDU *zget_APDU(ODR o, Z_APDU_which which);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The }{\cs27\f2\fs20 which}{ parameter is (of course) the discriminator belonging to the }{\cs27\f2\fs20 Z_APDU}{\r
- CHOICE type. All of the interface described here is provided by the }{\b ASN}{ module, and you access it through the }{\cs27\f2\fs20 proto.h}{ header file.\r
-\par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart oid}{\*\bkmkstart ss3_3}{\*\bkmkstart _Toc399132420}{\*\bkmkend oid}3.3 Object Identifiers\r
-{\*\bkmkend ss3_3}{\*\bkmkend _Toc399132420}\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
-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, }{\b YAZ}{ provides a utility module to }{\b ASN}{\r
- which provides an internal representation of the OIDs used in both protocols. Each oid is described by a structure:\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par typedef struct oident\r
-\par \{\r
-\par     enum oid_proto proto;\r
-\par     enum oid_class class;\r
-\par     enum oid_value value;\r
-\par     char *desc;\r
-\par \} oident;\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The }{\cs27\f2\fs20 proto}{ field can be set to either }{\cs27\f2\fs20 PROTO_SR}{ or }{\cs27\f2\fs20 PROTO_Z3950}{. The }{\cs27\f2\fs20 class}{\r
- might be, say, }{\cs27\f2\fs20 CLASS_RECSYN}{, and the }{\cs27\f2\fs20 value}{ might be }{\cs27\f2\fs20 VAL_USMARC}{ for the USMARC record format. Functions\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par Odr_oid *oid_getoidbyent(struct oident *ent);\r
-\par struct oident *oid_getentbyoid(Odr_oid *o);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {are provided to map between object identifiers and database entries. If you store a member of the }{\cs27\f2\fs20 oid_proto}{\r
- type in your association state information, it's a simple matter, at runtime, to generate the correct OID when you need it\r
-. 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 }{\cs27\f2\fs20 desc}{\r
- field is a short, human-readable name for the PDU, useful mainly for diagnostic output.\r
-\par }{\i NO\r
-TE: 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 da\r
-tabase.}{\r
-\par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss3_4}{\*\bkmkstart _Toc399132421}3.4 EXTERNAL Data{\*\bkmkend ss3_4}{\*\bkmkend _Toc399132421}\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
-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 t\r
-hem through ASN.1 EXTERNAL constructs. To simplify the construction and access to the externally referenced data, the }{\b ASN}{ module defines a specialized version of the EXTERNAL construct, called }{\cs27\f2\fs20 Z_External}{. It is defined thus:\r
-\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par typedef struct Z_External\r
-\par \{\r
-\par     Odr_oid *direct_reference;\r
-\par     int *indirect_reference;\r
-\par     char *descriptor;\r
-\par     enum\r
-\par     \{\r
-\par         /* Generic types */\r
-\par         Z_External_single = 0,\r
-\par         Z_External_octet,\r
-\par         Z_External_arbitrary,\r
-\par \r
-\par         /* Specific types */\r
-\par         Z_External_SUTRS,\r
-\par         Z_External_explainRecord,\r
-\par         Z_External_resourceReport1,\r
-\par         Z_External_resourceReport2\r
-\par \r
-\par         ...\r
-\par \r
-\par     \} which;\r
-\par     union\r
-\par     \{\r
-\par         /* Generic types */\r
-\par         Odr_any *single_ASN1_type;\r
-\par         Odr_oct *octet_aligned;\r
-\par         Odr_bitmask *arbitrary;\r
-\par \r
-\par         /* Specific types */\r
-\par         Z_SUTRS *sutrs;\r
-\par         Z_ExplainRecord *explainRecord;\r
-\par         Z_ResourceReport1 *resourceReport1;\r
-\par         Z_ResourceReport2 *resourceReport2;\r
-\par \r
-\par         ...\r
-\par \r
-\par     \} u;\r
-\par \} Z_External;\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {When decoding, the }{\b ASN}{\r
- 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 }{\cs27\f2\fs20 which}{ field to determine the\r
- 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 }{\cs27\f2\fs20 which}{\r
- 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 }{\cs27\f2\fs20 octet_aligned}{ arm of the union.\r
-\par Some servers return ASN.1 structured data values (eg. database records) as BER-encoded records placed in the }{\cs27\f2\fs20 octet-aligned}{ branch of the EXTERNAL CHOICE. The ASN-module will }{\i not}{\r
- automatically decode these records. To help you decode the records in the application, the function\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par Z_ext_typeent *z_ext_gettypebyref(oid_value ref);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Can be used to retrieve information about the known, external data type\r
-s. The function return a pointer to a static area, or NULL, if no match for the given direct reference is found. The }{\cs27\f2\fs20 Z_ext_typeent}{ is defined as:\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par typedef struct Z_ext_typeent\r
-\par \{\r
-\par     oid_value dref;    /* the direct-reference OID value. */\r
-\par     int what;          /* discriminator value for the external CHOICE */\r
-\par     Odr_fun fun;       /* decoder function */\r
-\par \} Z_ext_typeent;\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The }{\cs27\f2\fs20 what}{\r
- member contains the Z_External union discriminator value for the given type: For the SUTRS record syntax, the value would be }{\cs27\f2\fs20 Z_External_sutrs}{. The }{\cs27\f2\fs20 fun}{\r
- member contains a pointer to the function which encodes/decodes the given type. Again, for the SUTRS record syntax, the value of }{\cs27\f2\fs20 fun}{ would be }{\cs27\f2\fs20 z_SUTRS}{ (a function pointer).\r
-\par 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 }{\cs27\f2\fs20 z_ext_gettypebyref}{\r
- 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 }{\field{\*\fldinst {HYPERLINK "yaz-5.html" \\l "odr-use"}{\fs20 {\*\datafield \r
-08d0c9ea79f9bace118c8200aa004ba90b02000000090000000303000000000000c00000000000004600000b00000079617a2d352e68746d6c00ffffadde000000000000000000000000000000000000000000000000080000006f00640072002d0075007300650000000000}}}{\fldrslt {\cs29\ul\cf2 Using ODR}}}\r
-{). \r
-\par If you want to }{\i send}{ 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.\r
-\r
-\par If you need to add new, externally defined data types, you must update the struct above, in the source file }{\cs27\f2\fs20 prt-ext.h}{, as well as the encoder/decoder in the file }{\cs27\f2\fs20 prt-ext.c}{\r
-. When changing the latter, remember to update both the }{\cs27\f2\fs20 arm}{ arrary and the list }{\cs27\f2\fs20 type_table}{, which drives the CHOICE biasing that is necessary to tell the different, structured types apart on decoding.\r
-\par }{\i NOTE: Eventually, the EXTERNAL processing will most likely automatically insert the correct OIDs or indire\r
-ct-refs. First, however, we need to determine how application-context management (specifically the presentation-context-list) should fit into the various modules.}{\r
-\par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss3_5}{\*\bkmkstart _Toc399132422}3.5 PDU Contents Table{\*\bkmkend ss3_5}{\*\bkmkend _Toc399132422}\r
-\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {We include, for reference, a listing of the fields of each top-level PDU, as well as their default settings.\r
-\par }\pard\plain \s32\qj\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\r
-\par Z_InitRequest\r
-\par -------------\r
-\par Field                        Type                Default value\r
-\par \r
-\par referenceId                  Z_ReferenceId       NULL\r
-\par protocolVersion              Odr_bitmask         Empty bitmask\r
-\par options                      Odr_bitmask         Empty bitmask\r
-\par preferredMessageSize         int                 30*1024\r
-\par maximumRecordSize            int                 30*1024\r
-\par idAuthentication             Z_IdAuthentication  NULL\r
-\par implementationId             char*               "YAZ"\r
-\par implementationName           char*               "Index Data/YAZ"\r
-\par implementationVersion        char*               YAZ_VERSION\r
-\par userInformationField         Z_UserInformation   NULL\r
-\par otherInfo                    Z_OtherInformation  NULL\r
-\par \r
-\par Z_InitResponse\r
-\par --------------\r
-\par Field                        Type                Default value\r
-\par \r
-\par referenceId                  Z_ReferenceId       NULL\r
-\par protocolVersion              Odr_bitmask         Empty bitmask\r
-\par options                      Odr_bitmask         Empty bitmask\r
-\par preferredMessageSize         int                 30*1024\r
-\par maximumRecordSize            int                 30*1024\r
-\par result                       bool_t              TRUE\r
-\par implementationId             char*               "YAZ"\r
-\par implementationName           char*               "Index Data/YAZ"\r
-\par implementationVersion        char*               YAZ_VERSION\r
-\par userInformationField         Z_UserInformat..    NULL\r
-\par otherInfo                    Z_OtherInformation  NULL\r
-\par \r
-\par Z_SearchRequest\r
-\par ---------------\r
-\par Field                        Type                Default value\r
-\par \r
-\par referenceId                  Z_ReferenceId       NULL\r
-\par smallSetUpperBound           int                 0\r
-\par largeSetLowerBound           int                 1\r
-\par mediumSetPresentNumber       int                 0\r
-\par replaceIndicator             bool_t              TRUE\r
-\par resultSetName                char*               "Default"\r
-\par num_databaseNames            int                 0\r
-\par databaseNames                char**              NULL\r
-\par smallSetElementSetNames      Z_ElementSetNames   NULL\r
-\par mediumSetElementSetNames     Z_ElementSetNames   NULL\r
-\par preferredRecordSyntax        Odr_oid             NULL\r
-\par query                        Z_Query             NULL\r
-\par additionalSearchInfo         Z_OtherInformation  NULL\r
-\par otherInfo                    Z_OtherInformation  NULL\r
-\par \r
-\par Z_SearchResponse\r
-\par ----------------\r
-\par Field                        Type                Default value\r
-\par \r
-\par referenceId                  Z_ReferenceId       NULL\r
-\par resultCount                  int                 0\r
-\par numberOfRecordsReturned      int                 0\r
-\par nextResultSetPosition        int                 0\r
-\par searchStatus                 bool_t              TRUE\r
-\par resultSetStatus              int                 NULL\r
-\par presentStatus                int                 NULL\r
-\par records                      Z_Records           NULL\r
-\par additionalSearchInfo         Z_OtherInformation  NULL\r
-\par otherInfo                    Z_OtherInformation  NULL\r
-\par \r
-\par Z_PresentRequest\r
-\par ----------------\r
-\par Field                        Type                Default value\r
-\par \r
-\par referenceId                  Z_ReferenceId       NULL\r
-\par resultSetId                  char*               "Default"\r
-\par resultSetStartPoint          int                 1\r
-\par numberOfRecordsRequested     int                 10\r
-\par num_ranges                   int                 0\r
-\par additionalRanges             Z_Range             NULL\r
-\par recordComposition            Z_RecordComposition NULL\r
-\par preferredRecordSyntax        Odr_oid             NULL\r
-\par maxSegmentCount              int                 NULL\r
-\par maxRecordSize                int                 NULL\r
-\par maxSegmentSize               int                 NULL\r
-\par otherInfo                    Z_OtherInformation  NULL\r
-\par \r
-\par Z_PresentResponse\r
-\par -----------------\r
-\par Field                        Type                Default value\r
-\par \r
-\par referenceId                  Z_ReferenceId       NULL\r
-\par numberOfRecordsReturned      int                 0\r
-\par nextResultSetPosition        int                 0\r
-\par presentStatus                int                 Z_PRES_SUCCESS\r
-\par records                      Z_Records           NULL\r
-\par otherInfo                    Z_OtherInformation  NULL\r
-\par \r
-\par Z_DeleteResultSetRequest\r
-\par ------------------------\r
-\par Field                        Type                Default value\r
-\par \r
-\par referenceId                  Z_ReferenceId       NULL\r
-\par deleteFunction               int                 Z_DeleteRequest_list\r
-\par num_ids                      int                 0\r
-\par resultSetList                char**              NULL\r
-\par otherInfo                    Z_OtherInformation  NULL\r
-\par \r
-\par Z_DeleteResultSetResponse\r
-\par -------------------------\r
-\par Field                        Type                Default value\r
-\par \r
-\par referenceId                  Z_ReferenceId       NULL\r
-\par deleteOperationStatus        int                 Z_DeleteStatus_success\r
-\par num_statuses                 int                 0\r
-\par deleteListStatuses           Z_ListStatus**      NULL\r
-\par numberNotDeleted             int                 NULL\r
-\par num_bulkStatuses             int                 0\r
-\par bulkStatuses                 Z_ListStatus        NULL\r
-\par deleteMessage                char*               NULL\r
-\par otherInfo                    Z_OtherInformation  NULL\r
-\par \r
-\par Z_ScanRequest\r
-\par -------------\r
-\par Field                        Type                Default value\r
-\par \r
-\par referenceId                  Z_ReferenceId       NULL\r
-\par num_databaseNames            int                 0\r
-\par databaseNames                char**              NULL\r
-\par attributeSet                 Odr_oid             NULL\r
-\par termListAndStartPoint        Z_AttributesPlus... NULL\r
-\par stepSize                     int                 NULL\r
-\par numberOfTermsRequested       int                 20\r
-\par preferredPositionInResponse  int                 NULL\r
-\par otherInfo                    Z_OtherInformation  NULL\r
-\par \r
-\par Z_ScanResponse\r
-\par --------------\r
-\par Field                        Type                Default value\r
-\par \r
-\par referenceId                  Z_ReferenceId       NULL\r
-\par stepSize                     int                 NULL\r
-\par scanStatus                   int                 Z_Scan_success\r
-\par numberOfEntriesReturned      int                 0\r
-\par positionOfTerm               int                 NULL\r
-\par entries                      Z_ListEntris        NULL\r
-\par attributeSet                 Odr_oid             NULL\r
-\par otherInfo                    Z_OtherInformation  NULL\r
-\par \r
-\par Z_TriggerResourceControlRequest\r
-\par -------------------------------\r
-\par Field                        Type                Default value\r
-\par \r
-\par referenceId                  Z_ReferenceId       NULL\r
-\par requestedAction              int                 Z_TriggerResourceCtrl_resou..\r
-\par prefResourceReportFormat     Odr_oid             NULL\r
-\par resultSetWanted              bool_t              NULL\r
-\par otherInfo                    Z_OtherInformation  NULL\r
-\par \r
-\par Z_ResourceControlRequest\r
-\par ------------------------\r
-\par Field                        Type                Default value\r
-\par \r
-\par referenceId                  Z_ReferenceId       NULL\r
-\par suspendedFlag                bool_t              NULL\r
-\par resourceReport               Z_External          NULL\r
-\par partialResultsAvailable      int                 NULL\r
-\par responseRequired             bool_t              FALSE\r
-\par triggeredRequestFlag         bool_t              NULL\r
-\par otherInfo                    Z_OtherInformation  NULL\r
-\par \r
-\par Z_ResourceControlResponse\r
-\par -------------------------\r
-\par Field                        Type                Default value\r
-\par \r
-\par referenceId                  Z_ReferenceId       NULL\r
-\par continueFlag                 bool_t              TRUE\r
-\par resultSetWanted              bool_t              NULL\r
-\par otherInfo                    Z_OtherInformation  NULL\r
-\par \r
-\par Z_AccessControlRequest\r
-\par ----------------------\r
-\par Field                        Type                Default value\r
-\par \r
-\par referenceId                  Z_ReferenceId       NULL\r
-\par which                        enum                Z_AccessRequest_simpleForm;\r
-\par u                            union               NULL\r
-\par otherInfo                    Z_OtherInformation  NULL\r
-\par \r
-\par Z_AccessControlResponse\r
-\par -----------------------\r
-\par Field                        Type                Default value\r
-\par \r
-\par referenceId                  Z_ReferenceId       NULL\r
-\par which                        enum                Z_AccessResponse_simpleForm\r
-\par u                            union               NULL\r
-\par diagnostic                   Z_DiagRec           NULL\r
-\par otherInfo                    Z_OtherInformation  NULL\r
-\par \r
-\par Z_Segment\r
-\par ---------\r
-\par Field                        Type                Default value\r
-\par \r
-\par referenceId                  Z_ReferenceId       NULL\r
-\par numberOfRecordsReturned      int                 value=0\r
-\par num_segmentRecords           int                 0\r
-\par segmentRecords               Z_NamePlusRecord    NULL\r
-\par otherInfo                    Z_OtherInformation  NULL\r
-\par \r
-\par Z_Close\r
-\par -------\r
-\par Field                        Type                Default value\r
-\par \r
-\par referenceId                  Z_ReferenceId       NULL\r
-\par closeReason                  int                 Z_Close_finished\r
-\par diagnosticInformation        char*               NULL\r
-\par resourceReportFormat         Odr_oid             NULL\r
-\par resourceFormat               Z_External          NULL\r
-\par otherInfo                    Z_OtherInformation  NULL\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
-\par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart s4}{\*\bkmkstart _Toc399132423}4. Supporting Tools{\*\bkmkend s4}{\*\bkmkend _Toc399132423}\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
-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.\r
-\par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss4_1}{\*\bkmkstart _Toc399132424}4.1 Query Syntax Parsers{\*\bkmkend ss4_1}{\*\bkmkend _Toc399132424}\r
-\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
-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 }{\cs27\f2\fs20 Z_RPNQuery}{\r
- structure. Some programmers will prefer to construct the query manually, perhaps using }{\cs27\f2\fs20 odr_malloc()}{ to simplify memory management. The YAZ distribution includes two separate, query-generating tools that may be of use to you.\r
-\par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {Prefix Query Format\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
-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 rea\r
-son 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 d\r
-emonstration client included with YAZ uses the PQF.\r
-\par The PQF is defined by the pquery module in the YAZ library. The }{\cs27\f2\fs20 pquery.h}{ file provides the declaration of the functions\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par Z_RPNQuery *p_query_rpn (ODR o, oid_proto proto, const char *qbuf);\r
-\par \r
-\par Z_AttributesPlusTerm *p_query_scan (ODR o, oid_proto proto,\r
-\par       Odr_oid **attributeSetP, const char *qbuf);\r
-\par \r
-\par int p_query_attset (const char *arg);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The function }{\cs27\f2\fs20 p_query_rpn()}{ takes as arguments an }{\b ODR}{ stream (see section }{\field{\*\fldinst {HYPERLINK "yaz-5.html" \r
-\\l "odr"}{\fs20 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000090000000303000000000000c00000000000004600000b00000079617a2d352e68746d6c00ffffadde000000000000000000000000000000000000000000000000040000006f006400720000000000}}}{\fldrslt {\r
-\cs29\ul\cf2 The ODR Module}}}{) to provide a memory source (the structure created is released on the next call to }{\cs27\f2\fs20 odr_reset()}{ on the stream/), a protocol identifier (one of the constants }{\cs27\f2\fs20 PROTO_Z3950}{ and }{\r
-\cs27\f2\fs20 PROTO_SR}{), an attribute set reference, and finally a null-terminated string holding the query string.\r
-\par If the parse went well, }{\cs27\f2\fs20 p_query_rpn()}{ returns a pointer to a }{\cs27\f2\fs20 Z_RPNQuery}{ structure which can be placed directly into a }{\cs27\f2\fs20 Z_SearchRequest}{.\r
-\par The }{\cs27\f2\fs20 p_query_attset}{ specifies which attribute set to use if the query doesn't specify one by the }{\cs27\f2\fs20 @attrset}{ operator. The }{\cs27\f2\fs20 p_query_attset}{\r
- returns 0 if the argument is a valid attribute set specifier; otherwise the function returns -1.\r
-\par The grammar of the PQF is as follows:\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par Query ::= [ AttSet ] QueryStruct.\r
-\par \r
-\par AttSet ::= string.\r
-\par \r
-\par QueryStruct ::= \{ Attribute \} Simple | Complex.\r
-\par \r
-\par Attribute ::= '@attr' AttributeType '=' AttributeValue.\r
-\par \r
-\par AttributeType ::= integer.\r
-\par \r
-\par AttributeValue ::= integer.\r
-\par \r
-\par Complex ::= Operator QueryStruct QueryStruct.\r
-\par \r
-\par Operator ::= '@and' | '@or' | '@not' | '@prox' Proximity.\r
-\par \r
-\par Simple ::= ResultSet | Term.\r
-\par \r
-\par ResultSet ::= '@set' string.\r
-\par \r
-\par Term ::= string | '"' string '"'.\r
-\par \r
-\par Proximity ::= Exclusion Distance Ordered Relation WhichCode UnitCode.\r
-\par \r
-\par Exclusion ::= '1' | '0' | 'void'.\r
-\par \r
-\par Distance ::= integer.\r
-\par \r
-\par Ordered ::= '1' | '0'.\r
-\par \r
-\par Relation ::= integer.\r
-\par \r
-\par WhichCode ::= 'known' | 'private' | integer.\r
-\par \r
-\par UnitCode ::= integer.\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {You will note that the syntax above is a fairly faithful representation of RPN, except for the }{\cs27\f2\fs20 Attibute}{\r
-, 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.\r
-\par The following are all examples of valid queries in the PQF.\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par dylan\r
-\par \r
-\par "bob dylan"\r
-\par \r
-\par @or "dylan" "zimmerman"\r
-\par \r
-\par @set Result-1\r
-\par \r
-\par @or @and bob dylan @set Result-1\r
-\par \r
-\par @attr 4=1 @and @attr 1=1 "bob dylan" @attr 1=4 "slow train coming"\r
-\par \r
-\par @attr 4=1 @attr 1=4 "self portrait"\r
-\par \r
-\par @prox 0 3 1 2 k 2 dylan zimmerman\r
-\par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {Common Command Language\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
-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 wi\r
-despread 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.\r
-\par The EUROPAGATE research project working under the Libraries pro\r
-gramme 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 }{\cs27\f2\fs20 \r
-Z_RPNQuery}{ 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.\r
-\par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {CCL Syntax\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The CCL parser obeys the following grammar for the FIND argument. The syntax is annotated by in the lines prefixed by }{\cs27\f2\fs20 --}{.\r
-\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par CCL-Find ::= CCL-Find Op Elements\r
-\par            | Elements.\r
-\par \r
-\par Op ::= "and" | "or" | "not"\r
-\par -- The above means that Elements are separated by boolean operators.\r
-\par \r
-\par Elements ::= '(' CCL-Find ')'\r
-\par            | Set\r
-\par            | Terms\r
-\par            | Qualifiers Relation Terms\r
-\par            | Qualifiers Relation '(' CCL-Find ')'\r
-\par            | Qualifiers '=' string '-' string\r
-\par -- Elements is either a recursive definition, a result set reference, a\r
-\par -- list of terms, qualifiers followed by terms, qualifiers followed\r
-\par -- by a recursive definition or qualifiers in a range (lower - upper).\r
-\par \r
-\par Set ::= 'set' = string\r
-\par -- Reference to a result set\r
-\par \r
-\par Terms ::= Terms Prox Term\r
-\par         | Term\r
-\par -- Proximity of terms.\r
-\par \r
-\par Term ::= Term string\r
-\par        | string\r
-\par -- This basically means that a term may include a blank\r
-\par \r
-\par Qualifiers ::= Qualifiers ',' string\r
-\par              | string\r
-\par -- Qualifiers is a list of strings separated by comma\r
-\par \r
-\par Relation ::= '=' | '>=' | '<=' | '<>' | '>' | '<'\r
-\par -- Relational operators. This really doesn't follow the ISO8777\r
-\par -- standard.\r
-\par \r
-\par Prox ::= '%' | '!'\r
-\par -- Proximity operator\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The following queries are all valid:\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par dylan\r
-\par \r
-\par "bob dylan"\r
-\par \r
-\par dylan or zimmerman\r
-\par \r
-\par set=1\r
-\par \r
-\par (dylan and bob) or set=1\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Assuming that the qualifiers }{\cs27\f2\fs20 ti}{, }{\cs27\f2\fs20 au}{ and }{\cs27\f2\fs20 date}{ are defined we may use: \r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par ti=self portrait\r
-\par \r
-\par au=(bob dylan and slow train coming)\r
-\par \r
-\par date>1980 and (ti=((self portrait)))\r
-\par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {CCL Qualifiers\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
-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 customiz\r
-e\r
- 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, fo\r
-r example, the structure-attribute.\r
-\par Consider a scenario where the target support ranked searches in the title-index. In this case, the user could specify \r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par ti,ranked=knuth computer\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {and the }{\cs27\f2\fs20 ranked}{ would map to structure=free-form-text (4=105) and the }{\cs27\f2\fs20 ti}{ would map to title (1=4).\r
-\par 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 }{\cs27\f2\fs20 default.bib}{. Each line in the file has the form:\r
-\par }{\i qualifier-name}{ }{\i type}{=}{\i val}{ }{\i type}{=}{\i val}{ ...\r
-\par where }{\i qualifier-name}{ is the name of the qualifier to be used (eg. }{\cs27\f2\fs20 ti}{), }{\i type}{ is a BIB-1 category type and }{\i val}{ is the corresponding BIB-1 attribute value. The }{\i type}{ can be either numeric or it may be either }{\r
-\cs27\f2\fs20 u}{ (use), }{\cs27\f2\fs20 r}{ (relation), }{\cs27\f2\fs20 p}{ (position), }{\cs27\f2\fs20 s}{ (structure), }{\cs27\f2\fs20 t}{ (truncation) or }{\cs27\f2\fs20 c}{ (completeness). The }{\i qualifier-name}{ }{\cs27\f2\fs20 term}{\r
- has a special meaning. The types and values for this definition is used when }{\i no}{ qualifier is present.\r
-\par Consider the following definition: \r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par ti       u=4 s=1\r
-\par au       u=1 s=1\r
-\par term     s=105\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Two qualifiers are defined, }{\cs27\f2\fs20 ti}{ and }{\cs27\f2\fs20 au}{. They both set the structure-attribute to phrase (1). }{\r
-\cs27\f2\fs20 ti}{ sets the use-attribute to 4. }{\cs27\f2\fs20 au}{ sets the use-attribute to 1. When no qualifiers are used in the query the structure-attribute is set to free-form-text (105).\r
-\par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {CCL API\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {All public definitions can be found in the header file }{\cs27\f2\fs20 ccl.h}{. A profile identifier is of type }{\cs27\f2\fs20 CCL_bibset}{\r
-. A profile must be created with the call to the function }{\cs27\f2\fs20 ccl_qual_mk}{ which returns a profile handle of type }{\cs27\f2\fs20 CCL_bibset}{.\r
-\par To read a file containing qualifier definitions the function }{\cs27\f2\fs20 ccl_qual_file}{ may be convenient. This function takes an already opened }{\cs27\f2\fs20 FILE}{ handle pointer as argument along with a }{\cs27\f2\fs20 CCL_bibset}{ handle.\r
-\r
-\par To parse a simple string with a FIND query use the function \r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par struct ccl_rpn_node *ccl_find_str (CCL_bibset bibset, const char *str,\r
-\par                                    int *error, int *pos);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {which takes the CCL profile (}{\cs27\f2\fs20 bibset}{) and query (}{\cs27\f2\fs20 str}{\r
-) as input. Upon successful completion the RPN tree is returned. If an error eccur, such as a syntax error, the integer pointed to by }{\cs27\f2\fs20 error}{ holds the error code and }{\cs27\f2\fs20 pos}{\r
- holds the offset inside query string in which the parsing failed.\r
-\par An english representation of the error may be obtained by calling the }{\cs27\f2\fs20 ccl_err_msg}{ function. The error codes are listed in }{\cs27\f2\fs20 ccl.h}{.\r
-\par To convert the CCL RPN tree (type }{\cs27\f2\fs20 struct ccl_rpn_node *}{) to the Z_RPNQuery of YAZ the function }{\cs27\f2\fs20 ccl_rpn_query}{ must be used. This function which is part of YAZ is implemented in }{\cs27\f2\fs20 yaz-ccl.c}{\r
-. After calling this function the CCL RPN tree is probably no longer needed. The }{\cs27\f2\fs20 ccl_rpn_delete}{ destroys the CCL RPN tree.\r
-\par A CCL profile may be destroyed by calling the }{\cs27\f2\fs20 ccl_qual_rm}{ function.\r
-\par The token names for the CCL operators may be changed by setting the globals (all type }{\cs27\f2\fs20 char *}{) }{\cs27\f2\fs20 ccl_token_and}{, }{\cs27\f2\fs20 ccl_token_or}{, }{\cs27\f2\fs20 ccl_token_not}{ and }{\cs27\f2\fs20 ccl_token_set}{\r
-. 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.\r
-\par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss4_2}{\*\bkmkstart _Toc399132425}4.2 Object Identifiers{\*\bkmkend ss4_2}{\*\bkmkend _Toc399132425}\r
-\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The basic YAZ representation of an OID is an array of integers, terminated with the value -1. The }{\b ODR}{\r
- module provides two utility-functions to create and copy this type of data elements:\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par Odr_oid *odr_getoidbystr(ODR o, char *str);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Creates an OID based on a string-based representation using dots (.) to separate elements in the OID.\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par Odr_oid *odr_oiddup(ODR odr, Odr_oid *o);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Creates a copy of the OID referenced by the }{\i o}{ parameter. Both functions take an }{\b ODR}{\r
- stream as parameter. This stream is used to allocate memory for the data elements, which is released on a subsequent call to }{\cs27\f2\fs20 odr_reset()}{ on that stream.\r
-\par The }{\b 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 }{\cs27\f2\fs20 oid.h}{ file.\r
-\par The interface is mainly based on the }{\cs27\f2\fs20 oident}{ structure. The definition of this structure looks like this:\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par typedef struct oident\r
-\par \{\r
-\par     oid_proto proto;\r
-\par     oid_class oclass;\r
-\par     oid_value value;\r
-\par     int oidsuffix[20];\r
-\par     char *desc;\r
-\par \} oident;\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The }{\i proto}{ field takes one of the values\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par PROTO_Z3950\r
-\par PROTO_SR\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
-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 \r
-to PROTO_Z3950 for outgoing packages.\r
-\par The }{\i oclass}{ field takes one of the values\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par CLASS_APPCTX\r
-\par CLASS_ABSYN\r
-\par CLASS_ATTSET\r
-\par CLASS_TRANSYN\r
-\par CLASS_DIAGSET\r
-\par CLASS_RECSYN\r
-\par CLASS_RESFORM\r
-\par CLASS_ACCFORM\r
-\par CLASS_EXTSERV\r
-\par CLASS_USERINFO\r
-\par CLASS_ELEMSPEC\r
-\par CLASS_VARSET\r
-\par CLASS_SCHEMA\r
-\par CLASS_TAGSET\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {corresponding to the OID classes defined by the Z39.50 standard.\r
-\par Finally, the }{\i value}{ field takes one of the values\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par VAL_APDU\r
-\par VAL_BER\r
-\par VAL_BASIC_CTX\r
-\par VAL_BIB1\r
-\par VAL_EXP1\r
-\par VAL_EXT1\r
-\par VAL_CCL1\r
-\par VAL_GILS\r
-\par VAL_WAIS\r
-\par VAL_STAS\r
-\par VAL_DIAG1\r
-\par VAL_ISO2709\r
-\par VAL_UNIMARC\r
-\par VAL_INTERMARC\r
-\par VAL_CCF\r
-\par VAL_USMARC\r
-\par VAL_UKMARC\r
-\par VAL_NORMARC\r
-\par VAL_LIBRISMARC\r
-\par VAL_DANMARC\r
-\par VAL_FINMARC\r
-\par VAL_MAB\r
-\par VAL_CANMARC\r
-\par VAL_SBN\r
-\par VAL_PICAMARC\r
-\par VAL_AUSMARC\r
-\par VAL_IBERMARC\r
-\par VAL_EXPLAIN\r
-\par VAL_SUTRS\r
-\par VAL_OPAC\r
-\par VAL_SUMMARY\r
-\par VAL_GRS0\r
-\par VAL_GRS1\r
-\par VAL_EXTENDED\r
-\par VAL_RESOURCE1\r
-\par VAL_RESOURCE2\r
-\par VAL_PROMPT1\r
-\par VAL_DES1\r
-\par VAL_KRB1\r
-\par VAL_PRESSET\r
-\par VAL_PQUERY\r
-\par VAL_PCQUERY\r
-\par VAL_ITEMORDER\r
-\par VAL_DBUPDATE\r
-\par VAL_EXPORTSPEC\r
-\par VAL_EXPORTINV\r
-\par VAL_NONE\r
-\par VAL_SETM\r
-\par VAL_SETG\r
-\par VAL_VAR1\r
-\par VAL_ESPEC1\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {again, corresponding to the specific OIDs defined by the standard.\r
-\par The }{\i desc}{ field contains a brief, mnemonic name for the OID in question.\r
-\par The function\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par struct oident *oid_getentbyoid(int *o);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {takes as argument an OID, and returns a pointer to a static area containing an }{\cs27\f2\fs20 oident}{\r
- 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.\r
-\par The function\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par int *oid_getoidbyent(struct oident *ent);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Takes as argument an }{\cs27\f2\fs20 oident}{ structure - in which the }{\i proto}{, }{\i oclass}{, and }{\i value}{\r
- fields are assumed to be set correctly - and returns a pointer to a static buffer containing the base representation of the corresponding OID. The buffer is overwritten on the next successive call to the function, so if you need to create more than one O\r
-ID in this fashiion, you should use }{\cs27\f2\fs20 odr_oiddup()}{ or some similar measure to create a copy of the OID.\r
-\par The }{\cs27\f2\fs20 oid_getoidbyent()}{ function can be used whenever you need to prepare a PDU containing one or more OIDs. The separation of the }{\i protocol}{ element from the \r
-remainer of the OID-description makes it simple to write applications that can communicate with either Z39.50 or OSI SR-based applications.\r
-\par The function\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par oid_value oid_getvalbyname(const char *name);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {takes as argument a mnemonic OID name, and returns the }{\i value}{\r
- field of the first entry in the database that contains the given name in its }{\i desc}{ field.\r
-\par Finally, the module provides the following utility functions, whose meaning should be obvious:\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par void oid_oidcpy(int *t, int *s);\r
-\par void oid_oidcat(int *t, int *s);\r
-\par int oid_oidcmp(int *o1, int *o2);\r
-\par int oid_oidlen(int *o);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\i NOTE: The }{\b\i OID}{\i \r
- 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 result\r
-s. 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 }{\cs27\i\f2\fs20 oident}{\i \r
- 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.}{\r
-\par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss4_3}{\*\bkmkstart _Toc399132426}4.3 Nibble Memory{\*\bkmkend ss4_3}{\*\bkmkend _Toc399132426}\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Sometimes when you need to allocate and const\r
-ruct 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 }{\b \r
-ODR}{ subsystem (see }{\field{\*\fldinst {HYPERLINK "yaz-5.html" \\l "odr-use"}{\fs20 {\*\datafield \r
-08d0c9ea79f9bace118c8200aa004ba90b02000000090000000303000000000000c00000000000004600000b00000079617a2d352e68746d6c00ffffadde000000000000000000000000000000000000000000000000080000006f00640072002d0075007300650000000000}}}{\fldrslt {\cs29\ul\cf2 Using ODR}}}\r
-{). However, in some circumstances where you might otherwise benefit from using a simple nibble memory management system, it may be impractical to use }{\cs27\f2\fs20 odr_malloc()}{ and }{\b odr_reset()}{. For this purpose, \r
-the memory manager which also supports the }{\b ODR}{ streams is made available in the }{\b NMEM}{ module. The external interface to this module is given in the }{\cs27\f2\fs20 nmem.h}{ file.\r
-\par The following prototypes are given:\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par NMEM nmem_create(void);\r
-\par void nmem_destroy(NMEM n);\r
-\par void *nmem_malloc(NMEM n, int size);\r
-\par void nmem_reset(NMEM n);\r
-\par int nmem_total(NMEM n);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The }{\cs27\f2\fs20 nmem_create()}{ function returns a pointer to a memory control handle, which can be released again by }{\cs27\f2\fs20 \r
-nmem_destroy()}{ when no longer needed. The function }{\cs27\f2\fs20 nmem_malloc()}{ allocates a block of memory of the requested size. A call to }{\cs27\f2\fs20 nmem_reset()}{ or }{\cs27\f2\fs20 nmem_destroy()}{\r
- will release all memory allocated on the handle since it was created (or since the last call to }{\cs27\f2\fs20 nmem_reset()}{. The function }{\cs27\f2\fs20 nmem_total()}{ returns the number of bytes currently allocated on the handle.\r
-\par \r
-\par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart odr}{\*\bkmkstart s5}{\*\bkmkstart _Toc399132427}{\*\bkmkend odr}5. The ODR Module{\*\bkmkend s5}\r
-{\*\bkmkend _Toc399132427}\r
-\par {\*\bkmkstart ss5_1}{\*\bkmkstart _Toc399132428}5.1 Introduction{\*\bkmkend ss5_1}{\*\bkmkend _Toc399132428}\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\b ODR}{ is the BER-encoding/decoding subsystem of }{\b YAZ}{. Care as been taken to isolate }{\b ODR}{ from the rest of the package - specif\r
-ically from the transport interface. }{\b ODR}{ may be used in any context where basic ASN.1/BER representations are used.\r
-\par If you are only interested in writing a Z39.50 implementation based on the PDUs that are already provided with }{\b YAZ}{, you only need to concern yourself with the section on managing ODR streams (section }{\field{\*\fldinst {HYPERLINK  \\l "odr-use"}{\r
-\fs20 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b0200000008000000080000006f00640072002d007500730065000000000000}}}{\fldrslt {\cs29\ul\cf2 Using ODR}}}{\r
-). 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 }{\field{\*\fldinst {HYPERLINK  \\l "odr-prog"}{\fs20 {\*\datafield \r
-08d0c9ea79f9bace118c8200aa004ba90b0200000008000000090000006f00640072002d00700072006f006700000000}}}{\fldrslt {\cs29\ul\cf2 Programming with ODR}}}{). If you use one of the higher-level interfaces, you can skip this section entirely.\r
-\par This is important, so we'll repeat it for emphasis: }{\i You do not need to read section }{\field{\*\fldinst {\i HYPERLINK  \\l "odr-prog"}{\i\fs20 {\*\datafield \r
-08d0c9ea79f9bace118c8200aa004ba90b0200000008000000090000006f00640072002d00700072006f006700000000}}}{\fldrslt {\cs29\i\ul\cf2 Programming with ODR}}}{\i  to implement Z39.50 with }{\b\i YAZ}{\i .}{\r
-\par If you need a part of the protocol that isn't already in }{\b 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\r
-, we'd be happy to include it in a future release.\r
-\par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart odr_use}{\*\bkmkstart ss5_2}{\*\bkmkstart _Toc399132429}{\*\bkmkend odr_use}5.2 Using ODR\r
-{\*\bkmkend ss5_2}{\*\bkmkend _Toc399132429}\r
-\par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {ODR Streams\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Conceptu\r
-ally, 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\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par ODR odr_createmem(int direction);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The }{\cs27\f2\fs20 odr_createmem()}{ function takes as argument one of three manifest constants: }{\cs27\f2\fs20 ODR_ENCODE}{, }{\r
-\cs27\f2\fs20 ODR_DECODE}{, or }{\cs27\f2\fs20 ODR_PRINT}{. 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 lea\r
-st two ODR streams - one for decoding, and one for encoding.\r
-\par When you're done with the stream, you can use\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par void odr_destroy(ODR o);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {to release the resources allocated for the stream.\r
-\par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {{\*\bkmkstart memory}{\*\bkmkend memory}Memory Management\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Two forms of memory managem\r
-ent 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 d\r
-eals 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.\r
-\par The }{\b ODR}{ module \r
-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\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par void *odr_malloc(ODR o, int size);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {You can't use the normal }{\cs27\f2\fs20 free}{(2) routine to free memory allocated by this function, and }{\b ODR}{\r
- doesn't provide a parallel function. Instead, you can call\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par void odr_reset(ODR o, int size);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {when you are done with the memory: Everything allocated since the last call to }{\cs27\f2\fs20 odr_reset()}{ is released. The }{\cs27\f2\fs20 \r
-odr_reset()}{ call is also required to clear up an error condition on a stream.\r
-\par The function\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par int odr_total(ODR o);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {returns the number of bytes allocated on the stream since the last call to }{\cs27\f2\fs20 odr_reset()}{.\r
-\par The memory subsystem of }{\b ODR}{\r
- 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. Thi\r
-s scheme is generally known as a }{\i nibble memory}{ system. It is very useful for maintaing short-lived constructions such as protocol PDUs.\r
-\par If you want to retain a bit of memory beyond the next call to }{\cs27\f2\fs20 odr_reset()}{, you can use the function\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par ODR_MEM odr_extract_mem(ODR o);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {This function will give you control of the memory recently allocated on the ODR stream. The memory will live (past calls to }{\cs27\f2\fs20 \r
-odr_reset()}{), until you call the function\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par void odr_release_mem(ODR_MEM p);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The opaque }{\cs27\f2\fs20 ODR_MEM}{ handle has no other purpose than referencing the memory block for you until you want to release it.\r
-\par You can use }{\cs27\f2\fs20 odr_extract_mem()}{ repeatedly between allocating data, to retain individual control of separate chunks of data.\r
-\par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {Encoding and Decoding Data\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {When encoding data, the ODR stream will write the encoded octet string in an internal buffer. To retrieve the data, use the function\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par char *odr_getbuf(ODR o, int *len, int *size);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The integer pointed to by len is set to the length of the encoded data, and a pointer to that data is returned. *}{\cs27\f2\fs20 size}{\r
- is set to the size of the buffer (unless }{\cs27\f2\fs20 size}{ 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 buf\r
-fer has been supplied using the call\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par void odr_setbuf(ODR o, char *buf, int len, int can_grow);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {which sets the encoding (or decoding) buffer used by }{\cs27\f2\fs20 o}{ to }{\cs27\f2\fs20 buf}{, using the length }{\cs27\f2\fs20 len}{\r
-. Before a call to an encoding function, you can use }{\cs27\f2\fs20 odr_setbuf()}{ to provide the stream with an encoding buffer of sufficient size (length). The }{\cs27\f2\fs20 can_grow}{\r
- parameter tells the encoding ODR stream whether it is allowed to use }{\cs27\f2\fs20 realloc}{(2) to increase the size of the buffer when necessary. The default condition of a new encoding stream is equivalent to the results of calling\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par odr_setbuf(stream, 0, 0, 1);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
-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\r
- 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 }{\cs27\f2\fs20 can_grow}{\r
- parameter set to zero (in this case, you are expected to retain control of the memory yourself).\r
-\par To assume full control of an encoded buffer, you must first call }{\cs27\f2\fs20 odr_getbuf()}{ to fetch the buffer and its length. Next, you should call }{\cs27\f2\fs20 odr_setbuf()}{ to provide a different buffer (or a null pointer) to \r
-the stream. In the simplest case, you will reuse the same buffer over and over again, and you will just need to call }{\cs27\f2\fs20 odr_getbuf()}{\r
- 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.\r
-\par It is important to realise that the ODR stream will not release this memory when you call }{\cs27\f2\fs20 odr_reset()}{: It will merely update its internal pointers to prepare for the encoding of a new data value. When the stream is released by the }{\r
-\cs27\f2\fs20 odr_destroy()}{ function, the memory given to it by odr_setbuf will be released }{\i only}{ if the }{\cs27\f2\fs20 can_grow}{ parameter to }{\cs27\f2\fs20 odr_setbuf()}{ was nonzero. The }{\cs27\f2\fs20 can_grow}{ parameter, in other wo\r
-rds, is a way of signalling who is to own the buffer, you or the ODR stream. If you never call }{\cs27\f2\fs20 odr_setbuf()}{ on your encoding stream, which is typically the case, the buffer allocated by the stream will belong to the stream by default.\r
-\r
-\par When you wish to decode data, you should first call }{\cs27\f2\fs20 odr_setbuf()}{, to tell the decoding stream where to find the encoded data, and how long the buffer is (the }{\cs27\f2\fs20 can_grow}{\r
- parameter is ignored by a decoding stream). After this, you can call the function corresponding to the data you wish to decode (eg, }{\cs27\f2\fs20 odr_integer()}{ odr }{\cs27\f2\fs20 z_APDU()}{).\r
-\par Examples of encoding/decoding functions:\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par int odr_integer(ODR o, int **p, int optional);\r
-\par \r
-\par int z_APDU(ODR o, Z_APDU **p, int optional);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {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 }{\r
-\cs27\f2\fs20 optional}{ flag. If }{\cs27\f2\fs20 optional}{ is 0 and the data is absent, an error flag will be raised in the stream, and you'll need to call }{\cs27\f2\fs20 odr_reset()}{ before you can use the stream again. If }{\cs27\f2\fs20 optional}{\r
- is nonzero, the pointer }{\i pointed to}{ by }{\cs27\f2\fs20 p}{ will be set to the null value, and the function will return 1.\r
-\par If the data value is found where it's expected, the pointer }{\i pointed to}{ by the }{\cs27\f2\fs20 p}{ argume\r
-nt 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 }{\cs27\f2\fs20 odr_reset()}{ on the stream. You cannot use }{\cs27\f2\fs20 free}{\r
-(2) to release the memory. You can decode several data elements (by repeated calls to }{\cs27\f2\fs20 odr_setbuf()}{ and your decoding function), and new memory will be allocated each time. When you do call }{\cs27\f2\fs20 odr_reset()}{\r
-, everything decoded since the last call to }{\cs27\f2\fs20 odr_reset()}{ will be released.\r
-\par The use of the double indirection can be a li\r
-ttle 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.\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par void do_nothing_useful(int value)\r
-\par \{\r
-\par     ODR encode, decode;\r
-\par     int *valp, *resvalp;\r
-\par     char *bufferp;\r
-\par     int len;\r
-\par \r
-\par     /* allocate streams */\r
-\par     if (!(encode = odr_createmem(ODR_ENCODE)))\r
-\par         return;\r
-\par     if (!(decode = odr_createmem(ODR_DECODE)))\r
-\par         return;\r
-\par \r
-\par     valp = &value;\r
-\par     if (odr_integer(encode, &valp, 0) == 0)\r
-\par     \{\r
-\par         printf("encoding went bad\\n");\r
-\par         return;\r
-\par     \}\r
-\par     bufferp = odr_getbuf(encode, &len);\r
-\par     printf("length of encoded data is %d\\n", len);\r
-\par \r
-\par     /* now let's decode the thing again */\r
-\par     odr_setbuf(decode, bufferp, len);\r
-\par     if (odr_integer(decode, &resvalp, 0) == 0)\r
-\par     \{\r
-\par         printf("decoding went bad\\n");\r
-\par         return;\r
-\par     \}\r
-\par     printf("the value is %d\\n", *resvalp);\r
-\par \r
-\par     /* clean up */\r
-\par     odr_destroy(encode);\r
-\par     odr_destroy(decode);\r
-\par \}\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
-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 \r
-place in a few, isolated places in your program, so the overhead is quite manageable.\r
-\par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {Diagnostics\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The encoding/decoding functions all return 0 when an error occurs. Until you call }{\cs27\f2\fs20 odr_reset()}{\r
-, you cannot use the stream again, and any function called will immediately return 0.\r
-\par To provide information to the programmer or administrator, the function\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par void odr_perror(ODR o, char *message);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {is provided, which prints the }{\cs27\f2\fs20 message}{ argument to }{\cs27\f2\fs20 stderr}{ along with an error message from the stream.\r
-\r
-\par You can also use the function\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par int odr_geterror(ODR o);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {to get the current error number from the screen. The number will be one of these constants:\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\b OMEMORY}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Memory allocation failed.\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\b OSYSERR}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {A system- or library call has failed. The standard diagnostic variable }{\cs27\f2\fs20 errno}{ should be \r
-examined to determine the actual error.\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\b OSPACE}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
-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.\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\b OREQUIRED}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {This is a common protocol error; A required data element was missing during encoding or decoding.\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\b OUNEXPECTED}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {An unexpected data element was found during decoding.\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\b OOTHER}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Other error. This is typically an indication of misuse of the }{\b ODR}{\r
- system by the programmer, and also that the diagnostic system isn't as good as it should be, yet.\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The character string array\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par char *odr_errlist[]\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {can be indexed by the error code to obtain a human-readable representation of the problem.\r
-\par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {Summary and Synopsis\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par #include <odr.h>\r
-\par \r
-\par ODR odr_createmem(int direction);\r
-\par \r
-\par void odr_destroy(ODR o);\r
-\par \r
-\par void odr_reset(ODR o);\r
-\par \r
-\par char *odr_getbuf(ODR o, int *len);\r
-\par \r
-\par void odr_setbuf(ODR o, char *buf, int len);\r
-\par \r
-\par void *odr_malloc(ODR o, int size);\r
-\par \r
-\par ODR_MEM odr_extract_mem(ODR o);\r
-\par \r
-\par void odr_release_mem(ODR_MEM r);\r
-\par \r
-\par int odr_geterror(ODR o);\r
-\par \r
-\par void odr_perror(char *message);\r
-\par \r
-\par extern char *odr_errlist[];\r
-\par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart odr_prog}{\*\bkmkstart ss5_3}{\*\bkmkstart _Toc399132430}{\*\bkmkend odr_prog}5.3 Programming with ODR\r
-{\*\bkmkend ss5_3}{\*\bkmkend _Toc399132430}\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The API of }{\b ODR}{ is desig\r
-ned to reflect the structure of ASN.1, rather than BER itself. Future releases may be able to represent data in other external forms.\r
-\par The interface is based loosely on that of the Sun Microsystems XDR routines. Specifically, each function which corresponds\r
- 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 re\r
-p\r
-resent 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 \r
-compact, and is a pretty straightforward representation of the source ASN.1 specification. Although no ASN.1 compiler is supplied with }{\b ODR}{\r
- at this time, it shouldn't be too difficult to write one, or perhaps even to adapt an existing compiler to output }{\b ODR}{ routines (not surprisingly, writing encoders/decoders using }{\b ODR}{ turns out to be boring work).\r
-\par 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.\r
-\par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {The Primitive ASN.1 Types\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {ASN.1 defines a number of primitive types (many of which correspond roughly to primitive types in structured programming languages, such as C).\r
-\r
-\par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {INTEGER\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The }{\b ODR}{ function for encoding or decoding (or printing) the ASN.1 INTEGER type looks like this:\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par int odr_integer(ODR o, int **p, int optional);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {(we don't allow values that can't be contained in a C integer.)\r
-\par This form is typical of the primitive }{\b 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 }{\cs27\f2\fs20 optional}{\r
- 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 \r
-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.\r
-\par The }{\cs27\f2\fs20 o}{ 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.\r
-\par When encoding or printing, the function first looks at *}{\cs27\f2\fs20 p}{. If *}{\cs27\f2\fs20 p}{ (the pointer pointed to by }{\cs27\f2\fs20 p}{) is a null pointer, this is taken to mean that the data element is absent. If the }{\cs27\f2\fs20 optional}\r
-{ parameter is nonzero, the function will return one (signifying success) without any further processing. If the }{\cs27\f2\fs20 optional}{ is zero, an internal error flag is set in the ODR stream, and the function will return 0. No furthe\r
-r operations can be carried out on the stream without a call to the function }{\cs27\f2\fs20 odr_reset()}{.\r
-\par If *}{\cs27\f2\fs20 p}{ 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.\r
-\par The other ASN.1 primitives have similar functions that operate in similar manners:\r
-\par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {BOOLEAN\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par int odr_bool(ODR o, bool_t **p, int optional);\r
-\par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {REAL\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Not defined.\r
-\par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {NULL\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par int odr_null(ODR o, bool_t **p, int optional);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {In this case, the value of **p is not important. If *p is different from the null pointer, the null value is present, otherwise it's absent.\r
-\r
-\par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {OCTET STRING\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par typedef struct odr_oct\r
-\par \{\r
-\par     unsigned char *buf;\r
-\par     int len;\r
-\par     int size;\r
-\par \} Odr_oct;\r
-\par \r
-\par int odr_octetstring(ODR o, Odr_oct **p, int optional);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The }{\cs27\f2\fs20 buf}{ field should point to the character array that holds the octetstring. The }{\cs27\f2\fs20 len}{\r
- field holds the actual length, while the }{\cs27\f2\fs20 size}{ field gives the size of the allocated array (not of interest to you, in most cases). The character array need not be null terminated.\r
-\par To make things a little easier, an alternative is given for string types that are not expected to contain embedded NULL characters (eg. VisibleString):\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par int odr_cstring(ODR o, char **p, int optional);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Which encoded or decodes between OCTETSTRING representations and null-terminates C strings.\r
-\par Functions are provided for the derived string types, eg:\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par int odr_visiblestring(ODR o, char **p, int optional);\r
-\par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {BIT STRING\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par int odr_bitstring(ODR o, Odr_bitmask **p, int optional);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The opaque type }{\cs27\f2\fs20 Odr_bitmask}{\r
- is only suitable for holding relatively brief bit strings, eg. for options fields, etc. The constant }{\cs27\f2\fs20 ODR_BITMASK_SIZE}{ multiplied by 8 gives the maximum possible number of bits.\r
-\par A set of macros are provided for manipulating the }{\cs27\f2\fs20 Odr_bitmask}{ type:\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par void ODR_MASK_ZERO(Odr_bitmask *b);\r
-\par \r
-\par void ODR_MASK_SET(Odr_bitmask *b, int bitno);\r
-\par \r
-\par void ODR_MASK_CLEAR(Odr_bitmask *b, int bitno);\r
-\par \r
-\par int ODR_MASK_GET(Odr_bitmask *b, int bitno);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The functions are modelled after the manipulation functions that accompany the }{\cs27\f2\fs20 fd_set}{ type used by the }{\cs27\f2\fs20 select\r
-}{(2) call. }{\cs27\f2\fs20 ODR_MASK_ZERO}{ should always be called first on a new bitmask, to initialize the bits to zero.\r
-\par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {OBJECT IDENTIFIER\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par int odr_oid(ODR o, Odr_oid **p, int optional);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The C OID represenation is simply an array of integers, terminated by the value -1 (the }{\cs27\f2\fs20 Odr_oid}{ type is synonymous with the }\r
-{\cs27\f2\fs20 int}{ type). We suggest that you use the OID database module (see section }{\field{\*\fldinst {HYPERLINK "yaz-3.html" \\l "oid"}{\fs20 {\*\datafield \r
-08d0c9ea79f9bace118c8200aa004ba90b02000000090000000303000000000000c00000000000004600000b00000079617a2d332e68746d6c00ffffadde000000000000000000000000000000000000000000000000040000006f006900640000000000}}}{\fldrslt {\cs29\ul\cf2 Object Identifiers}}}{\r
-) to handle object identifiers in your application.\r
-\par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {{\*\bkmkstart tag_prim}{\*\bkmkend tag_prim}Tagging Primitive Types\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The simplest way of tagging a type is to use the }{\cs27\f2\fs20 odr_implicit()}{ or }{\cs27\f2\fs20 odr_explicit()}{ macros:\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par int odr_implicit(ODR o, Odr_fun fun, int class, int tag, int\r
-\par                     optional);\r
-\par \r
-\par int odr_explicit(ODR o, Odr_fun fun, int class, int tag,\r
-\par                     int optional);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {To create a type derived from the integer type by implicit tagging, you might write:\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par MyInt ::= [210] IMPLICIT INTEGER\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {In the }{\b ODR}{ system, this would be written like:\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par int myInt(ODR o, int **p, int optional)\r
-\par \{\r
-\par     return odr_implicit(o, odr_integer, p, ODR_CONTEXT, 210, optional);\r
-\par \}\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The function }{\cs27\f2\fs20 myInt()}{ can then be used like any of the primitive functions provided by ODR. Note that the behavior of }{\r
-\cs27\f2\fs20 odr_explicit()}{ and }{\cs27\f2\fs20 odr_implicit()}{\r
- 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: }{\cs27\f2\fs20 ODR_CONTEXT}{, }{\r
-\cs27\f2\fs20 ODR_PRIVATE}{, }{\cs27\f2\fs20 ODR_UNIVERSAL}{, or }{\cs27\f2\fs20 ODR_APPLICATION}{.\r
-\par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {Constructed Types\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Constructed types are created by combining primitive types. The }{\b ODR}{\r
- 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).\r
-\par For implementing SEQUENCEs, the functions\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par int odr_sequence_begin(ODR o, void *p, int size);\r
-\par int odr_sequence_end(ODR o);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {are provided.\r
-\par The }{\cs27\f2\fs20 odr_sequence_begin()}{ function should be called in the beginning of a function that implements a SEQUENCE type. Its parameters are the }{\b ODR}{ stream, a pointer (to a pointer to the type you're implementing), and the }{\r
-\cs27\f2\fs20 size}{ of the type (typically a C structure). On encoding, it returns 1 if *}{\cs27\f2\fs20 p}{ is a null pointer. The }{\cs27\f2\fs20 size}{ parameter is ignored. On decoding, it returns 1 if the type is found in the data stream. }{\r
-\cs27\f2\fs20 size}{ bytes of memory are allocated, and *}{\cs27\f2\fs20 p}{ is set to point to this space. }{\cs27\f2\fs20 odr_sequence_end()}{ is called at the end of the complex function. Assume that a type is defined like this:\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par MySequence ::= SEQUENCE \{\r
-\par     intval INTEGER,\r
-\par     boolval BOOLEAN OPTIONAL \}\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The corresponding ODR encoder/decoder function and the associated data structures could be written like this:\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par typedef struct MySequence\r
-\par \{\r
-\par     int *intval;\r
-\par     bool_t *boolval;\r
-\par \} MySequence;\r
-\par \r
-\par int mySequence(ODR o, MySequence **p, int optional)\r
-\par \{\r
-\par     if (odr_sequence_begin(o, p, sizeof(**p)) == 0)\r
-\par         return optional && odr_ok(o);\r
-\par     return\r
-\par         odr_integer(o, &(*p)->intval, 0) &&\r
-\par         odr_bool(o, &(*p)->boolval, 1) &&\r
-\par         odr_sequence_end(o);\r
-\par \}\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Note the 1 in the call to }{\cs27\f2\fs20 odr_bool()}{\r
-, to mark that the sequence member is optional. If either of the member types had been tagged, the macros }{\cs27\f2\fs20 odr_implicit()}{ or }{\cs27\f2\fs20 odr_explicit()}{\r
- could have been used. The new function can be used exactly like the standard functions provided with }{\b ODR}{. It will encode, decode or pretty-print a data value of the }{\cs27\f2\fs20 MySequence}{\r
- type. We like to name types with an initial capital, as done in ASN.1 definitio\r
-ns, 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. }{\r
-\cs27\f2\fs20 odr_ok}{ 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.\r
-\par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {Tagging Constructed Types\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\i NOTE: See section }{\field{\*\fldinst {\i HYPERLINK  \\l "tag-prim"}{\i\fs20 {\*\datafield \r
-08d0c9ea79f9bace118c8200aa004ba90b0200000008000000090000007400610067002d007000720069006d00000000}}}{\fldrslt {\cs29\i\ul\cf2 Tagging Primitive types}}}{\i  for information on how to tag the primitive types, as well as types that are already defined.}{\r
-\r
-\par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {Implicit Tagging\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Assume the type above had been defined as\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par MySequence ::= [10] IMPLICIT SEQUENCE \{\r
-\par     intval INTEGER,\r
-\par     boolval BOOLEAN OPTIONAL \}\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {You would implement this in }{\b ODR}{ by calling the function\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par int odr_implicit_settag(ODR o, int class, int tag);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {which overrides the tag of the type immediately following it. The macro }{\cs27\f2\fs20 odr_implicit()}{ works by calling }{\cs27\f2\fs20 \r
-odr_implicit_settag()}{ immediately before calling the function pointer argument. Your type function could look like this:\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par int mySequence(ODR o, MySequence **p, int optional)\r
-\par \{\r
-\par     if (odr_implicit_settag(o, ODR_CONTEXT, 10) == 0 ||\r
-\par         odr_sequence_begin(o, p, sizeof(**p)) == 0)\r
-\par         return optional && odr_ok(o);\r
-\par     return\r
-\par         odr_integer(o, &(*p)->intval, 0) &&\r
-\par         odr_bool(o, &(*p)->boolval, 1) &&\r
-\par         odr_sequence_end(o);\r
-\par \}\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The definition of the structure }{\cs27\f2\fs20 MySequence}{ would be the same.\r
-\par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {Explicit Tagging\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Explicit tagging of constructed types is a little more complicated, since you are in effect adding a level of construction to the data.\r
-\par Assume the definition:\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par MySequence ::= [10] IMPLICIT SEQUENCE \{\r
-\par     intval INTEGER,\r
-\par     boolval BOOLEAN OPTIONAL \}\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Since the new type has an extra level of construction, two new functions are needed to encapsulate the base type:\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par int odr_constructed_begin(ODR o, void *p, int class, int tag);\r
-\par \r
-\par int odr_constructed_end(ODR o);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Assume that the IMPLICIT in the type definiti\r
-on 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:\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par int mySequence(ODR o, MySequence **p, int optional)\r
-\par \{\r
-\par     if (odr_constructed_begin(o, p, ODR_CONTEXT, 10) == 0)\r
-\par         return optional && odr_ok(o);\r
-\par     if (o->direction == ODR_DECODE)\r
-\par         *p = odr_malloc(o, sizeof(**p));\r
-\par     if (odr_sequence_begin(o, p, sizeof(**p)) == 0)\r
-\par     \{\r
-\par         *p = 0; /* this is almost certainly a protocol error */\r
-\par         return 0;\r
-\par     \}\r
-\par     return\r
-\par         odr_integer(o, &(*p)->intval, 0) &&\r
-\par         odr_bool(o, &(*p)->boolval, 1) &&\r
-\par         odr_sequence_end(o) &&\r
-\par         odr_constructed_end(o);\r
-\par \}\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
-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 tha\r
-n 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 }{\cs27\f2\fs20 odr_explicit()}{\r
- macro to the first function, and not have to worry about }{\cs27\f2\fs20 odr_constructed_*}{ yourself. Incidentally, as you might have guessed, the }{\cs27\f2\fs20 odr_sequence_}{ functions are themselves implemented using the }{\cs27\f2\fs20 \r
-odr_constructed_}{ functions.\r
-\par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {SEQUENCE OF\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {To handle sequences (arrays) of a apecific type, the function\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par int odr_sequence_of(ODR o, int (*fun)(ODR o, void *p, int optional),\r
-\par                         void *p, int *num);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The }{\cs27\f2\fs20 fun}{ parameter is a pointer to the decoder/encoder function of the type. }{\cs27\f2\fs20 p}{\r
- is a pointer to an array of pointers to your type. }{\cs27\f2\fs20 num}{ is the number of elements in the array.\r
-\par Assume a type\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par MyArray ::= SEQUENCE OF INTEGER\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The C representation might be\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par typedef struct MyArray\r
-\par \{\r
-\par     int num_elements;\r
-\par     int **elements;\r
-\par \} MyArray;\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {And the function might look like\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par int myArray(ODR o, MyArray **p, int optional)\r
-\par \{\r
-\par     if (o->direction == ODR_DECODE)\r
-\par         *p = odr_malloc(o, sizeof(**p));\r
-\par     if (odr_sequence_of(o, odr_integer, &(*p)->elements,\r
-\par         &(*p)->num_elements))\r
-\par         return 1;\r
-\par     *p = 0;\r
-\par     return optional && odr_ok(o);\r
-\par \}\r
-\par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {CHOICE Types\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The choice type is used fairly often in some ASN.1 definitions, so some work has gone into streamlining its interface.\r
-\par CHOICE types are handled by the function:\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par int odr_choice(ODR o, Odr_arm arm[], void *p, int *whichp);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The }{\cs27\f2\fs20 arm}{ array is used\r
- 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 un\r
-ion. }{\cs27\f2\fs20 whichp}{ 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.\r
-\par The Odr_arm type is defined thus:\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par typedef struct odr_arm\r
-\par \{\r
-\par     int tagmode;\r
-\par     int class;\r
-\par     int tag;\r
-\par     int which;\r
-\par     Odr_fun fun;\r
-\par \} Odr_arm;\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The interpretation of the fields are:\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\b tagmode}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Either }{\cs27\f2\fs20 ODR_IMPLICIT}{, }{\cs27\f2\fs20 ODR_EXPLICIT}{, or }{\cs27\f2\fs20 ODR_NONE}{ (-1) to mark no tagging.\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\b class, tag}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The class and tag of the type (-1 if no tagging is used).\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\b which}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The value of the discriminator that corresponds to this CHOICE element. Typically, it will be a #defined constant, or an enum member.\r
-\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\b fun}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {A pointer to a function that implements the type of the CHOICE member. It may be either a standard }{\b ODR}{\r
- type or a type defined by yourself.\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {A handy way to prepare the array for use by the }{\cs27\f2\fs20 odr_choice()}{\r
- function is to define it as a static, initialized array in the beginning of your decoding/encoding function. Assume the type definition:\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par MyChoice ::= CHOICE \{\r
-\par     untagged INTEGER,\r
-\par     tagged   [99] IMPLICIT INTEGER,\r
-\par     other    BOOLEAN\r
-\par \}\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Your C type might look like\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par typedef struct MyChoice\r
-\par \{\r
-\par     enum\r
-\par     \{\r
-\par         MyChoice_untagged,\r
-\par         MyChoice_tagged,\r
-\par         MyChoice_other\r
-\par     \} which;\r
-\par     union\r
-\par     \{\r
-\par         int *untagged;\r
-\par         int *tagged;\r
-\par         bool_t *other;\r
-\par     \} u;\r
-\par \};\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {And your function could look like this:\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par int myChoice(ODR o, MyChoice **p, int optional)\r
-\par \{\r
-\par     static Odr_arm arm[] =\r
-\par     \{\r
-\par         \{-1, -1, -1, MyChoice_untagged, odr_integer\},\r
-\par         \{ODR_IMPLICIT, ODR_CONTEXT, 99, MyChoice_tagged, odr_integer\},\r
-\par         \{-1, -1, -1, MyChoice_other, odr_boolean\},\r
-\par         \{-1, -1, -1, -1, 0\}\r
-\par     \};\r
-\par \r
-\par     if (o->direction == ODR_DECODE)\r
-\par         *p = odr_malloc(o, sizeof(**p);\r
-\par     else if (!*p)\r
-\par         return optional && odr_ok(o);\r
-\par \r
-\par     if (odr_choice(o, arm, &(*p)->u, &(*p)->which))\r
-\par         return 1;\r
-\par     *p = 0;\r
-\par     return optional && odr_ok(o);\r
-\par \}\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {In some cases (say, a non-optional choice which is a membe\r
-r 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.\r
-\par 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.\r
-\par The ASN.1 specifictions naturally requires that each member of a CHOICE have\r
- 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 l\r
-i\r
-ke 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 fun\r
-ction to look for a specific arm of the table. The function\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par void odr_choice_bias(ODR o, int what);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {provides this functionality. When called, it leaves a notice for the next call to }{\cs27\f2\fs20 odr_choice()}{\r
- to be called on the decoding stream }{\cs27\f2\fs20 o}{ that only the }{\cs27\f2\fs20 arm}{ entry with a }{\cs27\f2\fs20 which}{ field equal to }{\cs27\f2\fs20 what}{ should be tried.\r
-\par 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.\r
-\par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss5_4}{\*\bkmkstart _Toc399132431}5.4 Debugging{\*\bkmkend ss5_4}{\*\bkmkend _Toc399132431}\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
-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 \r
-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 }{\cs27\f2\fs20 ODR_DEBUG}{\r
- 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.{\*\bkmkstart comstack}{\*\bkmkstart s6}\r
-{\*\bkmkend comstack}\r
-\par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart _Toc399132432}6. The COMSTACK Module{\*\bkmkend s6}{\*\bkmkend _Toc399132432}\r
-\par {\*\bkmkstart ss6_1}{\*\bkmkstart _Toc399132433}6.1 Introduction{\*\bkmkend ss6_1}{\*\bkmkend _Toc399132433}\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The }{\b COMSTACK}{\r
- 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\r
- 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.\r
-\par 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.\r
-\par You will note that even though simplicity was a goal in the design, the interface is still orders of\r
- 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 th\r
-e\r
- 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\r
- and server provided with the package. They are meant to be easily readable and instructive, while still being at least moderately useful.\r
-\par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss6_2}{\*\bkmkstart _Toc399132434}6.2 Common Functions{\*\bkmkend ss6_2}{\*\bkmkend _Toc399132434}\r
-\r
-\par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {Managing Endpoints\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par COMSTACK cs_create(CS_TYPE type, int blocking, int protocol);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Creates an instance of the protocol stack - a communications endpoint. The }{\cs27\f2\fs20 type}{\r
- parameter determines the mode of communication. At present, the values }{\cs27\f2\fs20 tcpip_type}{ and }{\cs27\f2\fs20 mosi_type}{ are recognized. The function returns a null-pointer if a system error occurs. The }{\cs27\f2\fs20 blocking}{\r
- parameter should be one if you wish the association to operate in blocking mode, zero otherwise. The }{\cs27\f2\fs20 protocol}{ field should be one of }{\cs27\f2\fs20 PROTO_SR}{ or }{\cs27\f2\fs20 PROTO_Z3950}{.\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par int cs_close(COMSTACK handle);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Closes the connection (as elegantly as the lower layers will permit), and releases the resouces pointed to by the }{\cs27\f2\fs20 handle}{\r
- parameter. The }{\cs27\f2\fs20 handle}{ should not be referenced again after this call.\r
-\par }{\i NOTE: We really need a soft disconnect, don't we?}{\r
-\par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {Data Exchange\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par int cs_put(COMSTACK handle, char *buf, int len);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Sends }{\cs27\f2\fs20 buf}{\r
- 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\r
- 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 }{\cs27\f2\fs20 buf}{ and }{\cs27\f2\fs20 len}{\r
-, 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).\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par int cs_get(COMSTACK handle, char **buf, int *size);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Receives a PDU from the peer. Returns the number of bytes read. In nonblocking mode, \r
-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,\r
- and will sometimes be moved around internally by the subsystem when partial packages are read. Before calling }{\cs27\f2\fs20 cs_get}{\r
- 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 }{\cs27\f2\fs20 malloc}{\r
-(2) 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.\r
-\par See also the }{\cs27\f2\fs20 cs_more()}{ function below.\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par int cs_more(COMSTACK handle);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The }{\cs27\f2\fs20 cs_more()}{ function should be used in conjunction with }{\cs27\f2\fs20 cs_get}{ and }{\cs27\f2\fs20 select}{(2). The }{\r
-\cs27\f2\fs20 cs_get()}{ 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 calling }{\cs27\f2\fs20 cs_get()}{\r
-, and before waiting for more input, You should always call }{\cs27\f2\fs20 cs_more()}{ to check if there's a full protocol package already read. If }{\cs27\f2\fs20 cs_more()}{ returns 1, }{\cs27\f2\fs20 cs_get()}{\r
- 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.\r
-\par }{\i NOTE: The }{\cs27\i\f2\fs20 cs_more()}{\i  function is required because the RFC1729-method does not provide a way of separating individual PDUs, short of partially decodin\r
-g the BER. Some other implementations will carefully nibble at the packet by calling }{\cs27\i\f2\fs20 read}{\i (2) several times. This was felt to be too inefficient (or at least clumsy) - hence the call for this extra function.}{\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par int cs_look(COMSTACK handle);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {This function is useful when you're operating in nonblocking mode. Call it when }{\cs27\f2\fs20 select}{\r
-(2) tells you there's something happening on the line. It returns one of the following values:\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\b CS_NONE}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {No event is pending. The data found on the line was not a complete package.\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\b CS_CONNECT}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {A response to your connect request has been received. Call }{\cs27\f2\fs20 cs_rcvconnect}{\r
- to process the event and to finalize the connection establishment.\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\b CS_DISCON}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The other side has closed the connection (or maybe sent a disconnect request - but do we care? Maybe later). Call }{\cs27\f2\fs20 \r
-cs_close}{ To close your end of the association as well.\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\b CS_LISTEN}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {A connect request has been received. Call }{\cs27\f2\fs20 cs_listen}{ to process the event.\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\b CS_DATA}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {There's data to be found on the line. Call }{\cs27\f2\fs20 cs_get}{ to get it.\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\i NOTE: You should be aware that even if }{\cs27\i\f2\fs20 cs_look()}{\i \r
- 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 u\r
-p again, when more data has arrived.}{\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par int cs_fileno(COMSTACK h);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Returns the file descriptor of the association. Use this when file-level operations on the endpoint are required (}{\cs27\f2\fs20 select}{\r
-(2) operations, specifically).\r
-\par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss6_3}{\*\bkmkstart _Toc399132435}6.3 Client Side{\*\bkmkend ss6_3}{\*\bkmkend _Toc399132435}\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par int cs_connect(COMSTACK handle, void *address);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Initiate a connection with the target at }{\cs27\f2\fs20 address}{\r
- (more on addresses 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 }{\cs27\f2\fs20 cs_rcvconnect}{ to complete the operation, when }{\r
-\cs27\f2\fs20 select}{(2) reports input pending on the association.\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par int cs_rcvconnect(COMSTACK handle);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Complete a connect operation initiated by }{\cs27\f2\fs20 cs_connect()}{. It will return 0 on suc\r
-cess; 1 if the operation has not yet completed (in this case, call the function again later); -1 if an error has occured.\r
-\par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss6_4}{\*\bkmkstart _Toc399132436}6.4 Server Side{\*\bkmkend ss6_4}{\*\bkmkend _Toc399132436}\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {To establish a server under the }{\cs27\f2\fs20 inetd}{ server, you can use\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par COMSTACK cs_createbysocket(int socket, CS_TYPE type, int blocking,\r
-\par                               int protocol);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The }{\i socket}{ parameter is an established socket (when your application is invoked from }{\cs27\f2\fs20 inetd}{\r
-, the socket will typically be 0. The following parameters are identical to the ones for }{\cs27\f2\fs20 cs_create}{.\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par int cs_bind(COMSTACK handle, void *address, int mode)\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Binds a local address to the endpoint. Read about addresses below. The }{\cs27\f2\fs20 mode}{ parameter should be either }{\cs27\f2\fs20 \r
-CS_CLIENT}{ or }{\cs27\f2\fs20 CS_SERVER}{.\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par int cs_listen(COMSTACK handle, char *addr, int *addrlen);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
-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.\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par COMSTACK cs_accept(COMSTACK handle);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
-This finalises the server-side association establishment, after cs_listen has completed successfully. It returns a new connection endpoint, which represe\r
-nts 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 }{\cs27\f2\fs20 handle}{.\r
-\par You can use the call\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par char *cs_addrstr(COMSTACK);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {on an established connection to retrieve the hostname of the remote host.\r
-\par }{\i NOTE: You may need to use this function with some care if your name server service is slow or unreliable}{\r
-\par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss6_5}{\*\bkmkstart _Toc399132437}6.5 Addresses{\*\bkmkend ss6_5}{\*\bkmkend _Toc399132437}\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The low-level format of the addresses are differen\r
-t 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.\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par struct sockaddr_in *tcpip_strtoaddr(char *str);\r
-\par \r
-\par struct netbuf *mosi_strtoaddr(char *str);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The format for TCP/IP addresses is straightforward:\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par <host> [ ':' <portnum> ]\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The }{\cs27\f2\fs20 hostname}{ can be either a domain name or an IP address. The port number, if omitted, defaults to 210.\r
-\par For OSI, the format is\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par [ <t-selector> '/' ] <host> [ ':' <port> ]\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The transport selector is given as an even number of hex digits.\r
-\par 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\r
- 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 \r
-to the address format as needed, however: Xtimosi }{\i does}{ support the full P-address structure.\r
-\par In both transport modes, the special hostname "@" is mapped to any local address (the manifest constant INADDR_ANY). It is used to establish local listening endpoints in the server role.\r
-\par When a connection has been established, you can use\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par char cs_addrstr(COMSTACK h);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
-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.\r
-\par }{\i N\r
-OTE: 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\r
\r
-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 b\r
-e 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.}{\r
-\par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss6_6}{\*\bkmkstart _Toc399132438}6.6 Diagnostics{\*\bkmkend ss6_6}{\*\bkmkend _Toc399132438}\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {All functions return -1 if an error occurs. Typically, the functions will return 0 on success, but the data exchange functions (}{\r
-\cs27\f2\fs20 cs_get}{, }{\cs27\f2\fs20 cs_put}{, }{\cs27\f2\fs20 cs_more}{) follow special rules. Consult their descriptions.\r
-\par When a function (including the data exchange functions) reports an error condition, use the function }{\cs27\f2\fs20 cs_errno()}{ to determine the cause of the problem. The function\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par void cs_perror(COMSTACK handle char *message);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {works like }{\cs27\f2\fs20 perror}{(2) and prints the }{\cs27\f2\fs20 message}{ argument, along with a system message, to }{\cs27\f2\fs20 \r
-stderr}{. Use the character array\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par extern const char *cs_errlist[];\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {to get hold of the message, if you want to process it differently. The function\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par const char *cs_stackerr(COMSTACK handle);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Returns an error message from the lower layer, if one has been provided.\r
-\par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss6_7}{\*\bkmkstart _Toc399132439}6.7 Enabling OSI Communication{\*\bkmkend ss6_7}\r
-{\*\bkmkend _Toc399132439}\r
-\par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {Installing Xtimosi\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
-Although you will have to download Peter Furniss' XTI/mOSI implementation for yourself, we've tried to make the integration as simple as possible.\r
-\par The latest version of xtimosi will generally be under\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par ftp://pluto.ulcc.ac.uk/ulcc/thinosi/xtimosi/\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {When you have downloaded and unpacked the archive, it will (we assume) have created a directory called }{\cs27\f2\fs20 xtimosi}{\r
-. We suggest that you place this directory }{\i in the same directory}{ where you unpacked the }{\b YAZ}{ distribution. This way, you shouldn't have to fiddle with the makefiles of }{\cs27\f2\fs20 YAZ}{ beyond uncommenting a few lines.\r
-\par Go to }{\cs27\f2\fs20 xtimosi/src}{, and type "}{\cs27\f2\fs20 make libmosi.a}{". This should generally create the library, ready to use.\r
-\par }{\b CAVEAT}{\r
-\par }{\i \r
-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 portabl\r
-e. 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 }{\b\i gcc}{\i \r
- 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).}{\r
-\par }{\i A problem has been encountered in the communication with ISODE-based applications. If the ISODE presentation-user calls }{\cs27\i\f2\fs20 PReadRequest()}{\i  with a timeout value different from }{\cs27\i\f2\fs20 OK}{\i  or }{\cs27\i\f2\fs20 NOTOK}{\r
-\i , he will get an immediate TIMEOUT abort when receiving large (>2041 bytes, which is the SPDU-size that the ISODE likes to w\r
-ork 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 bloc\r
-king or nonblocking mode), or to check that the timer really has expired before closing the connection.}{\r
-\par The next step in the installation is to modify the makefile in the toplevel }{\b YAZ}{ directory. The place to change is in the top of the file, and is clearly marked with a comment.\r
-\par Now run }{\cs27\f2\fs20 make}{ in the }{\b YAZ}{ toplevel directory (do a "}{\cs27\f2\fs20 make clean}{" first, if the system has been previously made without OSI support). Use the }{\b YAZ}{ }{\b ztest}{ and }{\b client}{\r
- demo programs to verify that OSI communication works OK. Then, you can go ahead and try to talk to other implementations.\r
-\par }{\i NOTE: Our interoperability experience is limited to version 7 of the Nordic SR-Nett package, which has had several protocol errors fi\r
-xed 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.}{\r
-\par If you write your own applications based on }{\b YAZ}{, and you wish to include OSI support, the procedure is equally simple. You should include the }{\cs27\f2\fs20 xmosi.h}{ header file in addition to }{\cs27\f2\fs20 comstack.h}{. }{\cs27\f2\fs20 xmosi.h\r
-}{ will define the manifest constant }{\cs27\f2\fs20 mosi_type}{, which you should pass to the }{\cs27\f2\fs20 cs_create()}{ function. In addition, you should use the function }{\cs27\f2\fs20 mosi_strtoaddr()}{ rather than }{\cs27\f2\fs20 \r
-tcpip_strtoaddr()}{ when you need to prepare an address.\r
-\par When you link your application, you should include (after the }{\cs27\f2\fs20 libyaz.a}{ library) the }{\cs27\f2\fs20 libmosi.a}{ library, and the }{\cs27\f2\fs20 librfc.a}{ library provided with }{\b YAZ}{ (for OSI transport).\r
-\par As always, it can be very useful, if not essential, to have a look at the example applications to see how things are done.\r
-\par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {OSI Transport\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Xtimosi requires an implementation of the OSI transport service under the X/OPEN XTI API. We provide an\r
- implementation of the RFC1006 encapsulation of OSI/TP0 in TCP/IP (through the Berkeley Sockets API), as an independent part of }{\b YAZ}{ (it's found under the }{\cs27\f2\fs20 rfc1006}{\r
- 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 }{\cs27\f2\fs20 mosi_strtoaddr()}{ function.\r
-\par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {Presentation Context Management\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {To simplify the implementation, we use Peter Furniss' alternative (PRF) option format for the Control of the presentation negotiation p\r
-hase. This format is enabled by default when you compile xtimosi.\r
-\par The current version of }{\b YAZ}{ does }{\i not}{ 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 \r
-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 h\r
-ave just hitherto given it a lower priority than other aspects of the protocol.\r
-\par One thing is certain: The addition of this capability to }{\b YAZ}{ should have only a minimal impact on existing applications, and on the interface to the software in general. Most li\r
-kely, we will add an extra layer of interface to the processing of EXPLAIN records, which will convert back and forth between }{\cs27\f2\fs20 oident}{ records (see section }{\field{\*\fldinst {HYPERLINK "yaz-3.html" \\l "oid"}{\fs20 {\*\datafield \r
-08d0c9ea79f9bace118c8200aa004ba90b02000000090000000303000000000000c00000000000004600000b00000079617a2d332e68746d6c00ffffadde000000000000000000000000000000000000000000000000040000006f006900640000000000}}}{\fldrslt {\cs29\ul\cf2 Object Identifiers}}}{\r
-) 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.\r
-\par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss6_8}{\*\bkmkstart _Toc399132440}6.8 Summary and Synopsis{\*\bkmkend ss6_8}{\*\bkmkend _Toc399132440}\r
-\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par #include <comstack.h>\r
-\par \r
-\par #include <tcpip.h>      /* this is for TCP/IP support   */\r
-\par #include <xmosi.h>      /* and this is for mOSI support */\r
-\par \r
-\par COMSTACK cs_create(CS_TYPE type, int blocking, int protocol);\r
-\par \r
-\par COMSTACK cs_createbysocket(int s, CS_TYPE type, int blocking,\r
-\par                               int protocol);\r
-\par \r
-\par int cs_bind(COMSTACK handle, int mode);\r
-\par \r
-\par int cs_connect(COMSTACK handle, void *address);\r
-\par \r
-\par int cs_rcvconnect(COMSTACK handle);\r
-\par \r
-\par int cs_listen(COMSTACK handle);\r
-\par \r
-\par COMSTACK cs_accept(COMSTACK handle);\r
-\par \r
-\par int cs_put(COMSTACK handle, char *buf, int len);\r
-\par \r
-\par int cs_get(COMSTACK handle, char **buf, int *size);\r
-\par \r
-\par int cs_more(COMSTACK handle);\r
-\par \r
-\par int cs_close(COMSTACK handle);\r
-\par \r
-\par int cs_look(COMSTACK handle);\r
-\par \r
-\par struct sockaddr_in *tcpip_strtoaddr(char *str);\r
-\par \r
-\par struct netbuf *mosi_strtoaddr(char *str);\r
-\par \r
-\par extern int cs_errno;\r
-\par \r
-\par void cs_perror(COMSTACK handle char *message);\r
-\par \r
-\par const char *cs_stackerr(COMSTACK handle);\r
-\par \r
-\par extern const char *cs_errlist[];\r
-\par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart server}{\*\bkmkstart s7}{\*\bkmkend server}\r
-\par {\*\bkmkstart _Toc399132441}7. Making an IR Interface for Your Database with YAZ{\*\bkmkend s7}{\*\bkmkend _Toc399132441}\r
-\par {\*\bkmkstart ss7_1}{\*\bkmkstart _Toc399132442}7.1 Introduction{\*\bkmkend ss7_1}{\*\bkmkend _Toc399132442}\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\i \r
-NOTE: If you aren't into documentation, a good way to learn how the backend interface works is to look at the backend.h file. Then, look at the small dummy-server in server/ztest.c. Finally, you can have a look at the seshigh.c file, which is\r
- where most of the logic of the frontend server is located. The backend.h file also makes a good reference, once you've chewed your way through the prose of this file.}{\r
-\par If you have a database system that you would like to make available by means of Z39.50/SR, }{\b YAZ}{ basically offers your two options. You can use the APIs provided by the }{\b ASN}{, }{\b ODR}{, and }{\b COMSTACK}{\r
- 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 proto\r
-col, 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 imple\r
-mented 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.\r
-\par }{\i NOTE: The backend interface was designed in anticipation of a specific \r
-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\r
- 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.}{\r
-\r
-\par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss7_2}{\*\bkmkstart _Toc399132443}7.2 The Database Frontend{\*\bkmkend ss7_2}{\*\bkmkend _Toc399132443}\r
-\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {We refer to this software as a generic database frontend. Your database system is the }{\i backend database}{\r
-, and the interface between the two is called the }{\i backend API}{. The backend API consists of a small number of function prototypes and structure definitions. You are required to provide the }{\b main()}{\r
- routine for the server (which can be quite simple), as well as functions to match each of the prototypes. The interface functions that you write can use any m\r
-echanism 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-part\r
-y software that handles the communication for you (like a commercial database client library). At any rate, the functions will perform the tasks of:\r
-\par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li720\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls3\adjustright {Initialization. \r
-\par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li720\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls3\adjustright {Searching. \r
-\par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li720\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls3\adjustright {Fetching records. \r
-\par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li720\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls3\adjustright {Scanning the database index (if you wish to impl\r
-ement SCAN). \r
-\par }\pard \qj\sb100\sa100\nowidctlpar\adjustright {(more functions will be added in time to support as much of Z39.50-1995 as possible).\r
-\par Because the model where pipes or sockets are used to access the backend database is a fairly common one, we have added a mechanism that allows this communic\r
-ation to take place asynchronously. In this mode, the frontend server doesn't have to block while the backend database is processing a request, but can wait for additional PDUs from the client.\r
-\par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss7_3}{\*\bkmkstart _Toc399132444}7.3 The Backend API{\*\bkmkend ss7_3}{\*\bkmkend _Toc399132444}\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {The headers files that you need to use the interface are in the include/ directory. They are called }{\cs27\f2\fs20 statserv.h}{ and }{\cs27\f2\fs20 backend.h}{\r
-. They will include other files from the }{\cs27\f2\fs20 include}{ 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 }{\cs27\f2\fs20 make}{ in the toplevel }{\b YAZ}{\r
- directory, everything you need to create your server is put the lib/libyaz.a library. If you want OSI as well, you'll also need to link in the }{\cs27\f2\fs20 libmosi.a}{ library from the xtimosi distribution (see the mosi.txt file), a well as the }{\r
-\cs27\f2\fs20 lib/librfc.a}{ library (to provide OSI transport over RFC1006/TCP).\r
-\par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss7_4}{\*\bkmkstart _Toc399132445}7.4 Your main() Routine{\*\bkmkend ss7_4}{\*\bkmkend _Toc399132445}\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {As mentioned, your }{\b main()}{\r
- 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\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par int statserv_main(int argc, char **argv);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b Statserv_main}{ will establish listening sockets according to the parameters given. When connection requests are received, the event handler will typically }{\b fork()}{\r
- to handle the new request. If you do use global variables, you should be aware, then, that these cannot be shared\r
- between associations, unless you explicitly disallow forking by command line parameters (we advise against this for any purposes except debugging, as a crash or hang in the server process will affect all users currently signed on to the server).\r
-\par The server provides a mechanism for controlling some of its behavior without using command-line options. The function\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par statserv_options_block *statserv_getcontrol(void);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {Will return a pointer to a }{\cs27\f2\fs20 struct statserv_options_block}{ describing the current default settings of the server. The structure contains these elements:\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b int dynamic}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {A boolean value, which determines whether the server will fork on each incoming request (TRUE), or not (FALSE). Default is TRUE.\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b int loglevel}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {Set this by ORing the constants defined in include/log.h.\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b char logfile[ODR_MAXNAME+1]}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {File for diagnostic output ("": stderr).\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b char apdufile[ODR_MAXNAME+1]}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {Name of file for logging incoming and outgoing APDUs ("": don't log APDUs, "-": }{\cs27\f2\fs20 stderr}{).\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b char default_listen[1024]}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\r
-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.\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b enum oid_proto default_proto;}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {Either }{\cs27\f2\fs20 PROTO_SR}{ or }{\cs27\f2\fs20 PROTO_Z3950}{. Default is }{\cs27\f2\fs20 PROTO_Z39_50}{.\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b int idle_timeout;}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {Maximum session idletime, in minutes. Zero indicates no (infinite) timeout. Default is 120 minutes.\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b int maxrecordsize;}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {Maximum permissible record (message) size. Default is 1Mb. This amount of mem\r
-ory 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.\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b char configname[ODR_MAXNAME+1]}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {Passed to the backend when a new connection is received.\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b char setuid[ODR_MAXNAME+1]}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {Set user id to the user specified, after binding the listener addresses.\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {The pointer returned by }{\cs27\f2\fs20 statserv_getcontrol}{ points to a static area. You are allowed to change the contents of the st\r
-ructure, but the changes will not take effect before you call\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par void statserv_setcontrol(statserv_options_block *block);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {Note that you should generally update this structure }{\i before}{ calling }{\cs27\f2\fs20 statserv_main()}{.\r
-\par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss7_5}{\*\bkmkstart _Toc399132446}7.5 The Backend Functions{\*\bkmkend ss7_5}{\*\bkmkend _Toc399132446}\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\r
-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.\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par bend_initresult *bend_init(bend_initrequest *r);\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\r
-This function is called once for each new connection request, after a new process has been forked, and an initRequest has been received from the client. The parameter and result structures are defined as\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par typedef struct bend_initrequest\r
-\par \{\r
-\par     char *configname;\r
-\par \} bend_initrequest;\r
-\par \r
-\par typedef struct bend_initresult\r
-\par \{\r
-\par     int errcode;       /* 0==OK */\r
-\par     char *errstring;   /* system error string or NULL */\r
-\par     void *handle;      /* private handle to the backend module */\r
-\par \} bend_initresult;\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {The }{\cs27\f2\fs20 configname}{ of }{\cs27\f2\fs20 bend_initrequest}{\r
- is currently always set to "default-config". We haven't had use for putting anything special in the initrequest yet, but something might go there if the need arises (account/password info would be obvious).\r
-\par In general, the server frontend expects that the }{\cs27\f2\fs20 bend_*result}{ pointer that you return is valid at least until the next call to a }{\cs27\f2\fs20 bend_* function}{\r
-. This applies to all of the functions described herein. The parameter structure passed to you in\r
- 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.\r
-\par The }{\cs27\f2\fs20 errcode}{ should be zero if the initialization of the backend went well. Any other value will be interpreted as an error. The }{\cs27\f2\fs20 errstring}{\r
- isn't used in the current version, but one option would be to stick it in the initResponse as a VisibleString. The }{\cs27\f2\fs20 handle}{ is t\r
-he 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\r
- dynamically allocated state structure that is private to your backend module.\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par bend_searchresult *bend_search(void *handle, bend_searchrequest *r,\r
-\par                                int *fd);\r
-\par bend_searchresult *bend_searchresponse(void *handle);\r
-\par \r
-\par typedef struct bend_searchrequest\r
-\par \{\r
-\par     char *setname;       /* name to give to this set */\r
-\par     int replace_set;     /* replace set, if it already exists */\r
-\par     int num_bases;       /* number of databases in list */\r
-\par     char **basenames;    /* databases to search */\r
-\par     Z_Query *query;      /* query structure */\r
-\par \} bend_searchrequest;\r
-\par \r
-\par typedef struct bend_searchresult\r
-\par \{\r
-\par     int hits;            /* number of hits */\r
-\par     int errcode;         /* 0==OK */\r
-\par     char *errstring;     /* system error string or NULL */\r
-\par \} bend_searchresult;\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\r
-The first thing to notice about the search request interface (as well as all of the following requests), is that it consists of two separate functions. The idea is to provide a simple facility for asynchronous communication with the backend ser\r
-ver. When a searchrequest comes in, the server frontend will fill out the }{\cs27\f2\fs20 bend_searchrequest}{ tructure, and call the }{\cs27\f2\fs20 bend_search function}{. The }{\cs27\f2\fs20 fd}{\r
- argument will point to an integer variable. If you are able to do asynchronous I/O with your database server, you should set *}{\cs27\f2\fs20 fd}{\r
- to the file descriptor you use for the communication, and return a null pointer. The server frontend will then }{\cs27\f2\fs20 select()}{ on the *}{\cs27\f2\fs20 fd}{, and will call }{\cs27\f2\fs20 bend_searchresult}{\r
- when it sees that data is available. If you don't support asynchronous I/O, you should return a pointer to the }{\cs27\f2\fs20 bend_searchresult}{ immediately, and leave *}{\cs27\f2\fs20 fd}{ untouched. This construction is common to all of the }{\r
-\cs27\f2\fs20 bend_}{ functions (except }{\cs27\f2\fs20 bend_init}{). Note that you can choose to support this facility in none, any, or all of the }{\cs27\f2\fs20 bend_}{ f\r
-unctions, and you can respond differently on each request at run-time. The server frontend will adapt accordingly.\r
-\par The }{\cs27\f2\fs20 bend_searchrequest}{ is a fairly close approximation of a protocol searchRequest PDU. The }{\cs27\f2\fs20 setname}{ is the resultSetName from the protocol. Y\r
-ou are required to establish a mapping between the set name and whatever your backend database likes to use. Similarly, the }{\cs27\f2\fs20 replace_set}{ is a boolean value corresponding to the resultSetIndicator field in the protocol. }{\cs27\f2\fs20 \r
-Num_bases/basenames}{ is a length of/array of character pointers to the database names provided by the client. The }{\cs27\f2\fs20 query}{\r
- 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\r
- 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 }{\cs27\f2\fs20 include/proto.h}{\r
-. 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 }{\cs27\f2\fs20 oid_getentbyoid}{ function provided by }{\b YAZ}{.\r
-\par The result structure contains a number of hits, and an }{\cs27\f2\fs20 errcode/errstring}{ pair. If an error occurs during the search, or if you're unhappy with the request, you should set\r
- 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 }{\cs27\f2\fs20 errstring}{\r
-, 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.\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par bend_fetchresult *bend_fetch(void *handle, bend_fetchrequest *r,\r
-\par                              int *fd);\r
-\par bend_fetchresult *bend_fetchresponse(void *handle);\r
-\par \r
-\par typedef struct bend_fetchrequest\r
-\par \{\r
-\par     char *setname;       /* set name */\r
-\par     int number;          /* record number */\r
-\par     oid_value format;\r
-\par \} bend_fetchrequest;\r
-\par \r
-\par typedef struct bend_fetchresult\r
-\par \{\r
-\par     char *basename;      /* name of database that provided record */\r
-\par     int len;             /* length of record */\r
-\par     char *record;        /* record */\r
-\par     int last_in_set;     /* is it?  */\r
-\par     oid_value format;\r
-\par     int errcode;         /* 0==success */\r
-\par     char *errstring;     /* system error string or NULL */\r
-\par \} bend_fetchresult;\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\i NOTE: The }{\cs27\i\f2\fs20 bend_fetchresponse()}{\i  function is not yet supported in this version of the software. Your implementation of }{\cs27\i\f2\fs20 bend_fetch()}{\i \r
- should always return a pointer to a }{\cs27\i\f2\fs20 bend_fetchresult}{\i .}{\r
-\par The frontend server calls }{\cs27\f2\fs20 bend_fetch}{ when it needs database records to fulfill a searchRequest or a presentRequest. The }{\cs27\f2\fs20 setname}{ is simply the name of the result set that holds the reference to the desired record. The }{\r
-\cs27\f2\fs20 number}{ is the offset into the set (with 1 being the first record in the set). The }{\cs27\f2\fs20 format}{ field is the record format requested by the client (See section }{\field{\*\fldinst {HYPERLINK "yaz-3.html" \\l "oid"}{\fs20 \r
-{\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000090000000303000000000000c00000000000004600000b00000079617a2d332e68746d6c00ffffadde000000000000000000000000000000000000000000000000040000006f006900640000000000}}}{\fldrslt {\cs29\ul\cf2 \r
-Object Identifiers}}}{). The value }{\cs27\f2\fs20 VAL_NONE}{ indicates that the client did not request a specific format. The }{\cs27\f2\fs20 stream}{ argument is an }{\b ODR}{ stream which should be used for alloc\r
-ating 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 rec\r
-ord between calls.\r
-\par In the result structure, the }{\cs27\f2\fs20 basename}{ is the name of the database that holds the record. }{\cs27\f2\fs20 Len}{ is the length of the record returned, in bytes, and }{\cs27\f2\fs20 record}{ is a pointer to the record. }{\cs27\f2\fs20 \r
-Last_in_set}{ should be nonzero only if the record returned is the last one in the given result set. }{\cs27\f2\fs20 Errcode}{ and }{\cs27\f2\fs20 errstring}{\r
-, if given, will currently be interpreted as a global error pertaining to the set, and will be returned in a nonSurrogateDiagnostic.\r
-\par }{\i NOTE: This is silly. Add a flag to say which is which.}{\r
-\par If the }{\cs27\f2\fs20 len}{ field has the value -1, then }{\cs27\f2\fs20 record}{ is assumed to point to a constructed data type. The }{\cs27\f2\fs20 format}{ field will be used to determine which encoder should be used to serialize the data.\r
-\par }{\i NOTE: If your backend generates structured records, it should use }{\cs27\i\f2\fs20 odr_malloc()}{\i  on the provided stream for allocating data: This allows the frontend server to keep track of the record sizes.}{\r
-\par The }{\cs27\f2\fs20 format}{ field is mapped to an object identifier in the direct reference of the resulting EXTERNAL representation of the record.\r
-\par }{\i NOTE: The current version of }{\b\i YAZ}{\i  only supports the direct reference mode.}{\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par bend_deleteresult *bend_delete(void *handle, bend_deleterequest *r,\r
-\par                                int *fd);\r
-\par bend_deleteresult *bend_deleteresponse(void *handle);\r
-\par \r
-\par typedef struct bend_deleterequest\r
-\par \{\r
-\par     char *setname;\r
-\par \} bend_deleterequest;\r
-\par \r
-\par typedef struct bend_deleteresult\r
-\par \{\r
-\par     int errcode;         /* 0==success */\r
-\par     char *errstring;     /* system error string or NULL */\r
-\par \} bend_deleteresult;\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\i NOTE: The "delete" function is not yet supported in this version of the software.}{\r
-\par }{\i NOTE: 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\r
-, 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?}{\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par bend_scanresult *bend_scan(void *handle, bend_scanrequest *r,\r
-\par     int *fd);\r
-\par bend_scanresult *bend_scanresponse(void *handle);\r
-\par \r
-\par typedef struct bend_scanrequest\r
-\par \{\r
-\par     int num_bases;      /* number of elements in databaselist */\r
-\par     char **basenames;   /* databases to search */\r
-\par     Z_AttributesPlusTerm *term;\r
-\par     int term_position;  /* desired index of term in result list */\r
-\par     int num_entries;    /* number of entries requested */\r
-\par \} bend_scanrequest;\r
-\par \r
-\par typedef struct bend_scanresult\r
-\par \{\r
-\par     int num_entries;\r
-\par     struct scan_entry\r
-\par     \{\r
-\par         char *term;\r
-\par         int occurrences;\r
-\par     \} *entries;\r
-\par     int term_position;\r
-\par     enum\r
-\par     \{\r
-\par         BEND_SCAN_SUCCESS,\r
-\par         BEND_SCAN_PARTIAL\r
-\par     \} status;\r
-\par     int errcode;\r
-\par     char *errstring;\r
-\par \} bend_scanresult;\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\i NOTE: The }{\cs27\i\f2\fs20 bend_scanresponse()}{\i  function is not yet supported in this version of the software. Your implementation of }{\cs27\i\f2\fs20 bend_scan()}{\i \r
- should always return a pointer to a }{\cs27\i\f2\fs20 bend_scanresult}{\i .}{\r
-\par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss7_6}{\*\bkmkstart _Toc399132447}7.6 Application Invocation{\*\bkmkend ss7_6}{\*\bkmkend _Toc399132447}\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {The finished application has the following invocation syntax (by way of }{\cs27\f2\fs20 statserv_main()}{):\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par appname [-szSu -a apdufile -l logfile -v loglevel]\r
-\par [listener ...]\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {The options are\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b -a}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {APDU file. Specify a file for dumping PDUs (for diagnostic purposes). The special name "-" sends output to }{\cs27\f2\fs20 stderr}{.\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b -S}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {Do\r
-n't fork 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.\r
-\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b -s}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {Use the SR protocol.\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b -z}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\r
-Use the Z39.50 protocol (default). These two options complement eachother. 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 c\r
-onnections in both protocols concurrently, on different local ports.\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b -l}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {The logfile.\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b -v}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {The log level. Use a comma-separated list of members of the set \{fatal,debug,warn,log,all,none\}.\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b -u}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\r
-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.\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b -w}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {Working directory.\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b -i}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {Use this when running from the }{\cs27\f2\fs20 inetd}{ server.\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b -t}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {Idle session timeout, in minutes.\r
-\par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b -k}{\r
-\par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {Maximum record size/message size, in kilobytes.\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {A listener specification consists of a transport mode followed by a colon (:) followed by a listener address. The transport mode is either }{\cs27\f2\fs20 osi}{ or }{\cs27\f2\fs20 tcp}{.\r
-\r
-\par For TCP, an address has the form\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par hostname | IP-number [: portnumber]\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {The port number defaults to 210 (standard Z39.50 port).\r
-\par For osi, the address form is\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par [t-selector /] hostname | IP-number [: portnumber]\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {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).\r
-\par Examples\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par tcp:dranet.dra.com\r
-\par \r
-\par osi:0402/dbserver.osiworld.com:3000\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {In both cases, the special hostname "@" is mapped to the address INADDR_ANY, which causes \r
-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):\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par my-server -u daemon tcp:@ -s osi:@\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {You can replace }{\cs27\f2\fs20 daemon}{ with another user, eg. your own account, or a dedicated IR server account. }{\cs27\f2\fs20 my-server}{\r
- should be the name of your server application. You can test the procedure with the }{\cs27\f2\fs20 ztest}{ application.\r
-\par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss7_7}{\*\bkmkstart _Toc399132448}7.7 Summary and Synopsis{\*\bkmkend ss7_7}{\*\bkmkend _Toc399132448}\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par #include <backend.h>\r
-\par \r
-\par bend_initresult *bend_init(bend_initrequest *r);\r
-\par \r
-\par bend_searchresult *bend_search(void *handle, bend_searchrequest *r,\r
-\par                                  int *fd);\r
-\par \r
-\par bend_searchresult *bend_searchresponse(void *handle);\r
-\par \r
-\par bend_fetchresult *bend_fetch(void *handle, bend_fetchrequest *r,\r
-\par                                int *fd);\r
-\par \r
-\par bend_fetchresult *bend_fetchresponse(void *handle);\r
-\par \r
-\par bend_scanresult *bend_scan(void *handle, bend_scanrequest *r, int *fd);\r
-\par \r
-\par bend_scanresult *bend_scanresponse(void *handle);\r
-\par \r
-\par bend_deleteresult *bend_delete(void *handle, bend_deleterequest *r,\r
-\par                                   int *fd);\r
-\par \r
-\par bend_deleteresult *bend_deleteresponse(void *handle);\r
-\par \r
-\par void bend_close(void *handle);\r
-\par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart s8}\r
-\par {\*\bkmkstart _Toc399132449}8. Future Directions{\*\bkmkend s8}{\*\bkmkend _Toc399132449}\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {The software has been successfully ported to the Mac as well as Windows NT/95 - we'd like to test those ports better and make sure they work as they should.\r
-\par 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 co\r
-ntrol, and easy support for Explain (possibly with Zebra as an extra database engine).\r
-\par 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.\r
-\par 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.\r
-\r
-\par O\r
-ther 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 w\r
-ith.\r
-\par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart s9}{\*\bkmkstart _Toc399132450}9. License{\*\bkmkend s9}{\*\bkmkend _Toc399132450}\r
-\par {\*\bkmkstart ss9_1}{\*\bkmkstart _Toc399132451}9.1 Index Data Copyright{\*\bkmkend ss9_1}{\*\bkmkend _Toc399132451}\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {Copyright (c) 1995,1996 Index Data.\r
-\par 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:\r
-\par 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.\r
-\par 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.\r
-\par THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED, OR OTH\r
-ERWISE, 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 RESULTI\r
-NG 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.\r
-\par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss9_2}{\*\bkmkstart _Toc399132452}9.2 Additional Copyright Statements{\*\bkmkend ss9_2}{\*\bkmkend _Toc399132452}\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {The optional CCL query language interpreter is covered by the following license:\r
-\par Copyright (c) 1995, the EUROPAGATE consortium (see below).\r
-\par The EUROPAGATE consortium members are:\r
-\par University College Dublin Danmarks Teknologiske Videnscenter An Chomhairle Leabharlanna Consejo Superior de Investigaciones Cientificas\r
-\par 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:\r
-\par 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.\r
-\par 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.\r
-\par 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 u\r
-sed to evaluate the EUROPAGATE project and the software, and to plan further developments. The consortium may use the information in later publications.\r
-\par 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.\r
-\par THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY \r
-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, WH\r
-ETHER 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.\r
-\par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart s10}{\*\bkmkstart _Toc399132453}10. About Index Data{\*\bkmkend s10}{\*\bkmkend _Toc399132453}\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {Index Data is a consulting and software-dev\r
-elopment 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 syst\r
-em with open network interfaces and hypermedia capabilities.\r
-\par 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.\r
-\par We'll be happy to answer questions about the software, and about ourselves in general.\r
-\par }\pard\plain \s25\qj\li360\ri360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\cs27\f2\fs20 Index Data\line Ryesgade 3\line DK-2200 K\'f8benhavn N}{\r
-\par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631\adjustright \f2\fs20\lang2057 {\cs27 \r
-\par Phone: +45 3536 3672\r
-\par Fax  : +45 3536 0449\r
-\par Email: info@index.ping.dk\r
-\par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\r
-\par }}
\ No newline at end of file
+{\rtf1\ansi\deff0
+{\fonttbl{\f1\fnil\fcharset0 Arial;}
+{\f0\fnil\fcharset0 Times New Roman;}
+}
+{\colortbl;}{\stylesheet{\s1 Heading 1;}{\s2 Heading 2;}{\s3 Heading 3;}{\s4 Heading 4;}{\s5 Heading 5;}{\s6 Heading 6;}{\s7 Heading 7;}{\s8 Heading 8;}{\s9 Heading 9;}}
+\deflang1024\notabind\facingp\hyphauto1\widowctrl
+\sectd\plain\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1920\headery0\footery0\pgndec{\headerl\pard\sl-240\sb770\sa430\plain\tqc\tx4680\tqr\tx9360 {}\tab {}\tab {}\par}{\footerl\pard\sl-240\sb770\sa910\plain\tqc\tx4680\tqr\tx9360 {}\tab {}\tab {}\par}{\headerr\pard\sl-240\sb770\sa430\plain\tqc\tx4680\tqr\tx9360 {}\tab {}\tab {}\par}{\footerr\pard\sl-240\sb770\sa910\plain\tqc\tx4680\tqr\tx9360 {}\tab {}\tab {}\par}\pard\sl20 \fs20 \hyphpar0\par\pard\sb373\sl647\qc \b\fs49\f1 YAZ' Users Guide and Reference\hyphpar0\par\sect\sectd\plain\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1920\headery0\footery0\pgndec{\headerl\pard\sl-240\sb770\sa430\plain\tqc\tx4680\tqr\tx9360 {}\tab {}\tab {}\par}{\footerl\pard\sl-240\sb770\sa910\plain\tqc\tx4680\tqr\tx9360 {}\tab {}\tab {}\par}{\headerr\pard\sl-240\sb770\sa430\plain\tqc\tx4680\tqr\tx9360 {}\tab {}\tab {}\par}{\footerr\pard\sl-240\sb770\sa910\plain\tqc\tx4680\tqr\tx9360 {}\tab {}\tab {}\par}\pard\sl20 \fs20 \keepn\hyphpar0\par\pard\sl-240 \b\f1  YAZ' Users Guide and Reference \hyphpar0\par\sect\sectd\plain\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1920\headery0\footery0\pgnlcrm\pgnrestart{\headerl\pard\sl-240\sb770\sa430\plain\tqc\tx4680\tqr\tx9360 {}\tab {}\tab {}\par}{\footerl\pard\sl-240\sb770\sa910\plain\tqc\tx4680\tqr\tx9360 {}\tab {}\tab {\i\fs20 \chpgn }\par}{\headerr\pard\sl-240\sb770\sa430\plain\tqc\tx4680\tqr\tx9360 {}\tab {}\tab {}\par}{\footerr\pard\sl-240\sb770\sa910\plain\tqc\tx4680\tqr\tx9360 {}\tab {}\tab {\i\fs20 \chpgn }\par}\pard\sb311\s1\sl539 \b\fs41\f1 Table of Contents\keepn\hyphpar0\par\pard\sb207\li1440\sl260\fi-480 {\field{\*\fldinst   HYPERLINK  \\l _3 }{\fldrslt \fs20\f0 1. Introduction}}\fs20\f0 \tqr\tldot\tx9360\tab {\field{\*\fldinst   HYPERLINK  \\l _3 }{\fldrslt {\field\flddirty{\*\fldinst PAGEREF _3}{\fldrslt 000}}}}\hyphpar0\par\sect\sectd\plain\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1920\headery0\footery0\pgndec\pgnrestart\titlepg{\headerf\pard\sl-240\sb770\sa430\plain\tqc\tx4680\tqr\tx9360 {}\tab {}\tab {}\par}{\footerf\pard\sl-240\sb770\sa910\plain\tqc\tx4680\tqr\tx9360 {}\tab {}\tab {\i\fs20 \chpgn }\par}{\headerl\pard\sl-240\sb770\sa430\plain\tqc\tx4680\tqr\tx9360 {}\tab {}\tab {\i\fs20 Chapter 1. Introduction}\par}{\footerl\pard\sl-240\sb770\sa910\plain\tqc\tx4680\tqr\tx9360 {}\tab {}\tab {\i\fs20 \chpgn }\par}{\headerr\pard\sl-240\sb770\sa430\plain\tqc\tx4680\tqr\tx9360 {}\tab {}\tab {\i\fs20 Chapter 1. Introduction}\par}{\footerr\pard\sl-240\sb770\sa910\plain\tqc\tx4680\tqr\tx9360 {}\tab {}\tab {\i\fs20 \chpgn }\par}\pard\sb311\s1\sl539 {\*\bkmkstart _3}{\*\bkmkend _3}\b\fs41\f1 Chapter 1. Introduction \keepn\hyphpar0\par\pard\sb207\li960\sl260 \b0\fs20\lang1033\f0  About the YAZ toolkit. \hyphpar0\par}
diff --git a/doc/yaz.xml b/doc/yaz.xml
new file mode 100644 (file)
index 0000000..d50abc4
--- /dev/null
@@ -0,0 +1,73 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+                    "../../docbook/docbookx.dtd" [
+     <!ENTITY yaz "YAZ">
+     <!ENTITY chap-introduction SYSTEM "introduction.xml">
+     <!ENTITY chap-installation SYSTEM "installation.xml">
+     <!ENTITY chap-asn SYSTEM "asn.xml">
+     <!ENTITY chap-tools SYSTEM "tools.xml">
+     <!ENTITY chap-odr SYSTEM "odr.xml">
+     <!ENTITY chap-comstack SYSTEM "comstack.xml">
+     <!ENTITY chap-frontend SYSTEM "frontend.xml">
+     <!ENTITY chap-future SYSTEM "future.xml">
+     <!ENTITY app-license SYSTEM "license.xml">
+     <!ENTITY app-indexdata SYSTEM "indexdata.xml">
+     <!ENTITY asn "<acronym>ASN</acronym>">
+     <!ENTITY odr "<acronym>ODR</acronym>">
+     <!ENTITY comstack "<acronym>COMSTACK</acronym>">
+]>
+<!-- $Header: /home/cvsroot/yaz/doc/yaz.xml,v 1.1 2001-01-04 13:36:25 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/SR 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
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:1
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-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:
+-->