blob: 4c6bf9e462f3fe8480fd15478c03a5e574629dfe [file] [log] [blame]
Radek Krejci5aeea3a2018-09-05 13:29:36 +02001/**
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 <stdlib.h>
20
Radek Krejci2c22f122018-09-05 15:08:03 +020021#include "config.h"
Radek Krejciad573502018-09-07 15:26:55 +020022#include "log.h"
Radek Krejci5aeea3a2018-09-05 13:29:36 +020023
24#if __STDC_VERSION__ >= 201112 && !defined __STDC_NO_THREADS__
25# define THREAD_LOCAL _Thread_local
26#elif defined __GNUC__ || \
27 defined __SUNPRO_C || \
28 defined __xlC__
29# define THREAD_LOCAL __thread
30#else
31# error "Cannot define THREAD_LOCAL"
32#endif
33
34#define GETMACRO2(_1, _2, NAME, ...) NAME
35#define GETMACRO3(_1, _2, _3, NAME, ...) NAME
36#define GETMACRO4(_1, _2, _3, _4, NAME, ...) NAME
37
38/*
39 * logger
40 */
41
42/* internal logging options */
43enum int_log_opts {
44 ILO_LOG = 0, /* log normally */
45 ILO_STORE, /* only store any messages, they will be processed higher on stack */
46 ILO_IGNORE, /* completely ignore messages */
47 ILO_ERR2WRN, /* change errors to warnings */
48};
49
Radek Krejci94aa9942018-09-07 17:12:17 +020050enum LY_VLOG_ELEM {
51 LY_VLOG_NONE = 0,
52 LY_VLOG_LINE,/* line number */
53 LY_VLOG_LYS, /* struct lysc_node* */
54 LY_VLOG_LYD, /* struct lyd_node* */
55 LY_VLOG_STR, /* const char* */
56 LY_VLOG_PREV /* use exact same previous path */
57};
58
Radek Krejci5aeea3a2018-09-05 13:29:36 +020059extern THREAD_LOCAL enum int_log_opts log_opt;
60extern volatile uint8_t ly_log_level;
61extern volatile uint8_t ly_log_opts;
62
Radek Krejciad573502018-09-07 15:26:55 +020063void ly_err_free(void *ptr);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020064void ly_log(const struct ly_ctx *ctx, LY_LOG_LEVEL level, LY_ERR no, const char *format, ...);
Radek Krejci94aa9942018-09-07 17:12:17 +020065void ly_vlog(const struct ly_ctx *ctx, enum LY_VLOG_ELEM elem_type, const void *elem, LY_VECODE code, const char *format, ...);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020066
67#define LOGERR(ctx, errno, str, args...) ly_log(ctx, LY_LLERR, errno, str, ##args)
68#define LOGWRN(ctx, str, args...) ly_log(ctx, LY_LLWRN, 0, str, ##args)
69#define LOGVRB(str, args...) ly_log(NULL, LY_LLVRB, 0, str, ##args)
70
Radek Krejci4ab61562018-09-05 15:00:37 +020071#ifdef NDEBUG
72# define LOGDBG(dbg_group, str, args...)
73#else
74 void ly_log_dbg(int group, const char *format, ...);
75# define LOGDBG(dbg_group, str, args...) ly_log_dbg(dbg_group, str, ##args);
76#endif
77
Radek Krejci5aeea3a2018-09-05 13:29:36 +020078#define LOGMEM(CTX) LOGERR(CTX, LY_EMEM, "Memory allocation failed (%s()).", __func__)
79#define LOGINT(CTX) LOGERR(CTX, LY_EINT, "Internal error (%s:%d).", __FILE__, __LINE__)
80#define LOGARG(CTX, ARG) LOGERR(CTX, LY_EINVAL, "Invalid argument %s (%s()).", #ARG, __func__)
Michal Vasko58257712018-09-12 11:11:38 +020081#define LOGVAL(CTX, ELEM_TYPE, ELEM, CODE, FORMAT, ...) ly_vlog(CTX, ELEM_TYPE, ELEM, CODE, FORMAT __VA_OPT__(,) __VA_ARGS__)
Radek Krejci94aa9942018-09-07 17:12:17 +020082
83#define LOGMEM_RET(CTX) LOGMEM(CTX); return LY_EMEM
84#define LOGINT_RET(CTX) LOGINT(CTX); return LY_EINT
85#define LOGARG_RET(CTX) LOGARG(CTX); return LY_EINVAL
Radek Krejci5aeea3a2018-09-05 13:29:36 +020086
87/*
88 * Common code to check return value and perform appropriate action.
89 */
90#define LY_CHECK_GOTO(COND, GOTO) if (COND) {goto GOTO;}
91#define LY_CHECK_ERR_GOTO(COND, ERR, GOTO) if (COND) {ERR; goto GOTO;}
Michal Vaskob3d0d6b2018-09-07 10:17:33 +020092#define LY_CHECK_RET(COND, RETVAL) if (COND) {return RETVAL;}
93#define LY_CHECK_ERR_RET(COND, ERR, RETVAL) if (COND) {ERR; return RETVAL;}
Radek Krejci5aeea3a2018-09-05 13:29:36 +020094
Michal Vaskob3d0d6b2018-09-07 10:17:33 +020095#define LY_CHECK_ARG_GOTO1(CTX, ARG, GOTO) if (!ARG) {LOGARG(CTX, ARG);goto GOTO;}
96#define LY_CHECK_ARG_GOTO2(CTX, ARG1, ARG2, GOTO) LY_CHECK_ARG_GOTO1(CTX, ARG1, GOTO);LY_CHECK_ARG_GOTO1(CTX, ARG2, GOTO)
97#define LY_CHECK_ARG_GOTO3(CTX, ARG1, ARG2, ARG3, GOTO) LY_CHECK_ARG_GOTO2(CTX, ARG1, ARG2, GOTO);LY_CHECK_ARG_GOTO1(CTX, ARG3, GOTO)
98#define LY_CHECK_ARG_GOTO(CTX, ...) GETMACRO4(__VA_ARGS__, LY_CHECK_ARG_GOTO3, LY_CHECK_ARG_GOTO2, LY_CHECK_ARG_GOTO1)(CTX, __VA_ARGS__)
Radek Krejci5aeea3a2018-09-05 13:29:36 +020099
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200100#define LY_CHECK_ARG_RET1(CTX, ARG, RETVAL) if (!ARG) {LOGARG(CTX, ARG);return RETVAL;}
101#define LY_CHECK_ARG_RET2(CTX, ARG1, ARG2, RETVAL) LY_CHECK_ARG_RET1(CTX, ARG1, RETVAL);LY_CHECK_ARG_RET1(CTX, ARG2, RETVAL)
102#define LY_CHECK_ARG_RET3(CTX, ARG1, ARG2, ARG3, RETVAL) LY_CHECK_ARG_RET2(CTX, ARG1, ARG2, RETVAL);LY_CHECK_ARG_RET1(CTX, ARG3, RETVAL)
103#define LY_CHECK_ARG_RET(CTX, ...) GETMACRO4(__VA_ARGS__, LY_CHECK_ARG_RET3, LY_CHECK_ARG_RET2, LY_CHECK_ARG_RET1)(CTX, __VA_ARGS__)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200104
Michal Vasko58257712018-09-12 11:11:38 +0200105#define LY_VCODE_INCHAR LYVE_SYNTAX, "Invalid character 0x%x."
106#define LY_VCODE_INSTREXP LYVE_SYNTAX, "Invalid character sequence \"%.*s\", expected \"%s\"."
107#define LY_VCODE_EOF LYVE_SYNTAX, "Unexpected end-of-file."
Radek Krejci94aa9942018-09-07 17:12:17 +0200108#define LY_VCODE_INSTMT LYVE_SYNTAX_YANG, "Invalid keyword \"%s\"."
Michal Vasko58257712018-09-12 11:11:38 +0200109#define LY_VCODE_INCHILDSTMT LYVE_SYNTAX_YANG, "Invalid keyword \"%s\" as a child of \"%s\"."
110#define LY_VCODE_DUPSTMT LYVE_SYNTAX_YANG, "Duplicate keyword \"%s\"."
111#define LY_VCODE_INVAL LYVE_SYNTAX_YANG, "Invalid value \"%*.s\" of \"%s\"."
112#define LY_VCODE_MISSTMT LYVE_SYNTAX_YANG, "Missing mandatory keyword \"%s\" as a child of \"%s\"."
113#define LY_VCODE_INORD LYVE_SYNTAX_YANG, "Invalid keyword \"%s\", it cannot appear after \"%s\"."
114#define LY_VCODE_OOB LYVE_SYNTAX_YANG, "Value \"%*.s\" is out of \"%s\" bounds."
115#define LY_VCODE_INDEV LYVE_SYNTAX_YANG, "Deviate \"%s\" does not support keyword \"%s\"."
Radek Krejci94aa9942018-09-07 17:12:17 +0200116
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200117/*
118 * If the compiler supports attribute to mark objects as hidden, mark all
119 * objects as hidden and export only objects explicitly marked to be part of
120 * the public API.
121 */
122#define API __attribute__((visibility("default")))
123
Michal Vasko1324b6c2018-09-07 11:16:23 +0200124/*
125 * Generic useful functions.
126 */
127
128/**
129 * @brief Wrapper for realloc() call. The only difference is that if it fails to
130 * allocate the requested memory, the original memory is freed as well.
131 *
132 * @param[in] ptr Memory to reallocate.
133 * @param[in] size New size of the memory block.
134 *
135 * @return Pointer to the new memory, NULL on error.
136 */
137void *ly_realloc(void *ptr, size_t size);
138
Michal Vasko58257712018-09-12 11:11:38 +0200139int lysp_check_date(struct ly_ctx *ctx, const char *date, int date_len, const char *stmt);
Michal Vasko841d1a92018-09-07 15:40:31 +0200140
Michal Vasko1324b6c2018-09-07 11:16:23 +0200141/*
142 * Macros to work with lysp structures arrays.
143 *
144 * There is a byte allocated after the last item with value 0.
145 */
146#define LYSP_ARRAY_NEW_RET(CTX, ARRAY, NEW_ITEM, RETVAL) int _count; \
147 for (_count = 0; *(ARRAY) && *((uint8_t *)(*(ARRAY) + _count)); ++_count); \
148 if (!_count) *(ARRAY) = malloc(sizeof **(ARRAY) + 1); \
149 else *(ARRAY) = ly_realloc(*(ARRAY), (_count + 1) * sizeof **(ARRAY) + 1); \
150 LY_CHECK_ERR_RET(!*(ARRAY), LOGMEM(CTX), RETVAL); \
151 *((uint8_t *)(*(ARRAY) + _count + 1)) = 0; \
Michal Vasko50b70142018-09-07 13:26:29 +0200152 (NEW_ITEM) = (*(ARRAY)) + _count; \
153 memset(NEW_ITEM, 0, sizeof *(NEW_ITEM));
Michal Vasko1324b6c2018-09-07 11:16:23 +0200154
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200155#endif /* LY_COMMON_H_ */