MEDIUM: pattern: The function pattern_exec_match() returns "struct pattern" if the patten match.

Before this commit, the pattern_exec_match() function returns the
associate sample, the associate struct pattern or the associate struct
pattern_tree. This is complex to use, because we can check the type of
information returned.

Now the function return always a "struct pattern". If <fill> is not set,
only the value of the pointer can be used as boolean (NULL or other). If
<fill> is set, you can use the <smp> pointer and the pattern
information.

If information must be duplicated, it is stored in trash buffer.
Otherwise, the pattern can point on existing strings.
diff --git a/include/proto/pattern.h b/include/proto/pattern.h
index c49f53d..1daf3bb 100644
--- a/include/proto/pattern.h
+++ b/include/proto/pattern.h
@@ -54,11 +54,12 @@
 }
 
 /* This function executes a pattern match on a sample. It applies pattern <expr>
- * to sample <smp>. If <sample> is not NULL, a pointer to an optional sample
- * associated to the matching patterned will be put there. The function returns
- * PAT_MATCH or PAT_NOMATCH.
+ * to sample <smp>. The function returns NULL if the sample dont match. It returns
+ * non-null if the sample match. If <fill> is true and the sample match, the
+ * function returns the matched pattern. In many cases, this pattern can be a
+ * static buffer.
  */
-enum pat_match_res pattern_exec_match(struct pattern_expr *expr, struct sample *smp, struct sample_storage **sample, struct pattern **pat, struct pattern_tree **elt);
+struct pattern *pattern_exec_match(struct pattern_expr *expr, struct sample *smp, int fill);
 
 /*
  *
diff --git a/src/acl.c b/src/acl.c
index 78c3f30..37fd8f4 100644
--- a/src/acl.c
+++ b/src/acl.c
@@ -39,9 +39,12 @@
 };
 
 /* input values are 0 or 3, output is the same */
-static inline enum acl_test_res pat2acl(enum pat_match_res res)
+static inline enum acl_test_res pat2acl(struct pattern *pat)
 {
-	return (enum acl_test_res)res;
+	if (pat)
+		return ACL_TEST_PASS;
+	else
+		return ACL_TEST_FAIL;
 }
 
 /*
@@ -1053,7 +1056,7 @@
 					continue;
 				}
 
-				acl_res |= pat2acl(pattern_exec_match(&expr->pat, &smp, NULL, NULL, NULL));
+				acl_res |= pat2acl(pattern_exec_match(&expr->pat, &smp, 0));
 				/*
 				 * OK now acl_res holds the result of this expression
 				 * as one of ACL_TEST_FAIL, ACL_TEST_MISS or ACL_TEST_PASS.
diff --git a/src/dumpstats.c b/src/dumpstats.c
index afd333c..01f5d37 100644
--- a/src/dumpstats.c
+++ b/src/dumpstats.c
@@ -4827,10 +4827,10 @@
 	struct sample_storage *smp;
 	struct sample sample;
 	struct pattern *pat;
-	struct pattern_tree *elt;
-	enum pat_match_res res;
-	struct sockaddr_in addr;
-	char addr_str[INET_ADDRSTRLEN];
+	struct sockaddr_storage addr;
+	char s_addr[INET_ADDRSTRLEN];
+	char s_mask[INET_ADDRSTRLEN];
+	char s_addr6[INET6_ADDRSTRLEN];
 
 	switch (appctx->st2) {
 	case STAT_ST_INIT:
@@ -4850,9 +4850,7 @@
 			sample.flags |= SMP_F_CONST;
 			sample.data.str.len = appctx->ctx.map.chunk.len;
 			sample.data.str.str = appctx->ctx.map.chunk.str;
-			pat = NULL;
-			elt = NULL;
-			res = pattern_exec_match(appctx->ctx.map.desc->pat, &sample, &smp, &pat, &elt);
+			pat = pattern_exec_match(appctx->ctx.map.desc->pat, &sample, 1);
 
 			/* build return message: set type of match */
 			/**/ if (appctx->ctx.map.desc->pat->match == NULL)
@@ -4885,9 +4883,8 @@
 				chunk_appendf(&trash, "unknown(%p), ", appctx->ctx.map.desc->pat->match);
 
 			/* Display no match, and set default value */
