.. index:: API

The libxo API
=============

This section gives details about the functions in libxo, how to call
them, and the actions they perform.

.. index:: Handles
.. _handles:

Handles
-------

libxo uses "handles" to control its rendering functionality.  The
handle contains state and buffered data, as well as callback functions
to process data.

Handles give an abstraction for libxo that encapsulates the state of a
stream of output.  Handles have the data type "`xo_handle_t`" and are
opaque to the caller.

The library has a default handle that is automatically initialized.
By default, this handle will send text style output (`XO_STYLE_TEXT`) to
standard output.  The xo_set_style and xo_set_flags functions can be
used to change this behavior.

For the typical command that is generating output on standard output,
there is no need to create an explicit handle, but they are available
when needed, e.g., for daemons that generate multiple streams of
output.

Many libxo functions take a handle as their first parameter; most that
do not use the default handle.  Any function taking a handle can be
passed NULL to access the default handle.  For the convenience of
callers, the libxo library includes handle-less functions that
implicitly use the default handle.

For example, the following are equivalent::

    xo_emit("test");
    xo_emit_h(NULL, "test");

Handles are created using `xo_create` and destroy using
`xo_destroy`. 

.. index:: xo_create

xo_create
~~~~~~~~~

.. c:function:: xo_handle_t *xo_create (xo_style_t style, xo_xof_flags_t flags)

  The `xo_create` function allocates a new handle which can be passed
  to further libxo function calls.  The `xo_handle_t` structure is
  opaque.

  :param xo_style_t style: Output style (XO_STYLE\_*)
  :param xo_xof_flags_t flags: Flags for this handle (XOF\_*)
  :return: New libxo handle
  :rtype: xo_handle_t \*

  ::

    EXAMPLE:
        xo_handle_t *xop = xo_create(XO_STYLE_JSON, XOF_WARN | XOF_PRETTY);
        ....
        xo_emit_h(xop, "testing\n");

  See also :ref:`output-styles` and :ref:`flags`.

.. index:: xo_create_to_file
.. index:: XOF_CLOSE_FP

xo_create_to_file
~~~~~~~~~~~~~~~~~

.. c:function::
  xo_handle_t *xo_create_to_file (FILE *fp, unsigned style, unsigned flags)

  The `xo_create_to_file` function is aconvenience function is
  provided for situations when output should be written to a different
  file, rather than the default of standard output.

  The `XOF_CLOSE_FP` flag can be set on the returned handle to trigger a
  call to fclose() for the FILE pointer when the handle is destroyed,
  avoiding the need for the caller to perform this task.

  :param fp: FILE to use as base for this handle
  :type fp: FILE *
  :param xo_style_t style: Output style (XO_STYLE\_*)
  :param xo_xof_flags_t flags: Flags for this handle (XOF\_*)
  :return: New libxo handle
  :rtype: xo_handle_t \*

.. index:: xo_set_writer
.. index:: xo_write_func_t
.. index:: xo_close_func_t
.. index:: xo_flush_func_t

xo_set_writer
~~~~~~~~~~~~~

.. c:function::
  void xo_set_writer (xo_handle_t *xop, void *opaque, \
  xo_write_func_t write_func, xo_close_func_t close_func, \
  xo_flush_func_t flush_func)

  The `xo_set_writer` function allows custom functions which can
  tailor how libxo writes data.  The `opaque` argument is recorded and
  passed back to the functions, allowing the function to acquire
  context information. The *write_func* function writes data to the
  output stream.  The *close_func* function can release this opaque
  data and any other resources as needed.  The *flush_func* function
  is called to flush buffered data associated with the opaque object.

  :param xop: Handle to modify (or NULL for default handle)
  :type xop: xo_handle_t *
  :param opaque: Pointer to opaque data passed to the given functions
  :type opaque: void *
  :param xo_write_func_t write_func: New write function
  :param xo_close_func_t close_func: New close function
  :param xo_flush_func_t flush_func: New flush function
  :returns: void

.. index:: xo_get_style

xo_get_style
~~~~~~~~~~~~

.. c:function:: xo_style_t xo_get_style(xo_handle_t *xop)

  Use the `xo_get_style` function to find the current output style for
  a given handle.  To use the default handle, pass a `NULL` handle.

  :param xop: Handle to interrogate (or NULL for default handle)
  :type xop: xo_handle_t *
  :returns: Output style (XO_STYLE\_*)
  :rtype: xo_style_t

  ::

    EXAMPLE::
        style = xo_get_style(NULL);

.. index::  XO_STYLE_TEXT
.. index::  XO_STYLE_XML
.. index::  XO_STYLE_JSON
.. index::  XO_STYLE_HTML

.. _output-styles:

Output Styles (XO_STYLE\_\*)
++++++++++++++++++++++++++++

The libxo functions accept a set of output styles:

  =============== =========================
   Flag            Description
  =============== =========================
   XO_STYLE_TEXT   Traditional text output
   XO_STYLE_XML    XML encoded data
   XO_STYLE_JSON   JSON encoded data
   XO_STYLE_HTML   HTML encoded data
  =============== =========================

The "XML", "JSON", and "HTML" output styles all use the UTF-8
character encoding.  "TEXT" using locale-based encoding.

.. index:: xo_set_style

xo_set_style
~~~~~~~~~~~~

.. c:function:: void xo_set_style(xo_handle_t *xop, xo_style_t style)

  The `xo_set_style` function is used to change the output style
  setting for a handle.  To use the default handle, pass a `NULL`
  handle.

  :param xop: Handle to modify
  :type xop: xo_handle_t *
  :param xo_style_t style: Output style (XO_STYLE\_*)
  :returns: void

  ::

    EXAMPLE:
        xo_set_style(NULL, XO_STYLE_XML);

.. index:: xo_set_style_name

xo_set_style_name
~~~~~~~~~~~~~~~~~

.. c:function:: int xo_set_style_name (xo_handle_t *xop, const char *style)

  The `xo_set_style_name` function can be used to set the style based
  on a name encoded as a string: The name can be any of the supported
  styles: "text", "xml", "json", or "html".

  :param xop: Handle for modify (or NULL for default handle)
  :type xop: xo_handle_t \*
  :param style: Text name of the style
  :type style: const char \*
  :returns: zero for success, non-zero for error
  :rtype: int

  ::

    EXAMPLE:
        xo_set_style_name(NULL, "html");

.. index:: xo_set_flags

xo_set_flags
~~~~~~~~~~~~

.. c:function:: void xo_set_flags(xo_handle_t *xop, xo_xof_flags_t flags)

  :param xop: Handle for modify (or NULL for default handle)
  :type xop: xo_handle_t \*
  :param xo_xof_flags_t flags: Flags to add for the handle
  :returns: void

  Use the `xo_set_flags` function to turn on flags for a given libxo
  handle.  To use the default handle, pass a `NULL` handle.

  ::

    EXAMPLE:
        xo_set_flags(NULL, XOF_PRETTY | XOF_WARN);

