extensions CHANGE support for revision statement in extension instances
diff --git a/src/extensions/ext_test.c b/src/extensions/ext_test.c
index e5ccccb..3dd56b4 100644
--- a/src/extensions/ext_test.c
+++ b/src/extensions/ext_test.c
@@ -97,8 +97,8 @@
     {LY_STMT_PATTERN,      30 * sizeof(void*) + 5 * sizeof(uint8_t), LY_STMT_CARD_OPT}, /* struct lys_restr* */
     {LY_STMT_RANGE,        31 * sizeof(void*) + 5 * sizeof(uint8_t), LY_STMT_CARD_OPT}, /* struct lys_restr* */
     {LY_STMT_WHEN,         32 * sizeof(void*) + 5 * sizeof(uint8_t), LY_STMT_CARD_OPT}, /* struct lys_when* */
-/*    {LY_STMT_REVISION,     66 * sizeof(void *), LY_STMT_CARD_OPT},
-*/    {0, 0, 0} /* terminating item */
+    {LY_STMT_REVISION,     33 * sizeof(void*) + 5 * sizeof(uint8_t), LY_STMT_CARD_OPT}, /* struct lys_revision* */
+    {0, 0, 0} /* terminating item */
 };
 
 struct lyext_substmt libyang_ext_test_substmt_arrays[] = {
@@ -152,8 +152,8 @@
     {LY_STMT_PATTERN,      31 * sizeof(void*), LY_STMT_CARD_ANY}, /* struct lys_restr** */
     {LY_STMT_RANGE,        32 * sizeof(void*), LY_STMT_CARD_ANY}, /* struct lys_restr** */
     {LY_STMT_WHEN,         33 * sizeof(void*), LY_STMT_CARD_ANY}, /* struct lys_when** */
-/*    {LY_STMT_REVISION,     66 * sizeof(void *), LY_STMT_CARD_ANY},
-*/    {0, 0, 0} /* terminating item */
+    {LY_STMT_REVISION,     34 * sizeof(void*), LY_STMT_CARD_ANY}, /* struct lys_revision** */
+    {0, 0, 0} /* terminating item */
 };
 
 /**
diff --git a/src/parser_yin.c b/src/parser_yin.c
index cd34ae0..ce72f13 100644
--- a/src/parser_yin.c
+++ b/src/parser_yin.c
@@ -1824,6 +1824,67 @@
 }
 
 static int
+fill_yin_revision(struct lys_module *module, struct lyxml_elem *yin, struct lys_revision *rev,
+                  struct unres_schema *unres)
+{
+    struct lyxml_elem *next, *child;
+    const char *value;
+
+    GETVAL(value, yin, "date");
+    if (lyp_check_date(value)) {
+        goto error;
+    }
+    memcpy(rev->date, value, LY_REV_SIZE - 1);
+
+    LY_TREE_FOR_SAFE(yin->child, next, child) {
+        if (!child->ns) {
+            /* garbage */
+            continue;
+        } else if (strcmp(child->ns->value, LY_NSYIN)) {
+            /* possible extension instance */
+            if (lyp_yin_parse_subnode_ext(module, rev, LYEXT_PAR_REVISION,
+                                          child, LYEXT_SUBSTMT_SELF, 0, unres)) {
+                goto error;
+            }
+        } else if (!strcmp(child->name, "description")) {
+            if (rev->dsc) {
+                LOGVAL(LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
+                goto error;
+            }
+            if (lyp_yin_parse_subnode_ext(module, rev, LYEXT_PAR_REVISION,
+                                          child, LYEXT_SUBSTMT_DESCRIPTION, 0, unres)) {
+                goto error;
+            }
+            rev->dsc = read_yin_subnode(module->ctx, child, "text");
+            if (!rev->dsc) {
+                goto error;
+            }
+        } else if (!strcmp(child->name, "reference")) {
+            if (rev->ref) {
+                LOGVAL(LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
+                goto error;
+            }
+            if (lyp_yin_parse_subnode_ext(module, rev, LYEXT_PAR_REVISION,
+                                          child, LYEXT_SUBSTMT_REFERENCE, 0, unres)) {
+                goto error;
+            }
+            rev->ref = read_yin_subnode(module->ctx, child, "text");
+            if (!rev->ref) {
+                goto error;
+            }
+        } else {
+            LOGVAL(LYE_INSTMT, LY_VLOG_NONE, NULL, child->name);
+            goto error;
+        }
+    }
+
+    return EXIT_SUCCESS;
+
+error:
+    return EXIT_FAILURE;
+}
+
+static int
 fill_yin_unique(struct lys_module *module, struct lys_node *parent, struct lyxml_elem *yin, struct lys_unique *unique,
                 struct unres_schema *unres)
 {
@@ -6322,7 +6383,7 @@
                 struct unres_schema *unres)
 {
     struct ly_ctx *ctx = module->ctx;
-    struct lyxml_elem *next, *next2, *child, *child2, root, grps, augs, revs, exts;
+    struct lyxml_elem *next, *child, root, grps, augs, revs, exts;
     struct lys_node *node = NULL;
     struct lys_module *trg;
     const char *value;
@@ -6804,61 +6865,19 @@
 
     /* middle part 1 - process revision and then check whether this (sub)module was not already parsed, add it there */
     LY_TREE_FOR_SAFE(revs.child, next, child) {
-        GETVAL(value, child, "date");
-        if (lyp_check_date(value)) {
+        r = fill_yin_revision(trg, child, &trg->rev[trg->rev_size], unres);
+        trg->rev_size++;
+        if (r) {
             goto error;
         }
-        memcpy(trg->rev[trg->rev_size].date, value, LY_REV_SIZE - 1);
-        /* check uniqueness of the revision date - not required by RFC */
-        for (i = 0; i < trg->rev_size; i++) {
-            if (!strcmp(value, trg->rev[i].date)) {
-                LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, child->name);
-                LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Revision is not unique.");
-            }
-        }
 
-        LY_TREE_FOR_SAFE(child->child, next2, child2) {
-            if (!child2->ns) {
-                /* garbage */
-                continue;
-            } else if (strcmp(child2->ns->value, LY_NSYIN)) {
-                /* possible extension instance */
-                if (lyp_yin_parse_subnode_ext(trg, &trg->rev[trg->rev_size], LYEXT_PAR_REVISION,
-                                              child2, LYEXT_SUBSTMT_SELF, 0, unres)) {
-                    goto error;
-                }
-            } else if (!strcmp(child2->name, "description")) {
-                if (trg->rev[trg->rev_size].dsc) {
-                    LOGVAL(LYE_TOOMANY, LY_VLOG_NONE, NULL, child2->name, child->name);
-                    goto error;
-                }
-                if (lyp_yin_parse_subnode_ext(trg, &trg->rev[trg->rev_size], LYEXT_PAR_REVISION,
-                                              child2, LYEXT_SUBSTMT_DESCRIPTION, 0, unres)) {
-                    goto error;
-                }
-                trg->rev[trg->rev_size].dsc = read_yin_subnode(ctx, child2, "text");
-                if (!trg->rev[trg->rev_size].dsc) {
-                    goto error;
-                }
-            } else if (!strcmp(child2->name, "reference")) {
-                if (trg->rev[trg->rev_size].ref) {
-                    LOGVAL(LYE_TOOMANY, LY_VLOG_NONE, NULL, child2->name, child->name);
-                    goto error;
-                }
-                if (lyp_yin_parse_subnode_ext(trg, &trg->rev[trg->rev_size], LYEXT_PAR_REVISION,
-                                              child2, LYEXT_SUBSTMT_REFERENCE, 0, unres)) {
-                    goto error;
-                }
-                trg->rev[trg->rev_size].ref = read_yin_subnode(ctx, child2, "text");
-                if (!trg->rev[trg->rev_size].ref) {
-                    goto error;
-                }
-            } else {
-                LOGVAL(LYE_INSTMT, LY_VLOG_NONE, NULL, child2->name);
-                goto error;
+        /* check uniqueness of the revision date - not required by RFC */
+        for (i = 0; i < (trg->rev_size - 1); i++) {
+            if (!strcmp(trg->rev[i].date, trg->rev[trg->rev_size - 1].date)) {
+                LOGWRN("Module's revisions are not unique (%s).", trg->rev[trg->rev_size - 1].date);
+                break;
             }
         }
-        trg->rev_size++;
 
         lyxml_free(ctx, child);
     }
@@ -7537,7 +7556,7 @@
     long int v;
     long long int ll;
     unsigned long u;
-    int i;
+    int i, j;
 
 #define YIN_EXTCOMPLEX_GETPLACE(STMT, TYPE)                                          \
     p = lys_ext_complex_get_substmt(STMT, ext, &info);                               \
@@ -7894,6 +7913,24 @@
             }
 
             YIN_EXTCOMPLEX_ENLARGE(struct lys_when*);
+        } else if (!strcmp(node->name, "revision")) {
+            YIN_EXTCOMPLEX_GETPLACE(LY_STMT_REVISION, struct lys_revision*);
+
+            *(struct lys_revision**)p = calloc(1, sizeof(struct lys_revision));
+            if (fill_yin_revision(mod, node, *(struct lys_revision**)p, unres)) {
+                goto error;
+            }
+
+            /* check uniqueness of the revision dates - not required by RFC */
+            if (pp) {
+                for (j = 0; j < i; j++) {
+                    if (!strcmp((*(struct lys_revision***)pp)[j]->date, (*(struct lys_revision**)p)->date)) {
+                        LOGWRN("Module's revisions are not unique (%s).", (*(struct lys_revision**)p)->date);
+                    }
+                }
+            }
+
+            YIN_EXTCOMPLEX_ENLARGE(struct lys_revision*);
         } else if (!strcmp(node->name, "unique")) {
             YIN_EXTCOMPLEX_GETPLACE(LY_STMT_UNIQUE, struct lys_unique*);
 
diff --git a/src/printer_yang.c b/src/printer_yang.c
index 996eeec..adee41a 100755
--- a/src/printer_yang.c
+++ b/src/printer_yang.c
@@ -1601,6 +1601,20 @@
     }
 }
 
