MINOR: config: Extract the code of "stick-table" line parsing.

With this patch we move the code responsible of parsing "stick-table"
lines to implement parse_stick_table() function in src/stick-tabble.c
so that to be able to parse "stick-table" elsewhere than in proxy sections.
We have have also added a conf struct to stktable struct to store the filename
and the line in the file the stick-table has been parsed to help in
diagnosing and displaying any configuration issue.
diff --git a/include/proto/stick_table.h b/include/proto/stick_table.h
index 40bb8ca..962c95a 100644
--- a/include/proto/stick_table.h
+++ b/include/proto/stick_table.h
@@ -38,6 +38,8 @@
 
 int stktable_init(struct stktable *t);
 int stktable_parse_type(char **args, int *idx, unsigned long *type, size_t *key_size);
+int parse_stick_table(const char *file, int linenum, char **args,
+                      struct stktable *t, char *id, struct peers *peers);
 struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key);
 struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts);
 void stktable_touch_with_exp(struct stktable *t, struct stksess *ts, int decrefcount, int expire);
diff --git a/include/types/stick_table.h b/include/types/stick_table.h
index 28e255f..695a75c 100644
--- a/include/types/stick_table.h
+++ b/include/types/stick_table.h
@@ -144,6 +144,13 @@
 /* stick table */
 struct stktable {
 	char *id;		  /* table id name */
+	struct stktable *next;    /* The stick-table may be linked when belonging to
+	                           * the same configuration section.
+	                           */
+	struct {
+		const char *file;     /* The file where the stick-table is declared. */
+		int line;             /* The line in this <file> the stick-table is declared. */
+	} conf;
 	struct eb_root keys;      /* head of sticky session tree */
 	struct eb_root exps;      /* head of sticky session expiration tree */
 	struct eb_root updates;   /* head of sticky updates sequence tree */
@@ -175,6 +182,7 @@
 		unsigned int u;
 		void *p;
 	} data_arg[STKTABLE_DATA_TYPES]; /* optional argument of each data type */
+	struct proxy *proxy;      /* The proxy this stick-table is attached to, if any.*/
 };
 
 extern struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES];
diff --git a/src/cfgparse-listen.c b/src/cfgparse-listen.c
index e7cd066..c0f4a46 100644
--- a/src/cfgparse-listen.c
+++ b/src/cfgparse-listen.c
@@ -25,6 +25,7 @@
 #include <proto/protocol.h>
 #include <proto/proxy.h>
 #include <proto/server.h>
