From: Alan T. DeKok Date: Mon, 6 Jun 2022 17:04:37 +0000 (-0400) Subject: update fr_calc_unary_op(), add xlat ~, -, !, cleanups, and tests X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bda7993394367c4b5e3044e31e65866163aede33;p=thirdparty%2Ffreeradius-server.git update fr_calc_unary_op(), add xlat ~, -, !, cleanups, and tests --- diff --git a/src/lib/unlang/xlat_expr.c b/src/lib/unlang/xlat_expr.c index fd35945181a..a889cecdafc 100644 --- a/src/lib/unlang/xlat_expr.c +++ b/src/lib/unlang/xlat_expr.c @@ -1061,51 +1061,78 @@ static xlat_action_t xlat_func_logical(TALLOC_CTX *ctx, fr_dcursor_t *out, } -static xlat_arg_parser_t const unary_not_xlat_args[] = { - { .required = true, .single = true, .type = FR_TYPE_BOOL }, +static xlat_arg_parser_t const unary_op_xlat_args[] = { + { .required = true, .single = true, .concat = true }, XLAT_ARG_PARSER_TERMINATOR }; -static xlat_action_t xlat_func_unary_not(TALLOC_CTX *ctx, fr_dcursor_t *out, - UNUSED xlat_ctx_t const *xctx, - UNUSED request_t *request, fr_value_box_list_t *in) +static xlat_action_t xlat_func_unary_op(TALLOC_CTX *ctx, fr_dcursor_t *out, + UNUSED xlat_ctx_t const *xctx, + request_t *request, fr_value_box_list_t *in, fr_token_t op) { - fr_value_box_t *dst, *a; + int rcode; + fr_value_box_t *dst, *group, *vb; - a = fr_dlist_head(in); - MEM(dst = fr_value_box_alloc(ctx, FR_TYPE_BOOL, attr_expr_bool_enum, a->tainted)); - dst->vb_bool = !a->vb_bool; + /* + * We do some basic type checks here. + */ + group = fr_dlist_head(in); + vb = fr_dlist_head(&group->vb_group); + + if (!fr_type_is_leaf(vb->type) || fr_type_is_variable_size(vb->type)) { + REDEBUG("Cannot perform operation on data type %s", fr_type_to_str(vb->type)); + return XLAT_ACTION_FAIL; + } + + MEM(dst = fr_value_box_alloc_null(ctx)); + + /* + * We rely on this function to do the remainder of the type checking. + */ + rcode = fr_value_calc_unary_op(dst, dst, op, vb); + if ((rcode < 0) || fr_type_is_null(dst->type)) { + RPEDEBUG("Failed calculating result, returning NULL"); + fr_value_box_init_null(dst); + } fr_dcursor_append(out, dst); return XLAT_ACTION_DONE; } -static xlat_arg_parser_t const unary_minus_xlat_args[] = { - { .required = true, .concat = true }, - XLAT_ARG_PARSER_TERMINATOR -}; -static xlat_action_t xlat_func_unary_minus(TALLOC_CTX *ctx, fr_dcursor_t *out, - UNUSED xlat_ctx_t const *xctx, - request_t *request, fr_value_box_list_t *in) +static xlat_action_t xlat_func_unary_not(TALLOC_CTX *ctx, fr_dcursor_t *out, + UNUSED xlat_ctx_t const *xctx, + UNUSED request_t *request, fr_value_box_list_t *in) { - int rcode; - fr_value_box_t *dst, a, *b; + fr_value_box_t *dst, *group, *vb; - MEM(dst = fr_value_box_alloc_null(ctx)); - - fr_value_box_init(&a, FR_TYPE_INT64, NULL, false); - b = fr_dlist_head(in); + group = fr_dlist_head(in); + vb = fr_dlist_head(&group->vb_group); - rcode = fr_value_calc_binary_op(dst, dst, FR_TYPE_NULL, &a, T_SUB, b); - if (rcode < 0) { - RPEDEBUG("Failed calculating result, returning NULL"); - } + /* + * Don't call calc_unary_op(), because we want the enum names. + */ + MEM(dst = fr_value_box_alloc(ctx, FR_TYPE_BOOL, attr_expr_bool_enum, false)); + dst->vb_bool = !fr_value_box_is_truthy(vb); fr_dcursor_append(out, dst); return XLAT_ACTION_DONE; } +static xlat_action_t xlat_func_unary_minus(TALLOC_CTX *ctx, fr_dcursor_t *out, + xlat_ctx_t const *xctx, + request_t *request, fr_value_box_list_t *in) +{ + return xlat_func_unary_op(ctx, out, xctx, request, in, T_SUB); +} + +static xlat_action_t xlat_func_unary_complement(TALLOC_CTX *ctx, fr_dcursor_t *out, + UNUSED xlat_ctx_t const *xctx, + request_t *request, fr_value_box_list_t *in) +{ + return xlat_func_unary_op(ctx, out, xctx, request, in, T_COMPLEMENT); +} + /** Convert XLAT_BOX arguments to XLAT_TMPL * * xlat_tokenize() just makes all unknown arguments into XLAT_BOX, of data type FR_TYPE_STRING. Whereas @@ -1244,6 +1271,15 @@ do { \ xlat_internal(xlat); \ } while (0) +#define XLAT_REGISTER_UNARY(_op, _xlat, _func) \ +do { \ + if (!(xlat = xlat_register(NULL, _xlat, _func, XLAT_FLAG_PURE))) return -1; \ + xlat_func_args(xlat, unary_op_xlat_args); \ + xlat_internal(xlat); \ + xlat_print_set(xlat, xlat_expr_print_unary); \ + xlat->token = _op; \ +} while (0) + int xlat_register_expressions(void) { xlat_t *xlat; @@ -1274,23 +1310,16 @@ int xlat_register_expressions(void) XLAT_REGISTER_NARY_OP(T_LAND, logical_and, logical); XLAT_REGISTER_NARY_OP(T_LOR, logical_or, logical); + XLAT_REGISTER_MONO("rcode", xlat_func_rcode, xlat_func_rcode_arg); + /* * -EXPR + * ~EXPR * !EXPR */ - if (!(xlat = xlat_register(NULL, "unary_minus", xlat_func_unary_minus, XLAT_FLAG_PURE))) return -1; - xlat_func_args(xlat, unary_minus_xlat_args); - xlat_internal(xlat); - xlat_print_set(xlat, xlat_expr_print_unary); - xlat->token = T_SUB; - - if (!(xlat = xlat_register(NULL, "unary_not", xlat_func_unary_not, XLAT_FLAG_PURE))) return -1; - xlat_func_args(xlat, unary_not_xlat_args); - xlat_internal(xlat); - xlat_print_set(xlat, xlat_expr_print_unary); - xlat->token = T_NOT; - - XLAT_REGISTER_MONO("rcode", xlat_func_rcode, xlat_func_rcode_arg); + XLAT_REGISTER_UNARY(T_SUB, "unary_minus", xlat_func_unary_minus); + XLAT_REGISTER_UNARY(T_COMPLEMENT, "unary_complement", xlat_func_unary_complement); + XLAT_REGISTER_UNARY(T_NOT, "unary_not", xlat_func_unary_not); return 0; } @@ -1466,6 +1495,14 @@ static ssize_t tokenize_unary(xlat_exp_head_t *head, xlat_exp_t **out, fr_sbuff_ c = '-'; goto check_for_double; + } + else if (fr_sbuff_next_if_char(&our_in, '~')) { /* unary complement */ + fmt = "~"; + func = xlat_func_find("unary_complement", 16); + fr_assert(func != NULL); + c = '~'; + goto check_for_double; + } else if (fr_sbuff_next_if_char(&our_in, '+')) { /* ignore unary + */ c = '+'; diff --git a/src/lib/util/calc.c b/src/lib/util/calc.c index b149a506672..7a1449828b1 100644 --- a/src/lib/util/calc.c +++ b/src/lib/util/calc.c @@ -589,6 +589,15 @@ static const fr_type_t upcast_cmp[FR_TYPE_MAX + 1][FR_TYPE_MAX + 1] = { }, }; +static const fr_type_t upcast_unsigned[FR_TYPE_MAX + 1] = { + [FR_TYPE_BOOL] = FR_TYPE_INT8, + [FR_TYPE_UINT8] = FR_TYPE_INT16, + [FR_TYPE_UINT16] = FR_TYPE_INT32, + [FR_TYPE_UINT32] = FR_TYPE_INT64, + [FR_TYPE_UINT64] = FR_TYPE_INT64, + [FR_TYPE_SIZE] = FR_TYPE_INT64, +}; + static int invalid_type(fr_type_t type) { fr_strerror_printf("Cannot perform mathematical operations on data type %s", @@ -1879,26 +1888,23 @@ int fr_value_calc_assignment_op(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_token_t return 0; } -/** Calculate DST OP +/** Calculate unary operations * - * e.g. "foo ++". - * - * This is done by doing some sanity checks, and then just calling - * the "binary operation" function. + * e.g. "foo++", or "-foo". */ -int fr_value_calc_unary_op(TALLOC_CTX *ctx, fr_value_box_t *box, fr_token_t op) +int fr_value_calc_unary_op(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_token_t op, fr_value_box_t const *src) { int rcode = -1; fr_value_box_t one; - if (!fr_type_is_numeric(box->type)) return invalid_type(box->type); + if (!fr_type_is_numeric(src->type)) return invalid_type(src->type); if (op == T_OP_INCRM) { /* * Add 1 or subtract 1 means RHS is always 1. */ - fr_value_box_init(&one, box->type, NULL, false); - switch (box->type) { + fr_value_box_init(&one, src->type, NULL, false); + switch (src->type) { case FR_TYPE_UINT8: one.vb_uint8 = 1; break; @@ -1948,14 +1954,15 @@ int fr_value_calc_unary_op(TALLOC_CTX *ctx, fr_value_box_t *box, fr_token_t op) return -1; } - rcode = fr_value_calc_binary_op(ctx, box, box->type, box, T_ADD, &one); - - return handle_result(box->type, op, rcode); + rcode = fr_value_calc_binary_op(ctx, dst, src->type, src, T_ADD, &one); + return handle_result(dst->type, op, rcode); } else if (op == T_COMPLEMENT) { + if (dst != src) fr_value_box_init(dst, src->type, src->enumv, src->tainted); + #undef COMP -#define COMP(_type, _field) case FR_TYPE_ ## _type: box->vb_ ##_field = ~box->vb_ ##_field; break - switch (box->type) { +#define COMP(_type, _field) case FR_TYPE_ ## _type: dst->vb_ ##_field = (_field ## _t) ~src->vb_ ##_field; break + switch (src->type) { COMP(UINT8, uint8); COMP(UINT16, uint16); COMP(UINT32, uint32); @@ -1974,15 +1981,33 @@ int fr_value_calc_unary_op(TALLOC_CTX *ctx, fr_value_box_t *box, fr_token_t op) return 0; } else if (op == T_SUB) { - fr_value_box_init(&one, box->type, NULL, box->tainted); /* init to zero */ + fr_type_t type = src->type; - rcode = fr_value_calc_binary_op(ctx, box, box->type, &one, T_SUB, box); + if ((dst != src) && !fr_type_is_signed(src->type)) { + type = upcast_unsigned[src->type]; - return handle_result(box->type, op, rcode); + if (type == FR_TYPE_NULL) { + type = src->type; /* hope for the best */ + } + } + + fr_value_box_init(&one, type, NULL, src->tainted); /* init to zero */ + rcode = fr_value_calc_binary_op(ctx, dst, type, &one, T_SUB, src); + + return handle_result(dst->type, op, rcode); + + } else if (op == T_NOT) { + bool value = fr_value_box_is_truthy(src); + + fr_value_box_clear(dst); + fr_value_box_init(dst, FR_TYPE_BOOL, NULL, false); // @todo - add enum! + dst->vb_bool = !value; + + return 0; } else { invalid: - return handle_result(box->type, op, ERR_INVALID); + return handle_result(src->type, op, ERR_INVALID); } } diff --git a/src/lib/util/calc.h b/src/lib/util/calc.h index 201806d4475..f25ff809002 100644 --- a/src/lib/util/calc.h +++ b/src/lib/util/calc.h @@ -36,7 +36,7 @@ int fr_value_calc_binary_op(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t hint int fr_value_calc_assignment_op(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_token_t op, fr_value_box_t const *src) CC_HINT(nonnull(2,4)); -int fr_value_calc_unary_op(TALLOC_CTX *ctx, fr_value_box_t *box, fr_token_t op) CC_HINT(nonnull(1)); +int fr_value_calc_unary_op(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_token_t op, fr_value_box_t const *src) CC_HINT(nonnull(1)); int fr_value_calc_list_op(TALLOC_CTX *ctx, fr_value_box_t *box, fr_token_t op, fr_value_box_list_t const *list); diff --git a/src/tests/unit/xlat/purify.txt b/src/tests/unit/xlat/purify.txt index 044ac8df102..45ae70d7ec4 100644 --- a/src/tests/unit/xlat/purify.txt +++ b/src/tests/unit/xlat/purify.txt @@ -1,5 +1,23 @@ proto-dictionary radius +xlat_purify ~(uint8) 1 +match 254 + +xlat_purify ~(uint8) 2 +match 253 + +# +# Signed! +# +xlat_purify -(int8) 1 +match -1 + +xlat_purify !1 +match false + +xlat_purify (uint8) 1 + -(int8) 1 +match 0 + # # xlat_expr, but purified # @@ -163,4 +181,4 @@ xlat_purify !true match false count -match 69 +match 79