Radek Krejci | d6b7645 | 2019-09-03 17:03:03 +0200 | [diff] [blame] | 1 | /** |
aPiecek | 023f83a | 2021-05-11 07:37:03 +0200 | [diff] [blame] | 2 | * @file metadata.c |
Radek Krejci | d6b7645 | 2019-09-03 17:03:03 +0200 | [diff] [blame] | 3 | * @author Radek Krejci <rkrejci@cesnet.cz> |
Michal Vasko | 193dacd | 2022-10-13 08:43:05 +0200 | [diff] [blame] | 4 | * @author Michal Vasko <mvasko@cesnet.cz> |
Radek Krejci | d6b7645 | 2019-09-03 17:03:03 +0200 | [diff] [blame] | 5 | * @brief libyang extension plugin - Metadata (RFC 7952) |
| 6 | * |
Michal Vasko | 193dacd | 2022-10-13 08:43:05 +0200 | [diff] [blame] | 7 | * Copyright (c) 2019 - 2022 CESNET, z.s.p.o. |
Radek Krejci | d6b7645 | 2019-09-03 17:03:03 +0200 | [diff] [blame] | 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 | */ |
Radek Krejci | d6b7645 | 2019-09-03 17:03:03 +0200 | [diff] [blame] | 15 | |
Radek Krejci | f1ca0ac | 2021-04-12 16:00:06 +0200 | [diff] [blame] | 16 | #include "metadata.h" |
Radek Krejci | 5f9a367 | 2021-03-05 21:35:22 +0100 | [diff] [blame] | 17 | |
Radek Krejci | 883355a | 2021-03-11 11:54:41 +0100 | [diff] [blame] | 18 | #include <stdint.h> |
| 19 | #include <stdlib.h> |
| 20 | #include <string.h> |
| 21 | |
| 22 | #include "libyang.h" |
| 23 | #include "plugins_exts.h" |
Radek Krejci | d6b7645 | 2019-09-03 17:03:03 +0200 | [diff] [blame] | 24 | |
Michal Vasko | 193dacd | 2022-10-13 08:43:05 +0200 | [diff] [blame] | 25 | struct lysp_ext_metadata { |
| 26 | struct lysp_type *type; /**< type of the metadata (mandatory) */ |
Radek Krejci | 1b2eef8 | 2021-02-17 11:17:27 +0100 | [diff] [blame] | 27 | const char *units; /**< units of the leaf's type */ |
Michal Vasko | 193dacd | 2022-10-13 08:43:05 +0200 | [diff] [blame] | 28 | struct lysp_qname *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */ |
Radek Krejci | 1b2eef8 | 2021-02-17 11:17:27 +0100 | [diff] [blame] | 29 | const char *dsc; /**< description */ |
| 30 | const char *ref; /**< reference */ |
| 31 | uint16_t flags; /**< [schema node flags](@ref snodeflags) - only LYS_STATUS_* values are allowed */ |
| 32 | }; |
Radek Krejci | 38d8536 | 2019-09-05 16:26:38 +0200 | [diff] [blame] | 33 | |
Michal Vasko | 193dacd | 2022-10-13 08:43:05 +0200 | [diff] [blame] | 34 | struct lysc_ext_metadata { |
| 35 | struct lysc_type *type; /**< type of the metadata (mandatory) */ |
| 36 | const char *units; /**< units of the leaf's type */ |
| 37 | const char *dsc; /**< description */ |
| 38 | const char *ref; /**< reference */ |
| 39 | uint16_t flags; /**< [schema node flags](@ref snodeflags) - only LYS_STATUS_* values are allowed */ |
| 40 | }; |
| 41 | |
| 42 | /** |
| 43 | * @brief Parse annotation extension instances. |
| 44 | * |
| 45 | * Implementation of ::lyplg_ext_parse_clb callback set as lyext_plugin::parse. |
| 46 | */ |
| 47 | static LY_ERR |
| 48 | annotation_parse(struct lysp_ctx *pctx, struct lysp_ext_instance *ext) |
| 49 | { |
| 50 | LY_ERR r; |
| 51 | struct lysp_ext_metadata *ann_pdata; |
| 52 | struct lysp_module *pmod; |
| 53 | LY_ARRAY_COUNT_TYPE u; |
| 54 | |
| 55 | /* annotations can appear only at the top level of a YANG module or submodule */ |
| 56 | if ((ext->parent_stmt != LY_STMT_MODULE) && (ext->parent_stmt != LY_STMT_SUBMODULE)) { |
| 57 | lyplg_ext_parse_log(pctx, ext, LY_LLERR, LY_EVALID, "Extension %s is allowed only at the top level of a YANG module or " |
| 58 | "submodule, but it is placed in \"%s\" statement.", ext->name, lyplg_ext_stmt2str(ext->parent_stmt)); |
| 59 | return LY_EVALID; |
| 60 | } |
| 61 | |
| 62 | pmod = ext->parent; |
| 63 | |
| 64 | /* check for duplication */ |
| 65 | LY_ARRAY_FOR(pmod->exts, u) { |
| 66 | if ((&pmod->exts[u] != ext) && (pmod->exts[u].name == ext->name) && !strcmp(pmod->exts[u].argument, ext->argument)) { |
| 67 | /* duplication of the same annotation extension in a single module */ |
| 68 | lyplg_ext_parse_log(pctx, ext, LY_LLERR, LY_EVALID, "Extension %s is instantiated multiple times.", ext->name); |
| 69 | return LY_EVALID; |
| 70 | } |
| 71 | } |
| 72 | |
| 73 | /* parse annotation substatements */ |
| 74 | ext->parsed = ann_pdata = calloc(1, sizeof *ann_pdata); |
| 75 | if (!ann_pdata) { |
| 76 | goto emem; |
| 77 | } |
Michal Vasko | a0ba01e | 2022-10-19 13:26:57 +0200 | [diff] [blame] | 78 | LY_ARRAY_CREATE_GOTO(lyplg_ext_parse_get_cur_pmod(pctx)->mod->ctx, ext->substmts, 6, r, emem); |
Michal Vasko | 193dacd | 2022-10-13 08:43:05 +0200 | [diff] [blame] | 79 | |
| 80 | LY_ARRAY_INCREMENT(ext->substmts); |
| 81 | ext->substmts[0].stmt = LY_STMT_IF_FEATURE; |
Michal Vasko | 909434e | 2024-06-13 16:08:37 +0200 | [diff] [blame] | 82 | ext->substmts[0].storage = (uint64_t)(uintptr_t)&ann_pdata->iffeatures; |
Michal Vasko | 193dacd | 2022-10-13 08:43:05 +0200 | [diff] [blame] | 83 | |
| 84 | LY_ARRAY_INCREMENT(ext->substmts); |
| 85 | ext->substmts[1].stmt = LY_STMT_UNITS; |
Michal Vasko | 909434e | 2024-06-13 16:08:37 +0200 | [diff] [blame] | 86 | ext->substmts[1].storage = (uint64_t)(uintptr_t)&ann_pdata->units; |
Michal Vasko | 193dacd | 2022-10-13 08:43:05 +0200 | [diff] [blame] | 87 | |
| 88 | LY_ARRAY_INCREMENT(ext->substmts); |
| 89 | ext->substmts[2].stmt = LY_STMT_STATUS; |
Michal Vasko | 909434e | 2024-06-13 16:08:37 +0200 | [diff] [blame] | 90 | ext->substmts[2].storage = (uint64_t)(uintptr_t)&ann_pdata->flags; |
Michal Vasko | 193dacd | 2022-10-13 08:43:05 +0200 | [diff] [blame] | 91 | |
| 92 | LY_ARRAY_INCREMENT(ext->substmts); |
| 93 | ext->substmts[3].stmt = LY_STMT_TYPE; |
Michal Vasko | 909434e | 2024-06-13 16:08:37 +0200 | [diff] [blame] | 94 | ext->substmts[3].storage = (uint64_t)(uintptr_t)&ann_pdata->type; |
Michal Vasko | 193dacd | 2022-10-13 08:43:05 +0200 | [diff] [blame] | 95 | |
| 96 | LY_ARRAY_INCREMENT(ext->substmts); |
| 97 | ext->substmts[4].stmt = LY_STMT_DESCRIPTION; |
Michal Vasko | 909434e | 2024-06-13 16:08:37 +0200 | [diff] [blame] | 98 | ext->substmts[4].storage = (uint64_t)(uintptr_t)&ann_pdata->dsc; |
Michal Vasko | 193dacd | 2022-10-13 08:43:05 +0200 | [diff] [blame] | 99 | |
| 100 | LY_ARRAY_INCREMENT(ext->substmts); |
| 101 | ext->substmts[5].stmt = LY_STMT_REFERENCE; |
Michal Vasko | 909434e | 2024-06-13 16:08:37 +0200 | [diff] [blame] | 102 | ext->substmts[5].storage = (uint64_t)(uintptr_t)&ann_pdata->ref; |
Michal Vasko | 193dacd | 2022-10-13 08:43:05 +0200 | [diff] [blame] | 103 | |
| 104 | if ((r = lyplg_ext_parse_extension_instance(pctx, ext))) { |
| 105 | return r; |
| 106 | } |
| 107 | |
| 108 | /* check for mandatory substatements */ |
| 109 | if (!ann_pdata->type) { |
| 110 | lyplg_ext_parse_log(pctx, ext, LY_LLERR, LY_EVALID, "Missing mandatory keyword \"type\" as a child of \"%s %s\".", |
| 111 | ext->name, ext->argument); |
| 112 | return LY_EVALID; |
| 113 | } |
| 114 | |
| 115 | return LY_SUCCESS; |
| 116 | |
| 117 | emem: |
| 118 | lyplg_ext_parse_log(pctx, ext, LY_LLERR, LY_EMEM, "Memory allocation failed (%s()).", __func__); |
| 119 | return LY_EMEM; |
| 120 | } |
| 121 | |
Radek Krejci | d6b7645 | 2019-09-03 17:03:03 +0200 | [diff] [blame] | 122 | /** |
| 123 | * @brief Compile annotation extension instances. |
| 124 | * |
Radek Krejci | 0b01330 | 2021-03-29 15:22:32 +0200 | [diff] [blame] | 125 | * Implementation of ::lyplg_ext_compile_clb callback set as lyext_plugin::compile. |
Radek Krejci | d6b7645 | 2019-09-03 17:03:03 +0200 | [diff] [blame] | 126 | */ |
Radek Krejci | 3e6632f | 2021-03-22 22:08:21 +0100 | [diff] [blame] | 127 | static LY_ERR |
Michal Vasko | 193dacd | 2022-10-13 08:43:05 +0200 | [diff] [blame] | 128 | annotation_compile(struct lysc_ctx *cctx, const struct lysp_ext_instance *extp, struct lysc_ext_instance *ext) |
Radek Krejci | d6b7645 | 2019-09-03 17:03:03 +0200 | [diff] [blame] | 129 | { |
Radek Krejci | 859a15a | 2021-03-05 20:56:59 +0100 | [diff] [blame] | 130 | LY_ERR ret; |
Michal Vasko | 193dacd | 2022-10-13 08:43:05 +0200 | [diff] [blame] | 131 | struct lysc_ext_metadata *ann_cdata; |
Radek Krejci | d6b7645 | 2019-09-03 17:03:03 +0200 | [diff] [blame] | 132 | |
| 133 | /* compile annotation substatements */ |
Michal Vasko | 193dacd | 2022-10-13 08:43:05 +0200 | [diff] [blame] | 134 | ext->compiled = ann_cdata = calloc(1, sizeof *ann_cdata); |
| 135 | if (!ann_cdata) { |
Radek Krejci | 859a15a | 2021-03-05 20:56:59 +0100 | [diff] [blame] | 136 | goto emem; |
Radek Krejci | 1b2eef8 | 2021-02-17 11:17:27 +0100 | [diff] [blame] | 137 | } |
Michal Vasko | 193dacd | 2022-10-13 08:43:05 +0200 | [diff] [blame] | 138 | LY_ARRAY_CREATE_GOTO(lysc_ctx_get_ctx(cctx), ext->substmts, 6, ret, emem); |
Radek Krejci | d6b7645 | 2019-09-03 17:03:03 +0200 | [diff] [blame] | 139 | |
Michal Vasko | 193dacd | 2022-10-13 08:43:05 +0200 | [diff] [blame] | 140 | LY_ARRAY_INCREMENT(ext->substmts); |
| 141 | ext->substmts[0].stmt = LY_STMT_IF_FEATURE; |
Michal Vasko | 708a8bf | 2024-06-13 09:44:51 +0200 | [diff] [blame] | 142 | ext->substmts[0].storage = 0; |
Radek Krejci | 1b2eef8 | 2021-02-17 11:17:27 +0100 | [diff] [blame] | 143 | |
Michal Vasko | 193dacd | 2022-10-13 08:43:05 +0200 | [diff] [blame] | 144 | LY_ARRAY_INCREMENT(ext->substmts); |
| 145 | ext->substmts[1].stmt = LY_STMT_UNITS; |
Michal Vasko | 909434e | 2024-06-13 16:08:37 +0200 | [diff] [blame] | 146 | ext->substmts[1].storage = (uint64_t)(uintptr_t)&ann_cdata->units; |
Radek Krejci | 1b2eef8 | 2021-02-17 11:17:27 +0100 | [diff] [blame] | 147 | |
Michal Vasko | 193dacd | 2022-10-13 08:43:05 +0200 | [diff] [blame] | 148 | LY_ARRAY_INCREMENT(ext->substmts); |
| 149 | ext->substmts[2].stmt = LY_STMT_STATUS; |
Michal Vasko | 909434e | 2024-06-13 16:08:37 +0200 | [diff] [blame] | 150 | ext->substmts[2].storage = (uint64_t)(uintptr_t)&ann_cdata->flags; |
Radek Krejci | 1b2eef8 | 2021-02-17 11:17:27 +0100 | [diff] [blame] | 151 | |
Michal Vasko | 193dacd | 2022-10-13 08:43:05 +0200 | [diff] [blame] | 152 | LY_ARRAY_INCREMENT(ext->substmts); |
| 153 | ext->substmts[3].stmt = LY_STMT_TYPE; |
Michal Vasko | 909434e | 2024-06-13 16:08:37 +0200 | [diff] [blame] | 154 | ext->substmts[3].storage = (uint64_t)(uintptr_t)&ann_cdata->type; |
Radek Krejci | 1b2eef8 | 2021-02-17 11:17:27 +0100 | [diff] [blame] | 155 | |
Michal Vasko | 193dacd | 2022-10-13 08:43:05 +0200 | [diff] [blame] | 156 | LY_ARRAY_INCREMENT(ext->substmts); |
| 157 | ext->substmts[4].stmt = LY_STMT_DESCRIPTION; |
Michal Vasko | 909434e | 2024-06-13 16:08:37 +0200 | [diff] [blame] | 158 | ext->substmts[4].storage = (uint64_t)(uintptr_t)&ann_cdata->dsc; |
Radek Krejci | 1b2eef8 | 2021-02-17 11:17:27 +0100 | [diff] [blame] | 159 | |
Michal Vasko | 193dacd | 2022-10-13 08:43:05 +0200 | [diff] [blame] | 160 | LY_ARRAY_INCREMENT(ext->substmts); |
| 161 | ext->substmts[5].stmt = LY_STMT_REFERENCE; |
Michal Vasko | 909434e | 2024-06-13 16:08:37 +0200 | [diff] [blame] | 162 | ext->substmts[5].storage = (uint64_t)(uintptr_t)&ann_cdata->ref; |
Radek Krejci | 1b2eef8 | 2021-02-17 11:17:27 +0100 | [diff] [blame] | 163 | |
Michal Vasko | 193dacd | 2022-10-13 08:43:05 +0200 | [diff] [blame] | 164 | ret = lyplg_ext_compile_extension_instance(cctx, extp, ext); |
Radek Krejci | 859a15a | 2021-03-05 20:56:59 +0100 | [diff] [blame] | 165 | return ret; |
Radek Krejci | d6b7645 | 2019-09-03 17:03:03 +0200 | [diff] [blame] | 166 | |
Radek Krejci | 859a15a | 2021-03-05 20:56:59 +0100 | [diff] [blame] | 167 | emem: |
Michal Vasko | 193dacd | 2022-10-13 08:43:05 +0200 | [diff] [blame] | 168 | lyplg_ext_compile_log(cctx, ext, LY_LLERR, LY_EMEM, "Memory allocation failed (%s()).", __func__); |
Radek Krejci | 859a15a | 2021-03-05 20:56:59 +0100 | [diff] [blame] | 169 | return LY_EMEM; |
Radek Krejci | d6b7645 | 2019-09-03 17:03:03 +0200 | [diff] [blame] | 170 | } |
| 171 | |
Radek Krejci | 38d8536 | 2019-09-05 16:26:38 +0200 | [diff] [blame] | 172 | /** |
Radek Krejci | adcf63d | 2021-02-09 10:21:18 +0100 | [diff] [blame] | 173 | * @brief INFO printer |
| 174 | * |
Michal Vasko | 941e056 | 2022-10-18 10:35:00 +0200 | [diff] [blame] | 175 | * Implementation of ::lyplg_ext_sprinter_info_clb set as ::lyext_plugin::printer_info |
Radek Krejci | adcf63d | 2021-02-09 10:21:18 +0100 | [diff] [blame] | 176 | */ |
Radek Krejci | 3e6632f | 2021-03-22 22:08:21 +0100 | [diff] [blame] | 177 | static LY_ERR |
Michal Vasko | 941e056 | 2022-10-18 10:35:00 +0200 | [diff] [blame] | 178 | annotation_printer_info(struct lyspr_ctx *ctx, struct lysc_ext_instance *ext, ly_bool *flag) |
Radek Krejci | adcf63d | 2021-02-09 10:21:18 +0100 | [diff] [blame] | 179 | { |
Michal Vasko | 941e056 | 2022-10-18 10:35:00 +0200 | [diff] [blame] | 180 | lyplg_ext_print_info_extension_instance(ctx, ext, flag); |
Radek Krejci | adcf63d | 2021-02-09 10:21:18 +0100 | [diff] [blame] | 181 | |
| 182 | return LY_SUCCESS; |
| 183 | } |
| 184 | |
| 185 | /** |
Michal Vasko | 193dacd | 2022-10-13 08:43:05 +0200 | [diff] [blame] | 186 | * @brief Free parsed annotation extension instance data. |
Radek Krejci | 38d8536 | 2019-09-05 16:26:38 +0200 | [diff] [blame] | 187 | * |
Michal Vasko | 193dacd | 2022-10-13 08:43:05 +0200 | [diff] [blame] | 188 | * Implementation of ::lyplg_ext_parse_free_clb callback set as ::lyext_plugin::pfree. |
Radek Krejci | 38d8536 | 2019-09-05 16:26:38 +0200 | [diff] [blame] | 189 | */ |
Radek Krejci | 3e6632f | 2021-03-22 22:08:21 +0100 | [diff] [blame] | 190 | static void |
Michal Vasko | 193dacd | 2022-10-13 08:43:05 +0200 | [diff] [blame] | 191 | annotation_pfree(const struct ly_ctx *ctx, struct lysp_ext_instance *ext) |
Radek Krejci | 38d8536 | 2019-09-05 16:26:38 +0200 | [diff] [blame] | 192 | { |
Radek Krejci | 1b2eef8 | 2021-02-17 11:17:27 +0100 | [diff] [blame] | 193 | if (!ext->substmts) { |
Radek Krejci | ad5963b | 2019-09-06 16:03:05 +0200 | [diff] [blame] | 194 | return; |
| 195 | } |
| 196 | |
Michal Vasko | 193dacd | 2022-10-13 08:43:05 +0200 | [diff] [blame] | 197 | lyplg_ext_pfree_instance_substatements(ctx, ext->substmts); |
| 198 | free(ext->parsed); |
| 199 | } |
| 200 | |
| 201 | /** |
| 202 | * @brief Free compiled annotation extension instance data. |
| 203 | * |
| 204 | * Implementation of ::lyplg_ext_compile_free_clb callback set as ::lyext_plugin::cfree. |
| 205 | */ |
| 206 | static void |
| 207 | annotation_cfree(const struct ly_ctx *ctx, struct lysc_ext_instance *ext) |
| 208 | { |
| 209 | if (!ext->substmts) { |
| 210 | return; |
| 211 | } |
| 212 | |
| 213 | lyplg_ext_cfree_instance_substatements(ctx, ext->substmts); |
| 214 | free(ext->compiled); |
Radek Krejci | 38d8536 | 2019-09-05 16:26:38 +0200 | [diff] [blame] | 215 | } |
Radek Krejci | d6b7645 | 2019-09-03 17:03:03 +0200 | [diff] [blame] | 216 | |
| 217 | /** |
Radek Krejci | 3e6632f | 2021-03-22 22:08:21 +0100 | [diff] [blame] | 218 | * @brief Plugin descriptions for the Metadata's annotation extension |
Radek Krejci | a6f61e7 | 2021-03-24 21:00:19 +0100 | [diff] [blame] | 219 | * |
| 220 | * Note that external plugins are supposed to use: |
| 221 | * |
| 222 | * LYPLG_EXTENSIONS = { |
Radek Krejci | d6b7645 | 2019-09-03 17:03:03 +0200 | [diff] [blame] | 223 | */ |
Radek Krejci | 3e6632f | 2021-03-22 22:08:21 +0100 | [diff] [blame] | 224 | const struct lyplg_ext_record plugins_metadata[] = { |
| 225 | { |
| 226 | .module = "ietf-yang-metadata", |
| 227 | .revision = "2016-08-05", |
| 228 | .name = "annotation", |
| 229 | |
Michal Vasko | 193dacd | 2022-10-13 08:43:05 +0200 | [diff] [blame] | 230 | .plugin.id = "ly2 metadata v1", |
| 231 | .plugin.parse = annotation_parse, |
| 232 | .plugin.compile = annotation_compile, |
Michal Vasko | 941e056 | 2022-10-18 10:35:00 +0200 | [diff] [blame] | 233 | .plugin.printer_info = annotation_printer_info, |
aPiecek | 03cb487 | 2022-10-24 10:31:51 +0200 | [diff] [blame] | 234 | .plugin.printer_ctree = NULL, |
| 235 | .plugin.printer_ptree = NULL, |
Michal Vasko | 135719f | 2022-08-25 12:18:17 +0200 | [diff] [blame] | 236 | .plugin.node = NULL, |
Michal Vasko | 8cc3f66 | 2022-03-29 11:25:51 +0200 | [diff] [blame] | 237 | .plugin.snode = NULL, |
Michal Vasko | 193dacd | 2022-10-13 08:43:05 +0200 | [diff] [blame] | 238 | .plugin.validate = NULL, |
| 239 | .plugin.pfree = annotation_pfree, |
| 240 | .plugin.cfree = annotation_cfree, |
Radek Krejci | 3e6632f | 2021-03-22 22:08:21 +0100 | [diff] [blame] | 241 | }, |
| 242 | {0} /* terminating zeroed record */ |
Radek Krejci | d6b7645 | 2019-09-03 17:03:03 +0200 | [diff] [blame] | 243 | }; |