-</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[]
-</synopsis>
-
-<para>
-can be indexed by the error code to obtain a human-readable
-representation of the problem.
-</para>
-
-</sect2>
-<sect2><title>Summary and Synopsis</title>
-
-<synopsis>
-#include <odr.h>
-
-ODR odr_createmem(int direction);
-
-void odr_destroy(ODR o);
-
-void odr_reset(ODR o);
-
-char *odr_getbuf(ODR o, int *len);
-
-void odr_setbuf(ODR o, char *buf, int len);
-
-void *odr_malloc(ODR o, int size);
-
-ODR_MEM odr_extract_mem(ODR o);
-
-void odr_release_mem(ODR_MEM r);
-
-int odr_geterror(ODR o);
-
-void odr_perror(char *message);
-
-extern char *odr_errlist[];
-</synopsis>
-
-</sect2>
-</sect1>
-
-<sect1><title id="odr-prog">Programming with ODR</title>
-
-<para>
-The API of &odr; is designed to reflect the structure of ASN.1, rather
-than BER itself. Future releases may be able to represent data in
-other external forms.
-</para>
-
-<para>
-The interface is based loosely on that of the Sun Microsystems XDR routines.
-Specifically, each function which corresponds to an ASN.1 primitive
-type has a dual function. Depending on the settings of the ODR
-stream which is supplied as a parameter, the function may be used
-either to encode or decode data. The functions that can be built
-using these primitive functions, to represent more complex datatypes, share
-this quality. The result is that you only have to enter the definition
-for a type once - and you have the functionality of encoding, decoding
-(and pretty-printing) all in one unit. The resulting C source code is
-quite compact, and is a pretty straightforward representation of the
-source ASN.1 specification. Although no ASN.1 compiler is supplied
-with &odr; at this time, it shouldn't be too difficult to write one, or
-perhaps even to adapt an existing compiler to output &odr; routines
-(not surprisingly, writing encoders/decoders using &odr; turns out
-to be boring work).
-</para>
-
-<para>
-In many cases, the model of the XDR functions works quite well in this
-role.
-In others, it is less elegant. Most of the hassle comes from the optional
-SEQUENCE memebers which don't exist in XDR.
-</para>
-
-<sect2><title>The Primitive ASN.1 Types</title>
-
-<para>
-ASN.1 defines a number of primitive types (many of which correspond
-roughly to primitive types in structured programming languages, such as C).
-</para>
-
-<sect3><title>INTEGER</title>
-
-<para>
-The &odr; function for encoding or decoding (or printing) the ASN.1
-INTEGER type looks like this:
-</para>
-
-<synopsis>
- int odr_integer(ODR o, int **p, int optional, const char *name);
-</synopsis>
-
-<para>
-(we don't allow values that can't be contained in a C integer.)
-</para>
-
-<para>
-This form is typical of the primitive &odr; functions. They are named
-after the type of data that they encode or decode. They take an &odr;
-stream, an indirect reference to the type in question, and an
-<literal>optional</literal> flag (corresponding to the OPTIONAL keyword
-of ASN.1) as parameters. They all return an integer value of either one
-or zero.
-When you use the primitive functions to construct encoders for complex
-types of your own, you should follow this model as well. This
-ensures that your new types can be reused as elements in yet more
-complex types.
-</para>
-
-<para>
-The <literal>o</literal> parameter should obviously refer to a properly
-initialized &odr; stream of the right type (encoding/decoding/printing)
-for the operation that you wish to perform.
-</para>
-
-<para>
-When encoding or printing, the function first looks at
-<literal>* p</literal>. If <literal>* p</literal> (the pointer pointed
-to by <literal>p</literal>) is a null pointer, this is taken to mean that
-the data element is absent. If the <literal>optional</literal> parameter
-is nonzero, the function will return one (signifying success) without
-any further processing. If the <literal>optional</literal> is zero, an
-internal error flag is set in the &odr; stream, and the function will
-return 0. No further operations can be carried out on the stream without
-a call to the function <function>odr_reset()</function>.
-</para>
-
-<para>
-If <literal>*p</literal> is not a null pointer, it is expected to
-point to an instance of the data type. The data will be subjected to
-the encoding rules, and the result will be placed in the buffer held
-by the &odr; stream.
-</para>
-
-<para>
-The other ASN.1 primitives have similar functions that operate in
-similar manners:
-</para>
-</sect3>
-<sect3><title>BOOLEAN</title>
-
-<synopsis>
- int odr_bool(ODR o, bool_t **p, int optional, const char *name);
-</synopsis>
-
-</sect3>
-<sect3><title>REAL</title>
-
-<para>
-Not defined.
-</para>
-
-</sect3>
-<sect3><title>NULL</title>
-
-<synopsis>
- int odr_null(ODR o, bool_t **p, int optional, const char *name);
-</synopsis>
-
-<para>
-In this case, the value of **p is not important. If <literal>*p</literal>
-is different from the null pointer, the null value is present, otherwise
-it's absent.
-</para>
-
-</sect3>
-<sect3><title>OCTET STRING</title>
-
-<synopsis>
- typedef struct odr_oct
- {
- unsigned char *buf;
- int len;
- int size;
- } Odr_oct;
-
- int odr_octetstring(ODR o, Odr_oct **p, int optional, const char *name);
-</synopsis>
-
-<para>
-The <literal>buf</literal> field should point to the character array
-that holds the octetstring. The <literal>len</literal> field holds the
-actual length, while the <literal>size</literal> field gives the size
-of the allocated array (not of interest to you, in most cases).
-The character array need not be null terminated.
-</para>
-
-<para>
-To make things a little easier, an alternative is given for string
-types that are not expected to contain embedded NULL characters (eg.
-VisibleString):
-</para>
-
-<synopsis>
- int odr_cstring(ODR o, char **p, int optional, const char *name);
-</synopsis>
-
-<para>
-Which encoded or decodes between OCTETSTRING representations and
-null-terminates C strings.
-</para>
-
-<para>
-Functions are provided for the derived string types, eg:
-</para>
-
-<synopsis>
- int odr_visiblestring(ODR o, char **p, int optional, const char *name);
-</synopsis>
-
-</sect3>
-<sect3><title>BIT STRING</title>
-
-<synopsis>
- int odr_bitstring(ODR o, Odr_bitmask **p, int optional, const char *name);
-</synopsis>
-
-<para>
-The opaque type <literal>Odr_bitmask</literal> is only suitable for
-holding relatively brief bit strings, eg. for options fields, etc.
-The constant <literal>ODR_BITMASK_SIZE</literal> multiplied by 8
-gives the maximum possible number of bits.
-</para>
-
-<para>
-A set of macros are provided for manipulating the
-<literal>Odr_bitmask</literal> type:
-</para>
-
-<synopsis>
- void ODR_MASK_ZERO(Odr_bitmask *b);
-
- void ODR_MASK_SET(Odr_bitmask *b, int bitno);
-
- void ODR_MASK_CLEAR(Odr_bitmask *b, int bitno);
-
- int ODR_MASK_GET(Odr_bitmask *b, int bitno);
-</synopsis>
-
-<para>
-The functions are modelled after the manipulation functions that
-accompany the <literal>fd_set</literal> type used by the
-<function>select(2)</function> call.
-<literal>ODR_MASK_ZERO</literal> should always be called first on a
-new bitmask, to initialize the bits to zero.
-</para>
-</sect3>
-
-<sect3><title>OBJECT IDENTIFIER</title>
-
-<synopsis>
+]]>
+ </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>
+ </example>
+
+ </sect2>
+
+ <sect2><title>Printing</title>
+ <para>
+ When an ODR stream is created of type <literal>ODR_PRINT</literal>
+ the ODR module will print the contents of a PDU in a readable format.
+ By default output is written to the <literal>stderr</literal> stream.
+ This behavior can be changed, however, by calling the function
+ <synopsis>
+ odr_setprint(ODR o, FILE *file);
+ </synopsis>
+ before encoders or decoders are being invoked.
+ It is also possible to direct the output to a buffer (of indeed
+ another file), by using the more generic mechanism:
+ <synopsis>
+ void odr_set_stream(ODR o, void *handle,
+ void (*stream_write)(ODR o, void *handle, int type,
+ const char *buf, int len),
+ void (*stream_close)(void *handle));
+ </synopsis>
+ Here the user provides an opaque handle and two handlers,
+ <replaceable>stream_write</replaceable> for writing,
+ and <replaceable>stream_close</replaceable> which is supposed
+ to close/free resources associated with handle.
+ The <replaceable>stream_close</replaceable> handler is optional and
+ if NULL for the function is provided, it will not be invoked.
+ The <replaceable>stream_write</replaceable> takes the ODR handle
+ as parameter, the user defined handle, a type
+ <literal>ODR_OCTETSTRING</literal>, <literal>ODR_VISIBLESTRING</literal>
+ which indicates the type of contents is being written.
+ </para>
+ <para>
+ Another utility useful for diagnostics (error handling) or as
+ part of the printing facilities is:
+ <synopsis>
+ const char **odr_get_element_path(ODR o);
+ </synopsis>
+ which returns a list of current elements that ODR deals with at the
+ moment. For the returned array, say <literal>ar</literal>,
+ <literal>ar[0]</literal> is the top level element,
+ <literal>ar[n]</literal> is the last. The last element has the
+ property that <literal>ar[n+1] == NULL</literal>.
+ </para>
+ <example>
+ <title>Element Path for record</title>
+ <para>
+ For a database record part of a PresentResponse the
+ array returned by <function>odr_get_element</function>
+ is <literal>presentResponse</literal>, <literal>databaseOrSurDiagnostics</literal>, <literal>?</literal>, <literal>record</literal>, <literal>?</literal>, <literal>databaseRecord</literal> . The question mark appears due to
+ unnamed constructions.
+ </para>
+ </example>
+ </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[]
+ </synopsis>
+
+ <para>
+ can be indexed by the error code to obtain a human-readable
+ representation of the problem.
+ </para>
+
+ </sect2>
+ <sect2><title>Summary and Synopsis</title>
+
+ <synopsis>
+ #include <odr.h>
+
+ ODR odr_createmem(int direction);
+
+ void odr_destroy(ODR o);
+
+ void odr_reset(ODR o);
+
+ char *odr_getbuf(ODR o, int *len);
+
+ void odr_setbuf(ODR o, char *buf, int len);
+
+ void *odr_malloc(ODR o, int size);
+
+ ODR_MEM odr_extract_mem(ODR o);
+
+ void odr_release_mem(ODR_MEM r);
+
+ int odr_geterror(ODR o);
+
+ void odr_perror(char *message);
+
+ extern char *odr_errlist[];
+ </synopsis>
+
+ </sect2>
+ </sect1>
+
+ <sect1 id="odr.programming"><title>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>
+
+ <tip>
+ <para>
+ There is an ASN.1 tutorial available at
+ <ulink url="&url.asn.1.tutorial;">this site</ulink>.
+ This site also has standards for ASN.1 (X.680) and BER (X.690)
+ <ulink url="&url.asn.1.standards;">online</ulink>.
+ </para>
+ </tip>
+
+ <para>
+ The ODR 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 data types,
+ 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.
+ </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 members 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 modeled 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>