+static void
+yang_print_revision(struct lyout *out, int level, const struct lys_module *module, const struct lys_revision *rev)
+{
+    if (rev->dsc || rev->ref || rev->ext_size) {
+        ly_print(out, "%*srevision \"%s\" {\n", LEVEL, INDENT, rev->date);
+        yang_print_extension_instances(out, level + 1, module, LYEXT_SUBSTMT_SELF, 0, rev->ext, rev->ext_size);
+        yang_print_substmt(out, level + 1, LYEXT_SUBSTMT_DESCRIPTION, 0, rev->dsc, module, rev->ext, rev->ext_size);
+        yang_print_substmt(out, level + 1, LYEXT_SUBSTMT_REFERENCE, 0, rev->ref, module, rev->ext, rev->ext_size);
+        ly_print(out, "%*s}\n", LEVEL, INDENT);
+    } else {
+        ly_print(out, "%*srevision %s;\n", LEVEL, INDENT, rev->date);
+    }
+}
+
 static int
 yang_print_model_(struct lyout *out, int level, const struct lys_module *module)
 {
@@ -1700,18 +1714,7 @@
         ly_print(out, "\n");
     }
     for (i = 0; i < module->rev_size; i++) {
-        if (module->rev[i].dsc || module->rev[i].ref || module->rev[i].ext_size) {
-            ly_print(out, "%*srevision \"%s\" {\n", LEVEL, INDENT, module->rev[i].date);
-            yang_print_extension_instances(out, level + 1, module, LYEXT_SUBSTMT_SELF, 0,
-                                           module->rev[i].ext, module->rev[i].ext_size);
-            yang_print_substmt(out, level + 1, LYEXT_SUBSTMT_DESCRIPTION, 0, module->rev[i].dsc,
-                               module, module->rev[i].ext, module->rev[i].ext_size);
-            yang_print_substmt(out, level + 1, LYEXT_SUBSTMT_REFERENCE, 0, module->rev[i].ref,
-                               module, module->rev[i].ext, module->rev[i].ext_size);
-            ly_print(out, "%*s}\n", LEVEL, INDENT);
-        } else {
-            ly_print(out, "%*srevision %s;\n", LEVEL, INDENT, module->rev[i].date);
-        }
+        yang_print_revision(out, level, module, &module->rev[i]);
     }
 
     /* body-stmts */
