/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 | | }; |