/** 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
*/
#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
*
*/
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,