@@ -2190,6 +2193,9 @@
                 case LY_STMT_WHEN:
                     YANG_PRINT_EXTCOMPLEX_STRUCT_M(LY_STMT_WHEN, struct lys_when, yang_print_when);
                     break;
+                case LY_STMT_REVISION:
+                    YANG_PRINT_EXTCOMPLEX_STRUCT_M(LY_STMT_REVISION, struct lys_revision, yang_print_revision);
+                    break;
                 default:
                     /* TODO */
                     break;
diff --git a/src/printer_yin.c b/src/printer_yin.c
index debb72f..a8075ef 100644
--- a/src/printer_yin.c
+++ b/src/printer_yin.c
@@ -1579,6 +1579,22 @@
 }
 
 static void
+yin_print_revision(struct lyout *out, int level, const struct lys_module *module, const struct lys_revision *rev)
+{
+    if (rev->dsc || rev->ref || rev->ext_size) {
+        yin_print_open(out, level, NULL, "revision", "date", rev->date, 1);
+        level++;
+        yin_print_extension_instances(out, level, module, LYEXT_SUBSTMT_SELF, 0, rev->ext, rev->ext_size);
+        yin_print_substmt(out, level, LYEXT_SUBSTMT_DESCRIPTION, 0, rev->dsc, module, rev->ext, rev->ext_size);
+        yin_print_substmt(out, level, LYEXT_SUBSTMT_REFERENCE, 0, rev->ref, module, rev->ext, rev->ext_size);
+        level--;
+        yin_print_close(out, level, NULL, "revision", 1);
+    } else {
+        yin_print_open(out, level, NULL, "revision", "date", rev->date, -1);
+    }
+}
+
+static void
 yin_print_xmlns(struct lyout *out, const struct lys_module *module)
 {
     unsigned int i, lvl;
@@ -1702,20 +1718,7 @@
 
     /* revision-stmts */
     for (i = 0; i < module->rev_size; i++) {
-        if (module->rev[i].dsc || module->rev[i].ref || module->ext_size) {
-            yin_print_open(out, level, NULL, "revision", "date", module->rev[i].date, 1);
-            level++;
-            yin_print_extension_instances(out, level, module, LYEXT_SUBSTMT_SELF, 0,
-                                          module->rev[i].ext, module->rev[i].ext_size);
-            yin_print_substmt(out, level, LYEXT_SUBSTMT_DESCRIPTION, 0, module->rev[i].dsc,
-                              module, module->rev[i].ext, module->rev[i].ext_size);
-            yin_print_substmt(out, level, LYEXT_SUBSTMT_REFERENCE, 0, module->rev[i].ref,
-                               module, module->rev[i].ext, module->rev[i].ext_size);
-            level--;
-            yin_print_close(out, level, NULL, "revision", 1);
-        } else {
-            yin_print_open(out, level, NULL, "revision", "date", module->rev[i].date, -1);
-        }
+        yin_print_revision(out, level, module, &module->rev[i]);
     }
 
     /* body-stmts */
@@ -2202,6 +2205,9 @@
                 case LY_STMT_WHEN:
                     YIN_PRINT_EXTCOMPLEX_STRUCT_M(LY_STMT_WHEN, struct lys_when, yin_print_when);
                     break;
+                case LY_STMT_REVISION:
+                    YIN_PRINT_EXTCOMPLEX_STRUCT_M(LY_STMT_REVISION, struct lys_revision, yin_print_revision);
+                    break;
                 default:
                     /* TODO */
                     break;
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 9e67819..122f9e9 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -4531,6 +4531,28 @@
                 case LY_STMT_WHEN:
                     EXTCOMPLEX_FREE_STRUCT(LY_STMT_WHEN, struct lys_when, lys_when_free, 0);
                     break;
+                case LY_STMT_REVISION:
+                    pp = lys_ext_complex_get_substmt(LY_STMT_REVISION, (struct lys_ext_instance_complex *)e[i], NULL);
+                    if (!pp || !(*pp)) {
+                        break;
+                    }
+                    if (substmt[j].cardinality >= LY_STMT_CARD_SOME) { /* process array */
+                        for (start = pp = *pp; *pp; pp++) {
+                            lydict_remove(ctx, (*(struct lys_revision**)pp)->dsc);
+                            lydict_remove(ctx, (*(struct lys_revision**)pp)->ref);
+                            lys_extension_instances_free(ctx, (*(struct lys_revision**)pp)->ext,
+                                                         (*(struct lys_revision**)pp)->ext_size);
+                            free(*pp);
+                        }
+                        free(start);
+                    } else { /* single item */
+                        lydict_remove(ctx, (*(struct lys_revision**)pp)->dsc);
+                        lydict_remove(ctx, (*(struct lys_revision**)pp)->ref);
+                        lys_extension_instances_free(ctx, (*(struct lys_revision**)pp)->ext,
+                                                     (*(struct lys_revision**)pp)->ext_size);
+                        free(*pp);
+                    }
+                    break;
                 default:
                     /* nothing to free */
                     break;