MINOR: samples: add a function to list register sample fetch keywords

New function smp_dump_fetch_kw lists registered sample fetch keywords
with their compatibility matrix, mandatory and optional argument types,
and output types. It's called from dump_registered_keywords() with class
"smp".
diff --git a/include/haproxy/sample.h b/include/haproxy/sample.h
index 670205f..f6ce3c0 100644
--- a/include/haproxy/sample.h
+++ b/include/haproxy/sample.h
@@ -49,6 +49,7 @@
 const char *sample_src_names(unsigned int use);
 const char *sample_ckp_names(unsigned int use);
 struct sample_fetch *find_sample_fetch(const char *kw, int len);
+void smp_dump_fetch_kw(void);
 struct sample_fetch *sample_fetch_getnext(struct sample_fetch *current, int *idx);
 struct sample_conv *sample_conv_getnext(struct sample_conv *current, int *idx);
 int smp_resolve_args(struct proxy *p, char **err);
diff --git a/src/haproxy.c b/src/haproxy.c
index 72c065e..a17692c 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -1829,6 +1829,7 @@
 			printf("cfg: configuration keywords\n");
 			printf("cli: CLI keywords\n");
 			printf("flt: filter names\n");
+			printf("smp: sample fetch functions\n");
 			printf("svc: service names\n");
 			continue;
 		}
@@ -1856,6 +1857,11 @@
 			flt_dump_kws(NULL);
 		}
 
+		if (all || strcmp(kwd_dump, "smp") == 0) {
+			printf("# List of registered sample fetch functions:\n");
+			smp_dump_fetch_kw();
+		}
+
 		if (all || strcmp(kwd_dump, "svc") == 0) {
 			printf("# List of registered service names:\n");
 			list_services(NULL);
diff --git a/src/sample.c b/src/sample.c
index 7db5fde..c4b7da9 100644
--- a/src/sample.c
+++ b/src/sample.c
@@ -434,6 +434,67 @@
 	return NULL;
 }
 
+/* dump list of registered sample fetch keywords on stdout */
+void smp_dump_fetch_kw(void)
+{
+	struct sample_fetch_kw_list *kwl;
+	struct sample_fetch *kw;
+	uint64_t mask;
+	int index;
+	int arg;
+	int bit;
+
+	for (bit = 0; bit <= SMP_CKP_ENTRIES + 1; bit++) {
+		putchar('#');
+		for (index = 0; bit + index <= SMP_CKP_ENTRIES; index++)
+			putchar(' ');
+		for (index = 0; index < bit && index < SMP_CKP_ENTRIES; index++)
+			printf((bit <= SMP_CKP_ENTRIES) ? "/ " : " |");
+		for (index = bit; bit < SMP_CKP_ENTRIES && index < SMP_CKP_ENTRIES + 2; index++)
+			if (index == bit)
+				putchar('_');
+			else if (index == bit + 1)
+				putchar('.');
+			else
+				putchar('-');
+		printf(" %s\n", (bit < SMP_CKP_ENTRIES) ? fetch_ckp_names[bit] : "");
+	}
+
+	list_for_each_entry(kwl, &sample_fetches.list, list) {
+		for (index = 0; kwl->kw[index].kw != NULL; index++) {
+			kw = &kwl->kw[index];
+
+			printf("[ ");
+			for (bit = 0; bit < SMP_CKP_ENTRIES; bit++)
+				printf("%s", (kw->val & (1 << bit)) ? "Y " : ". ");
+
+			printf("] %s", kw->kw);
+			if (kw->arg_mask) {
+				mask = kw->arg_mask >> ARGM_BITS;
+				printf("(");
+				for (arg = 0;
+				     arg < ARGM_NBARGS && ((mask >> (arg * ARGT_BITS)) & ARGT_MASK);
+				     arg++) {
+					if (arg == (kw->arg_mask & ARGM_MASK)) {
+						/* now dumping extra args */
+						printf("[");
+					}
+					if (arg)
+						printf(",");
+					printf("%s", arg_type_names[(mask >> (arg * ARGT_BITS)) & ARGT_MASK]);
+				}
+				if (arg > (kw->arg_mask & ARGM_MASK)) {
+					/* extra args were dumped */
+					printf("]");
+				}
+				printf(")");
+			}
+			printf(": %s", smp_to_type[kw->out_type]);
+			printf("\n");
+		}
+	}
+}
+
 /* This function browses the list of available sample fetches. <current> is
  * the last used sample fetch. If it is the first call, it must set to NULL.
  * <idx> is the index of the next sample fetch entry. It is used as private