From: Arran Cudbard-Bell Date: Tue, 15 Nov 2022 19:15:51 +0000 (-0600) Subject: Add XLAT_ARGS helper macro to pull xlat arguments from the input list X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7edcd29d2365af6f3ebb7607dbb37d430082096c;p=thirdparty%2Ffreeradius-server.git Add XLAT_ARGS helper macro to pull xlat arguments from the input list --- diff --git a/src/include/build.h b/src/include/build.h index b796f84b64a..ce5c3c210d5 100644 --- a/src/include/build.h +++ b/src/include/build.h @@ -191,9 +191,16 @@ do { \ /** The ubiquitous stringify macros * */ -#define XSTRINGIFY(x) #x -#define STRINGIFY(x) XSTRINGIFY(x) -#define JOINSTR(x,y) XSTRINGIFY(x ## y) +#define XSTRINGIFY(x) #x +#define STRINGIFY(x) XSTRINGIFY(x) +#define JOINSTR(x,y) XSTRINGIFY(x ## y) + +/** Join two values without stringifying + * + * Useful for calling different macros based on the output of +*/ +#define _JOIN(x,y) x ## y +#define JOIN(x,y) _JOIN(x,y) /** Helper for initialising arrays of string literals */ @@ -211,6 +218,42 @@ do { \ #define F128(_idx, _val) F64(_idx, _val), F64(_idx + 64, _val) #define F256(_idx, _val) F128(_idx, _val), F128(_idx + 128, _val) +/** Variadic macro framework + */ + +/** + * The VA_NARG macro evaluates to the number of arguments that have been + * passed to it. + * + * Laurent Deniau, "__VA_NARG__," 17 January 2006, (29 November 2007). + */ +#define VA_ARG_N( \ + _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \ + _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \ + _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \ + _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \ + _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \ + _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \ + _61,_62,_63,N,...) N + +#define VA_RSEQ_N() \ + 63,62,61,60, \ + 59,58,57,56,55,54,53,52,51,50, \ + 49,48,47,46,45,44,43,42,41,40, \ + 39,38,37,36,35,34,33,32,31,30, \ + 29,28,27,26,25,24,23,22,21,20, \ + 19,18,17,16,15,14,13,12,11,10, \ + 9,8,7,6,5,4,3,2,1,0 + +#define _VA_NARG(...) VA_ARG_N(__VA_ARGS__) + +/** Return the number of variadic arguments up to 64 + * + * @param[in] ... Variadic arguments to count. + */ +#define VA_NARG(...) _VA_NARG(__VA_ARGS__, VA_RSEQ_N()) + + /** Pass caller information to the function * */ diff --git a/src/lib/unlang/xlat.h b/src/lib/unlang/xlat.h index c76cff2afb3..7153b783383 100644 --- a/src/lib/unlang/xlat.h +++ b/src/lib/unlang/xlat.h @@ -267,6 +267,98 @@ typedef int (*xlat_thread_detach_t)(xlat_thread_inst_ctx_t const *xctx); typedef size_t (*xlat_escape_legacy_t)(request_t *request, char *out, size_t outlen, char const *in, void *arg); +/** Set the next argument to the next item in the input list or NULL + * + * @param[in] _list we're extracting arguments from. + * @param[in] _prev argument. + * @param[in] _curr argument we're populating. + */ +#define XLAT_ARGS_NEXT(_list, _prev, _curr) *(_curr) = likely(*(_prev) != NULL) ? fr_value_box_list_next(_list, *(_prev)) : NULL + +#define XLAT_ARGS_1(_list, _a) \ + *(_a) = fr_value_box_list_head(_list) + +#define XLAT_ARGS_2(_list, _a, _b) \ + do { \ + *(_a) = fr_value_box_list_head(_list); \ + XLAT_ARGS_NEXT(_list, _a, _b); \ + } while (0); + +#define XLAT_ARGS_3(_list, _a, _b, _c) \ + do { \ + *(_a) = fr_value_box_list_head(_list); \ + XLAT_ARGS_NEXT(_list, _a, _b); \ + XLAT_ARGS_NEXT(_list, _b, _c); \ + } while (0); + +#define XLAT_ARGS_4(_list, _a, _b, _c, _d) \ + do { \ + *(_a) = fr_value_box_list_head(_list); \ + XLAT_ARGS_NEXT(_list, _a, _b); \ + XLAT_ARGS_NEXT(_list, _b, _c); \ + XLAT_ARGS_NEXT(_list, _c, _d); \ + } while (0); + +#define XLAT_ARGS_5(_list, _a, _b, _c, _d, _e) \ + do { \ + *(_a) = fr_value_box_list_head(_list); \ + XLAT_ARGS_NEXT(_list, _a, _b); \ + XLAT_ARGS_NEXT(_list, _b, _c); \ + XLAT_ARGS_NEXT(_list, _c, _d); \ + XLAT_ARGS_NEXT(_list, _d, _e); \ + } while (0); + +#define XLAT_ARGS_6(_list, _a, _b, _c, _d, _e, _f) \ + do { \ + *(_a) = fr_value_box_list_head(_list); \ + XLAT_ARGS_NEXT(_list, _a, _b); \ + XLAT_ARGS_NEXT(_list, _b, _c); \ + XLAT_ARGS_NEXT(_list, _c, _d); \ + XLAT_ARGS_NEXT(_list, _d, _e); \ + XLAT_ARGS_NEXT(_list, _e, _f); \ + } while (0); + +#define XLAT_ARGS_7(_list, _a, _b, _c, _d, _e, _f, _g) \ + do { \ + *(_a) = fr_value_box_list_head(_list); \ + XLAT_ARGS_NEXT(_list, _a, _b); \ + XLAT_ARGS_NEXT(_list, _b, _c); \ + XLAT_ARGS_NEXT(_list, _c, _d); \ + XLAT_ARGS_NEXT(_list, _d, _e); \ + XLAT_ARGS_NEXT(_list, _e, _f); \ + XLAT_ARGS_NEXT(_list, _f, _g); \ + } while (0); + +#define XLAT_ARGS_8(_list, _a, _b, _c, _d, _e, _f, _g, _h) \ + do { \ + *(_a) = fr_value_box_list_head(_list); \ + XLAT_ARGS_NEXT(_list, _a, _b); \ + XLAT_ARGS_NEXT(_list, _b, _c); \ + XLAT_ARGS_NEXT(_list, _c, _d); \ + XLAT_ARGS_NEXT(_list, _d, _e); \ + XLAT_ARGS_NEXT(_list, _e, _f); \ + XLAT_ARGS_NEXT(_list, _f, _g); \ + XLAT_ARGS_NEXT(_list, _g, _h); \ + } while (0); + +/** Trampoline macro for selecting which XLAT_ARGS_ macro to expand + * + * + * @param[in] XLAT_ARGS_N the name of the macro to expand. + * Created by concating XLAT_ARGS_ + . + * @param[in] _in The input list of value boxes. + * @param[in] ... The variadic arguments themselves. + */ +#define _XLAT_ARGS_X(XLAT_ARGS_N, _list, ...) XLAT_ARGS_N(_list, __VA_ARGS__) + +/** Populate local variables with value boxes from the input list + * + * @param[in] _list input list to pull arguments from. + * @param[in] ... 1-8 output boxes pointers `fr_value_box_t **` + * e.g. `XLAT_ARGS(in, &arg0, &arg1, &argN)``. + */ +#define XLAT_ARGS(_list, ...) _XLAT_ARGS_X(JOIN(XLAT_ARGS_, VA_NARG(__VA_ARGS__)), _list, __VA_ARGS__) + int xlat_fmt_get_vp(fr_pair_t **out, request_t *request, char const *name); ssize_t xlat_eval(char *out, size_t outlen, request_t *request, char const *fmt, xlat_escape_legacy_t escape, diff --git a/src/lib/unlang/xlat_builtin.c b/src/lib/unlang/xlat_builtin.c index 69123af30d8..84684955d5d 100644 --- a/src/lib/unlang/xlat_builtin.c +++ b/src/lib/unlang/xlat_builtin.c @@ -1863,17 +1863,25 @@ static xlat_action_t xlat_func_lpad(UNUSED TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, FR_DLIST_HEAD(fr_value_box_list) *args) { - fr_value_box_t *values = fr_value_box_list_head(args); - FR_DLIST_HEAD(fr_value_box_list) *list = &values->vb_group; - fr_value_box_t *pad = fr_value_box_list_next(args, values); + fr_value_box_t *values; + fr_value_box_t *pad; + fr_value_box_t *fill; + + FR_DLIST_HEAD(fr_value_box_list) *list; + + size_t pad_len; + + char const *fill_str = NULL; + size_t fill_len = 0; + + fr_value_box_t *in = NULL; + + XLAT_ARGS(args, &values, &pad, &fill); + /* coverity[dereference] */ - size_t pad_len = (size_t)pad->vb_uint64; + list = &values->vb_group; /* coverity[dereference] */ - fr_value_box_t *fill = fr_value_box_list_next(args, pad); - char const *fill_str = NULL; - size_t fill_len = 0; - - fr_value_box_t *in = NULL; + pad_len = (size_t)pad->vb_uint64; /* * Fill is optional