vty: command.c: Fix: multi-choice args are no longer passed incomplete to vty func

For instance, take command "multi0 (one|two|three)":
If user executes "multi0 tw", VTY func will receive argv[0]="two"
instead of argv[0]="tw".

Fixes: OS#4045
Change-Id: I91b6621ac3d87fda5412a9b415e7bfb4736c8a9a
diff --git a/src/vty/command.c b/src/vty/command.c
index 17d28fe..3c91bfd 100644
--- a/src/vty/command.c
+++ b/src/vty/command.c
@@ -2217,7 +2217,7 @@
 cmd_execute_command_real(vector vline, struct vty *vty,
 			 struct cmd_element **cmd)
 {
-	unsigned int i;
+	unsigned int i, j;
 	unsigned int index;
 	vector cmd_vector;
 	struct cmd_element *cmd_element;
@@ -2228,6 +2228,10 @@
 	enum match_type match = 0;
 	int varflag;
 	char *command;
+	int rc;
+	/* Used for temporary storage of cmd_deopt() allocated arguments during
+	   argv[] generation */
+	void *cmd_deopt_ctx = NULL;
 
 	/* Make copy of command elements. */
 	cmd_vector = vector_copy(cmd_node_vector(cmdvec, vty->node));
@@ -2293,9 +2297,13 @@
 	varflag = 0;
 	argc = 0;
 
+	cmd_deopt_ctx = talloc_named_const(tall_vty_cmd_ctx, 0, __func__);
+
 	for (i = 0; i < vector_active(vline); i++) {
-		if (argc == CMD_ARGC_MAX)
-			return CMD_ERR_EXEED_ARGC_MAX;
+		if (argc == CMD_ARGC_MAX) {
+			rc = CMD_ERR_EXEED_ARGC_MAX;
+			goto rc_free_deopt_ctx;
+		}
 		if (varflag) {
 			argv[argc++] = vector_slot(vline, i);
 			continue;
@@ -2313,7 +2321,32 @@
 			    || CMD_OPTION(desc->cmd))
 				argv[argc++] = vector_slot(vline, i);
 		} else {
-			argv[argc++] = vector_slot(vline, i);
+			/* multi choice argument. look up which choice
+			   the user meant (can only be one after
+			   filtering and checking for ambigous). For instance,
+			   if user typed "th" for "(two|three)" arg, we
+			   want to pass "three" in argv[]. */
+			for (j = 0; j < vector_active(descvec); j++) {
+				struct desc *desc = vector_slot(descvec, j);
+				const char *tmp_cmd;
+				if (!desc)
+					continue;
+				if (cmd_match(desc->cmd, vector_slot(vline, i), ANY_MATCH, true) == NO_MATCH)
+					continue;
+				if (CMD_OPTION(desc->cmd)) {
+					/* we need to first remove the [] chars, then check to see what's inside (var or token) */
+					tmp_cmd = cmd_deopt(cmd_deopt_ctx, desc->cmd);
+				} else {
+					tmp_cmd = desc->cmd;
+				}
+
+				if(CMD_VARIABLE(tmp_cmd)) {
+					argv[argc++] = vector_slot(vline, i);
+				} else {
+					argv[argc++] = tmp_cmd;
+				}
+				break;
+			}
 		}
 	}
 
@@ -2322,10 +2355,14 @@
 		*cmd = matched_element;
 
 	if (matched_element->daemon)
-		return CMD_SUCCESS_DAEMON;
+		rc = CMD_SUCCESS_DAEMON;
+	else	/* Execute matched command. */
+		rc = (*matched_element->func) (matched_element, vty, argc, argv);
 
-	/* Execute matched command. */
-	return (*matched_element->func) (matched_element, vty, argc, argv);
+rc_free_deopt_ctx:
+	/* Now after we called the command func, we can free temporary strings */
+	talloc_free(cmd_deopt_ctx);
+	return rc;
 }
 
 int