MINOR: pattern: Each pattern is identified by unique id.

The pattern reference are stored with two identifiers: the unique_id and
the reference.

The reference identify a file. Each file with the same name point to the
same reference. We can register many times one file. If the file is
modified, all his dependencies are also modified. The reference can be
used with map or acl.

The unique_id identify inline acl. The unique id is unique for each acl.
You cannot force the same id in the configuration file, because this
repport an error.

The format of the acl and map listing through the "socket" has changed
for displaying these new ids.
diff --git a/include/proto/pattern.h b/include/proto/pattern.h
index 9b7c40e..830630b 100644
--- a/include/proto/pattern.h
+++ b/include/proto/pattern.h
@@ -40,7 +40,7 @@
  * The function returns 1 if the processing is ok, return 0
  * if the parser fails, with <err> message filled.
  */
-int pattern_register(struct pattern_head *head, char *reference, int refflags, const char *arg, struct sample_storage *smp, int patflags, char **err);
+int pattern_register(struct pattern_head *head, int unique_id, int refflags, const char *arg, struct sample_storage *smp, int patflags, char **err);
 void pattern_finalize_config(void);
 
 /* return the PAT_MATCH_* index for match name "name", or < 0 if not found */
@@ -197,7 +197,9 @@
  * pattern_ref manipulation.
  */
 struct pat_ref *pat_ref_lookup(const char *reference);
+struct pat_ref *pat_ref_lookupid(int unique_id);
 struct pat_ref *pat_ref_new(const char *reference, unsigned int flags);
+struct pat_ref *pat_ref_newid(int unique_id, unsigned int flags);
 int pat_ref_append(struct pat_ref *ref, char *pattern, char *sample, int line);
 int pat_ref_add(struct pat_ref *ref, const char *pattern, const char *sample, char **err);
 int pat_ref_set(struct pat_ref *ref, const char *pattern, const char *sample);
diff --git a/include/types/pattern.h b/include/types/pattern.h
index dfee109..156e57b 100644
--- a/include/types/pattern.h
+++ b/include/types/pattern.h
@@ -97,6 +97,7 @@
 	struct list list; /* Used to chain refs. */
 	unsigned int flags; /* flags PAT_REF_*. */
 	char *reference; /* The reference name. */
+	int unique_id; /* Each pattern reference have unique id. */
 	struct list head; /* The head of the list of struct pat_ref_elt. */
 	struct list pat; /* The head of the list of struct pattern_expr. */
 };
diff --git a/src/acl.c b/src/acl.c
index d4d1cfb..4e33213 100644
--- a/src/acl.c
+++ b/src/acl.c
@@ -598,7 +598,7 @@
 			}
 		}
 
-		if (!pattern_register(&expr->pat, NULL, PAT_REF_ACL, arg, NULL, patflags, err))
+		if (!pattern_register(&expr->pat, -1, PAT_REF_ACL, arg, NULL, patflags, err))
 			goto out_free_expr;
 		args++;
 	}
diff --git a/src/dumpstats.c b/src/dumpstats.c
index 57a9fc5..f6768c9 100644
--- a/src/dumpstats.c
+++ b/src/dumpstats.c
@@ -982,6 +982,27 @@
 	}
 }
 
+static inline
+struct pat_ref *pat_ref_lookup_ref(const char *reference)
+{
+	int id;
+	char *error;
+
+	/* If the reference starts by a '#', this is numeric id. */
+	if (reference[0] == '#') {
+		/* Try to convert the numeric id. If the conversion fails, the lookup fails. */
+		id = strtol(reference + 1, &error, 10);
+		if (*error != '\0')
+			return NULL;
+
+		/* Perform the unique id lookup. */
+		return pat_ref_lookupid(id);
+	}
+
+	/* Perform the string lookup. */
+	return pat_ref_lookup(reference);
+}
+
 /* This function is used with map and acl management. It permits to browse
  * each reference.
  */
@@ -1123,13 +1144,13 @@
 			}
 
 			/* lookup into the refs and check the map flag */
-			appctx->ctx.map.ref = pat_ref_lookup(args[2]);
+			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)
-					appctx->ctx.cli.msg = "Unknown map identifier. Please use <name>.\n";
+					appctx->ctx.cli.msg = "Unknown map identifier. Please use #<id> or <name>.\n";
 				else
-					appctx->ctx.cli.msg = "Unknown ACL identifier. Please use <name>.\n";
+					appctx->ctx.cli.msg = "Unknown ACL identifier. Please use #<id> or <name>.\n";
 				appctx->st0 = STAT_CLI_PRINT;
 				return 1;
 			}
@@ -1222,13 +1243,13 @@
 			}
 
 			/* lookup into the refs and check the map flag */
-			appctx->ctx.map.ref = pat_ref_lookup(args[2]);
+			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)
-					appctx->ctx.cli.msg = "Unknown map identifier. Please use <name>.\n";
+					appctx->ctx.cli.msg = "Unknown map identifier. Please use #<id> or <name>.\n";
 				else
-					appctx->ctx.cli.msg = "Unknown ACL identifier. Please use <name>.\n";
+					appctx->ctx.cli.msg = "Unknown ACL identifier. Please use #<id> or <name>.\n";
 				appctx->st0 = STAT_CLI_PRINT;
 				return 1;
 			}
@@ -1293,12 +1314,12 @@
 			}
 
 			/* lookup into the maps */
-			appctx->ctx.map.ref = pat_ref_lookup(args[2]);
+			appctx->ctx.map.ref = pat_ref_lookup_ref(args[2]);
 			if (!appctx->ctx.map.ref) {
 				if (appctx->ctx.map.display_flags == PAT_REF_MAP)
-					appctx->ctx.cli.msg = "Unknown map identifier. Please use <name>.\n";
+					appctx->ctx.cli.msg = "Unknown map identifier. Please use #<id> or <name>.\n";
 				else
-					appctx->ctx.cli.msg = "Unknown ACL identifier. Please use <name>.\n";
+					appctx->ctx.cli.msg = "Unknown ACL identifier. Please use #<id> or <name>.\n";
 				appctx->st0 = STAT_CLI_PRINT;
 				return 1;
 			}
@@ -1605,9 +1626,9 @@
 			}
 
 			/* Lookup the reference in the maps. */
-			appctx->ctx.map.ref = pat_ref_lookup(args[2]);
+			appctx->ctx.map.ref = pat_ref_lookup_ref(args[2]);
 			if (!appctx->ctx.map.ref) {
-				appctx->ctx.cli.msg = "Unknown map identifier. Please use <name>.\n";
+				appctx->ctx.cli.msg = "Unknown map identifier. Please use #<id> or <name>.\n";
 				appctx->st0 = STAT_CLI_PRINT;
 				return 1;
 			}
@@ -1872,10 +1893,10 @@
 			}
 
 			/* Lookup the reference in the maps. */
-			appctx->ctx.map.ref = pat_ref_lookup(args[2]);
+			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)) {
-				appctx->ctx.cli.msg = "Unknown map identifier. Please use <name>.\n";
+				appctx->ctx.cli.msg = "Unknown map identifier. Please use #<id> or <name>.\n";
 				appctx->st0 = STAT_CLI_PRINT;
 				return 1;
 			}
@@ -1929,12 +1950,12 @@
 			}
 
 			/* Lookup for the reference. */
-			appctx->ctx.map.ref = pat_ref_lookup(args[2]);
+			appctx->ctx.map.ref = pat_ref_lookup_ref(args[2]);
 			if (!appctx->ctx.map.ref) {
 				if (appctx->ctx.map.display_flags == PAT_REF_MAP)
-					appctx->ctx.cli.msg = "Unknown map identifier. Please use <name>.\n";
+					appctx->ctx.cli.msg = "Unknown map identifier. Please use #<id> or <name>.\n";
 				else
-					appctx->ctx.cli.msg = "Unknown ACL identifier. Please use <name>.\n";
+					appctx->ctx.cli.msg = "Unknown ACL identifier. Please use #<id> or <name>.\n";
 				appctx->st0 = STAT_CLI_PRINT;
 				return 1;
 			}
