CLEANUP: map/cli: take the "show map" context definition out of the appctx

This makes use of the generic command context allocation so that the
appctx doesn't have to declare a specific one anymore. The context is
created during parsing. Many commands, including pure parsers, use this
context but that's not a problem as it's designed to be used this way.
Due to this, many lines are changed but that's in fact a replacement of
"appctx->ctx.map" with "ctx->". Note that the code also uses st2 which
deserves being addressed in separate commit.
diff --git a/include/haproxy/applet-t.h b/include/haproxy/applet-t.h
index f416f73..39338f8 100644
--- a/include/haproxy/applet-t.h
+++ b/include/haproxy/applet-t.h
@@ -150,13 +150,6 @@
 				int st_code;		/* the status code returned by an action */
 			} stats;
 			struct {
-				unsigned int display_flags;
-				struct pat_ref *ref;
-				struct bref bref;	/* back-reference from the pat_ref_elt being dumped */
-				struct pattern_expr *expr;
-				struct buffer chunk;
-			} map;
-			struct {
 				struct hlua *hlua;
 				struct task *task;
 				struct hlua_function *fcn;
diff --git a/src/map.c b/src/map.c
index 6c35680..c20998d 100644
--- a/src/map.c
+++ b/src/map.c
@@ -14,7 +14,7 @@
 #include <syslog.h>
 
 #include <haproxy/api.h>
-#include <haproxy/applet-t.h>
+#include <haproxy/applet.h>
 #include <haproxy/arg.h>
 #include <haproxy/cli.h>
 #include <haproxy/conn_stream.h>
@@ -321,9 +321,23 @@
 	return expr;
 }
 
