blob: bbfdfd6e3016956eefa4e9f2bd64e523532f6fc3 [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"
Michal Vasko703370c2021-10-19 14:07:16 +020041 " Features to support, default all in all implemented modules.\n"
roman300b8782022-08-11 12:49:21 +020042 " Specify separately for each module.\n"
Radek Krejcie9f13b12020-11-09 17:42:04 +010043 " <modname>:[<feature>,]*\n"
Michal Vasko8d6d0ad2021-10-19 12:32:27 +020044 " -i, --make-implemented\n"
Radek Krejcie9f13b12020-11-09 17:42:04 +010045 " Make the imported modules \"referenced\" from any loaded\n"
46 " <schema> module also implemented. If specified a second time,\n"
47 " all the modules are set implemented.\n");
48}
49
50void
51cmd_add(struct ly_ctx **ctx, const char *cmdline)
52{
53 int argc = 0;
54 char **argv = NULL;
55 int opt, opt_index;
56 struct option options[] = {
57 {"disable-searchdir", no_argument, NULL, 'D'},
58 {"features", required_argument, NULL, 'F'},
59 {"help", no_argument, NULL, 'h'},
Michal Vasko8d6d0ad2021-10-19 12:32:27 +020060 {"make-implemented", no_argument, NULL, 'i'},
Radek Krejcie9f13b12020-11-09 17:42:04 +010061 {NULL, 0, NULL, 0}
62 };
63 uint16_t options_ctx = 0;
Michal Vasko584b0c42022-09-14 10:20:52 +020064 const char *all_features[] = {"*", NULL};
Radek Krejcie9f13b12020-11-09 17:42:04 +010065 struct ly_set fset = {0};
66
67 if (parse_cmdline(cmdline, &argc, &argv)) {
68 goto cleanup;
69 }
70
71 while ((opt = getopt_long(argc, argv, "D:F:hi", options, &opt_index)) != -1) {
72 switch (opt) {
73 case 'D': /* --disable--search */
74 if (options_ctx & LY_CTX_DISABLE_SEARCHDIRS) {
75 YLMSG_W("The -D option specified too many times.\n");
76 }
77 if (options_ctx & LY_CTX_DISABLE_SEARCHDIR_CWD) {
78 options_ctx &= ~LY_CTX_DISABLE_SEARCHDIR_CWD;
79 options_ctx |= LY_CTX_DISABLE_SEARCHDIRS;
80 } else {
81 options_ctx |= LY_CTX_DISABLE_SEARCHDIR_CWD;
82 }
83 break;
84
85 case 'F': /* --features */
86 if (parse_features(optarg, &fset)) {
87 goto cleanup;
88 }
89 break;
90
91 case 'h':
92 cmd_add_help();
93 goto cleanup;
94
Michal Vasko8d6d0ad2021-10-19 12:32:27 +020095 case 'i': /* --make-implemented */
Radek Krejcie9f13b12020-11-09 17:42:04 +010096 if (options_ctx & LY_CTX_REF_IMPLEMENTED) {
97 options_ctx &= ~LY_CTX_REF_IMPLEMENTED;
98 options_ctx |= LY_CTX_ALL_IMPLEMENTED;
99 } else {
100 options_ctx |= LY_CTX_REF_IMPLEMENTED;
101 }
102 break;
103
104 default:
105 YLMSG_E("Unknown option.\n");
106 goto cleanup;
107 }
108 }
109
110 if (argc == optind) {
111 /* no argument */
112 cmd_add_help();
113 goto cleanup;
114 }
115
Michal Vasko703370c2021-10-19 14:07:16 +0200116 if (!fset.count) {
117 /* no features, enable all of them */
118 options_ctx |= LY_CTX_ENABLE_IMP_FEATURES;
119 }
120
Radek Krejcie9f13b12020-11-09 17:42:04 +0100121 if (options_ctx) {
122 ly_ctx_set_options(*ctx, options_ctx);
123 }
124
125 for (int i = 0; i < argc - optind; i++) {
126 /* process the schema module files */
127 LY_ERR ret;
128 uint8_t path_unset = 1; /* flag to unset the path from the searchpaths list (if not already present) */
129 char *dir, *module;
130 const char **features = NULL;
131 struct ly_in *in = NULL;
132
133 if (parse_schema_path(argv[optind + i], &dir, &module)) {
134 goto cleanup;
135 }
136
137 /* add temporarily also the path of the module itself */
138 if (ly_ctx_set_searchdir(*ctx, dirname(dir)) == LY_EEXIST) {
139 path_unset = 0;
140 }
141
142 /* get features list for this module */
Michal Vasko584b0c42022-09-14 10:20:52 +0200143 if (!fset.count) {
144 features = all_features;
145 } else {
146 get_features(&fset, module, &features);
147 }
Radek Krejcie9f13b12020-11-09 17:42:04 +0100148
149 /* temporary cleanup */
150 free(dir);
151 free(module);
152
153 /* prepare input handler */
154 ret = ly_in_new_filepath(argv[optind + i], 0, &in);
155 if (ret) {
156 goto cleanup;
157 }
158
159 /* parse the file */
160 ret = lys_parse(*ctx, in, LYS_IN_UNKNOWN, features, NULL);
161 ly_in_free(in, 1);
162 ly_ctx_unset_searchdir_last(*ctx, path_unset);
163
164 if (ret) {
165 /* libyang printed the error messages */
166 goto cleanup;
167 }
168 }
169
170cleanup:
171 if (options_ctx) {
172 ly_ctx_unset_options(*ctx, options_ctx);
173 }
174 ly_set_erase(&fset, free_features);
175 free_cmdline(argv);
176}