diff options
Diffstat (limited to 'doc/api.rst')
-rw-r--r-- | doc/api.rst | 1702 |
1 files changed, 1702 insertions, 0 deletions
diff --git a/doc/api.rst b/doc/api.rst new file mode 100644 index 000000000000..8a9b7bb5cefe --- /dev/null +++ b/doc/api.rst @@ -0,0 +1,1702 @@ +.. 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. |