Michal Vasko | 5a9eb76 | 2018-03-26 11:45:33 +0200 | [diff] [blame] | 1 | /** |
| 2 | * @file common.h |
| 3 | * @author Radek Krejci <rkrejci@cesnet.cz> |
| 4 | * @brief common internal definitions for libyang |
| 5 | * |
| 6 | * Copyright (c) 2015 - 2018 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_COMMON_H_ |
| 16 | #define LY_COMMON_H_ |
| 17 | |
| 18 | #include <stdint.h> |
| 19 | #include <errno.h> |
| 20 | #include <inttypes.h> |
| 21 | |
| 22 | #include "libyang.h" |
| 23 | #include "hash_table.h" |
| 24 | #include "resolve.h" |
| 25 | |
| 26 | #define UNUSED(x) @COMPILER_UNUSED_ATTR@ |
| 27 | |
Rafael Zalamena | fc54377 | 2018-10-14 16:32:53 +0200 | [diff] [blame] | 28 | #if __STDC_VERSION__ >= 201112 && \ |
| 29 | !defined __STDC_NO_THREADS__ && \ |
| 30 | !defined __NetBSD__ |
Michal Vasko | 5a9eb76 | 2018-03-26 11:45:33 +0200 | [diff] [blame] | 31 | # define THREAD_LOCAL _Thread_local |
| 32 | #elif defined __GNUC__ || \ |
| 33 | defined __SUNPRO_C || \ |
| 34 | defined __xlC__ |
| 35 | # define THREAD_LOCAL __thread |
| 36 | #else |
| 37 | # error "Cannot define THREAD_LOCAL" |
| 38 | #endif |
| 39 | |
| 40 | #ifndef __WORDSIZE |
| 41 | # if defined __x86_64__ && !defined __ILP32__ |
| 42 | # define __WORDSIZE 64 |
| 43 | # else |
| 44 | # define __WORDSIZE 32 |
| 45 | # endif |
| 46 | #endif |
| 47 | |
| 48 | #ifndef __INT64_C |
| 49 | # if __WORDSIZE == 64 |
| 50 | # define __INT64_C(c) c ## L |
| 51 | # define __UINT64_C(c) c ## UL |
| 52 | # else |
| 53 | # define __INT64_C(c) c ## LL |
| 54 | # define __UINT64_C(c) c ## ULL |
| 55 | # endif |
| 56 | #endif |
| 57 | |
Rafael Zalamena | 0d7142e | 2018-10-14 16:17:48 +0200 | [diff] [blame] | 58 | #ifndef MAP_ANONYMOUS |
| 59 | #define MAP_ANONYMOUS MAP_ANON |
| 60 | #endif /* !MAP_ANONYMOUS */ |
| 61 | |
Michal Vasko | 5a9eb76 | 2018-03-26 11:45:33 +0200 | [diff] [blame] | 62 | #define LY_CHECK_GOTO(COND, GOTO) if (COND) {goto GOTO;} |
| 63 | #define LY_CHECK_ERR_GOTO(COND, ERR, GOTO) if (COND) {ERR; goto GOTO;} |
| 64 | #define LY_CHECK_RETURN(COND, RETVAL) if (COND) {return RETVAL;} |
| 65 | #define LY_CHECK_ERR_RETURN(COND, ERR, RETVAL) if (COND) {ERR; return RETVAL;} |
| 66 | |
| 67 | /* |
| 68 | * If the compiler supports attribute to mark objects as hidden, mark all |
| 69 | * objects as hidden and export only objects explicitly marked to be part of |
| 70 | * the public API. |
| 71 | */ |
| 72 | #define API __attribute__((visibility("default"))) |
| 73 | |
| 74 | #ifndef __USE_GNU |
| 75 | /* |
| 76 | * If we don't have GNU extension, implement these function on your own |
| 77 | */ |
| 78 | char *get_current_dir_name(void); |
| 79 | |
| 80 | #endif |
| 81 | |
| 82 | /* how many bytes add when enlarging buffers */ |
| 83 | #define LY_BUF_STEP 128 |
| 84 | |
| 85 | /* internal logging options */ |
| 86 | enum int_log_opts { |
| 87 | ILO_LOG = 0, /* log normally */ |
| 88 | ILO_STORE, /* only store any messages, they will be processed higher on stack */ |
| 89 | ILO_IGNORE, /* completely ignore messages */ |
| 90 | ILO_ERR2WRN, /* change errors to warnings */ |
| 91 | }; |
| 92 | |
| 93 | void ly_err_free(void *ptr); |
| 94 | void ly_err_free_next(struct ly_ctx *ctx, struct ly_err_item *last_eitem); |
| 95 | void ly_ilo_change(struct ly_ctx *ctx, enum int_log_opts new_ilo, enum int_log_opts *prev_ilo, struct ly_err_item **prev_last_eitem); |
| 96 | void ly_ilo_restore(struct ly_ctx *ctx, enum int_log_opts prev_ilo, struct ly_err_item *prev_last_eitem, int keep_and_print); |
| 97 | void ly_err_last_set_apptag(const struct ly_ctx *ctx, const char *apptag); |
| 98 | extern THREAD_LOCAL enum int_log_opts log_opt; |
| 99 | |
| 100 | /* |
| 101 | * logger |
| 102 | */ |
| 103 | extern volatile uint8_t ly_log_level; |
| 104 | extern volatile uint8_t ly_log_opts; |
| 105 | |
| 106 | void ly_log(const struct ly_ctx *ctx, LY_LOG_LEVEL level, LY_ERR no, const char *format, ...); |
| 107 | |
| 108 | #define LOGERR(ctx, errno, str, args...) \ |
| 109 | ly_log(ctx, LY_LLERR, errno, str, ##args); |
| 110 | |
| 111 | #define LOGWRN(ctx, str, args...) \ |
| 112 | ly_log(ctx, LY_LLWRN, 0, str, ##args); |
| 113 | |
| 114 | #define LOGVRB(str, args...) \ |
| 115 | ly_log(NULL, LY_LLVRB, 0, str, ##args); |
| 116 | |
| 117 | #ifdef NDEBUG |
| 118 | |
| 119 | #define LOGDBG(dbg_group, str, args...) |
| 120 | |
| 121 | #else |
| 122 | |
| 123 | #define LOGDBG(dbg_group, str, args...) \ |
| 124 | ly_log_dbg(dbg_group, str, ##args); |
| 125 | |
| 126 | void ly_log_dbg(int group, const char *format, ...); |
| 127 | |
| 128 | #endif |
| 129 | |
| 130 | #define LOGMEM(ctx) LOGERR(ctx, LY_EMEM, "Memory allocation failed (%s()).", __func__) |
| 131 | |
| 132 | #define LOGINT(ctx) LOGERR(ctx, LY_EINT, "Internal error (%s:%d).", __FILE__, __LINE__) |
| 133 | |
| 134 | #define LOGARG LOGERR(NULL, LY_EINVAL, "Invalid arguments (%s()).", __func__) |
| 135 | |
| 136 | typedef enum { |
| 137 | LYE_PATH = -2, /**< error path set */ |
| 138 | LYE_SPEC = -1, /**< generic error */ |
| 139 | |
| 140 | LYE_SUCCESS = 0, |
| 141 | |
| 142 | LYE_XML_MISS, |
| 143 | LYE_XML_INVAL, |
| 144 | LYE_XML_INCHAR, |
| 145 | |
| 146 | LYE_EOF, |
| 147 | LYE_INSTMT, |
| 148 | LYE_INCHILDSTMT, |
| 149 | LYE_INPAR, |
| 150 | LYE_INID, |
| 151 | LYE_INDATE, |
| 152 | LYE_INARG, |
| 153 | LYE_MISSSTMT, |
| 154 | LYE_MISSCHILDSTMT, |
| 155 | LYE_MISSARG, |
| 156 | LYE_TOOMANY, |
| 157 | LYE_DUPID, |
| 158 | LYE_DUPLEAFLIST, |
| 159 | LYE_DUPLIST, |
| 160 | LYE_NOUNIQ, |
| 161 | LYE_ENUM_INVAL, |
| 162 | LYE_ENUM_INNAME, |
| 163 | LYE_ENUM_DUPVAL, |
| 164 | LYE_ENUM_DUPNAME, |
| 165 | LYE_ENUM_WS, |
| 166 | LYE_BITS_INVAL, |
| 167 | LYE_BITS_INNAME, |
| 168 | LYE_BITS_DUPVAL, |
| 169 | LYE_BITS_DUPNAME, |
| 170 | LYE_INMOD, |
| 171 | LYE_INMOD_LEN, |
| 172 | LYE_KEY_NLEAF, |
| 173 | LYE_KEY_TYPE, |
| 174 | LYE_KEY_CONFIG, |
| 175 | LYE_KEY_MISS, |
| 176 | LYE_KEY_DUP, |
| 177 | LYE_INREGEX, |
| 178 | LYE_INRESOLV, |
| 179 | LYE_INSTATUS, |
| 180 | LYE_CIRC_LEAFREFS, |
| 181 | LYE_CIRC_FEATURES, |
| 182 | LYE_CIRC_IMPORTS, |
| 183 | LYE_CIRC_INCLUDES, |
| 184 | LYE_INVER, |
| 185 | LYE_SUBMODULE, |
| 186 | |
| 187 | LYE_OBSDATA, |
| 188 | LYE_OBSTYPE, |
| 189 | LYE_NORESOLV, |
| 190 | LYE_INELEM, |
| 191 | LYE_INELEM_LEN, |
| 192 | LYE_MISSELEM, |
| 193 | LYE_INVAL, |
| 194 | LYE_INMETA, |
| 195 | LYE_INATTR, |
| 196 | LYE_MISSATTR, |
| 197 | LYE_NOCONSTR, |
| 198 | LYE_INCHAR, |
| 199 | LYE_INPRED, |
| 200 | LYE_MCASEDATA, |
| 201 | LYE_NOMUST, |
| 202 | LYE_NOWHEN, |
| 203 | LYE_INORDER, |
| 204 | LYE_INWHEN, |
| 205 | LYE_NOMIN, |
| 206 | LYE_NOMAX, |
| 207 | LYE_NOREQINS, |
| 208 | LYE_NOLEAFREF, |
| 209 | LYE_NOMANDCHOICE, |
| 210 | |
| 211 | LYE_XPATH_INTOK, |
| 212 | LYE_XPATH_EOF, |
| 213 | LYE_XPATH_INOP_1, |
| 214 | LYE_XPATH_INOP_2, |
| 215 | LYE_XPATH_INCTX, |
| 216 | LYE_XPATH_INMOD, |
| 217 | LYE_XPATH_INFUNC, |
| 218 | LYE_XPATH_INARGCOUNT, |
| 219 | LYE_XPATH_INARGTYPE, |
| 220 | LYE_XPATH_DUMMY, |
| 221 | LYE_XPATH_NOEND, |
| 222 | |
| 223 | LYE_PATH_INCHAR, |
| 224 | LYE_PATH_INMOD, |
| 225 | LYE_PATH_MISSMOD, |
| 226 | LYE_PATH_INNODE, |
| 227 | LYE_PATH_INKEY, |
| 228 | LYE_PATH_MISSKEY, |
Michal Vasko | 310bc58 | 2018-05-22 10:47:59 +0200 | [diff] [blame] | 229 | LYE_PATH_INIDENTREF, |
Michal Vasko | 5a9eb76 | 2018-03-26 11:45:33 +0200 | [diff] [blame] | 230 | LYE_PATH_EXISTS, |
| 231 | LYE_PATH_MISSPAR, |
Michal Vasko | febd13d | 2018-05-17 10:42:24 +0200 | [diff] [blame] | 232 | LYE_PATH_PREDTOOMANY, |
Michal Vasko | 5a9eb76 | 2018-03-26 11:45:33 +0200 | [diff] [blame] | 233 | } LY_ECODE; |
| 234 | |
| 235 | enum LY_VLOG_ELEM { |
| 236 | LY_VLOG_NONE = 0, |
| 237 | LY_VLOG_XML, /* struct lyxml_elem* */ |
| 238 | LY_VLOG_LYS, /* struct lys_node* */ |
| 239 | LY_VLOG_LYD, /* struct lyd_node* */ |
| 240 | LY_VLOG_STR, /* const char* */ |
| 241 | LY_VLOG_PREV /* use exact same previous path */ |
| 242 | }; |
| 243 | |
| 244 | void ly_vlog(const struct ly_ctx *ctx, LY_ECODE code, enum LY_VLOG_ELEM elem_type, const void *elem, ...); |
| 245 | #define LOGVAL(ctx, code, elem_type, elem, args...) \ |
| 246 | ly_vlog(ctx, code, elem_type, elem, ##args); |
| 247 | |
| 248 | #define LOGPATH(ctx, elem_type, elem) \ |
| 249 | ly_vlog(ctx, LYE_PATH, elem_type, elem); |
| 250 | |
| 251 | /** |
Michal Vasko | b4b31f6 | 2018-11-23 11:49:20 +0100 | [diff] [blame] | 252 | * @brief Print additional validation information string. |
| 253 | * |
| 254 | * All special characters will be escaped ('%'). |
| 255 | * |
| 256 | * @param[in] ctx Context to use for logging. |
| 257 | * @param[in] elem_type Identify the element at issue. Either #LY_VLOG_NONE or #LY_VLOG_PREV. |
| 258 | * @param[in] str String to print that will be escaped. |
| 259 | * @param[in] ... Always leave empty (needed for compiler to accept va_start() call). |
| 260 | */ |
| 261 | void ly_vlog_str(const struct ly_ctx *ctx, enum LY_VLOG_ELEM elem_type, const char *str, ...); |
| 262 | |
| 263 | /** |
Michal Vasko | 5a9eb76 | 2018-03-26 11:45:33 +0200 | [diff] [blame] | 264 | * @brief Build path of \p elem. |
| 265 | * |
| 266 | * @param[in] elem_type What to expect in \p elem. |
| 267 | * @param[in] elem Element to print. |
| 268 | * @param[in,out] path Resulting path printed. |
| 269 | * @param[in] schema_all_prefixes Whether to include prefixes for all the nodes (only for schema paths). |
Michal Vasko | 185b527 | 2018-09-13 14:26:12 +0200 | [diff] [blame] | 270 | * @param[in] data_no_predicates Whether to skip generating predicates for all the nodes (only for data paths). |
Michal Vasko | 5a9eb76 | 2018-03-26 11:45:33 +0200 | [diff] [blame] | 271 | * @return 0 on success, -1 on error. |
| 272 | */ |
Michal Vasko | 185b527 | 2018-09-13 14:26:12 +0200 | [diff] [blame] | 273 | int ly_vlog_build_path(enum LY_VLOG_ELEM elem_type, const void *elem, char **path, int schema_all_prefixes, int data_no_predicates); |
Michal Vasko | 5a9eb76 | 2018-03-26 11:45:33 +0200 | [diff] [blame] | 274 | |
| 275 | /** |
| 276 | * @brief Get module from a context based on its name and revision. |
| 277 | * |
| 278 | * @param[in] ctx Context to search in. |
| 279 | * @param[in] name Name of the module. |
| 280 | * @param[in] name_len Length of \p name, can be 0 if the name is ended with '\0'. |
| 281 | * @param[in] revision Revision of the module, can be NULL for the newest. |
| 282 | * @param[in] implemented Whether only implemented modules should be returned. |
| 283 | * @return Matching module, NULL if not found. |
| 284 | */ |
| 285 | const struct lys_module *ly_ctx_nget_module(const struct ly_ctx *ctx, const char *name, size_t name_len, |
| 286 | const char *revision, int implemented); |
| 287 | |
| 288 | /* |
| 289 | * - if \p module specified, it searches for submodules, they can be loaded only from a file or via module callback, |
| 290 | * they cannot be get from context |
| 291 | * - if \p module is not specified |
| 292 | * - if specific revision is specified, the first try is to get module from the context |
| 293 | * - if no specific revision is specified, it tries to get the newest module - first it searches for the file and |
| 294 | * then checks that the schema loaded from the same source isn't already in context. If the source wasn't |
| 295 | * previously loaded, it is parsed. |
| 296 | */ |
| 297 | const struct lys_module *ly_ctx_load_sub_module(struct ly_ctx *ctx, struct lys_module *module, const char *name, |
| 298 | const char *revision, int implement, struct unres_schema *unres); |
| 299 | |
| 300 | /** |
| 301 | * @brief Basic functionality like strpbrk(3). However, it searches string \p s |
| 302 | * backwards up to most \p s_len characters. |
| 303 | * |
| 304 | * @param[in] s String to search backwards. |
| 305 | * @param[in] accept String of characters that are searched for. |
| 306 | * @param[in] s_len Backward length of \p s. |
| 307 | * |
| 308 | * @return Pointer to the first backward occurence of a character from |
| 309 | * \p accept or \p s - \p s_len if not found. |
| 310 | */ |
| 311 | const char *strpbrk_backwards(const char *s, const char *accept, unsigned int s_len); |
| 312 | |
| 313 | char *strnchr(const char *s, int c, unsigned int len); |
| 314 | |
| 315 | const char *strnodetype(LYS_NODE type); |
| 316 | |
| 317 | /** |
| 318 | * @brief Transform a module name (JSON format prefix) to a prefix as defined |
| 319 | * in \p module imports. Its own name is transformed to its own prefix. |
| 320 | * |
| 321 | * @param[in] module Module with imports to use. |
| 322 | * @param[in] module_name Module name to transform. |
| 323 | * |
| 324 | * @return Module import prefix (do not modify, free, or lydict_remove), |
| 325 | * NULL on error. |
| 326 | */ |
| 327 | const char *transform_module_name2import_prefix(const struct lys_module *module, const char *module_name); |
| 328 | |
| 329 | /** |
| 330 | * @brief Transform expression from JSON format to XML format. |
| 331 | * Output arrays point to strings in the dictionary, but without |
| 332 | * correcting their ref_count -> do not touch them. Prefixes of |
| 333 | * the namespaces are prefixes specified by the module itself. Output |
| 334 | * parameters are optional, but either all 3 are set or none |
| 335 | * of them are. Logs directly. |
| 336 | * |
| 337 | * @param[in] module Module with imports to use. |
| 338 | * @param[in] expr JSON expression. |
| 339 | * @param[in] inst_id Whether to add prefixes to all node names (XML instance-identifier). |
| 340 | * @param[out] prefixes Array of pointers to prefixes. After use free them with free(*prefixes). |
| 341 | * Can be NULL. |
| 342 | * @param[out] namespaces Array of pointers to full namespaces. After use free them with |
| 343 | * free(*namespaces). Can be NULL. |
| 344 | * @param[out] ns_count Number of elements in both \p prefixes and \p namespaces arrays. |
| 345 | * Can be NULL. |
| 346 | * |
| 347 | * @return Transformed XML expression in the dictionary, NULL on error. |
| 348 | */ |
| 349 | const char *transform_json2xml(const struct lys_module *module, const char *expr, int inst_id, const char ***prefixes, |
| 350 | const char ***namespaces, uint32_t *ns_count); |
| 351 | |
| 352 | /** |
| 353 | * @brief Transform expression from JSON format to schema format. |
| 354 | * Prefixes of the namespaces (models) are those from the main |
| 355 | * \p module imports of the corresponding modules. Logs directly. |
| 356 | * |
| 357 | * @param[in] module Module with imports to use. |
| 358 | * @param[in] expr JSON expression. |
| 359 | * |
| 360 | * @return Transformed XML expression in the dictionary, NULL on error. |
| 361 | */ |
| 362 | const char *transform_json2schema(const struct lys_module *module, const char *expr); |
| 363 | |
| 364 | /** |
| 365 | * @brief Transform expression from XML data format (prefixes and separate NS definitions) to |
| 366 | * JSON format (prefixes are module names instead). Logs directly. |
| 367 | * |
| 368 | * @param[in] ctx libyang context to use. |
| 369 | * @param[in] expr XML expression. |
| 370 | * @param[in] xml XML element with the expression. |
| 371 | * @param[in] inst_id Whether all the node names must have a prefix (XML instance-identifier). |
| 372 | * @param[in] use_ctx_data_clb Whether to use data_clb in \p ctx if an unknown module namespace is found. |
| 373 | * |
| 374 | * @return Transformed JSON expression in the dictionary, NULL on error. |
| 375 | */ |
| 376 | const char *transform_xml2json(struct ly_ctx *ctx, const char *expr, struct lyxml_elem *xml, int inst_id, |
| 377 | int use_ctx_data_clb); |
| 378 | |
| 379 | /** |
| 380 | * @brief Transform expression from the schema format (prefixes of imports) to |
| 381 | * JSON format (prefixes are module names directly). Logs directly. |
| 382 | * |
| 383 | * @param[in] module Module (schema) with imports to search. |
| 384 | * @param[in] expr Expression from \p module. |
| 385 | * |
| 386 | * @return Transformed JSON expression in the dictionary, NULL on error. |
| 387 | */ |
| 388 | const char *transform_schema2json(const struct lys_module *module, const char *expr); |
| 389 | |
| 390 | /** |
| 391 | * @brief Same as transform_schema2json, but dumbed down, because if-feature expressions |
| 392 | * are not valid XPath expressions. |
| 393 | */ |
| 394 | const char *transform_iffeat_schema2json(const struct lys_module *module, const char *expr); |
| 395 | |
| 396 | /** |
| 397 | * @brief Transform an XPath expression in JSON node naming conventions into |
| 398 | * standard YANG XPath. |
| 399 | */ |
| 400 | char *transform_json2xpath(const struct lys_module *cur_module, const char *expr); |
| 401 | |
| 402 | /** |
| 403 | * @brief Get a new node (non-validated) validity value. |
| 404 | * |
| 405 | * @param[in] schema Schema node of the new data node. |
| 406 | * |
| 407 | * @return Validity of the new node. |
| 408 | */ |
| 409 | int ly_new_node_validity(const struct lys_node *schema); |
| 410 | |
| 411 | /** |
| 412 | * @brief Wrapper for realloc() call. The only difference is that if it fails to |
| 413 | * allocate the requested memory, the original memory is freed as well. |
| 414 | * |
| 415 | * @param[in] ptr Memory to reallocate. |
| 416 | * @param[in] size New size of the memory block. |
| 417 | * |
| 418 | * @return Pointer to the new memory, NULL on error. |
| 419 | */ |
| 420 | void *ly_realloc(void *ptr, size_t size); |
| 421 | |
| 422 | /** |
| 423 | * @brief Compare strings |
| 424 | * @param[in] s1 First string to compare |
| 425 | * @param[in] s2 Second string to compare |
| 426 | * @param[in] both_in_dictionary Flag for optimization, 1 if it is sure that \p s1 and \p s2 were stored in dictionary. |
| 427 | * This parameter is supposed to be a number (digit) known in compile time, not a variable or expression! |
| 428 | * @return 1 if both strings are the same, 0 if they differ. |
| 429 | */ |
| 430 | int ly_strequal_(const char *s1, const char *s2); |
| 431 | #define ly_strequal0(s1, s2) ly_strequal_(s1, s2) |
| 432 | #define ly_strequal1(s1, s2) (s1 == s2) |
| 433 | #define ly_strequal(s1, s2, d) ly_strequal##d(s1, s2) |
| 434 | |
| 435 | int64_t dec_pow(uint8_t exp); |
| 436 | |
| 437 | int dec64cmp(int64_t num1, uint8_t dig1, int64_t num2, uint8_t dig2); |
| 438 | |
| 439 | #endif /* LY_COMMON_H_ */ |