From: Alan T. DeKok Date: Fri, 16 Aug 2024 20:06:25 +0000 (-0400) Subject: allow cast to same data type to mean "print value, not enum name" X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4499f524843b20b424babf9f8a812e760fd45236;p=thirdparty%2Ffreeradius-server.git allow cast to same data type to mean "print value, not enum name" because I tried to use it, and it didn't work. So the logical next step is to make it work. --- diff --git a/src/lib/server/tmpl_tokenize.c b/src/lib/server/tmpl_tokenize.c index b5d9d4abf5e..7add1c3d07a 100644 --- a/src/lib/server/tmpl_tokenize.c +++ b/src/lib/server/tmpl_tokenize.c @@ -3593,15 +3593,33 @@ int tmpl_cast_set(tmpl_t *vpt, fr_type_t dst_type) goto check_types; case TMPL_TYPE_ATTR: - src_type = tmpl_attr_tail_da(vpt)->type; + { + fr_dict_attr_t const *da = tmpl_attr_tail_da(vpt); + /* + * If the attribute has an enum, then the cast means "use the raw value, and not + * the enum name". + */ + if (da->type == dst_type) { + if (da->flags.has_value) goto done; + return 0; + } + src_type = da->type; + } /* - * Suppress casts where they are duplicate. + * Suppress casts where they are duplicate, unless there's an enumv. In which case the + * cast means "don't print the enumv value, just print the raw data". */ check_types: if (src_type == dst_type) { - tmpl_rules_cast(vpt) = FR_TYPE_NULL; + /* + * Cast with enumv means "use the raw value, and not the enum name". + */ + if (tmpl_rules_enumv(vpt)) { + tmpl_rules_enumv(vpt) = NULL; + goto done; + } return 0; } diff --git a/src/lib/unlang/xlat_expr.c b/src/lib/unlang/xlat_expr.c index c2ab44cdad6..f1349db83d9 100644 --- a/src/lib/unlang/xlat_expr.c +++ b/src/lib/unlang/xlat_expr.c @@ -2589,7 +2589,8 @@ static fr_slen_t tokenize_field(xlat_exp_head_t *head, xlat_exp_t **out, fr_sbuf * case, the cast will convert the value-box to one _without_ an enumv entry, which means * that the value will get printed as its underlying data type, and not as the enum name. */ - if (da && !da->flags.has_value && (da->type == cast_type)) { + if (da && (da->type == cast_type)) { + tmpl_cast_set(vpt, cast_type); cast_type = FR_TYPE_NULL; } diff --git a/src/tests/keywords/cast-integer b/src/tests/keywords/cast-integer index 09ba3fd1fbc..c5cd8f79e8c 100644 --- a/src/tests/keywords/cast-integer +++ b/src/tests/keywords/cast-integer @@ -30,3 +30,16 @@ if (&foo != (&zscore + (uint64) 0x10000000000000)) { test_fail } +&Service-Type := ::Framed-User + +if ((uint32) &Service-Type != 2) { + test_fail +} + +# +# Cast Service-Type to it's underlying data type, +# which means "don't print the enum name". +# +if ("%{(uint32) &Service-Type}" != "2") { + test_fail +} diff --git a/src/tests/unit/xlat/expr.txt b/src/tests/unit/xlat/expr.txt index f192bfa56e5..b09b6a35a0d 100644 --- a/src/tests/unit/xlat/expr.txt +++ b/src/tests/unit/xlat/expr.txt @@ -136,8 +136,12 @@ xlat_expr 5 + 5 - 10 match ((5 + 5) - 10) xlat_expr (integer) &Service-Type -match %cast(uint32, &Service-Type) +match (uint32)&Service-Type +# +# Wrapping the RHS in brackets means that the parse doesn't hoist +# things, and thus can't add the cast to the tmpl. +# xlat_expr (uint32) (&Service-Type) match %cast(uint32, &Service-Type)