blob: 38663c22e830e778eeb39f7a776b5b5e6412b638 [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>
Radek Krejcie9f13b12020-11-09 17:42:04 +010021#include <stdint.h>
22#include <stdio.h>
23#include <stdlib.h>
24
25#include "libyang.h"
26
27#include "common.h"
28
29void
30cmd_add_help(void)
31{
32 printf("Usage: add [-iD] <schema1> [<schema2> ...]\n"
33 " Add a new module from a specific file.\n\n"
34 " -D, --disable-searchdir\n"
35 " Do not implicitly search in current working directory for\n"
36 " the import schema modules. If specified a second time, do not\n"
37 " even search in the module directory (all modules must be \n"
38 " explicitly specified).\n"
39 " -F FEATURES, --features=FEATURES\n"
Michal Vasko703370c2021-10-19 14:07:16 +020040 " Features to support, default all in all implemented modules.\n"
roman300b8782022-08-11 12:49:21 +020041 " Specify separately for each module.\n"
Radek Krejcie9f13b12020-11-09 17:42:04 +010042 " <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;
Michal Vasko584b0c42022-09-14 10:20:52 +020063 const char *all_features[] = {"*", NULL};
Radek Krejcie9f13b12020-11-09 17:42:04 +010064 struct ly_set fset = {0};
65
66 if (parse_cmdline(cmdline, &argc, &argv)) {
67 goto cleanup;
68 }
69
aPiecek6d41a522023-03-27 14:20:38 +020070 while ((opt = getopt_long(argc, argv, "DF:hi", options, &opt_index)) != -1) {
Radek Krejcie9f13b12020-11-09 17:42:04 +010071 switch (opt) {
72 case 'D': /* --disable--search */
73 if (options_ctx & LY_CTX_DISABLE_SEARCHDIRS) {
74 YLMSG_W("The -D option specified too many times.\n");
75 }
76 if (options_ctx & LY_CTX_DISABLE_SEARCHDIR_CWD) {
77 options_ctx &= ~LY_CTX_DISABLE_SEARCHDIR_CWD;
78 options_ctx |= LY_CTX_DISABLE_SEARCHDIRS;
79 } else {
80 options_ctx |= LY_CTX_DISABLE_SEARCHDIR_CWD;
81 }
82 break;
83
84 case 'F': /* --features */
85 if (parse_features(optarg, &fset)) {
86 goto cleanup;
87 }
88 break;
89
90 case 'h':
91 cmd_add_help();
92 goto cleanup;
93
Michal Vasko8d6d0ad2021-10-19 12:32:27 +020094 case 'i': /* --make-implemented */
Radek Krejcie9f13b12020-11-09 17:42:04 +010095 if (options_ctx & LY_CTX_REF_IMPLEMENTED) {
96 options_ctx &= ~LY_CTX_REF_IMPLEMENTED;
97 options_ctx |= LY_CTX_ALL_IMPLEMENTED;
98 } else {
99 options_ctx |= LY_CTX_REF_IMPLEMENTED;
100 }
101 break;
102
103 default:
104 YLMSG_E("Unknown option.\n");
105 goto cleanup;
106 }
107 }
108
109 if (argc == optind) {
110 /* no argument */
111 cmd_add_help();
112 goto cleanup;
113 }
114
Michal Vasko703370c2021-10-19 14:07:16 +0200115 if (!fset.count) {
116 /* no features, enable all of them */
117 options_ctx |= LY_CTX_ENABLE_IMP_FEATURES;
118 }
119
Radek Krejcie9f13b12020-11-09 17:42:04 +0100120 if (options_ctx) {
121 ly_ctx_set_options(*ctx, options_ctx);
122 }
123
124 for (int i = 0; i < argc - optind; i++) {
125 /* process the schema module files */
126 LY_ERR ret;
127 uint8_t path_unset = 1; /* flag to unset the path from the searchpaths list (if not already present) */
128 char *dir, *module;
129 const char **features = NULL;
130 struct ly_in *in = NULL;
131
132 if (parse_schema_path(argv[optind + i], &dir, &module)) {
133 goto cleanup;
134 }
135
136 /* add temporarily also the path of the module itself */
aPiecekfdd555d2023-03-27 14:26:01 +0200137 if (ly_ctx_set_searchdir(*ctx, dir) == LY_EEXIST) {
Radek Krejcie9f13b12020-11-09 17:42:04 +0100138 path_unset = 0;
139 }
140
141 /* get features list for this module */
Michal Vasko584b0c42022-09-14 10:20:52 +0200142 if (!fset.count) {
143 features = all_features;
144 } else {
145 get_features(&fset, module, &features);
146 }
Radek Krejcie9f13b12020-11-09 17:42:04 +0100147
148 /* temporary cleanup */
149 free(dir);
150 free(module);
151
152 /* prepare input handler */
153 ret = ly_in_new_filepath(argv[optind + i], 0, &in);
154 if (ret) {
155 goto cleanup;
156 }
157
158 /* parse the file */
159 ret = lys_parse(*ctx, in, LYS_IN_UNKNOWN, features, NULL);
160 ly_in_free(in, 1);
161 ly_ctx_unset_searchdir_last(*ctx, path_unset);
162
163 if (ret) {
164 /* libyang printed the error messages */
165 goto cleanup;
166 }
167 }
168
169cleanup:
170 if (options_ctx) {
171 ly_ctx_unset_options(*ctx, options_ctx);
172 }
173 ly_set_erase(&fset, free_features);
174 free_cmdline(argv);
175}