Coverage Report

Created: 2025-11-11 06:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libyang/src/plugins_exts/metadata.c
Line
Count
Source
1
/**
2
 * @file metadata.c
3
 * @author Radek Krejci <rkrejci@cesnet.cz>
4
 * @author Michal Vasko <mvasko@cesnet.cz>
5
 * @brief libyang extension plugin - Metadata (RFC 7952)
6
 *
7
 * Copyright (c) 2019 - 2025 CESNET, z.s.p.o.
8
 *
9
 * This source code is licensed under BSD 3-Clause License (the "License").
10
 * You may not use this file except in compliance with the License.
11
 * You may obtain a copy of the License at
12
 *
13
 *     https://opensource.org/licenses/BSD-3-Clause
14
 */
15
16
#include "metadata.h"
17
18
#include <stdint.h>
19
#include <stdlib.h>
20
#include <string.h>
21
22
#include "compat.h"
23
#include "libyang.h"
24
#include "plugins_exts.h"
25
26
struct lysp_ext_metadata {
27
    struct lysp_type *type;            /**< type of the metadata (mandatory) */
28
    const char *units;                 /**< units of the leaf's type */
29
    struct lysp_qname *iffeatures;     /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
30
    const char *dsc;                   /**< description */
31
    const char *ref;                   /**< reference */
32
    uint16_t flags;                    /**< [schema node flags](@ref snodeflags) - only LYS_STATUS_* values are allowed */
33
};
34
35
struct lysc_ext_metadata {
36
    struct lysc_type *type;            /**< type of the metadata (mandatory) */
37
    const char *units;                 /**< units of the leaf's type */
38
    const char *dsc;                   /**< description */
39
    const char *ref;                   /**< reference */
40
    uint16_t flags;                    /**< [schema node flags](@ref snodeflags) - only LYS_STATUS_* values are allowed */
41
};
42
43
/**
44
 * @brief Parse annotation extension instances.
45
 *
46
 * Implementation of ::lyplg_ext_parse_clb callback set as lyext_plugin::parse.
47
 */
48
static LY_ERR
49
annotation_parse(struct lysp_ctx *pctx, struct lysp_ext_instance *ext)
50
433k
{
51
433k
    LY_ERR r;
52
433k
    struct lysp_ext_metadata *ann_pdata;
53
433k
    struct lysp_module *pmod;
54
433k
    LY_ARRAY_COUNT_TYPE u;
55
56
    /* annotations can appear only at the top level of a YANG module or submodule */
57
433k
    if ((ext->parent_stmt != LY_STMT_MODULE) && (ext->parent_stmt != LY_STMT_SUBMODULE)) {
58
0
        lyplg_ext_parse_log(pctx, ext, LY_LLERR, LY_EVALID, "Extension %s is allowed only at the top level of a YANG module or "
59
0
                "submodule, but it is placed in \"%s\" statement.", ext->name, lyplg_ext_stmt2str(ext->parent_stmt));
60
0
        return LY_EVALID;
61
0
    }
62
63
433k
    pmod = ext->parent;
64
65
    /* check for duplication */
66
5.69M
    LY_ARRAY_FOR(pmod->exts, u) {
67
5.69M
        if ((&pmod->exts[u] != ext) && (pmod->exts[u].name == ext->name) && !strcmp(pmod->exts[u].argument, ext->argument)) {
68
            /* duplication of the same annotation extension in a single module */
69
0
            lyplg_ext_parse_log(pctx, ext, LY_LLERR, LY_EVALID, "Extension %s is instantiated multiple times.", ext->name);
70
0
            return LY_EVALID;
71
0
        }
72
5.69M
    }
73
74
    /* parse annotation substatements */
75
433k
    ext->parsed = ann_pdata = calloc(1, sizeof *ann_pdata);
76
433k
    if (!ann_pdata) {
77
0
        goto emem;
78
0
    }
79
867k
    LY_ARRAY_CREATE_GOTO(lyplg_ext_parse_get_cur_pmod(pctx)->mod->ctx, ext->substmts, 6, r, emem);
80
81
867k
    LY_ARRAY_INCREMENT(ext->substmts);
82
867k
    ext->substmts[0].stmt = LY_STMT_IF_FEATURE;
83
867k
    ext->substmts[0].storage_p = (void **)&ann_pdata->iffeatures;
84
85
867k
    LY_ARRAY_INCREMENT(ext->substmts);
86
867k
    ext->substmts[1].stmt = LY_STMT_UNITS;
87
867k
    ext->substmts[1].storage_p = (void **)&ann_pdata->units;
88
89
867k
    LY_ARRAY_INCREMENT(ext->substmts);
90
867k
    ext->substmts[2].stmt = LY_STMT_STATUS;
91
867k
    ext->substmts[2].storage_p = (void **)&ann_pdata->flags;
92
93
867k
    LY_ARRAY_INCREMENT(ext->substmts);
94
867k
    ext->substmts[3].stmt = LY_STMT_TYPE;
95
867k
    ext->substmts[3].storage_p = (void **)&ann_pdata->type;
96
97
867k
    LY_ARRAY_INCREMENT(ext->substmts);
98
867k
    ext->substmts[4].stmt = LY_STMT_DESCRIPTION;
99
867k
    ext->substmts[4].storage_p = (void **)&ann_pdata->dsc;
100
101
867k
    LY_ARRAY_INCREMENT(ext->substmts);
102
867k
    ext->substmts[5].stmt = LY_STMT_REFERENCE;
103
867k
    ext->substmts[5].storage_p = (void **)&ann_pdata->ref;
104
105
867k
    if ((r = lyplg_ext_parse_extension_instance(pctx, ext))) {
106
0
        return r;
107
0
    }
108
109
    /* check for mandatory substatements */
110
433k
    if (!ann_pdata->type) {
111
0
        lyplg_ext_parse_log(pctx, ext, LY_LLERR, LY_EVALID, "Missing mandatory keyword \"type\" as a child of \"%s %s\".",
112
0
                ext->name, ext->argument);
113
0
        return LY_EVALID;
114
0
    }
115
116
433k
    return LY_SUCCESS;
117
118
0
emem:
119
0
    lyplg_ext_parse_log(pctx, ext, LY_LLERR, LY_EMEM, "Memory allocation failed (%s()).", __func__);
120
0
    return LY_EMEM;
121
433k
}
122
123
/**
124
 * @brief Compile annotation extension instances.
125
 *
126
 * Implementation of ::lyplg_ext_compile_clb callback set as lyext_plugin::compile.
127
 */
