]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Add XLAT_ARGS helper macro to pull xlat arguments from the input list
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Tue, 15 Nov 2022 19:15:51 +0000 (13:15 -0600)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Tue, 15 Nov 2022 19:15:51 +0000 (13:15 -0600)
src/include/build.h
src/lib/unlang/xlat.h
src/lib/unlang/xlat_builtin.c

index b796f84b64a8fb837920e80ee8a4e55e1e48dc87..ce5c3c210d586da619f9ec44f48be452c8c491be 100644 (file)
@@ -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, <comp.std.c> (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
  *
  */
index c76cff2afb33ff32883971e6c9c15c2b1a9ed86b..7153b7833833219176d6e269951c3226aa901380 100644 (file)
@@ -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_<num> macro to expand
+ *
+ *
+ * @param[in] XLAT_ARGS_N      the name of the macro to expand.
+ *                             Created by concating XLAT_ARGS_ + <number of variadic arguments>.
+ * @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,
index 69123af30d8e8e0bb5fed71c2bddc880e05dc09d..84684955d5d352b3e2d4d8cd563c780522581010 100644 (file)
@@ -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