+#include <proto/stick_table.h>
 
 /* Report a warning if a rule is placed after a 'tcp-request session' rule.
  * Return 1 if the warning has been emitted, otherwise 0.
@@ -1710,7 +1711,6 @@
 		LIST_ADDQ(&curproxy->persist_rules, &rule->list);
 	}
 	else if (!strcmp(args[0], "stick-table")) {
-		int myidx = 1;
 		struct proxy *other;
 
 		if (curproxy == &defproxy) {
@@ -1728,163 +1728,12 @@
 			goto out;
 		}
 
-		curproxy->table.id =  curproxy->id;
-		curproxy->table.type = (unsigned int)-1;
-		while (*args[myidx]) {
-			const char *err;
-
-			if (strcmp(args[myidx], "size") == 0) {
-				myidx++;
-				if (!*(args[myidx])) {
-					ha_alert("parsing [%s:%d] : stick-table: missing argument after '%s'.\n",
-						 file, linenum, args[myidx-1]);
-					err_code |= ERR_ALERT | ERR_FATAL;
-					goto out;
-				}
-				if ((err = parse_size_err(args[myidx], &curproxy->table.size))) {
-					ha_alert("parsing [%s:%d] : stick-table: unexpected character '%c' in argument of '%s'.\n",
-						 file, linenum, *err, args[myidx-1]);
-					err_code |= ERR_ALERT | ERR_FATAL;
-					goto out;
-				}
-				myidx++;
-			}
-			else if (strcmp(args[myidx], "peers") == 0) {
-				myidx++;
-				if (!*(args[myidx])) {
-					ha_alert("parsing [%s:%d] : stick-table: missing argument after '%s'.\n",
-						 file, linenum, args[myidx-1]);
-					err_code |= ERR_ALERT | ERR_FATAL;
-					goto out;
-				}
-				curproxy->table.peers.name = strdup(args[myidx++]);
-			}
-			else if (strcmp(args[myidx], "expire") == 0) {
-				myidx++;
-				if (!*(args[myidx])) {
-					ha_alert("parsing [%s:%d] : stick-table: missing argument after '%s'.\n",
-						 file, linenum, args[myidx-1]);
-					err_code |= ERR_ALERT | ERR_FATAL;
-					goto out;
-				}
-				err = parse_time_err(args[myidx], &val, TIME_UNIT_MS);
-				if (err) {
-					ha_alert("parsing [%s:%d] : stick-table: unexpected character '%c' in argument of '%s'.\n",
-						 file, linenum, *err, args[myidx-1]);
-					err_code |= ERR_ALERT | ERR_FATAL;
-					goto out;
-				}
-				if (val > INT_MAX) {
-					ha_alert("parsing [%s:%d] : Expire value [%u]ms exceeds maxmimum value of 24.85 days.\n",
-						 file, linenum, val);
-					err_code |= ERR_ALERT | ERR_FATAL;
-					goto out;
-				}
-				curproxy->table.expire = val;
-				myidx++;
-			}
-			else if (strcmp(args[myidx], "nopurge") == 0) {
-				curproxy->table.nopurge = 1;
-				myidx++;
-			}
-			else if (strcmp(args[myidx], "type") == 0) {
-				myidx++;
-				if (stktable_parse_type(args, &myidx, &curproxy->table.type, &curproxy->table.key_size) != 0) {
-					ha_alert("parsing [%s:%d] : stick-table: unknown type '%s'.\n",
-						 file, linenum, args[myidx]);
-					err_code |= ERR_ALERT | ERR_FATAL;
-					goto out;
-				}
-				/* myidx already points to next arg */
-			}
-			else if (strcmp(args[myidx], "store") == 0) {
-				int type, err;
-				char *cw, *nw, *sa;
-
-				myidx++;
-				nw = args[myidx];
-				while (*nw) {
-					/* the "store" keyword supports a comma-separated list */
-					cw = nw;
-					sa = NULL; /* store arg */
-					while (*nw && *nw != ',') {
-						if (*nw == '(') {
-							*nw = 0;
-							sa = ++nw;
-							while (*nw != ')') {
-								if (!*nw) {
-									ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
-										 file, linenum, args[0], cw);
-									err_code |= ERR_ALERT | ERR_FATAL;
-									goto out;
-								}
-								nw++;
-							}
-							*nw = '\0';
-						}
-						nw++;
-					}
-					if (*nw)
-						*nw++ = '\0';
-					type = stktable_get_data_type(cw);
-					if (type < 0) {
-						ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
-							 file, linenum, args[0], cw);
-						err_code |= ERR_ALERT | ERR_FATAL;
-						goto out;
-					}
-
-					err = stktable_alloc_data_type(&curproxy->table, type, sa);
-					switch (err) {
-					case PE_NONE: break;
-					case PE_EXIST:
-						ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
-							   file, linenum, args[0], cw);
-						err_code |= ERR_WARN;
-						break;
-
-					case PE_ARG_MISSING:
-						ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
-							 file, linenum, args[0], cw);
-						err_code |= ERR_ALERT | ERR_FATAL;
-						goto out;
-
-					case PE_ARG_NOT_USED:
-						ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
-							 file, linenum, args[0], cw);
-						err_code |= ERR_ALERT | ERR_FATAL;
-						goto out;
-
-					default:
-						ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
-							 file, linenum, args[0], cw);
-						err_code |= ERR_ALERT | ERR_FATAL;
-						goto out;
-					}
-				}
-				myidx++;
-			}
-			else {
-				ha_alert("parsing [%s:%d] : stick-table: unknown argument '%s'.\n",
-					 file, linenum, args[myidx]);
-				err_code |= ERR_ALERT | ERR_FATAL;
-				goto out;
-			}
-		}
-
-		if (!curproxy->table.size) {
-			ha_alert("parsing [%s:%d] : stick-table: missing size.\n",
-				 file, linenum);
-			err_code |= ERR_ALERT | ERR_FATAL;
+		err_code |= parse_stick_table(file, linenum, args, &curproxy->table, curproxy->id, NULL);
+		if (err_code & ERR_FATAL)
 			goto out;
-		}
 
