blob: ff025dbdf4bfb7ed30172ddf525f6f222a65a89e [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"
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;
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
Michal Vasko703370c2021-10-19 14:07:16 +0200114 if (!fset.count) {
115 /* no features, enable all of them */
116 options_ctx |= LY_CTX_ENABLE_IMP_FEATURES;
117 }
118
Radek Krejcie9f13b12020-11-09 17:42:04 +0100119 if (options_ctx) {
120 ly_ctx_set_options(*ctx, options_ctx);
121 }
122
123 for (int i = 0; i < argc - optind; i++) {
124 /* process the schema module files */
125 LY_ERR ret;
126 uint8_t path_unset = 1; /* flag to unset the path from the searchpaths list (if not already present) */
127 char *dir, *module;
128 const char **features = NULL;
129 struct ly_in *in = NULL;
130
131 if (parse_schema_path(argv[optind + i], &dir, &module)) {
132 goto cleanup;
133 }
134
135 /* add temporarily also the path of the module itself */
136 if (ly_ctx_set_searchdir(*ctx, dirname(dir)) == LY_EEXIST) {
137 path_unset = 0;
138 }
139
140 /* get features list for this module */
141 get_features(&fset, module, &features);
142
143 /* temporary cleanup */
144 free(dir);
145 free(module);
146
147 /* prepare input handler */
148 ret = ly_in_new_filepath(argv[optind + i], 0, &in);
149 if (ret) {
150 goto cleanup;
151 }
152
153 /* parse the file */
154 ret = lys_parse(*ctx, in, LYS_IN_UNKNOWN, features, NULL);
155 ly_in_free(in, 1);
156 ly_ctx_unset_searchdir_last(*ctx, path_unset);
157
158 if (ret) {
159 /* libyang printed the error messages */
160 goto cleanup;
161 }
162 }
163
164cleanup:
165 if (options_ctx) {
166 ly_ctx_unset_options(*ctx, options_ctx);
167 }
168 ly_set_erase(&fset, free_features);
169 free_cmdline(argv);
170}