@@ -4736,6 +4757,14 @@
 
 	switch (appctx->st2) {
 	case STAT_ST_INIT:
+		/* Display the column headers. If the message cannot be sent,
+		 * quit the fucntion with returning 0. The function is called
+		 * later and restart at the state "STAT_ST_INIT".
+		 */
+		chunk_reset(&trash);
+		chunk_appendf(&trash, "# id (name)\n");
+		if (bi_putchk(si->ib, &trash) == -1)
+			return 0;
 
 		/* Now, we start the browsing of the references lists.
 		 * Note that the following call to LIST_ELEM return bad pointer. The only
@@ -4750,24 +4779,23 @@
 
 	case STAT_ST_LIST:
 		while (appctx->ctx.map.ref) {
-
 			chunk_reset(&trash);
 
 			/* Build messages. If the reference is used by another category than
 			 * the listed categorie, display the information in the massage.
 			 */
-			if ((appctx->ctx.map.display_flags & PAT_REF_MAP) &&
-			    (appctx->ctx.map.ref->flags & PAT_REF_ACL)) {
-				chunk_appendf(&trash, "%s (also used by an ACL)\n",
-				              appctx->ctx.map.ref->reference);
+			chunk_appendf(&trash, "%d (%s)", appctx->ctx.map.ref->unique_id,
+			              appctx->ctx.map.ref->reference ? appctx->ctx.map.ref->reference : "");
+
+			if (appctx->ctx.map.display_flags & PAT_REF_MAP) {
+				if (appctx->ctx.map.ref->flags & PAT_REF_ACL)
+					chunk_appendf(&trash, " - also used by an ACL");
 			}
-			else if ((appctx->ctx.map.display_flags & PAT_REF_ACL) &&
-			         (appctx->ctx.map.ref->flags & PAT_REF_MAP)) {
-				chunk_appendf(&trash, "%s (also used by a map)\n",
-				              appctx->ctx.map.ref->reference);
+			else {
+				if (appctx->ctx.map.ref->flags & PAT_REF_MAP)
+					chunk_appendf(&trash, " - also used by a map");
 			}
-			else
-				chunk_appendf(&trash, "%s\n", appctx->ctx.map.ref->reference);
+			chunk_appendf(&trash, "\n");
 
 			if (bi_putchk(si->ib, &trash) == -1) {
 				/* let's try again later from this session. We add ourselves into
diff --git a/src/haproxy.c b/src/haproxy.c
index 2b83c62..fb8c8a1 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -89,6 +89,7 @@
 #include <proto/hdr_idx.h>
 #include <proto/listener.h>
 #include <proto/log.h>
+#include <proto/pattern.h>
 #include <proto/protocol.h>
 #include <proto/proto_http.h>
 #include <proto/proxy.h>
@@ -693,6 +694,8 @@
 			exit(1);
 	}
 
+	pattern_finalize_config();
+
 	err_code |= check_config_validity();
 	if (err_code & (ERR_ABORT|ERR_FATAL)) {
 		Alert("Fatal errors found in configuration.\n");
diff --git a/src/pattern.c b/src/pattern.c
index e35a59d..8625048 100644
--- a/src/pattern.c
+++ b/src/pattern.c
@@ -1562,6 +1562,23 @@
  * value as string form.
  *
  * This is used with modifiable ACL and MAPS
+ *
+ * The pattern reference are stored with two identifiers: the unique_id and
+ * the reference.
+ *
+ * The reference identify a file. Each file with the same name point to the
+ * same reference. We can register many times one file. If the file is modified,
+ * all his dependencies are also modified. The reference can be used with map or
+ * acl.
+ *
+ * The unique_id identify inline acl. The unique id is unique for each acl.
+ * You cannot force the same id in the configuration file, because this repoort
+ * an error.
+ *
+ * A particular case appears if the filename is a number. In this case, the
+ * unique_id is set with the number represented by the filename and the
+ * reference is also set. This method prevent double unique_id.
+ *
  */
 
 /* This function lookup for reference. If the reference is found, they return
@@ -1572,11 +1589,24 @@
 	struct pat_ref *ref;
 
 	list_for_each_entry(ref, &pattern_reference, list)
-		if (strcmp(reference, ref->reference) == 0)
+		if (ref->reference && strcmp(reference, ref->reference) == 0)
 			return ref;
 	return NULL;
 }
 
+/* This function lookup for unique id. If the reference is found, they return
+ * pointer to the struct pat_ref, else return NULL.
+ */
+struct pat_ref *pat_ref_lookupid(int unique_id)
+{
+	struct pat_ref *ref;
+
+	list_for_each_entry(ref, &pattern_reference, list)
+		if (ref->unique_id == unique_id)
+			return ref;
+	return NULL;
+}
+
 /* This function remove all pattern match <key> from the the reference
  * and from each expr member of the reference. This fucntion returns 1
  * if the deletion is done and return 0 is the entry is not found.
@@ -1662,7 +1692,35 @@
 		return NULL;
 	}
 
+	ref->flags = flags;
+	ref->unique_id = -1;
+
+	LIST_INIT(&ref->head);
+	LIST_INIT(&ref->pat);
+
+	LIST_ADDQ(&pattern_reference, &ref->list);
+
+	return ref;
+}
+
+/* This function create new reference. <unique_id> is the unique id. If
+ * the value of <unique_id> is -1, the unique id is calculated later.
+ * <flags> are PAT_REF_*. /!\ The reference is not checked, and must
+ * be unique. The user must check the reference with "pat_ref_lookup()"
+ * or pat_ref_lookupid before calling this function. If the function
+ * fail, it return NULL, else return new struct pat_ref.
+ */
+struct pat_ref *pat_ref_newid(int unique_id, unsigned int flags)
+{
+	struct pat_ref *ref;
+
+	ref = malloc(sizeof(*ref));
+	if (!ref)
+		return NULL;
+
+	ref->reference = NULL;
 	ref->flags = flags;
+	ref->unique_id = unique_id;
 	LIST_INIT(&ref->head);
 	LIST_INIT(&ref->pat);
 
@@ -1961,7 +2019,7 @@
  * return -2 if out of memory
  */
 int pattern_register(struct pattern_head *head,
-                     char *reference, int refflags,
+                     int unique_id, int refflags,
                      const char *arg,
                      struct sample_storage *smp,
                      int patflags, char **err)
@@ -1969,30 +2027,27 @@
 	struct pattern_expr *expr;
 	struct pat_ref *ref;
 
-	/* If reference is set, look up for existing reference. If the
-	 * reference is not found, create it.
-	 */
-	if (reference) {
-		ref = pat_ref_lookup(reference);
-		if (!ref) {
-			ref = pat_ref_new(reference, refflags);
-			if (!ref) {
-				memprintf(err, "out of memory");
-				return 0;
-			}
+	/* Look if the unique id already exists. If exists, abort the acl creation. */
+	if (unique_id >= 0) {
+		ref = pat_ref_lookupid(unique_id);
+		if (ref) {
+			memprintf(err, "The unique id \"%d\" is already used.", unique_id);
+			return 0;
 		}
 	}
-	else
-		ref = NULL;
 
-	/* look for reference or create it */
-	expr = pattern_lookup_expr(head, ref);
-	if (!expr) {
-		expr = pattern_new_expr(head, ref, err);
-		if (!expr)
-			return 0;
+	/* Create new reference. */
+	ref = pat_ref_newid(unique_id, refflags);
+	if (!ref) {
+		memprintf(err, "out of memory");
+		return 0;
 	}
 
+	/* create new pattern_expr. */
+	expr = pattern_new_expr(head, ref, err);
+	if (!expr)
+		return 0;
+
 	/* Index value. */
 	return pattern_add(expr, arg, smp, patflags, err);
 }
@@ -2060,10 +2115,10 @@
 	struct pat_ref *ref;
 	struct pattern_expr *expr;
 
-	/* Look for existing reference. If the reference doesn't exists,
-	 * create it and load file.
-	 */
+	/* Lookup for the existing reference. */
 	ref = pat_ref_lookup(filename);
+
+	/* If the reference doesn't exists, create it and load associated file. */
 	if (!ref) {
 		ref = pat_ref_new(filename, refflags);
 		if (!ref) {
@@ -2170,3 +2225,50 @@
 	expr->pat_head->delete(expr, &pattern);
 	return 1;
 }
+
+/* This function finalize the configuration parsing. Its set all the
+ * automatic ids
+ */
+void pattern_finalize_config(void)
+{
+	int i = 0;
+	struct pat_ref *ref, *ref2, *ref3;
+	struct list pr = LIST_HEAD_INIT(pr);
+
+	list_for_each_entry(ref, &pattern_reference, list) {
+		if (ref->unique_id == -1) {
+			/* Look for the first free id. */
+			while (1) {
+				list_for_each_entry(ref2, &pattern_reference, list) {
+					if (ref2->unique_id == i) {
+						i++;
+						break;
+					}
+				}
+				if (&ref2->list == &pattern_reference);
+					break;
+			}
+
+			/* Uses the unique id and increment it for the next entry. */
+			ref->unique_id = i;
+			i++;
+		}
+	}
+
+	/* This sort the reference list by id. */
+	list_for_each_entry_safe(ref, ref2, &pattern_reference, list) {
+		LIST_DEL(&ref->list);
+		list_for_each_entry(ref3, &pr, list) {
+			if (ref->unique_id < ref3->unique_id) {
+				LIST_ADDQ(&ref3->list, &ref->list);
+				break;
+			}
+		}
+		if (&ref3->list == &pr)
+			LIST_ADDQ(&pr, &ref->list);
+	}
+
+	/* swap root */
+	LIST_ADD(&pr, &pattern_reference);
+	LIST_DEL(&pr);
+}