blob: 7cd855f4576fe7e444f11fb34a869a83083a46ba [file] [log] [blame]
aPieceka83b8e02023-06-07 15:25:16 +02001/**
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"
aPiecekd8f002f2023-06-21 10:40:41 +020026#include "yl_schema_features.h"
aPieceka83b8e02023-06-07 15:25:16 +020027
28struct cmdline_file *
29fill_cmdline_file(struct ly_set *set, struct ly_in *in, const char *path, LYD_FORMAT format)
30{
31 struct cmdline_file *rec;
32
33 rec = malloc(sizeof *rec);
34 if (!rec) {
Michal Vasko1407d7d2023-08-21 09:57:54 +020035 YLMSG_E("Allocating memory for data file information failed.");
aPieceka83b8e02023-06-07 15:25:16 +020036 return NULL;
37 }
38 rec->in = in;
39 rec->path = path;
40 rec->format = format;
41
42 if (set && ly_set_add(set, rec, 1, NULL)) {
43 free(rec);
Michal Vasko1407d7d2023-08-21 09:57:54 +020044 YLMSG_E("Storing data file information failed.");
aPieceka83b8e02023-06-07 15:25:16 +020045 return NULL;
46 }
47
48 return rec;
49}
50
51void
52free_cmdline_file_items(struct cmdline_file *rec)
53{
54 if (rec && rec->in) {
55 ly_in_free(rec->in, 1);
56 }
57}
58
59void
60free_cmdline_file(void *cmdline_file)
61{
62 struct cmdline_file *rec = (struct cmdline_file *)cmdline_file;
63
64 if (rec) {
65 free_cmdline_file_items(rec);
66 free(rec);
67 }
68}
69
70void
71yl_opt_erase(struct yl_opt *yo)
72{
73 ly_bool interactive;
74
75 interactive = yo->interactive;
76
77 /* data */
78 ly_set_erase(&yo->data_inputs, free_cmdline_file);
79 ly_in_free(yo->data_operational.in, 1);
80 ly_set_erase(&yo->data_xpath, NULL);
81
82 /* schema */
aPiecekd8f002f2023-06-21 10:40:41 +020083 ly_set_erase(&yo->schema_features, yl_schema_features_free);
aPieceka83b8e02023-06-07 15:25:16 +020084 ly_set_erase(&yo->schema_modules, NULL);
aPieceka83b8e02023-06-07 15:25:16 +020085
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
aPiecek113e0f02023-06-09 08:47:48 +0200102int
103yl_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
124int
125yl_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
143static int
144yl_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
155int
156yl_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
Michal Vasko1407d7d2023-08-21 09:57:54 +0200168 YLMSG_E("Unknown output format %s.", arg);
aPiecek113e0f02023-06-09 08:47:48 +0200169 return 1;
170}
171
aPiecek3167f382023-06-09 09:23:10 +0200172int
173yl_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
aPiecek20cc2fe2023-06-09 09:32:28 +0200203int
204yo_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
aPiecekb5dff492023-06-09 09:38:08 +0200221int
222yo_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
aPieceka83b8e02023-06-07 15:25:16 +0200237void
aPiecek7f22c102023-06-09 09:48:44 +0200238yo_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
248void
aPiecek88ae15e2023-06-09 10:20:17 +0200249yo_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
259void
aPieceka83b8e02023-06-07 15:25:16 +0200260free_cmdline(char *argv[])
261{
262 if (argv) {
263 free(argv[0]);
264 free(argv);
265 }
266}
267
268int
269parse_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) {
Michal Vasko1407d7d2023-08-21 09:57:54 +0200315 YLMSG_E("Memory allocation failed (%s:%d, %s).", __FILE__, __LINE__, strerror(errno));
aPieceka83b8e02023-06-07 15:25:16 +0200316 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}