[MINOR] stats: use a dedicated state to output static data

It is a bit expensive and complex to use to call buffer_feed()
directly from the request parser, and there are risks that some
output messages are lost in case of buffer full. Since most of
these messages are static, let's have a state dedicated to print
these messages and store them in a specific area shared with the
stats in the session. This both reduces code size and risks of
losing output data.
diff --git a/include/proto/dumpstats.h b/include/proto/dumpstats.h
index ea579f5..0fe2bbe 100644
--- a/include/proto/dumpstats.h
+++ b/include/proto/dumpstats.h
@@ -46,8 +46,8 @@
 #define STAT_CLI_GETREQ 2   /* wait for a request */
 #define STAT_CLI_OUTPUT 3   /* all states after this one are responses */
 #define STAT_CLI_PROMPT 3   /* display the prompt (first output, same code) */
+#define STAT_CLI_PRINT  4   /* display message in cli->msg */
 
-#define STAT_CLI_O_HELP 4   /* display help */
 #define STAT_CLI_O_INFO 5   /* dump info/stats */
 #define STAT_CLI_O_SESS 6   /* dump sessions */
 #define STAT_CLI_O_ERR  7   /* dump errors */
diff --git a/include/types/session.h b/include/types/session.h
index 356f0ca..a8734ff 100644
--- a/include/types/session.h
+++ b/include/types/session.h
@@ -212,6 +212,9 @@
 			int ptr;		/* <0: headers, >=0 : text pointer to restart from */
 			int bol;		/* pointer to beginning of current line */
 		} errors;
+		struct {
+			const char *msg;	/* pointer to a persistent message to be returned in PRINT state */
+		} cli;
 	} data_ctx;				/* used by stats I/O handlers to dump the stats */
 	unsigned int uniq_id;			/* unique ID used for the traces */
 };
diff --git a/src/dumpstats.c b/src/dumpstats.c
index 510d0d2..6d42b41 100644
--- a/src/dumpstats.c
+++ b/src/dumpstats.c
@@ -250,7 +250,8 @@
 /* Processes the stats interpreter on the statistics socket. This function is
  * called from an applet running in a stream interface. The function returns 1
  * if the request was understood, otherwise zero. It sets si->st0 to a value
- * designating the function which will have to process the request.
+ * designating the function which will have to process the request, which can
+ * also be the print function to display the return message set into cli.msg.
  */
 int stats_sock_parse_request(struct stream_interface *si, char *line)
 {
@@ -305,14 +306,16 @@
 		else if (strcmp(args[1], "sess") == 0) {
 			s->data_state = DATA_ST_INIT;
 			if (s->listener->perm.ux.level < ACCESS_LVL_OPER) {
-				buffer_feed(si->ib, stats_permission_denied_msg);
+				s->data_ctx.cli.msg = stats_permission_denied_msg;
+				si->st0 = STAT_CLI_PRINT;
 				return 1;
 			}
 			si->st0 = STAT_CLI_O_SESS; // stats_dump_sess_to_buffer
 		}
 		else if (strcmp(args[1], "errors") == 0) {
 			if (s->listener->perm.ux.level < ACCESS_LVL_OPER) {
-				buffer_feed(si->ib, stats_permission_denied_msg);
+				s->data_ctx.cli.msg = stats_permission_denied_msg;
+				si->st0 = STAT_CLI_PRINT;
 				return 1;
 			}
 			if (*args[2])
@@ -340,7 +343,8 @@
 			/* check permissions */
 			if (s->listener->perm.ux.level < ACCESS_LVL_OPER ||
 			    (clrall && s->listener->perm.ux.level < ACCESS_LVL_ADMIN)) {
-				buffer_feed(si->ib, stats_permission_denied_msg);
+				s->data_ctx.cli.msg = stats_permission_denied_msg;
+				si->st0 = STAT_CLI_PRINT;
 				return 1;
 			}
 
@@ -392,15 +396,14 @@
 				}
 
 			if (!*line) {
-				buffer_feed(si->ib, "Require 'backend/server'.\n");
+				s->data_ctx.cli.msg = "Require 'backend/server'.\n";
+				si->st0 = STAT_CLI_PRINT;
 				return 1;
 			}
 
 			if (!get_backend_server(args[2], line, &px, &sv)) {
-				if (!px)
-					buffer_feed(si->ib, "No such backend.\n");
-				else
-					buffer_feed(si->ib, "No such server.\n");
+				s->data_ctx.cli.msg = px ? "No such server.\n" : "No such backend.\n";
+				si->st0 = STAT_CLI_PRINT;
 				return 1;
 			}
 
@@ -420,7 +423,8 @@
 			int w;
 
 			if (s->listener->perm.ux.level < ACCESS_LVL_ADMIN) {
-				buffer_feed(si->ib, stats_permission_denied_msg);
+				s->data_ctx.cli.msg = stats_permission_denied_msg;
+				si->st0 = STAT_CLI_PRINT;
 				return 1;
 			}
 
@@ -432,15 +436,14 @@
 				}
 
 			if (!*line || !*args[3]) {
-				buffer_feed(si->ib, "Require 'backend/server' and 'weight' or 'weight%'.\n");
+				s->data_ctx.cli.msg = "Require 'backend/server' and 'weight' or 'weight%'.\n";
+				si->st0 = STAT_CLI_PRINT;
 				return 1;
 			}
 
 			if (!get_backend_server(args[2], line, &px, &sv)) {
-				if (!px)
-					buffer_feed(si->ib, "No such backend.\n");
-				else
-					buffer_feed(si->ib, "No such server.\n");
+				s->data_ctx.cli.msg = px ? "No such server.\n" : "No such backend.\n";
+				si->st0 = STAT_CLI_PRINT;
 				return 1;
 			}
 
