11f8ca01b7
from 1.0.0: Add "continuation" flag, to allow multiple "xo" invocations in a single line of output (#58) Add --top-wrap to make top-level JSON wrappers Add --{open,close}-{list,instace} options Add xo_xml_leader(), to detect use of some bogus XML tags. It's still bad form, but it's a little safer now Avoid call to xo_write before xo_flush, since the latter calls the former Check return code from xo_flush_h properly (<0) (FreeBSD Bug 236935) For JSON output, avoid newline before a container's close brace (#62) Merge branch 'text_only' of https://github.com/zvr/libxo into zvr-text_only Use XO_USE_INT_RETURN_CODES, not USE_INT_RETURN_CODES add docs for --continuation add docs for --not-first call xo_state_set_flags before values and close containers; add XOIF_MADE_OUTPUT flag to track state; make proper empty JSON objects in xo_finish color_map code has to be #ifdef'd out, since the struct definition correct xo_flush_func_t (doesn't use xo_ssize_t) make depth change for --top-wrap only for JSON fix to handle --top-wrap in "xo" by being more consistent with handling trailing newlines fix to handle text-only version #64 (from zvr) fix xo_buf_has_room for round up to the next XO_BUFSIZ, not just add XO_BUFSIZ to the size (FreeBSD Bug 236937) update docs for new "xo" options update functions to use xo_ssize_t update test cases from 1.0.1: Add EINTEGRITY to .pot files under test/gettext/ (fix from FreeBSD) from 1.0.2: handle failure from xo_vnsprintf; don't add -1 to "rc" PR: 236937, 236935 Submitted by: phil Reported by: Alfonso S. Siciliano <alfix86@gmail.com> MFC after: 2 weeks
1621 lines
53 KiB
ReStructuredText
1621 lines
53 KiB
ReStructuredText
.. 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.
|
|
|
|
The "fmt" argument is a 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 cast 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 can also make output, but only make a
|
|
single field at a time. These functions are intended to avoid the
|
|
scenario where one would otherwise need to compose a format
|
|
descriptors using `snprintf`. The individual parts of the format
|
|
descriptor are passed in distinctly.
|
|
|
|
.. c:function:: xo_ssize_t xo_emit_field (const char *rolmod, const char *contents, const char *fmt, const char *efmt, ...)
|
|
|
|
: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
|
|
|
|
::
|
|
|
|
EXAMPLE::
|
|
xo_emit_field("T", "Host name is ", NULL, NULL);
|
|
xo_emit_field("V", "host-name", NULL, NULL, host-name);
|
|
|
|
.. 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
|
|
|
|
xo_error
|
|
~~~~~~~~
|
|
|
|
.. c:function:: void xo_error (const char *fmt, ...)
|
|
|
|
:param fmt: Format string
|
|
:type fmt: const char *
|
|
: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" }
|
|
|
|
.. 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.
|