blob: bd6c697542fd9b400d6c64eb5ee78cdf17c2b59d [file] [log] [blame]
Radek Krejci94ca54b2015-07-08 15:48:47 +02001/**
2 * @file printer/json.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief JSON printer for libyang data structure
5 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of the Company nor the names of its contributors
18 * may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 */
21
22#include <stdlib.h>
23#include <stdio.h>
24#include <string.h>
25#include <assert.h>
Radek Krejci7511f402015-07-10 09:56:30 +020026#include <inttypes.h>
Radek Krejci94ca54b2015-07-08 15:48:47 +020027
28#include "../common.h"
29#include "../tree.h"
30
31#define INDENT ""
32#define LEVEL (level*2)
33
34void json_print_node(FILE *f, int level, struct lyd_node *node);
35
36/* 0 - same, 1 - different */
37static int
38nscmp(struct lyd_node *node1, struct lyd_node *node2)
39{
40 struct ly_module *m1, *m2;
41
42 /* we have to cover submodules belonging to the same module */
43 if (node1->schema->module->type) {
44 m1 = ((struct ly_submodule *)node1->schema->module)->belongsto;
45 } else {
46 m1 = node1->schema->module;
47 }
48 if (node2->schema->module->type) {
49 m2 = ((struct ly_submodule *)node2->schema->module)->belongsto;
50 } else {
51 m2 = node2->schema->module;
52 }
53 if (m1 == m2) {
54 /* belongs to the same module */
55 return 0;
56 } else {
57 /* different modules */
58 return 1;
59 }
60}
61
62static void
63json_print_container(FILE *f, int level, struct lyd_node *node)
64{
65 const char *schema;
66 struct lyd_node *child;
67
68 if (!node->parent || nscmp(node, node->parent)) {
69 /* print "namespace" */
70 if (node->schema->module->type) {
71 /* submodule, get module */
72 schema = ((struct ly_submodule *)node->schema->module)->belongsto->name;
73 } else {
74 schema = node->schema->module->name;
75 }
76 fprintf(f, "%*s\"%s:%s\": {\n", LEVEL, INDENT, schema, node->schema->name);
77 } else {
78 fprintf(f, "%*s\"%s\": {\n", LEVEL, INDENT, node->schema->name);
79 }
80 LY_TREE_FOR(node->child, child) {
81 json_print_node(f, level + 1, child);
82 }
83 fprintf(f, "%*s}%s\n", LEVEL, INDENT, node->next ? "," : "");
84}
85
86static void
87json_print_list_internal(FILE *f, int level, struct lyd_node_list *list)
88{
89 struct lyd_node *child;
90
91 fprintf(f, "%*s{\n", LEVEL, INDENT);
92
Radek Krejci94ca54b2015-07-08 15:48:47 +020093 LY_TREE_FOR(list->child, child) {
94 json_print_node(f, level + 1, child);
95 }
96
97 fprintf(f, "%*s}%s\n", LEVEL, INDENT, list->lnext ? "," : "");
98}
99
100static void
101json_print_list(FILE *f, int level, struct lyd_node *node)
102{
103 const char *schema;
104 struct lyd_node_list *list = (struct lyd_node_list *)node;
105 struct lyd_node *iter;
106 char *delim = "";
107
108 if (list->lprev) {
109 /* this list is already printed */
110 return;
111 }
112
113 if (!node->parent || nscmp(node, node->parent)) {
114 /* print "namespace" */
115 if (node->schema->module->type) {
116 /* submodule, get module */
117 schema = ((struct ly_submodule *)node->schema->module)->belongsto->name;
118 } else {
119 schema = node->schema->module->name;
120 }
121 fprintf(f, "%*s\"%s:%s\": [\n", LEVEL, INDENT, schema, node->schema->name);
122 } else {
123 fprintf(f, "%*s\"%s\": [\n", LEVEL, INDENT, node->schema->name);
124 }
125
126 for(; list; list = list->lnext) {
127 json_print_list_internal(f, level + 1, list);
128 }
129 for (iter = node->next; iter; iter = iter->next) {
130 if (iter->schema != node->schema) {
131 delim = ",";
132 break;
133 }
134 }
135 fprintf(f, "%*s]%s\n", LEVEL, INDENT, delim);
136}
137
138static void
139json_print_leaf(FILE *f, int level, struct lyd_node *node)
140{
Radek Krejcie4748472015-07-08 18:00:22 +0200141 struct lyd_node_leaf *leaf = (struct lyd_node_leaf *)node;
Radek Krejci3e3affe2015-07-09 15:38:40 +0200142 struct ly_mnode_leaf *sleaf = (struct ly_mnode_leaf *)node->schema;
143 struct ly_type *type;
Radek Krejci94ca54b2015-07-08 15:48:47 +0200144 const char *schema;
Radek Krejci7511f402015-07-10 09:56:30 +0200145 char dec[21];
146 int i, len;
Radek Krejci94ca54b2015-07-08 15:48:47 +0200147
148 if (!node->parent || nscmp(node, node->parent)) {
149 /* print "namespace" */
150 if (node->schema->module->type) {
151 /* submodule, get module */
152 schema = ((struct ly_submodule *)node->schema->module)->belongsto->name;
153 } else {
154 schema = node->schema->module->name;
155 }
Radek Krejcie4748472015-07-08 18:00:22 +0200156 fprintf(f, "%*s\"%s:%s\": ", LEVEL, INDENT, schema, node->schema->name);
Radek Krejci94ca54b2015-07-08 15:48:47 +0200157 } else {
Radek Krejcie4748472015-07-08 18:00:22 +0200158 fprintf(f, "%*s\"%s\": ", LEVEL, INDENT, node->schema->name);
Radek Krejci94ca54b2015-07-08 15:48:47 +0200159 }
Radek Krejcie4748472015-07-08 18:00:22 +0200160
161 switch (((struct ly_mnode_leaf *)leaf->schema)->type.base) {
162 case LY_TYPE_BINARY:
163 case LY_TYPE_STRING:
Radek Krejci44e6dc52015-07-10 12:46:39 +0200164 fprintf(f, "\"%s\"%s\n", leaf->value.string ? leaf->value.string : "", node->next ? "," : "");
Radek Krejcie4748472015-07-08 18:00:22 +0200165 break;
Radek Krejci3e3affe2015-07-09 15:38:40 +0200166 case LY_TYPE_BITS:
167 fprintf(f, "\"");
168
169 /* locate bits structure with the bits definitions to get the array size */
170 for (type = &sleaf->type; type->der->type.der; type = &type->der->type);
171
172 /* print set bits */
173 for (i = 0; i < type->info.bits.count; i++) {
174 if (leaf->value.bit[i]) {
175 fprintf(f, "%s%s", i ? " " : "", leaf->value.bit[i]->name);
176 }
177 }
178 fprintf(f, "\"%s\n", node->next ? "," : "");
179 break;
Radek Krejcib7384642015-07-09 16:08:45 +0200180 case LY_TYPE_BOOL:
181 fprintf(f, "\"%s\"%s\n", leaf->value.bool ? "true" : "false", node->next ? "," : "");
182 break;
Radek Krejci7511f402015-07-10 09:56:30 +0200183 case LY_TYPE_DEC64:
184
185 /* locate dec structure with the fraction-digits definitions to get the value */
186 for (type = &sleaf->type; type->der->type.der; type = &type->der->type);
187
188 snprintf(dec, 21, "%" PRId64, leaf->value.dec64);
189 len = strlen(dec);
190 for (i = 0; dec[i]; ) {
191 fputc(dec[i++], f);
192 if (i + type->info.dec64.dig == len) {
193 fputc('.', f);
194 }
195 }
196 fprintf(f, "%s\n", node->next ? "," : "");
197
198 break;
Radek Krejcibce73742015-07-10 12:46:06 +0200199 case LY_TYPE_EMPTY:
200 fprintf(f, "[null]%s\n", node->next ? "," : "");
201 break;
Radek Krejcie4748472015-07-08 18:00:22 +0200202 default:
203 /* TODO */
204 fprintf(f, "%s%s\n", "\"TBD\"", node->next ? "," : "");
205 }
206
Radek Krejci94ca54b2015-07-08 15:48:47 +0200207}
208
209void
210json_print_node(FILE *f, int level, struct lyd_node *node)
211{
212 switch (node->schema->nodetype) {
213 case LY_NODE_LIST:
214 json_print_list(f, level, node);
215 break;
216 case LY_NODE_CONTAINER:
217 json_print_container(f, level, node);
218 break;
219 case LY_NODE_LEAF:
220 json_print_leaf(f, level, node);
221 break;
222 default:
223 /* TODO: remove when all node types are covered */
224 break;
225 }
226
227}
228
229int
230json_print_data(FILE *f, struct lyd_node *root)
231{
232 int level = 0;
233 struct lyd_node *node;
234
235 /* start */
236 fprintf(f, "{\n");
237
238 /* content */
239 LY_TREE_FOR(root, node) {
240 json_print_node(f, level + 1, node);
241 }
242
243 /* end */
244 fprintf(f, "}\n");
245
246 return EXIT_SUCCESS;
247}