.. index:: Flags; XOF_*
.. index:: XOF_CLOSE_FP
.. index:: XOF_COLOR
.. index:: XOF_COLOR_ALLOWED
.. index:: XOF_DTRT
.. index:: XOF_INFO
.. index:: XOF_KEYS
.. index:: XOF_NO_ENV
.. index:: XOF_NO_HUMANIZE
.. index:: XOF_PRETTY
.. index:: XOF_UNDERSCORES
.. index:: XOF_UNITS
.. index:: XOF_WARN
.. index:: XOF_WARN_XML
.. index:: XOF_XPATH
.. index:: XOF_COLUMNS
.. index:: XOF_FLUSH

.. _flags:

Flags (XOF\_\*)
+++++++++++++++

The set of valid flags include:

  =================== =========================================
   Flag                Description
  =================== =========================================
   XOF_CLOSE_FP        Close file pointer on `xo_destroy`
   XOF_COLOR           Enable color and effects in output
   XOF_COLOR_ALLOWED   Allow color/effect for terminal output
   XOF_DTRT            Enable "do the right thing" mode
   XOF_INFO            Display info data attributes (HTML)
   XOF_KEYS            Emit the key attribute (XML)
   XOF_NO_ENV          Do not use the :ref:`libxo-options` env var
   XOF_NO_HUMANIZE     Display humanization (TEXT, HTML)
   XOF_PRETTY          Make "pretty printed" output
   XOF_UNDERSCORES     Replaces hyphens with underscores
   XOF_UNITS           Display units (XML, HMTL)
   XOF_WARN            Generate warnings for broken calls
   XOF_WARN_XML        Generate warnings in XML on stdout
   XOF_XPATH           Emit XPath expressions (HTML)
   XOF_COLUMNS         Force xo_emit to return columns used
   XOF_FLUSH           Flush output after each `xo_emit` call
  =================== =========================================

The `XOF_CLOSE_FP` flag will trigger the call of the *close_func*
(provided via `xo_set_writer`) when the handle is destroyed.

The `XOF_COLOR` flag enables color and effects in output regardless
of output device, while the `XOF_COLOR_ALLOWED` flag allows color
and effects only if the output device is a terminal.

The `XOF_PRETTY` flag requests "pretty printing", which will trigger
the addition of indentation and newlines to enhance the readability of
XML, JSON, and HTML output.  Text output is not affected.

The `XOF_WARN` flag requests that warnings will trigger diagnostic
output (on standard error) when the library notices errors during
operations, or with arguments to functions.  Without warnings enabled,
such conditions are ignored.

Warnings allow developers to debug their interaction with libxo.
The function `xo_failure` can used as a breakpoint for a debugger,
regardless of whether warnings are enabled.

If the style is `XO_STYLE_HTML`, the following additional flags can be
used:

  =============== =========================================
   Flag            Description
  =============== =========================================
   XOF_XPATH       Emit "data-xpath" attributes
   XOF_INFO        Emit additional info fields
  =============== =========================================

The `XOF_XPATH` flag enables the emission of XPath expressions detailing
the hierarchy of XML elements used to encode the data field, if the
XPATH style of output were requested.

The `XOF_INFO` flag encodes additional informational fields for HTML
output.  See :ref:`field-information` for details.

If the style is `XO_STYLE_XML`, the following additional flags can be
used:

  =============== =========================================
   Flag            Description
  =============== =========================================
   XOF_KEYS        Flag "key" fields for XML
  =============== =========================================

The `XOF_KEYS` flag adds "key" attribute to the XML encoding for
field definitions that use the "k" modifier.  The key attribute has
the value "key"::

    xo_emit("{k:name}", item);

  XML:
      <name key="key">truck</name>

.. index:: xo_clear_flags

xo_clear_flags
++++++++++++++

.. c:function:: void xo_clear_flags (xo_handle_t *xop, xo_xof_flags_t flags)

  :param xop: Handle for modify (or NULL for default handle)
  :type xop: xo_handle_t \*
  :param xo_xof_flags_t flags: Flags to clear for the handle
  :returns: void

  Use the `xo_clear_flags` function to turn off the given flags in a
  specific handle.  To use the default handle, pass a `NULL` handle.

.. index:: xo_set_options

xo_set_options
++++++++++++++

.. c:function:: int xo_set_options (xo_handle_t *xop, const char *input)

  :param xop: Handle for modify (or NULL for default handle)
  :type xop: xo_handle_t \*
  :param input: string containing options to set
  :type input: const char *
  :returns: zero for success, non-zero for error
  :rtype: int

  The `xo_set_options` function accepts a comma-separated list of
  output styles and modifier flags and enables them for a specific
  handle.  The options are identical to those listed in
  :ref:`options`.  To use the default handle, pass a `NULL` handle.

.. index:: xo_destroy

xo_destroy
++++++++++

.. c:function:: void xo_destroy(xo_handle_t *xop)

  :param xop: Handle for modify (or NULL for default handle)
  :type xop: xo_handle_t \*
  :returns: void  

  The `xo_destroy` function releases a handle and any resources it is
  using.  Calling `xo_destroy` with a `NULL` handle will release any
  resources associated with the default handle.

.. index:: xo_emit

Emitting Content (xo_emit)
--------------------------

The functions in this section are used to emit output.  They use a
`format` string containing field descriptors as specified in
:ref:`format-strings`.  The use of a handle is optional and `NULL` can
be passed to access the internal "default" handle.  See
:ref:`handles`.

The remaining arguments to `xo_emit` and `xo_emit_h` are a set of
arguments corresponding to the fields in the format string.  Care must
be taken to ensure the argument types match the fields in the format
string, since an inappropriate or missing argument can ruin your day.
The `vap` argument to `xo_emit_hv` points to a variable argument list
that can be used to retrieve arguments via `va_arg`.

.. c:function:: xo_ssize_t xo_emit (const char *fmt, ...)

  :param fmt: The format string, followed by zero or more arguments
  :returns: If XOF_COLUMNS is set, the number of columns used; otherwise the number of bytes emitted
  :rtype: xo_ssize_t

.. c:function:: xo_ssize_t xo_emit_h (xo_handle_t *xop, const char *fmt, ...)

  :param xop: Handle for modify (or NULL for default handle)
  :type xop: xo_handle_t \*
  :param fmt: The format string, followed by zero or more arguments
  :returns: If XOF_COLUMNS is set, the number of columns used; otherwise the number of bytes emitted
  :rtype: xo_ssize_t

.. c:function:: xo_ssize_t xo_emit_hv (xo_handle_t *xop, const char *fmt, va_list vap)

  :param xop: Handle for modify (or NULL for default handle)
  :type xop: xo_handle_t \*
  :param fmt: The format string
  :param va_list vap: A set of variadic arguments
  :returns: If XOF_COLUMNS is set, the number of columns used; otherwise the number of bytes emitted
  :rtype: xo_ssize_t

