CONTRIB: debug: add the possibility to decode the value as certain types only

It's often confusing to have a whole dump on the screen while only
checking for a set of task or stream flags, and appending "|grep ^chn"
isn't very convenient to repeat the opeation. Instead let's add the
ability to filter the output as certain types only by prepending their
name(s) before the value.

(cherry picked from commit 354b6f5e288f466aed48d46dd8467b023a0b3660)
Signed-off-by: Willy Tarreau <w@1wt.eu>
(cherry picked from commit 531fccc5301987c4ce4235d3c812912edf1db291)
Signed-off-by: Willy Tarreau <w@1wt.eu>
diff --git a/contrib/debug/flags.c b/contrib/debug/flags.c
index 0afdae9..a41d668 100644
--- a/contrib/debug/flags.c
+++ b/contrib/debug/flags.c
@@ -8,6 +8,21 @@
 #include <types/stream_interface.h>
 #include <types/task.h>
 
+// 1 bit per flag, no hole permitted here
+#define SHOW_AS_ANA   0x00000001
+#define SHOW_AS_CHN   0x00000002
+#define SHOW_AS_CONN  0x00000004
+#define SHOW_AS_CS    0x00000008
+#define SHOW_AS_SI    0x00000010
+#define SHOW_AS_SIET  0x00000020
+#define SHOW_AS_STRM  0x00000040
+#define SHOW_AS_TASK  0x00000080
+#define SHOW_AS_TXN   0x00000100
+
+// command line names, must be in exact same order as the SHOW_AS_* flags above
+// so that show_as_words[i] matches flag 1U<<i.
+const char *show_as_words[] = { "ana", "chn", "conn", "cs", "si", "siet", "strm", "task", "txn", };
+
 #define SHOW_FLAG(f,n)					\
 	do {				 		\
 		if (!((f) & (n))) break; 		\
@@ -15,6 +30,19 @@
 		printf(#n"%s", (f) ? " | " : "");	\
 	} while (0)
 
+unsigned int get_show_as(const char *word)
+{
+	int w = 0;
+
+	while (1) {
+		if (w == sizeof(show_as_words) / sizeof(*show_as_words))
+			return 0;
+		if (strcmp(word, show_as_words[w]) == 0)
+			return 1U << w;
+		w++;
+	}
+}
+
 void show_chn_ana(unsigned int f)
 {
 	printf("chn->ana    = ");
@@ -382,26 +410,49 @@
 	putchar('\n');
 }
 
+void usage_exit(const char *name)
+{
+	fprintf(stderr, "Usage: %s [ana|chn|conn|cs|si|sierr|strm|task|txn]* [0x]value\n", name);
+	exit(1);
+}
+
 int main(int argc, char **argv)
 {
 	unsigned int flags;
+	unsigned int show_as = 0;
+	unsigned int f;
+	const char *name = argv[0];
+	char *err;
+
+	while (argc > 0) {
+		argv++; argc--;
+		if (argc < 1)
+			usage_exit(name);
 
-	if (argc < 2) {
-		fprintf(stderr, "Usage: %s 0x<flags|state>\n", argv[0]);
-		exit(1);
+		flags = strtoul(argv[0], &err, 0);
+		if (*argv[0] && !*err)
+			break;
+
+		f = get_show_as(argv[0]);
+		if (!f) {
+			fprintf(stderr, "Unknown argument: <%s>\n", argv[0]);
+			usage_exit(name);
+		}
+		show_as |= f;
 	}
 
-	flags = strtoul(argv[1], NULL, 0);
+	if (!show_as)
+		show_as = ~0U;
 
-	show_task_state(flags);
-	show_txn_flags(flags);
-	show_strm_flags(flags);
-	show_si_et(flags);
-	show_si_flags(flags);
-	show_cs_flags(flags);
-	show_conn_flags(flags);
-	show_chn_flags(flags);
-	show_chn_ana(flags);
+	if (show_as & SHOW_AS_ANA)   show_chn_ana(flags);
+	if (show_as & SHOW_AS_CHN)   show_chn_flags(flags);
+	if (show_as & SHOW_AS_CONN)  show_conn_flags(flags);
+	if (show_as & SHOW_AS_CS)    show_cs_flags(flags);
+	if (show_as & SHOW_AS_SI)    show_si_flags(flags);
+	if (show_as & SHOW_AS_SIET)  show_si_et(flags);
+	if (show_as & SHOW_AS_STRM)  show_strm_flags(flags);
+	if (show_as & SHOW_AS_TASK)  show_task_state(flags);
+	if (show_as & SHOW_AS_TXN)   show_txn_flags(flags);
 
 	return 0;
 }