128
static LY_ERR
129
annotation_compile(struct lysc_ctx *cctx, const struct lysp_ext_instance *extp, struct lysc_ext_instance *ext)
130
433k
{
131
433k
    LY_ERR ret;
132
433k
    struct lysc_ext_metadata *ann_cdata;
133
134
    /* compile annotation substatements */
135
433k
    ext->compiled = ann_cdata = calloc(1, sizeof *ann_cdata);
136
433k
    if (!ann_cdata) {
137
0
        goto emem;
138
0
    }
139
433k
    LY_ARRAY_CREATE_GOTO(lysc_ctx_get_ctx(cctx), ext->substmts, 6, ret, emem);
140
141
433k
    LY_ARRAY_INCREMENT(ext->substmts);
142
433k
    ext->substmts[0].stmt = LY_STMT_IF_FEATURE;
143
433k
    ext->substmts[0].storage_p = NULL;
144
145
433k
    LY_ARRAY_INCREMENT(ext->substmts);
146
433k
    ext->substmts[1].stmt = LY_STMT_UNITS;
147
433k
    ext->substmts[1].storage_p = (void **)&ann_cdata->units;
148
149
433k
    LY_ARRAY_INCREMENT(ext->substmts);
150
433k
    ext->substmts[2].stmt = LY_STMT_STATUS;
151
433k
    ext->substmts[2].storage_p = (void **)&ann_cdata->flags;
152
153
433k
    LY_ARRAY_INCREMENT(ext->substmts);
154
433k
    ext->substmts[3].stmt = LY_STMT_TYPE;
155
433k
    ext->substmts[3].storage_p = (void **)&ann_cdata->type;
156
157
433k
    LY_ARRAY_INCREMENT(ext->substmts);
158
433k
    ext->substmts[4].stmt = LY_STMT_DESCRIPTION;
159
433k
    ext->substmts[4].storage_p = (void **)&ann_cdata->dsc;
160
161
433k
    LY_ARRAY_INCREMENT(ext->substmts);
162
433k
    ext->substmts[5].stmt = LY_STMT_REFERENCE;
163
433k
    ext->substmts[5].storage_p = (void **)&ann_cdata->ref;
164
165
433k
    ret = lyplg_ext_compile_extension_instance(cctx, extp, ext, NULL);
166
433k
    return ret;
167
168
0
emem:
169
0
    lyplg_ext_compile_log(cctx, ext, LY_LLERR, LY_EMEM, "Memory allocation failed (%s()).", __func__);
170
0
    return LY_EMEM;
171
433k
}
172
173
/**
174
 * @brief INFO printer
175
 *
176
 * Implementation of ::lyplg_ext_sprinter_info_clb set as ::lyext_plugin::printer_info
177
 */