.. index:: xo_emit_field

Single Field Emitting Functions (xo_emit_field)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The functions in this section emit formatted output similar to
`xo_emit` but where `xo_emit` uses a single string argument containing
the description for multiple fields, `xo_emit_field` emits a single
field using multiple ar- guments to contain the field description.
`xo_emit_field_h` adds an ex- plicit handle to use instead of the
default handle, while `xo_emit_field_hv` accepts a va_list for
additional flexibility.

The arguments `rolmod`, `content`, `fmt`, and `efmt` are detailed in
:ref:`field-formatting`.  Using distinct arguments allows callers to
pass the field description in pieces, rather than having to use
something like `snprintf` to build the format string required by
`xo_emit`.  The arguments are each NUL-terminated strings. The `rolmod`
argument contains the `role` and `modifier` portions of the field
description, the `content` argument contains the `content` portion, and
the `fmt` and `efmt` contain the `field-format` and `encoding-format` por-
tions, respectively.

As with `xo_emit`, the `fmt` and `efmt` values are both optional,
since the `field-format` string defaults to "%s", and the
`encoding-format`'s default value is derived from the `field-format`
per :ref:`field-formatting`.  However, care must be taken to avoid
using a value directly as the format, since characters like '{', '%',
and '}' will be interpreted as formatting directives, and may cause
xo_emit_field to dereference arbitrary values off the stack, leading
to bugs, core files, and gnashing of teeth.

.. c:function:: xo_ssize_t xo_emit_field (const char *rolmod, const char *content, const char *fmt, const char *efmt, ...)

  :param rolmod: A comma-separated list of field roles and field modifiers
  :type rolmod: const char *
  :param content: The "content" portion of the field description string
  :type content: const char *
  :param fmt: Contents format string
  :type fmt: const char *
  :param efmt: Encoding format string, followed by additional arguments
  :type efmt: const char *
  :returns: If XOF_COLUMNS is set, the number of columns used; otherwise the number of bytes emitted
  :rtype: xo_ssize_t

  ::

    EXAMPLE::
        xo_emit_field("T", title, NULL, NULL, NULL);
        xo_emit_field("T", "Host name is ", NULL, NULL);
        xo_emit_field("V", "host-name", NULL, NULL, host-name);
        xo_emit_field(",leaf-list,quotes", "sku", "%s-%u", "%s-000-%u",
                        "gum", 1412);

.. c:function:: xo_ssize_t xo_emit_field_h (xo_handle_t *xop, const char *rolmod, const char *contents, const char *fmt, const char *efmt, ...)

  :param xop: Handle for modify (or NULL for default handle)
  :type xop: xo_handle_t \*
  :param rolmod: A comma-separated list of field roles and field modifiers
  :type rolmod: const char *
  :param contents: The "contents" portion of the field description string
  :type contents: const char *
  :param fmt: Content format string
  :type fmt: const char *
  :param efmt: Encoding format string, followed by additional arguments
  :type efmt: const char *
  :returns: If XOF_COLUMNS is set, the number of columns used; otherwise the number of bytes emitted
  :rtype: xo_ssize_t

.. c:function:: xo_ssize_t xo_emit_field_hv (xo_handle_t *xop, const char *rolmod, const char *contents, const char *fmt, const char *efmt, va_list vap)

  :param xop: Handle for modify (or NULL for default handle)
  :type xop: xo_handle_t \*
  :param rolmod: A comma-separated list of field roles and field modifiers
  :type rolmod: const char *
  :param contents: The "contents" portion of the field description string
  :type contents: const char *
  :param fmt: Content format string
  :type fmt: const char *
  :param efmt: Encoding format string
  :type efmt: const char *
  :param va_list vap: A set of variadic arguments
  :returns: If XOF_COLUMNS is set, the number of columns used; otherwise the number of bytes emitted
  :rtype: xo_ssize_t

.. index:: xo_attr
.. _xo_attr:

Attributes (xo_attr)
~~~~~~~~~~~~~~~~~~~~

The functions in this section emit an XML attribute with the given name
and value.  This only affects the XML output style.

The `name` parameter give the name of the attribute to be encoded.  The
`fmt` parameter gives a printf-style format string used to format the
value of the attribute using any remaining arguments, or the vap
parameter passed to `xo_attr_hv`.

All attributes recorded via `xo_attr` are placed on the next
container, instance, leaf, or leaf list that is emitted.

Since attributes are only emitted in XML, their use should be limited
to meta-data and additional or redundant representations of data
already emitted in other form.

.. c:function:: xo_ssize_t xo_attr (const char *name, const char *fmt, ...)

  :param name: Attribute name
  :type name: const char *
  :param fmt: Attribute value, as variadic arguments
  :type fmt: const char *
  :returns: -1 for error, or the number of bytes in the formatted attribute value
  :rtype: xo_ssize_t

  ::

    EXAMPLE:
        xo_attr("seconds", "%ld", (unsigned long) login_time);
        struct tm *tmp = localtime(login_time);
        strftime(buf, sizeof(buf), "%R", tmp);
        xo_emit("Logged in at {:login-time}\n", buf);
    XML:
        <login-time seconds="1408336270">00:14</login-time>


.. c:function:: xo_ssize_t xo_attr_h (xo_handle_t *xop, const char *name, const char *fmt, ...)

  :param xop: Handle for modify (or NULL for default handle)
  :type xop: xo_handle_t \*

  The `xo_attr_h` function follows the conventions of `xo_attr` but
  adds an explicit libxo handle.

.. c:function:: xo_ssize_t xo_attr_hv (xo_handle_t *xop, const char *name, const char *fmt, va_list vap)

  The `xo_attr_h` function follows the conventions of `xo_attr_h`
  but replaced the variadic list with a variadic pointer.

.. index:: xo_flush

Flushing Output (xo_flush)
~~~~~~~~~~~~~~~~~~~~~~~~~~

.. c:function:: xo_ssize_t xo_flush (void)

  :returns: -1 for error, or the number of bytes generated
  :rtype: xo_ssize_t

  libxo buffers data, both for performance and consistency, but also
  to allow for the proper function of various advanced features.  At
  various times, the caller may wish to flush any data buffered within
  the library.  The `xo_flush` call is used for this.

  Calling `xo_flush` also triggers the flush function associated with
  the handle.  For the default handle, this is equivalent to
  "fflush(stdio);".

.. c:function:: xo_ssize_t xo_flush_h (xo_handle_t *xop)

  :param xop: Handle for flush (or NULL for default handle)
  :type xop: xo_handle_t \*
  :returns: -1 for error, or the number of bytes generated
  :rtype: xo_ssize_t

  The `xo_flush_h` function follows the conventions of `xo_flush`,
  but adds an explicit libxo handle.

.. index:: xo_finish
.. index:: xo_finish_atexit
.. index:: atexit

Finishing Output (xo_finish)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

