blob: 37bf78c0b0162e0892594e28737fa49139636af6 [file] [log] [blame]
Radek Krejcie9f13b12020-11-09 17:42:04 +01001/**
2 * @file cmd_add.c
3 * @author Michal Vasko <mvasko@cesnet.cz>
4 * @author Radek Krejci <rkrejci@cesnet.cz>
5 * @brief 'add' command of the libyang's yanglint tool.
6 *
7 * Copyright (c) 2015-2020 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#define _GNU_SOURCE
17
18#include "cmd.h"
19
20#include <getopt.h>
Radek Krejcie9f13b12020-11-09 17:42:04 +010021#include <stdint.h>
22#include <stdio.h>
23#include <stdlib.h>
24
25#include "libyang.h"
26
27#include "common.h"
28
29void
30cmd_add_help(void)
31{
32 printf("Usage: add [-iD] <schema1> [<schema2> ...]\n"
33 " Add a new module from a specific file.\n\n"
34 " -D, --disable-searchdir\n"
35 " Do not implicitly search in current working directory for\n"
36 " the import schema modules. If specified a second time, do not\n"
37 " even search in the module directory (all modules must be \n"
38 " explicitly specified).\n"
39 " -F FEATURES, --features=FEATURES\n"
Michal Vasko703370c2021-10-19 14:07:16 +020040 " Features to support, default all in all implemented modules.\n"
roman300b8782022-08-11 12:49:21 +020041 " Specify separately for each module.\n"
Radek Krejcie9f13b12020-11-09 17:42:04 +010042 " <modname>:[<feature>,]*\n"
Michal Vasko8d6d0ad2021-10-19 12:32:27 +020043 " -i, --make-implemented\n"
Radek Krejcie9f13b12020-11-09 17:42:04 +010044 " Make the imported modules \"referenced\" from any loaded\n"
45 " <schema> module also implemented. If specified a second time,\n"
aPiecek88030e52023-06-02 11:03:57 +020046 " all the modules are set implemented.\n"
47 " -X, --extended-leafref\n"
48 " Allow usage of deref() XPath function within leafref.\n");
Radek Krejcie9f13b12020-11-09 17:42:04 +010049}
50
51void
52cmd_add(struct ly_ctx **ctx, const char *cmdline)
53{
54 int argc = 0;
55 char **argv = NULL;
56 int opt, opt_index;
57 struct option options[] = {
58 {"disable-searchdir", no_argument, NULL, 'D'},
59 {"features", required_argument, NULL, 'F'},
60 {"help", no_argument, NULL, 'h'},
Michal Vasko8d6d0ad2021-10-19 12:32:27 +020061 {"make-implemented", no_argument, NULL, 'i'},
aPiecek88030e52023-06-02 11:03:57 +020062 {"extended-leafref", no_argument, NULL, 'X'},
Radek Krejcie9f13b12020-11-09 17:42:04 +010063 {NULL, 0, NULL, 0}
64 };
65 uint16_t options_ctx = 0;
Michal Vasko584b0c42022-09-14 10:20:52 +020066 const char *all_features[] = {"*", NULL};
Radek Krejcie9f13b12020-11-09 17:42:04 +010067 struct ly_set fset = {0};
68
69 if (parse_cmdline(cmdline, &argc, &argv)) {
70 goto cleanup;
71 }
72
aPiecek15cc4cf2023-04-17 15:23:21 +020073 while ((opt = getopt_long(argc, argv, commands[CMD_ADD].optstring, options, &opt_index)) != -1) {
Radek Krejcie9f13b12020-11-09 17:42:04 +010074 switch (opt) {
75 case 'D': /* --disable--search */
76 if (options_ctx & LY_CTX_DISABLE_SEARCHDIRS) {
77 YLMSG_W("The -D option specified too many times.\n");
78 }
79 if (options_ctx & LY_CTX_DISABLE_SEARCHDIR_CWD) {
80 options_ctx &= ~LY_CTX_DISABLE_SEARCHDIR_CWD;
81 options_ctx |= LY_CTX_DISABLE_SEARCHDIRS;
82 } else {
83 options_ctx |= LY_CTX_DISABLE_SEARCHDIR_CWD;
84 }
85 break;
86
87 case 'F': /* --features */
88 if (parse_features(optarg, &fset)) {
89 goto cleanup;
90 }
91 break;
92
93 case 'h':
94 cmd_add_help();
95 goto cleanup;
96
Michal Vasko8d6d0ad2021-10-19 12:32:27 +020097 case 'i': /* --make-implemented */
Radek Krejcie9f13b12020-11-09 17:42:04 +010098 if (options_ctx & LY_CTX_REF_IMPLEMENTED) {
99 options_ctx &= ~LY_CTX_REF_IMPLEMENTED;
100 options_ctx |= LY_CTX_ALL_IMPLEMENTED;
101 } else {
102 options_ctx |= LY_CTX_REF_IMPLEMENTED;
103 }
104 break;
105
aPiecek88030e52023-06-02 11:03:57 +0200106 case 'X': /* --extended-leafref */
107 options_ctx |= LY_CTX_LEAFREF_EXTENDED;
108 break;
109
Radek Krejcie9f13b12020-11-09 17:42:04 +0100110 default:
111 YLMSG_E("Unknown option.\n");
112 goto cleanup;
113 }
114 }
115
116 if (argc == optind) {
117 /* no argument */
118 cmd_add_help();
119 goto cleanup;
120 }
121
Michal Vasko703370c2021-10-19 14:07:16 +0200122 if (!fset.count) {
123 /* no features, enable all of them */
124 options_ctx |= LY_CTX_ENABLE_IMP_FEATURES;
125 }
126
Radek Krejcie9f13b12020-11-09 17:42:04 +0100127 if (options_ctx) {
128 ly_ctx_set_options(*ctx, options_ctx);
129 }
130
131 for (int i = 0; i < argc - optind; i++) {
132 /* process the schema module files */
133 LY_ERR ret;
134 uint8_t path_unset = 1; /* flag to unset the path from the searchpaths list (if not already present) */
135 char *dir, *module;
136 const char **features = NULL;
137 struct ly_in *in = NULL;
138
139 if (parse_schema_path(argv[optind + i], &dir, &module)) {
140 goto cleanup;
141 }
142
143 /* add temporarily also the path of the module itself */
aPiecekfdd555d2023-03-27 14:26:01 +0200144 if (ly_ctx_set_searchdir(*ctx, dir) == LY_EEXIST) {
Radek Krejcie9f13b12020-11-09 17:42:04 +0100145 path_unset = 0;
146 }
147
148 /* get features list for this module */
Michal Vasko584b0c42022-09-14 10:20:52 +0200149 if (!fset.count) {
150 features = all_features;
151 } else {
152 get_features(&fset, module, &features);
153 }
Radek Krejcie9f13b12020-11-09 17:42:04 +0100154
155 /* temporary cleanup */
156 free(dir);
157 free(module);
158
159 /* prepare input handler */
160 ret = ly_in_new_filepath(argv[optind + i], 0, &in);
161 if (ret) {
162 goto cleanup;
163 }
164
165 /* parse the file */
166 ret = lys_parse(*ctx, in, LYS_IN_UNKNOWN, features, NULL);
167 ly_in_free(in, 1);
168 ly_ctx_unset_searchdir_last(*ctx, path_unset);
169
170 if (ret) {
171 /* libyang printed the error messages */
172 goto cleanup;
173 }
174 }
175
176cleanup:
177 if (options_ctx) {
178 ly_ctx_unset_options(*ctx, options_ctx);
179 }
180 ly_set_erase(&fset, free_features);
181 free_cmdline(argv);
182}