-			if (res == PAT_NOMATCH) {
+			if (!pat) {
 				chunk_appendf(&trash, "no-match, ");
-				smp = appctx->ctx.map.desc->def;
 			}
 
 			/* Display match and match info */
@@ -4895,46 +4892,61 @@
 				/* display match */
 				chunk_appendf(&trash, "match, ");
 
-				/* display search mode */
-				if (elt)
+				/* display index mode */
+				if (pat->flags & PAT_F_TREE)
 					chunk_appendf(&trash, "tree, ");
 				else
 					chunk_appendf(&trash, "list, ");
 
-				/* display search options */
-				if (pat) {
-					/* case sensitive */
-					if (pat->flags & PAT_F_IGNORE_CASE)
-						chunk_appendf(&trash, "case-insensitive, ");
-					else
-						chunk_appendf(&trash, "case-sensitive, ");
+				/* case sensitive */
+				if (pat->flags & PAT_F_IGNORE_CASE)
+					chunk_appendf(&trash, "case-insensitive, ");
+				else
+					chunk_appendf(&trash, "case-sensitive, ");
 
-					/* display source */
-					if (pat->flags & PAT_F_FROM_FILE)
-						chunk_appendf(&trash, "from-file, ");
-				}
+				/* display source */
+				if (pat->flags & PAT_F_FROM_FILE)
+					chunk_appendf(&trash, "from-file, ");
 
-				/* display match expresion */
-				if (elt) {
-					if (appctx->ctx.map.desc->pat->match == pat_match_str) {
-						chunk_appendf(&trash, "match=\"%s\", ", elt->node.key);
+				/* display string */
+				if (appctx->ctx.map.desc->pat->match == pat_match_str ||
+				    appctx->ctx.map.desc->pat->match == pat_match_str ||
+				    appctx->ctx.map.desc->pat->match == pat_match_beg ||
+				    appctx->ctx.map.desc->pat->match == pat_match_sub ||
+				    appctx->ctx.map.desc->pat->match == pat_match_dir ||
+				    appctx->ctx.map.desc->pat->match == pat_match_dom ||
+				    appctx->ctx.map.desc->pat->match == pat_match_end) {
+					chunk_appendf(&trash, "match=\"%s\", ", pat->ptr.str);
+				}
+				else if (appctx->ctx.map.desc->pat->match == pat_match_ip) {
+					/* display IPv4/v6 */
+					if (pat->type == SMP_T_IPV4) {
+						((struct sockaddr_in *)&addr)->sin_family = AF_INET;
+						memcpy(&((struct sockaddr_in *)&addr)->sin_addr, &pat->val.ipv4.addr,
+						       sizeof(pat->val.ipv4.addr));
+						if (addr_to_str(&addr, s_addr, INET_ADDRSTRLEN)) {
+							memcpy(&((struct sockaddr_in *)&addr)->sin_addr, &pat->val.ipv4.mask,
+							       sizeof(pat->val.ipv4.mask));
+							if (addr_to_str(&addr, s_mask, INET_ADDRSTRLEN))
+								chunk_appendf(&trash, "match=\"%s/%s\", ", s_addr, s_mask);
+						}
 					}
-					/* only IPv4 */
-					else if (appctx->ctx.map.desc->pat->match == pat_match_ip) {
-						/* convert ip */
-						memcpy(&addr.sin_addr, elt->node.key, 4);
-						addr.sin_family = AF_INET;
-						if (addr_to_str((struct sockaddr_storage *)&addr, addr_str, INET_ADDRSTRLEN))
-							chunk_appendf(&trash, "match=\"%s/%d\", ", addr_str, elt->node.node.pfx);
+					else if (pat->type == SMP_T_IPV6) {
+						((struct sockaddr_in6 *)&addr)->sin6_family = AF_INET6;
+						memcpy(&((struct sockaddr_in6 *)&addr)->sin6_addr, &pat->val.ipv6.addr,
+						       sizeof(pat->val.ipv6.addr));
+						if (addr_to_str(&addr, s_addr6, INET6_ADDRSTRLEN))
+							chunk_appendf(&trash, "match=\"%s/%d\", ", s_addr6, pat->val.ipv6.mask);
 					}
 				}
 			}
 
 			/* display return value */
-			if (!smp) {
+			if (!pat || !pat->smp) {
 				chunk_appendf(&trash, "return=nothing\n");
 			}
 			else {
+				smp = pat->smp;
 				memcpy(&sample.data, &smp->data, sizeof(sample.data));
 				sample.type = smp->type;
 				if (sample_casts[sample.type][SMP_T_STR] &&
diff --git a/src/map.c b/src/map.c
index e48408a..c244bb7 100644
--- a/src/map.c
+++ b/src/map.c
@@ -457,24 +457,38 @@
 static int sample_conv_map(const struct arg *arg_p, struct sample *smp)
 {
 	struct map_descriptor *desc;
-	struct sample_storage *sample;
-	enum pat_match_res ret;
+	struct pattern *pat;
 
 	/* get config */
 	desc = arg_p[0].data.map;
 
 	/* Execute the match function. */
-	ret = pattern_exec_match(desc->pat, smp, &sample, NULL, NULL);
-	if (ret != PAT_MATCH) {
-		if (!desc->def)
-			return 0;
-		sample = desc->def;
+	pat = pattern_exec_match(desc->pat, smp, 1);
+
+	/* Match case. */
+	if (pat) {
+		/* Copy sample. */
+		if (pat->smp) {
+			smp->type = pat->smp->type;
+			smp->flags |= SMP_F_CONST;
+			memcpy(&smp->data, &pat->smp->data, sizeof(smp->data));
+			return 1;
+		}
+
+		/* Return just int sample containing 1. */
+		smp->type = SMP_T_UINT;
+		smp->data.uint= 1;
+		return 1;
 	}
 
-	/* copy new data */
-	smp->type = sample->type;
+	/* If no default value avalaible, the converter fails. */
+	if (!desc->def)
+		return 0;
+
+	/* Return the default value. */
+	smp->type = desc->def->type;
 	smp->flags |= SMP_F_CONST;
-	memcpy(&smp->data, &sample->data, sizeof(smp->data));
+	memcpy(&smp->data, &desc->def->data, sizeof(smp->data));
 	return 1;
 }
 
diff --git a/src/pattern.c b/src/pattern.c
index d41e086..aa6a3d4 100644
--- a/src/pattern.c
+++ b/src/pattern.c
@@ -105,6 +105,9 @@
 	[PAT_MATCH_REG]   = SMP_T_STR,
 };
 
+/* this struct is used to return information */
+static struct pattern static_pattern;
+
 /*
  *
  * The following functions are not exported and are used by internals process
@@ -1059,19 +1062,18 @@
 	return ret;
 }
 
-/* This function matches a sample <smp> against a set of patterns presented in
- * pattern expression <expr>. Upon success, if <sample> is not NULL, it is fed
- * with the pointer associated with the matching pattern. This function returns
- * PAT_NOMATCH or PAT_MATCH.
+/* This function executes a pattern match on a sample. It applies pattern <expr>
+ * to sample <smp>. The function returns NULL if the sample dont match. It returns
+ * non-null if the sample match. If <fill> is true and the sample match, the
+ * function returns the matched pattern. In many cases, this pattern can be a
+ * static buffer.
  */
-enum pat_match_res pattern_exec_match(struct pattern_expr *expr, struct sample *smp,
-                                      struct sample_storage **sample,
-                                      struct pattern **pat, struct pattern_tree **idx_elt)
+struct pattern *pattern_exec_match(struct pattern_expr *expr, struct sample *smp, int fill)
 {
 	enum pat_match_res pat_res = PAT_NOMATCH;
-	struct pattern_list *pattern;
+	struct pattern_list *pattern = NULL;
 	struct ebmb_node *node = NULL;
-	struct pattern_tree *elt;
+	struct pattern_tree *elt = NULL;
 
 	if (expr->match == pat_match_nothing) {
 		if (smp->data.uint)
@@ -1097,27 +1099,62 @@
 			if (node) {
 				pat_res |= PAT_MATCH;
 				elt = ebmb_entry(node, struct pattern_tree, node);
-				if (sample)
-					*sample = elt->smp;
-				if (idx_elt)
-					*idx_elt = elt;
 			}
 		}
 
 		/* call the match() function for all tests on this value */
-		list_for_each_entry(pattern, &expr->patterns, list) {
-			if (pat_res == PAT_MATCH)
-				break;
-			if (sample_convert(smp, pattern->pat.expect_type))
-				pat_res |= expr->match(smp, &pattern->pat);
-			if (sample)
-				*sample = pattern->pat.smp;
-			if (pat)
-				*pat = &pattern->pat;
+		if (pat_res != PAT_MATCH) {
+			list_for_each_entry(pattern, &expr->patterns, list) {
+				if (sample_convert(smp, pattern->pat.expect_type))
+					pat_res |= expr->match(smp, &pattern->pat);
+				if (pat_res == PAT_MATCH)
+					break;
+			}
 		}
 	}
 
+	if (pat_res == PAT_MATCH) {
+		static_pattern.flags = 0;
+		if (fill) {
+			/* fill with boolean */
+			if (expr->match == NULL ||
+			    expr->match == pat_match_nothing) {
+				static_pattern.smp = NULL;
+				static_pattern.type = SMP_T_BOOL;
+				static_pattern.val.i = 1;
+				return &static_pattern;
+			}
+
+			/* fill with ipv4 */
+			if (expr->match == pat_match_ip && elt) {
+				static_pattern.smp = elt->smp;;
+				static_pattern.flags |= PAT_F_TREE;
+				static_pattern.type = SMP_T_IPV4;
+				memcpy(&static_pattern.val.ipv4.addr, &elt->node.key, 4);
+				if (!cidr2dotted(elt->node.node.pfx, &static_pattern.val.ipv4.mask))
+					return NULL;
+				return &static_pattern;
+			}
+
+			/* fill with string */
+			if (expr->match == pat_match_str && elt) {
+				static_pattern.smp = elt->smp;;
+				static_pattern.flags |= PAT_F_TREE;
+				static_pattern.type = SMP_T_STR;
+				static_pattern.ptr.str = (char *)elt->node.key;
+				return &static_pattern;
+			}
+
+			/* return the pattern */
+			return &pattern->pat;
+		}
+
+		/* Return uninitialized pattern. The content must not be used by the caller */
+		return &static_pattern;
+	}
+
-	return pat_res;
+	/* No match */
+	return NULL;
 }
 
 /* This function browse the pattern expr <expr> to lookup the key <key>. On