blob: 44f2dff706a9633dc064034915b923d19db2603c [file] [log] [blame]
Michal Vaskoe0cb2522015-07-01 10:24:53 +02001/**
2 * @file commands.c
3 * @author Michal Vasko <mvasko@cesnet.cz>
4 * @brief libyang's yanglint tool commands
Michal Vaskof3e59f12015-06-18 11:53:56 +02005 *
Michal Vaskoe0cb2522015-07-01 10:24:53 +02006 * Copyright (c) 2015 CESNET, z.s.p.o.
Michal Vaskof3e59f12015-06-18 11:53:56 +02007 *
Radek Krejci54f6fb32016-02-24 12:56:39 +01008 * 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
Michal Vasko10e89e72016-03-01 16:00:27 +010011 *
Radek Krejci54f6fb32016-02-24 12:56:39 +010012 * https://opensource.org/licenses/BSD-3-Clause
Michal Vaskof3e59f12015-06-18 11:53:56 +020013 */
Michal Vaskoe0cb2522015-07-01 10:24:53 +020014
Michal Vaskof3e59f12015-06-18 11:53:56 +020015#include <string.h>
16#include <stdio.h>
17#include <errno.h>
Michal Vasko662610a2015-12-07 11:25:45 +010018#include <assert.h>
Michal Vaskof3e59f12015-06-18 11:53:56 +020019#include <sys/types.h>
20#include <sys/stat.h>
Michal Vaskof3e59f12015-06-18 11:53:56 +020021#include <unistd.h>
22#include <getopt.h>
23
Michal Vasko203b4e72015-06-30 15:25:15 +020024#include "commands.h"
Michal Vaskof3e59f12015-06-18 11:53:56 +020025#include "../../src/libyang.h"
Michal Vasko2d162e12015-09-24 14:33:29 +020026#include "../../src/tree_schema.h"
27#include "../../src/tree_data.h"
Michal Vasko520d4732015-07-13 15:53:33 +020028#include "../../src/parser.h"
Michal Vaskoabbdaa02015-10-06 15:47:25 +020029#include "../../src/xpath.h"
Michal Vaskof3e59f12015-06-18 11:53:56 +020030
Michal Vasko203b4e72015-06-30 15:25:15 +020031COMMAND commands[];
Michal Vaskof3e59f12015-06-18 11:53:56 +020032extern int done;
33extern struct ly_ctx *ctx;
Michal Vaskof3e59f12015-06-18 11:53:56 +020034
35void
Michal Vaskof3e59f12015-06-18 11:53:56 +020036cmd_add_help(void)
37{
Michal Vasko370d9102015-08-21 13:06:11 +020038 printf("add <path-to-model> [<other-models> ...]\n");
Michal Vaskof3e59f12015-06-18 11:53:56 +020039}
40
41void
42cmd_print_help(void)
43{
Michal Vasko5d51c0a2016-02-05 14:29:54 +010044 printf("print [-f (yang | yin | tree | info)] [-t <info-target-node>] [-o <output-file>] <model-name>[@<revision>]\n\n");
Michal Vasko7df7f142015-07-15 12:10:53 +020045 printf("\tinfo-target-node: <absolute-schema-node> | typedef/<typedef-name> |\n");
Michal Vasko035f5232015-07-15 12:26:52 +020046 printf("\t | identity/<identity-name> | feature/<feature-name> |\n");
Michal Vaskod04dbea2015-08-06 15:10:19 +020047 printf("\t | grouping/<grouping-name>(<absolute-schema-nodeid>) |\n");
Michal Vasko035f5232015-07-15 12:26:52 +020048 printf("\t | type/<absolute-schema-node-leaf-or-leaflist>\n");
Michal Vaskod04dbea2015-08-06 15:10:19 +020049 printf("\n");
50 printf("\tabsolute-schema-nodeid: ( /(<import-prefix>:)<node-identifier> )+\n");
Michal Vaskof3e59f12015-06-18 11:53:56 +020051}
52
53void
Michal Vasko520d4732015-07-13 15:53:33 +020054cmd_data_help(void)
55{
Radek Krejci4bfa6642016-03-23 15:57:45 +010056 printf("data [-(-s)trict] [-x OPTION] [-d DEFAULTS] [-o <output-file>] [-f (xml | json)] <data-file-name>\n");
Radek Krejci9a716122015-12-15 15:15:32 +010057 printf("Accepted OPTIONs:\n");
Radek Krejci4a2aad82016-01-13 15:01:07 +010058 printf("\tauto - resolve data type (one of the following) automatically (as pyang does),\n");
59 printf("\t this option is applicable only in case of XML input data.\n");
Radek Krejci4a49bdf2016-01-12 17:17:01 +010060 printf("\tconfig - LYD_OPT_CONFIG\n");
Radek Krejci9a716122015-12-15 15:15:32 +010061 printf("\tget - LYD_OPT_GET\n");
62 printf("\tgetconfig - LYD_OPT_GETCONFIG\n");
Radek Krejci4a49bdf2016-01-12 17:17:01 +010063 printf("\tedit - LYD_OPT_EDIT\n");
64 printf("\trpc - LYD_OPT_RPC\n");
65 /* printf("\trpcreply - LYD_OPT_RPCREPLY\n"); */
Radek Krejci92ece002016-04-04 15:45:05 +020066 printf("\tnotif - LYD_OPT_NOTIF\n\n");
Michal Vasko104f58c2016-04-11 11:04:13 +020067 printf("Accepted DEFAULTS:\n");
Radek Krejci4bfa6642016-03-23 15:57:45 +010068 printf("\tall - add missing default nodes\n");
Michal Vasko104f58c2016-04-11 11:04:13 +020069 printf("\tall-tagged - add missing default nodes and mark all the default nodes with the attribute.\n");
70 printf("\ttrim - remove all nodes with a default value\n");
71 printf("\timplicit-tagged - add missing nodes and mark them with the attribute\n");
Michal Vasko520d4732015-07-13 15:53:33 +020072}
73
74void
Michal Vaskoabbdaa02015-10-06 15:47:25 +020075cmd_xpath_help(void)
76{
Michal Vaskoa8c77c22016-02-04 12:08:40 +010077 printf("xpath -e <XPath-expression> <XML-data-file-name>\n");
Michal Vaskof3e59f12015-06-18 11:53:56 +020078}
79
80void
81cmd_list_help(void)
82{
Radek Krejci83a66b02016-02-25 15:10:31 +010083 printf("list [-f (xml | json)]\n");
Michal Vaskof3e59f12015-06-18 11:53:56 +020084}
85
86void
Michal Vasko50cfb782015-07-07 11:37:34 +020087cmd_feature_help(void)
88{
Michal Vasko87148412015-08-21 14:29:51 +020089 printf("feature [ -(-e)nable | -(-d)isable (* | <feature-name>[,<feature-name> ...]) ] <model-name>[@<revision>]\n");
Michal Vasko50cfb782015-07-07 11:37:34 +020090}
91
92void
Michal Vaskof3e59f12015-06-18 11:53:56 +020093cmd_searchpath_help(void)
94{
Michal Vasko6572fb42015-07-07 09:55:05 +020095 printf("searchpath <model-dir-path>\n");
Michal Vaskof3e59f12015-06-18 11:53:56 +020096}
97
98void
99cmd_verb_help(void)
100{
Michal Vaskob93d0142015-08-11 16:08:25 +0200101 printf("verb (error/0 | warning/1 | verbose/2 | debug/3)\n");
Michal Vaskof3e59f12015-06-18 11:53:56 +0200102}
103
104int
105cmd_add(const char *arg)
106{
Michal Vasko662610a2015-12-07 11:25:45 +0100107 int path_len;
108 char *ptr, *path;
Michal Vasko370d9102015-08-21 13:06:11 +0200109 const char *arg_ptr;
Michal Vasko1e62a092015-12-01 12:27:20 +0100110 const struct lys_module *model;
Radek Krejcia9167ef2015-08-03 11:01:11 +0200111 LYS_INFORMAT format;
Michal Vaskof3e59f12015-06-18 11:53:56 +0200112
Michal Vasko203b4e72015-06-30 15:25:15 +0200113 if (strlen(arg) < 5) {
Michal Vaskof3e59f12015-06-18 11:53:56 +0200114 cmd_add_help();
115 return 1;
116 }
117
Michal Vasko370d9102015-08-21 13:06:11 +0200118 arg_ptr = arg + strlen("add ");
119 while (arg_ptr[0] == ' ') {
120 ++arg_ptr;
121 }
122 if (strchr(arg_ptr, ' ')) {
123 path_len = strchr(arg_ptr, ' ') - arg_ptr;
124 } else {
125 path_len = strlen(arg_ptr);
126 }
Michal Vasko203b4e72015-06-30 15:25:15 +0200127
Michal Vasko370d9102015-08-21 13:06:11 +0200128 path = strndup(arg_ptr, path_len);
129
130 while (path) {
131 if ((ptr = strrchr(path, '.')) != NULL) {
132 ++ptr;
133 if (!strcmp(ptr, "yin")) {
134 format = LYS_IN_YIN;
135 } else if (!strcmp(ptr, "yang")) {
136 format = LYS_IN_YANG;
137 } else {
138 fprintf(stderr, "Input file in an unknown format \"%s\".\n", ptr);
139 free(path);
140 return 1;
141 }
Michal Vaskof3e59f12015-06-18 11:53:56 +0200142 } else {
Michal Vasko370d9102015-08-21 13:06:11 +0200143 fprintf(stdout, "Input file \"%.*s\" without extension, assuming YIN format.\n", path_len, arg_ptr);
144 format = LYS_IN_YIN;
145 }
146
Michal Vasko662610a2015-12-07 11:25:45 +0100147 model = lys_parse_path(ctx, path, format);
Michal Vasko370d9102015-08-21 13:06:11 +0200148 free(path);
Radek Krejci4041a2d2015-07-02 09:16:42 +0200149
Michal Vasko370d9102015-08-21 13:06:11 +0200150 if (!model) {
151 /* libyang printed the error messages */
152 return 1;
153 }
Radek Krejci4041a2d2015-07-02 09:16:42 +0200154
Michal Vasko370d9102015-08-21 13:06:11 +0200155 /* next model */
156 arg_ptr += path_len;
157 while (arg_ptr[0] == ' ') {
158 ++arg_ptr;
159 }
160 if (strchr(arg_ptr, ' ')) {
161 path_len = strchr(arg_ptr, ' ') - arg_ptr;
162 } else {
163 path_len = strlen(arg_ptr);
164 }
Michal Vaskof3e59f12015-06-18 11:53:56 +0200165
Michal Vasko370d9102015-08-21 13:06:11 +0200166 if (path_len) {
167 path = strndup(arg_ptr, path_len);
168 } else {
169 path = NULL;
170 }
Michal Vaskof3e59f12015-06-18 11:53:56 +0200171 }
172
Michal Vaskof3e59f12015-06-18 11:53:56 +0200173 return 0;
174}
175
176int
177cmd_print(const char *arg)
178{
Michal Vasko462be9a2016-04-05 11:24:08 +0200179 int c, argc, option_index, ret = 1;
Michal Vaskoadfcfa12015-08-12 14:33:44 +0200180 char **argv = NULL, *ptr, *target_node = NULL, *model_name, *revision;
Michal Vasko462be9a2016-04-05 11:24:08 +0200181 const char *out_path = NULL;
182 const struct lys_module *module;
Radek Krejcia9167ef2015-08-03 11:01:11 +0200183 LYS_OUTFORMAT format = LYS_OUT_TREE;
Michal Vaskof3e59f12015-06-18 11:53:56 +0200184 FILE *output = stdout;
185 static struct option long_options[] = {
186 {"help", no_argument, 0, 'h'},
187 {"format", required_argument, 0, 'f'},
188 {"output", required_argument, 0, 'o'},
Michal Vaskodd3b8bc2015-07-07 11:42:28 +0200189 {"target-node", required_argument, 0, 't'},
Michal Vaskof3e59f12015-06-18 11:53:56 +0200190 {NULL, 0, 0, 0}
191 };
192
193 argc = 1;
194 argv = malloc(2*sizeof *argv);
195 *argv = strdup(arg);
196 ptr = strtok(*argv, " ");
197 while ((ptr = strtok(NULL, " "))) {
198 argv = realloc(argv, (argc+2)*sizeof *argv);
199 argv[argc++] = ptr;
200 }
201 argv[argc] = NULL;
202
Michal Vasko50cfb782015-07-07 11:37:34 +0200203 optind = 0;
Michal Vaskof3e59f12015-06-18 11:53:56 +0200204 while (1) {
Michal Vasko1074ce92015-07-03 16:16:31 +0200205 option_index = 0;
Michal Vaskodd3b8bc2015-07-07 11:42:28 +0200206 c = getopt_long(argc, argv, "hf:o:t:", long_options, &option_index);
Michal Vaskof3e59f12015-06-18 11:53:56 +0200207 if (c == -1) {
208 break;
209 }
210
211 switch (c) {
212 case 'h':
213 cmd_print_help();
214 ret = 0;
215 goto cleanup;
216 case 'f':
217 if (!strcmp(optarg, "yang")) {
Radek Krejcia9167ef2015-08-03 11:01:11 +0200218 format = LYS_OUT_YANG;
Michal Vasko5d51c0a2016-02-05 14:29:54 +0100219 } else if (!strcmp(optarg, "yin")) {
220 format = LYS_OUT_YIN;
Michal Vaskof3e59f12015-06-18 11:53:56 +0200221 } else if (!strcmp(optarg, "tree")) {
Radek Krejcia9167ef2015-08-03 11:01:11 +0200222 format = LYS_OUT_TREE;
Michal Vaskodd3b8bc2015-07-07 11:42:28 +0200223 } else if (!strcmp(optarg, "info")) {
Radek Krejcia9167ef2015-08-03 11:01:11 +0200224 format = LYS_OUT_INFO;
Michal Vaskof3e59f12015-06-18 11:53:56 +0200225 } else {
226 fprintf(stderr, "Unknown output format \"%s\".\n", optarg);
227 goto cleanup;
228 }
229 break;
230 case 'o':
231 if (out_path) {
232 fprintf(stderr, "Output specified twice.\n");
233 goto cleanup;
234 }
235 out_path = optarg;
236 break;
Michal Vaskodd3b8bc2015-07-07 11:42:28 +0200237 case 't':
238 target_node = optarg;
239 break;
Michal Vaskof3e59f12015-06-18 11:53:56 +0200240 case '?':
241 fprintf(stderr, "Unknown option \"%d\".\n", (char)c);
242 goto cleanup;
243 }
244 }
245
246 /* file name */
247 if (optind == argc) {
Michal Vasko462be9a2016-04-05 11:24:08 +0200248 fprintf(stderr, "Missing the module name.\n");
Michal Vaskof3e59f12015-06-18 11:53:56 +0200249 goto cleanup;
250 }
Michal Vaskocf0a41c2015-07-07 11:43:10 +0200251
Michal Vasko462be9a2016-04-05 11:24:08 +0200252 /* module, revision */
Michal Vaskoadfcfa12015-08-12 14:33:44 +0200253 model_name = argv[optind];
254 revision = NULL;
255 if (strchr(model_name, '@')) {
256 revision = strchr(model_name, '@');
257 revision[0] = '\0';
258 ++revision;
259 }
260
Michal Vasko462be9a2016-04-05 11:24:08 +0200261 module = ly_ctx_get_module(ctx, model_name, revision);
262 if (!module) {
263 /* not a module, try to find it as a submodule */
264 module = (const struct lys_module *)ly_ctx_get_submodule(ctx, NULL, NULL, model_name, revision);
Michal Vaskocf0a41c2015-07-07 11:43:10 +0200265 }
Michal Vaskof3e59f12015-06-18 11:53:56 +0200266
Michal Vasko462be9a2016-04-05 11:24:08 +0200267 if (!module) {
Michal Vaskoadfcfa12015-08-12 14:33:44 +0200268 if (revision) {
Michal Vasko462be9a2016-04-05 11:24:08 +0200269 fprintf(stderr, "No (sub)module \"%s\" in revision %s found.\n", model_name, revision);
Michal Vaskoadfcfa12015-08-12 14:33:44 +0200270 } else {
Michal Vasko462be9a2016-04-05 11:24:08 +0200271 fprintf(stderr, "No (sub)module \"%s\" found.\n", model_name);
Michal Vaskoadfcfa12015-08-12 14:33:44 +0200272 }
Michal Vaskof3e59f12015-06-18 11:53:56 +0200273 goto cleanup;
274 }
275
276 if (out_path) {
277 output = fopen(out_path, "w");
278 if (!output) {
279 fprintf(stderr, "Could not open the output file (%s).\n", strerror(errno));
280 goto cleanup;
281 }
282 }
283
Michal Vasko462be9a2016-04-05 11:24:08 +0200284 ret = lys_print_file(output, module, format, target_node);
Michal Vaskof3e59f12015-06-18 11:53:56 +0200285
286cleanup:
287 free(*argv);
288 free(argv);
289
Radek Krejci94f05832015-06-19 09:58:53 +0200290 if (output && (output != stdout)) {
Michal Vaskof3e59f12015-06-18 11:53:56 +0200291 fclose(output);
292 }
293
294 return ret;
295}
296
Radek Krejciba04f3e2015-11-10 19:16:01 +0100297int
298cmd_data(const char *arg)
Michal Vasko520d4732015-07-13 15:53:33 +0200299{
Michal Vasko662610a2015-12-07 11:25:45 +0100300 int c, argc, option_index, ret = 1;
Radek Krejci46180b52016-08-31 16:01:32 +0200301 int options = 0, printopt = 0;
Radek Krejci5449d472015-10-26 14:35:56 +0100302 size_t len;
Michal Vasko662610a2015-12-07 11:25:45 +0100303 char **argv = NULL, *ptr;
Michal Vasko520d4732015-07-13 15:53:33 +0200304 const char *out_path = NULL;
Radek Krejci4a2aad82016-01-13 15:01:07 +0100305 struct lyd_node *data = NULL;
306 struct lyxml_elem *xml;
Radek Krejci5449d472015-10-26 14:35:56 +0100307 LYD_FORMAT outformat = LYD_UNKNOWN, informat = LYD_UNKNOWN;
Michal Vasko520d4732015-07-13 15:53:33 +0200308 FILE *output = stdout;
309 static struct option long_options[] = {
Radek Krejci4bfa6642016-03-23 15:57:45 +0100310 {"defaults", required_argument, 0, 'd'},
Michal Vasko520d4732015-07-13 15:53:33 +0200311 {"help", no_argument, 0, 'h'},
312 {"format", required_argument, 0, 'f'},
Radek Krejciba04f3e2015-11-10 19:16:01 +0100313 {"option", required_argument, 0, 'x'},
Michal Vasko520d4732015-07-13 15:53:33 +0200314 {"output", required_argument, 0, 'o'},
Radek Krejcib9120952015-08-12 10:03:51 +0200315 {"strict", no_argument, 0, 's'},
Michal Vasko520d4732015-07-13 15:53:33 +0200316 {NULL, 0, 0, 0}
317 };
318
319 argc = 1;
320 argv = malloc(2*sizeof *argv);
321 *argv = strdup(arg);
322 ptr = strtok(*argv, " ");
323 while ((ptr = strtok(NULL, " "))) {
324 argv = realloc(argv, (argc+2)*sizeof *argv);
325 argv[argc++] = ptr;
326 }
327 argv[argc] = NULL;
328
329 optind = 0;
330 while (1) {
331 option_index = 0;
Radek Krejci4bfa6642016-03-23 15:57:45 +0100332 c = getopt_long(argc, argv, "d:hf:o:sx:", long_options, &option_index);
Michal Vasko520d4732015-07-13 15:53:33 +0200333 if (c == -1) {
334 break;
335 }
336
337 switch (c) {
Radek Krejci4bfa6642016-03-23 15:57:45 +0100338 case 'd':
339 if (!strcmp(optarg, "all")) {
Radek Krejci46180b52016-08-31 16:01:32 +0200340 printopt = (printopt & ~LYP_WD_MASK) | LYP_WD_ALL;
Radek Krejci4bfa6642016-03-23 15:57:45 +0100341 } else if (!strcmp(optarg, "all-tagged")) {
Radek Krejci46180b52016-08-31 16:01:32 +0200342 printopt = (printopt & ~LYP_WD_MASK) | LYP_WD_ALL_TAG;
Radek Krejci4bfa6642016-03-23 15:57:45 +0100343 } else if (!strcmp(optarg, "trim")) {
Radek Krejci46180b52016-08-31 16:01:32 +0200344 printopt = (printopt & ~LYP_WD_MASK) | LYP_WD_TRIM;
Radek Krejci4bfa6642016-03-23 15:57:45 +0100345 } else if (!strcmp(optarg, "implicit-tagged")) {
Radek Krejci46180b52016-08-31 16:01:32 +0200346 printopt = (printopt & ~LYP_WD_MASK) | LYP_WD_IMPL_TAG;
Radek Krejci4bfa6642016-03-23 15:57:45 +0100347 }
348 break;
Michal Vasko520d4732015-07-13 15:53:33 +0200349 case 'h':
350 cmd_data_help();
351 ret = 0;
352 goto cleanup;
353 case 'f':
354 if (!strcmp(optarg, "xml")) {
Michal Vasko95068c42016-03-24 14:58:11 +0100355 outformat = LYD_XML;
Michal Vasko520d4732015-07-13 15:53:33 +0200356 } else if (!strcmp(optarg, "json")) {
Radek Krejci5449d472015-10-26 14:35:56 +0100357 outformat = LYD_JSON;
Michal Vasko520d4732015-07-13 15:53:33 +0200358 } else {
359 fprintf(stderr, "Unknown output format \"%s\".\n", optarg);
360 goto cleanup;
361 }
362 break;
363 case 'o':
364 if (out_path) {
365 fprintf(stderr, "Output specified twice.\n");
366 goto cleanup;
367 }
368 out_path = optarg;
369 break;
Radek Krejcib9120952015-08-12 10:03:51 +0200370 case 's':
371 options |= LYD_OPT_STRICT;
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100372 options |= LYD_OPT_OBSOLETE;
Radek Krejcib9120952015-08-12 10:03:51 +0200373 break;
Radek Krejciba04f3e2015-11-10 19:16:01 +0100374 case 'x':
Radek Krejci4a2aad82016-01-13 15:01:07 +0100375 if (!strcmp(optarg, "auto")) {
376 options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_TYPEMASK;
377 } else if (!strcmp(optarg, "config")) {
378 options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_CONFIG;
Radek Krejciba04f3e2015-11-10 19:16:01 +0100379 } else if (!strcmp(optarg, "get")) {
Radek Krejci4a2aad82016-01-13 15:01:07 +0100380 options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_GET;
Radek Krejciba04f3e2015-11-10 19:16:01 +0100381 } else if (!strcmp(optarg, "getconfig")) {
Radek Krejci4a2aad82016-01-13 15:01:07 +0100382 options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_GETCONFIG;
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100383 } else if (!strcmp(optarg, "edit")) {
Radek Krejci4a2aad82016-01-13 15:01:07 +0100384 options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_EDIT;
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100385 } else if (!strcmp(optarg, "rpc")) {
Radek Krejci4a2aad82016-01-13 15:01:07 +0100386 options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_RPC;
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100387 /* support for RPC replies is missing, because it requires to provide
388 * also pointer to the reply's RPC request
389 } else if (!strcmp(optarg, "rpcreply")) {
Radek Krejci4a2aad82016-01-13 15:01:07 +0100390 options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_RPCREPLY;
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100391 */
392 } else if (!strcmp(optarg, "notif")) {
Radek Krejci4a2aad82016-01-13 15:01:07 +0100393 options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_NOTIF;
Radek Krejci83b5ae52016-03-11 11:17:26 +0100394 } else {
395 fprintf(stderr, "Invalid parser option \"%s\".\n", optarg);
396 cmd_data_help();
397 goto cleanup;
Radek Krejciba04f3e2015-11-10 19:16:01 +0100398 }
399 break;
Michal Vasko520d4732015-07-13 15:53:33 +0200400 case '?':
401 fprintf(stderr, "Unknown option \"%d\".\n", (char)c);
402 goto cleanup;
403 }
404 }
405
406 /* file name */
407 if (optind == argc) {
408 fprintf(stderr, "Missing the data file name.\n");
409 goto cleanup;
410 }
411
Radek Krejci5449d472015-10-26 14:35:56 +0100412 /* detect input format according to file suffix */
413 len = strlen(argv[optind]);
414 if (len >= 5 && !strcmp(&argv[optind][len - 4], ".xml")) {
415 informat = LYD_XML;
416 } else if (len >= 6 && !strcmp(&argv[optind][len - 5], ".json")) {
417 informat = LYD_JSON;
418 } else {
Tomas Cejka99c268f2015-11-04 14:07:21 +0900419 fprintf(stderr, "Unable to resolve format of the input file, please add \".xml\" or \".json\" suffix.\n");
Radek Krejci5449d472015-10-26 14:35:56 +0100420 goto cleanup;
421 }
422
Radek Krejci4a2aad82016-01-13 15:01:07 +0100423 if ((options & LYD_OPT_TYPEMASK) == LYD_OPT_TYPEMASK) {
424 /* automatically detect data type from the data top level */
425 if (informat != LYD_XML) {
426 fprintf(stderr, "Only XML data can be automatically explored.\n");
427 goto cleanup;
428 }
429
Radek Krejci722b0072016-02-01 17:09:45 +0100430 xml = lyxml_parse_path(ctx, argv[optind], 0);
Radek Krejci4a2aad82016-01-13 15:01:07 +0100431 if (!xml) {
Radek Krejci2342cf62016-01-29 16:48:23 +0100432 fprintf(stderr, "Failed to parse XML data for automatic type detection.\n");
Radek Krejci4a2aad82016-01-13 15:01:07 +0100433 goto cleanup;
434 }
435
436 /* NOTE: namespace is ignored to simplify usage of this feature */
437
438 if (!strcmp(xml->name, "data")) {
439 fprintf(stdout, "Parsing %s as complete datastore.\n", argv[optind]);
Radek Krejci03b71f72016-03-16 11:10:09 +0100440 options = (options & ~LYD_OPT_TYPEMASK);
Radek Krejci4a2aad82016-01-13 15:01:07 +0100441 } else if (!strcmp(xml->name, "config")) {
442 fprintf(stdout, "Parsing %s as config data.\n", argv[optind]);
443 options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_CONFIG;
444 } else if (!strcmp(xml->name, "get-reply")) {
445 fprintf(stdout, "Parsing %s as <get> reply data.\n", argv[optind]);
446 options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_GET;
447 } else if (!strcmp(xml->name, "get-config-reply")) {
448 fprintf(stdout, "Parsing %s as <get-config> reply data.\n", argv[optind]);
449 options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_GETCONFIG;
450 } else if (!strcmp(xml->name, "edit-config")) {
451 fprintf(stdout, "Parsing %s as <edit-config> data.\n", argv[optind]);
452 options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_EDIT;
453 } else if (!strcmp(xml->name, "rpc")) {
454 fprintf(stdout, "Parsing %s as <rpc> data.\n", argv[optind]);
455 options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_RPC;
456 /* support for RPC replies is missing, because it requires to provide
457 * also pointer to the reply's RPC request
458 } else if (!strcmp(xml->name, "rpc-reply")) {
459 fprintf(stdout, "Parsing %s as <rpc-reply> data.\n");
460 options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_RPCREPLY;
461 */
462 } else if (!strcmp(xml->name, "notification")) {
463 fprintf(stdout, "Parsing %s as <notification> data.\n", argv[optind]);
464 options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_NOTIF;
Radek Krejci4a2aad82016-01-13 15:01:07 +0100465 } else {
466 fprintf(stderr, "Invalid top-level element for automatic data type recognition.\n");
467 lyxml_free(ctx, xml);
468 goto cleanup;
469 }
470
471 data = lyd_parse_xml(ctx, &xml->child, options);
472 lyxml_free(ctx, xml);
473 } else {
474 data = lyd_parse_path(ctx, argv[optind], informat, options);
475 }
Radek Krejci2342cf62016-01-29 16:48:23 +0100476 if (ly_errno) {
Michal Vasko520d4732015-07-13 15:53:33 +0200477 fprintf(stderr, "Failed to parse data.\n");
478 goto cleanup;
479 }
480
481 if (out_path) {
482 output = fopen(out_path, "w");
483 if (!output) {
484 fprintf(stderr, "Could not open the output file (%s).\n", strerror(errno));
485 goto cleanup;
486 }
Michal Vasko520d4732015-07-13 15:53:33 +0200487 }
488
Radek Krejci5449d472015-10-26 14:35:56 +0100489 if (outformat != LYD_UNKNOWN) {
Radek Krejci46180b52016-08-31 16:01:32 +0200490 lyd_print_file(output, data, outformat, LYP_WITHSIBLINGS | LYP_FORMAT | printopt);
Michal Vasko520d4732015-07-13 15:53:33 +0200491 }
492
Michal Vaskoabbdaa02015-10-06 15:47:25 +0200493 ret = 0;
494
Michal Vasko520d4732015-07-13 15:53:33 +0200495cleanup:
496 free(*argv);
497 free(argv);
498
499 if (output && (output != stdout)) {
500 fclose(output);
501 }
502
Radek Krejci4a2aad82016-01-13 15:01:07 +0100503 lyd_free_withsiblings(data);
Michal Vasko520d4732015-07-13 15:53:33 +0200504
505 return ret;
506}
507
508int
Michal Vaskoabbdaa02015-10-06 15:47:25 +0200509cmd_xpath(const char *arg)
510{
Michal Vaskoa8c77c22016-02-04 12:08:40 +0100511 int c, argc, option_index, ret = 1, long_str;
512 char **argv = NULL, *ptr, *expr = NULL;
513 unsigned int i, j;
514 struct lyd_node *data = NULL, *node;
Michal Vaskof29903d2016-04-18 13:13:10 +0200515 struct lyd_node_leaf_list *key;
516 struct ly_set *set;
Michal Vaskoabbdaa02015-10-06 15:47:25 +0200517 static struct option long_options[] = {
518 {"help", no_argument, 0, 'h'},
519 {"expr", required_argument, 0, 'e'},
Michal Vaskoabbdaa02015-10-06 15:47:25 +0200520 {NULL, 0, 0, 0}
521 };
522
523 long_str = 0;
524 argc = 1;
525 argv = malloc(2 * sizeof *argv);
526 *argv = strdup(arg);
527 ptr = strtok(*argv, " ");
528 while ((ptr = strtok(NULL, " "))) {
529 if (long_str) {
530 ptr[-1] = ' ';
531 if (ptr[strlen(ptr) - 1] == long_str) {
532 long_str = 0;
533 ptr[strlen(ptr) - 1] = '\0';
534 }
535 } else {
536 argv = realloc(argv, (argc + 2) * sizeof *argv);
537 argv[argc] = ptr;
538 if (ptr[0] == '"') {
539 long_str = '"';
540 ++argv[argc];
541 }
542 if (ptr[0] == '\'') {
543 long_str = '\'';
544 ++argv[argc];
545 }
546 if (ptr[strlen(ptr) - 1] == long_str) {
547 long_str = 0;
548 ptr[strlen(ptr) - 1] = '\0';
549 }
550 ++argc;
551 }
552 }
553 argv[argc] = NULL;
554
555 optind = 0;
556 while (1) {
557 option_index = 0;
Michal Vaskoa8c77c22016-02-04 12:08:40 +0100558 c = getopt_long(argc, argv, "he:", long_options, &option_index);
Michal Vaskoabbdaa02015-10-06 15:47:25 +0200559 if (c == -1) {
560 break;
561 }
562
563 switch (c) {
564 case 'h':
565 cmd_xpath_help();
566 ret = 0;
567 goto cleanup;
568 case 'e':
569 expr = optarg;
570 break;
Michal Vaskoabbdaa02015-10-06 15:47:25 +0200571 case '?':
572 fprintf(stderr, "Unknown option \"%d\".\n", (char)c);
573 goto cleanup;
574 }
575 }
576
577 if (optind == argc) {
578 fprintf(stderr, "Missing the file with data.\n");
579 goto cleanup;
580 }
581
582 if (!expr) {
583 fprintf(stderr, "Missing the XPath expression.\n");
584 goto cleanup;
585 }
586
587 /* data file */
Michal Vasko662610a2015-12-07 11:25:45 +0100588 data = lyd_parse_path(ctx, argv[optind], LYD_XML, 0);
Radek Krejci2342cf62016-01-29 16:48:23 +0100589 if (ly_errno) {
Michal Vaskoabbdaa02015-10-06 15:47:25 +0200590 fprintf(stderr, "Failed to parse data.\n");
591 goto cleanup;
592 }
593
Michal Vaskoa8c77c22016-02-04 12:08:40 +0100594 if (!(set = lyd_get_node(data, expr))) {
Michal Vaskoabbdaa02015-10-06 15:47:25 +0200595 goto cleanup;
596 }
597
Michal Vaskoa8c77c22016-02-04 12:08:40 +0100598 /* print result */
599 printf("Result:\n");
600 if (!set->number) {
601 printf("\tEmpty\n");
602 } else {
603 for (i = 0; i < set->number; ++i) {
Radek Krejci8f08df12016-03-21 11:11:30 +0100604 node = set->set.d[i];
Michal Vaskoa8c77c22016-02-04 12:08:40 +0100605 switch (node->schema->nodetype) {
606 case LYS_CONTAINER:
607 printf("\tContainer ");
608 break;
609 case LYS_LEAF:
610 printf("\tLeaf ");
611 break;
612 case LYS_LEAFLIST:
613 printf("\tLeaflist ");
614 break;
615 case LYS_LIST:
Michal Vaskodbb86322016-02-04 13:53:38 +0100616 printf("\tList ");
Michal Vaskoa8c77c22016-02-04 12:08:40 +0100617 break;
618 case LYS_ANYXML:
619 printf("\tAnyxml ");
620 break;
Radek Krejcibf2abff2016-08-23 15:51:52 +0200621 case LYS_ANYDATA:
622 printf("\tAnydata ");
623 break;
Michal Vaskoa8c77c22016-02-04 12:08:40 +0100624 default:
625 printf("\tUnknown ");
626 break;
627 }
628 printf("\"%s\"", node->schema->name);
629 if (node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
630 printf(" (val: %s)", ((struct lyd_node_leaf_list *)node)->value_str);
631 } else if (node->schema->nodetype == LYS_LIST) {
Michal Vaskof29903d2016-04-18 13:13:10 +0200632 key = (struct lyd_node_leaf_list *)node->child;
633 printf(" (");
634 for (j = 0; j < ((struct lys_node_list *)node->schema)->keys_size; ++j) {
635 if (j) {
636 printf(" ");
Michal Vaskoa8c77c22016-02-04 12:08:40 +0100637 }
Michal Vaskof29903d2016-04-18 13:13:10 +0200638 printf("\"%s\": %s", key->schema->name, key->value_str);
639 key = (struct lyd_node_leaf_list *)key->next;
Michal Vaskoa8c77c22016-02-04 12:08:40 +0100640 }
Michal Vaskof29903d2016-04-18 13:13:10 +0200641 printf(")");
Michal Vaskoa8c77c22016-02-04 12:08:40 +0100642 }
643 printf("\n");
644 }
645 }
646 printf("\n");
647
Michal Vasko2b67bf72016-05-05 17:49:36 +0200648 ly_set_free(set);
Michal Vaskoabbdaa02015-10-06 15:47:25 +0200649 ret = 0;
650
651cleanup:
652 free(*argv);
653 free(argv);
654
Radek Krejci4a2aad82016-01-13 15:01:07 +0100655 lyd_free_withsiblings(data);
Michal Vaskoabbdaa02015-10-06 15:47:25 +0200656
657 return ret;
658}
659
660int
Radek Krejci83a66b02016-02-25 15:10:31 +0100661cmd_list(const char *arg)
Michal Vaskof3e59f12015-06-18 11:53:56 +0200662{
Radek Krejcifc3692c2016-02-25 15:36:13 +0100663 struct lyd_node *ylib = NULL, *module, *submodule, *node;
Radek Krejci6e05cea2015-12-10 16:34:37 +0100664 int has_modules = 0, flag;
Radek Krejci83a66b02016-02-25 15:10:31 +0100665 char **argv = NULL, *ptr;
666 int c, argc, option_index;
667 LYD_FORMAT outformat = LYD_UNKNOWN;
668 static struct option long_options[] = {
669 {"help", no_argument, 0, 'h'},
670 {"format", required_argument, 0, 'f'},
671 {NULL, 0, 0, 0}
672 };
673
674 argc = 1;
675 argv = malloc(2*sizeof *argv);
676 *argv = strdup(arg);
677 ptr = strtok(*argv, " ");
678 while ((ptr = strtok(NULL, " "))) {
679 argv = realloc(argv, (argc+2)*sizeof *argv);
680 argv[argc++] = ptr;
681 }
682 argv[argc] = NULL;
683
684 optind = 0;
685 while (1) {
686 option_index = 0;
687 c = getopt_long(argc, argv, "hf:", long_options, &option_index);
688 if (c == -1) {
689 break;
690 }
691
692 switch (c) {
693 case 'h':
694 cmd_data_help();
695 free(*argv);
696 free(argv);
697 return 0;
698 case 'f':
699 if (!strcmp(optarg, "xml")) {
Michal Vasko95068c42016-03-24 14:58:11 +0100700 outformat = LYD_XML;
Radek Krejci83a66b02016-02-25 15:10:31 +0100701 } else if (!strcmp(optarg, "json")) {
702 outformat = LYD_JSON;
703 } else {
704 fprintf(stderr, "Unknown output format \"%s\".\n", optarg);
Radek Krejcifc3692c2016-02-25 15:36:13 +0100705 goto error;
Radek Krejci83a66b02016-02-25 15:10:31 +0100706 }
707 break;
708 case '?':
Radek Krejcifc3692c2016-02-25 15:36:13 +0100709 /* getopt_long() prints message */
710 goto error;
Radek Krejci83a66b02016-02-25 15:10:31 +0100711 }
712 }
Radek Krejcifc3692c2016-02-25 15:36:13 +0100713 if (optind != argc) {
714 fprintf(stderr, "Unknown parameter \"%s\"\n", argv[optind]);
715error:
716 free(*argv);
717 free(argv);
718 return 1;
719 }
Radek Krejci83a66b02016-02-25 15:10:31 +0100720 free(*argv);
721 free(argv);
722
Radek Krejci7ab25152015-08-07 14:48:45 +0200723 ylib = ly_ctx_info(ctx);
Michal Vasko3e671b52015-10-23 16:23:15 +0200724 if (!ylib) {
Michal Vasko7c7023f2015-12-11 11:59:54 +0100725 fprintf(stderr, "Getting context info (ietf-yang-library data) failed.\n");
Michal Vasko3e671b52015-10-23 16:23:15 +0200726 return 1;
727 }
Michal Vaskof3e59f12015-06-18 11:53:56 +0200728
Radek Krejci83a66b02016-02-25 15:10:31 +0100729 if (outformat != LYD_UNKNOWN) {
Michal Vasko95068c42016-03-24 14:58:11 +0100730 lyd_print_file(stdout, ylib, outformat, LYP_WITHSIBLINGS | LYP_FORMAT);
Radek Krejcidd1c4172016-02-25 15:17:45 +0100731 lyd_free(ylib);
Radek Krejci83a66b02016-02-25 15:10:31 +0100732 return 0;
733 }
734
Michal Vaskoea31f192015-08-03 15:21:56 +0200735 LY_TREE_FOR(ylib->child, node) {
736 if (!strcmp(node->schema->name, "module-set-id")) {
Michal Vasko4c183312015-09-25 10:41:47 +0200737 printf("List of the loaded models (mod-set-id %s):\n", ((struct lyd_node_leaf_list *)node)->value_str);
Michal Vaskoea31f192015-08-03 15:21:56 +0200738 break;
Michal Vaskofa8c8282015-07-03 15:14:59 +0200739 }
Michal Vaskoe0cb2522015-07-01 10:24:53 +0200740 }
Michal Vaskoea31f192015-08-03 15:21:56 +0200741 assert(node);
Michal Vaskoe0cb2522015-07-01 10:24:53 +0200742
Michal Vaskoea31f192015-08-03 15:21:56 +0200743 LY_TREE_FOR(ylib->child, module) {
744 if (!strcmp(module->schema->name, "module")) {
745 has_modules = 1;
746
747 /* module print */
748 LY_TREE_FOR(module->child, node) {
749 if (!strcmp(node->schema->name, "name")) {
Michal Vasko4c183312015-09-25 10:41:47 +0200750 printf("\t%s", ((struct lyd_node_leaf_list *)node)->value_str);
Michal Vaskoea31f192015-08-03 15:21:56 +0200751 } else if (!strcmp(node->schema->name, "revision")) {
Radek Krejci6e05cea2015-12-10 16:34:37 +0100752 if (((struct lyd_node_leaf_list *)node)->value_str[0] != '\0') {
753 printf("@%s", ((struct lyd_node_leaf_list *)node)->value_str);
Michal Vaskoea31f192015-08-03 15:21:56 +0200754 }
755 }
756 }
757
758 /* submodules print */
759 LY_TREE_FOR(module->child, submodule) {
760 if (!strcmp(submodule->schema->name, "submodules")) {
Radek Krejci6e05cea2015-12-10 16:34:37 +0100761 printf(" (");
762 flag = 0;
Michal Vaskoea31f192015-08-03 15:21:56 +0200763 LY_TREE_FOR(submodule->child, submodule) {
764 if (!strcmp(submodule->schema->name, "submodule")) {
765 LY_TREE_FOR(submodule->child, node) {
766 if (!strcmp(node->schema->name, "name")) {
Radek Krejci6e05cea2015-12-10 16:34:37 +0100767 printf("%s%s", flag ? "," : "", ((struct lyd_node_leaf_list *)node)->value_str);
Michal Vaskoea31f192015-08-03 15:21:56 +0200768 } else if (!strcmp(node->schema->name, "revision")) {
Radek Krejci6e05cea2015-12-10 16:34:37 +0100769 if (((struct lyd_node_leaf_list *)node)->value_str[0] != '\0') {
770 printf("@%s", ((struct lyd_node_leaf_list *)node)->value_str);
Michal Vaskoea31f192015-08-03 15:21:56 +0200771 }
772 }
773 }
Radek Krejci6e05cea2015-12-10 16:34:37 +0100774 flag++;
Michal Vaskoea31f192015-08-03 15:21:56 +0200775 }
776 }
Radek Krejci6e05cea2015-12-10 16:34:37 +0100777 printf(")");
Michal Vaskoea31f192015-08-03 15:21:56 +0200778 break;
779 }
780 }
Radek Krejci6e05cea2015-12-10 16:34:37 +0100781 printf("\n");
Michal Vaskoea31f192015-08-03 15:21:56 +0200782 }
783 }
784
785 if (!has_modules) {
Michal Vaskoe0cb2522015-07-01 10:24:53 +0200786 printf("\t(none)\n");
787 }
Michal Vaskof3e59f12015-06-18 11:53:56 +0200788
Michal Vaskoea31f192015-08-03 15:21:56 +0200789 lyd_free(ylib);
Michal Vaskof3e59f12015-06-18 11:53:56 +0200790 return 0;
791}
792
793int
Michal Vasko50cfb782015-07-07 11:37:34 +0200794cmd_feature(const char *arg)
795{
Michal Vasko87148412015-08-21 14:29:51 +0200796 int c, i, argc, option_index, ret = 1, task = 0;
Michal Vaskob011e6b2015-08-06 09:57:46 +0200797 unsigned int max_len;
Michal Vasko87148412015-08-21 14:29:51 +0200798 char **argv = NULL, *ptr, *model_name, *revision, *feat_names = NULL;
799 const char **names;
Radek Krejcie98bb4b2015-07-30 14:21:41 +0200800 uint8_t *states;
Michal Vasko462be9a2016-04-05 11:24:08 +0200801 const struct lys_module *module;
Michal Vasko50cfb782015-07-07 11:37:34 +0200802 static struct option long_options[] = {
803 {"help", no_argument, 0, 'h'},
Michal Vasko50cfb782015-07-07 11:37:34 +0200804 {"enable", required_argument, 0, 'e'},
805 {"disable", required_argument, 0, 'd'},
806 {NULL, 0, 0, 0}
807 };
808
809 argc = 1;
810 argv = malloc(2*sizeof *argv);
811 *argv = strdup(arg);
812 ptr = strtok(*argv, " ");
813 while ((ptr = strtok(NULL, " "))) {
814 argv = realloc(argv, (argc+2)*sizeof *argv);
815 argv[argc++] = ptr;
816 }
817 argv[argc] = NULL;
818
819 optind = 0;
820 while (1) {
821 option_index = 0;
Michal Vasko87148412015-08-21 14:29:51 +0200822 c = getopt_long(argc, argv, "he:d:", long_options, &option_index);
Michal Vasko50cfb782015-07-07 11:37:34 +0200823 if (c == -1) {
824 break;
825 }
826
827 switch (c) {
828 case 'h':
829 cmd_feature_help();
830 ret = 0;
831 goto cleanup;
Michal Vasko50cfb782015-07-07 11:37:34 +0200832 case 'e':
Michal Vasko87148412015-08-21 14:29:51 +0200833 if (task) {
834 fprintf(stderr, "Only one of enable or disable can be specified.\n");
Michal Vasko50cfb782015-07-07 11:37:34 +0200835 goto cleanup;
836 }
837 task = 1;
Michal Vasko87148412015-08-21 14:29:51 +0200838 feat_names = optarg;
Michal Vasko50cfb782015-07-07 11:37:34 +0200839 break;
840 case 'd':
Michal Vasko87148412015-08-21 14:29:51 +0200841 if (task) {
842 fprintf(stderr, "Only one of enable, or disable can be specified.\n");
Michal Vasko50cfb782015-07-07 11:37:34 +0200843 goto cleanup;
844 }
845 task = 2;
Michal Vasko87148412015-08-21 14:29:51 +0200846 feat_names = optarg;
Michal Vasko50cfb782015-07-07 11:37:34 +0200847 break;
848 case '?':
849 fprintf(stderr, "Unknown option \"%d\".\n", (char)c);
850 goto cleanup;
851 }
852 }
853
Michal Vasko462be9a2016-04-05 11:24:08 +0200854 /* module name */
Michal Vasko50cfb782015-07-07 11:37:34 +0200855 if (optind == argc) {
Michal Vasko462be9a2016-04-05 11:24:08 +0200856 fprintf(stderr, "Missing the module name.\n");
Michal Vasko50cfb782015-07-07 11:37:34 +0200857 goto cleanup;
858 }
Michal Vasko4b484272015-08-12 14:41:25 +0200859
860 revision = NULL;
861 model_name = argv[optind];
862 if (strchr(model_name, '@')) {
863 revision = strchr(model_name, '@');
864 revision[0] = '\0';
865 ++revision;
866 }
867
Michal Vasko462be9a2016-04-05 11:24:08 +0200868 module = ly_ctx_get_module(ctx, model_name, revision);
869 if (!module) {
870 /* not a module, try to find it as a submodule */
871 module = (const struct lys_module *)ly_ctx_get_submodule(ctx, NULL, NULL, model_name, revision);
Michal Vasko50cfb782015-07-07 11:37:34 +0200872 }
Michal Vasko462be9a2016-04-05 11:24:08 +0200873
874 if (module == NULL) {
Michal Vasko4b484272015-08-12 14:41:25 +0200875 if (revision) {
Michal Vasko462be9a2016-04-05 11:24:08 +0200876 fprintf(stderr, "No (sub)module \"%s\" in revision %s found.\n", model_name, revision);
Michal Vasko4b484272015-08-12 14:41:25 +0200877 } else {
Michal Vasko462be9a2016-04-05 11:24:08 +0200878 fprintf(stderr, "No (sub)module \"%s\" found.\n", model_name);
Michal Vasko4b484272015-08-12 14:41:25 +0200879 }
Michal Vasko50cfb782015-07-07 11:37:34 +0200880 goto cleanup;
881 }
882
Michal Vasko87148412015-08-21 14:29:51 +0200883 if (!task) {
Michal Vasko462be9a2016-04-05 11:24:08 +0200884 printf("%s features:\n", module->name);
Michal Vasko50cfb782015-07-07 11:37:34 +0200885
Michal Vasko462be9a2016-04-05 11:24:08 +0200886 names = lys_features_list(module, &states);
Michal Vaskob011e6b2015-08-06 09:57:46 +0200887
888 /* get the max len */
889 max_len = 0;
Michal Vasko50cfb782015-07-07 11:37:34 +0200890 for (i = 0; names[i]; ++i) {
Michal Vaskob011e6b2015-08-06 09:57:46 +0200891 if (strlen(names[i]) > max_len) {
892 max_len = strlen(names[i]);
893 }
894 }
895 for (i = 0; names[i]; ++i) {
896 printf("\t%-*s (%s)\n", max_len, names[i], states[i] ? "on" : "off");
Michal Vasko50cfb782015-07-07 11:37:34 +0200897 }
898 free(names);
Radek Krejcie98bb4b2015-07-30 14:21:41 +0200899 free(states);
Michal Vasko50cfb782015-07-07 11:37:34 +0200900 if (!i) {
901 printf("\t(none)\n");
902 }
Michal Vasko87148412015-08-21 14:29:51 +0200903 } else {
904 feat_names = strtok(feat_names, ",");
905 while (feat_names) {
Michal Vasko462be9a2016-04-05 11:24:08 +0200906 if (((task == 1) && lys_features_enable(module, feat_names))
907 || ((task == 2) && lys_features_disable(module, feat_names))) {
Michal Vasko87148412015-08-21 14:29:51 +0200908 fprintf(stderr, "Feature \"%s\" not found.\n", feat_names);
909 ret = 1;
910 }
911 feat_names = strtok(NULL, ",");
Michal Vasko50cfb782015-07-07 11:37:34 +0200912 }
913 }
914
915cleanup:
916 free(*argv);
917 free(argv);
918
919 return ret;
920}
921
922int
Michal Vaskof3e59f12015-06-18 11:53:56 +0200923cmd_searchpath(const char *arg)
924{
925 const char *path;
926 struct stat st;
927
928 if (strchr(arg, ' ') == NULL) {
929 fprintf(stderr, "Missing the search path.\n");
930 return 1;
931 }
932 path = strchr(arg, ' ')+1;
933
934 if (!strcmp(path, "-h") || !strcmp(path, "--help")) {
935 cmd_searchpath_help();
936 return 0;
937 }
938
939 if (stat(path, &st) == -1) {
940 fprintf(stderr, "Failed to stat the search path (%s).\n", strerror(errno));
941 return 1;
942 }
943 if (!S_ISDIR(st.st_mode)) {
944 fprintf(stderr, "\"%s\" is not a directory.\n", path);
945 return 1;
946 }
947
Radek Krejci0cb47842015-12-09 15:24:32 +0100948 ly_ctx_set_searchdir(ctx, path);
Michal Vaskof3e59f12015-06-18 11:53:56 +0200949
Michal Vasko6572fb42015-07-07 09:55:05 +0200950 return 0;
951}
Michal Vaskof3e59f12015-06-18 11:53:56 +0200952
Michal Vasko50cfb782015-07-07 11:37:34 +0200953int
954cmd_clear(const char *UNUSED(arg))
955{
Radek Krejcifa0b5e02016-02-04 13:57:03 +0100956 ly_ctx_destroy(ctx, NULL);
Radek Krejci0cb47842015-12-09 15:24:32 +0100957 ctx = ly_ctx_new(NULL);
Michal Vasko5f998eb2015-08-21 14:05:58 +0200958 if (!ctx) {
959 fprintf(stderr, "Failed to create context.\n");
960 return 1;
961 }
Michal Vaskof3e59f12015-06-18 11:53:56 +0200962 return 0;
963}
964
965int
966cmd_verb(const char *arg)
967{
968 const char *verb;
Radek Krejci7408bf12015-07-20 18:15:51 +0200969 if (strlen(arg) < 5) {
970 cmd_verb_help();
971 return 1;
972 }
Michal Vaskof3e59f12015-06-18 11:53:56 +0200973
974 verb = arg + 5;
Michal Vaskob93d0142015-08-11 16:08:25 +0200975 if (!strcmp(verb, "error") || !strcmp(verb, "0")) {
Radek Krejci2abfdfe2016-07-19 11:05:06 +0200976 ly_verb(LY_LLERR);
Michal Vaskob93d0142015-08-11 16:08:25 +0200977 } else if (!strcmp(verb, "warning") || !strcmp(verb, "1")) {
Radek Krejci2abfdfe2016-07-19 11:05:06 +0200978 ly_verb(LY_LLWRN);
Michal Vaskob93d0142015-08-11 16:08:25 +0200979 } else if (!strcmp(verb, "verbose") || !strcmp(verb, "2")) {
Radek Krejci2abfdfe2016-07-19 11:05:06 +0200980 ly_verb(LY_LLVRB);
Michal Vaskob93d0142015-08-11 16:08:25 +0200981 } else if (!strcmp(verb, "debug") || !strcmp(verb, "3")) {
Radek Krejci2abfdfe2016-07-19 11:05:06 +0200982 ly_verb(LY_LLDBG);
Michal Vaskof3e59f12015-06-18 11:53:56 +0200983 } else {
Radek Krejci7408bf12015-07-20 18:15:51 +0200984 fprintf(stderr, "Unknown verbosity \"%s\"\n", verb);
Michal Vaskof3e59f12015-06-18 11:53:56 +0200985 return 1;
986 }
987
988 return 0;
989}
990
991int
992cmd_quit(const char *UNUSED(arg))
993{
994 done = 1;
995 return 0;
996}
997
998int
999cmd_help(const char *arg)
1000{
1001 int i;
Radek Krejciec797a32016-02-05 16:52:12 +01001002 char *args = strdup(arg);
Michal Vaskof3e59f12015-06-18 11:53:56 +02001003 char *cmd = NULL;
1004
1005 strtok(args, " ");
1006 if ((cmd = strtok(NULL, " ")) == NULL) {
1007
1008generic_help:
1009 fprintf(stdout, "Available commands:\n");
1010
1011 for (i = 0; commands[i].name; i++) {
1012 if (commands[i].helpstring != NULL) {
1013 fprintf(stdout, " %-15s %s\n", commands[i].name, commands[i].helpstring);
1014 }
1015 }
1016 } else {
1017 /* print specific help for the selected command */
1018
1019 /* get the command of the specified name */
1020 for (i = 0; commands[i].name; i++) {
1021 if (strcmp(cmd, commands[i].name) == 0) {
1022 break;
1023 }
1024 }
1025
1026 /* execute the command's help if any valid command specified */
1027 if (commands[i].name) {
1028 if (commands[i].help_func != NULL) {
1029 commands[i].help_func();
1030 } else {
1031 printf("%s\n", commands[i].helpstring);
1032 }
1033 } else {
1034 /* if unknown command specified, print the list of commands */
1035 printf("Unknown command \'%s\'\n", cmd);
1036 goto generic_help;
1037 }
1038 }
1039
Radek Krejciec797a32016-02-05 16:52:12 +01001040 free(args);
Michal Vaskof3e59f12015-06-18 11:53:56 +02001041 return 0;
1042}
1043
1044COMMAND commands[] = {
1045 {"help", cmd_help, NULL, "Display commands description"},
1046 {"add", cmd_add, cmd_add_help, "Add a new model"},
1047 {"print", cmd_print, cmd_print_help, "Print model"},
Radek Krejciba04f3e2015-11-10 19:16:01 +01001048 {"data", cmd_data, cmd_data_help, "Load, validate and optionally print instance data"},
Michal Vaskoa8c77c22016-02-04 12:08:40 +01001049 {"xpath", cmd_xpath, cmd_xpath_help, "Get data nodes satisfying an XPath expression"},
Michal Vaskof3e59f12015-06-18 11:53:56 +02001050 {"list", cmd_list, cmd_list_help, "List all the loaded models"},
Michal Vasko50cfb782015-07-07 11:37:34 +02001051 {"feature", cmd_feature, cmd_feature_help, "Print/enable/disable all/specific features of models"},
Michal Vaskof3e59f12015-06-18 11:53:56 +02001052 {"searchpath", cmd_searchpath, cmd_searchpath_help, "Set the search path for models"},
Michal Vasko6572fb42015-07-07 09:55:05 +02001053 {"clear", cmd_clear, NULL, "Clear the context - remove all the loaded models"},
Michal Vaskof3e59f12015-06-18 11:53:56 +02001054 {"verb", cmd_verb, cmd_verb_help, "Change verbosity"},
1055 {"quit", cmd_quit, NULL, "Quit the program"},
1056 /* synonyms for previous commands */
1057 {"?", cmd_help, NULL, "Display commands description"},
1058 {"exit", cmd_quit, NULL, "Quit the program"},
1059 {NULL, NULL, NULL, NULL}
1060};