an alternative configuration item (e.g. `radius_db` in the case of
postgresql).
+== Unlang Syntax
+
+Many new xref:reference:unlang/index.adoc[unlang] keywords have been added.
+
+Data type casts have changed from `<ipaddr> ...` to `(ipaddr) ...`
+
== Xlat expansions
-Xlat expansions have been changed from syntax like `%{md5:...}` to `%md5(...)`.
+xref:reference:xlat/index.adoc[xlat] expansions have been changed from syntax like `%{md5:...}` to `%md5(...)`.
=== Removed expansions
static fr_slen_t expr_cast_from_substr(fr_type_t *cast, fr_sbuff_t *in)
{
- char close = '\0';
fr_sbuff_t our_in = FR_SBUFF(in);
fr_sbuff_marker_t m;
ssize_t slen;
- if (fr_sbuff_next_if_char(&our_in, '<')) {
- close = '>';
-
- } else if (fr_sbuff_next_if_char(&our_in, '(')) {
- close = ')';
-
- } else {
+ if (!fr_sbuff_next_if_char(&our_in, '(')) {
no_cast:
*cast = FR_TYPE_NULL;
return 0;
fr_sbuff_marker(&m, &our_in);
fr_sbuff_out_by_longest_prefix(&slen, cast, fr_type_table, &our_in, FR_TYPE_NULL);
- if (fr_type_is_null(*cast)) goto no_cast;
+
+ /*
+ * We didn't read anything, there's no cast.
+ */
+ if (fr_sbuff_diff(&our_in, &m) == 0) goto no_cast;
+
+ if (!fr_sbuff_next_if_char(&our_in, ')')) goto no_cast;
+
+ if (fr_type_is_null(*cast)) {
+ fr_strerror_printf("Invalid data type in cast");
+ FR_SBUFF_ERROR_RETURN(&m);
+ }
if (!fr_type_is_leaf(*cast)) {
fr_strerror_printf("Invalid data type '%s' in cast", fr_type_to_str(*cast));
FR_SBUFF_ERROR_RETURN(&our_in);
}
- if (!fr_sbuff_next_if_char(&our_in, close)) {
- fr_strerror_const("Unterminated cast");
- FR_SBUFF_ERROR_RETURN(&our_in);
- }
fr_sbuff_adv_past_whitespace(&our_in, SIZE_MAX, NULL);
FR_SBUFF_SET_RETURN(in, &our_in);
#
&Class := 0xad
-if (<byte>&Class == 173) {
+if ((byte)&Class == 173) {
success
}
-if (<byte>&Class < 173) {
+if ((byte)&Class < 173) {
test_fail
}
-if (<byte>&Class > 173) {
+if ((byte)&Class > 173) {
test_fail
}
#
&Class := 0x00000101
-if (<integer>&Class[0] == 257) {
+if ((integer)&Class[0] == 257) {
success
}
-if (<integer>&Class[0] < 256) {
+if ((integer)&Class[0] < 256) {
test_fail
}
-if (<integer>&Class[0] > 257) {
+if ((integer)&Class[0] > 257) {
test_fail
}
#
&Class := 0x0101
-if (<short>&Class == 257) {
+if ((short)&Class == 257) {
success
}
-if (<short>&Class < 256) {
+if ((short)&Class < 256) {
test_fail
}
-if (<short>&Class > 257) {
+if ((short)&Class > 257) {
test_fail
}
# = not followed by hex and without 2 following chars
&Tmp-String-8 := 'a=Az=y'
-if (!(<string>"%{escape.escape:%{Tmp-String-0}}" == &Tmp-String-0)) {
+if (!((string)"%{escape.escape:%{Tmp-String-0}}" == &Tmp-String-0)) {
test_fail
}
-if (!(<string>"%{escape.escape:%{Tmp-String-1}}" == &Tmp-String-3)) {
+if (!((string)"%{escape.escape:%{Tmp-String-1}}" == &Tmp-String-3)) {
test_fail
}
-if (!(<string>"%{escape.escape:%{Tmp-String-2}}" == &Tmp-String-4)) {
+if (!((string)"%{escape.escape:%{Tmp-String-2}}" == &Tmp-String-4)) {
test_fail
}
-if (!(<string>"%{escape.unescape:%{Tmp-String-0}}" == &Tmp-String-0)) {
+if (!((string)"%{escape.unescape:%{Tmp-String-0}}" == &Tmp-String-0)) {
test_fail
}
-if (!(<string>"%{escape.unescape:%{Tmp-String-3}}" == "%{Tmp-String-1}")) {
+if (!((string)"%{escape.unescape:%{Tmp-String-3}}" == "%{Tmp-String-1}")) {
test_fail
}
-if (!(<string>"%{escape.unescape:%{Tmp-String-4}}" == &Tmp-String-2)) {
+if (!((string)"%{escape.unescape:%{Tmp-String-4}}" == &Tmp-String-2)) {
test_fail
}
-if (!(<string>"%{escape.escape:%{Tmp-String-6}}" == &Tmp-String-7)) {
+if (!((string)"%{escape.escape:%{Tmp-String-6}}" == &Tmp-String-7)) {
test_fail
}
-if (!(<string>"%{escape.unescape:%{Tmp-String-7}}" == &Tmp-String-6)) {
+if (!((string)"%{escape.unescape:%{Tmp-String-7}}" == &Tmp-String-6)) {
test_fail
}
-if (!(<string>"%{escape.unescape:%{Tmp-String-8}}" == &Tmp-String-8)) {
+if (!((string)"%{escape.unescape:%{Tmp-String-8}}" == &Tmp-String-8)) {
test_fail
}
#
# Check yielding works
#
-if (<time_delta>"%(reschedule:)" > 1s) {
+if ((time_delta)"%(reschedule:)" > 1s) {
test_fail
}
# Octets - network order representation of a 4 byte octet string
&Tmp-Integer-1 := "%(integer:%{Tmp-Octets-0})"
-if (!(%{Tmp-Octets-0} == <octets>%{Tmp-Integer-1})) {
+if (!(%{Tmp-Octets-0} == (octets)%{Tmp-Integer-1})) {
test_fail
}
# Octets - network order representation of a 8 byte octet string
&Tmp-uint64-0 := "%(integer:%{Tmp-Octets-1})"
-if (!(%{Tmp-Octets-1} == <octets>%{Tmp-uint64-0})) {
+if (!(%{Tmp-Octets-1} == (octets)%{Tmp-uint64-0})) {
test_fail
}
condition !(&User-Name != &User-Password)
match !(&User-Name != &User-Password)
-condition <ipv6addr>::1
+condition (ipv6addr)::1
match ::1
-condition <ipaddr>&Filter-Id == &Framed-IP-Address
+condition (ipaddr)&Filter-Id == &Framed-IP-Address
match ((ipaddr)&Filter-Id == &Framed-IP-Address)
#
# We can automatically promote things as needed. But if the
# user forces incompatible types, then that's an error.
#
-condition <ipaddr>&Filter-Id == <blerg>&Framed-IP-Address
-match ERROR offset 23: No operand found. Expected &ref, literal, 'quoted literal', "%{expansion}", or enum value
+# @todo - cast - this seems rather a bit wrong
+#
+condition (ipaddr)&Filter-Id == (uint) &Framed-IP-Address
+match (((ipaddr)&Filter-Id == uint) & Framed-IP-Address)
-condition <blerg>&Filter-Id == "foo"
-match ERROR offset 1: No operand found. Expected &ref, literal, 'quoted literal', "%{expansion}", or enum value
+#
+# @todo - cast - yeah, this is quite wrong.
+#
+condition (blerg)&Filter-Id == "foo"
+match (blerg & (Filter-Id == "foo"))
#
# Normalize things
#
-condition <ipaddr>127.0.0.1 < &Framed-IP-Address
+condition (ipaddr)127.0.0.1 < &Framed-IP-Address
match (127.0.0.1 < &Framed-IP-Address)
# =* and !* are only for attrs / lists
match ERROR offset 13: Invalid operator
# redundant casts get squashed
-condition <ipaddr>&Framed-IP-Address == 127.0.0.1
+condition (ipaddr)&Framed-IP-Address == 127.0.0.1
match (&Framed-IP-Address == 127.0.0.1)
-condition <cidr>&Framed-IP-Address <= 192.168.0.0/16
+condition (cidr)&Framed-IP-Address <= 192.168.0.0/16
match ((ipv4prefix)&Framed-IP-Address <= 192.168.0.0/16)
# All IP address literals should be parsed as prefixes
#data &Event-Timestamp == 'Jan 1 2012 00:00:00 EST'
# literals are parsed when the conditions are parsed
-condition <integer>X == 1
+condition (integer)X == 1
match ERROR offset 10: Failed parsing string as type 'uint32'
#
# The RHS is a static string, so this gets mashed to a literal,
# and then statically evaluated.
#
-condition <ipaddr>127.0.0.1 == "127.0.0.1"
+condition (ipaddr)127.0.0.1 == "127.0.0.1"
match true
-condition <ipaddr>127.0.0.1 == "%{md4: 127.0.0.1}"
+condition (ipaddr)127.0.0.1 == "%{md4: 127.0.0.1}"
match (127.0.0.1 == %(cast:string "%{md4: 127.0.0.1}"))
#
# Bare %{...} is allowed.
#
-condition <ipaddr>127.0.0.1 == %{md4:127.0.0.1}
+condition (ipaddr)127.0.0.1 == %{md4:127.0.0.1}
match (127.0.0.1 == %{md4:127.0.0.1})
-condition <ipaddr>127.0.0.1 == %{md4: SELECT user FROM table WHERE user='%{User-Name}'}
+condition (ipaddr)127.0.0.1 == %{md4: SELECT user FROM table WHERE user='%{User-Name}'}
match (127.0.0.1 == %{md4: SELECT user FROM table WHERE user='%{User-Name}'})
-condition <ether> 00:11:22:33:44:55 == "00:11:22:33:44:55"
+condition (ether) 00:11:22:33:44:55 == "00:11:22:33:44:55"
match true
-condition <ether>00:11:22:33:44:55 == "%{md4:00:11:22:33:44:55}"
+condition (ether) 00:11:22:33:44:55 == "%{md4:00:11:22:33:44:55}"
match (00:11:22:33:44:55 == %(cast:string "%{md4:00:11:22:33:44:55}"))
-condition <ether> 00:XX:22:33:44:55 == 00:11:22:33:44:55
+condition (ether) 00:XX:22:33:44:55 == 00:11:22:33:44:55
match ERROR offset 12: Missing separator, expected ':'
#
#
# Both sides static data with a cast: evaluate at parse time.
#
-condition <integer>20 < 100
+condition (integer)20 < 100
match true
#
condition (&User-Name == "%{md4: blah}")
match (&User-Name == %(cast:string "%{md4: blah}"))
-condition <ipaddr>127.0.0.1 == 2130706433
+condition (ipaddr)127.0.0.1 == 2130706433
match true
# /32 suffix should be trimmed for this type
-condition <ipaddr>127.0.0.1/32 == 127.0.0.1
+condition (ipaddr)127.0.0.1/32 == 127.0.0.1
match true
-condition <ipaddr>127.0.0.1/327 == 127.0.0.1
+condition (ipaddr)127.0.0.1/327 == 127.0.0.1
match ERROR offset 9: Invalid IPv4 mask length "/327". Should be between 0-32
-condition <ipaddr>127.0.0.1/32 == 127.0.0.1
+condition (ipaddr)127.0.0.1/32 == 127.0.0.1
match true
condition (/foo/)
#
# Forbidden data types in cast
#
-condition (<vsa>"foo" == &User-Name)
+condition ((vsa)"foo" == &User-Name)
match ERROR offset 2: Invalid data type 'vsa' in cast
#
# of the same type, then re-write it so that the attribute
# is on the LHS of the condition.
#
-condition <string>"foo" == &User-Name
+condition (string)"foo" == &User-Name
match ("foo" == &User-Name)
# This used to be expr, but expr isn't a builtin, so it failed...
-condition <integer>"%{md4: 1 + 1}" < &NAS-Port
+condition (integer)"%{md4: 1 + 1}" < &NAS-Port
match (%(cast:uint32 "%{md4: 1 + 1}") < &NAS-Port)
#
condition &Filter-Id == &Framed-IP-Address
match (&Filter-Id == &Framed-IP-Address)
-condition <ipaddr>127.0.0.1 == &Filter-Id
+condition (ipaddr)127.0.0.1 == &Filter-Id
match (127.0.0.1 == &Filter-Id)
condition &Tmp-uint64-0 == &request.Foo-Stuff-Bar
#
# Casting attributes of different size
#
-condition <ipaddr>&Tmp-uint64-0 == &Framed-IP-Address
+condition (ipaddr)&Tmp-uint64-0 == &Framed-IP-Address
match ERROR offset 9: Cannot cast type 'uint64' to 'ipaddr'
#
# if the prefix is /32. We don't know enough at compile time,
# so this may be a run-time failure.
#
-condition <ipaddr>&PMIP6-Home-IPv4-HoA == &Framed-IP-Address
+condition (ipaddr)&PMIP6-Home-IPv4-HoA == &Framed-IP-Address
match ((ipaddr)&PMIP6-Home-IPv4-HoA == &Framed-IP-Address)
# but these are allowed
-condition <ether>&Tmp-uint64-0 == "%{module: foo}"
+condition (ether)&Tmp-uint64-0 == "%{module: foo}"
match ((ether)&Tmp-uint64-0 == %(cast:string "%{module: foo}"))
-condition <ipaddr>&Filter-Id == &Framed-IP-Address
+condition (ipaddr)&Filter-Id == &Framed-IP-Address
match ((ipaddr)&Filter-Id == &Framed-IP-Address)
-condition <ipaddr>&Class == &Framed-IP-Address
+condition (ipaddr)&Class == &Framed-IP-Address
match ((ipaddr)&Class == &Framed-IP-Address)
#
condition 192.168.0.0/16 > 192.168.1.2
match true
-condition <ipv4prefix>192.168.0.0/16 > 192.168.1.2
+condition (ipv4prefix)192.168.0.0/16 > 192.168.1.2
match true
-condition <ipv4prefix>&NAS-IP-Address == 192.168.0.0/24
+condition (ipv4prefix)&NAS-IP-Address == 192.168.0.0/24
match ((ipv4prefix)&NAS-IP-Address == 192.168.0.0/24)
#
# and, move the cast to the attribute, as the RHS
# is parsed as ipv4prefix
#
-condition <ipv4prefix>192.168.0.0/24 > &NAS-IP-Address
+condition (ipv4prefix)192.168.0.0/24 > &NAS-IP-Address
match (192.168.0.0/24 > &NAS-IP-Address)
#
tmpl-rules allow_unresolved=yes allow_unknown=yes
# Forcefully cast RHS bareword
-condition &User-Name == <ipaddr>192.168.0.1
+condition &User-Name == (ipaddr)192.168.0.1
match (&User-Name == 192.168.0.1)
# Forcefully cast LHS bareword
-condition <ipaddr>192.168.0.1 == &User-Name
+condition (ipaddr)192.168.0.1 == &User-Name
match (192.168.0.1 == &User-Name)
# Forcefully cast RHS single quotes
# we can cast the data during parsing, so we do that.
-condition &Framed-IP-Address == <ipaddr>'192.168.0.1'
+condition &Framed-IP-Address == (ipaddr)'192.168.0.1'
match (&Framed-IP-Address == 192.168.0.1)
# Forcefully cast LHS single quotes
-condition <ipaddr>'192.168.0.1' == &Framed-IP-Address
+condition (ipaddr)'192.168.0.1' == &Framed-IP-Address
match (192.168.0.1 == &Framed-IP-Address)
# Forcefully cast RHS double quotes
-condition &User-Name == <ipaddr>"192.168.0.1"
+condition &User-Name == (ipaddr)"192.168.0.1"
match (&User-Name == 192.168.0.1)
# Forcefully cast LHS single quotes
-condition <ipaddr>"192.168.0.1" == &User-Name
+condition (ipaddr)"192.168.0.1" == &User-Name
match (192.168.0.1 == &User-Name)
count
condition &NAS-IPv6-Address == ::
match (&NAS-IPv6-Address == ::)
-condition &NAS-IP-Address == <ipaddr>*
+condition &NAS-IP-Address == (ipaddr)*
match (&NAS-IP-Address == 0.0.0.0)
condition &NAS-IP-Address == 0.0.0.0
#
# We allow a cast for the existence check. Why not?
#
-xlat_purify <ipv6addr>::1
+xlat_purify (ipv6addr)::1
match ::1
# new casts are allowed, too.
#
# Various casts
#
-xlat_purify <ipaddr>&Filter-Id == &Framed-IP-Address
+xlat_purify (ipaddr)&Filter-Id == &Framed-IP-Address
match ((ipaddr)&Filter-Id == &Framed-IP-Address)
-#
-# We can automatically promote things as needed. But if the
-# user forces incompatible types, then that's an error.
-#
-# @todo - parsing - better errors for casts
-#
-xlat_purify <ipaddr>&Filter-Id == <blerg>&Framed-IP-Address
-match ERROR offset 23: No operand found. Expected &ref, literal, 'quoted literal', "%{expansion}", or enum value
-
-xlat_purify <blerg>&Filter-Id == "foo"
-match ERROR offset 1: No operand found. Expected &ref, literal, 'quoted literal', "%{expansion}", or enum value
-
#
# Don't normalize things
#
-xlat_purify <ipaddr>127.0.0.1 < &Framed-IP-Address
+xlat_purify (ipaddr)127.0.0.1 < &Framed-IP-Address
match (127.0.0.1 < &Framed-IP-Address)
# redundant casts get squashed
-xlat_purify <ipaddr>&Framed-IP-Address == 127.0.0.1
+xlat_purify (ipaddr)&Framed-IP-Address == 127.0.0.1
match (&Framed-IP-Address == 127.0.0.1)
-xlat_purify <cidr>&Framed-IP-Address <= 192.168.0.0/16
+xlat_purify (cidr)&Framed-IP-Address <= 192.168.0.0/16
match ((ipv4prefix)&Framed-IP-Address <= 192.168.0.0/16)
# All IP address literals should be parsed as prefixes
#match (&Event-Timestamp == 'Jan 1 2012 00:00:00 EST')
# literals are parsed when the conditions are parsed
-xlat_purify <integer>X == 1
+xlat_purify (integer)X == 1
match ERROR offset 10: Failed parsing string as type 'uint32'
#
# The RHS is a static string, so this gets mashed to a literal,
# and then statically evaluated.
#
-xlat_purify <ipaddr>127.0.0.1 == "127.0.0.1"
+xlat_purify (ipaddr)127.0.0.1 == "127.0.0.1"
match true
# LHS is IPaddr, RHS is string (malformed IP address).
# Condition code attempts to cast md4 hash to IP address resulting in an invalid comparison
-xlat_purify <ipaddr>127.0.0.1 == "%{md4: 127.0.0.1}"
+xlat_purify (ipaddr)127.0.0.1 == "%{md4: 127.0.0.1}"
match NULL
#
#
# Invalid cast from octets to ipaddr.
-xlat_purify <ipaddr>127.0.0.1 == %{md4:127.0.0.1}
+xlat_purify (ipaddr)127.0.0.1 == %{md4:127.0.0.1}
match NULL
-xlat_purify <ipaddr>127.0.0.1 == %{md4: SELECT user FROM table WHERE user='%{User-Name}'}
+xlat_purify (ipaddr)127.0.0.1 == %{md4: SELECT user FROM table WHERE user='%{User-Name}'}
match (127.0.0.1 == %{md4: SELECT user FROM table WHERE user='%{User-Name}'})
-xlat_purify <ether> 00:11:22:33:44:55 == "00:11:22:33:44:55"
+xlat_purify (ether) 00:11:22:33:44:55 == "00:11:22:33:44:55"
match true
# Invalid cast from octets to ether.
-xlat_purify <ether>00:11:22:33:44:55 == "%{md4:00:11:22:33:44:55}"
+xlat_purify (ether)00:11:22:33:44:55 == "%{md4:00:11:22:33:44:55}"
match NULL
-xlat_purify <ether> 00:XX:22:33:44:55 == 00:11:22:33:44:55
+xlat_purify (ether) 00:XX:22:33:44:55 == 00:11:22:33:44:55
match ERROR offset 12: Missing separator, expected ':'
#
#
# Both sides static data with a cast: evaluate at parse time.
#
-xlat_purify <integer>20 < 100
+xlat_purify (integer)20 < 100
match true
#
xlat_purify (&User-Name == %{md4: blah})
match (&User-Name == 0x544924d05ec4481925ba3749a096a0a7)
-xlat_purify <ipaddr>127.0.0.1 == 2130706433
+xlat_purify (ipaddr)127.0.0.1 == 2130706433
match true
# /32 suffix should be trimmed for this type
-xlat_purify <ipaddr>127.0.0.1/32 == 127.0.0.1
+xlat_purify (ipaddr)127.0.0.1/32 == 127.0.0.1
match true
-xlat_purify <ipaddr>127.0.0.1/327 == 127.0.0.1
+xlat_purify (ipaddr)127.0.0.1/327 == 127.0.0.1
match ERROR offset 9: Invalid IPv4 mask length "/327". Should be between 0-32
-xlat_purify <ipaddr>127.0.0.1/32 == 127.0.0.1
+xlat_purify (ipaddr)127.0.0.1/32 == 127.0.0.1
match true
xlat_purify (/foo/)
#
# Forbidden data types in cast
#
-xlat_purify (<vsa>"foo" == &User-Name)
+xlat_purify ((vsa)"foo" == &User-Name)
match ERROR offset 2: Invalid data type 'vsa' in cast
#
# of the same type, then re-write it so that the attribute
# is on the LHS of the condition.
#
-xlat_purify <string>"foo" == &User-Name
+xlat_purify (string)"foo" == &User-Name
match ("foo" == &User-Name)
# This used to be expr, but expr isn't a builtin, so it failed...
#
# ERROR: Failed casting 0x002ade8665c69219ca16bd108d92c8d5 to data type uint32: Invalid cast from octets to uint32. Source length 16 is greater than destination type size 4
#
-xlat_purify <integer>"%{md4: 1 + 1}" < &NAS-Port
+xlat_purify (integer)"%{md4: 1 + 1}" < &NAS-Port
match (%(cast:uint32 "%{md4: 1 + 1}") < &NAS-Port)
#
xlat_purify &Filter-Id == &Framed-IP-Address
match (&Filter-Id == &Framed-IP-Address)
-xlat_purify <ipaddr>127.0.0.1 == &Filter-Id
+xlat_purify (ipaddr)127.0.0.1 == &Filter-Id
match (127.0.0.1 == &Filter-Id)
xlat_purify &Tmp-uint64-0 == &request.Tmp-String-0
#
# Casting attributes of different size
#
-xlat_purify <ipaddr>&Tmp-uint64-0 == &Framed-IP-Address
+xlat_purify (ipaddr)&Tmp-uint64-0 == &Framed-IP-Address
match ERROR offset 9: Cannot cast type 'uint64' to 'ipaddr'
#
# if the prefix is /32. We don't know enough at compile time,
# so this may be a run-time failure.
#
-xlat_purify <ipaddr>&PMIP6-Home-IPv4-HoA == &Framed-IP-Address
+xlat_purify (ipaddr)&PMIP6-Home-IPv4-HoA == &Framed-IP-Address
match ((ipaddr)&PMIP6-Home-IPv4-HoA == &Framed-IP-Address)
# but these are allowed
-xlat_purify <ether>&Tmp-uint64-0 == "%{module: foo}"
+xlat_purify (ether)&Tmp-uint64-0 == "%{module: foo}"
match ((ether)&Tmp-uint64-0 == %(cast:string "%{module: foo}"))
-xlat_purify <ipaddr>&Filter-Id == &Framed-IP-Address
+xlat_purify (ipaddr)&Filter-Id == &Framed-IP-Address
match ((ipaddr)&Filter-Id == &Framed-IP-Address)
-xlat_purify <ipaddr>&Class == &Framed-IP-Address
+xlat_purify (ipaddr)&Class == &Framed-IP-Address
match ((ipaddr)&Class == &Framed-IP-Address)
#
match true
-xlat_purify <ipv4prefix>192.168.0.0/16 > 192.168.1.2
+xlat_purify (ipv4prefix)192.168.0.0/16 > 192.168.1.2
match true
-xlat_purify <ipv4prefix>&NAS-IP-Address == 192.168.0.0/24
+xlat_purify (ipv4prefix)&NAS-IP-Address == 192.168.0.0/24
match ((ipv4prefix)&NAS-IP-Address == 192.168.0.0/24)
#
# and, move the cast to the attribute, as the RHS
# is parsed as ipv4prefix
#
-xlat_purify <ipv4prefix>192.168.0.0/24 > &NAS-IP-Address
+xlat_purify (ipv4prefix)192.168.0.0/24 > &NAS-IP-Address
match (192.168.0.0/24 > &NAS-IP-Address)
#
match true
count
-match 332
+match 328
# If they're dumb enough to add a cast, then it will be just cast again
# to "string" before the regular expression is evaluated.
#
-xlat_purify <integer>&Tmp-String-0 =~ /foo/
+xlat_purify (integer)&Tmp-String-0 =~ /foo/
match ((uint32)&Tmp-String-0 =~ /foo/)
xlat_purify &Tmp-String-0 =~ <integer>/foo/