When the program is ready to exit or close a handle, a call to
`xo_finish` or `xo_finish_h` is required.  This flushes any buffered
data, closes open libxo constructs, and completes any pending
operations.

Calling this function is vital to the proper operation of libxo,
especially for the non-TEXT output styles.

.. c:function:: xo_ssize_t xo_finish (void)

  :returns: -1 on error, or the number of bytes flushed
  :rtype: xo_ssize_t

.. c:function:: xo_ssize_t xo_finish_h (xo_handle_t *xop)

  :param xop: Handle for finish (or NULL for default handle)
  :type xop: xo_handle_t \*
  :returns: -1 on error, or the number of bytes flushed
  :rtype: xo_ssize_t

.. c:function:: void xo_finish_atexit (void)

  The `xo_finish_atexit` function is suitable for use with
  :manpage:`atexit(3)` to ensure that `xo_finish` is called
  on the default handle when the application exits.

.. index:: UTF-8
.. index:: xo_open_container
.. index:: xo_close_container

Emitting Hierarchy
------------------

libxo represents two types of hierarchy: containers and lists.  A
container appears once under a given parent where a list consists of
instances that can appear multiple times.  A container is used to hold
related fields and to give the data organization and scope.

.. index:: YANG

.. admonition:: YANG Terminology

  libxo uses terminology from YANG (:RFC:`7950`), the data modeling
  language for NETCONF: container, list, leaf, and leaf-list.

For XML and JSON, individual fields appear inside hierarchies which
provide context and meaning to the fields.  Unfortunately, these
encoding have a basic disconnect between how lists is similar objects
are represented.

XML encodes lists as set of sequential elements::

    <user>phil</user>
    <user>pallavi</user>
    <user>sjg</user>

JSON encodes lists using a single name and square brackets::

    "user": [ "phil", "pallavi", "sjg" ]

This means libxo needs three distinct indications of hierarchy: one
for containers of hierarchy appear only once for any specific parent,
one for lists, and one for each item in a list.

.. index:: Containers

Containers
~~~~~~~~~~

A "*container*" is an element of a hierarchy that appears only once
under any specific parent.  The container has no value, but serves to
contain and organize other nodes.

To open a container, call xo_open_container() or
xo_open_container_h().  The former uses the default handle and the
latter accepts a specific handle.  To close a level, use the
xo_close_container() or xo_close_container_h() functions.

Each open call must have a matching close call.  If the XOF_WARN flag
is set and the name given does not match the name of the currently open
container, a warning will be generated.

.. c:function:: xo_ssize_t xo_open_container (const char *name)

  :param name: Name of the container
  :type name: const char *
  :returns: -1 on error, or the number of bytes generated
  :rtype: xo_ssize_t

  The `name` parameter gives the name of the container, encoded in
  UTF-8.  Since ASCII is a proper subset of UTF-8, traditional C
  strings can be used directly.

.. c:function:: xo_ssize_t xo_open_container_h (xo_handle_t *xop, const char *name)

  :param xop: Handle to use (or NULL for default handle)
  :type xop: xo_handle_t *

  The `xo_open_container_h` function adds a `handle` parameter.

.. c:function:: xo_ssize_t xo_close_container (const char *name)

  :param name: Name of the container
  :type name: const char *
  :returns: -1 on error, or the number of bytes generated
  :rtype: xo_ssize_t

.. c:function:: xo_ssize_t xo_close_container_h (xo_handle_t *xop, const char *name)

  :param xop: Handle to use (or NULL for default handle)
  :type xop: xo_handle_t *

  The `xo_close_container_h` function adds a `handle` parameter.

Use the :index:`XOF_WARN` flag to generate a warning if the name given
on the close does not match the current open container.

For TEXT and HTML output, containers are not rendered into output
text, though for HTML they are used to record an XPath value when the
:index:`XOF_XPATH` flag is set.

::

    EXAMPLE:
        xo_open_container("top");
        xo_open_container("system");
        xo_emit("{:host-name/%s%s%s}", hostname,
                domainname ? "." : "", domainname ?: "");
        xo_close_container("system");
        xo_close_container("top");
    TEXT:
        my-host.example.org
    XML:
        <top>
          <system>
              <host-name>my-host.example.org</host-name>
          </system>
        </top>
    JSON:
        "top" : {
          "system" : {
              "host-name": "my-host.example.org"
          }
        }
    HTML:
        <div class="data"
             data-tag="host-name">my-host.example.org</div>

.. index:: xo_open_instance
.. index:: xo_close_instance
.. index:: xo_open_list
.. index:: xo_close_list

Lists and Instances
~~~~~~~~~~~~~~~~~~~

A "*list*" is set of one or more instances that appear under the same
parent.  The instances contain details about a specific object.  One
can think of instances as objects or records.  A call is needed to
open and close the list, while a distinct call is needed to open and
close each instance of the list.

The name given to all calls must be identical, and it is strongly
suggested that the name be singular, not plural, as a matter of
style and usage expectations::

  EXAMPLE:
      xo_open_list("item");

      for (ip = list; ip->i_title; ip++) {
          xo_open_instance("item");
          xo_emit("{L:Item} '{:name/%s}':\n", ip->i_title);
          xo_close_instance("item");
      }

      xo_close_list("item");

Getting the list and instance calls correct is critical to the proper
generation of XML and JSON data.

Opening Lists
+++++++++++++

.. c:function:: xo_ssize_t xo_open_list (const char *name)

  :param name: Name of the list
  :type name: const char *
  :returns: -1 on error, or the number of bytes generated
  :rtype: xo_ssize_t
		
  The `xo_open_list` function open a list of instances.

.. c:function:: xo_ssize_t xo_open_list_h (xo_handle_t *xop, const char *name)

  :param xop: Handle to use (or NULL for default handle)
  :type xop: xo_handle_t *

Closing Lists
+++++++++++++

.. c:function:: xo_ssize_t xo_close_list (const char *name)

  :param name: Name of the list
  :type name: const char *
  :returns: -1 on error, or the number of bytes generated
  :rtype: xo_ssize_t
		
  The `xo_close_list` function closes a list of instances.

.. c:function:: xo_ssize_t xo_close_list_h (xo_handle_t *xop, const char *name)

  :param xop: Handle to use (or NULL for default handle)
  :type xop: xo_handle_t *

   The `xo_close_container_h` function adds a `handle` parameter.

Opening Instances
+++++++++++++++++

.. c:function:: xo_ssize_t xo_open_instance (const char *name)

  :param name: Name of the instance (same as the list name)
  :type name: const char *
  :returns: -1 on error, or the number of bytes generated
  :rtype: xo_ssize_t
		
  The `xo_open_instance` function open a single instance.

.. c:function:: xo_ssize_t xo_open_instance_h (xo_handle_t *xop, const char *name)

  :param xop: Handle to use (or NULL for default handle)
  :type xop: xo_handle_t *

   The `xo_open_instance_h` function adds a `handle` parameter.

Closing Instances
+++++++++++++++++

.. c:function:: xo_ssize_t xo_close_instance (const char *name)

  :param name: Name of the instance
  :type name: const char *
  :returns: -1 on error, or the number of bytes generated
  :rtype: xo_ssize_t

  The `xo_close_instance` function closes an open instance.

.. c:function:: xo_ssize_t xo_close_instance_h (xo_handle_t *xop, const char *name)

  :param xop: Handle to use (or NULL for default handle)
  :type xop: xo_handle_t *

  The `xo_close_instance_h` function adds a `handle` parameter.

  ::

    EXAMPLE:
        xo_open_list("user");
        for (i = 0; i < num_users; i++) {
            xo_open_instance("user");
            xo_emit("{k:name}:{:uid/%u}:{:gid/%u}:{:home}\n",
                    pw[i].pw_name, pw[i].pw_uid,
                    pw[i].pw_gid, pw[i].pw_dir);
            xo_close_instance("user");
        }
        xo_close_list("user");
    TEXT:
        phil:1001:1001:/home/phil
        pallavi:1002:1002:/home/pallavi
    XML:
        <user>
            <name>phil</name>
            <uid>1001</uid>
            <gid>1001</gid>
            <home>/home/phil</home>
        </user>
        <user>
            <name>pallavi</name>
            <uid>1002</uid>
            <gid>1002</gid>
            <home>/home/pallavi</home>
        </user>
    JSON:
        user: [
            {
                "name": "phil",
                "uid": 1001,
                "gid": 1001,
                "home": "/home/phil",
            },
            {
                "name": "pallavi",
                "uid": 1002,
                "gid": 1002,
                "home": "/home/pallavi",
            }
        ]

Markers
~~~~~~~

Markers are used to protect and restore the state of open hierarchy
constructs (containers, lists, or instances).  While a marker is open,
no other open constructs can be closed.  When a marker is closed, all
constructs open since the marker was opened will be closed.

Markers use names which are not user-visible, allowing the caller to
choose appropriate internal names.

In this example, the code whiffles through a list of fish, calling a
function to emit details about each fish.  The marker "fish-guts" is
used to ensure that any constructs opened by the function are closed
properly::

  EXAMPLE:
      for (i = 0; fish[i]; i++) {
          xo_open_instance("fish");
          xo_open_marker("fish-guts");
          dump_fish_details(i);
          xo_close_marker("fish-guts");
      }

.. c:function:: xo_ssize_t xo_open_marker(const char *name)

  :param name: Name of the instance
  :type name: const char *
  :returns: -1 on error, or the number of bytes generated
  :rtype: xo_ssize_t

  The `xo_open_marker` function records the current state of open tags
  in order for `xo_close_marker` to close them at some later point.

.. c:function:: xo_ssize_t xo_open_marker_h(const char *name)

  :param xop: Handle to use (or NULL for default handle)
  :type xop: xo_handle_t *

  The `xo_open_marker_h` function adds a `handle` parameter.

.. c:function:: xo_ssize_t xo_close_marker(const char *name)

  :param name: Name of the instance
  :type name: const char *
  :returns: -1 on error, or the number of bytes generated
  :rtype: xo_ssize_t

  The `xo_close_marker` function closes any open containers, lists, or
  instances as needed to return to the state recorded when
  `xo_open_marker` was called with the matching name.

.. c:function:: xo_ssize_t xo_close_marker(const char *name)

  :param xop: Handle to use (or NULL for default handle)
  :type xop: xo_handle_t *

  The `xo_close_marker_h` function adds a `handle` parameter.

DTRT Mode
~~~~~~~~~

Some users may find tracking the names of open containers, lists, and
instances inconvenient.  libxo offers a "Do The Right Thing" mode, where
libxo will track the names of open containers, lists, and instances so
the close function can be called without a name.  To enable DTRT mode,
turn on the XOF_DTRT flag prior to making any other libxo output::

    xo_set_flags(NULL, XOF_DTRT);

.. index:: XOF_DTRT

Each open and close function has a version with the suffix "_d", which
will close the open container, list, or instance::

    xo_open_container_d("top");
    ...
    xo_close_container_d();

This also works for lists and instances::

    xo_open_list_d("item");
    for (...) {
        xo_open_instance_d("item");
        xo_emit(...);
        xo_close_instance_d();
    }
    xo_close_list_d();

.. index:: XOF_WARN

Note that the XOF_WARN flag will also cause libxo to track open
containers, lists, and instances.  A warning is generated when the
name given to the close function and the name recorded do not match.

Support Functions
-----------------

.. index:: xo_parse_args
.. _xo_parse_args:

Parsing Command-line Arguments (xo_parse_args)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. c:function:: int xo_parse_args (int argc, char **argv)

  :param int argc: Number of arguments
  :param argv: Array of argument strings
  :return: -1 on error, or the number of remaining arguments
  :rtype: int

  The `xo_parse_args` function is used to process a program's
  arguments.  libxo-specific options are processed and removed from
  the argument list so the calling application does not need to
  process them.  If successful, a new value for argc is returned.  On
  failure, a message is emitted and -1 is returned::

    argc = xo_parse_args(argc, argv);
    if (argc < 0)
        exit(EXIT_FAILURE);

  Following the call to xo_parse_args, the application can process the
  remaining arguments in a normal manner.  See :ref:`options` for a
  description of valid arguments.

.. index:: xo_set_program

xo_set_program
~~~~~~~~~~~~~~

.. c:function:: void xo_set_program (const char *name)

  :param name: Name to use as the program name
  :type name: const char *
  :returns: void

  The `xo_set_program` function sets the name of the program as
  reported by functions like `xo_failure`, `xo_warn`, `xo_err`, etc.
  The program name is initialized by `xo_parse_args`, but subsequent
  calls to `xo_set_program` can override this value::

    EXAMPLE:
        xo_set_program(argv[0]);

  Note that the value is not copied, so the memory passed to
  `xo_set_program` (and `xo_parse_args`) must be maintained by the
  caller.

.. index:: xo_set_version

xo_set_version
~~~~~~~~~~~~~~

.. c:function:: void xo_set_version (const char *version)

  :param name: Value to use as the version string
  :type name: const char *
  :returns: void

  The `xo_set_version` function records a version number to be emitted
  as part of the data for encoding styles (XML and JSON).  This
  version number is suitable for tracking changes in the content,
  allowing a user of the data to discern which version of the data
  model is in use.

.. c:function:: void xo_set_version_h (xo_handle_t *xop, const char *version)

  :param xop: Handle to use (or NULL for default handle)
  :type xop: xo_handle_t *

  The `xo_set_version` function adds a `handle` parameter.

.. index:: --libxo
.. index:: XOF_INFO
.. index:: xo_info_t

.. _field-information:

Field Information (xo_info_t)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

HTML data can include additional information in attributes that
begin with "data-".  To enable this, three things must occur:

