lyb UPDATE store enabled features for all the used modules

Fixes #1947
diff --git a/src/printer_lyb.c b/src/printer_lyb.c
index f1583ee..62902de 100644
--- a/src/printer_lyb.c
+++ b/src/printer_lyb.c
@@ -3,7 +3,7 @@
  * @author Michal Vasko <mvasko@cesnet.cz>
  * @brief LYB printer for libyang data structure
  *
- * Copyright (c) 2020 CESNET, z.s.p.o.
+ * Copyright (c) 2020 - 2022 CESNET, z.s.p.o.
  *
  * This source code is licensed under BSD 3-Clause License (the "License").
  * You may not use this file except in compliance with the License.
@@ -453,17 +453,22 @@
  *
  * @param[in] out Out structure.
  * @param[in] mod Module to print.
+ * @param[in] with_features Whether to also print enabled features or not.
  * @param[in] lybctx LYB context.
  * @return LY_ERR value.
  */
 static LY_ERR
-lyb_print_model(struct ly_out *out, const struct lys_module *mod, struct lylyb_ctx *lybctx)
+lyb_print_model(struct ly_out *out, const struct lys_module *mod, ly_bool with_features, struct lylyb_ctx *lybctx)
 {
+    LY_ERR rc = LY_SUCCESS;
     uint16_t revision;
+    struct ly_set feat_set = {0};
+    struct lysp_feature *f = NULL;
+    uint32_t i = 0;
     int r;
 
     /* model name length and model name */
-    LY_CHECK_RET(lyb_write_string(mod->name, 0, sizeof(uint16_t), out, lybctx));
+    LY_CHECK_GOTO(rc = lyb_write_string(mod->name, 0, sizeof(uint16_t), out, lybctx), cleanup);
 
     /* model revision as XXXX XXXX XXXX XXXX (2B) (year is offset from 2000)
      *                   YYYY YYYM MMMD DDDD */
@@ -484,12 +489,30 @@
 
         revision |= r;
     }
-    LY_CHECK_RET(lyb_write_number(revision, sizeof revision, out, lybctx));
+    LY_CHECK_GOTO(rc = lyb_write_number(revision, sizeof revision, out, lybctx), cleanup);
+
+    if (with_features) {
+        /* collect enabled module features */
+        while ((f = lysp_feature_next(f, mod->parsed, &i))) {
+            if (f->flags & LYS_FENABLED) {
+                LY_CHECK_GOTO(rc = ly_set_add(&feat_set, f, 1, NULL), cleanup);
+            }
+        }
+
+        /* print enabled feature count and their names */
+        LY_CHECK_GOTO(rc = lyb_write_number(feat_set.count, sizeof(uint16_t), out, lybctx), cleanup);
+        for (i = 0; i < feat_set.count; ++i) {
+            f = feat_set.objs[i];
+            LY_CHECK_GOTO(rc = lyb_write_string(f->name, 0, sizeof(uint16_t), out, lybctx), cleanup);
+        }
+    }
 
     /* fill cached hashes, if not already */
     lyb_cache_module_hash(mod);
 
-    return LY_SUCCESS;
+cleanup:
+    ly_set_erase(&feat_set, NULL);
+    return rc;
 }
 
 /**
@@ -543,7 +566,7 @@
 
     /* and all the used models */
     for (i = 0; i < set->count; ++i) {
-        LY_CHECK_GOTO(ret = lyb_print_model(out, set->objs[i], lybctx), cleanup);
+        LY_CHECK_GOTO(ret = lyb_print_model(out, set->objs[i], 1, lybctx), cleanup);
     }
 
 cleanup:
@@ -754,7 +777,7 @@
 
     if (wd_mod) {
         /* write the "default" metadata */
-        LY_CHECK_RET(lyb_print_model(out, wd_mod, lybctx->lybctx));
+        LY_CHECK_RET(lyb_print_model(out, wd_mod, 0, lybctx->lybctx));
         LY_CHECK_RET(lyb_write_string("default", 0, sizeof(uint16_t), out, lybctx->lybctx));
         LY_CHECK_RET(lyb_write_string("true", 0, sizeof(uint16_t), out, lybctx->lybctx));
     }
@@ -762,7 +785,7 @@
     /* write all the node metadata */
     LY_LIST_FOR(node->meta, iter) {
         /* model */
-        LY_CHECK_RET(lyb_print_model(out, iter->annotation->module, lybctx->lybctx));
+        LY_CHECK_RET(lyb_print_model(out, iter->annotation->module, 0, lybctx->lybctx));
 
         /* annotation name with length */
         LY_CHECK_RET(lyb_write_string(iter->name, 0, sizeof(uint16_t), out, lybctx->lybctx));
@@ -1188,7 +1211,7 @@
 
     /* write model info first */
     if (node->schema && ((node->flags & LYD_EXT) || !lysc_data_parent(node->schema))) {
-        LY_CHECK_RET(lyb_print_model(out, node->schema->module, lybctx->lybctx));
+        LY_CHECK_RET(lyb_print_model(out, node->schema->module, 0, lybctx->lybctx));
     }
 
     if (node->flags & LYD_EXT) {