:orphan: .. index:: pair: group; Compound strings .. _doxid-group__te__tools__te__compound: Compound strings ================ .. toctree:: :hidden: enum_te_compound_kind.rst enum_te_compound_mod_op.rst Overview ~~~~~~~~ Compound strings are an extension to ordinary TE dynamic strings that can hold one-dimensional arrays of string and key-value pairs. :ref:`More...` .. ref-code-block:: cpp :class: doxyrest-overview-code-block // typedefs typedef enum :ref:`te_compound_kind` :ref:`te_compound_kind`; typedef enum :ref:`te_compound_mod_op` :ref:`te_compound_mod_op`; typedef :ref:`te_errno` :ref:`te_compound_iter_fn`( char *key, size_t idx, char *value, bool has_more, void *user ); // enums enum :ref:`te_compound_kind`; enum :ref:`te_compound_mod_op`; // global functions :ref:`te_compound_kind` :ref:`te_compound_classify`(const :ref:`te_string`* comp); bool :ref:`te_compound_validate`(const :ref:`te_string`* comp); bool :ref:`te_compound_validate_str`(const char* comp); bool :ref:`te_compound_extract`(:ref:`te_string`* dst, const :ref:`te_string`* comp, const char* key, size_t idx); size_t :ref:`te_compound_count`(const :ref:`te_string`* comp, const char* key); void :ref:`te_compound_set_va`(:ref:`te_string`* comp, const char* key, :ref:`te_compound_mod_op` mod_op, const char* val_fmt, va_list args); void :ref:`te_compound_set`(:ref:`te_string`* comp, const char* key, :ref:`te_compound_mod_op` mod_op, const char* val_fmt, ...); static void static void :ref:`te_compound_append_fast`(:ref:`te_string`* comp, const char* key, const char* value); void :ref:`te_compound_merge`(:ref:`te_string`* dst, const :ref:`te_string`* src, :ref:`te_compound_mod_op` mod_op); :ref:`te_errno` :ref:`te_compound_iterate`(const :ref:`te_string`* src, :ref:`te_compound_iter_fn`* callback, void* user); :ref:`te_errno` :ref:`te_compound_iterate_str`(const char* src, :ref:`te_compound_iter_fn`* callback, void* user); void :ref:`te_vec2compound`(:ref:`te_string`* dst, const :ref:`te_vec`* vec); void :ref:`te_kvpair2compound`(:ref:`te_string`* dst, const te_kvpair_h* kv); void :ref:`te_compound2vec`(:ref:`te_vec`* dst, const :ref:`te_string`* compound); void :ref:`te_compound2kvpair`(te_kvpair_h* dst, const :ref:`te_string`* compound); void :ref:`te_json_add_compound`(:ref:`te_json_ctx_t`* ctx, const :ref:`te_string`* compound); void :ref:`te_kvpair_set_compound_va`(te_kvpair_h* dst, const char* outer_key, const char* inner_key, :ref:`te_compound_mod_op` mod_op, const char* val_fmt, va_list args); void :ref:`te_kvpair_set_compound`(te_kvpair_h* dst, const char* outer_key, const char* inner_key, :ref:`te_compound_mod_op` mod_op, const char* val_fmt, ...); void void :ref:`te_compound_build_name`(:ref:`te_string`* dst, const char* stem, const char* key, size_t idx); :ref:`te_errno` :ref:`te_compound_dereference`(const :ref:`te_string`* compound, const char* stem, const char* key, :ref:`te_compound_iter_fn`* callback, void* user); :ref:`te_errno` :ref:`te_compound_dereference_str`(const char* compound, const char* stem, const char* key, :ref:`te_compound_iter_fn`* callback, void* user); .. _details-group__te__tools__te__compound: Detailed Documentation ~~~~~~~~~~~~~~~~~~~~~~ Compound strings are an extension to ordinary TE dynamic strings that can hold one-dimensional arrays of string and key-value pairs. They employ special characters, normally not found in regular strings to separate items from each other and keys from values. So they cannot be used to store arbitrary binary data, but instead they are fully compatible with regular TE strings and C strings (i.e. no embedded zeroes). The main usecase for compound strings is to extend existing APIs that were designed to handle simple strings only so that they could pass around structured values without losing backward compatibility. Key-value pairs are stored sorted in compound strings, so that two equivalent key-value sets would compare equal. This makes compound strings slightly more efficient on read that plain key-value pairs API. Typedefs -------- .. index:: pair: typedef; te_compound_kind .. _doxid-group__te__tools__te__compound_1ga651c6e0ef9ba9660a2343b860e03d917: .. ref-code-block:: cpp :class: doxyrest-title-code-block typedef enum :ref:`te_compound_kind` te_compound_kind The kind of a compound string. This is mostly important for JSON serialization. .. index:: pair: typedef; te_compound_mod_op .. _doxid-group__te__tools__te__compound_1ga78bd341fa315e94d25ab37183d3c8b0a: .. ref-code-block:: cpp :class: doxyrest-title-code-block typedef enum :ref:`te_compound_mod_op` te_compound_mod_op The mode of operation for duplicate keys. .. index:: pair: typedef; te_compound_iter_fn .. _doxid-group__te__tools__te__compound_1ga992e2b5fdf82135b11f9c4630aeefe8a: .. ref-code-block:: cpp :class: doxyrest-title-code-block typedef :ref:`te_errno` te_compound_iter_fn( char *key, size_t idx, char *value, bool has_more, void *user ) Function type of callbacks for :ref:`te_compound_iterate() `. The callback may freely modify the contents of ``key`` and ``value``, but it must never try to free it or to store pointers to them across the calls, i.e. they should be treated as local arrays. .. rubric:: Parameters: .. list-table:: :widths: 20 80 * - key - Current key (may be ``NULL``). * - idx - Index of the current value with a given key. * - value - Current value (never ``NULL``). * - has_more - ``true`` if there are more items to process (not necessary with the same key), * - user - Callback user data. * - TE_EOK - :ref:`te_compound_iterate() ` will stop immediately and return success to the caller. .. rubric:: Returns: Status code. Global Functions ---------------- .. index:: pair: function; te_compound_classify .. _doxid-group__te__tools__te__compound_1gaa68baf9251974503dea0f508a36fa8eb: .. ref-code-block:: cpp :class: doxyrest-title-code-block :ref:`te_compound_kind` te_compound_classify(const :ref:`te_string`* comp) Determine the kind of a compound string. .. rubric:: Parameters: .. list-table:: :widths: 20 80 * - comp - Compound string. .. rubric:: Returns: The kind of the string. .. index:: pair: function; te_compound_validate .. _doxid-group__te__tools__te__compound_1ga1cb25f60ec49d11f7b9328badc1ef371: .. ref-code-block:: cpp :class: doxyrest-title-code-block bool te_compound_validate(const :ref:`te_string`* comp) Validate the compound string. Errors will be logged by this function. .. rubric:: Parameters: .. list-table:: :widths: 20 80 * - comp - Compound string. .. rubric:: Returns: ``true`` if the compound string is well-formed. .. index:: pair: function; te_compound_validate_str .. _doxid-group__te__tools__te__compound_1ga899584d5044e37293df03405fdbd37e4: .. ref-code-block:: cpp :class: doxyrest-title-code-block bool te_compound_validate_str(const char* comp) Like :ref:`te_compound_validate() `, but accepts a plain C string as an input. The reason for this function existence is to avoid creating an intermediate :ref:`te_string ` if a compound string was obtained from some external source (e.g. read from a file). .. rubric:: Parameters: .. list-table:: :widths: 20 80 * - comp - Compound string representation. .. rubric:: Returns: ``true`` if ``comp`` represents a valid compound string. .. index:: pair: function; te_compound_extract .. _doxid-group__te__tools__te__compound_1ga38192eaf2b1560404a30bc0a42e9b164: .. ref-code-block:: cpp :class: doxyrest-title-code-block bool te_compound_extract(:ref:`te_string`* dst, const :ref:`te_string`* comp, const char* key, size_t idx) Extract a value associated with a given key in the compound. If ``key`` is ``NULL``, an ``idx'th`` unnamed item is extracted. A compound that has no structure is treated as single-item array. If there is no value associated with a given key or if there is less values than ``idx``, nothing is extracted and the function just returns ``false``. .. rubric:: Parameters: .. list-table:: :widths: 20 80 * - dst - String which is appended the extracted value. * - comp - Compound string. * - key - Key of a value (may be ``NULL``) * - idx - Index of a value among equal keys. .. rubric:: Returns: ``true`` if a value has been extracted. .. index:: pair: function; te_compound_count .. _doxid-group__te__tools__te__compound_1gaaa0235d0eeb5506930c18b4fbc7b0ff5: .. ref-code-block:: cpp :class: doxyrest-title-code-block size_t te_compound_count(const :ref:`te_string`* comp, const char* key) Count the number of values associated with a given key or the number of unnamed items if ``key`` is ``NULL``. .. rubric:: Parameters: .. list-table:: :widths: 20 80 * - comp - Compound string. * - key - Key (may be ``NULL``). .. rubric:: Returns: The number of values associated with ``key``. .. index:: pair: function; te_compound_set_va .. _doxid-group__te__tools__te__compound_1gafb6977e49f9cdcf63226504c04821c9d: .. ref-code-block:: cpp :class: doxyrest-title-code-block void te_compound_set_va(:ref:`te_string`* comp, const char* key, :ref:`te_compound_mod_op` mod_op, const char* val_fmt, va_list args) Set or unset a value inside a compound associated with a given key. The behaviour of this function when there is already a value associated with the given key depends on ``mod_op:`` * :ref:`TE_COMPOUND_MOD_OP_APPEND ` : a new value is appended after all existing values; * :ref:`TE_COMPOUND_MOD_OP_PREPEND ` : a new value is prepended before all existing values; * :ref:`TE_COMPOUND_MOD_OP_REPLACE ` : a new value is replacing all existing values. If there is no existing value for a given key, all modification modes are identical. If ``val_fmt`` is ``NULL``, all existing values are deleted irrespective of the value of ``mod_op``. When ``key`` is ``NULL``, the function operates on unnamed items. Please note that, unlike :ref:`te_vec `, it is not possible to replace a single unnamed item at a given index: if ``mod_op`` is :ref:`TE_COMPOUND_MOD_OP_REPLACE `, all existing unnamed items will be replaced with the new one. If a value is added to a plain string, the latter is converted to a single-item array. .. rubric:: Parameters: .. list-table:: :widths: 20 80 * - comp - Compound string. * - key - Key (may be ``NULL``). * - mod_op - Modification mode. * - val_fmt - Format string (may be ``NULL``). * - args - Variadic list to format. .. index:: pair: function; te_compound_set .. _doxid-group__te__tools__te__compound_1ga2a98f1e3fa784949e8a47d6d36bf3c2e: .. ref-code-block:: cpp :class: doxyrest-title-code-block void te_compound_set(:ref:`te_string`* comp, const char* key, :ref:`te_compound_mod_op` mod_op, const char* val_fmt, ...) Like :ref:`te_compound_set_va() `, but accepts variable number of arguments. .. rubric:: Parameters: .. list-table:: :widths: 20 80 * - comp - Compound string. * - key - Key (may be ``NULL``). * - mod_op - Modification mode. * - val_fmt - Format string (may be ``NULL``). * - ... - Arguments to format. .. index:: pair: function; te_compound_append_fast .. _doxid-group__te__tools__te__compound_1ga2b27a9b328f136f9cd390a6cd8d97162: .. ref-code-block:: cpp :class: doxyrest-title-code-block static void static void te_compound_append_fast(:ref:`te_string`* comp, const char* key, const char* value) Append a new value to the compound without any checks. Careless use of this function may result in an ill-formed compound string, so it should be used in special cases. One use case for the function is to implement a filter for another compound, when it is known for sure that items would come in the right order. .. rubric:: Parameters: .. list-table:: :widths: 20 80 * - comp - Compound string. * - key - Key to append (may be ``NULL``). * - value - Value to add (should not be ``NULL``). .. index:: pair: function; te_compound_merge .. _doxid-group__te__tools__te__compound_1gac3caf42e4f7ca349065f3c7147f8109a: .. ref-code-block:: cpp :class: doxyrest-title-code-block void te_compound_merge(:ref:`te_string`* dst, const :ref:`te_string`* src, :ref:`te_compound_mod_op` mod_op) Merge a compound string into another one. The behaviour for keys from ``src`` that are already in ``dst`` depends on the value of ``mod_op:`` * :ref:`TE_COMPOUND_MOD_OP_APPEND ` : all values from ``src`` for a given key would come after all values originally from ``dst`` for the same key; * :ref:`TE_COMPOUND_MOD_OP_PREPEND ` : all values from ``src`` for a given key would come before all values originally from ``dst`` for the same key; * :ref:`TE_COMPOUND_MOD_OP_REPLACE ` : values from ``src`` would replace values from ``dst`` for a given key. The function behaves almost exactly as if ``src`` were iterated and :ref:`te_compound_set() ` were called for every item, however, it is much more efficient. .. rubric:: Parameters: .. list-table:: :widths: 20 80 * - dst - Destination compound. * - src - Source compound to merge from. * - mod_op - Modification mode. .. index:: pair: function; te_compound_iterate .. _doxid-group__te__tools__te__compound_1ga3f5f08e8e3d7f9fb98a47df991efc2e2: .. ref-code-block:: cpp :class: doxyrest-title-code-block :ref:`te_errno` te_compound_iterate(const :ref:`te_string`* src, :ref:`te_compound_iter_fn`* callback, void* user) Iterate over all items in the compound. All unnamed items will be processed before any named one. Named items will be processed in the ascending order of their keys. If a compound is empty, the callback will not be called. If a compound is a non-empty plain string, the callback will be called exactly once, as if it were a single-item array. If a callback returns a non-zero status code, the processing stops and the status code is returned (:ref:`TE_EOK ` being replaced with zero). .. rubric:: Parameters: .. list-table:: :widths: 20 80 * - src - Compound string. * - callback - Callback. * - user - Callback data. * - TE_ENODATA - The compound is empty and the callback was not called. .. rubric:: Returns: Status code. .. index:: pair: function; te_compound_iterate_str .. _doxid-group__te__tools__te__compound_1gabbbf2aae2bfb6b69b3f8412b5929cd2f: .. ref-code-block:: cpp :class: doxyrest-title-code-block :ref:`te_errno` te_compound_iterate_str(const char* src, :ref:`te_compound_iter_fn`* callback, void* user) Like :ref:`te_compound_iterate() `, but accepts a plain C string as an input. The reason for this function existence is to avoid creating an intermediate :ref:`te_string ` if a compound string was obtained from some external source (e.g. read from a file). :ref:`te_compound_validate_str() ` must return ``true`` for ``src``. .. rubric:: Parameters: .. list-table:: :widths: 20 80 * - src - Compound string representation. * - callback - Callback. * - user - Callback data. * - TE_ENODATA - The compound is empty and the callback was not called. .. rubric:: Returns: Status code. .. index:: pair: function; te_vec2compound .. _doxid-group__te__tools__te__compound_1ga3aa602cfa619639ef82aba26f068058f: .. ref-code-block:: cpp :class: doxyrest-title-code-block void te_vec2compound(:ref:`te_string`* dst, const :ref:`te_vec`* vec) Append a vector of strings to the compound. All existing values in ``src`` are preserved. .. rubric:: Parameters: .. list-table:: :widths: 20 80 * - dst - Destination compound. * - vec - Vector of string pointers. .. index:: pair: function; te_kvpair2compound .. _doxid-group__te__tools__te__compound_1ga75c4fffc25a7d363ea6eeffe2cd836fa: .. ref-code-block:: cpp :class: doxyrest-title-code-block void te_kvpair2compound(:ref:`te_string`* dst, const te_kvpair_h* kv) Append key-value pairs to the compound. All existing values in ``src`` are preserved. .. rubric:: Parameters: .. list-table:: :widths: 20 80 * - dst - Destination compound. * - kv - Key-value pairs. .. index:: pair: function; te_compound2vec .. _doxid-group__te__tools__te__compound_1gaf259351bd9570c97cfbcf7b0f127fbec: .. ref-code-block:: cpp :class: doxyrest-title-code-block void te_compound2vec(:ref:`te_vec`* dst, const :ref:`te_string`* compound) Append all values from the compound to a vector. Values of named items will also be appended after unnamed items, but their keys will be ignored. The values will be copied, so they need to be eventually freed by a vector user. .. rubric:: Parameters: .. list-table:: :widths: 20 80 * - dst - Destination vector of string pointers. * - compound - Source compound. .. index:: pair: function; te_compound2kvpair .. _doxid-group__te__tools__te__compound_1ga5c6c573c099cdd319c825f964feeed7d: .. ref-code-block:: cpp :class: doxyrest-title-code-block void te_compound2kvpair(te_kvpair_h* dst, const :ref:`te_string`* compound) Append all values from the compound to a key-value list. Keys for unnamed items will be generated from their indices. Bug Due to limitations of #te_kvpair_h API, if there are several values associated with a given key, they will appear in ``dst`` in reverse order, so :ref:`te_compound2kvpair() ` and :ref:`te_kvpair2compound() ` are not exact inverse of each other. .. rubric:: Parameters: .. list-table:: :widths: 20 80 * - dst - Destination key-value list. * - compound - Source compound. .. index:: pair: function; te_json_add_compound .. _doxid-group__te__tools__te__compound_1ga294f1fc4a0e7e2e90e046a8ffdce20b3: .. ref-code-block:: cpp :class: doxyrest-title-code-block void te_json_add_compound(:ref:`te_json_ctx_t`* ctx, const :ref:`te_string`* compound) Serialize a compound as a JSON entity. The result of the function depends on the result of :ref:`te_compound_classify() ` : * :ref:`TE_COMPOUND_NULL ` : ``null`` will be produced; * :ref:`TE_COMPOUND_PLAIN ` : a JSON string will be produced; * :ref:`TE_COMPOUND_ARRAY ` : a JSON array will be produced; * :ref:`TE_COMPOUND_OBJECT ` : a JSON object will be produced. If ``compound`` contains both named and unnamed items, it will be serialized as a JSON object, but unnamed items will have keys generated from their indices. If ``compound`` contains multiple values associated with some keys, all values for a given key but the first will have an index appended to a key, so the generated JSON would never contain invalid duplicate keys. .. rubric:: Parameters: .. list-table:: :widths: 20 80 * - ctx - JSON context. * - compound - Source compound. .. index:: pair: function; te_kvpair_set_compound_va .. _doxid-group__te__tools__te__compound_1ga1208b4a7b0b67fb943e358de28d50103: .. ref-code-block:: cpp :class: doxyrest-title-code-block void te_kvpair_set_compound_va(te_kvpair_h* dst, const char* outer_key, const char* inner_key, :ref:`te_compound_mod_op` mod_op, const char* val_fmt, va_list args) Updates a compound value associated with a key in key-value pair list. The behaviour of this function is essentially the same as :ref:`te_compound_set_va() `, but if there was no value associated with ``outer_key`` and ``inner_key`` is ``NULL``, the added value will be a plain string, not a one-level array compound. If the compound value is empty after an update, the binding will be removed altogether. If there are multiple bindings for ``outer_key``, the function always operates on the most recent one. Bug This function is not very efficient due to the way key-value pairs are implemented. .. rubric:: Parameters: .. list-table:: :widths: 20 80 * - dst - Target key-value list. * - outer_key - The key for ``dst`` (may not be ``NULL``). * - inner_key - The key for the compound (may be ``NULL``). * - mod_op - Modification mode. * - val_fmt - Format string (may be ``NULL``). * - args - Variadic list to format. .. index:: pair: function; te_kvpair_set_compound .. _doxid-group__te__tools__te__compound_1ga5327831347b5cf8bbde9641070f3582c: .. ref-code-block:: cpp :class: doxyrest-title-code-block void te_kvpair_set_compound(te_kvpair_h* dst, const char* outer_key, const char* inner_key, :ref:`te_compound_mod_op` mod_op, const char* val_fmt, ...) Like :ref:`te_kvpair_set_compound_va() `, but accepts variable number of arguments. .. rubric:: Parameters: .. list-table:: :widths: 20 80 * - dst - Target key-value list. * - outer_key - The key for ``dst`` (may not be ``NULL``). * - inner_key - The key for the compound (may be ``NULL``). * - mod_op - Modification mode. * - val_fmt - Format string (may be ``NULL``). * - ... - Arguments to format. .. index:: pair: function; te_compound_build_name .. _doxid-group__te__tools__te__compound_1ga7c21742dc6910143d61b1afb741750a2: .. ref-code-block:: cpp :class: doxyrest-title-code-block void void te_compound_build_name(:ref:`te_string`* dst, const char* stem, const char* key, size_t idx) Construct a name that may reliably identify a compound item within some named value. For example, if a parameter named ``param`` holds a compound with two values for a field ``field``, the second value may be addresed as ``param_field1``. .. rubric:: Parameters: .. list-table:: :widths: 20 80 * - dst - TE string to append the name. * - stem - Name stem (i.e. the name of a parameter holding a compound value, may not be ``NULL``) * - key - Key to address (may be ``NULL``). * - idx - Index of a value in a multi-valued binding. .. index:: pair: function; te_compound_dereference .. _doxid-group__te__tools__te__compound_1ga03d0137e6a88f573f06add76f5d7211c: .. ref-code-block:: cpp :class: doxyrest-title-code-block :ref:`te_errno` te_compound_dereference(const :ref:`te_string`* compound, const char* stem, const char* key, :ref:`te_compound_iter_fn`* callback, void* user) Apply a function to a member of compound referenced by ``key``. The ``key`` should have been eventually constructed with :ref:`te_compound_build_name() ` with ``stem`` as an argument, otherwise :ref:`TE_ENODATA ` will be returned. The ``callback`` has the same signature as for :ref:`te_compound_iterate() `, but at most one field is ever processed. .. rubric:: Parameters: .. list-table:: :widths: 20 80 * - compound - Compound string. * - stem - Stem of ``key``. * - key - Name referencing a field in ``compound``. * - callback - Callback. * - user - User data to callback. * - TE_ENODATA - It is returned if ``callback`` has not been called: if ``key`` does not start with ``stem``, if there is no field with a given name or if there are not enough associated values for a given inded. .. rubric:: Returns: Status code (usuallaly the one returned by ``callback``). .. index:: pair: function; te_compound_dereference_str .. _doxid-group__te__tools__te__compound_1gaca32aa200e5467e7a71df39e242fc8b1: .. ref-code-block:: cpp :class: doxyrest-title-code-block :ref:`te_errno` te_compound_dereference_str(const char* compound, const char* stem, const char* key, :ref:`te_compound_iter_fn`* callback, void* user) Like :ref:`te_compound_dereference() `, but accepts a plain C string as an input. .. rubric:: Parameters: .. list-table:: :widths: 20 80 * - compound - Compound string. * - stem - Stem of ``key``. * - key - Name referencing a field in ``compound``. * - callback - Callback. * - user - User data to callback. .. rubric:: Returns: Status code (see :ref:`te_compound_dereference() ` for details).