Radek Krejci | e7b9509 | 2019-05-15 11:03:07 +0200 | [diff] [blame] | 1 | /** |
| 2 | * @file tree.h |
| 3 | * @author Radek Krejci <rkrejci@cesnet.cz> |
Radek Krejci | 8678fa4 | 2020-08-18 16:07:28 +0200 | [diff] [blame] | 4 | * @brief libyang generic macros and functions to work with YANG schema or data trees. |
Radek Krejci | e7b9509 | 2019-05-15 11:03:07 +0200 | [diff] [blame] | 5 | * |
| 6 | * Copyright (c) 2019 CESNET, z.s.p.o. |
| 7 | * |
| 8 | * This source code is licensed under BSD 3-Clause License (the "License"). |
| 9 | * You may not use this file except in compliance with the License. |
| 10 | * You may obtain a copy of the License at |
| 11 | * |
| 12 | * https://opensource.org/licenses/BSD-3-Clause |
| 13 | */ |
| 14 | |
| 15 | #ifndef LY_TREE_H_ |
| 16 | #define LY_TREE_H_ |
| 17 | |
Michal Vasko | ae867c7 | 2020-10-07 08:54:27 +0200 | [diff] [blame] | 18 | #include <inttypes.h> |
Radek Krejci | 7eb54ba | 2020-05-18 16:30:04 +0200 | [diff] [blame] | 19 | |
Michal Vasko | 9f96a05 | 2020-03-10 09:41:45 +0100 | [diff] [blame] | 20 | #include "tree_data.h" |
| 21 | |
Radek Krejci | e7b9509 | 2019-05-15 11:03:07 +0200 | [diff] [blame] | 22 | #ifdef __cplusplus |
| 23 | extern "C" { |
| 24 | #endif |
| 25 | |
| 26 | /** |
Radek Krejci | 8678fa4 | 2020-08-18 16:07:28 +0200 | [diff] [blame] | 27 | * @page howtoXPath XPath Addressing |
| 28 | * |
| 29 | * Internally, XPath evaluation is performed on __when__ and __must__ conditions in the schema. For that almost |
| 30 | * a full [XPath 1.0](http://www.w3.org/TR/1999/REC-xpath-19991116/) evaluator was implemented. |
| 31 | * In YANG models you can also find paths identifying __augment__ targets, __leafref__ targets, and trivial paths in |
| 32 | * __choice default__ and __unique__ statements argument. The exact format of all those paths can be found in the |
| 33 | * relevant RFCs. Further will only be discussed paths that are used directly in libyang API functions. |
| 34 | * |
| 35 | * XPath |
| 36 | * ===== |
| 37 | * |
| 38 | * Generally, any xpath argument expects an expression similar to _when_ or _must_ as the same evaluator is used. As for |
| 39 | * the format of any prefixes, the standardized JSON ([RFC 7951](https://tools.ietf.org/html/rfc7951#section-6.11)) |
| 40 | * was used. Summarized, xpath follows these conventions: |
| 41 | * - full XPath can be used, but only data nodes (node sets) will always be returned, |
| 42 | * - as per the specification, prefixes are actually __module names__, |
| 43 | * - also in the specification, for _absolute_ paths, the first (leftmost) node _MUST_ have a prefix, |
| 44 | * - for _relative_ paths, you specify the __context node__, which then acts as a parent for the first node in the path, |
| 45 | * - nodes always inherit their module (prefix) from their __parent node__ so whenever a node is from a different |
| 46 | * module than its parent, it _MUST_ have a prefix, |
| 47 | * - nodes from the same module as their __parent__ _MUST NOT_ have a prefix, |
| 48 | * - note that non-data nodes/schema-only node (choice, case, uses, input, output) are skipped and _MUST_ not be |
| 49 | * included in the path. |
| 50 | * |
| 51 | * Functions List |
| 52 | * -------------- |
| 53 | * - ::lyd_find_xpath() |
| 54 | * - ::lys_find_xpath() |
| 55 | * |
| 56 | * Path |
| 57 | * ==== |
| 58 | * |
| 59 | * The term path is used when a simplified (subset of) XPath is expected. Path is always a valid XPath but not |
| 60 | * the other way around. In short, paths only identify a specific (set of) nodes based on their ancestors in the |
| 61 | * schema. Predicates are allowed the same as for an [instance-identifier](https://tools.ietf.org/html/rfc7950#section-9.13). |
| 62 | * Specifically, key values of a list, leaf-list value, or position of lists without keys can be used. |
| 63 | * |
| 64 | * Examples |
| 65 | * -------- |
| 66 | * |
| 67 | * - get __list__ instance with __key1__ of value __1__ and __key2__ of value __2__ (this can return more __list__ instances if there are more keys than __key1__ and __key2__) |
| 68 | * |
| 69 | * /module-name:container/list[key1='1'][key2='2'] |
| 70 | * |
| 71 | * - get __leaf-list__ instance with the value __val__ |
| 72 | * |
| 73 | * /module-name:container/leaf-list[.='val'] |
| 74 | * |
| 75 | * - get __3rd list-without-keys__ instance with no keys defined |
| 76 | * |
| 77 | * /module-name:container/list-without-keys[3] |
| 78 | * |
| 79 | * - get __aug-list__ with __aug-list-key__, which was added to __module-name__ from an augment module __augment-module__ |
| 80 | * |
| 81 | * /module-name:container/container2/augment-module:aug-cont/aug-list[aug-list-key='value'] |
| 82 | * |
| 83 | * Functions List |
| 84 | * -------------- |
| 85 | * - ::lyd_new_path() |
| 86 | * - ::lyd_new_path2() |
| 87 | * - ::lyd_path() |
Radek Krejci | fba9c62 | 2020-10-30 08:28:54 +0100 | [diff] [blame] | 88 | * - ::lys_find_path() |
Radek Krejci | 8678fa4 | 2020-08-18 16:07:28 +0200 | [diff] [blame] | 89 | * |
| 90 | */ |
| 91 | |
| 92 | /** |
Radek Krejci | 2ff0d57 | 2020-05-21 15:27:28 +0200 | [diff] [blame] | 93 | * @defgroup trees Trees |
| 94 | * |
| 95 | * Generic macros, functions, etc. to work with both [schema](@ref schematree) and [data](@ref datatree) trees. |
| 96 | * |
| 97 | * @{ |
| 98 | */ |
| 99 | |
| 100 | /** |
Radek Krejci | c4fa029 | 2020-05-14 10:54:49 +0200 | [diff] [blame] | 101 | * @brief Type (i.e. size) of the [sized array](@ref sizedarrays)'s size counter. |
Radek Krejci | 7eb54ba | 2020-05-18 16:30:04 +0200 | [diff] [blame] | 102 | * |
Michal Vasko | fd69e1d | 2020-07-03 11:57:17 +0200 | [diff] [blame] | 103 | * To print the value via a print format, use LY_PRI_ARRAY_COUNT_TYPE specifier. |
Radek Krejci | c4fa029 | 2020-05-14 10:54:49 +0200 | [diff] [blame] | 104 | */ |
Michal Vasko | fd69e1d | 2020-07-03 11:57:17 +0200 | [diff] [blame] | 105 | #define LY_ARRAY_COUNT_TYPE uint64_t |
Radek Krejci | c4fa029 | 2020-05-14 10:54:49 +0200 | [diff] [blame] | 106 | |
| 107 | /** |
Radek Krejci | 7eb54ba | 2020-05-18 16:30:04 +0200 | [diff] [blame] | 108 | * @brief Printing format specifier macro for LY_ARRAY_SIZE_TYPE values. |
| 109 | */ |
Michal Vasko | fd69e1d | 2020-07-03 11:57:17 +0200 | [diff] [blame] | 110 | #define LY_PRI_ARRAY_COUNT_TYPE PRIu64 |
Radek Krejci | 7eb54ba | 2020-05-18 16:30:04 +0200 | [diff] [blame] | 111 | |
| 112 | /** |
Radek Krejci | e7b9509 | 2019-05-15 11:03:07 +0200 | [diff] [blame] | 113 | * @brief Macro selector for other LY_ARRAY_* macros, do not use directly! |
| 114 | */ |
| 115 | #define LY_ARRAY_SELECT(_1, _2, NAME, ...) NAME |
| 116 | |
| 117 | /** |
| 118 | * @brief Helper macro to go through sized-arrays with a pointer iterator. |
| 119 | * |
| 120 | * Use with opening curly bracket (`{`). |
| 121 | * |
| 122 | * @param[in] ARRAY Array to go through |
| 123 | * @param[in] TYPE Type of the records in the ARRAY |
| 124 | * @param[out] ITER Iterating pointer to the item being processed in each loop |
| 125 | */ |
| 126 | #define LY_ARRAY_FOR_ITER(ARRAY, TYPE, ITER) \ |
| 127 | for (ITER = ARRAY; \ |
Michal Vasko | fd69e1d | 2020-07-03 11:57:17 +0200 | [diff] [blame] | 128 | (ARRAY) && ((void*)ITER - (void*)ARRAY)/(sizeof(TYPE)) < (*((LY_ARRAY_COUNT_TYPE*)(ARRAY) - 1)); \ |
Radek Krejci | e7b9509 | 2019-05-15 11:03:07 +0200 | [diff] [blame] | 129 | ITER = (void*)((TYPE*)ITER + 1)) |
| 130 | |
| 131 | /** |
| 132 | * @brief Helper macro to go through sized-arrays with a numeric iterator. |
| 133 | * |
| 134 | * Use with opening curly bracket (`{`). |
| 135 | * |
Radek Krejci | 5ee14f3 | 2020-11-05 13:16:42 +0100 | [diff] [blame] | 136 | * The item on the current INDEX in the ARRAY can be accessed in a standard C way as ARRAY[INDEX]. |
Radek Krejci | e7b9509 | 2019-05-15 11:03:07 +0200 | [diff] [blame] | 137 | * |
| 138 | * @param[in] ARRAY Array to go through |
Radek Krejci | 5ee14f3 | 2020-11-05 13:16:42 +0100 | [diff] [blame] | 139 | * @param[out] INDEX Variable for the iterating index of the item being processed in each loop |
Radek Krejci | e7b9509 | 2019-05-15 11:03:07 +0200 | [diff] [blame] | 140 | */ |
| 141 | #define LY_ARRAY_FOR_INDEX(ARRAY, INDEX) \ |
| 142 | for (INDEX = 0; \ |
Michal Vasko | fd69e1d | 2020-07-03 11:57:17 +0200 | [diff] [blame] | 143 | ARRAY && INDEX < (*((LY_ARRAY_COUNT_TYPE*)(ARRAY) - 1)); \ |
Radek Krejci | e7b9509 | 2019-05-15 11:03:07 +0200 | [diff] [blame] | 144 | ++INDEX) |
| 145 | |
| 146 | /** |
Michal Vasko | fd69e1d | 2020-07-03 11:57:17 +0200 | [diff] [blame] | 147 | * @brief Get the number of records in the ARRAY. |
Radek Krejci | e7b9509 | 2019-05-15 11:03:07 +0200 | [diff] [blame] | 148 | * |
| 149 | * Does not check if array exists! |
| 150 | */ |
Michal Vasko | fd69e1d | 2020-07-03 11:57:17 +0200 | [diff] [blame] | 151 | #define LY_ARRAY_COUNT(ARRAY) (*((LY_ARRAY_COUNT_TYPE*)(ARRAY) - 1)) |
Radek Krejci | e7b9509 | 2019-05-15 11:03:07 +0200 | [diff] [blame] | 152 | |
| 153 | /** |
| 154 | * @brief Sized-array iterator (for-loop). |
| 155 | * |
| 156 | * Use with opening curly bracket (`{`). |
| 157 | * |
| 158 | * There are 2 variants: |
| 159 | * |
| 160 | * LY_ARRAY_FOR(ARRAY, TYPE, ITER) |
| 161 | * |
| 162 | * Where ARRAY is a sized-array to go through, TYPE is the type of the items in the ARRAY and ITER is a pointer variable |
| 163 | * providing the items of the ARRAY in the loops. This functionality is provided by LY_ARRAY_FOR_ITER macro |
| 164 | * |
| 165 | * LY_ARRAY_FOR(ARRAY, INDEX) |
| 166 | * |
Michal Vasko | fd69e1d | 2020-07-03 11:57:17 +0200 | [diff] [blame] | 167 | * The ARRAY is again a sized-array to go through, the INDEX is a variable (LY_ARRAY_COUNT_TYPE) for storing iterating ARRAY's index |
Radek Krejci | e7b9509 | 2019-05-15 11:03:07 +0200 | [diff] [blame] | 168 | * to access the items of ARRAY in the loops. This functionality is provided by LY_ARRAY_FOR_INDEX macro. |
| 169 | */ |
| 170 | #define LY_ARRAY_FOR(ARRAY, ...) LY_ARRAY_SELECT(__VA_ARGS__, LY_ARRAY_FOR_ITER, LY_ARRAY_FOR_INDEX)(ARRAY, __VA_ARGS__) |
| 171 | |
| 172 | /** |
| 173 | * @brief Macro to iterate via all sibling elements without affecting the list itself |
| 174 | * |
| 175 | * Works for all types of nodes despite it is data or schema tree, but all the |
| 176 | * parameters must be pointers to the same type. |
| 177 | * |
| 178 | * Use with opening curly bracket (`{`). All parameters must be of the same type. |
| 179 | * |
| 180 | * @param START Pointer to the starting element. |
| 181 | * @param ELEM Iterator. |
| 182 | */ |
| 183 | #define LY_LIST_FOR(START, ELEM) \ |
| 184 | for ((ELEM) = (START); \ |
| 185 | (ELEM); \ |
| 186 | (ELEM) = (ELEM)->next) |
| 187 | |
| 188 | /** |
| 189 | * @brief Macro to iterate via all sibling elements allowing to modify the list itself (e.g. removing elements) |
| 190 | * |
| 191 | * Use with opening curly bracket (`{`). All parameters must be of the same type. |
| 192 | * |
| 193 | * @param START Pointer to the starting element. |
| 194 | * @param NEXT Temporary storage to allow removing of the current iterator content. |
| 195 | * @param ELEM Iterator. |
| 196 | */ |
| 197 | #define LY_LIST_FOR_SAFE(START, NEXT, ELEM) \ |
| 198 | for ((ELEM) = (START); \ |
| 199 | (ELEM) ? (NEXT = (ELEM)->next, 1) : 0; \ |
| 200 | (ELEM) = (NEXT)) |
| 201 | |
| 202 | /** |
Michal Vasko | 4c583e8 | 2020-07-17 12:16:14 +0200 | [diff] [blame] | 203 | * @brief Macro to iterate via all schema node data instances in data siblings. |
| 204 | * |
| 205 | * @param START Pointer to the starting sibling. Even if it is not first, all the siblings are searched. |
| 206 | * @param SCHEMA Schema node of the searched instances. |
| 207 | * @param ELEM Iterator. |
| 208 | */ |
| 209 | #define LYD_LIST_FOR_INST(START, SCHEMA, ELEM) \ |
| 210 | for (lyd_find_sibling_val(START, SCHEMA, NULL, 0, &(ELEM)); \ |
| 211 | (ELEM) && ((ELEM)->schema == (SCHEMA)); \ |
| 212 | (ELEM) = (ELEM)->next) |
| 213 | |
| 214 | /** |
| 215 | * @brief Macro to iterate via all schema node data instances in data siblings allowing to modify the list itself. |
| 216 | * |
| 217 | * @param START Pointer to the starting sibling. Even if it is not first, all the siblings are searched. |
| 218 | * @param SCHEMA Schema node of the searched instances. |
| 219 | * @param NEXT Temporary storage to allow removing of the current iterator content. |
| 220 | * @param ELEM Iterator. |
| 221 | */ |
| 222 | #define LYD_LIST_FOR_INST_SAFE(START, SCHEMA, NEXT, ELEM) \ |
| 223 | for (lyd_find_sibling_val(START, SCHEMA, NULL, 0, &(ELEM)); \ |
| 224 | (ELEM) && ((ELEM)->schema == (SCHEMA)) ? ((NEXT) = (ELEM)->next, 1) : 0; \ |
| 225 | (ELEM) = (NEXT)) |
| 226 | |
| 227 | /** |
Radek Krejci | e7b9509 | 2019-05-15 11:03:07 +0200 | [diff] [blame] | 228 | * @brief YANG built-in types |
| 229 | */ |
| 230 | typedef enum |
| 231 | { |
| 232 | LY_TYPE_UNKNOWN = 0, /**< Unknown type */ |
| 233 | LY_TYPE_BINARY, /**< Any binary data ([RFC 6020 sec 9.8](http://tools.ietf.org/html/rfc6020#section-9.8)) */ |
| 234 | LY_TYPE_UINT8, /**< 8-bit unsigned integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */ |
| 235 | LY_TYPE_UINT16, /**< 16-bit unsigned integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */ |
| 236 | LY_TYPE_UINT32, /**< 32-bit unsigned integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */ |
| 237 | LY_TYPE_UINT64, /**< 64-bit unsigned integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */ |
| 238 | LY_TYPE_STRING, /**< Human-readable string ([RFC 6020 sec 9.4](http://tools.ietf.org/html/rfc6020#section-9.4)) */ |
| 239 | LY_TYPE_BITS, /**< A set of bits or flags ([RFC 6020 sec 9.7](http://tools.ietf.org/html/rfc6020#section-9.7)) */ |
| 240 | LY_TYPE_BOOL, /**< "true" or "false" ([RFC 6020 sec 9.5](http://tools.ietf.org/html/rfc6020#section-9.5)) */ |
| 241 | LY_TYPE_DEC64, /**< 64-bit signed decimal number ([RFC 6020 sec 9.3](http://tools.ietf.org/html/rfc6020#section-9.3))*/ |
| 242 | LY_TYPE_EMPTY, /**< A leaf that does not have any value ([RFC 6020 sec 9.11](http://tools.ietf.org/html/rfc6020#section-9.11)) */ |
| 243 | LY_TYPE_ENUM, /**< Enumerated strings ([RFC 6020 sec 9.6](http://tools.ietf.org/html/rfc6020#section-9.6)) */ |
| 244 | LY_TYPE_IDENT, /**< A reference to an abstract identity ([RFC 6020 sec 9.10](http://tools.ietf.org/html/rfc6020#section-9.10)) */ |
| 245 | LY_TYPE_INST, /**< References a data tree node ([RFC 6020 sec 9.13](http://tools.ietf.org/html/rfc6020#section-9.13)) */ |
| 246 | LY_TYPE_LEAFREF, /**< A reference to a leaf instance ([RFC 6020 sec 9.9](http://tools.ietf.org/html/rfc6020#section-9.9))*/ |
| 247 | LY_TYPE_UNION, /**< Choice of member types ([RFC 6020 sec 9.12](http://tools.ietf.org/html/rfc6020#section-9.12)) */ |
| 248 | LY_TYPE_INT8, /**< 8-bit signed integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */ |
| 249 | LY_TYPE_INT16, /**< 16-bit signed integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */ |
| 250 | LY_TYPE_INT32, /**< 32-bit signed integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */ |
Michal Vasko | 6973015 | 2020-10-09 16:30:07 +0200 | [diff] [blame] | 251 | LY_TYPE_INT64 /**< 64-bit signed integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */ |
Radek Krejci | e7b9509 | 2019-05-15 11:03:07 +0200 | [diff] [blame] | 252 | } LY_DATA_TYPE; |
| 253 | #define LY_DATA_TYPE_COUNT 20 /**< Number of different types */ |
| 254 | |
| 255 | /** |
| 256 | * @brief Stringified YANG built-in data types |
| 257 | */ |
Michal Vasko | 22df3f0 | 2020-08-24 13:29:22 +0200 | [diff] [blame] | 258 | extern const char *ly_data_type2str[LY_DATA_TYPE_COUNT]; |
Radek Krejci | e7b9509 | 2019-05-15 11:03:07 +0200 | [diff] [blame] | 259 | |
Radek Krejci | 2ff0d57 | 2020-05-21 15:27:28 +0200 | [diff] [blame] | 260 | /** @} trees */ |
Radek Krejci | e7b9509 | 2019-05-15 11:03:07 +0200 | [diff] [blame] | 261 | |
| 262 | #ifdef __cplusplus |
| 263 | } |
| 264 | #endif |
| 265 | |
| 266 | #endif /* LY_TREE_H_ */ |