| /** |
| * @file yl_opt.c |
| * @author Adam Piecek <piecek@cesnet.cz> |
| * @brief Settings options for the libyang context. |
| * |
| * Copyright (c) 2020 - 2023 CESNET, z.s.p.o. |
| * |
| * This source code is licensed under BSD 3-Clause License (the "License"). |
| * You may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * https://opensource.org/licenses/BSD-3-Clause |
| */ |
| |
| #define _GNU_SOURCE |
| |
| #include <assert.h> |
| #include <errno.h> |
| #include <getopt.h> |
| #include <strings.h> |
| |
| #include "in.h" /* ly_in_free */ |
| |
| #include "common.h" |
| #include "yl_opt.h" |
| |
| struct cmdline_file * |
| fill_cmdline_file(struct ly_set *set, struct ly_in *in, const char *path, LYD_FORMAT format) |
| { |
| struct cmdline_file *rec; |
| |
| rec = malloc(sizeof *rec); |
| if (!rec) { |
| YLMSG_E("Allocating memory for data file information failed.\n"); |
| return NULL; |
| } |
| rec->in = in; |
| rec->path = path; |
| rec->format = format; |
| |
| if (set && ly_set_add(set, rec, 1, NULL)) { |
| free(rec); |
| YLMSG_E("Storing data file information failed.\n"); |
| return NULL; |
| } |
| |
| return rec; |
| } |
| |
| void |
| free_cmdline_file_items(struct cmdline_file *rec) |
| { |
| if (rec && rec->in) { |
| ly_in_free(rec->in, 1); |
| } |
| } |
| |
| void |
| free_cmdline_file(void *cmdline_file) |
| { |
| struct cmdline_file *rec = (struct cmdline_file *)cmdline_file; |
| |
| if (rec) { |
| free_cmdline_file_items(rec); |
| free(rec); |
| } |
| } |
| |
| void |
| yl_opt_erase(struct yl_opt *yo) |
| { |
| ly_bool interactive; |
| |
| interactive = yo->interactive; |
| |
| /* data */ |
| ly_set_erase(&yo->data_inputs, free_cmdline_file); |
| ly_in_free(yo->data_operational.in, 1); |
| ly_set_erase(&yo->data_xpath, NULL); |
| |
| /* schema */ |
| ly_set_erase(&yo->schema_features, free_features); |
| ly_set_erase(&yo->schema_modules, NULL); |
| free(yo->features_output); |
| |
| /* context */ |
| free(yo->searchpaths); |
| |
| /* --reply-rpc */ |
| ly_in_free(yo->reply_rpc.in, 1); |
| |
| ly_out_free(yo->out, NULL, yo->out_stdout ? 0 : 1); |
| |
| free_cmdline(yo->argv); |
| |
| *yo = (const struct yl_opt) { |
| 0 |
| }; |
| yo->interactive = interactive; |
| } |
| |
| int |
| yl_opt_update_schema_out_format(const char *arg, struct yl_opt *yo) |
| { |
| if (!strcasecmp(arg, "yang")) { |
| yo->schema_out_format = LYS_OUT_YANG; |
| yo->data_out_format = 0; |
| } else if (!strcasecmp(arg, "yin")) { |
| yo->schema_out_format = LYS_OUT_YIN; |
| yo->data_out_format = 0; |
| } else if (!strcasecmp(arg, "info")) { |
| yo->schema_out_format = LYS_OUT_YANG_COMPILED; |
| yo->data_out_format = 0; |
| } else if (!strcasecmp(arg, "tree")) { |
| yo->schema_out_format = LYS_OUT_TREE; |
| yo->data_out_format = 0; |
| } else { |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| int |
| yl_opt_update_data_out_format(const char *arg, struct yl_opt *yo) |
| { |
| if (!strcasecmp(arg, "xml")) { |
| yo->schema_out_format = 0; |
| yo->data_out_format = LYD_XML; |
| } else if (!strcasecmp(arg, "json")) { |
| yo->schema_out_format = 0; |
| yo->data_out_format = LYD_JSON; |
| } else if (!strcasecmp(arg, "lyb")) { |
| yo->schema_out_format = 0; |
| yo->data_out_format = LYD_LYB; |
| } else { |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| static int |
| yl_opt_update_other_out_format(const char *arg, struct yl_opt *yo) |
| { |
| if (!strcasecmp(arg, "feature-param")) { |
| yo->feature_param_format = 1; |
| } else { |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| int |
| yl_opt_update_out_format(const char *arg, struct yl_opt *yo) |
| { |
| if (!yl_opt_update_schema_out_format(arg, yo)) { |
| return 0; |
| } |
| if (!yl_opt_update_data_out_format(arg, yo)) { |
| return 0; |
| } |
| if (!yl_opt_update_other_out_format(arg, yo)) { |
| return 0; |
| } |
| |
| YLMSG_E("Unknown output format %s\n", arg); |
| return 1; |
| } |
| |
| int |
| yl_opt_update_data_type(const char *arg, struct yl_opt *yo) |
| { |
| if (!strcasecmp(arg, "config")) { |
| yo->data_parse_options |= LYD_PARSE_NO_STATE; |
| yo->data_validate_options |= LYD_VALIDATE_NO_STATE; |
| } else if (!strcasecmp(arg, "get")) { |
| yo->data_parse_options |= LYD_PARSE_ONLY; |
| } else if (!strcasecmp(arg, "getconfig") || !strcasecmp(arg, "get-config") || !strcasecmp(arg, "edit")) { |
| yo->data_parse_options |= LYD_PARSE_ONLY | LYD_PARSE_NO_STATE; |
| } else if (!strcasecmp(arg, "rpc") || !strcasecmp(arg, "action")) { |
| yo->data_type = LYD_TYPE_RPC_YANG; |
| } else if (!strcasecmp(arg, "nc-rpc")) { |
| yo->data_type = LYD_TYPE_RPC_NETCONF; |
| } else if (!strcasecmp(arg, "reply") || !strcasecmp(arg, "rpcreply")) { |
| yo->data_type = LYD_TYPE_REPLY_YANG; |
| } else if (!strcasecmp(arg, "nc-reply")) { |
| yo->data_type = LYD_TYPE_REPLY_NETCONF; |
| } else if (!strcasecmp(arg, "notif") || !strcasecmp(arg, "notification")) { |
| yo->data_type = LYD_TYPE_NOTIF_YANG; |
| } else if (!strcasecmp(arg, "nc-notif")) { |
| yo->data_type = LYD_TYPE_NOTIF_NETCONF; |
| } else if (!strcasecmp(arg, "data")) { |
| /* default option */ |
| } else { |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| int |
| yo_opt_update_data_default(const char *arg, struct yl_opt *yo) |
| { |
| if (!strcasecmp(arg, "all")) { |
| yo->data_print_options = (yo->data_print_options & ~LYD_PRINT_WD_MASK) | LYD_PRINT_WD_ALL; |
| } else if (!strcasecmp(arg, "all-tagged")) { |
| yo->data_print_options = (yo->data_print_options & ~LYD_PRINT_WD_MASK) | LYD_PRINT_WD_ALL_TAG; |
| } else if (!strcasecmp(arg, "trim")) { |
| yo->data_print_options = (yo->data_print_options & ~LYD_PRINT_WD_MASK) | LYD_PRINT_WD_TRIM; |
| } else if (!strcasecmp(arg, "implicit-tagged")) { |
| yo->data_print_options = (yo->data_print_options & ~LYD_PRINT_WD_MASK) | LYD_PRINT_WD_IMPL_TAG; |
| } else { |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| void |
| free_cmdline(char *argv[]) |
| { |
| if (argv) { |
| free(argv[0]); |
| free(argv); |
| } |
| } |
| |
| int |
| parse_cmdline(const char *cmdline, int *argc_p, char **argv_p[]) |
| { |
| int count; |
| char **vector; |
| char *ptr; |
| char qmark = 0; |
| |
| assert(cmdline); |
| assert(argc_p); |
| assert(argv_p); |
| |
| /* init */ |
| optind = 0; /* reinitialize getopt() */ |
| count = 1; |
| vector = malloc((count + 1) * sizeof *vector); |
| vector[0] = strdup(cmdline); |
| |
| /* command name */ |
| strtok(vector[0], " "); |
| |
| /* arguments */ |
| while ((ptr = strtok(NULL, " "))) { |
| size_t len; |
| void *r; |
| |
| len = strlen(ptr); |
| |
| if (qmark) { |
| /* still in quotated text */ |
| /* remove NULL termination of the previous token since it is not a token, |
| * but a part of the quotation string */ |
| ptr[-1] = ' '; |
| |
| if ((ptr[len - 1] == qmark) && (ptr[len - 2] != '\\')) { |
| /* end of quotation */ |
| qmark = 0; |
| /* shorten the argument by the terminating quotation mark */ |
| ptr[len - 1] = '\0'; |
| } |
| continue; |
| } |
| |
| /* another token in cmdline */ |
| ++count; |
| r = realloc(vector, (count + 1) * sizeof *vector); |
| if (!r) { |
| YLMSG_E("Memory allocation failed (%s:%d, %s).\n", __FILE__, __LINE__, strerror(errno)); |
| free(vector); |
| return -1; |
| } |
| vector = r; |
| vector[count - 1] = ptr; |
| |
| if ((ptr[0] == '"') || (ptr[0] == '\'')) { |
| /* remember the quotation mark to identify end of quotation */ |
| qmark = ptr[0]; |
| |
| /* move the remembered argument after the quotation mark */ |
| ++vector[count - 1]; |
| |
| /* check if the quotation is terminated within this token */ |
| if ((ptr[len - 1] == qmark) && (ptr[len - 2] != '\\')) { |
| /* end of quotation */ |
| qmark = 0; |
| /* shorten the argument by the terminating quotation mark */ |
| ptr[len - 1] = '\0'; |
| } |
| } |
| } |
| vector[count] = NULL; |
| |
| *argc_p = count; |
| *argv_p = vector; |
| |
| return 0; |
| } |