First the application must build an array of xo_info_t structures,
one per tag.  The array must be sorted by name, since libxo uses a
binary search to find the entry that matches names from format
instructions.

Second, the application must inform libxo about this information using
the `xo_set_info` call::

    typedef struct xo_info_s {
        const char *xi_name;    /* Name of the element */
        const char *xi_type;    /* Type of field */
        const char *xi_help;    /* Description of field */
    } xo_info_t;

    void xo_set_info (xo_handle_t *xop, xo_info_t *infop, int count);

Like other libxo calls, passing `NULL` for the handle tells libxo to
use the default handle.

If the count is -1, libxo will count the elements of infop, but there
must be an empty element at the end.  More typically, the number is
known to the application::

    xo_info_t info[] = {
        { "in-stock", "number", "Number of items in stock" },
        { "name", "string", "Name of the item" },
        { "on-order", "number", "Number of items on order" },
        { "sku", "string", "Stock Keeping Unit" },
        { "sold", "number", "Number of items sold" },
    };
    int info_count = (sizeof(info) / sizeof(info[0]));
    ...
    xo_set_info(NULL, info, info_count);

Third, the emission of info must be triggered with the `XOF_INFO` flag
using either the `xo_set_flags` function or the "`--libxo=info`"
command line argument.

The type and help values, if present, are emitted as the "data-type"
and "data-help" attributes::

  <div class="data" data-tag="sku" data-type="string"
       data-help="Stock Keeping Unit">GRO-000-533</div>

.. c:function:: void xo_set_info (xo_handle_t *xop, xo_info_t *infop, int count)

  :param xop: Handle to use (or NULL for default handle)
  :type xop: xo_handle_t *
  :param infop: Array of information structures
  :type infop: xo_info_t *
  :returns: void

.. index:: xo_set_allocator
.. index:: xo_realloc_func_t
.. index:: xo_free_func_t

Memory Allocation
~~~~~~~~~~~~~~~~~

The `xo_set_allocator` function allows libxo to be used in
environments where the standard :manpage:`realloc(3)` and
:manpage:`free(3)` functions are not appropriate.

.. c:function:: void xo_set_allocator (xo_realloc_func_t realloc_func, xo_free_func_t free_func)

  :param xo_realloc_func_t realloc_func:  Allocation function
  :param xo_free_func_t free_func: Free function

  *realloc_func* should expect the same arguments as
  :manpage:`realloc(3)` and return a pointer to memory following the
  same convention.  *free_func* will receive the same argument as
  :manpage:`free(3)` and should release it, as appropriate for the
  environment.

By default, the standard :manpage:`realloc(3)` and :manpage:`free(3)`
functions are used.

.. index:: --libxo

.. _libxo-options:

LIBXO_OPTIONS
~~~~~~~~~~~~~

The environment variable "LIBXO_OPTIONS" can be set to a subset of
libxo options, including:

- color
- flush
- flush-line
- no-color
- no-humanize
- no-locale
- no-retain
- pretty
- retain
- underscores
- warn

For example, warnings can be enabled by::

    % env LIBXO_OPTIONS=warn my-app

Since environment variables are inherited, child processes will have
the same options, which may be undesirable, making the use of the
"`--libxo`" command-line option preferable in most situations.

.. index:: xo_warn
.. index:: xo_err
.. index:: xo_errx
.. index:: xo_message

Errors, Warnings, and Messages
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Many programs make use of the standard library functions
:manpage:`err(3)` and :manpage:`warn(3)` to generate errors and
warnings for the user.  libxo wants to pass that information via the
current output style, and provides compatible functions to allow
this::

    void xo_warn (const char *fmt, ...);
    void xo_warnx (const char *fmt, ...);
    void xo_warn_c (int code, const char *fmt, ...);
    void xo_warn_hc (xo_handle_t *xop, int code,
                     const char *fmt, ...);
    void xo_err (int eval, const char *fmt, ...);
    void xo_errc (int eval, int code, const char *fmt, ...);
    void xo_errx (int eval, const char *fmt, ...);

::

    void xo_message (const char *fmt, ...);
    void xo_message_c (int code, const char *fmt, ...);
    void xo_message_hc (xo_handle_t *xop, int code,
                        const char *fmt, ...);
    void xo_message_hcv (xo_handle_t *xop, int code,
                         const char *fmt, va_list vap);

These functions display the program name, a colon, a formatted message
based on the arguments, and then optionally a colon and an error
message associated with either *errno* or the *code* parameter::

    EXAMPLE:
        if (open(filename, O_RDONLY) < 0)
            xo_err(1, "cannot open file '%s'", filename);

.. index:: xo_error
.. index:: xo_error_h
.. index:: xo_error_hv
.. index:: xo_errorn
.. index:: xo_errorn_h
.. index:: xo_errorn_hv

xo_error
~~~~~~~~

.. c:function:: void xo_error (const char *fmt, ...)

  :param fmt: Format string
  :type fmt: const char *
  :returns: void

.. c:function:: void xo_error_h (xo_handle_t *xop, const char *fmt, ...)

  :param xop: libxo handle pointer
  :type xop: xo_handle_t *
  :param fmt: Format string
  :type fmt: const char *
  :returns: void

.. c:function:: void xo_error_hv (xo_handle_t *xop, const char *fmt, va_list vap)

  :param xop: libxo handle pointer
  :type xop: xo_handle_t *
  :param fmt: Format string
  :type fmt: const char *
  :param vap: variadic arguments
  :type xop: va_list
  :returns: void

.. c:function:: void xo_errorn (const char *fmt, ...)

  :param fmt: Format string
  :type fmt: const char *
  :returns: void

.. c:function:: void xo_errorn_h (xo_handle_t *xop, const char *fmt, ...)

  :param xop: libxo handle pointer
  :type xop: xo_handle_t *
  :param fmt: Format string
  :type fmt: const char *
  :returns: void

.. c:function:: void xo_errorn_hv (xo_handle_t *xop, int need_newline, const char *fmt, va_list vap)

  :param xop: libxo handle pointer
  :type xop: xo_handle_t *
  :param need_newline: boolean indicating need for trailing newline
  :type need_newline: int
  :param fmt: Format string
  :type fmt: const char *
  :param vap: variadic arguments
  :type xop: va_list
  :returns: void

  The `xo_error` function can be used for generic errors that should
  be reported over the handle, rather than to stderr.  The `xo_error`
  function behaves like `xo_err` for TEXT and HTML output styles, but
  puts the error into XML or JSON elements::

    EXAMPLE::
        xo_error("Does not %s", "compute");
    XML::
        <error><message>Does not compute</message></error>
    JSON::
        "error": { "message": "Does not compute" }

  The `xo_error_h` and `xo_error_hv` add a handle object and a
  variadic-ized parameter to the signature, respectively.

  The `xo_errorn` function supplies a newline at the end the error
  message if the format string does not include one.  The
  `xo_errorn_h` and `xo_errorn_hv` functions add a handle object and
  a variadic-ized parameter to the signature, respectively.  The
  `xo_errorn_hv` function also adds a boolean to indicate the need for
  a trailing newline.