+/* appctx context for the "{show|get|add|del|*} {map|acl}" commands. This is
+ * used even by commands that only have a parser and no I/O handler because
+ * it provides a unified way to manipulate some fields and will allow to
+ * expand some of them more easily later if needed.
+ */
+struct show_map_ctx {
+	struct pat_ref *ref;
+	struct bref bref;	/* back-reference from the pat_ref_elt being dumped */
+	struct pattern_expr *expr;
+	struct buffer chunk;
+	unsigned int display_flags;
+};
+
 /* expects the current generation ID in appctx->cli.cli.i0 */
 static int cli_io_handler_pat_list(struct appctx *appctx)
 {
+	struct show_map_ctx *ctx = appctx->svcctx;
 	struct conn_stream *cs = appctx->owner;
 	struct pat_ref_elt *elt;
 
@@ -332,12 +346,12 @@
 		 * reference to the last ref_elt being dumped.
 		 */
 		if (appctx->st2 == STAT_ST_LIST) {
-			HA_SPIN_LOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
-			if (!LIST_ISEMPTY(&appctx->ctx.map.bref.users)) {
-				LIST_DELETE(&appctx->ctx.map.bref.users);
-				LIST_INIT(&appctx->ctx.map.bref.users);
+			HA_SPIN_LOCK(PATREF_LOCK, &ctx->ref->lock);
+			if (!LIST_ISEMPTY(&ctx->bref.users)) {
+				LIST_DELETE(&ctx->bref.users);
+				LIST_INIT(&ctx->bref.users);
 			}
-			HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
+			HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
 		}
 		return 1;
 	}
@@ -349,19 +363,19 @@
 		/* fall through */
 
 	case STAT_ST_LIST:
-		HA_SPIN_LOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
+		HA_SPIN_LOCK(PATREF_LOCK, &ctx->ref->lock);
 
-		if (!LIST_ISEMPTY(&appctx->ctx.map.bref.users)) {
-			LIST_DELETE(&appctx->ctx.map.bref.users);
-			LIST_INIT(&appctx->ctx.map.bref.users);
+		if (!LIST_ISEMPTY(&ctx->bref.users)) {
+			LIST_DELETE(&ctx->bref.users);
+			LIST_INIT(&ctx->bref.users);
 		} else {
-			appctx->ctx.map.bref.ref = appctx->ctx.map.ref->head.n;
+			ctx->bref.ref = ctx->ref->head.n;
 		}
 
-		while (appctx->ctx.map.bref.ref != &appctx->ctx.map.ref->head) {
+		while (ctx->bref.ref != &ctx->ref->head) {
 			chunk_reset(&trash);
 
-			elt = LIST_ELEM(appctx->ctx.map.bref.ref, struct pat_ref_elt *, list);
+			elt = LIST_ELEM(ctx->bref.ref, struct pat_ref_elt *, list);
 
 			if (elt->gen_id != appctx->ctx.cli.i0)
 				goto skip;
@@ -379,16 +393,16 @@
 				/* let's try again later from this stream. We add ourselves into
 				 * this stream's users so that it can remove us upon termination.
 				 */
-				LIST_APPEND(&elt->back_refs, &appctx->ctx.map.bref.users);
-				HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
+				LIST_APPEND(&elt->back_refs, &ctx->bref.users);
+				HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
 				cs_rx_room_blk(cs);
 				return 0;
 			}
 		skip:
 			/* get next list entry and check the end of the list */
-			appctx->ctx.map.bref.ref = elt->list.n;
+			ctx->bref.ref = elt->list.n;
 		}
-		HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
+		HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
 		/* fall through */
 
 	default:
@@ -399,6 +413,7 @@
 
 static int cli_io_handler_pats_list(struct appctx *appctx)
 {
+	struct show_map_ctx *ctx = appctx->svcctx;
 	struct conn_stream *cs = appctx->owner;
 
 	switch (appctx->st2) {
@@ -419,23 +434,23 @@
 		 * available field of this pointer is <list>. It is used with the function
 		 * pat_list_get_next() for returning the first available entry
 		 */
-		appctx->ctx.map.ref = LIST_ELEM(&pattern_reference, struct pat_ref *, list);
-		appctx->ctx.map.ref = pat_list_get_next(appctx->ctx.map.ref, &pattern_reference,
-		                                        appctx->ctx.map.display_flags);
+		ctx->ref = LIST_ELEM(&pattern_reference, struct pat_ref *, list);
+		ctx->ref = pat_list_get_next(ctx->ref, &pattern_reference,
+		                                        ctx->display_flags);
 		appctx->st2 = STAT_ST_LIST;
 		/* fall through */
 
 	case STAT_ST_LIST:
-		while (appctx->ctx.map.ref) {
+		while (ctx->ref) {
 			chunk_reset(&trash);
 
 			/* Build messages. If the reference is used by another category than
 			 * the listed categories, display the information in the message.
 			 */
-			chunk_appendf(&trash, "%d (%s) %s. curr_ver=%u next_ver=%u entry_cnt=%llu\n", appctx->ctx.map.ref->unique_id,
-			              appctx->ctx.map.ref->reference ? appctx->ctx.map.ref->reference : "",
-			              appctx->ctx.map.ref->display, appctx->ctx.map.ref->curr_gen, appctx->ctx.map.ref->next_gen,
-			              appctx->ctx.map.ref->entry_cnt);
+			chunk_appendf(&trash, "%d (%s) %s. curr_ver=%u next_ver=%u entry_cnt=%llu\n", ctx->ref->unique_id,
+			              ctx->ref->reference ? ctx->ref->reference : "",
+			              ctx->ref->display, ctx->ref->curr_gen, ctx->ref->next_gen,
+			              ctx->ref->entry_cnt);
 
 			if (ci_putchk(cs_ic(cs), &trash) == -1) {
 				/* let's try again later from this stream. We add ourselves into
@@ -446,8 +461,8 @@
 			}
 
 			/* get next list entry and check the end of the list */
-			appctx->ctx.map.ref = pat_list_get_next(appctx->ctx.map.ref, &pattern_reference,
-			                                        appctx->ctx.map.display_flags);
+			ctx->ref = pat_list_get_next(ctx->ref, &pattern_reference,
+			                                        ctx->display_flags);
 		}
 
 		/* fall through */
@@ -461,6 +476,7 @@
 
 static int cli_io_handler_map_lookup(struct appctx *appctx)
 {
+	struct show_map_ctx *ctx = appctx->svcctx;
 	struct conn_stream *cs = appctx->owner;
 	struct sample sample;
 	struct pattern *pat;
@@ -469,48 +485,48 @@
 	switch (appctx->st2) {
 	case STAT_ST_INIT:
 		/* Init to the first entry. The list cannot be change */
-		appctx->ctx.map.expr = LIST_ELEM(&appctx->ctx.map.ref->pat, struct pattern_expr *, list);
-		appctx->ctx.map.expr = pat_expr_get_next(appctx->ctx.map.expr, &appctx->ctx.map.ref->pat);
+		ctx->expr = LIST_ELEM(&ctx->ref->pat, struct pattern_expr *, list);
+		ctx->expr = pat_expr_get_next(ctx->expr, &ctx->ref->pat);
 		appctx->st2 = STAT_ST_LIST;
 		/* fall through */
 
 	case STAT_ST_LIST:
-		HA_SPIN_LOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
+		HA_SPIN_LOCK(PATREF_LOCK, &ctx->ref->lock);
 		/* for each lookup type */
-		while (appctx->ctx.map.expr) {
+		while (ctx->expr) {
 			/* initialise chunk to build new message */
 			chunk_reset(&trash);
 
 			/* execute pattern matching */
 			sample.data.type = SMP_T_STR;
 			sample.flags = SMP_F_CONST;
-			sample.data.u.str.data = appctx->ctx.map.chunk.data;
-			sample.data.u.str.area = appctx->ctx.map.chunk.area;
+			sample.data.u.str.data = ctx->chunk.data;
+			sample.data.u.str.area = ctx->chunk.area;
 
-			if (appctx->ctx.map.expr->pat_head->match &&
-			    sample_convert(&sample, appctx->ctx.map.expr->pat_head->expect_type))
-				pat = appctx->ctx.map.expr->pat_head->match(&sample, appctx->ctx.map.expr, 1);
+			if (ctx->expr->pat_head->match &&
+			    sample_convert(&sample, ctx->expr->pat_head->expect_type))
+				pat = ctx->expr->pat_head->match(&sample, ctx->expr, 1);
 			else
 				pat = NULL;
 
 			/* build return message: set type of match */
 			for (match_method=0; match_method<PAT_MATCH_NUM; match_method++)
-				if (appctx->ctx.map.expr->pat_head->match == pat_match_fcts[match_method])
+				if (ctx->expr->pat_head->match == pat_match_fcts[match_method])
 					break;
 			if (match_method >= PAT_MATCH_NUM)
-				chunk_appendf(&trash, "type=unknown(%p)", appctx->ctx.map.expr->pat_head->match);
+				chunk_appendf(&trash, "type=unknown(%p)", ctx->expr->pat_head->match);
 			else
 				chunk_appendf(&trash, "type=%s", pat_match_names[match_method]);
 
 			/* case sensitive */
-			if (appctx->ctx.map.expr->mflags & PAT_MF_IGNORE_CASE)
+			if (ctx->expr->mflags & PAT_MF_IGNORE_CASE)
 				chunk_appendf(&trash, ", case=insensitive");
 			else
 				chunk_appendf(&trash, ", case=sensitive");
 
 			/* Display no match, and set default value */
 			if (!pat) {
-				if (appctx->ctx.map.display_flags == PAT_REF_MAP)
+				if (ctx->display_flags == PAT_REF_MAP)
 					chunk_appendf(&trash, ", found=no");
 				else
 					chunk_appendf(&trash, ", match=no");
@@ -519,7 +535,7 @@
 			/* Display match and match info */
 			else {
 				/* display match */
-				if (appctx->ctx.map.display_flags == PAT_REF_MAP)
+				if (ctx->display_flags == PAT_REF_MAP)
 					chunk_appendf(&trash, ", found=yes");
 				else
 					chunk_appendf(&trash, ", match=yes");
@@ -531,7 +547,7 @@
 					chunk_appendf(&trash, ", idx=list");
 
 				/* display pattern */
-				if (appctx->ctx.map.display_flags == PAT_REF_MAP) {
+				if (ctx->display_flags == PAT_REF_MAP) {
 					if (pat->ref && pat->ref->pattern)
 						chunk_appendf(&trash, ", key=\"%s\"", pat->ref->pattern);
 					else
@@ -545,7 +561,7 @@
 				}
 
 				/* display return value */
-				if (appctx->ctx.map.display_flags == PAT_REF_MAP) {
+				if (ctx->display_flags == PAT_REF_MAP) {
 					if (pat->data && pat->ref && pat->ref->sample)
 						chunk_appendf(&trash, ", value=\"%s\", type=\"%s\"", pat->ref->sample,
 						              smp_to_type[pat->data->type]);
@@ -561,16 +577,16 @@
 				/* let's try again later from this stream. We add ourselves into
 				 * this stream's users so that it can remove us upon termination.
 				 */
-				HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
+				HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
 				cs_rx_room_blk(cs);
 				return 0;
 			}
 
 			/* get next entry */
-			appctx->ctx.map.expr = pat_expr_get_next(appctx->ctx.map.expr,
-			                                         &appctx->ctx.map.ref->pat);
+			ctx->expr = pat_expr_get_next(ctx->expr,
+			                                         &ctx->ref->pat);
 		}
-		HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
+		HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
 		/* fall through */
 
 	default:
@@ -581,31 +597,35 @@
 
 static void cli_release_mlook(struct appctx *appctx)
 {
-	ha_free(&appctx->ctx.map.chunk.area);
+	struct show_map_ctx *ctx = appctx->svcctx;
+
+	ha_free(&ctx->chunk.area);
 }
 
 
 static int cli_parse_get_map(char **args, char *payload, struct appctx *appctx, void *private)
 {
+	struct show_map_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
+
 	if (strcmp(args[1], "map") == 0 || strcmp(args[1], "acl") == 0) {
 		/* Set flags. */
 		if (args[1][0] == 'm')
-			appctx->ctx.map.display_flags = PAT_REF_MAP;
+			ctx->display_flags = PAT_REF_MAP;
 		else
-			appctx->ctx.map.display_flags = PAT_REF_ACL;
+			ctx->display_flags = PAT_REF_ACL;
 
 		/* No parameter. */
 		if (!*args[2] || !*args[3]) {
-			if (appctx->ctx.map.display_flags == PAT_REF_MAP)
+			if (ctx->display_flags == PAT_REF_MAP)
 				return cli_err(appctx, "Missing map identifier and/or key.\n");
 			else
 				return cli_err(appctx, "Missing ACL identifier and/or key.\n");
 		}
 
 		/* lookup into the maps */
-		appctx->ctx.map.ref = pat_ref_lookup_ref(args[2]);
-		if (!appctx->ctx.map.ref) {
-			if (appctx->ctx.map.display_flags == PAT_REF_MAP)
+		ctx->ref = pat_ref_lookup_ref(args[2]);
+		if (!ctx->ref) {
+			if (ctx->display_flags == PAT_REF_MAP)
 				return cli_err(appctx, "Unknown map identifier. Please use #<id> or <file>.\n");
 			else
 				return cli_err(appctx, "Unknown ACL identifier. Please use #<id> or <file>.\n");
@@ -615,10 +635,10 @@
 		 * it may be used over multiple iterations. It's released
 		 * at the end and upon abort anyway.
 		 */
-		appctx->ctx.map.chunk.data = strlen(args[3]);
-		appctx->ctx.map.chunk.size = appctx->ctx.map.chunk.data + 1;
-		appctx->ctx.map.chunk.area = strdup(args[3]);
-		if (!appctx->ctx.map.chunk.area)
+		ctx->chunk.data = strlen(args[3]);
+		ctx->chunk.size = ctx->chunk.data + 1;
+		ctx->chunk.area = strdup(args[3]);
+		if (!ctx->chunk.area)
 			return cli_err(appctx,  "Out of memory error.\n");
 
 		return 0;
@@ -628,6 +648,8 @@
 
 static int cli_parse_prepare_map(char **args, char *payload, struct appctx *appctx, void *private)
 {
+	struct show_map_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
+
 	if (strcmp(args[1], "map") == 0 ||
 	    strcmp(args[1], "acl") == 0) {
 		uint next_gen;
@@ -635,20 +657,20 @@
 
 		/* Set ACL or MAP flags. */
 		if (args[1][0] == 'm')
-			appctx->ctx.map.display_flags = PAT_REF_MAP;
+			ctx->display_flags = PAT_REF_MAP;
 		else
-			appctx->ctx.map.display_flags = PAT_REF_ACL;
+			ctx->display_flags = PAT_REF_ACL;
 
 		/* lookup into the refs and check the map flag */
-		appctx->ctx.map.ref = pat_ref_lookup_ref(args[2]);
-		if (!appctx->ctx.map.ref ||
-		    !(appctx->ctx.map.ref->flags & appctx->ctx.map.display_flags)) {
-			if (appctx->ctx.map.display_flags == PAT_REF_MAP)
+		ctx->ref = pat_ref_lookup_ref(args[2]);
+		if (!ctx->ref ||
+		    !(ctx->ref->flags & ctx->display_flags)) {
+			if (ctx->display_flags == PAT_REF_MAP)
 				return cli_err(appctx, "Unknown map identifier. Please use #<id> or <file>.\n");
 			else
 				return cli_err(appctx, "Unknown ACL identifier. Please use #<id> or <file>.\n");
 		}
-		next_gen = pat_ref_newgen(appctx->ctx.map.ref);
+		next_gen = pat_ref_newgen(ctx->ref);
 		return cli_dynmsg(appctx, LOG_INFO, memprintf(&msg, "New version created: %u\n", next_gen));
 	}
 
@@ -657,25 +679,29 @@
 
 static void cli_release_show_map(struct appctx *appctx)
 {
+	struct show_map_ctx *ctx = appctx->svcctx;
+
 	if (appctx->st2 == STAT_ST_LIST) {
-		HA_SPIN_LOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
-		if (!LIST_ISEMPTY(&appctx->ctx.map.bref.users))
-			LIST_DELETE(&appctx->ctx.map.bref.users);
-		HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
+		HA_SPIN_LOCK(PATREF_LOCK, &ctx->ref->lock);
+		if (!LIST_ISEMPTY(&ctx->bref.users))
+			LIST_DELETE(&ctx->bref.users);
+		HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
 	}
 }
 
 static int cli_parse_show_map(char **args, char *payload, struct appctx *appctx, void *private)
 {
+	struct show_map_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
+
 	if (strcmp(args[1], "map") == 0 ||
 	    strcmp(args[1], "acl") == 0) {
 		const char *gen = NULL;
 
 		/* Set ACL or MAP flags. */
 		if (args[1][0] == 'm')
-			appctx->ctx.map.display_flags = PAT_REF_MAP;
+			ctx->display_flags = PAT_REF_MAP;
 		else
-			appctx->ctx.map.display_flags = PAT_REF_ACL;
+			ctx->display_flags = PAT_REF_ACL;
 
 		/* no parameter: display all map available */
 		if (!*args[2]) {
@@ -693,10 +719,10 @@
 		}
 
 		/* lookup into the refs and check the map flag */
-		appctx->ctx.map.ref = pat_ref_lookup_ref(args[2]);
-		if (!appctx->ctx.map.ref ||
-		    !(appctx->ctx.map.ref->flags & appctx->ctx.map.display_flags)) {
-			if (appctx->ctx.map.display_flags == PAT_REF_MAP)
+		ctx->ref = pat_ref_lookup_ref(args[2]);
+		if (!ctx->ref ||
+		    !(ctx->ref->flags & ctx->display_flags)) {
+			if (ctx->display_flags == PAT_REF_MAP)
 				return cli_err(appctx, "Unknown map identifier. Please use #<id> or <file>.\n");
 			else
 				return cli_err(appctx, "Unknown ACL identifier. Please use #<id> or <file>.\n");
@@ -706,9 +732,9 @@
 		if (gen)
 			appctx->ctx.cli.i0 = str2uic(gen);
 		else
-			appctx->ctx.cli.i0 = appctx->ctx.map.ref->curr_gen;
+			appctx->ctx.cli.i0 = ctx->ref->curr_gen;
 
-		LIST_INIT(&appctx->ctx.map.bref.users);
+		LIST_INIT(&ctx->bref.users);
 		appctx->io_handler = cli_io_handler_pat_list;
 		appctx->io_release = cli_release_show_map;
 		return 0;
@@ -719,19 +745,21 @@
 
 static int cli_parse_set_map(char **args, char *payload, struct appctx *appctx, void *private)
 {
+	struct show_map_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
+
 	if (strcmp(args[1], "map") == 0) {
 		char *err;
 
 		/* Set flags. */
-		appctx->ctx.map.display_flags = PAT_REF_MAP;
+		ctx->display_flags = PAT_REF_MAP;
 
 		/* Expect three parameters: map name, key and new value. */
 		if (!*args[2] || !*args[3] || !*args[4])
 			return cli_err(appctx, "'set map' expects three parameters: map identifier, key and value.\n");
 
 		/* Lookup the reference in the maps. */
-		appctx->ctx.map.ref = pat_ref_lookup_ref(args[2]);
-		if (!appctx->ctx.map.ref)
+		ctx->ref = pat_ref_lookup_ref(args[2]);
+		if (!ctx->ref)
 			return cli_err(appctx, "Unknown map identifier. Please use #<id> or <file>.\n");
 
 		/* If the entry identifier start with a '#', it is considered as
@@ -754,30 +782,30 @@
 
 			/* Try to modify the entry. */
 			err = NULL;
-			HA_SPIN_LOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
-			if (!pat_ref_set_by_id(appctx->ctx.map.ref, ref, args[4], &err)) {
-				HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
+			HA_SPIN_LOCK(PATREF_LOCK, &ctx->ref->lock);
+			if (!pat_ref_set_by_id(ctx->ref, ref, args[4], &err)) {
+				HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
 				if (err)
 					return cli_dynerr(appctx, memprintf(&err, "%s.\n", err));
 				else
 					return cli_err(appctx, "Failed to update an entry.\n");
 			}
-			HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
+			HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
 		}
 		else {
 			/* Else, use the entry identifier as pattern
 			 * string, and update the value.
 			 */
 			err = NULL;
-			HA_SPIN_LOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
-			if (!pat_ref_set(appctx->ctx.map.ref, args[3], args[4], &err)) {
-				HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
+			HA_SPIN_LOCK(PATREF_LOCK, &ctx->ref->lock);
+			if (!pat_ref_set(ctx->ref, args[3], args[4], &err)) {
+				HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
 				if (err)
 					return cli_dynerr(appctx, memprintf(&err, "%s.\n", err));
 				else
 					return cli_err(appctx, "Failed to update an entry.\n");
 			}
-			HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
+			HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
 		}
 
 		/* The set is done, send message. */
@@ -789,6 +817,8 @@
 
 static int cli_parse_add_map(char **args, char *payload, struct appctx *appctx, void *private)
 {
+	struct show_map_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
+
 	if (strcmp(args[1], "map") == 0 ||
 	    strcmp(args[1], "acl") == 0) {
 		const char *gen = NULL;
@@ -798,9 +828,9 @@
 
 		/* Set flags. */
 		if (args[1][0] == 'm')
-			appctx->ctx.map.display_flags = PAT_REF_MAP;
+			ctx->display_flags = PAT_REF_MAP;
 		else
-			appctx->ctx.map.display_flags = PAT_REF_ACL;
+			ctx->display_flags = PAT_REF_ACL;
 
 		/* For both "map" and "acl" we may have an optional generation
 		 * number specified using a "@" character before the pattern
@@ -816,7 +846,7 @@
 		 *   - 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 (ctx->display_flags == PAT_REF_MAP) {
 			if ((!payload && (!*args[2] || !*args[3] || !*args[4])) ||
 			    (payload && !*args[2]))
 				return cli_err(appctx,
@@ -827,9 +857,9 @@
 			return cli_err(appctx, "'add acl' expects two parameters: ACL identifier and pattern.\n");
 
 		/* Lookup for the reference. */
-		appctx->ctx.map.ref = pat_ref_lookup_ref(args[2]);
-		if (!appctx->ctx.map.ref) {
-			if (appctx->ctx.map.display_flags == PAT_REF_MAP)
+		ctx->ref = pat_ref_lookup_ref(args[2]);
+		if (!ctx->ref) {
+			if (ctx->display_flags == PAT_REF_MAP)
 				return cli_err(appctx, "Unknown map identifier. Please use #<id> or <file>.\n");
 			else
 				return cli_err(appctx, "Unknown ACL identifier. Please use #<id> or <file>.\n");
@@ -837,8 +867,8 @@
 
 		if (gen) {
 			genid = str2uic(gen);
-			if ((int)(genid - appctx->ctx.map.ref->next_gen) > 0) {
-				if (appctx->ctx.map.display_flags == PAT_REF_MAP)
+			if ((int)(genid - ctx->ref->next_gen) > 0) {
+				if (ctx->display_flags == PAT_REF_MAP)
 					return cli_err(appctx, "Version number in the future, please use 'prepare map' before.\n");
 				else
 					return cli_err(appctx, "Version number in the future, please use 'prepare acl' before.\n");
@@ -848,8 +878,8 @@
 		/* The command "add acl" is prohibited if the reference
 		 * use samples.
 		 */
-		if ((appctx->ctx.map.display_flags & PAT_REF_ACL) &&
-		    (appctx->ctx.map.ref->flags & PAT_REF_SMP)) {
+		if ((ctx->display_flags & PAT_REF_ACL) &&
+		    (ctx->ref->flags & PAT_REF_SMP)) {
 			return cli_err(appctx,
 				       "This ACL is shared with a map containing samples. "
 				       "You must use the command 'add map' to add values.\n");
@@ -876,7 +906,7 @@
 				l = strcspn(key, " \t");
 				payload += l;
 
-				if (!*payload && appctx->ctx.map.display_flags == PAT_REF_MAP)
+				if (!*payload && ctx->display_flags == PAT_REF_MAP)
 					return cli_dynerr(appctx, memprintf(&err, "Missing value for key '%s'.\n", key));
 
 				key[l] = 0;
@@ -892,12 +922,12 @@
 				value[l] = 0;
 			}
 
-			if (appctx->ctx.map.display_flags != PAT_REF_MAP)
+			if (ctx->display_flags != PAT_REF_MAP)
 				value = NULL;
 
-			HA_SPIN_LOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
-			ret = !!pat_ref_load(appctx->ctx.map.ref, gen ? genid : appctx->ctx.map.ref->curr_gen, key, value, -1, &err);
-			HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
+			HA_SPIN_LOCK(PATREF_LOCK, &ctx->ref->lock);
+			ret = !!pat_ref_load(ctx->ref, gen ? genid : ctx->ref->curr_gen, key, value, -1, &err);
+			HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
 
 			if (!ret) {
 				if (err)
@@ -917,23 +947,25 @@
 
 static int cli_parse_del_map(char **args, char *payload, struct appctx *appctx, void *private)
 {
+	struct show_map_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
+
 	if (args[1][0] == 'm')
-		appctx->ctx.map.display_flags = PAT_REF_MAP;
+		ctx->display_flags = PAT_REF_MAP;
 	else
-		appctx->ctx.map.display_flags = PAT_REF_ACL;
+		ctx->display_flags = PAT_REF_ACL;
 
 	/* Expect two parameters: map name and key. */
 	if (!*args[2] || !*args[3]) {
-		if (appctx->ctx.map.display_flags == PAT_REF_MAP)
+		if (ctx->display_flags == PAT_REF_MAP)
 			return cli_err(appctx, "This command expects two parameters: map identifier and key.\n");
 		else
 			return cli_err(appctx, "This command expects two parameters: ACL identifier and key.\n");
 	}
 
 	/* Lookup the reference in the maps. */
-	appctx->ctx.map.ref = pat_ref_lookup_ref(args[2]);
-	if (!appctx->ctx.map.ref ||
-	    !(appctx->ctx.map.ref->flags & appctx->ctx.map.display_flags))
+	ctx->ref = pat_ref_lookup_ref(args[2]);
+	if (!ctx->ref ||
+	    !(ctx->ref->flags & ctx->display_flags))
 		return cli_err(appctx, "Unknown map identifier. Please use #<id> or <file>.\n");
 
 	/* If the entry identifier start with a '#', it is considered as
@@ -955,25 +987,25 @@
 			return cli_err(appctx, "Malformed identifier. Please use #<id> or <file>.\n");
 
 		/* Try to delete the entry. */
-		HA_SPIN_LOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
-		if (!pat_ref_delete_by_id(appctx->ctx.map.ref, ref)) {
-			HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
+		HA_SPIN_LOCK(PATREF_LOCK, &ctx->ref->lock);
+		if (!pat_ref_delete_by_id(ctx->ref, ref)) {
+			HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
 			/* The entry is not found, send message. */
 			return cli_err(appctx, "Key not found.\n");
 		}
-		HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
+		HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
 	}
 	else {
 		/* Else, use the entry identifier as pattern
 		 * string and try to delete the entry.
 		 */
-		HA_SPIN_LOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
-		if (!pat_ref_delete(appctx->ctx.map.ref, args[3])) {
-			HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
+		HA_SPIN_LOCK(PATREF_LOCK, &ctx->ref->lock);
+		if (!pat_ref_delete(ctx->ref, args[3])) {
+			HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
 			/* The entry is not found, send message. */
 			return cli_err(appctx, "Key not found.\n");
 		}
-		HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
+		HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
 	}
 
 	/* The deletion is done, send message. */
@@ -987,11 +1019,12 @@
  */
 static int cli_io_handler_clear_map(struct appctx *appctx)
 {
+	struct show_map_ctx *ctx = appctx->svcctx;
 	int finished;
 
-	HA_SPIN_LOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
-	finished = pat_ref_purge_range(appctx->ctx.map.ref, appctx->ctx.cli.i0, appctx->ctx.cli.i1, 100);
-	HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
+	HA_SPIN_LOCK(PATREF_LOCK, &ctx->ref->lock);
+	finished = pat_ref_purge_range(ctx->ref, appctx->ctx.cli.i0, appctx->ctx.cli.i1, 100);
+	HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
 
 	if (!finished) {
 		/* let's come back later */
@@ -1007,14 +1040,16 @@
  */
 static int cli_parse_clear_map(char **args, char *payload, struct appctx *appctx, void *private)
 {
+	struct show_map_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
+
 	if (strcmp(args[1], "map") == 0 || strcmp(args[1], "acl") == 0) {
 		const char *gen = NULL;
 
 		/* Set ACL or MAP flags. */
 		if (args[1][0] == 'm')
-			appctx->ctx.map.display_flags = PAT_REF_MAP;
+			ctx->display_flags = PAT_REF_MAP;
 		else
-			appctx->ctx.map.display_flags = PAT_REF_ACL;
+			ctx->display_flags = PAT_REF_ACL;
 
 		/* For both "map" and "acl" we may have an optional generation
 		 * number specified using a "@" character before the pattern
@@ -1027,17 +1062,17 @@
 
 		/* no parameter */
 		if (!*args[2]) {
-			if (appctx->ctx.map.display_flags == PAT_REF_MAP)
+			if (ctx->display_flags == PAT_REF_MAP)
 				return cli_err(appctx, "Missing map identifier.\n");
 			else
 				return cli_err(appctx, "Missing ACL identifier.\n");
 		}
 
 		/* lookup into the refs and check the map flag */
-		appctx->ctx.map.ref = pat_ref_lookup_ref(args[2]);
-		if (!appctx->ctx.map.ref ||
-		    !(appctx->ctx.map.ref->flags & appctx->ctx.map.display_flags)) {
-			if (appctx->ctx.map.display_flags == PAT_REF_MAP)
+		ctx->ref = pat_ref_lookup_ref(args[2]);
+		if (!ctx->ref ||
+		    !(ctx->ref->flags & ctx->display_flags)) {
+			if (ctx->display_flags == PAT_REF_MAP)
 				return cli_err(appctx, "Unknown map identifier. Please use #<id> or <file>.\n");
 			else
 				return cli_err(appctx, "Unknown ACL identifier. Please use #<id> or <file>.\n");
@@ -1047,7 +1082,7 @@
 		if (gen)
 			appctx->ctx.cli.i1 = appctx->ctx.cli.i0 = str2uic(gen);
 		else
-			appctx->ctx.cli.i1 = appctx->ctx.cli.i0 = appctx->ctx.map.ref->curr_gen;
+			appctx->ctx.cli.i1 = appctx->ctx.cli.i0 = ctx->ref->curr_gen;
 
 		/* delegate the clearing to the I/O handler which can yield */
 		return 0;
@@ -1061,6 +1096,8 @@
  */
 static int cli_parse_commit_map(char **args, char *payload, struct appctx *appctx, void *private)
 {
+	struct show_map_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
+
 	if (strcmp(args[1], "map") == 0 || strcmp(args[1], "acl") == 0) {
 		const char *gen = NULL;
 		uint genid;
@@ -1068,9 +1105,9 @@
 
 		/* Set ACL or MAP flags. */
 		if (args[1][0] == 'm')
-			appctx->ctx.map.display_flags = PAT_REF_MAP;
+			ctx->display_flags = PAT_REF_MAP;
 		else
-			appctx->ctx.map.display_flags = PAT_REF_ACL;
+			ctx->display_flags = PAT_REF_ACL;
 
 		if (*args[2] != '@')
 			return cli_err(appctx, "Missing version number.\n");
@@ -1086,29 +1123,29 @@
 
 		/* no parameter */
 		if (!*args[3]) {
-			if (appctx->ctx.map.display_flags == PAT_REF_MAP)
+			if (ctx->display_flags == PAT_REF_MAP)
 				return cli_err(appctx, "Missing map identifier.\n");
 			else
 				return cli_err(appctx, "Missing ACL identifier.\n");
 		}
 
 		/* lookup into the refs and check the map flag */
-		appctx->ctx.map.ref = pat_ref_lookup_ref(args[3]);
-		if (!appctx->ctx.map.ref ||
-		    !(appctx->ctx.map.ref->flags & appctx->ctx.map.display_flags)) {
-			if (appctx->ctx.map.display_flags == PAT_REF_MAP)
+		ctx->ref = pat_ref_lookup_ref(args[3]);
+		if (!ctx->ref ||
+		    !(ctx->ref->flags & ctx->display_flags)) {
+			if (ctx->display_flags == PAT_REF_MAP)
 				return cli_err(appctx, "Unknown map identifier. Please use #<id> or <file>.\n");
 			else
 				return cli_err(appctx, "Unknown ACL identifier. Please use #<id> or <file>.\n");
 		}
 
-		HA_SPIN_LOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
-		if (genid - (appctx->ctx.map.ref->curr_gen + 1) <
-		    appctx->ctx.map.ref->next_gen - appctx->ctx.map.ref->curr_gen)
-			ret = pat_ref_commit(appctx->ctx.map.ref, genid);
+		HA_SPIN_LOCK(PATREF_LOCK, &ctx->ref->lock);
+		if (genid - (ctx->ref->curr_gen + 1) <
+		    ctx->ref->next_gen - ctx->ref->curr_gen)
+			ret = pat_ref_commit(ctx->ref, genid);
 		else
 			ret = 1;
-		HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
+		HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
 
 		if (ret != 0)
 			return cli_err(appctx, "Version number out of range.\n");