178
static LY_ERR
179
annotation_printer_info(struct lyspr_ctx *ctx, struct lysc_ext_instance *ext, ly_bool *flag)
180
0
{
181
0
    lyplg_ext_print_info_extension_instance(ctx, ext, flag);
182
183
0
    return LY_SUCCESS;
184
0
}
185
186
/**
187
 * @brief Free parsed annotation extension instance data.
188
 *
189
 * Implementation of ::lyplg_ext_parse_free_clb callback set as ::lyext_plugin::pfree.
190
 */
191
static void
192
annotation_pfree(const struct ly_ctx *ctx, struct lysp_ext_instance *ext)
193
433k
{
194
433k
    if (!ext->substmts) {
195
0
        return;
196
0
    }
197
198
433k
    lyplg_ext_pfree_instance_substatements(ctx, ext->substmts);
199
433k
    free(ext->parsed);
200
433k
}
201
202
/**
203
 * @brief Free compiled annotation extension instance data.
204
 *
205
 * Implementation of ::lyplg_ext_compile_free_clb callback set as ::lyext_plugin::cfree.
206
 */
207
static void
208
annotation_cfree(const struct ly_ctx *ctx, struct lysc_ext_instance *ext)
209
433k
{
210
433k
    if (!ext->substmts) {
211
0
        return;
212
0
    }
213
214
433k
    lyplg_ext_cfree_instance_substatements(ctx, ext->substmts);
215
433k
    free(ext->compiled);
216
433k
}
217
218
static int
219
annotation_compiled_size(const struct lysc_ext_instance *ext, struct ly_ht *addr_ht)
220
0
{
221
0
    int size = 0;
222
223
0
    size += sizeof(struct lysc_ext_metadata);
224
0
    size += lyplg_ext_compiled_stmts_storage_size(ext->substmts, addr_ht);
225
226
0
    return size;
227
0
}
228
229
static LY_ERR
230
annotation_compiled_print(const struct lysc_ext_instance *orig_ext, struct lysc_ext_instance *ext,
231
        struct ly_ht *addr_ht, struct ly_set *ptr_set, void **mem)
232
0
{
233
0
    struct lysc_ext_metadata *ann_cdata;
234
235
0
    ann_cdata = ext->compiled = *mem;
236
0
    *mem = (char *)*mem + sizeof *ann_cdata;
237
0
    memset(ann_cdata, 0, sizeof *ann_cdata);
238
239
0
    ext->substmts[1].storage_p = (void **)&ann_cdata->units;
240
0
    ext->substmts[2].storage_p = (void **)&ann_cdata->flags;
241
0
    ext->substmts[3].storage_p = (void **)&ann_cdata->type;
242
0
    ext->substmts[4].storage_p = (void **)&ann_cdata->dsc;
243
0
    ext->substmts[5].storage_p = (void **)&ann_cdata->ref;
244
245
0
    return lyplg_ext_compiled_stmts_storage_print(orig_ext->substmts, ext->substmts, addr_ht, ptr_set, mem);
246
0
}
247
248
/**
249
 * @brief Plugin descriptions for the Metadata's annotation extension
250
 *
251
 * Note that external plugins are supposed to use:
252
 *
253
 *   LYPLG_EXTENSIONS = {
254
 */
255
const struct lyplg_ext_record plugins_metadata[] = {
256
    {
257
        .module = "ietf-yang-metadata",
258
        .revision = "2016-08-05",
259
        .name = "annotation",
260
261
        .plugin.id = "ly2 metadata",
262
        .plugin.parse = annotation_parse,
263
        .plugin.compile = annotation_compile,
264
        .plugin.printer_info = annotation_printer_info,
265
        .plugin.printer_ctree = NULL,
266
        .plugin.printer_ptree = NULL,
267
        .plugin.node_xpath = NULL,
268
        .plugin.snode = NULL,
269
        .plugin.validate = NULL,
270
        .plugin.pfree = annotation_pfree,
271
        .plugin.cfree = annotation_cfree,
272
        .plugin.compiled_size = annotation_compiled_size,
273
        .plugin.compiled_print = annotation_compiled_print
274
    },
275
    {0}     /* terminating zeroed record */
276
};