--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <haproxy/connection-t.h>
+#include <haproxy/intops.h>
+
+struct tevt_info {
+ const char *loc;
+ const char **types;
+};
+
+
+/* will be sufficient for even largest flag names */
+static char buf[4096];
+static size_t bsz = sizeof(buf);
+
+
+static const char *tevt_unknown_types[16] = {
+ [ 0] = "-", [ 1] = "-", [ 2] = "-", [ 3] = "-",
+ [ 4] = "-", [ 5] = "-", [ 6] = "-", [ 7] = "-",
+ [ 8] = "-", [ 9] = "-", [10] = "-", [11] = "-",
+ [12] = "-", [13] = "-", [14] = "-", [15] = "-",
+};
+
+static const char *tevt_fd_types[16] = {
+ [ 0] = "-", [ 1] = "shutw", [ 2] = "shutr", [ 3] = "rcv_err",
+ [ 4] = "snd_err", [ 5] = "-", [ 6] = "-", [ 7] = "conn_err",
+ [ 8] = "intercepted", [ 9] = "-", [10] = "-", [11] = "-",
+ [12] = "-", [13] = "-", [14] = "-", [15] = "-",
+};
+
+static const char *tevt_hs_types[16] = {
+ [ 0] = "-", [ 1] = "-", [ 2] = "-", [ 3] = "rcv_err",
+ [ 4] = "snd_err", [ 5] = "-", [ 6] = "-", [ 7] = "-",
+ [ 8] = "-", [ 9] = "-", [10] = "-", [11] = "-",
+ [12] = "-", [13] = "-", [14] = "-", [15] = "-",
+};
+
+static const char *tevt_xprt_types[16] = {
+ [ 0] = "-", [ 1] = "shutw", [ 2] = "shutr", [ 3] = "rcv_err",
+ [ 4] = "snd_err", [ 5] = "-", [ 6] = "-", [ 7] = "-",
+ [ 8] = "-", [ 9] = "-", [10] = "-", [11] = "-",
+ [12] = "-", [13] = "-", [14] = "-", [15] = "-",
+};
+
+static const char *tevt_muxc_types[16] = {
+ [ 0] = "-", [ 1] = "shutw", [ 2] = "shutr", [ 3] = "rcv_err",
+ [ 4] = "snd_err", [ 5] = "truncated_shutr", [ 6] = "truncated_rcv_err", [ 7] = "tout",
+ [ 8] = "goaway_rcvd", [ 9] = "proto_err", [10] = "internal_err", [11] = "other_err",
+ [12] = "graceful_shut", [13] = "-", [14] = "-", [15] = "-",
+};
+
+static const char *tevt_se_types[16] = {
+ [ 0] = "-", [ 1] = "shutw", [ 2] = "eos", [ 3] = "rcv_err",
+ [ 4] = "snd_err", [ 5] = "truncated_eos", [ 6] = "truncated_rcv_err", [ 7] = "-",
+ [ 8] = "rst_rcvd", [ 9] = "proto_err", [10] = "internal_err", [11] = "other_err",
+ [12] = "cancelled", [13] = "-", [14] = "-", [15] = "-",
+};
+
+static const char *tevt_strm_types[16] = {
+ [ 0] = "-", [ 1] = "shutw", [ 2] = "eos", [ 3] = "rcv_err",
+ [ 4] = "snd_err", [ 5] = "truncated_eos", [ 6] = "truncated_rcv_err", [ 7] = "tout",
+ [ 8] = "intercepted", [ 9] = "proto_err", [10] = "internal_err", [11] = "other_err",
+ [12] = "aborted", [13] = "-", [14] = "-", [15] = "-",
+};
+
+static const struct tevt_info tevt_location[26] = {
+ [ 0] = {.loc = "-", .types = tevt_unknown_types}, [ 1] = {.loc = "-", .types = tevt_unknown_types},
+ [ 2] = {.loc = "-", .types = tevt_unknown_types}, [ 3] = {.loc = "-", .types = tevt_unknown_types},
+ [ 4] = {.loc = "se", .types = tevt_se_types}, [ 5] = {.loc = "fd", .types = tevt_fd_types},
+ [ 6] = {.loc = "-", .types = tevt_unknown_types}, [ 7] = {.loc = "hs", .types = tevt_hs_types},
+ [ 8] = {.loc = "-", .types = tevt_unknown_types}, [ 9] = {.loc = "-", .types = tevt_unknown_types},
+ [10] = {.loc = "-", .types = tevt_unknown_types}, [11] = {.loc = "-", .types = tevt_unknown_types},
+ [12] = {.loc = "muxc", .types = tevt_muxc_types}, [13] = {.loc = "-", .types = tevt_unknown_types},
+ [14] = {.loc = "-", .types = tevt_unknown_types}, [15] = {.loc = "-", .types = tevt_unknown_types},
+ [16] = {.loc = "-", .types = tevt_unknown_types}, [17] = {.loc = "-", .types = tevt_unknown_types},
+ [18] = {.loc = "strm", .types = tevt_strm_types}, [19] = {.loc = "-", .types = tevt_unknown_types},
+ [20] = {.loc = "-", .types = tevt_unknown_types}, [21] = {.loc = "-", .types = tevt_unknown_types},
+ [22] = {.loc = "-", .types = tevt_unknown_types}, [23] = {.loc = "xprt", .types = tevt_xprt_types},
+ [24] = {.loc = "-", .types = tevt_unknown_types}, [25] = {.loc = "-", .types = tevt_unknown_types},
+};
+
+void usage_exit(const char *name)
+{
+ fprintf(stderr, "Usage: %s { value* | - }\n", name);
+ exit(1);
+}
+
+char *to_upper(char *dst, const char *src)
+{
+ int i;
+
+ for (i = 0; src[i]; i++)
+ dst[i] = toupper(src[i]);
+ dst[i] = 0;
+ return dst;
+}
+
+char *tevt_show_events(char *buf, size_t len, const char *delim, const char *value)
+{
+ char loc[5];
+ int ret;
+
+ if (!value)
+ goto end;
+
+ if (strlen(value) % 2 != 0) {
+ snprintf(buf, len, "##INV");
+ goto end;
+ }
+
+ while (*value) {
+ struct tevt_info info;
+ char l = value[0];
+ char t = value[1];
+
+ if (!isalpha(l) || !isxdigit(t)) {
+ snprintf(buf, len, "##INV");
+ goto end;
+ }
+
+ info = tevt_location[tolower(l) - 'a'];
+ ret = snprintf(buf, len, "%s:%s%s",
+ isupper(l) ? to_upper(loc, info.loc) : info.loc,
+ info.types[hex2i(t)],
+ value[2] != 0 ? delim : "");
+ if (ret < 0)
+ break;
+ len -= ret;
+ buf += ret;
+ value += 2;
+ }
+
+ end:
+ return buf;
+}
+
+int main(int argc, char **argv)
+{
+ const char *name = argv[0];
+ char line[20];
+ char *value;
+ int multi = 0;
+ int use_stdin = 0;
+ char *err;
+
+ while (argc == 1)
+ usage_exit(name);
+
+ argv++; argc--;
+ if (argc > 1)
+ multi = 1;
+
+ if (strcmp(argv[0], "-") == 0)
+ use_stdin = 1;
+
+ while (argc > 0) {
+ if (use_stdin) {
+ value = fgets(line, sizeof(line), stdin);
+ if (!value)
+ break;
+
+ /* skip common leading delimiters that slip from copy-paste */
+ while (*value == ' ' || *value == '\t' || *value == ':' || *value == '=')
+ value++;
+
+ err = value;
+ while (isalnum((unsigned char)*err))
+ err++;
+ *err = 0;
+ }
+ else {
+ value = argv[0];
+ argv++; argc--;
+ }
+
+ if (multi)
+ printf("### %-8s : ", value);
+
+ tevt_show_events(buf, bsz, " > ", value);
+ printf("%s\n", buf);
+ }
+ return 0;
+}