]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
update fr_calc_unary_op(), add xlat ~, -, !, cleanups, and tests
authorAlan T. DeKok <aland@freeradius.org>
Mon, 6 Jun 2022 17:04:37 +0000 (13:04 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Mon, 6 Jun 2022 21:39:04 +0000 (17:39 -0400)
src/lib/unlang/xlat_expr.c
src/lib/util/calc.c
src/lib/util/calc.h
src/tests/unit/xlat/purify.txt

index fd35945181aa512e9bb00cd4bba8323b6f36fb7e..a889cecdafcf53cbce6c749c49050372a224df5a 100644 (file)
@@ -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 = '+';
index b149a5066720514aa4e5e23ed196f3b198ea02a2..7a1449828b19ce8fe7767c88e6a3602c64c9d8a9 100644 (file)
@@ -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);
        }
 
 }
index 201806d4475cd0778766c4b6146103b7c1522948..f25ff809002945424ca033c6f6c95d6aa959a854 100644 (file)
@@ -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);
 
index 044ac8df102ac9977fd89d456cae27f0b2947550..45ae70d7ec44cfb6cd4fb6ff236e218c70d1b92c 100644 (file)
@@ -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