@@ -159,6 +159,71 @@ bool const xlat_func_chars[UINT8_MAX + 1] = {
159159};
160160
161161
162+ static int xlat_tmpl_normalize (xlat_exp_t * node )
163+ {
164+ tmpl_t * vpt = node -> vpt ;
165+
166+ /*
167+ * Any casting, etc. has to be taken care of in the xlat expression parser, and not here.
168+ */
169+ fr_assert (tmpl_rules_cast (vpt ) == FR_TYPE_NULL );
170+
171+ /*
172+ * Add in unknown attributes, by defining them in the local dictionary.
173+ */
174+ if (tmpl_is_attr (vpt )) {
175+ if (tmpl_attr_unknown_add (vpt ) < 0 ) {
176+ fr_strerror_printf ("Failed defining attribute %s" , tmpl_attr_tail_da (vpt )-> name );
177+ return -1 ;
178+ }
179+
180+ node -> flags .constant = node -> flags .pure = node -> flags .can_purify = false;
181+ return 0 ;
182+ }
183+
184+ #if 0
185+ /*
186+ * We have a nested xlat. This is likely bad. The caller SHOULD have checked for %{...}, and
187+ * created an XLAT_GROUP, and then parsed that.
188+ */
189+ if (tmpl_contains_xlat (vpt )) {
190+ fr_assert (!tmpl_needs_resolving (vpt ));
191+ fr_assert (!tmpl_contains_regex (vpt ));
192+
193+ return 0 ;
194+ }
195+ #endif
196+
197+ if (!tmpl_contains_data (vpt )) {
198+ fr_assert (!tmpl_needs_resolving (vpt ));
199+ fr_assert (!tmpl_contains_regex (vpt ));
200+
201+ return 0 ;
202+ }
203+
204+ if (tmpl_is_data_unresolved (vpt ) && (tmpl_resolve (vpt , NULL ) < 0 )) return -1 ;
205+
206+ /*
207+ * Hoist data to an XLAT_BOX instead of an XLAT_TMPL
208+ */
209+ fr_assert (tmpl_is_data (vpt ));
210+
211+ /*
212+ * Print "true" and "false" instead of "yes" and "no".
213+ */
214+ if ((tmpl_value_type (vpt ) == FR_TYPE_BOOL ) && !tmpl_value_enumv (vpt )) {
215+ tmpl_value_enumv (vpt ) = attr_expr_bool_enum ;
216+ }
217+
218+ /*
219+ * Convert the XLAT_TMPL to XLAT_BOX
220+ */
221+ xlat_exp_set_type (node , XLAT_BOX );
222+
223+ return 0 ;
224+ }
225+
226+
162227static int xlat_validate_function_arg (xlat_arg_parser_t const * arg_p , xlat_exp_t * arg , int argc )
163228{
164229 xlat_exp_t * node ;
@@ -182,40 +247,17 @@ static int xlat_validate_function_arg(xlat_arg_parser_t const *arg_p, xlat_exp_t
182247 }
183248
184249 /*
185- * @todo - check arg_p->single, and complain.
250+ * @todo - if arg->group->flags.constant AND there is more than one child, then concat in place,
251+ * etc.
186252 */
187- if (xlat_exp_next (arg -> group , node )) {
188- return 0 ;
189- }
190253
191254 /*
192- * Hoist constant factors .
255+ * Do at least somewhat of a pass of normalizing the nodes, even if there are more than one .
193256 */
194- if (node -> type == XLAT_TMPL ) {
195- /*
196- * @todo - hoist the xlat, and then check the hoisted value again.
197- * However, there seem to be few cases where this is used?
198- */
199- if (tmpl_is_xlat (node -> vpt )) {
200- return 0 ;
201-
202- /*
203- * Raw data can be hoisted to a value-box in this xlat node.
204- */
205- } else if (tmpl_is_data (node -> vpt )) {
206- xlat_exp_set_type (node , XLAT_BOX ); /* also steals the data */
207- fr_value_box_mark_safe_for (& node -> data , arg_p -> safe_for );
208-
209- } else {
210- fr_assert (!tmpl_is_data_unresolved (node -> vpt ));
211- fr_assert (!tmpl_contains_regex (node -> vpt ));
257+ xlat_exp_foreach (arg -> group , child ) {
258+ if (child -> type != XLAT_TMPL ) continue ;
212259
213- /*
214- * Can't cast the attribute / exec/ etc. to the expected data type of the
215- * argument, that has to happen at run-time.
216- */
217- return 0 ;
218- }
260+ if (xlat_tmpl_normalize (child ) < 0 ) return -1 ;
219261 }
220262
221263 /*
@@ -1264,61 +1306,6 @@ static void xlat_safe_for(xlat_exp_head_t *head, fr_value_box_safe_for_t safe_fo
12641306}
12651307#endif
12661308
1267- static int xlat_tmpl_normalize (xlat_exp_t * node )
1268- {
1269- tmpl_t * vpt = node -> vpt ;
1270-
1271- /*
1272- * Any casting, etc. has to be taken care of in the xlat expression parser, and not here.
1273- */
1274- fr_assert (tmpl_rules_cast (vpt ) == FR_TYPE_NULL );
1275-
1276- /*
1277- * Add in unknown attributes, by defining them in the local dictionary.
1278- */
1279- if (tmpl_is_attr (vpt )) {
1280- if (tmpl_attr_unknown_add (vpt ) < 0 ) {
1281- fr_strerror_printf ("Failed defining attribute %s" , tmpl_attr_tail_da (vpt )-> name );
1282- return -1 ;
1283- }
1284-
1285- node -> flags .pure = node -> flags .can_purify = false;
1286- return 0 ;
1287- }
1288-
1289- if (tmpl_is_data_unresolved (vpt ) && (tmpl_resolve (vpt , NULL ) < 0 )) return -1 ;
1290-
1291- /*
1292- * Hoist data to an XLAT_BOX instead of an XLAT_TMPL
1293- */
1294- if (tmpl_is_data (node -> vpt )) {
1295- /*
1296- * Print "true" and "false" instead of "yes" and "no".
1297- */
1298- if ((tmpl_value_type (vpt ) == FR_TYPE_BOOL ) && !tmpl_value_enumv (vpt )) {
1299- tmpl_value_enumv (vpt ) = attr_expr_bool_enum ;
1300- }
1301-
1302- /*
1303- * The name is set later, by the caller.
1304- */
1305- fr_value_box_steal (node , & node -> data , tmpl_value (vpt ));
1306- talloc_free (vpt );
1307- xlat_exp_set_type (node , XLAT_BOX );
1308-
1309- node -> flags .pure = node -> flags .can_purify = true;
1310- return 0 ;
1311- }
1312-
1313- fr_assert (!tmpl_contains_regex (vpt ));
1314-
1315- /*
1316- * We have a nested xlat. This is likely bad. The caller SHOULD have checked for %{...}, and
1317- * created an XLAT_GROUP, and then parsed that.
1318- */
1319- return 0 ;
1320- }
1321-
13221309static ssize_t xlat_tokenize_word (TALLOC_CTX * ctx , xlat_exp_t * * out , fr_sbuff_t * in , fr_sbuff_marker_t * m ,
13231310 fr_token_t quote ,
13241311 fr_sbuff_parse_rules_t const * p_rules , tmpl_rules_t const * t_rules )
0 commit comments