blob: 69245d4209031aae797c60c84924dc420ef4c2c4 [file] [log] [blame]
Michal Vasko1324b6c2018-09-07 11:16:23 +02001/**
2 * @file common.c
3 * @author Michal Vasko <mvasko@cesnet.cz>
4 * @brief common internal definitions for libyang
5 *
6 * Copyright (c) 2018 CESNET, z.s.p.o.
7 *
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 */
Radek Krejcib7db73a2018-10-24 14:18:40 +020014
15#include "common.h"
Michal Vasko1324b6c2018-09-07 11:16:23 +020016
Radek Krejci86d106e2018-10-18 09:53:19 +020017#include <assert.h>
Michal Vasko841d1a92018-09-07 15:40:31 +020018#include <ctype.h>
Radek Krejci4546aa62019-07-15 16:53:32 +020019#include <errno.h>
20#include <stdarg.h>
21#include <stdlib.h>
Michal Vasko841d1a92018-09-07 15:40:31 +020022#include <string.h>
Radek Krejci86d106e2018-10-18 09:53:19 +020023#include <sys/mman.h>
24#include <sys/stat.h>
Radek Krejci86d106e2018-10-18 09:53:19 +020025#include <unistd.h>
Michal Vasko841d1a92018-09-07 15:40:31 +020026
Radek Krejci0935f412019-08-20 16:15:18 +020027#include "plugins_exts.h"
Michal Vasko841d1a92018-09-07 15:40:31 +020028#include "tree_schema.h"
Radek Krejcib4a4a272019-06-10 12:44:52 +020029#include "tree_schema_internal.h"
Michal Vasko1324b6c2018-09-07 11:16:23 +020030
Radek Krejcic59bc972018-09-17 16:13:06 +020031const char *const ly_stmt_list[] = {
Radek Krejcid6b76452019-09-03 17:03:03 +020032 [LY_STMT_ACTION] = "action",
33 [LY_STMT_ANYDATA] = "anydata",
34 [LY_STMT_ANYXML] = "anyxml",
35 [LY_STMT_ARGUMENT] = "argument",
36 [LY_STMT_AUGMENT] = "augment",
37 [LY_STMT_BASE] = "base",
38 [LY_STMT_BELONGS_TO] = "belongs-to",
39 [LY_STMT_BIT] = "bit",
40 [LY_STMT_CASE] = "case",
41 [LY_STMT_CHOICE] = "choice",
42 [LY_STMT_CONFIG] = "config",
43 [LY_STMT_CONTACT] = "contact",
44 [LY_STMT_CONTAINER] = "container",
45 [LY_STMT_EXTENSION_INSTANCE] = "<extension-instance>",
46 [LY_STMT_DEFAULT] = "default",
47 [LY_STMT_DESCRIPTION] = "description",
48 [LY_STMT_DEVIATE] = "deviate",
49 [LY_STMT_DEVIATION] = "deviation",
50 [LY_STMT_ENUM] = "enum",
51 [LY_STMT_ERROR_APP_TAG] = "error-app-tag",
52 [LY_STMT_ERROR_MESSAGE] = "error-message",
53 [LY_STMT_EXTENSION] = "extension",
54 [LY_STMT_FEATURE] = "feature",
55 [LY_STMT_FRACTION_DIGITS] = "fraction-digits",
56 [LY_STMT_GROUPING] = "grouping",
57 [LY_STMT_IDENTITY] = "identity",
58 [LY_STMT_IF_FEATURE] = "if-feature",
59 [LY_STMT_IMPORT] = "import",
60 [LY_STMT_INCLUDE] = "include",
61 [LY_STMT_INPUT] = "input",
62 [LY_STMT_KEY] = "key",
63 [LY_STMT_LEAF] = "leaf",
64 [LY_STMT_LEAF_LIST] = "leaf-list",
65 [LY_STMT_LENGTH] = "length",
66 [LY_STMT_LIST] = "list",
67 [LY_STMT_MANDATORY] = "mandatory",
68 [LY_STMT_MAX_ELEMENTS] = "max-elements",
69 [LY_STMT_MIN_ELEMENTS] = "min-elements",
70 [LY_STMT_MODIFIER] = "modifier",
71 [LY_STMT_MODULE] = "module",
72 [LY_STMT_MUST] = "must",
73 [LY_STMT_NAMESPACE] = "namespace",
74 [LY_STMT_NOTIFICATION] = "notification",
75 [LY_STMT_ORDERED_BY] = "ordered-by",
76 [LY_STMT_ORGANIZATION] = "organization",
77 [LY_STMT_OUTPUT] = "output",
78 [LY_STMT_PATH] = "path",
79 [LY_STMT_PATTERN] = "pattern",
80 [LY_STMT_POSITION] = "position",
81 [LY_STMT_PREFIX] = "prefix",
82 [LY_STMT_PRESENCE] = "presence",
83 [LY_STMT_RANGE] = "range",
84 [LY_STMT_REFERENCE] = "reference",
85 [LY_STMT_REFINE] = "refine",
86 [LY_STMT_REQUIRE_INSTANCE] = "require-instance",
87 [LY_STMT_REVISION] = "revision",
88 [LY_STMT_REVISION_DATE] = "revision-date",
89 [LY_STMT_RPC] = "rpc",
90 [LY_STMT_STATUS] = "status",
91 [LY_STMT_SUBMODULE] = "submodule",
92 [LY_STMT_TYPE] = "type",
93 [LY_STMT_TYPEDEF] = "typedef",
94 [LY_STMT_UNIQUE] = "unique",
95 [LY_STMT_UNITS] = "units",
96 [LY_STMT_USES] = "uses",
97 [LY_STMT_VALUE] = "value",
98 [LY_STMT_WHEN] = "when",
99 [LY_STMT_YANG_VERSION] = "yang-version",
100 [LY_STMT_YIN_ELEMENT] = "yin-element",
101 [LY_STMT_SYNTAX_SEMICOLON] = ";",
102 [LY_STMT_SYNTAX_LEFT_BRACE] = "{",
103 [LY_STMT_SYNTAX_RIGHT_BRACE] = "}",
104 [LY_STMT_ARG_TEXT] = "text",
105 [LY_STMT_ARG_VALUE] = "value",
Radek Krejcic59bc972018-09-17 16:13:06 +0200106};
107
108const char *const lyext_substmt_list[] = {
109 [LYEXT_SUBSTMT_ARGUMENT] = "argument",
110 [LYEXT_SUBSTMT_BASE] = "base",
111 [LYEXT_SUBSTMT_BELONGSTO] = "belongs-to",
112 [LYEXT_SUBSTMT_CONTACT] = "contact",
113 [LYEXT_SUBSTMT_DEFAULT] = "default",
114 [LYEXT_SUBSTMT_DESCRIPTION] = "description",
115 [LYEXT_SUBSTMT_ERRTAG] = "error-app-tag",
116 [LYEXT_SUBSTMT_ERRMSG] = "error-message",
117 [LYEXT_SUBSTMT_KEY] = "key",
118 [LYEXT_SUBSTMT_NAMESPACE] = "namespace",
119 [LYEXT_SUBSTMT_ORGANIZATION] = "organization",
120 [LYEXT_SUBSTMT_PATH] = "path",
121 [LYEXT_SUBSTMT_PREFIX] = "prefix",
122 [LYEXT_SUBSTMT_PRESENCE] = "presence",
123 [LYEXT_SUBSTMT_REFERENCE] = "reference",
124 [LYEXT_SUBSTMT_REVISIONDATE] = "revision-date",
125 [LYEXT_SUBSTMT_UNITS] = "units",
126 [LYEXT_SUBSTMT_VALUE] = "value",
127 [LYEXT_SUBSTMT_VERSION] = "yang-version",
128 [LYEXT_SUBSTMT_MODIFIER] = "modifier",
129 [LYEXT_SUBSTMT_REQINSTANCE] = "require-instance",
130 [LYEXT_SUBSTMT_YINELEM] = "yin-element",
131 [LYEXT_SUBSTMT_CONFIG] = "config",
132 [LYEXT_SUBSTMT_MANDATORY] = "mandatory",
133 [LYEXT_SUBSTMT_ORDEREDBY] = "ordered-by",
134 [LYEXT_SUBSTMT_STATUS] = "status",
135 [LYEXT_SUBSTMT_FRACDIGITS] = "fraction-digits",
136 [LYEXT_SUBSTMT_MAX] = "max-elements",
137 [LYEXT_SUBSTMT_MIN] = "min-elements",
138 [LYEXT_SUBSTMT_POSITION] = "position",
139 [LYEXT_SUBSTMT_UNIQUE] = "unique",
140 [LYEXT_SUBSTMT_IFFEATURE] = "if-feature",
141};
142
143const char *const ly_devmod_list[] = {
144 [LYS_DEV_NOT_SUPPORTED] = "not-supported",
145 [LYS_DEV_ADD] = "add",
146 [LYS_DEV_DELETE] = "delete",
147 [LYS_DEV_REPLACE] = "replace",
148};
149
Michal Vasko1324b6c2018-09-07 11:16:23 +0200150void *
151ly_realloc(void *ptr, size_t size)
152{
153 void *new_mem;
154
155 new_mem = realloc(ptr, size);
156 if (!new_mem) {
157 free(ptr);
158 }
159
160 return new_mem;
161}
Michal Vasko841d1a92018-09-07 15:40:31 +0200162
Radek Krejcib416be62018-10-01 14:51:45 +0200163LY_ERR
164ly_getutf8(const char **input, unsigned int *utf8_char, size_t *bytes_read)
165{
166 unsigned int c, len;
167 int aux;
168 int i;
169
Radek Krejcicc6a45c2019-05-13 10:16:14 +0200170 if (bytes_read) {
171 (*bytes_read) = 0;
172 }
173
Radek Krejcib416be62018-10-01 14:51:45 +0200174 c = (*input)[0];
175 LY_CHECK_RET(!c, LY_EINVAL);
176
177 if (!(c & 0x80)) {
178 /* one byte character */
179 len = 1;
180
181 if (c < 0x20 && c != 0x9 && c != 0xa && c != 0xd) {
182 return LY_EINVAL;
183 }
184 } else if ((c & 0xe0) == 0xc0) {
185 /* two bytes character */
186 len = 2;
187
188 aux = (*input)[1];
189 if ((aux & 0xc0) != 0x80) {
190 return LY_EINVAL;
191 }
192 c = ((c & 0x1f) << 6) | (aux & 0x3f);
193
194 if (c < 0x80) {
195 return LY_EINVAL;
196 }
197 } else if ((c & 0xf0) == 0xe0) {
198 /* three bytes character */
199 len = 3;
200
201 c &= 0x0f;
202 for (i = 1; i <= 2; i++) {
203 aux = (*input)[i];
204 if ((aux & 0xc0) != 0x80) {
205 return LY_EINVAL;
206 }
207
208 c = (c << 6) | (aux & 0x3f);
209 }
210
211 if (c < 0x800 || (c > 0xd7ff && c < 0xe000) || c > 0xfffd) {
212 return LY_EINVAL;
213 }
214 } else if ((c & 0xf8) == 0xf0) {
215 /* four bytes character */
216 len = 4;
217
218 c &= 0x07;
219 for (i = 1; i <= 3; i++) {
220 aux = (*input)[i];
221 if ((aux & 0xc0) != 0x80) {
222 return LY_EINVAL;
223 }
224
225 c = (c << 6) | (aux & 0x3f);
226 }
227
228 if (c < 0x1000 || c > 0x10ffff) {
229 return LY_EINVAL;
230 }
231 } else {
232 return LY_EINVAL;
233 }
234
235 (*utf8_char) = c;
236 (*input) += len;
237 if (bytes_read) {
238 (*bytes_read) = len;
239 }
240 return LY_SUCCESS;
241}
242
Radek Krejci76c98012019-08-14 11:23:24 +0200243/**
244 * @brief Static table of the UTF8 characters lengths according to their first byte.
245 */
246static const unsigned char
247utf8_char_length_table[] = {
248 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
249 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
250 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
251 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
252 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
253 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
254 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
255 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
256 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
257 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
258 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
259 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
260 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
261 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
262 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
263 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1
264};
265
266size_t
267ly_utf8len(const char *str, size_t bytes)
268{
269 size_t len;
270 const char *ptr;
271
272 for (len = 0, ptr = str; *ptr && (size_t)(ptr - str) < bytes; ++len, ptr += utf8_char_length_table[((unsigned char)(*ptr))]);
273 return len;
274}
275
Radek Krejcid972c252018-09-25 13:23:39 +0200276size_t
277LY_VCODE_INSTREXP_len(const char *str)
278{
279 size_t len = 0;
280 if (!str) {
281 return len;
282 } else if (!str[0]) {
283 return 1;
284 }
285 for (len = 1; len < LY_VCODE_INSTREXP_MAXLEN && str[len]; ++len);
286 return len;
287}
288
Radek Krejcif345c012018-09-19 11:12:59 +0200289LY_ERR
Radek Krejci86d106e2018-10-18 09:53:19 +0200290ly_mmap(struct ly_ctx *ctx, int fd, size_t *length, void **addr)
Michal Vasko841d1a92018-09-07 15:40:31 +0200291{
Radek Krejci86d106e2018-10-18 09:53:19 +0200292 struct stat sb;
293 long pagesize;
294 size_t m;
Michal Vasko841d1a92018-09-07 15:40:31 +0200295
Radek Krejci86d106e2018-10-18 09:53:19 +0200296 assert(length);
297 assert(addr);
298 assert(fd >= 0);
Michal Vasko841d1a92018-09-07 15:40:31 +0200299
Radek Krejci86d106e2018-10-18 09:53:19 +0200300 if (fstat(fd, &sb) == -1) {
301 LOGERR(ctx, LY_ESYS, "Failed to stat the file descriptor (%s) for the mmap().", strerror(errno));
302 return LY_ESYS;
Michal Vasko841d1a92018-09-07 15:40:31 +0200303 }
Radek Krejci86d106e2018-10-18 09:53:19 +0200304 if (!S_ISREG(sb.st_mode)) {
305 LOGERR(ctx, LY_EINVAL, "File to mmap() is not a regular file.");
306 return LY_ESYS;
Michal Vasko841d1a92018-09-07 15:40:31 +0200307 }
Radek Krejci86d106e2018-10-18 09:53:19 +0200308 if (!sb.st_size) {
309 *addr = NULL;
310 return LY_SUCCESS;
311 }
312 pagesize = sysconf(_SC_PAGESIZE);
313
314 m = sb.st_size % pagesize;
315 if (m && pagesize - m >= 1) {
316 /* there will be enough space (at least 1 byte) after the file content mapping to provide zeroed NULL-termination byte */
317 *length = sb.st_size + 1;
318 *addr = mmap(NULL, *length, PROT_READ, MAP_PRIVATE, fd, 0);
319 } else {
320 /* there will not be enough bytes after the file content mapping for the additional bytes and some of them
321 * would overflow into another page that would not be zerroed and any access into it would generate SIGBUS.
322 * Therefore we have to do the following hack with double mapping. First, the required number of bytes
323 * (including the additinal bytes) is required as anonymous and thus they will be really provided (actually more
324 * because of using whole pages) and also initialized by zeros. Then, the file is mapped to the same address
325 * where the anonymous mapping starts. */
326 *length = sb.st_size + pagesize;
327 *addr = mmap(NULL, *length, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
328 *addr = mmap(*addr, sb.st_size, PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, 0);
329 }
330 if (*addr == MAP_FAILED) {
331 LOGERR(ctx, LY_ESYS, "mmap() failed (%s).", strerror(errno));
332 return LY_ESYS;
Michal Vasko841d1a92018-09-07 15:40:31 +0200333 }
334
Radek Krejcif345c012018-09-19 11:12:59 +0200335 return LY_SUCCESS;
Radek Krejci86d106e2018-10-18 09:53:19 +0200336}
Michal Vasko841d1a92018-09-07 15:40:31 +0200337
Radek Krejci86d106e2018-10-18 09:53:19 +0200338LY_ERR
339ly_munmap(void *addr, size_t length)
340{
341 if (munmap(addr, length)) {
342 return LY_ESYS;
343 }
344 return LY_SUCCESS;
Michal Vasko841d1a92018-09-07 15:40:31 +0200345}
Radek Krejci4f28eda2018-11-12 11:46:16 +0100346
347LY_ERR
Radek Krejci4546aa62019-07-15 16:53:32 +0200348ly_strcat(char **dest, const char *format, ...)
349{
350 va_list fp;
351 char *addition = NULL;
352 size_t len;
353
354 va_start(fp, format);
355 len = vasprintf(&addition, format, fp);
356 len += (*dest ? strlen(*dest) : 0) + 1;
357
358 if (*dest) {
359 *dest = ly_realloc(*dest, len);
360 if (!*dest) {
361 return LY_EMEM;
362 }
363 *dest = strcat(*dest, addition);
364 free(addition);
365 } else {
366 *dest = addition;
367 }
368
369 va_end(fp);
370 return LY_SUCCESS;
371}
372
373LY_ERR
Radek Krejci249973a2019-06-10 10:50:54 +0200374ly_parse_int(const char *val_str, size_t val_len, int64_t min, int64_t max, int base, int64_t *ret)
Radek Krejci4f28eda2018-11-12 11:46:16 +0100375{
376 char *strptr;
Radek Krejci9ea8ca12019-06-10 13:11:55 +0200377 int64_t i;
Radek Krejci4f28eda2018-11-12 11:46:16 +0100378
Radek Krejci249973a2019-06-10 10:50:54 +0200379 LY_CHECK_ARG_RET(NULL, val_str, val_str[0], val_len, LY_EINVAL);
Radek Krejci4f28eda2018-11-12 11:46:16 +0100380
381 /* convert to 64-bit integer, all the redundant characters are handled */
382 errno = 0;
383 strptr = NULL;
384
385 /* parse the value */
Radek Krejci9ea8ca12019-06-10 13:11:55 +0200386 i = strtoll(val_str, &strptr, base);
Radek Krejci249973a2019-06-10 10:50:54 +0200387 if (errno || strptr == val_str) {
Radek Krejci4f28eda2018-11-12 11:46:16 +0100388 return LY_EVALID;
Radek Krejci9ea8ca12019-06-10 13:11:55 +0200389 } else if ((i < min) || (i > max)) {
Radek Krejci4f28eda2018-11-12 11:46:16 +0100390 return LY_EDENIED;
391 } else if (strptr && *strptr) {
392 while (isspace(*strptr)) {
393 ++strptr;
394 }
Radek Krejci249973a2019-06-10 10:50:54 +0200395 if (*strptr && strptr < val_str + val_len) {
Radek Krejci4f28eda2018-11-12 11:46:16 +0100396 return LY_EVALID;
397 }
398 }
Radek Krejci9ea8ca12019-06-10 13:11:55 +0200399
400 *ret = i;
Radek Krejci4f28eda2018-11-12 11:46:16 +0100401 return LY_SUCCESS;
402}
403
404LY_ERR
Radek Krejci249973a2019-06-10 10:50:54 +0200405ly_parse_uint(const char *val_str, size_t val_len, uint64_t max, int base, uint64_t *ret)
Radek Krejci4f28eda2018-11-12 11:46:16 +0100406{
407 char *strptr;
408 uint64_t u;
409
410 LY_CHECK_ARG_RET(NULL, val_str, val_str[0], LY_EINVAL);
411
412 errno = 0;
413 strptr = NULL;
414 u = strtoull(val_str, &strptr, base);
Radek Krejci249973a2019-06-10 10:50:54 +0200415 if (errno || strptr == val_str) {
Radek Krejci4f28eda2018-11-12 11:46:16 +0100416 return LY_EVALID;
417 } else if ((u > max) || (u && val_str[0] == '-')) {
418 return LY_EDENIED;
419 } else if (strptr && *strptr) {
420 while (isspace(*strptr)) {
421 ++strptr;
422 }
Radek Krejci249973a2019-06-10 10:50:54 +0200423 if (*strptr && strptr < val_str + val_len) {
Radek Krejci4f28eda2018-11-12 11:46:16 +0100424 return LY_EVALID;
425 }
426 }
427
428 *ret = u;
429 return LY_SUCCESS;
430}
Radek Krejcib4a4a272019-06-10 12:44:52 +0200431
432/**
433 * @brief Parse an identifier.
434 *
435 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
436 * identifier = (ALPHA / "_")
437 * *(ALPHA / DIGIT / "_" / "-" / ".")
438 *
439 * @param[in,out] id Identifier to parse. When returned, it points to the first character which is not part of the identifier.
440 * @return LY_ERR value: LY_SUCCESS or LY_EINVAL in case of invalid starting character.
441 */
442static LY_ERR
443lys_parse_id(const char **id)
444{
445 assert(id && *id);
446
447 if (!is_yangidentstartchar(**id)) {
448 return LY_EINVAL;
449 }
450 ++(*id);
451
452 while (is_yangidentchar(**id)) {
453 ++(*id);
454 }
455 return LY_SUCCESS;
456}
457
458LY_ERR
459ly_parse_nodeid(const char **id, const char **prefix, size_t *prefix_len, const char **name, size_t *name_len)
460{
461 assert(id && *id);
462 assert(prefix && prefix_len);
463 assert(name && name_len);
464
465 *prefix = *id;
466 *prefix_len = 0;
467 *name = NULL;
468 *name_len = 0;
469
470 LY_CHECK_RET(lys_parse_id(id));
471 if (**id == ':') {
472 /* there is prefix */
473 *prefix_len = *id - *prefix;
474 ++(*id);
475 *name = *id;
476
477 LY_CHECK_RET(lys_parse_id(id));
478 *name_len = *id - *name;
479 } else {
480 /* there is no prefix, so what we have as prefix now is actually the name */
481 *name = *prefix;
482 *name_len = *id - *name;
483 *prefix = NULL;
484 }
485
486 return LY_SUCCESS;
487}
488
489LY_ERR
Radek Krejci084289f2019-07-09 17:35:30 +0200490ly_parse_instance_predicate(const char **pred, size_t limit, LYD_FORMAT format,
491 const char **prefix, size_t *prefix_len, const char **id, size_t *id_len, const char **value, size_t *value_len,
492 const char **errmsg)
Radek Krejcib4a4a272019-06-10 12:44:52 +0200493{
494 LY_ERR ret = LY_EVALID;
495 const char *in = *pred;
496 size_t offset = 1;
497 int expr = 0;
498 char quot;
499
500 assert(in[0] == '\[');
501
502 *prefix = *id = *value = NULL;
503 *prefix_len = *id_len = *value_len = 0;
504
505 /* leading *WSP */
506 for (; isspace(in[offset]); offset++);
507
508 if (isdigit(in[offset])) {
509 /* pos: "[" *WSP positive-integer-value *WSP "]" */
510 if (in[offset] == '0') {
511 /* zero */
512 *errmsg = "The position predicate cannot be zero.";
513 goto error;
514 }
515
516 /* positive-integer-value */
Radek Krejci10bfdf82019-06-10 14:08:13 +0200517 *value = &in[offset++];
Radek Krejcib4a4a272019-06-10 12:44:52 +0200518 for (; isdigit(in[offset]); offset++);
Radek Krejci10bfdf82019-06-10 14:08:13 +0200519 *value_len = &in[offset] - *value;
Radek Krejcib4a4a272019-06-10 12:44:52 +0200520
521 } else if (in[offset] == '.') {
522 /* leaf-list-predicate: "[" *WSP "." *WSP "=" *WSP quoted-string *WSP "]" */
523 *id = &in[offset];
524 *id_len = 1;
525 offset++;
526 expr = 1;
Radek Krejci10bfdf82019-06-10 14:08:13 +0200527 } else if (in[offset] == '-') {
528 /* typically negative value */
529 *errmsg = "Invalid instance predicate format (negative position or invalid node-identifier).";
530 goto error;
Radek Krejcib4a4a272019-06-10 12:44:52 +0200531 } else {
532 /* key-predicate: "[" *WSP node-identifier *WSP "=" *WSP quoted-string *WSP "]" */
533 in = &in[offset];
534 if (ly_parse_nodeid(&in, prefix, prefix_len, id, id_len)) {
535 *errmsg = "Invalid node-identifier.";
536 goto error;
537 }
Radek Krejci084289f2019-07-09 17:35:30 +0200538 if (format == LYD_XML && !(*prefix)) {
539 /* all node names MUST be qualified with explicit namespace prefix */
540 *errmsg = "Missing prefix of a node name.";
541 goto error;
542 }
Radek Krejcib4a4a272019-06-10 12:44:52 +0200543 offset = in - *pred;
544 in = *pred;
Radek Krejci10bfdf82019-06-10 14:08:13 +0200545 expr = 2;
Radek Krejcib4a4a272019-06-10 12:44:52 +0200546 }
547
548 if (expr) {
549 /* *WSP "=" *WSP quoted-string *WSP "]" */
550 for (; isspace(in[offset]); offset++);
551
552 if (in[offset] != '=') {
Radek Krejci10bfdf82019-06-10 14:08:13 +0200553 if (expr == 1) {
554 *errmsg = "Unexpected character instead of \'=\' in leaf-list-predicate.";
555 } else { /* 2 */
556 *errmsg = "Unexpected character instead of \'=\' in key-predicate.";
557 }
Radek Krejcib4a4a272019-06-10 12:44:52 +0200558 goto error;
559 }
560 offset++;
561 for (; isspace(in[offset]); offset++);
562
563 /* quoted-string */
564 quot = in[offset++];
565 if (quot != '\'' && quot != '\"') {
566 *errmsg = "String value is not quoted.";
567 goto error;
568 }
569 *value = &in[offset];
Radek Krejci084289f2019-07-09 17:35:30 +0200570 for (;offset < limit && (in[offset] != quot || (offset && in[offset - 1] == '\\')); offset++);
Radek Krejci10bfdf82019-06-10 14:08:13 +0200571 if (in[offset] == quot) {
572 *value_len = &in[offset] - *value;
573 offset++;
574 } else {
575 *errmsg = "Value is not terminated quoted-string.";
576 goto error;
577 }
Radek Krejcib4a4a272019-06-10 12:44:52 +0200578 }
579
580 /* *WSP "]" */
581 for(; isspace(in[offset]); offset++);
582 if (in[offset] != ']') {
Radek Krejci10bfdf82019-06-10 14:08:13 +0200583 if (expr == 0) {
584 *errmsg = "Predicate (pos) is not terminated by \']\' character.";
585 } else if (expr == 1) {
586 *errmsg = "Predicate (leaf-list-predicate) is not terminated by \']\' character.";
587 } else { /* 2 */
588 *errmsg = "Predicate (key-predicate) is not terminated by \']\' character.";
589 }
Radek Krejcib4a4a272019-06-10 12:44:52 +0200590 goto error;
591 }
Radek Krejci10bfdf82019-06-10 14:08:13 +0200592 offset++;
Radek Krejcib4a4a272019-06-10 12:44:52 +0200593
Radek Krejci10bfdf82019-06-10 14:08:13 +0200594 if (offset <= limit) {
595 *pred = &in[offset];
Radek Krejcib4a4a272019-06-10 12:44:52 +0200596 return LY_SUCCESS;
597 }
598
599 /* we read after the limit */
600 *errmsg = "Predicate is incomplete.";
601 *prefix = *id = *value = NULL;
602 *prefix_len = *id_len = *value_len = 0;
603 offset = limit;
604 ret = LY_EINVAL;
605
606error:
607 *pred = &in[offset];
608 return ret;
609}