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