.. index:: xo_no_setlocale
.. index:: Locale

xo_no_setlocale
~~~~~~~~~~~~~~~

.. c:function:: void xo_no_setlocale (void)

  libxo automatically initializes the locale based on setting of the
  environment variables LC_CTYPE, LANG, and LC_ALL.  The first of this
  list of variables is used and if none of the variables, the locale
  defaults to "UTF-8".  The caller may wish to avoid this behavior,
  and can do so by calling the `xo_no_setlocale` function.

Emitting syslog Messages
------------------------

syslog is the system logging facility used throughout the unix world.
Messages are sent from commands, applications, and daemons to a
hierarchy of servers, where they are filtered, saved, and forwarded
based on configuration behaviors.

syslog is an older protocol, originally documented only in source
code.  By the time :RFC:`3164` published, variation and mutation left the
leading "<pri>" string as only common content.  :RFC:`5424` defines a new
version (version 1) of syslog and introduces structured data into the
messages.  Structured data is a set of name/value pairs transmitted
distinctly alongside the traditional text message, allowing filtering
on precise values instead of regular expressions.

These name/value pairs are scoped by a two-part identifier; an
enterprise identifier names the party responsible for the message
catalog and a name identifying that message.  `Enterprise IDs`_ are
defined by IANA, the Internet Assigned Numbers Authority.

.. _Enterprise IDs:
    https://www.iana.org/assignments/enterprise-numbers/enterprise-numbers

Use the `xo_set_syslog_enterprise_id` function to set the Enterprise
ID, as needed.

The message name should follow the conventions in
:ref:`good-field-names`\ , as should the fields within the message::

    /* Both of these calls are optional */
    xo_set_syslog_enterprise_id(32473);
    xo_open_log("my-program", 0, LOG_DAEMON);

    /* Generate a syslog message */
    xo_syslog(LOG_ERR, "upload-failed",
              "error <%d> uploading file '{:filename}' "
              "as '{:target/%s:%s}'",
              code, filename, protocol, remote);

    xo_syslog(LOG_INFO, "poofd-invalid-state",
              "state {:current/%u} is invalid {:connection/%u}",
	      state, conn);

The developer should be aware that the message name may be used in the
future to allow access to further information, including
documentation.  Care should be taken to choose quality, descriptive
names.

.. _syslog-details:

Priority, Facility, and Flags
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The `xo_syslog`, `xo_vsyslog`, and `xo_open_log` functions
accept a set of flags which provide the priority of the message, the
source facility, and some additional features.  These values are OR'd
together to create a single integer argument::

    xo_syslog(LOG_ERR | LOG_AUTH, "login-failed",
             "Login failed; user '{:user}' from host '{:address}'",
             user, addr);

These values are defined in <syslog.h>.

The priority value indicates the importance and potential impact of
each message:

  ============= =======================================================
   Priority      Description
  ============= =======================================================
   LOG_EMERG     A panic condition, normally broadcast to all users
   LOG_ALERT     A condition that should be corrected immediately
   LOG_CRIT      Critical conditions
   LOG_ERR       Generic errors
   LOG_WARNING   Warning messages
   LOG_NOTICE    Non-error conditions that might need special handling
   LOG_INFO      Informational messages
   LOG_DEBUG     Developer-oriented messages
  ============= =======================================================

The facility value indicates the source of message, in fairly generic
terms:

  =============== =======================================================
   Facility        Description
  =============== =======================================================
   LOG_AUTH        The authorization system (e.g. :manpage:`login(1)`)
   LOG_AUTHPRIV    As LOG_AUTH, but logged to a privileged file
   LOG_CRON        The cron daemon: :manpage:`cron(8)`
   LOG_DAEMON      System daemons, not otherwise explicitly listed
   LOG_FTP         The file transfer protocol daemons
   LOG_KERN        Messages generated by the kernel
   LOG_LPR         The line printer spooling system
   LOG_MAIL        The mail system
   LOG_NEWS        The network news system
   LOG_SECURITY    Security subsystems, such as :manpage:`ipfw(4)`
   LOG_SYSLOG      Messages generated internally by :manpage:`syslogd(8)`
   LOG_USER        Messages generated by user processes (default)
   LOG_UUCP        The uucp system
   LOG_LOCAL0..7   Reserved for local use
  =============== =======================================================

In addition to the values listed above, xo_open_log accepts a set of
addition flags requesting specific logging behaviors:

  ============ ====================================================
   Flag         Description
  ============ ====================================================
   LOG_CONS     If syslogd fails, attempt to write to /dev/console
   LOG_NDELAY   Open the connection to :manpage:`syslogd(8)` immediately
   LOG_PERROR   Write the message also to standard error output
   LOG_PID      Log the process id with each message
  ============ ====================================================

.. index:: xo_syslog

xo_syslog
~~~~~~~~~

.. c:function:: void xo_syslog (int pri, const char *name, const char *fmt, ...)

  :param int pri: syslog priority
  :param name: Name of the syslog event
  :type name: const char *
  :param fmt: Format string, followed by arguments
  :type fmt: const char *
  :returns: void

  Use the `xo_syslog` function to generate syslog messages by calling
  it with a log priority and facility, a message name, a format
  string, and a set of arguments.  The priority/facility argument are
  discussed above, as is the message name.

  The format string follows the same conventions as `xo_emit`'s format
  string, with each field being rendered as an SD-PARAM pair::

    xo_syslog(LOG_ERR, "poofd-missing-file",
              "'{:filename}' not found: {:error/%m}", filename);

    ... [poofd-missing-file@32473 filename="/etc/poofd.conf"
          error="Permission denied"] '/etc/poofd.conf' not
          found: Permission denied

Support functions
~~~~~~~~~~~~~~~~~

.. index:: xo_vsyslog

xo_vsyslog
++++++++++

.. c:function:: void xo_vsyslog (int pri, const char *name, const char *fmt, va_list vap)

  :param int pri: syslog priority
  :param name: Name of the syslog event
  :type name: const char *
  :param fmt: Format string
  :type fmt: const char *
  :param va_list vap: Variadic argument list
  :returns: void

  xo_vsyslog is identical in function to xo_syslog, but takes the set of
  arguments using a va_list::

    EXAMPLE:
        void
        my_log (const char *name, const char *fmt, ...)
        {
            va_list vap;
            va_start(vap, fmt);
            xo_vsyslog(LOG_ERR, name, fmt, vap);
            va_end(vap);
        }

.. index:: xo_open_log

xo_open_log
+++++++++++

.. c:function:: void xo_open_log (const char *ident, int logopt, int facility)

  :param indent:
  :type indent: const char *
  :param int logopt: Bit field containing logging options
  :param int facility:
  :returns: void

  xo_open_log functions similar to :manpage:`openlog(3)`, allowing
  customization of the program name, the log facility number, and the
  additional option flags described in :ref:`syslog-details`.