-		if (curproxy->table.type == (unsigned int)-1) {
-			ha_alert("parsing [%s:%d] : stick-table: missing type.\n",
-				 file, linenum);
-			err_code |= ERR_ALERT | ERR_FATAL;
-			goto out;
-		}
+		/* Store the proxy in the stick-table. */
+		curproxy->table->proxy = curproxy;
 	}
 	else if (!strcmp(args[0], "stick")) {
 		struct sticking_rule *rule;
diff --git a/src/stick_table.c b/src/stick_table.c
index e24ef65..d8053dc 100644
--- a/src/stick_table.c
+++ b/src/stick_table.c
@@ -15,6 +15,7 @@
 #include <errno.h>
 
 #include <common/config.h>
+#include <common/cfgparse.h>
 #include <common/initcall.h>
 #include <common/memory.h>
 #include <common/mini-clist.h>
@@ -664,6 +665,197 @@
 	return 1;
 }
 
+/*
+ * Parse a line with <linenum> as number in <file> configuration file to configure the
+ * stick-table with <t> as address and  <id> as ID.
+ * <peers> provides the "peers" section pointer only if this function is called from a "peers" section.
+ * Return an error status with ERR_* flags set if required, 0 if no error was encountered.
+ */
+int parse_stick_table(const char *file, int linenum, char **args,
+                      struct stktable *t, char *id, struct peers *peers)
+{
+	int err_code = 0;
+	int idx = 1;
+	unsigned int val;
+
+	if (!id || !*id) {
+		ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]);
+		err_code |= ERR_ALERT | ERR_ABORT;
+		goto out;
+	}
+
+	/* Store the "peers" section if this function is called from a "peers" section. */
+	if (peers) {
+		t->peers.p = peers;
+		idx++;
+	}
+
+	t->id =  id;
+	t->type = (unsigned int)-1;
+	t->conf.file = file;
+	t->conf.line = linenum;
+
+	while (*args[idx]) {
+		const char *err;
+
+		if (strcmp(args[idx], "size") == 0) {
+			idx++;
+			if (!*(args[idx])) {
+				ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
+					 file, linenum, args[0], args[idx-1]);
+				err_code |= ERR_ALERT | ERR_FATAL;
+				goto out;
+			}
+			if ((err = parse_size_err(args[idx], &t->size))) {
+				ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
+					 file, linenum, args[0], *err, args[idx-1]);
+				err_code |= ERR_ALERT | ERR_FATAL;
+				goto out;
+			}
+			idx++;
+		}
+		/* This argument does not exit in "peers" section. */
+		else if (!peers && strcmp(args[idx], "peers") == 0) {
+			idx++;
+			if (!*(args[idx])) {
+				ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
+					 file, linenum, args[0], args[idx-1]);
+				err_code |= ERR_ALERT | ERR_FATAL;
+				goto out;
+			}
+			t->peers.name = strdup(args[idx++]);
+		}
+		else if (strcmp(args[idx], "expire") == 0) {
+			idx++;
+			if (!*(args[idx])) {
+				ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
+					 file, linenum, args[0], args[idx-1]);
+				err_code |= ERR_ALERT | ERR_FATAL;
+				goto out;
+			}
+			err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
+			if (err) {
+				ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
+					 file, linenum, args[0], *err, args[idx-1]);
+				err_code |= ERR_ALERT | ERR_FATAL;
+				goto out;
+			}
+			if (val > INT_MAX) {
+				ha_alert("parsing [%s:%d] : Expire value [%u]ms exceeds maxmimum value of 24.85 days.\n",
+					 file, linenum, val);
+				err_code |= ERR_ALERT | ERR_FATAL;
+				goto out;
+			}
+			t->expire = val;
+			idx++;
+		}
+		else if (strcmp(args[idx], "nopurge") == 0) {
+			t->nopurge = 1;
+			idx++;
+		}
+		else if (strcmp(args[idx], "type") == 0) {
+			idx++;
+			if (stktable_parse_type(args, &idx, &t->type, &t->key_size) != 0) {
+				ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n",
+					 file, linenum, args[0], args[idx]);
+				err_code |= ERR_ALERT | ERR_FATAL;
+				goto out;
+			}
+			/* idx already points to next arg */
+		}
+		else if (strcmp(args[idx], "store") == 0) {
+			int type, err;
+			char *cw, *nw, *sa;
+
+			idx++;
+			nw = args[idx];
+			while (*nw) {
+				/* the "store" keyword supports a comma-separated list */
+				cw = nw;
+				sa = NULL; /* store arg */
+				while (*nw && *nw != ',') {
+					if (*nw == '(') {
+						*nw = 0;
+						sa = ++nw;
+						while (*nw != ')') {
+							if (!*nw) {
+								ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
+									 file, linenum, args[0], cw);
+								err_code |= ERR_ALERT | ERR_FATAL;
+								goto out;
+							}
+							nw++;
+						}
+						*nw = '\0';
+					}
+					nw++;
+				}
+				if (*nw)
+					*nw++ = '\0';
+				type = stktable_get_data_type(cw);
+				if (type < 0) {
+					ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
+						 file, linenum, args[0], cw);
+					err_code |= ERR_ALERT | ERR_FATAL;
+					goto out;
+				}
+
+				err = stktable_alloc_data_type(t, type, sa);
+				switch (err) {
+				case PE_NONE: break;
+				case PE_EXIST:
+					ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
+						   file, linenum, args[0], cw);
+					err_code |= ERR_WARN;
+					break;
+
+				case PE_ARG_MISSING:
+					ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
+						 file, linenum, args[0], cw);
+					err_code |= ERR_ALERT | ERR_FATAL;
+					goto out;
+
+				case PE_ARG_NOT_USED:
+					ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
+						 file, linenum, args[0], cw);
+					err_code |= ERR_ALERT | ERR_FATAL;
+					goto out;
+
+				default:
+					ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
+						 file, linenum, args[0], cw);
+					err_code |= ERR_ALERT | ERR_FATAL;
+					goto out;
+				}
+			}
+			idx++;
+		}
+		else {
+			ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
+				 file, linenum, args[0], args[idx]);
+			err_code |= ERR_ALERT | ERR_FATAL;
+			goto out;
+		}
+	}
+
+	if (!t->size) {
+		ha_alert("parsing [%s:%d] : %s: missing size.\n",
+			 file, linenum, args[0]);
+		err_code |= ERR_ALERT | ERR_FATAL;
+		goto out;
+	}
+
+	if (t->type == (unsigned int)-1) {
+		ha_alert("parsing [%s:%d] : %s: missing type.\n",
+			 file, linenum, args[0]);
+		err_code |= ERR_ALERT | ERR_FATAL;
+		goto out;
+	}
+
+ out:
+	return err_code;
+}
+
 /* Prepares a stktable_key from a sample <smp> to search into table <t>.
  * Note that the sample *is* modified and that the returned key may point
  * to it, so the sample must not be modified afterwards before the lookup.