blob: c976624e699332946cf6b7a13d1e5eb1c24b3a52 [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>
21#include <libgen.h>
22#include <stdint.h>
23#include <stdio.h>
24#include <stdlib.h>
25
26#include "libyang.h"
27
28#include "common.h"
29
30void
31cmd_add_help(void)
32{
33 printf("Usage: add [-iD] <schema1> [<schema2> ...]\n"
34 " Add a new module from a specific file.\n\n"
35 " -D, --disable-searchdir\n"
36 " Do not implicitly search in current working directory for\n"
37 " the import schema modules. If specified a second time, do not\n"
38 " even search in the module directory (all modules must be \n"
39 " explicitly specified).\n"
40 " -F FEATURES, --features=FEATURES\n"
41 " Features to support, default all.\n"
42 " <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"
46 " all the modules are set implemented.\n");
47}
48
49void
50cmd_add(struct ly_ctx **ctx, const char *cmdline)
51{
52 int argc = 0;
53 char **argv = NULL;
54 int opt, opt_index;
55 struct option options[] = {
56 {"disable-searchdir", no_argument, NULL, 'D'},
57 {"features", required_argument, NULL, 'F'},
58 {"help", no_argument, NULL, 'h'},
Michal Vasko8d6d0ad2021-10-19 12:32:27 +020059 {"make-implemented", no_argument, NULL, 'i'},
Radek Krejcie9f13b12020-11-09 17:42:04 +010060 {NULL, 0, NULL, 0}
61 };
62 uint16_t options_ctx = 0;
63 struct ly_set fset = {0};
64
65 if (parse_cmdline(cmdline, &argc, &argv)) {
66 goto cleanup;
67 }
68
69 while ((opt = getopt_long(argc, argv, "D:F:hi", options, &opt_index)) != -1) {
70 switch (opt) {
71 case 'D': /* --disable--search */
72 if (options_ctx & LY_CTX_DISABLE_SEARCHDIRS) {
73 YLMSG_W("The -D option specified too many times.\n");
74 }
75 if (options_ctx & LY_CTX_DISABLE_SEARCHDIR_CWD) {
76 options_ctx &= ~LY_CTX_DISABLE_SEARCHDIR_CWD;
77 options_ctx |= LY_CTX_DISABLE_SEARCHDIRS;
78 } else {
79 options_ctx |= LY_CTX_DISABLE_SEARCHDIR_CWD;
80 }
81 break;
82
83 case 'F': /* --features */
84 if (parse_features(optarg, &fset)) {
85 goto cleanup;
86 }
87 break;
88
89 case 'h':
90 cmd_add_help();
91 goto cleanup;
92
Michal Vasko8d6d0ad2021-10-19 12:32:27 +020093 case 'i': /* --make-implemented */
Radek Krejcie9f13b12020-11-09 17:42:04 +010094 if (options_ctx & LY_CTX_REF_IMPLEMENTED) {
95 options_ctx &= ~LY_CTX_REF_IMPLEMENTED;
96 options_ctx |= LY_CTX_ALL_IMPLEMENTED;
97 } else {
98 options_ctx |= LY_CTX_REF_IMPLEMENTED;
99 }
100 break;
101
102 default:
103 YLMSG_E("Unknown option.\n");
104 goto cleanup;
105 }
106 }
107
108 if (argc == optind) {
109 /* no argument */
110 cmd_add_help();
111 goto cleanup;
112 }
113
114 if (options_ctx) {
115 ly_ctx_set_options(*ctx, options_ctx);
116 }
117
118 for (int i = 0; i < argc - optind; i++) {
119 /* process the schema module files */
120 LY_ERR ret;
121 uint8_t path_unset = 1; /* flag to unset the path from the searchpaths list (if not already present) */
122 char *dir, *module;
123 const char **features = NULL;
124 struct ly_in *in = NULL;
125
126 if (parse_schema_path(argv[optind + i], &dir, &module)) {
127 goto cleanup;
128 }
129
130 /* add temporarily also the path of the module itself */
131 if (ly_ctx_set_searchdir(*ctx, dirname(dir)) == LY_EEXIST) {
132 path_unset = 0;
133 }
134
135 /* get features list for this module */
136 get_features(&fset, module, &features);
137
138 /* temporary cleanup */
139 free(dir);
140 free(module);
141
142 /* prepare input handler */
143 ret = ly_in_new_filepath(argv[optind + i], 0, &in);
144 if (ret) {
145 goto cleanup;
146 }
147
148 /* parse the file */
149 ret = lys_parse(*ctx, in, LYS_IN_UNKNOWN, features, NULL);
150 ly_in_free(in, 1);
151 ly_ctx_unset_searchdir_last(*ctx, path_unset);
152
153 if (ret) {
154 /* libyang printed the error messages */
155 goto cleanup;
156 }
157 }
158
159cleanup:
160 if (options_ctx) {
161 ly_ctx_unset_options(*ctx, options_ctx);
162 }
163 ly_set_erase(&fset, free_features);
164 free_cmdline(argv);
165}