show.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. #include <stdlib.h>
  2. #include <stdint.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <assert.h>
  6. #include <faux/faux.h>
  7. #include <faux/str.h>
  8. #include <faux/list.h>
  9. #include <faux/argv.h>
  10. #include <sysrepo.h>
  11. #include <sysrepo/xpath.h>
  12. #include <sysrepo/values.h>
  13. #include <libyang/tree_edit.h>
  14. #include "pline.h"
  15. #include "private.h"
  16. static void show_container(const struct lyd_node *node, size_t level,
  17. enum diff_op op, pline_opts_t *opts);
  18. static void show_list(const struct lyd_node *node, size_t level,
  19. enum diff_op op, pline_opts_t *opts);
  20. static void show_leaf(const struct lyd_node *node, size_t level,
  21. enum diff_op op, pline_opts_t *opts);
  22. static void show_leaflist(const struct lyd_node *node, size_t level,
  23. enum diff_op op, pline_opts_t *opts);
  24. static void show_node(const struct lyd_node *node, size_t level,
  25. enum diff_op op, pline_opts_t *opts);
  26. static enum diff_op str2diff_op(const char *str);
  27. static char *get_value(const struct lyd_node *node)
  28. {
  29. const struct lysc_node *schema = NULL;
  30. const struct lysc_type *type = NULL;
  31. const char *origin_value = NULL;
  32. char *space = NULL;
  33. char *escaped = NULL;
  34. char *result = NULL;
  35. if (!node)
  36. return NULL;
  37. schema = node->schema;
  38. if (!(schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)))
  39. return NULL;
  40. if (schema->nodetype & LYS_LEAF)
  41. type = ((const struct lysc_node_leaf *)schema)->type;
  42. else
  43. type = ((const struct lysc_node_leaflist *)schema)->type;
  44. if (type->basetype != LY_TYPE_IDENT) {
  45. origin_value = lyd_get_value(node);
  46. } else {
  47. // Identity
  48. const struct lyd_value *value = NULL;
  49. value = &((const struct lyd_node_term *)node)->value;
  50. origin_value = value->ident->name;
  51. }
  52. escaped = faux_str_c_esc(origin_value);
  53. // String with space must have quotes
  54. space = strchr(origin_value, ' ');
  55. if (space) {
  56. result = faux_str_sprintf("\"%s\"", escaped);
  57. faux_str_free(escaped);
  58. } else {
  59. result = escaped;
  60. }
  61. return result;
  62. }
  63. static const char *diff_prefix(enum diff_op op, pline_opts_t *opts)
  64. {
  65. bool_t c = opts->colorize;
  66. if (DIFF_OP_CREATE == op)
  67. return c ? "\x1b[32m+" : "+";
  68. else if (DIFF_OP_DELETE == op)
  69. return c ? "\x1b[31m-" : "-";
  70. else if (DIFF_OP_REPLACE == op)
  71. return c ? "\x1b[33m=" : "=";
  72. return "";
  73. }
  74. static const char *diff_suffix(enum diff_op op, pline_opts_t *opts)
  75. {
  76. if (opts->colorize && (DIFF_OP_NONE != op))
  77. return "\x1b[0m";
  78. return "";
  79. }
  80. static void show_container(const struct lyd_node *node, size_t level,
  81. enum diff_op op, pline_opts_t *opts)
  82. {
  83. char begin_bracket[3] = {' ', opts->begin_bracket, '\0'};
  84. if (!node)
  85. return;
  86. printf("%s%*s%s%s%s\n",
  87. diff_prefix(op, opts),
  88. (int)(level * opts->indent), "",
  89. node->schema->name,
  90. opts->show_brackets ? begin_bracket : "",
  91. diff_suffix(op, opts));
  92. show_subtree(lyd_child(node), level + 1, op, opts);
  93. if (opts->show_brackets) {
  94. printf("%s%*s%c%s\n",
  95. diff_prefix(op, opts),
  96. (int)(level * opts->indent), "",
  97. opts->end_bracket,
  98. diff_suffix(op, opts));
  99. }
  100. }
  101. static void show_list(const struct lyd_node *node, size_t level,
  102. enum diff_op op, pline_opts_t *opts)
  103. {
  104. char begin_bracket[3] = {' ', opts->begin_bracket, '\0'};
  105. size_t keys_num = 0;
  106. const struct lyd_node *iter = NULL;
  107. bool_t first_key = BOOL_TRUE;
  108. if (!node)
  109. return;
  110. printf("%s%*s%s",
  111. diff_prefix(op, opts),
  112. (int)(level * opts->indent), "",
  113. node->schema->name);
  114. LY_LIST_FOR(lyd_child(node), iter) {
  115. char *value = NULL;
  116. if (!(iter->schema->nodetype & LYS_LEAF))
  117. continue;
  118. if (!(iter->schema->flags & LYS_KEY))
  119. continue;
  120. if ((first_key && opts->first_key_w_stmt) ||
  121. (!first_key && opts->multi_keys_w_stmt))
  122. printf(" %s", iter->schema->name);
  123. value = get_value(iter);
  124. printf(" %s", value);
  125. faux_str_free(value);
  126. first_key = BOOL_FALSE;
  127. }
  128. printf("%s%s\n",
  129. opts->show_brackets ? begin_bracket : "",
  130. diff_suffix(op, opts));
  131. show_subtree(lyd_child(node), level + 1, op, opts);
  132. if (opts->show_brackets) {
  133. printf("%s%*s%c%s\n",
  134. diff_prefix(op, opts),
  135. (int)(level * opts->indent), "",
  136. opts->end_bracket,
  137. diff_suffix(op, opts));
  138. }
  139. }
  140. static void show_leaf(const struct lyd_node *node, size_t level,
  141. enum diff_op op, pline_opts_t *opts)
  142. {
  143. struct lysc_node_leaf *leaf = (struct lysc_node_leaf *)node;
  144. if (!node)
  145. return;
  146. if (node->schema->flags & LYS_KEY)
  147. return;
  148. printf("%s%*s%s",
  149. diff_prefix(op, opts),
  150. (int)(level * opts->indent), "",
  151. node->schema->name);
  152. leaf = (struct lysc_node_leaf *)node->schema;
  153. if (leaf->type->basetype != LY_TYPE_EMPTY) {
  154. char *value = get_value(node);
  155. printf(" %s", value);
  156. faux_str_free(value);
  157. }
  158. printf("%s%s\n",
  159. opts->show_semicolons ? ";" : "",
  160. diff_suffix(op, opts));
  161. }
  162. static void show_leaflist(const struct lyd_node *node, size_t level,
  163. enum diff_op op, pline_opts_t *opts)
  164. {
  165. char *value = NULL;
  166. if (!node)
  167. return;
  168. value = get_value(node);
  169. printf("%s%*s%s %s%s%s\n",
  170. diff_prefix(op, opts),
  171. (int)(level * opts->indent), "",
  172. node->schema->name,
  173. value,
  174. opts->show_semicolons ? ";" : "",
  175. diff_suffix(op, opts));
  176. faux_str_free(value);
  177. }
  178. static void show_node(const struct lyd_node *node, size_t level,
  179. enum diff_op op, pline_opts_t *opts)
  180. {
  181. const struct lysc_node *schema = NULL;
  182. struct lyd_meta *meta = NULL;
  183. enum diff_op cur_op = op;
  184. if (!node)
  185. return;
  186. if (node->flags & LYD_DEFAULT)
  187. return;
  188. schema = node->schema;
  189. if (!schema)
  190. return;
  191. if (!(schema->nodetype & SRP_NODETYPE_CONF))
  192. return;
  193. if (!(schema->flags & LYS_CONFIG_W))
  194. return;
  195. meta = lyd_find_meta(node->meta, NULL, "yang:operation");
  196. if (meta)
  197. cur_op = str2diff_op(lyd_get_meta_value(meta));
  198. // Container
  199. if (schema->nodetype & LYS_CONTAINER) {
  200. show_container(node, level, cur_op, opts);
  201. // List
  202. } else if (schema->nodetype & LYS_LIST) {
  203. show_list(node, level, cur_op, opts);
  204. // Leaf
  205. } else if (schema->nodetype & LYS_LEAF) {
  206. show_leaf(node, level, cur_op, opts);
  207. // Leaf-list
  208. } else if (schema->nodetype & LYS_LEAFLIST) {
  209. show_leaflist(node, level, cur_op, opts);
  210. } else {
  211. return;
  212. }
  213. }
  214. static void show_sorted_list(faux_list_t *list, size_t level,
  215. enum diff_op op, pline_opts_t *opts)
  216. {
  217. faux_list_node_t *iter = NULL;
  218. const struct lyd_node *lyd = NULL;
  219. if (!list)
  220. return;
  221. iter = faux_list_head(list);
  222. while ((lyd = (const struct lyd_node *)faux_list_each(&iter)))
  223. show_node(lyd, level, op, opts);
  224. }
  225. static char *list_keys_str(const struct lyd_node *node)
  226. {
  227. char *keys = NULL;
  228. const struct lyd_node *iter = NULL;
  229. if (!node)
  230. return NULL;
  231. if (node->schema->nodetype != LYS_LIST)
  232. return NULL;
  233. LY_LIST_FOR(lyd_child(node), iter) {
  234. if (!(iter->schema->nodetype & LYS_LEAF))
  235. continue;
  236. if (!(iter->schema->flags & LYS_KEY))
  237. continue;
  238. if (keys)
  239. faux_str_cat(&keys, " ");
  240. faux_str_cat(&keys, lyd_get_value(iter));
  241. }
  242. return keys;
  243. }
  244. static int list_compare(const void *first, const void *second)
  245. {
  246. int rc = 0;
  247. const struct lyd_node *f = (const struct lyd_node *)first;
  248. const struct lyd_node *s = (const struct lyd_node *)second;
  249. char *f_keys = list_keys_str(f);
  250. char *s_keys = list_keys_str(s);
  251. rc = faux_str_numcmp(f_keys, s_keys);
  252. faux_str_free(f_keys);
  253. faux_str_free(s_keys);
  254. return rc;
  255. }
  256. static int leaflist_compare(const void *first, const void *second)
  257. {
  258. const struct lyd_node *f = (const struct lyd_node *)first;
  259. const struct lyd_node *s = (const struct lyd_node *)second;
  260. return faux_str_numcmp(lyd_get_value(f), lyd_get_value(s));
  261. }
  262. void show_subtree(const struct lyd_node *nodes_list, size_t level,
  263. enum diff_op op, pline_opts_t *opts)
  264. {
  265. const struct lyd_node *iter = NULL;
  266. faux_list_t *list = NULL;
  267. const struct lysc_node *saved_lysc = NULL;
  268. if(!nodes_list)
  269. return;
  270. LY_LIST_FOR(nodes_list, iter) {
  271. if (saved_lysc) {
  272. if (saved_lysc == iter->schema) {
  273. faux_list_add(list, (void *)iter);
  274. continue;
  275. }
  276. show_sorted_list(list, level, op, opts);
  277. faux_list_free(list);
  278. list = NULL;
  279. saved_lysc = NULL;
  280. }
  281. if (((LYS_LIST == iter->schema->nodetype) ||
  282. (LYS_LEAFLIST == iter->schema->nodetype)) &&
  283. (iter->schema->flags & LYS_ORDBY_SYSTEM)) {
  284. saved_lysc = iter->schema;
  285. if (LYS_LIST == iter->schema->nodetype) {
  286. list = faux_list_new(FAUX_LIST_SORTED, FAUX_LIST_UNIQUE,
  287. list_compare, NULL, NULL);
  288. } else { // LEAFLIST
  289. list = faux_list_new(FAUX_LIST_SORTED, FAUX_LIST_UNIQUE,
  290. leaflist_compare, NULL, NULL);
  291. }
  292. faux_list_add(list, (void *)iter);
  293. continue;
  294. }
  295. show_node(iter, level, op, opts);
  296. }
  297. if (list) {
  298. show_sorted_list(list, level, op, opts);
  299. faux_list_free(list);
  300. }
  301. }
  302. bool_t show_xpath(sr_session_ctx_t *sess, const char *xpath, pline_opts_t *opts)
  303. {
  304. sr_data_t *data = NULL;
  305. struct lyd_node *nodes_list = NULL;
  306. assert(sess);
  307. if (xpath) {
  308. if (sr_get_subtree(sess, xpath, 0, &data) != SR_ERR_OK)
  309. return BOOL_FALSE;
  310. nodes_list = lyd_child(data->tree);
  311. } else {
  312. if (sr_get_data(sess, "/*", 0, 0, 0, &data) != SR_ERR_OK)
  313. return BOOL_FALSE;
  314. nodes_list = data->tree;
  315. }
  316. show_subtree(nodes_list, 0, DIFF_OP_NONE, opts);
  317. sr_release_data(data);
  318. return BOOL_TRUE;
  319. }
  320. static enum diff_op str2diff_op(const char *str)
  321. {
  322. if (!strcmp(str, "create"))
  323. return DIFF_OP_CREATE;
  324. else if (!strcmp(str, "delete"))
  325. return DIFF_OP_DELETE;
  326. else if (!strcmp(str, "replace"))
  327. return DIFF_OP_REPLACE;
  328. return DIFF_OP_NONE;
  329. }