.. index:: xo_close_log

xo_close_log
++++++++++++

.. c:function:: void xo_close_log (void)

  The `xo_close_log` function is similar to :manpage:`closelog(3)`,
  closing the log file and releasing any associated resources.

.. index:: xo_set_logmask

xo_set_logmask
++++++++++++++

.. c:function:: int xo_set_logmask (int maskpri)

  :param int maskpri: the log priority mask
  :returns: The previous log priority mask

  The `xo_set_logmask` function is similar to :manpage:`setlogmask(3)`,
  restricting the set of generated log event to those whose associated
  bit is set in maskpri.  Use `LOG_MASK(pri)` to find the appropriate bit,
  or `LOG_UPTO(toppri)` to create a mask for all priorities up to and
  including toppri::

    EXAMPLE:
        setlogmask(LOG_UPTO(LOG_WARN));

.. index:: xo_set_syslog_enterprise_id

xo_set_syslog_enterprise_id
+++++++++++++++++++++++++++

.. c:function:: void xo_set_syslog_enterprise_id (unsigned short eid)

  Use the `xo_set_syslog_enterprise_id` to supply a platform- or
  application-specific enterprise id.  This value is used in any future
  syslog messages.

  Ideally, the operating system should supply a default value via the
  "kern.syslog.enterprise_id" sysctl value.  Lacking that, the
  application should provide a suitable value.

Enterprise IDs are administered by IANA, the Internet Assigned Number
Authority.  The complete list is EIDs on their web site::

    https://www.iana.org/assignments/enterprise-numbers/enterprise-numbers

New EIDs can be requested from IANA using the following page::

    http://pen.iana.org/pen/PenApplication.page

Each software development organization that defines a set of syslog
messages should register their own EID and use that value in their
software to ensure that messages can be uniquely identified by the
combination of EID + message name.

Creating Custom Encoders
------------------------

The number of encoding schemes in current use is staggering, with new
and distinct schemes appearing daily.  While libxo provide XML, JSON,
HMTL, and text natively, there are requirements for other encodings.

Rather than bake support for all possible encoders into libxo, the API
allows them to be defined externally.  libxo can then interfaces with
these encoding modules using a simplistic API.  libxo processes all
functions calls, handles state transitions, performs all formatting,
and then passes the results as operations to a customized encoding
function, which implements specific encoding logic as required.  This
means your encoder doesn't need to detect errors with unbalanced
open/close operations but can rely on libxo to pass correct data.

By making a simple API, libxo internals are not exposed, insulating the
encoder and the library from future or internal changes.

The three elements of the API are:

- loading
- initialization
- operations

The following sections provide details about these topics.

.. index:: CBOR

libxo source contains an encoder for Concise Binary Object
Representation, aka CBOR (:RFC:`7049`), which can be used as an
example for the API for other encoders.

Loading Encoders
~~~~~~~~~~~~~~~~

Encoders can be registered statically or discovered dynamically.
Applications can choose to call the `xo_encoder_register` function
to explicitly register encoders, but more typically they are built as
shared libraries, placed in the libxo/extensions directory, and loaded
based on name.  libxo looks for a file with the name of the encoder
and an extension of ".enc".  This can be a file or a symlink to the
shared library file that supports the encoder::

    % ls -1 lib/libxo/extensions/*.enc
    lib/libxo/extensions/cbor.enc
    lib/libxo/extensions/test.enc

Encoder Initialization
~~~~~~~~~~~~~~~~~~~~~~

Each encoder must export a symbol used to access the library, which
must have the following signature::

    int xo_encoder_library_init (XO_ENCODER_INIT_ARGS);

`XO_ENCODER_INIT_ARGS` is a macro defined in "xo_encoder.h" that defines
an argument called "arg", a pointer of the type
`xo_encoder_init_args_t`.  This structure contains two fields:

- `xei_version` is the version number of the API as implemented
  within libxo.  This version is currently as 1 using
  `XO_ENCODER_VERSION`.  This number can be checked to ensure
  compatibility.  The working assumption is that all versions should
  be backward compatible, but each side may need to accurately know
  the version supported by the other side.  `xo_encoder_library_init`
  can optionally check this value, and must then set it to the version
  number used by the encoder, allowing libxo to detect version
  differences and react accordingly.  For example, if version 2 adds
  new operations, then libxo will know that an encoding library that
  set `xei_version` to 1 cannot be expected to handle those new
  operations.

- xei_handler must be set to a pointer to a function of type
  `xo_encoder_func_t`, as defined in "xo_encoder.h".  This function
  takes a set of parameters:
  - xop is a pointer to the opaque `xo_handle_t` structure
  - op is an integer representing the current operation
  - name is a string whose meaning differs by operation
  - value is a string whose meaning differs by operation
  - private is an opaque structure provided by the encoder

Additional arguments may be added in the future, so handler functions
should use the `XO_ENCODER_HANDLER_ARGS` macro.  An appropriate
"extern" declaration is provided to help catch errors.

Once the encoder initialization function has completed processing, it
should return zero to indicate that no error has occurred.  A non-zero
return code will cause the handle initialization to fail.

Operations
~~~~~~~~~~

The encoder API defines a set of operations representing the
processing model of libxo.  Content is formatted within libxo, and
callbacks are made to the encoder's handler function when data is
ready to be processed:

  ======================= =======================================
   Operation               Meaning  (Base function)
  ======================= =======================================
   XO_OP_CREATE            Called when the handle is created
   XO_OP_OPEN_CONTAINER    Container opened (xo_open_container)
   XO_OP_CLOSE_CONTAINER   Container closed (xo_close_container)
   XO_OP_OPEN_LIST         List opened (xo_open_list)
   XO_OP_CLOSE_LIST        List closed (xo_close_list)
   XO_OP_OPEN_LEAF_LIST    Leaf list opened (xo_open_leaf_list)
   XO_OP_CLOSE_LEAF_LIST   Leaf list closed (xo_close_leaf_list)
   XO_OP_OPEN_INSTANCE     Instance opened (xo_open_instance)
   XO_OP_CLOSE_INSTANCE    Instance closed (xo_close_instance)
   XO_OP_STRING            Field with Quoted UTF-8 string
   XO_OP_CONTENT           Field with content
   XO_OP_FINISH            Finish any pending output
   XO_OP_FLUSH             Flush any buffered output
   XO_OP_DESTROY           Clean up resources
   XO_OP_ATTRIBUTE         An attribute name/value pair
   XO_OP_VERSION           A version string
  ======================= =======================================

For all the open and close operations, the name parameter holds the
name of the construct.  For string, content, and attribute operations,
the name parameter is the name of the field and the value parameter is
the value.  "string" are differentiated from "content" to allow differing
treatment of true, false, null, and numbers from real strings, though
content values are formatted as strings before the handler is called.
For version operations, the value parameter contains the version.

All strings are encoded in UTF-8.
