MINOR: map: Add payload support to "add map"

It is now possible to use a payload with the "add map" command.
These syntaxes will work the same way:

 # echo "add map #-1 key value" | socat /tmp/sock1 -

 # echo -e "add map #-1 <<\n$(cat data)\n" | socat /tmp/sock1 -

with

 # cat data
 key1 value1 with spaces
 key2 value2
 key3 value3 also with spaces

Signed-off-by: Aurélien Nephtali <aurelien.nephtali@corp.ovh.com>
diff --git a/src/map.c b/src/map.c
index d02a025..ad47c7f 100644
--- a/src/map.c
+++ b/src/map.c
@@ -772,6 +772,20 @@
 	return 1;
 }
 
+static int map_add_key_value(struct appctx *appctx, const char *key, const char *value, char **err)
+{
+	int ret;
+
+	HA_SPIN_LOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
+	if (appctx->ctx.map.display_flags == PAT_REF_MAP)
+		ret = pat_ref_add(appctx->ctx.map.ref, key, value, err);
+	else
+		ret = pat_ref_add(appctx->ctx.map.ref, key, NULL, err);
+	HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
+
+	return ret;
+}
+
 static int cli_parse_add_map(char **args, char *payload, struct appctx *appctx, void *private)
 {
 	if (strcmp(args[1], "map") == 0 ||
@@ -785,13 +799,16 @@
 		else
 			appctx->ctx.map.display_flags = PAT_REF_ACL;
 
-		/* If the keywork is "map", we expect three parameters, if it
-		 * is "acl", we expect only two parameters
+		/* If the keyword is "map", we expect:
+		 *   - three parameters if there is no payload
+		 *   - one parameter if there is a payload
+		 * If it is "acl", we expect only two parameters
 		 */
 		if (appctx->ctx.map.display_flags == PAT_REF_MAP) {
-			if (!*args[2] || !*args[3] || !*args[4]) {
+			if ((!payload && (!*args[2] || !*args[3] || !*args[4])) ||
+			    (payload && !*args[2])) {
 				appctx->ctx.cli.severity = LOG_ERR;
-				appctx->ctx.cli.msg = "'add map' expects three parameters: map identifier, key and value.\n";
+				appctx->ctx.cli.msg = "'add map' expects three parameters (map identifier, key and value) or one parameter (map identifier) and a payload\n";
 				appctx->st0 = CLI_ST_PRINT;
 				return 1;
 			}
@@ -832,26 +849,69 @@
 			return 1;
 		}
 
-		/* Add value. */
+		/* Add value(s). */
 		err = NULL;
-		HA_SPIN_LOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
-		if (appctx->ctx.map.display_flags == PAT_REF_MAP)
-			ret = pat_ref_add(appctx->ctx.map.ref, args[3], args[4], &err);
-		else
-			ret = pat_ref_add(appctx->ctx.map.ref, args[3], NULL, &err);
-		HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
-		if (!ret) {
-			if (err) {
-				memprintf(&err, "%s.\n", err);
-				appctx->ctx.cli.err = err;
-				appctx->st0 = CLI_ST_PRINT_FREE;
+		if (!payload) {
+			ret = map_add_key_value(appctx, args[3], args[4], &err);
+			if (!ret) {
+				if (err) {
+					memprintf(&err, "%s.\n", err);
+					appctx->ctx.cli.err = err;
+					appctx->st0 = CLI_ST_PRINT_FREE;
+				}
+				else {
+					appctx->ctx.cli.severity = LOG_ERR;
+					appctx->ctx.cli.msg = "Failed to add an entry.\n";
+					appctx->st0 = CLI_ST_PRINT;
+				}
+				return 1;
 			}
-			else {
-				appctx->ctx.cli.severity = LOG_ERR;
-				appctx->ctx.cli.msg = "Failed to add an entry.\n";
-				appctx->st0 = CLI_ST_PRINT;
+		}
+		else {
+			const char *end = payload + strlen(payload);
+
+			while (payload < end) {
+				char *key, *value;
+				size_t l;
+
+				/* key */
+				key = payload;
+				l = strcspn(key, " \t");
+				payload += l;
+
+				if (!*payload && appctx->ctx.map.display_flags == PAT_REF_MAP) {
+					memprintf(&err, "Missing value for key '%s'.\n", key);
+					appctx->ctx.cli.err = err;
+					appctx->st0 = CLI_ST_PRINT_FREE;
+					return 1;
+				}
+				key[l] = 0;
+				payload++;
+
+				/* value */
+				payload += strspn(payload, " \t");
+				value = payload;
+				l = strcspn(value, "\n");
+				payload += l;
+				if (*payload)
+					payload++;
+				value[l] = 0;
+
+				ret = map_add_key_value(appctx, key, value, &err);
+				if (!ret) {
+					if (err) {
+						memprintf(&err, "%s.\n", err);
+						appctx->ctx.cli.err = err;
+						appctx->st0 = CLI_ST_PRINT_FREE;
+					}
+					else {
+						appctx->ctx.cli.severity = LOG_ERR;
+						appctx->ctx.cli.msg = "Failed to add a key.\n";
+						appctx->st0 = CLI_ST_PRINT;
+					}
+					return 1;
+				}
 			}
-			return 1;
 		}
 
 		/* The add is done, send message. */