MINOR: sample: Add strcmp sample converter

This converter supplements the existing string matching by allowing
strings to be converted to a variable.

Example usage:

  http-request set-var(txn.host) hdr(host)
  # Check whether the client is attempting domain fronting.
  acl ssl_sni_http_host_match ssl_fc_sni,strcmp(txn.host) eq 0
diff --git a/doc/configuration.txt b/doc/configuration.txt
index dcc87fd..b865b33 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -13242,6 +13242,21 @@
   Converts a binary input sample to a SHA1 digest. The result is a binary
   sample with length of 20 bytes.
 
+strcmp(<var>)
+  Compares the contents of <var> with the input value of type string. Returns
+  the result as a signed integer compatible with strcmp(3): 0 if both strings
+  are identical. A value less than 0 if the left string is lexicographically
+  smaller than the right string or if the left string is shorter. A value greater
+  than 0 otherwise (right string greater than left string or the right string is
+  shorter).
+
+  Example :
+
+     http-request set-var(txn.host) hdr(host)
+     # Check whether the client is attempting domain fronting.
+     acl ssl_sni_http_host_match ssl_fc_sni,strcmp(txn.host) eq 0
+
+
 sub(<value>)
   Subtracts <value> from the input value of type signed integer, and returns
   the result as an signed integer. Note: in order to subtract the input from
diff --git a/src/sample.c b/src/sample.c
index b1c0148..3f72266 100644
--- a/src/sample.c
+++ b/src/sample.c
@@ -2684,6 +2684,54 @@
 	return 1;
 }
 
+/* compares string with a variable containing a string. Return value
+ * is compatible with strcmp(3)'s return value.
+ */
+static int sample_conv_strcmp(const struct arg *arg_p, struct sample *smp, void *private)
+{
+	struct sample tmp;
+	int max, result;
+
+	smp_set_owner(&tmp, smp->px, smp->sess, smp->strm, smp->opt);
+	if (arg_p[0].type != ARGT_VAR)
+		return 0;
+	if (!vars_get_by_desc(&arg_p[0].data.var, &tmp))
+		return 0;
+	if (!sample_casts[tmp.data.type][SMP_T_STR](&tmp))
+		return 0;
+
+	max = MIN(smp->data.u.str.len, tmp.data.u.str.len);
+	result = strncmp(smp->data.u.str.str, tmp.data.u.str.str, max);
+	if (result == 0) {
+		if (smp->data.u.str.len != tmp.data.u.str.len) {
+			if (smp->data.u.str.len < tmp.data.u.str.len) {
+				result = -1;
+			}
+			else {
+				result = 1;
+			}
+		}
+	}
+
+	smp->data.u.sint = result;
+	smp->data.type = SMP_T_SINT;
+	return 1;
+}
+
+/* This function checks the "strcmp" converter's arguments and extracts the
+ * variable name and its scope.
+ */
+static int smp_check_strcmp(struct arg *args, struct sample_conv *conv,
+                           const char *file, int line, char **err)
+{
+	/* Try to decode a variable. */
+	if (vars_check_arg(&args[0], NULL))
+		return 1;
+
+	memprintf(err, "failed to register variable name '%s'", args[0].data.str.str);
+	return 0;
+}
+
 /************************************************************************/
 /*       All supported sample fetch functions must be declared here     */
 /************************************************************************/
@@ -2999,6 +3047,7 @@
 	{ "regsub", sample_conv_regsub,    ARG3(2,REG,STR,STR), sample_conv_regsub_check, SMP_T_STR, SMP_T_STR },
 	{ "sha1",   sample_conv_sha1,      0,            NULL, SMP_T_BIN,  SMP_T_BIN  },
 	{ "concat", sample_conv_concat,    ARG3(1,STR,STR,STR), smp_check_concat, SMP_T_STR,  SMP_T_STR },
+	{ "strcmp", sample_conv_strcmp,    ARG1(1,STR), smp_check_strcmp, SMP_T_STR,  SMP_T_SINT },
 
 	{ "and",    sample_conv_binary_and, ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT  },
 	{ "or",     sample_conv_binary_or,  ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT  },