1 /**
2 * @file printer.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief Wrapper for all libyang printers.
5 *
6 * Copyright (c) 2015 - 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 */
14
15 #define _GNU_SOURCE /* vasprintf(), vdprintf() */
16 #define _POSIX_C_SOURCE 200809L
17
18 #include <sys/types.h>
19 #include <stdarg.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <errno.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25
26 #include "common.h"
27 #include "tree_schema.h"
28 #include "tree_data.h"
29 #include "printer.h"
30
31 struct ext_substmt_info_s ext_substmt_info[] = {
32 {NULL, NULL, 0}, /**< LYEXT_SUBSTMT_SELF */
33 {"argument", "name", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_ARGUMENT */
34 {"base", "name", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_BASE */
35 {"belongs-to", "module", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_BELONGSTO */
36 {"contact", "text", SUBST_FLAG_YIN}, /**< LYEXT_SUBSTMT_CONTACT */
37 {"default", "value", 0}, /**< LYEXT_SUBSTMT_DEFAULT */
38 {"description", "text", SUBST_FLAG_YIN}, /**< LYEXT_SUBSTMT_DESCRIPTION */
39 {"error-app-tag", "value", 0}, /**< LYEXT_SUBSTMT_ERRTAG */
40 {"error-message", "value", SUBST_FLAG_YIN}, /**< LYEXT_SUBSTMT_ERRMSG */
41 {"key", "value", 0}, /**< LYEXT_SUBSTMT_KEY */
42 {"namespace", "uri", 0}, /**< LYEXT_SUBSTMT_NAMESPACE */
43 {"organization", "text", SUBST_FLAG_YIN}, /**< LYEXT_SUBSTMT_ORGANIZATION */
44 {"path", "value", 0}, /**< LYEXT_SUBSTMT_PATH */
45 {"prefix", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_PREFIX */
46 {"presence", "value", 0}, /**< LYEXT_SUBSTMT_PRESENCE */
47 {"reference", "text", SUBST_FLAG_YIN}, /**< LYEXT_SUBSTMT_REFERENCE */
48 {"revision-date", "date", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_REVISIONDATE */
49 {"units", "name", 0}, /**< LYEXT_SUBSTMT_UNITS */
50 {"value", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_VALUE */
51 {"yang-version", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_VERSION */
52 {"modifier", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_MODIFIER */
53 {"require-instance", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_REQINST */
54 {"yin-element", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_YINELEM */
55 {"config", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_CONFIG */
56 {"mandatory", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_MANDATORY */
57 {"ordered-by", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_ORDEREDBY */
58 {"status", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_STATUS */
59 {"fraction-digits", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_DIGITS */
60 {"max-elements", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_MAX */
61 {"min-elements", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_MIN */
62 {"position", "value", SUBST_FLAG_ID}, /**< LYEXT_SUBSTMT_POSITION */
63 {"unique", "tag", 0}, /**< LYEXT_SUBSTMT_UNIQUE */
64 };
65
66 /* 0 - same, 1 - different */
67 int
nscmp(const struct lyd_node * node1,const struct lyd_node * node2)68 nscmp(const struct lyd_node *node1, const struct lyd_node *node2)
69 {
70 /* we have to cover submodules belonging to the same module */
71 if (lys_node_module(node1->schema) == lys_node_module(node2->schema)) {
72 /* belongs to the same module */
73 return 0;
74 } else {
75 /* different modules */
76 return 1;
77 }
78 }
79
80 int
ly_print(struct lyout * out,const char * format,...)81 ly_print(struct lyout *out, const char *format, ...)
82 {
83 int count = 0;
84 char *msg = NULL, *aux;
85 va_list ap;
86
87 va_start(ap, format);
88
89 switch (out->type) {
90 case LYOUT_FD:
91 count = vdprintf(out->method.fd, format, ap);
92 break;
93 case LYOUT_STREAM:
94 count = vfprintf(out->method.f, format, ap);
95 break;
96 case LYOUT_MEMORY:
97 count = vasprintf(&msg, format, ap);
98 if (out->method.mem.len + count + 1 > out->method.mem.size) {
99 aux = ly_realloc(out->method.mem.buf, out->method.mem.len + count + 1);
100 if (!aux) {
101 out->method.mem.buf = NULL;
102 out->method.mem.len = 0;
103 out->method.mem.size = 0;
104 LOGMEM(NULL);
105 free(msg);
106 va_end(ap);
107 return -1;
108 }
109 out->method.mem.buf = aux;
110 out->method.mem.size = out->method.mem.len + count + 1;
111 }
112 memcpy(&out->method.mem.buf[out->method.mem.len], msg, count);
113 out->method.mem.len += count;
114 out->method.mem.buf[out->method.mem.len] = '\0';
115 free(msg);
116 break;
117 case LYOUT_CALLBACK:
118 count = vasprintf(&msg, format, ap);
119 count = out->method.clb.f(out->method.clb.arg, msg, count);
120 if (count >= 0) {
121 /*
122 * Depending on what the callback function does, errno might
123 * contain non-zero values that are not real "errors" (EAGAIN or
124 * EINTR). Reset errno if the callback returns a zero or positive
125 * value.
126 */
127 errno = 0;
128 }
129 free(msg);
130 break;
131 }
132
133 va_end(ap);
134 return count;
135 }
136
137 void
ly_print_flush(struct lyout * out)138 ly_print_flush(struct lyout *out)
139 {
140 switch (out->type) {
141 case LYOUT_STREAM:
142 fflush(out->method.f);
143 break;
144 case LYOUT_FD:
145 case LYOUT_MEMORY:
146 case LYOUT_CALLBACK:
147 /* nothing to do */
148 break;
149 }
150 }
151
152 int
ly_write(struct lyout * out,const char * buf,size_t count)153 ly_write(struct lyout *out, const char *buf, size_t count)
154 {
155 if (out->hole_count) {
156 /* we are buffering data after a hole */
157 if (out->buf_len + count > out->buf_size) {
158 out->buffered = ly_realloc(out->buffered, out->buf_len + count);
159 if (!out->buffered) {
160 out->buf_len = 0;
161 out->buf_size = 0;
162 LOGMEM(NULL);
163 return -1;
164 }
165 out->buf_size = out->buf_len + count;
166 }
167
168 memcpy(&out->buffered[out->buf_len], buf, count);
169 out->buf_len += count;
170 return count;
171 }
172
173 switch (out->type) {
174 case LYOUT_MEMORY:
175 if (out->method.mem.len + count + 1 > out->method.mem.size) {
176 out->method.mem.buf = ly_realloc(out->method.mem.buf, out->method.mem.len + count + 1);
177 if (!out->method.mem.buf) {
178 out->method.mem.len = 0;
179 out->method.mem.size = 0;
180 LOGMEM(NULL);
181 return -1;
182 }
183 out->method.mem.size = out->method.mem.len + count + 1;
184 }
185 memcpy(&out->method.mem.buf[out->method.mem.len], buf, count);
186 out->method.mem.len += count;
187 out->method.mem.buf[out->method.mem.len] = '\0';
188 return count;
189 case LYOUT_FD:
190 return write(out->method.fd, buf, count);
191 case LYOUT_STREAM:
192 return fwrite(buf, sizeof *buf, count, out->method.f);
193 case LYOUT_CALLBACK:
194 return out->method.clb.f(out->method.clb.arg, buf, count);
195 }
196
197 return 0;
198 }
199
200 int
ly_write_skip(struct lyout * out,size_t count,size_t * position)201 ly_write_skip(struct lyout *out, size_t count, size_t *position)
202 {
203 switch (out->type) {
204 case LYOUT_MEMORY:
205 if (out->method.mem.len + count > out->method.mem.size) {
206 out->method.mem.buf = ly_realloc(out->method.mem.buf, out->method.mem.len + count);
207 if (!out->method.mem.buf) {
208 out->method.mem.len = 0;
209 out->method.mem.size = 0;
210 LOGMEM(NULL);
211 return -1;
212 }
213 out->method.mem.size = out->method.mem.len + count;
214 }
215
216 /* save the current position */
217 *position = out->method.mem.len;
218
219 /* skip the memory */
220 out->method.mem.len += count;
221 break;
222 case LYOUT_FD:
223 case LYOUT_STREAM:
224 case LYOUT_CALLBACK:
225 /* buffer the hole */
226 if (out->buf_len + count > out->buf_size) {
227 out->buffered = ly_realloc(out->buffered, out->buf_len + count);
228 if (!out->buffered) {
229 out->buf_len = 0;
230 out->buf_size = 0;
231 LOGMEM(NULL);
232 return -1;
233 }
234 out->buf_size = out->buf_len + count;
235 }
236
237 /* save the current position */
238 *position = out->buf_len;
239
240 /* skip the memory */
241 out->buf_len += count;
242
243 /* increase hole counter */
244 ++out->hole_count;
245 }
246
247 return count;
248 }
249
250 int
ly_write_skipped(struct lyout * out,size_t position,const char * buf,size_t count)251 ly_write_skipped(struct lyout *out, size_t position, const char *buf, size_t count)
252 {
253 switch (out->type) {
254 case LYOUT_MEMORY:
255 /* write */
256 memcpy(&out->method.mem.buf[position], buf, count);
257 break;
258 case LYOUT_FD:
259 case LYOUT_STREAM:
260 case LYOUT_CALLBACK:
261 if (out->buf_len < position + count) {
262 LOGINT(NULL);
263 return -1;
264 }
265
266 /* write into the hole */
267 memcpy(&out->buffered[position], buf, count);
268
269 /* decrease hole counter */
270 --out->hole_count;
271
272 if (!out->hole_count) {
273 /* all holes filled, we can write the buffer */
274 count = ly_write(out, out->buffered, out->buf_len);
275 out->buf_len = 0;
276 }
277 break;
278 }
279
280 return count;
281 }
282
283 static int
write_iff(struct lyout * out,const struct lys_module * module,struct lys_iffeature * expr,int prefix_kind,int * index_e,int * index_f)284 write_iff(struct lyout *out, const struct lys_module *module, struct lys_iffeature *expr, int prefix_kind,
285 int *index_e, int *index_f)
286 {
287 int count = 0, brackets_flag = *index_e;
288 uint8_t op;
289 struct lys_module *mod;
290
291 op = iff_getop(expr->expr, *index_e);
292 (*index_e)++;
293
294 switch (op) {
295 case LYS_IFF_F:
296 if (lys_main_module(expr->features[*index_f]->module) != lys_main_module(module)) {
297 if (prefix_kind == 0) {
298 count += ly_print(out, "%s:", transform_module_name2import_prefix(module,
299 lys_main_module(expr->features[*index_f]->module)->name));
300 } else if (prefix_kind == 1) {
301 count += ly_print(out, "%s:", lys_main_module(expr->features[*index_f]->module)->name);
302 } else if (prefix_kind == 2) {
303 count += ly_print(out, "%s:", lys_main_module(expr->features[*index_f]->module)->prefix);
304 } else if (prefix_kind == 3) {
305 mod = lys_main_module(expr->features[*index_f]->module);
306 count += ly_print(out, "%s%s%s:", mod->name, mod->rev_size ? "@" : "", mod->rev_size ? mod->rev[0].date : "");
307 }
308 }
309 count += ly_print(out, expr->features[*index_f]->name);
310 (*index_f)++;
311 break;
312 case LYS_IFF_NOT:
313 count += ly_print(out, "not ");
314 count += write_iff(out, module, expr, prefix_kind, index_e, index_f);
315 break;
316 case LYS_IFF_AND:
317 if (brackets_flag) {
318 /* AND need brackets only if previous op was not */
319 if (*index_e < 2 || iff_getop(expr->expr, *index_e - 2) != LYS_IFF_NOT) {
320 brackets_flag = 0;
321 }
322 }
323 /* falls through */
324 case LYS_IFF_OR:
325 if (brackets_flag) {
326 count += ly_print(out, "(");
327 }
328 count += write_iff(out, module, expr, prefix_kind, index_e, index_f);
329 count += ly_print(out, " %s ", op == LYS_IFF_OR ? "or" : "and");
330 count += write_iff(out, module, expr, prefix_kind, index_e, index_f);
331 if (brackets_flag) {
332 count += ly_print(out, ")");
333 }
334 }
335
336 return count;
337 }
338
339 int
ly_print_iffeature(struct lyout * out,const struct lys_module * module,struct lys_iffeature * expr,int prefix_kind)340 ly_print_iffeature(struct lyout *out, const struct lys_module *module, struct lys_iffeature *expr, int prefix_kind)
341 {
342 int index_e = 0, index_f = 0;
343
344 if (expr->expr) {
345 return write_iff(out, module, expr, prefix_kind, &index_e, &index_f);
346 }
347
348 return 0;
349 }
350
351 static int
lys_print_(struct lyout * out,const struct lys_module * module,LYS_OUTFORMAT format,const char * target_node,int line_length,int options)352 lys_print_(struct lyout *out, const struct lys_module *module, LYS_OUTFORMAT format, const char *target_node,
353 int line_length, int options)
354 {
355 int ret;
356
357 switch (format) {
358 case LYS_OUT_YIN:
359 lys_disable_deviations((struct lys_module *)module);
360 ret = yin_print_model(out, module);
361 lys_enable_deviations((struct lys_module *)module);
362 break;
363 case LYS_OUT_YANG:
364 lys_disable_deviations((struct lys_module *)module);
365 ret = yang_print_model(out, module);
366 lys_enable_deviations((struct lys_module *)module);
367 break;
368 case LYS_OUT_TREE:
369 ret = tree_print_model(out, module, target_node, line_length, options);
370 break;
371 case LYS_OUT_INFO:
372 ret = info_print_model(out, module, target_node);
373 break;
374 case LYS_OUT_JSON:
375 ret = jsons_print_model(out, module, target_node);
376 break;
377 default:
378 LOGERR(module->ctx, LY_EINVAL, "Unknown output format.");
379 ret = EXIT_FAILURE;
380 break;
381 }
382
383 return ret;
384 }
385
386 API int
lys_print_file(FILE * f,const struct lys_module * module,LYS_OUTFORMAT format,const char * target_node,int line_length,int options)387 lys_print_file(FILE *f, const struct lys_module *module, LYS_OUTFORMAT format, const char *target_node,
388 int line_length, int options)
389 {
390 struct lyout out;
391
392 if (!f || !module) {
393 LOGARG;
394 return EXIT_FAILURE;
395 }
396
397 memset(&out, 0, sizeof out);
398
399 out.type = LYOUT_STREAM;
400 out.method.f = f;
401
402 return lys_print_(&out, module, format, target_node, line_length, options);
403 }
404
405 API int
lys_print_path(const char * path,const struct lys_module * module,LYS_OUTFORMAT format,const char * target_node,int line_length,int options)406 lys_print_path(const char *path, const struct lys_module *module, LYS_OUTFORMAT format, const char *target_node,
407 int line_length, int options)
408 {
409 FILE *f;
410 int ret;
411
412 if (!path || !module) {
413 LOGARG;
414 return EXIT_FAILURE;
415 }
416
417 f = fopen(path, "w");
418 if (!f) {
419 LOGERR(module->ctx, LY_ESYS, "Failed to open file \"%s\" (%s).", path, strerror(errno));
420 return EXIT_FAILURE;
421 }
422
423 ret = lys_print_file(f, module, format, target_node, line_length, options);
424 fclose(f);
425 return ret;
426 }
427
428 API int
lys_print_fd(int fd,const struct lys_module * module,LYS_OUTFORMAT format,const char * target_node,int line_length,int options)429 lys_print_fd(int fd, const struct lys_module *module, LYS_OUTFORMAT format, const char *target_node,
430 int line_length, int options)
431 {
432 struct lyout out;
433
434 if (fd < 0 || !module) {
435 LOGARG;
436 return EXIT_FAILURE;
437 }
438
439 memset(&out, 0, sizeof out);
440
441 out.type = LYOUT_FD;
442 out.method.fd = fd;
443
444 return lys_print_(&out, module, format, target_node, line_length, options);
445 }
446
447 API int
lys_print_mem(char ** strp,const struct lys_module * module,LYS_OUTFORMAT format,const char * target_node,int line_length,int options)448 lys_print_mem(char **strp, const struct lys_module *module, LYS_OUTFORMAT format, const char *target_node,
449 int line_length, int options)
450 {
451 struct lyout out;
452 int r;
453
454 if (!strp || !module) {
455 LOGARG;
456 return EXIT_FAILURE;
457 }
458
459 memset(&out, 0, sizeof out);
460
461 out.type = LYOUT_MEMORY;
462
463 r = lys_print_(&out, module, format, target_node, line_length, options);
464
465 *strp = out.method.mem.buf;
466 return r;
467 }
468
469 API int
lys_print_clb(ssize_t (* writeclb)(void * arg,const void * buf,size_t count),void * arg,const struct lys_module * module,LYS_OUTFORMAT format,const char * target_node,int line_length,int options)470 lys_print_clb(ssize_t (*writeclb)(void *arg, const void *buf, size_t count), void *arg, const struct lys_module *module,
471 LYS_OUTFORMAT format, const char *target_node, int line_length, int options)
472 {
473 struct lyout out;
474
475 if (!writeclb || !module) {
476 LOGARG;
477 return EXIT_FAILURE;
478 }
479
480 memset(&out, 0, sizeof out);
481
482 out.type = LYOUT_CALLBACK;
483 out.method.clb.f = writeclb;
484 out.method.clb.arg = arg;
485
486 return lys_print_(&out, module, format, target_node, line_length, options);
487 }
488
489 int
lys_print_target(struct lyout * out,const struct lys_module * module,const char * target_schema_path,void (* clb_print_typedef)(struct lyout *,const struct lys_tpdf *,int *),void (* clb_print_identity)(struct lyout *,const struct lys_ident *,int *),void (* clb_print_feature)(struct lyout *,const struct lys_feature *,int *),void (* clb_print_type)(struct lyout *,const struct lys_type *,int *),void (* clb_print_grouping)(struct lyout *,const struct lys_node *,int *),void (* clb_print_container)(struct lyout *,const struct lys_node *,int *),void (* clb_print_choice)(struct lyout *,const struct lys_node *,int *),void (* clb_print_leaf)(struct lyout *,const struct lys_node *,int *),void (* clb_print_leaflist)(struct lyout *,const struct lys_node *,int *),void (* clb_print_list)(struct lyout *,const struct lys_node *,int *),void (* clb_print_anydata)(struct lyout *,const struct lys_node *,int *),void (* clb_print_case)(struct lyout *,const struct lys_node *,int *),void (* clb_print_notif)(struct lyout *,const struct lys_node *,int *),void (* clb_print_rpc)(struct lyout *,const struct lys_node *,int *),void (* clb_print_action)(struct lyout *,const struct lys_node *,int *),void (* clb_print_input)(struct lyout *,const struct lys_node *,int *),void (* clb_print_output)(struct lyout *,const struct lys_node *,int *))490 lys_print_target(struct lyout *out, const struct lys_module *module, const char *target_schema_path,
491 void (*clb_print_typedef)(struct lyout*, const struct lys_tpdf*, int*),
492 void (*clb_print_identity)(struct lyout*, const struct lys_ident*, int*),
493 void (*clb_print_feature)(struct lyout*, const struct lys_feature*, int*),
494 void (*clb_print_type)(struct lyout*, const struct lys_type*, int*),
495 void (*clb_print_grouping)(struct lyout*, const struct lys_node*, int*),
496 void (*clb_print_container)(struct lyout*, const struct lys_node*, int*),
497 void (*clb_print_choice)(struct lyout*, const struct lys_node*, int*),
498 void (*clb_print_leaf)(struct lyout*, const struct lys_node*, int*),
499 void (*clb_print_leaflist)(struct lyout*, const struct lys_node*, int*),
500 void (*clb_print_list)(struct lyout*, const struct lys_node*, int*),
501 void (*clb_print_anydata)(struct lyout*, const struct lys_node*, int*),
502 void (*clb_print_case)(struct lyout*, const struct lys_node*, int*),
503 void (*clb_print_notif)(struct lyout*, const struct lys_node*, int*),
504 void (*clb_print_rpc)(struct lyout*, const struct lys_node*, int*),
505 void (*clb_print_action)(struct lyout*, const struct lys_node*, int*),
506 void (*clb_print_input)(struct lyout*, const struct lys_node*, int*),
507 void (*clb_print_output)(struct lyout*, const struct lys_node*, int*))
508 {
509 int rc, i, f = 1;
510 char *spec_target = NULL;
511 struct lys_node *target = NULL;
512 struct lys_tpdf *tpdf = NULL;
513 uint8_t tpdf_size = 0;
514
515 if ((target_schema_path[0] == '/') || !strncmp(target_schema_path, "type/", 5)) {
516 rc = resolve_absolute_schema_nodeid((target_schema_path[0] == '/' ? target_schema_path : target_schema_path + 4), module,
517 LYS_ANY & ~(LYS_USES | LYS_AUGMENT | LYS_GROUPING), (const struct lys_node **)&target);
518 if (rc || !target) {
519 LOGERR(module->ctx, LY_EINVAL, "Target %s could not be resolved.",
520 (target_schema_path[0] == '/' ? target_schema_path : target_schema_path + 4));
521 return EXIT_FAILURE;
522 }
523 } else if (!strncmp(target_schema_path, "grouping/", 9)) {
524 /* cut the data part off */
525 if ((spec_target = strchr(target_schema_path + 9, '/'))) {
526 /* HACK only temporary */
527 spec_target[0] = '\0';
528 ++spec_target;
529 }
530 rc = resolve_absolute_schema_nodeid(target_schema_path + 8, module, LYS_GROUPING, (const struct lys_node **)&target);
531 if (rc || !target) {
532 ly_print(out, "Grouping %s not found.\n", target_schema_path + 8);
533 return EXIT_FAILURE;
534 }
535 } else if (!strncmp(target_schema_path, "typedef/", 8)) {
536 if ((spec_target = strrchr(target_schema_path + 8, '/'))) {
537 /* schema node typedef */
538 /* HACK only temporary */
539 spec_target[0] = '\0';
540 ++spec_target;
541
542 rc = resolve_absolute_schema_nodeid(target_schema_path + 7, module,
543 LYS_CONTAINER | LYS_LIST | LYS_NOTIF | LYS_RPC | LYS_ACTION,
544 (const struct lys_node **)&target);
545 if (rc || !target) {
546 /* perhaps it's in a grouping */
547 rc = resolve_absolute_schema_nodeid(target_schema_path + 7, module, LYS_GROUPING,
548 (const struct lys_node **)&target);
549 }
550 if (!rc && target) {
551 switch (target->nodetype) {
552 case LYS_CONTAINER:
553 tpdf = ((struct lys_node_container *)target)->tpdf;
554 tpdf_size = ((struct lys_node_container *)target)->tpdf_size;
555 break;
556 case LYS_LIST:
557 tpdf = ((struct lys_node_list *)target)->tpdf;
558 tpdf_size = ((struct lys_node_list *)target)->tpdf_size;
559 break;
560 case LYS_NOTIF:
561 tpdf = ((struct lys_node_notif *)target)->tpdf;
562 tpdf_size = ((struct lys_node_notif *)target)->tpdf_size;
563 break;
564 case LYS_RPC:
565 case LYS_ACTION:
566 tpdf = ((struct lys_node_rpc_action *)target)->tpdf;
567 tpdf_size = ((struct lys_node_rpc_action *)target)->tpdf_size;
568 break;
569 case LYS_GROUPING:
570 tpdf = ((struct lys_node_grp *)target)->tpdf;
571 tpdf_size = ((struct lys_node_grp *)target)->tpdf_size;
572 break;
573 default:
574 LOGINT(module->ctx);
575 return EXIT_FAILURE;
576 }
577 }
578 } else {
579 /* module typedef */
580 spec_target = (char *)target_schema_path + 8;
581 tpdf = module->tpdf;
582 tpdf_size = module->tpdf_size;
583 }
584
585 for (i = 0; i < tpdf_size; ++i) {
586 if (!strcmp(tpdf[i].name, spec_target)) {
587 clb_print_typedef(out, &tpdf[i], &f);
588 break;
589 }
590 }
591 /* HACK return previous hack */
592 --spec_target;
593 spec_target[0] = '/';
594
595 if (i == tpdf_size) {
596 ly_print(out, "Typedef %s not found.\n", target_schema_path);
597 return EXIT_FAILURE;
598 }
599 return EXIT_SUCCESS;
600
601 } else if (!strncmp(target_schema_path, "identity/", 9)) {
602 target_schema_path += 9;
603 for (i = 0; i < (signed)module->ident_size; ++i) {
604 if (!strcmp(module->ident[i].name, target_schema_path)) {
605 break;
606 }
607 }
608 if (i == (signed)module->ident_size) {
609 ly_print(out, "Identity %s not found.\n", target_schema_path);
610 return EXIT_FAILURE;
611 }
612
613 clb_print_identity(out, &module->ident[i], &f);
614 return EXIT_SUCCESS;
615
616 } else if (!strncmp(target_schema_path, "feature/", 8)) {
617 target_schema_path += 8;
618 for (i = 0; i < module->features_size; ++i) {
619 if (!strcmp(module->features[i].name, target_schema_path)) {
620 break;
621 }
622 }
623 if (i == module->features_size) {
624 ly_print(out, "Feature %s not found.\n", target_schema_path);
625 return EXIT_FAILURE;
626 }
627
628 clb_print_feature(out, &module->features[i], &f);
629 return EXIT_SUCCESS;
630 } else {
631 ly_print(out, "Target could not be resolved.\n");
632 return EXIT_FAILURE;
633 }
634
635 if (!strncmp(target_schema_path, "type/", 5)) {
636 if (!(target->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
637 LOGERR(module->ctx, LY_EINVAL, "Target is not a leaf or a leaf-list.");
638 return EXIT_FAILURE;
639 }
640 clb_print_type(out, &((struct lys_node_leaf *)target)->type, &f);
641 return EXIT_SUCCESS;
642 } else if (!strncmp(target_schema_path, "grouping/", 9) && !spec_target) {
643 clb_print_grouping(out, target, &f);
644 return EXIT_SUCCESS;
645 }
646
647 /* find the node in the grouping */
648 if (spec_target) {
649 rc = resolve_descendant_schema_nodeid(spec_target, target->child, LYS_NO_RPC_NOTIF_NODE,
650 0, (const struct lys_node **)&target);
651 if (rc || !target) {
652 ly_print(out, "Grouping %s child \"%s\" not found.\n", target_schema_path + 9, spec_target);
653 return EXIT_FAILURE;
654 }
655 /* HACK return previous hack */
656 --spec_target;
657 spec_target[0] = '/';
658 }
659 switch (target->nodetype) {
660 case LYS_CONTAINER:
661 clb_print_container(out, target, &f);
662 break;
663 case LYS_CHOICE:
664 clb_print_choice(out, target, &f);
665 break;
666 case LYS_LEAF:
667 clb_print_leaf(out, target, &f);
668 break;
669 case LYS_LEAFLIST:
670 clb_print_leaflist(out, target, &f);
671 break;
672 case LYS_LIST:
673 clb_print_list(out, target, &f);
674 break;
675 case LYS_ANYXML:
676 case LYS_ANYDATA:
677 clb_print_anydata(out, target, &f);
678 break;
679 case LYS_CASE:
680 clb_print_case(out, target, &f);
681 break;
682 case LYS_NOTIF:
683 clb_print_notif(out, target, &f);
684 break;
685 case LYS_RPC:
686 clb_print_rpc(out, target, &f);
687 break;
688 case LYS_ACTION:
689 clb_print_action(out, target, &f);
690 break;
691 case LYS_INPUT:
692 clb_print_input(out, target, &f);
693 break;
694 case LYS_OUTPUT:
695 clb_print_output(out, target, &f);
696 break;
697 default:
698 ly_print(out, "Nodetype %s not supported.\n", strnodetype(target->nodetype));
699 break;
700 }
701
702 return EXIT_SUCCESS;
703 }
704
705 static int
lyd_print_(struct lyout * out,const struct lyd_node * root,LYD_FORMAT format,int options)706 lyd_print_(struct lyout *out, const struct lyd_node *root, LYD_FORMAT format, int options)
707 {
708 switch (format) {
709 case LYD_XML:
710 return xml_print_data(out, root, options);
711 case LYD_JSON:
712 return json_print_data(out, root, options);
713 case LYD_LYB:
714 return lyb_print_data(out, root, options);
715 default:
716 LOGERR(root->schema->module->ctx, LY_EINVAL, "Unknown output format.");
717 return EXIT_FAILURE;
718 }
719 }
720
721 API int
lyd_print_file(FILE * f,const struct lyd_node * root,LYD_FORMAT format,int options)722 lyd_print_file(FILE *f, const struct lyd_node *root, LYD_FORMAT format, int options)
723 {
724 int r;
725 struct lyout out;
726
727 if (!f) {
728 LOGARG;
729 return EXIT_FAILURE;
730 }
731
732 memset(&out, 0, sizeof out);
733
734 out.type = LYOUT_STREAM;
735 out.method.f = f;
736
737 r = lyd_print_(&out, root, format, options);
738
739 free(out.buffered);
740 return r;
741 }
742
743 API int
lyd_print_path(const char * path,const struct lyd_node * root,LYD_FORMAT format,int options)744 lyd_print_path(const char *path, const struct lyd_node *root, LYD_FORMAT format, int options)
745 {
746 FILE *f;
747 int ret;
748
749 if (!path) {
750 LOGARG;
751 return EXIT_FAILURE;
752 }
753
754 f = fopen(path, "w");
755 if (!f) {
756 LOGERR(root->schema->module->ctx, LY_EINVAL, "Cannot open file \"%s\" for writing.", path);
757 return EXIT_FAILURE;
758 }
759
760 ret = lyd_print_file(f, root, format, options);
761
762 fclose(f);
763 return ret;
764 }
765
766 API int
lyd_print_fd(int fd,const struct lyd_node * root,LYD_FORMAT format,int options)767 lyd_print_fd(int fd, const struct lyd_node *root, LYD_FORMAT format, int options)
768 {
769 int r;
770 struct lyout out;
771
772 if (fd < 0) {
773 LOGARG;
774 return EXIT_FAILURE;
775 }
776
777 memset(&out, 0, sizeof out);
778
779 out.type = LYOUT_FD;
780 out.method.fd = fd;
781
782 r = lyd_print_(&out, root, format, options);
783
784 free(out.buffered);
785 return r;
786 }
787
788 API int
lyd_print_mem(char ** strp,const struct lyd_node * root,LYD_FORMAT format,int options)789 lyd_print_mem(char **strp, const struct lyd_node *root, LYD_FORMAT format, int options)
790 {
791 struct lyout out;
792 int r;
793
794 if (!strp) {
795 LOGARG;
796 return EXIT_FAILURE;
797 }
798
799 memset(&out, 0, sizeof out);
800
801 out.type = LYOUT_MEMORY;
802
803 r = lyd_print_(&out, root, format, options);
804
805 *strp = out.method.mem.buf;
806 free(out.buffered);
807 return r;
808 }
809
810 API int
lyd_print_clb(ssize_t (* writeclb)(void * arg,const void * buf,size_t count),void * arg,const struct lyd_node * root,LYD_FORMAT format,int options)811 lyd_print_clb(ssize_t (*writeclb)(void *arg, const void *buf, size_t count), void *arg, const struct lyd_node *root,
812 LYD_FORMAT format, int options)
813 {
814 int r;
815 struct lyout out;
816
817 if (!writeclb) {
818 LOGARG;
819 return EXIT_FAILURE;
820 }
821
822 memset(&out, 0, sizeof out);
823
824 out.type = LYOUT_CALLBACK;
825 out.method.clb.f = writeclb;
826 out.method.clb.arg = arg;
827
828 r = lyd_print_(&out, root, format, options);
829
830 free(out.buffered);
831 return r;
832 }
833
834 static int
lyd_wd_toprint(const struct lyd_node * node,int options)835 lyd_wd_toprint(const struct lyd_node *node, int options)
836 {
837 const struct lyd_node *subroot, *next, *elem;
838 int flag = 0;
839
840 if (options & LYP_WD_TRIM) {
841 /* do not print default nodes */
842 if (node->dflt) {
843 /* implicit default node */
844 return 0;
845 } else if (node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
846 if (lyd_wd_default((struct lyd_node_leaf_list *)node)) {
847 /* explicit default node */
848 return 0;
849 }
850 } else if ((node->schema->nodetype & (LYS_CONTAINER)) && !((struct lys_node_container *)node->schema)->presence) {
851 /* get know if non-presence container contains non-default node */
852 for (subroot = node->child; subroot && !flag; subroot = subroot->next) {
853 LY_TREE_DFS_BEGIN(subroot, next, elem) {
854 if (elem->dflt) {
855 /* skip subtree */
856 goto trim_dfs_nextsibling;
857 }
858 switch (elem->schema->nodetype) {
859 case LYS_LEAF:
860 case LYS_LEAFLIST:
861 if (!lyd_wd_default((struct lyd_node_leaf_list *)elem)) {
862 /* non-default node */
863 flag = 1;
864 }
865 break;
866 case LYS_ANYDATA:
867 case LYS_ANYXML:
868 case LYS_NOTIF:
869 case LYS_ACTION:
870 case LYS_LIST:
871 /* non-default nodes */
872 flag = 1;
873 break;
874 case LYS_CONTAINER:
875 if (((struct lys_node_container *)elem->schema)->presence) {
876 /* non-default node */
877 flag = 1;
878 }
879 break;
880 default:
881 break;
882 }
883 if (flag) {
884 break;
885 }
886
887 /* modified LY_TREE_DFS_END */
888 /* select element for the next run - children first */
889 /* child exception for leafs, leaflists and anyxml without children */
890 if (elem->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
891 next = NULL;
892 } else {
893 next = elem->child;
894 }
895 if (!next) {
896 trim_dfs_nextsibling:
897 /* no children */
898 if (elem == subroot) {
899 /* we are done, (START) has no children */
900 break;
901 }
902 /* try siblings */
903 next = elem->next;
904 }
905 while (!next) {
906 /* parent is already processed, go to its sibling */
907 elem = elem->parent;
908 /* no siblings, go back through parents */
909 if (elem->parent == subroot->parent) {
910 /* we are done, no next element to process */
911 break;
912 }
913 next = elem->next;
914 }
915 }
916 }
917 if (!flag) {
918 /* only default nodes in subtree, do not print the container */
919 return 0;
920 }
921 }
922 } else if (node->dflt && !(options & LYP_WD_MASK) && !(node->schema->flags & LYS_CONFIG_R)) {
923 /* LYP_WD_EXPLICIT
924 * - print only if it contains status data in its subtree */
925 LY_TREE_DFS_BEGIN(node, next, elem) {
926 if ((elem->schema->nodetype != LYS_CONTAINER) || ((struct lys_node_container *)elem->schema)->presence) {
927 if (elem->schema->flags & LYS_CONFIG_R) {
928 flag = 1;
929 break;
930 }
931 }
932 LY_TREE_DFS_END(node, next, elem)
933 }
934 if (!flag) {
935 return 0;
936 }
937 } else if (node->dflt && node->schema->nodetype == LYS_CONTAINER && !(options & LYP_KEEPEMPTYCONT)) {
938 /* avoid empty default containers */
939 LY_TREE_DFS_BEGIN(node, next, elem) {
940 if (elem->schema->nodetype != LYS_CONTAINER) {
941 flag = 1;
942 break;
943 }
944 LY_TREE_DFS_END(node, next, elem)
945 }
946 if (!flag) {
947 return 0;
948 }
949 }
950
951 return 1;
952 }
953
954 API int
lyd_node_should_print(const struct lyd_node * node,int options)955 lyd_node_should_print(const struct lyd_node *node, int options)
956 {
957 struct lys_node *scase, *sparent;
958 struct lyd_node *first;
959
960 if (!lyd_wd_toprint(node, options)) {
961 /* wd says do not print, but make exception for direct descendants of case nodes without other printable nodes */
962 for (sparent = lys_parent(node->schema); sparent && (sparent->nodetype == LYS_USES); sparent = lys_parent(sparent));
963 if (!sparent || (sparent->nodetype != LYS_CASE)) {
964 /* parent not a case */
965 return 0;
966 }
967 scase = sparent;
968
969 for (sparent = lys_parent(scase); sparent && (sparent->nodetype == LYS_USES); sparent = lys_parent(sparent));
970 if (!sparent || (sparent->nodetype != LYS_CHOICE)) {
971 /* weird */
972 LOGINT(lyd_node_module(node)->ctx);
973 return 0;
974 }
975 if (((struct lys_node_choice *)sparent)->dflt == scase) {
976 /* this is a default case, respect the previous original toprint flag */
977 return 0;
978 }
979
980 /* try to find a sibling that will be printed */
981 for (first = node->prev; first->prev->next; first = first->prev);
982 LY_TREE_FOR(first, first) {
983 if (first == node) {
984 /* skip this node */
985 continue;
986 }
987
988 /* find schema parent, whether it is the same case */
989 for (sparent = lys_parent(first->schema); sparent && (sparent->nodetype == LYS_USES); sparent = lys_parent(sparent));
990 if ((sparent == scase) && lyd_wd_toprint(first, options)) {
991 /* this other node will be printed, we do not have to print the current one */
992 return 0;
993 }
994 }
995
996 /* there is no case child that will be printed, print this node */
997 return 1;
998 }
999
1000 return 1;
1001 }
1002