blob: 38b42a8db2aa5c9bf7c22efe6395edafad2cf16d [file] [log] [blame]
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001/**
Michal Vaskoafac7822020-10-20 14:22:26 +02002 * @file in.c
Radek Krejcif0e1ba52020-05-22 15:14:35 +02003 * @author Radek Krejci <rkrejci@cesnet.cz>
Michal Vaskoafac7822020-10-20 14:22:26 +02004 * @brief libyang input functions.
Radek Krejcif0e1ba52020-05-22 15:14:35 +02005 *
Michal Vaskoafac7822020-10-20 14:22:26 +02006 * Copyright (c) 2015 - 2020 CESNET, z.s.p.o.
Radek Krejcif0e1ba52020-05-22 15:14:35 +02007 *
8 * 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
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
15#define _GNU_SOURCE
Radek Krejcif8dc59a2020-11-25 13:47:44 +010016#define _POSIX_C_SOURCE 200809L /* strdup, strndup */
17
Michal Vaskoafac7822020-10-20 14:22:26 +020018#include "in.h"
19#include "in_internal.h"
Radek Krejcica376bd2020-06-11 16:04:06 +020020
Radek Krejcif0e1ba52020-05-22 15:14:35 +020021#include <errno.h>
22#include <fcntl.h>
23#include <limits.h>
Radek Krejci47fab892020-11-05 17:02:41 +010024#include <stdint.h>
Radek Krejcif0e1ba52020-05-22 15:14:35 +020025#include <stdio.h>
Radek Krejcica376bd2020-06-11 16:04:06 +020026#include <stdlib.h>
Radek Krejcif0e1ba52020-05-22 15:14:35 +020027#include <string.h>
Radek Krejcica376bd2020-06-11 16:04:06 +020028#include <unistd.h>
Radek Krejcif0e1ba52020-05-22 15:14:35 +020029
Michal Vasko5aa44c02020-06-29 11:47:02 +020030#include "compat.h"
Radek Krejcica376bd2020-06-11 16:04:06 +020031#include "dict.h"
32#include "log.h"
Michal Vasko8f702ee2024-02-20 15:44:24 +010033#include "ly_common.h"
Radek Krejci1798aae2020-07-14 13:26:06 +020034#include "parser_data.h"
Radek Krejcif0e1ba52020-05-22 15:14:35 +020035#include "parser_internal.h"
Radek Krejci47fab892020-11-05 17:02:41 +010036#include "set.h"
Radek Krejci77114102021-03-10 15:21:57 +010037#include "tree.h"
Radek Krejci47fab892020-11-05 17:02:41 +010038#include "tree_data.h"
Radek Krejci1798aae2020-07-14 13:26:06 +020039#include "tree_data_internal.h"
Radek Krejci47fab892020-11-05 17:02:41 +010040#include "tree_schema.h"
Radek Krejcica376bd2020-06-11 16:04:06 +020041#include "tree_schema_internal.h"
Radek Krejcif0e1ba52020-05-22 15:14:35 +020042
Jan Kundrátc53a7ec2021-12-09 16:01:19 +010043LIBYANG_API_DEF LY_IN_TYPE
Radek Krejcif0e1ba52020-05-22 15:14:35 +020044ly_in_type(const struct ly_in *in)
45{
46 LY_CHECK_ARG_RET(NULL, in, LY_IN_ERROR);
47 return in->type;
48}
49
Jan Kundrátc53a7ec2021-12-09 16:01:19 +010050LIBYANG_API_DEF LY_ERR
Michal Vaskoddd76592022-01-17 13:34:48 +010051ly_in_reset(struct ly_in *in)
52{
53 LY_CHECK_ARG_RET(NULL, in, LY_EINVAL);
54
55 in->current = in->func_start = in->start;
56 in->line = 1;
57 return LY_SUCCESS;
58}
59
60LIBYANG_API_DEF LY_ERR
Radek Krejcif0e1ba52020-05-22 15:14:35 +020061ly_in_new_fd(int fd, struct ly_in **in)
62{
63 size_t length;
64 char *addr;
65
66 LY_CHECK_ARG_RET(NULL, fd >= 0, in, LY_EINVAL);
67
68 LY_CHECK_RET(ly_mmap(NULL, fd, &length, (void **)&addr));
69 if (!addr) {
70 LOGERR(NULL, LY_EINVAL, "Empty input file.");
71 return LY_EINVAL;
72 }
73
74 *in = calloc(1, sizeof **in);
75 LY_CHECK_ERR_RET(!*in, LOGMEM(NULL); ly_munmap(addr, length), LY_EMEM);
76
77 (*in)->type = LY_IN_FD;
78 (*in)->method.fd = fd;
Michal Vasko63f3d842020-07-08 10:10:14 +020079 (*in)->current = (*in)->start = (*in)->func_start = addr;
Radek Krejcid54412f2020-12-17 20:25:35 +010080 (*in)->line = 1;
Radek Krejcif0e1ba52020-05-22 15:14:35 +020081 (*in)->length = length;
82
83 return LY_SUCCESS;
84}
85
Jan Kundrátc53a7ec2021-12-09 16:01:19 +010086LIBYANG_API_DEF int
Radek Krejcif0e1ba52020-05-22 15:14:35 +020087ly_in_fd(struct ly_in *in, int fd)
88{
89 int prev_fd;
90 size_t length;
91 const char *addr;
92
93 LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_FD, -1);
94
95 prev_fd = in->method.fd;
96
97 if (fd != -1) {
98 LY_CHECK_RET(ly_mmap(NULL, fd, &length, (void **)&addr), -1);
99 if (!addr) {
100 LOGERR(NULL, LY_EINVAL, "Empty input file.");
101 return -1;
102 }
103
Michal Vasko22df3f02020-08-24 13:29:22 +0200104 ly_munmap((char *)in->start, in->length);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200105
106 in->method.fd = fd;
107 in->current = in->start = addr;
Radek Krejcid54412f2020-12-17 20:25:35 +0100108 in->line = 1;
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200109 in->length = length;
110 }
111
112 return prev_fd;
113}
114
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100115LIBYANG_API_DEF LY_ERR
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200116ly_in_new_file(FILE *f, struct ly_in **in)
117{
118 LY_CHECK_ARG_RET(NULL, f, in, LY_EINVAL);
119
120 LY_CHECK_RET(ly_in_new_fd(fileno(f), in));
121
122 /* convert the LY_IN_FD input handler into the LY_IN_FILE */
123 (*in)->type = LY_IN_FILE;
124 (*in)->method.f = f;
125
126 return LY_SUCCESS;
127}
128
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100129LIBYANG_API_DEF FILE *
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200130ly_in_file(struct ly_in *in, FILE *f)
131{
132 FILE *prev_f;
133
134 LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_FILE, NULL);
135
136 prev_f = in->method.f;
137
138 if (f) {
139 /* convert LY_IN_FILE handler into LY_IN_FD to be able to update it via ly_in_fd() */
140 in->type = LY_IN_FD;
141 in->method.fd = fileno(prev_f);
142 if (ly_in_fd(in, fileno(f)) == -1) {
143 in->type = LY_IN_FILE;
144 in->method.f = prev_f;
145 return NULL;
146 }
147
148 /* if success, convert the result back */
149 in->type = LY_IN_FILE;
150 in->method.f = f;
151 }
152
153 return prev_f;
154}
155
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100156LIBYANG_API_DEF LY_ERR
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200157ly_in_new_memory(const char *str, struct ly_in **in)
158{
159 LY_CHECK_ARG_RET(NULL, str, in, LY_EINVAL);
160
161 *in = calloc(1, sizeof **in);
162 LY_CHECK_ERR_RET(!*in, LOGMEM(NULL), LY_EMEM);
163
164 (*in)->type = LY_IN_MEMORY;
Michal Vasko63f3d842020-07-08 10:10:14 +0200165 (*in)->start = (*in)->current = (*in)->func_start = str;
Radek Krejcid54412f2020-12-17 20:25:35 +0100166 (*in)->line = 1;
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200167
168 return LY_SUCCESS;
169}
170
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100171LIBYANG_API_DEF const char *
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200172ly_in_memory(struct ly_in *in, const char *str)
173{
174 const char *data;
175
176 LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_MEMORY, NULL);
177
178 data = in->current;
179
180 if (str) {
181 in->start = in->current = str;
Radek Krejcid54412f2020-12-17 20:25:35 +0100182 in->line = 1;
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200183 }
184
185 return data;
186}
187
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100188LIBYANG_API_DEF LY_ERR
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200189ly_in_new_filepath(const char *filepath, size_t len, struct ly_in **in)
190{
Radek Krejci0f969882020-08-21 16:56:47 +0200191 LY_ERR ret;
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200192 char *fp;
193 int fd;
194
195 LY_CHECK_ARG_RET(NULL, filepath, in, LY_EINVAL);
196
197 if (len) {
198 fp = strndup(filepath, len);
199 } else {
200 fp = strdup(filepath);
201 }
202
203 fd = open(fp, O_RDONLY);
Michal Vaskof2eb8af2020-07-14 12:22:40 +0200204 LY_CHECK_ERR_RET(fd == -1, LOGERR(NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", fp, strerror(errno)); free(fp),
Michal Vasko69730152020-10-09 16:30:07 +0200205 LY_ESYS);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200206
207 LY_CHECK_ERR_RET(ret = ly_in_new_fd(fd, in), free(fp), ret);
208
209 /* convert the LY_IN_FD input handler into the LY_IN_FILE */
210 (*in)->type = LY_IN_FILEPATH;
211 (*in)->method.fpath.fd = fd;
212 (*in)->method.fpath.filepath = fp;
213
214 return LY_SUCCESS;
215}
216
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100217LIBYANG_API_DEF const char *
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200218ly_in_filepath(struct ly_in *in, const char *filepath, size_t len)
219{
220 int fd, prev_fd;
221 char *fp = NULL;
222
223 LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_FILEPATH, filepath ? NULL : ((void *)-1));
224
225 if (!filepath) {
226 return in->method.fpath.filepath;
227 }
228
229 if (len) {
230 fp = strndup(filepath, len);
231 } else {
232 fp = strdup(filepath);
233 }
234
235 /* replace filepath */
236 fd = open(fp, O_RDONLY);
237 LY_CHECK_ERR_RET(!fd, LOGERR(NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", fp, strerror(errno)); free(fp), NULL);
238
239 /* convert LY_IN_FILEPATH handler into LY_IN_FD to be able to update it via ly_in_fd() */
240 in->type = LY_IN_FD;
241 prev_fd = ly_in_fd(in, fd);
242 LY_CHECK_ERR_RET(prev_fd == -1, in->type = LY_IN_FILEPATH; free(fp), NULL);
243
244 /* and convert the result back */
245 in->type = LY_IN_FILEPATH;
246 close(prev_fd);
247 free(in->method.fpath.filepath);
248 in->method.fpath.fd = fd;
249 in->method.fpath.filepath = fp;
250
251 return NULL;
252}
253
Michal Vaskoddd76592022-01-17 13:34:48 +0100254LIBYANG_API_DEF size_t
255ly_in_parsed(const struct ly_in *in)
256{
Michal Vasko62c37262023-01-11 11:12:46 +0100257 LY_CHECK_ARG_RET(NULL, in, 0);
258
Michal Vaskoddd76592022-01-17 13:34:48 +0100259 return in->current - in->func_start;
260}
261
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100262LIBYANG_API_DEF void
Radek Krejci857189e2020-09-01 13:26:36 +0200263ly_in_free(struct ly_in *in, ly_bool destroy)
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200264{
265 if (!in) {
266 return;
267 } else if (in->type == LY_IN_ERROR) {
268 LOGINT(NULL);
269 return;
270 }
271
272 if (destroy) {
273 if (in->type == LY_IN_MEMORY) {
Michal Vasko22df3f02020-08-24 13:29:22 +0200274 free((char *)in->start);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200275 } else {
Michal Vasko22df3f02020-08-24 13:29:22 +0200276 ly_munmap((char *)in->start, in->length);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200277
278 if (in->type == LY_IN_FILE) {
279 fclose(in->method.f);
280 } else {
281 close(in->method.fd);
282
283 if (in->type == LY_IN_FILEPATH) {
284 free(in->method.fpath.filepath);
285 }
286 }
287 }
288 } else if (in->type != LY_IN_MEMORY) {
Michal Vasko22df3f02020-08-24 13:29:22 +0200289 ly_munmap((char *)in->start, in->length);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200290
291 if (in->type == LY_IN_FILEPATH) {
292 close(in->method.fpath.fd);
293 free(in->method.fpath.filepath);
294 }
295 }
296
297 free(in);
298}
Michal Vasko63f3d842020-07-08 10:10:14 +0200299
Michal Vasko62c37262023-01-11 11:12:46 +0100300LIBYANG_API_DEF LY_ERR
Michal Vasko63f3d842020-07-08 10:10:14 +0200301ly_in_read(struct ly_in *in, void *buf, size_t count)
302{
Michal Vasko62c37262023-01-11 11:12:46 +0100303 LY_CHECK_ARG_RET(NULL, in, buf, LY_EINVAL);
304
Michal Vasko63f3d842020-07-08 10:10:14 +0200305 if (in->length && (in->length - (in->current - in->start) < count)) {
306 /* EOF */
307 return LY_EDENIED;
308 }
309
Michal Vasko08e9b112021-06-11 15:41:17 +0200310 if (count) {
311 memcpy(buf, in->current, count);
312 }
Michal Vasko63f3d842020-07-08 10:10:14 +0200313 in->current += count;
314 return LY_SUCCESS;
315}
316
Michal Vasko62c37262023-01-11 11:12:46 +0100317LIBYANG_API_DEF LY_ERR
Michal Vasko63f3d842020-07-08 10:10:14 +0200318ly_in_skip(struct ly_in *in, size_t count)
319{
Michal Vasko62c37262023-01-11 11:12:46 +0100320 LY_CHECK_ARG_RET(NULL, in, LY_EINVAL);
321
Michal Vasko63f3d842020-07-08 10:10:14 +0200322 if (in->length && (in->length - (in->current - in->start) < count)) {
323 /* EOF */
324 return LY_EDENIED;
325 }
326
327 in->current += count;
328 return LY_SUCCESS;
329}