blob: 1d21eb8b79a4471d12f4817d8b19128e25603e7a [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"
26
27struct cmdline_file *
28fill_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
50void
51free_cmdline_file_items(struct cmdline_file *rec)
52{
53 if (rec && rec->in) {
54 ly_in_free(rec->in, 1);
55 }
56}
57
58void
59free_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
69void
70yl_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
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
168 YLMSG_E("Unknown output format %s\n", arg);
169 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
aPieceka83b8e02023-06-07 15:25:16 +0200249free_cmdline(char *argv[])
250{
251 if (argv) {
252 free(argv[0]);
253 free(argv);
254 }
255}
256
257int
258parse_cmdline(const char *cmdline, int *argc_p, char **argv_p[])
259{
260 int count;
261 char **vector;
262 char *ptr;
263 char qmark = 0;
264
265 assert(cmdline);
266 assert(argc_p);
267 assert(argv_p);
268
269 /* init */
270 optind = 0; /* reinitialize getopt() */
271 count = 1;
272 vector = malloc((count + 1) * sizeof *vector);
273 vector[0] = strdup(cmdline);
274
275 /* command name */
276 strtok(vector[0], " ");
277
278 /* arguments */
279 while ((ptr = strtok(NULL, " "))) {
280 size_t len;
281 void *r;
282
283 len = strlen(ptr);
284
285 if (qmark) {
286 /* still in quotated text */
287 /* remove NULL termination of the previous token since it is not a token,
288 * but a part of the quotation string */
289 ptr[-1] = ' ';
290
291 if ((ptr[len - 1] == qmark) && (ptr[len - 2] != '\\')) {
292 /* end of quotation */
293 qmark = 0;
294 /* shorten the argument by the terminating quotation mark */
295 ptr[len - 1] = '\0';
296 }
297 continue;
298 }
299
300 /* another token in cmdline */
301 ++count;
302 r = realloc(vector, (count + 1) * sizeof *vector);
303 if (!r) {
304 YLMSG_E("Memory allocation failed (%s:%d, %s).\n", __FILE__, __LINE__, strerror(errno));
305 free(vector);
306 return -1;
307 }
308 vector = r;
309 vector[count - 1] = ptr;
310
311 if ((ptr[0] == '"') || (ptr[0] == '\'')) {
312 /* remember the quotation mark to identify end of quotation */
313 qmark = ptr[0];
314
315 /* move the remembered argument after the quotation mark */
316 ++vector[count - 1];
317
318 /* check if the quotation is terminated within this token */
319 if ((ptr[len - 1] == qmark) && (ptr[len - 2] != '\\')) {
320 /* end of quotation */
321 qmark = 0;
322 /* shorten the argument by the terminating quotation mark */
323 ptr[len - 1] = '\0';
324 }
325 }
326 }
327 vector[count] = NULL;
328
329 *argc_p = count;
330 *argv_p = vector;
331
332 return 0;
333}