aPiecek | a83b8e0 | 2023-06-07 15:25:16 +0200 | [diff] [blame] | 1 | /** |
| 2 | * @file yl_opt.c |
| 3 | * @author Adam Piecek <piecek@cesnet.cz> |
| 4 | * @brief Settings options for the libyang context. |
| 5 | * |
| 6 | * Copyright (c) 2020 - 2023 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 | #define _GNU_SOURCE |
| 16 | |
| 17 | #include <assert.h> |
| 18 | #include <errno.h> |
| 19 | #include <getopt.h> |
| 20 | #include <strings.h> |
| 21 | |
| 22 | #include "in.h" /* ly_in_free */ |
| 23 | |
| 24 | #include "common.h" |
| 25 | #include "yl_opt.h" |
| 26 | |
| 27 | struct cmdline_file * |
| 28 | fill_cmdline_file(struct ly_set *set, struct ly_in *in, const char *path, LYD_FORMAT format) |
| 29 | { |
| 30 | struct cmdline_file *rec; |
| 31 | |
| 32 | rec = malloc(sizeof *rec); |
| 33 | if (!rec) { |
| 34 | YLMSG_E("Allocating memory for data file information failed.\n"); |
| 35 | return NULL; |
| 36 | } |
| 37 | rec->in = in; |
| 38 | rec->path = path; |
| 39 | rec->format = format; |
| 40 | |
| 41 | if (set && ly_set_add(set, rec, 1, NULL)) { |
| 42 | free(rec); |
| 43 | YLMSG_E("Storing data file information failed.\n"); |
| 44 | return NULL; |
| 45 | } |
| 46 | |
| 47 | return rec; |
| 48 | } |
| 49 | |
| 50 | void |
| 51 | free_cmdline_file_items(struct cmdline_file *rec) |
| 52 | { |
| 53 | if (rec && rec->in) { |
| 54 | ly_in_free(rec->in, 1); |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | void |
| 59 | free_cmdline_file(void *cmdline_file) |
| 60 | { |
| 61 | struct cmdline_file *rec = (struct cmdline_file *)cmdline_file; |
| 62 | |
| 63 | if (rec) { |
| 64 | free_cmdline_file_items(rec); |
| 65 | free(rec); |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | void |
| 70 | yl_opt_erase(struct yl_opt *yo) |
| 71 | { |
| 72 | ly_bool interactive; |
| 73 | |
| 74 | interactive = yo->interactive; |
| 75 | |
| 76 | /* data */ |
| 77 | ly_set_erase(&yo->data_inputs, free_cmdline_file); |
| 78 | ly_in_free(yo->data_operational.in, 1); |
| 79 | ly_set_erase(&yo->data_xpath, NULL); |
| 80 | |
| 81 | /* schema */ |
| 82 | ly_set_erase(&yo->schema_features, free_features); |
| 83 | ly_set_erase(&yo->schema_modules, NULL); |
| 84 | free(yo->features_output); |
| 85 | |
| 86 | /* context */ |
| 87 | free(yo->searchpaths); |
| 88 | |
| 89 | /* --reply-rpc */ |
| 90 | ly_in_free(yo->reply_rpc.in, 1); |
| 91 | |
| 92 | ly_out_free(yo->out, NULL, yo->out_stdout ? 0 : 1); |
| 93 | |
| 94 | free_cmdline(yo->argv); |
| 95 | |
| 96 | *yo = (const struct yl_opt) { |
| 97 | 0 |
| 98 | }; |
| 99 | yo->interactive = interactive; |
| 100 | } |
| 101 | |
aPiecek | 113e0f0 | 2023-06-09 08:47:48 +0200 | [diff] [blame] | 102 | int |
| 103 | yl_opt_update_schema_out_format(const char *arg, struct yl_opt *yo) |
| 104 | { |
| 105 | if (!strcasecmp(arg, "yang")) { |
| 106 | yo->schema_out_format = LYS_OUT_YANG; |
| 107 | yo->data_out_format = 0; |
| 108 | } else if (!strcasecmp(arg, "yin")) { |
| 109 | yo->schema_out_format = LYS_OUT_YIN; |
| 110 | yo->data_out_format = 0; |
| 111 | } else if (!strcasecmp(arg, "info")) { |
| 112 | yo->schema_out_format = LYS_OUT_YANG_COMPILED; |
| 113 | yo->data_out_format = 0; |
| 114 | } else if (!strcasecmp(arg, "tree")) { |
| 115 | yo->schema_out_format = LYS_OUT_TREE; |
| 116 | yo->data_out_format = 0; |
| 117 | } else { |
| 118 | return 1; |
| 119 | } |
| 120 | |
| 121 | return 0; |
| 122 | } |
| 123 | |
| 124 | int |
| 125 | yl_opt_update_data_out_format(const char *arg, struct yl_opt *yo) |
| 126 | { |
| 127 | if (!strcasecmp(arg, "xml")) { |
| 128 | yo->schema_out_format = 0; |
| 129 | yo->data_out_format = LYD_XML; |
| 130 | } else if (!strcasecmp(arg, "json")) { |
| 131 | yo->schema_out_format = 0; |
| 132 | yo->data_out_format = LYD_JSON; |
| 133 | } else if (!strcasecmp(arg, "lyb")) { |
| 134 | yo->schema_out_format = 0; |
| 135 | yo->data_out_format = LYD_LYB; |
| 136 | } else { |
| 137 | return 1; |
| 138 | } |
| 139 | |
| 140 | return 0; |
| 141 | } |
| 142 | |
| 143 | static int |
| 144 | yl_opt_update_other_out_format(const char *arg, struct yl_opt *yo) |
| 145 | { |
| 146 | if (!strcasecmp(arg, "feature-param")) { |
| 147 | yo->feature_param_format = 1; |
| 148 | } else { |
| 149 | return 1; |
| 150 | } |
| 151 | |
| 152 | return 0; |
| 153 | } |
| 154 | |
| 155 | int |
| 156 | yl_opt_update_out_format(const char *arg, struct yl_opt *yo) |
| 157 | { |
| 158 | if (!yl_opt_update_schema_out_format(arg, yo)) { |
| 159 | return 0; |
| 160 | } |
| 161 | if (!yl_opt_update_data_out_format(arg, yo)) { |
| 162 | return 0; |
| 163 | } |
| 164 | if (!yl_opt_update_other_out_format(arg, yo)) { |
| 165 | return 0; |
| 166 | } |
| 167 | |
| 168 | YLMSG_E("Unknown output format %s\n", arg); |
| 169 | return 1; |
| 170 | } |
| 171 | |
aPiecek | 3167f38 | 2023-06-09 09:23:10 +0200 | [diff] [blame] | 172 | int |
| 173 | yl_opt_update_data_type(const char *arg, struct yl_opt *yo) |
| 174 | { |
| 175 | if (!strcasecmp(arg, "config")) { |
| 176 | yo->data_parse_options |= LYD_PARSE_NO_STATE; |
| 177 | yo->data_validate_options |= LYD_VALIDATE_NO_STATE; |
| 178 | } else if (!strcasecmp(arg, "get")) { |
| 179 | yo->data_parse_options |= LYD_PARSE_ONLY; |
| 180 | } else if (!strcasecmp(arg, "getconfig") || !strcasecmp(arg, "get-config") || !strcasecmp(arg, "edit")) { |
| 181 | yo->data_parse_options |= LYD_PARSE_ONLY | LYD_PARSE_NO_STATE; |
| 182 | } else if (!strcasecmp(arg, "rpc") || !strcasecmp(arg, "action")) { |
| 183 | yo->data_type = LYD_TYPE_RPC_YANG; |
| 184 | } else if (!strcasecmp(arg, "nc-rpc")) { |
| 185 | yo->data_type = LYD_TYPE_RPC_NETCONF; |
| 186 | } else if (!strcasecmp(arg, "reply") || !strcasecmp(arg, "rpcreply")) { |
| 187 | yo->data_type = LYD_TYPE_REPLY_YANG; |
| 188 | } else if (!strcasecmp(arg, "nc-reply")) { |
| 189 | yo->data_type = LYD_TYPE_REPLY_NETCONF; |
| 190 | } else if (!strcasecmp(arg, "notif") || !strcasecmp(arg, "notification")) { |
| 191 | yo->data_type = LYD_TYPE_NOTIF_YANG; |
| 192 | } else if (!strcasecmp(arg, "nc-notif")) { |
| 193 | yo->data_type = LYD_TYPE_NOTIF_NETCONF; |
| 194 | } else if (!strcasecmp(arg, "data")) { |
| 195 | /* default option */ |
| 196 | } else { |
| 197 | return 1; |
| 198 | } |
| 199 | |
| 200 | return 0; |
| 201 | } |
| 202 | |
aPiecek | 20cc2fe | 2023-06-09 09:32:28 +0200 | [diff] [blame] | 203 | int |
| 204 | yo_opt_update_data_default(const char *arg, struct yl_opt *yo) |
| 205 | { |
| 206 | if (!strcasecmp(arg, "all")) { |
| 207 | yo->data_print_options = (yo->data_print_options & ~LYD_PRINT_WD_MASK) | LYD_PRINT_WD_ALL; |
| 208 | } else if (!strcasecmp(arg, "all-tagged")) { |
| 209 | yo->data_print_options = (yo->data_print_options & ~LYD_PRINT_WD_MASK) | LYD_PRINT_WD_ALL_TAG; |
| 210 | } else if (!strcasecmp(arg, "trim")) { |
| 211 | yo->data_print_options = (yo->data_print_options & ~LYD_PRINT_WD_MASK) | LYD_PRINT_WD_TRIM; |
| 212 | } else if (!strcasecmp(arg, "implicit-tagged")) { |
| 213 | yo->data_print_options = (yo->data_print_options & ~LYD_PRINT_WD_MASK) | LYD_PRINT_WD_IMPL_TAG; |
| 214 | } else { |
| 215 | return 1; |
| 216 | } |
| 217 | |
| 218 | return 0; |
| 219 | } |
| 220 | |
aPiecek | b5dff49 | 2023-06-09 09:38:08 +0200 | [diff] [blame] | 221 | int |
| 222 | yo_opt_update_data_in_format(const char *arg, struct yl_opt *yo) |
| 223 | { |
| 224 | if (!strcasecmp(arg, "xml")) { |
| 225 | yo->data_in_format = LYD_XML; |
| 226 | } else if (!strcasecmp(arg, "json")) { |
| 227 | yo->data_in_format = LYD_JSON; |
| 228 | } else if (!strcasecmp(arg, "lyb")) { |
| 229 | yo->data_in_format = LYD_LYB; |
| 230 | } else { |
| 231 | return 1; |
| 232 | } |
| 233 | |
| 234 | return 0; |
| 235 | } |
| 236 | |
aPiecek | a83b8e0 | 2023-06-07 15:25:16 +0200 | [diff] [blame] | 237 | void |
aPiecek | 7f22c10 | 2023-06-09 09:48:44 +0200 | [diff] [blame] | 238 | yo_opt_update_make_implemented(struct yl_opt *yo) |
| 239 | { |
| 240 | if (yo->ctx_options & LY_CTX_REF_IMPLEMENTED) { |
| 241 | yo->ctx_options &= ~LY_CTX_REF_IMPLEMENTED; |
| 242 | yo->ctx_options |= LY_CTX_ALL_IMPLEMENTED; |
| 243 | } else { |
| 244 | yo->ctx_options |= LY_CTX_REF_IMPLEMENTED; |
| 245 | } |
| 246 | } |
| 247 | |
| 248 | void |
aPiecek | 88ae15e | 2023-06-09 10:20:17 +0200 | [diff] [blame] | 249 | yo_opt_update_disable_searchdir(struct yl_opt *yo) |
| 250 | { |
| 251 | if (yo->ctx_options & LY_CTX_DISABLE_SEARCHDIR_CWD) { |
| 252 | yo->ctx_options &= ~LY_CTX_DISABLE_SEARCHDIR_CWD; |
| 253 | yo->ctx_options |= LY_CTX_DISABLE_SEARCHDIRS; |
| 254 | } else { |
| 255 | yo->ctx_options |= LY_CTX_DISABLE_SEARCHDIR_CWD; |
| 256 | } |
| 257 | } |
| 258 | |
| 259 | void |
aPiecek | a83b8e0 | 2023-06-07 15:25:16 +0200 | [diff] [blame] | 260 | free_cmdline(char *argv[]) |
| 261 | { |
| 262 | if (argv) { |
| 263 | free(argv[0]); |
| 264 | free(argv); |
| 265 | } |
| 266 | } |
| 267 | |
| 268 | int |
| 269 | parse_cmdline(const char *cmdline, int *argc_p, char **argv_p[]) |
| 270 | { |
| 271 | int count; |
| 272 | char **vector; |
| 273 | char *ptr; |
| 274 | char qmark = 0; |
| 275 | |
| 276 | assert(cmdline); |
| 277 | assert(argc_p); |
| 278 | assert(argv_p); |
| 279 | |
| 280 | /* init */ |
| 281 | optind = 0; /* reinitialize getopt() */ |
| 282 | count = 1; |
| 283 | vector = malloc((count + 1) * sizeof *vector); |
| 284 | vector[0] = strdup(cmdline); |
| 285 | |
| 286 | /* command name */ |
| 287 | strtok(vector[0], " "); |
| 288 | |
| 289 | /* arguments */ |
| 290 | while ((ptr = strtok(NULL, " "))) { |
| 291 | size_t len; |
| 292 | void *r; |
| 293 | |
| 294 | len = strlen(ptr); |
| 295 | |
| 296 | if (qmark) { |
| 297 | /* still in quotated text */ |
| 298 | /* remove NULL termination of the previous token since it is not a token, |
| 299 | * but a part of the quotation string */ |
| 300 | ptr[-1] = ' '; |
| 301 | |
| 302 | if ((ptr[len - 1] == qmark) && (ptr[len - 2] != '\\')) { |
| 303 | /* end of quotation */ |
| 304 | qmark = 0; |
| 305 | /* shorten the argument by the terminating quotation mark */ |
| 306 | ptr[len - 1] = '\0'; |
| 307 | } |
| 308 | continue; |
| 309 | } |
| 310 | |
| 311 | /* another token in cmdline */ |
| 312 | ++count; |
| 313 | r = realloc(vector, (count + 1) * sizeof *vector); |
| 314 | if (!r) { |
| 315 | YLMSG_E("Memory allocation failed (%s:%d, %s).\n", __FILE__, __LINE__, strerror(errno)); |
| 316 | free(vector); |
| 317 | return -1; |
| 318 | } |
| 319 | vector = r; |
| 320 | vector[count - 1] = ptr; |
| 321 | |
| 322 | if ((ptr[0] == '"') || (ptr[0] == '\'')) { |
| 323 | /* remember the quotation mark to identify end of quotation */ |
| 324 | qmark = ptr[0]; |
| 325 | |
| 326 | /* move the remembered argument after the quotation mark */ |
| 327 | ++vector[count - 1]; |
| 328 | |
| 329 | /* check if the quotation is terminated within this token */ |
| 330 | if ((ptr[len - 1] == qmark) && (ptr[len - 2] != '\\')) { |
| 331 | /* end of quotation */ |
| 332 | qmark = 0; |
| 333 | /* shorten the argument by the terminating quotation mark */ |
| 334 | ptr[len - 1] = '\0'; |
| 335 | } |
| 336 | } |
| 337 | } |
| 338 | vector[count] = NULL; |
| 339 | |
| 340 | *argc_p = count; |
| 341 | *argv_p = vector; |
| 342 | |
| 343 | return 0; |
| 344 | } |