yin parser: FEATURE: support augment in uses statement
diff --git a/src/parser/yin.c b/src/parser/yin.c
index 7d39b72..1e73740 100644
--- a/src/parser/yin.c
+++ b/src/parser/yin.c
@@ -891,6 +891,27 @@
 	return EXIT_FAILURE;
 }
 
+static int fill_yin_augment(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, struct ly_augment *aug)
+{
+	const char *value;
+
+	GETVAL(value, yin, "target-node");
+	aug->target_name = lydict_insert(module->ctx, value, 0);
+	aug->parent = parent;
+
+	/* do not resolve now, just keep the definition which will be parsed later
+	 * when we will have the target node
+	 */
+	lyxml_unlink_elem(yin);
+	aug->child = (struct ly_mnode *)yin;
+
+	return EXIT_SUCCESS;
+
+error:
+
+	return EXIT_FAILURE;
+}
+
 static int fill_yin_refine(struct ly_module *module, struct lyxml_elem *yin, struct ly_refine *rfn)
 {
 	struct lyxml_elem *sub, *next;
@@ -904,43 +925,13 @@
 	GETVAL(value, yin, "target-node");
 	rfn->target = lydict_insert(module->ctx, value, strlen(value));
 
-	LY_TREE_FOR_SAFE(yin->child, next, sub) {
-		/* applicable to any target */
-		if (!strcmp(sub->name, "description")) {
-			if (rfn->dsc) {
-				LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
-				goto error;
-			}
-			rfn->dsc = read_yin_subnode(module->ctx, sub, "text");
-			if (!rfn->dsc) {
-				goto error;
-			}
-		} else if (!strcmp(sub->name, "reference")) {
-			if (rfn->ref) {
-				LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
-				goto error;
-			}
-			rfn->ref = read_yin_subnode(module->ctx, sub, "text");
-			if (!rfn->ref) {
-				goto error;
-			}
-		} else if (!strcmp(sub->name, "config")) {
-			if (rfn->flags & LY_NODE_CONFIG_MASK) {
-				LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
-				goto error;
-			}
-			GETVAL(value, sub, "value");
-			if (!strcmp(value, "false")) {
-				rfn->flags |= LY_NODE_CONFIG_R;
-			} else if (!strcmp(value, "false")) {
-				rfn->flags |= LY_NODE_CONFIG_W;
-			} else {
-				LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
-				goto error;
-			}
+	if (read_yin_common(module, NULL, (struct ly_mnode *)rfn, yin, OPT_CONFIG)) {
+		goto error;
+	}
 
+	LY_TREE_FOR_SAFE(yin->child, next, sub) {
 		/* limited applicability */
-		} else if (!strcmp(sub->name, "default")) {
+		if (!strcmp(sub->name, "default")) {
 			/* leaf or choice */
 			if (rfn->mod.dflt) {
 				LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
@@ -1234,9 +1225,6 @@
  * Covers:
  * description, reference, status, optionaly config
  *
- * ext: 0 - no config
- *      1 - parse config, but not inherit it
- *      2 - parse config and if not present, inherit it from parent
  */
 static int read_yin_common(struct ly_module *module, struct ly_mnode *parent,
 		                   struct ly_mnode *mnode, struct lyxml_elem *xmlnode, int opt)
@@ -1250,11 +1238,13 @@
 		mnode->module = module;
 	}
 
-	GETVAL(value, xmlnode, "name");
-	if ((opt & OPT_IDENT) && check_identifier(value, LY_IDENT_NAME, LOGLINE(xmlnode), NULL, NULL)) {
-		goto error;
+	if (opt & OPT_IDENT) {
+		GETVAL(value, xmlnode, "name");
+		if (check_identifier(value, LY_IDENT_NAME, LOGLINE(xmlnode), NULL, NULL)) {
+			goto error;
+		}
+		mnode->name = lydict_insert(ctx, value, strlen(value));
 	}
-	mnode->name = lydict_insert(ctx, value, strlen(value));
 
 	/* process local parameters */
 	LY_TREE_FOR_SAFE(xmlnode->child, next, sub) {
@@ -2553,6 +2543,199 @@
 	return EXIT_SUCCESS;
 }
 
+int resolve_uses(struct ly_mnode_uses *uses, unsigned int line)
+{
+	struct ly_ctx *ctx;
+	struct ly_mnode *mnode = NULL, *mnode_aux;
+	struct ly_refine *rfn;
+	struct ly_augment *aug;
+	struct ly_must *newmust;
+	struct lyxml_elem *yin, *next, *sub;
+	struct ly_module *module;
+	int i, j;
+	uint8_t size;
+
+	/* copy the data nodes from grouping into the uses context */
+	LY_TREE_FOR(uses->grp->child, mnode) {
+		mnode_aux = ly_mnode_dup(uses->module, mnode, uses->flags, 1, line);
+		if (!mnode_aux) {
+			LOGVAL(VE_SPEC, line, "Copying data from grouping failed");
+			return EXIT_FAILURE;
+		}
+		ly_mnode_addchild((struct ly_mnode *)uses, mnode_aux);
+	}
+	ctx = uses->module->ctx;
+
+	/* apply refines */
+	for (i = 0; i < uses->refine_size; i++) {
+		rfn = &uses->refine[i];
+		mnode = resolve_schema_nodeid(rfn->target, (struct ly_mnode *)uses, 1);
+		if (!mnode) {
+			LOGVAL(VE_INARG, line, rfn->target, "uses");
+			return EXIT_FAILURE;
+		}
+
+		if (rfn->target_type && !(mnode->nodetype & rfn->target_type)) {
+			LOGVAL(VE_SPEC, line, "refine substatements not applicable to the target-node");
+			return EXIT_FAILURE;
+		}
+
+		/* description on any nodetype */
+		if (rfn->dsc) {
+			lydict_remove(ctx, mnode->dsc);
+			mnode->dsc = lydict_insert(ctx, rfn->dsc, 0);
+		}
+
+		/* reference on any nodetype */
+		if (rfn->ref) {
+			lydict_remove(ctx, mnode->ref);
+			mnode->ref = lydict_insert(ctx, rfn->ref, 0);
+		}
+
+		/* config on any nodetype */
+		if (rfn->flags & LY_NODE_CONFIG_MASK) {
+			mnode->flags &= ~LY_NODE_CONFIG_MASK;
+			mnode->flags |= (rfn->flags & LY_NODE_CONFIG_MASK);
+		}
+
+		/* default value ... */
+		if (rfn->mod.dflt) {
+			if (mnode->nodetype == LY_NODE_LEAF) {
+				/* leaf */
+				lydict_remove(ctx, ((struct ly_mnode_leaf *)mnode)->dflt);
+				((struct ly_mnode_leaf *)mnode)->dflt = lydict_insert(ctx, rfn->mod.dflt, 0);
+			} else if (mnode->nodetype == LY_NODE_CHOICE) {
+				/* choice */
+				((struct ly_mnode_choice *)mnode)->dflt = resolve_schema_nodeid(rfn->mod.dflt, mnode, 0);
+				if (!((struct ly_mnode_choice *)mnode)->dflt) {
+					LOGVAL(VE_INARG, line, rfn->mod.dflt, "default");
+					return EXIT_FAILURE;
+				}
+			}
+		}
+
+		/* mandatory on leaf, anyxml or choice */
+		if (mnode->nodetype & (LY_NODE_LEAF | LY_NODE_ANYXML | LY_NODE_CHOICE)) {
+			if (rfn->flags & LY_NODE_MAND_FALSE) {
+				/* erase mandatory true flag, we don't use false flag in schema nodes */
+				mnode->flags &= ~LY_NODE_MAND_TRUE;
+			} else if (rfn->flags & LY_NODE_MAND_TRUE) {
+				/* set mandatory true flag */
+				mnode->flags |= LY_NODE_MAND_TRUE;
+			}
+		}
+
+		/* presence on container */
+		if ((mnode->nodetype & LY_NODE_CONTAINER) && rfn->mod.presence) {
+			lydict_remove(ctx, ((struct ly_mnode_container *)mnode)->presence);
+			((struct ly_mnode_container *)mnode)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
+		}
+
+		/* min/max-elements on list or leaf-list */
+		if (mnode->nodetype & (LY_NODE_LEAFLIST | LY_NODE_LIST)) {
+			/* magic - bit 3 in flags means min set, bit 4 says max set */
+			if (rfn->flags & 0x04) {
+				((struct ly_mnode_list *)mnode)->min = rfn->mod.list.min;
+			}
+			if (rfn->flags & 0x08) {
+				((struct ly_mnode_list *)mnode)->max = rfn->mod.list.max;
+			}
+		}
+
+		/* must in leaf, leaf-list, list, container or anyxml */
+		if (rfn->must_size) {
+			size = ((struct ly_mnode_leaf *)mnode)->must_size + rfn->must_size;
+			newmust = realloc(((struct ly_mnode_leaf *)mnode)->must, size * sizeof *rfn->must);
+			if (!newmust) {
+				LOGMEM;
+				return EXIT_FAILURE;
+			}
+			for (i = 0, j = ((struct ly_mnode_leaf *)mnode)->must_size; i < rfn->must_size; i++, j++) {
+				newmust[j].cond = lydict_insert(ctx, rfn->must[i].cond, 0);
+				newmust[j].dsc = lydict_insert(ctx, rfn->must[i].dsc, 0);
+				newmust[j].ref = lydict_insert(ctx, rfn->must[i].ref, 0);
+				newmust[j].eapptag = lydict_insert(ctx, rfn->must[i].eapptag, 0);
+				newmust[j].emsg = lydict_insert(ctx, rfn->must[i].emsg, 0);
+			}
+
+			((struct ly_mnode_leaf *)mnode)->must = newmust;
+			((struct ly_mnode_leaf *)mnode)->must_size = size;
+		}
+	}
+
+	/* apply augments */
+	for (i = 0; i < uses->augment_size; i++) {
+		/* resolve target node */
+		aug = &uses->augment[i];
+		aug->target = resolve_schema_nodeid(aug->target_name, (struct ly_mnode *)uses, 1);
+		if (!aug->target) {
+			LOGVAL(VE_INARG, line, aug->target, "uses");
+			goto error;
+		}
+
+		if (!aug->child) {
+			continue;
+		}
+
+		yin = (struct lyxml_elem *)aug->child;
+		module = aug->parent->module;
+
+		if (read_yin_common(module, aug->target, (struct ly_mnode *)aug, yin, OPT_CONFIG)) {
+			return EXIT_FAILURE;
+		}
+
+		LY_TREE_FOR_SAFE(yin->child, next, sub) {
+			if (!strcmp(sub->name, "container")) {
+				mnode = read_yin_container(module, aug->target, sub, 1, NULL);
+			} else if (!strcmp(sub->name, "leaf-list")) {
+				mnode = read_yin_leaflist(module, aug->target, sub, 1);
+			} else if (!strcmp(sub->name, "leaf")) {
+				mnode = read_yin_leaf(module, aug->target, sub, 1);
+			} else if (!strcmp(sub->name, "list")) {
+				mnode = read_yin_list(module, aug->target, sub, 1, NULL);
+			} else if (!strcmp(sub->name, "uses")) {
+				mnode = read_yin_uses(module, aug->target, sub, 1, NULL);
+			} else if (!strcmp(sub->name, "choice")) {
+				mnode = read_yin_case(module, aug->target, sub, 1, NULL);
+			} else if (aug->target->nodetype == LY_NODE_CHOICE && !strcmp(sub->name, "case")) {
+					mnode = read_yin_case(module, aug->target, sub, 1, NULL);
+			} else if (!strcmp(sub->name, "anyxml")) {
+				mnode = read_yin_anyxml(module, aug->target, sub, 1);
+	#if 0
+			} else {
+				LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
+				goto error;
+	#else
+			} else {
+				continue;
+	#endif
+			}
+
+			if (!mnode) {
+				goto error;
+			}
+
+			lyxml_free_elem(module->ctx, sub);
+
+			/* the parent pointer will point to the augment node, but all
+			 * siblings pointers and possibly the child node in target does
+			 * not know about the augment and follow the standard schema tree
+			 * structure
+			 */
+			mnode->parent = (struct ly_mnode *)aug;
+			mnode = NULL;
+		}
+
+		lyxml_free_elem(module->ctx, yin);
+		aug->child = NULL;
+	}
+
+	return EXIT_SUCCESS;
+
+error:
+
+	return EXIT_FAILURE;
+}
 
 /*
  * resolve - referenced grouping should be bounded to the namespace (resolved)
@@ -2568,6 +2751,7 @@
 	struct ly_mnode *retval;
 	struct ly_mnode_uses *uses;
 	struct mnode_list *unres_new;
+	const char *value;
 	int c_ref = 0, c_aug = 0;
 	int r;
 
@@ -2576,6 +2760,9 @@
 	uses->prev = (struct ly_mnode *)uses;
 	retval = (struct ly_mnode *)uses;
 
+	GETVAL(value, node, "name");
+	uses->name = lydict_insert(module->ctx, value, 0);
+
 	if (read_yin_common(module, parent, retval, node, OPT_MODULE | (resolve ? OPT_INHERIT : 0))) {
 		goto error;
 	}
@@ -2607,8 +2794,7 @@
 			r = fill_yin_refine(module, sub, &uses->refine[uses->refine_size]);
 			uses->refine_size++;
 		} else if (!strcmp(sub->name, "augment")) {
-			/* TODO r = fill_yin_augment(module, sub, &uses->augment[uses->augment_size]); */
-			r = 0;
+			r = fill_yin_augment(module, retval, sub, &uses->augment[uses->augment_size]);
 			uses->augment_size++;
 		}