/** * @file yl_opt.c * @author Adam Piecek * @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 #include #include #include #include "in.h" /* ly_in_free */ #include "common.h" #include "yl_opt.h" #include "yl_schema_features.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."); 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."); 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, yl_schema_features_free); ly_set_erase(&yo->schema_modules, NULL); /* 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.", 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; } int yo_opt_update_data_in_format(const char *arg, struct yl_opt *yo) { if (!strcasecmp(arg, "xml")) { yo->data_in_format = LYD_XML; } else if (!strcasecmp(arg, "json")) { yo->data_in_format = LYD_JSON; } else if (!strcasecmp(arg, "lyb")) { yo->data_in_format = LYD_LYB; } else { return 1; } return 0; } void yo_opt_update_make_implemented(struct yl_opt *yo) { if (yo->ctx_options & LY_CTX_REF_IMPLEMENTED) { yo->ctx_options &= ~LY_CTX_REF_IMPLEMENTED; yo->ctx_options |= LY_CTX_ALL_IMPLEMENTED; } else { yo->ctx_options |= LY_CTX_REF_IMPLEMENTED; } } void yo_opt_update_disable_searchdir(struct yl_opt *yo) { if (yo->ctx_options & LY_CTX_DISABLE_SEARCHDIR_CWD) { yo->ctx_options &= ~LY_CTX_DISABLE_SEARCHDIR_CWD; yo->ctx_options |= LY_CTX_DISABLE_SEARCHDIRS; } else { yo->ctx_options |= LY_CTX_DISABLE_SEARCHDIR_CWD; } } 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).", __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; }