@@ -450,20 +453,23 @@
 			w = atoi(args[3]);
 			if (strchr(args[3], '%') != NULL) {
 				if (w < 0 || w > 100) {
-					buffer_feed(si->ib, "Relative weight can only be set between 0 and 100% inclusive.\n");
+					s->data_ctx.cli.msg = "Relative weight can only be set between 0 and 100% inclusive.\n";
+					si->st0 = STAT_CLI_PRINT;
 					return 1;
 				}
 				w = sv->iweight * w / 100;
 			}
 			else {
 				if (w < 0 || w > 256) {
-					buffer_feed(si->ib, "Absolute weight can only be between 0 and 256 inclusive.\n");
+					s->data_ctx.cli.msg = "Absolute weight can only be between 0 and 256 inclusive.\n";
+					si->st0 = STAT_CLI_PRINT;
 					return 1;
 				}
 			}
 
 			if (w && w != sv->iweight && !(px->lbprm.algo & BE_LB_PROP_DYN)) {
-				buffer_feed(si->ib, "Backend is using a static LB algorithm and only accepts weights '0%' and '100%'.\n");
+				s->data_ctx.cli.msg = "Backend is using a static LB algorithm and only accepts weights '0%' and '100%'.\n";
+				si->st0 = STAT_CLI_PRINT;
 				return 1;
 			}
 
@@ -576,8 +582,10 @@
 				else if (strcmp(trash, "prompt") == 0)
 					si->st1 = !si->st1;
 				else if (strcmp(trash, "help") == 0 ||
-					 !stats_sock_parse_request(si, trash))
-					si->st0 = STAT_CLI_O_HELP;
+					 !stats_sock_parse_request(si, trash)) {
+					s->data_ctx.cli.msg = stats_sock_usage_msg;
+					si->st0 = STAT_CLI_PRINT;
+				}
 				/* NB: stats_sock_parse_request() may have put
 				 * another STAT_CLI_O_* into si->st0.
 				 */
@@ -587,7 +595,8 @@
 				 * so that the user at least knows how to enable
 				 * prompt and find help.
 				 */
-				si->st0 = STAT_CLI_O_HELP;
+				s->data_ctx.cli.msg = stats_sock_usage_msg;
+				si->st0 = STAT_CLI_PRINT;
 			}
 
 			/* re-adjust req buffer */
@@ -601,8 +610,8 @@
 			}
 
 			switch (si->st0) {
-			case STAT_CLI_O_HELP:
-				if (buffer_feed(si->ib, stats_sock_usage_msg) < 0)
+			case STAT_CLI_PRINT:
+				if (buffer_feed(si->ib, s->data_ctx.cli.msg) < 0)
 					si->st0 = STAT_CLI_PROMPT;
 				break;
 			case STAT_CLI_O_INFO: