cf_stack_frame_t *frame = &stack->frame[stack->depth];
CONF_SECTION *parent = frame->current;
char *buff[4];
+ tmpl_rules_t t_rules;
/*
* Short names are nicer.
*/
buff[1] = stack->buff[1];
buff[2] = stack->buff[2];
+ buff[3] = stack->buff[3];
dict = virtual_server_dict_by_child_ci(cf_section_to_item(parent));
+ t_rules = (tmpl_rules_t) {
+ .attr = {
+ .dict_def = dict,
+ .allow_unresolved = true,
+ .allow_unknown = true
+ }
+ };
/*
* fr_cond_tokenize needs the current section, so we
* create it first. We don't pass a name2, as it hasn't
cf_filename_set(cs, frame->filename);
cf_lineno_set(cs, frame->lineno);
+ RULES_VERIFY(cs, &t_rules);
+
/*
- * Skip (...) to find the {
+ * Keep parsing the condition until we hit EOL, or a real error.
*/
while (true) {
- tmpl_rules_t t_rules = {
- .attr = {
- .dict_def = dict,
- .allow_unresolved = true,
- .allow_unknown = true
- }
- };
-
- RULES_VERIFY(cs, &t_rules);
+ ssize_t end;
+ char *spaces, *text;
+ /*
+ * Parse the condition. If it succeeded, stop
+ * trying to expand the buffer.
+ */
slen = fr_cond_tokenize(cs, &cond,
&t_rules, &FR_SBUFF_IN(ptr, strlen(ptr)));
- if (slen < 0) {
- ssize_t end = -slen;
+ if (slen > 0) break;
- /*
- * For paranoia, check that "end" is valid.
- */
- if ((ptr + end) > (stack->buff[0] + stack->bufsize)) {
- cf_log_err(parent, "Failed parsing condition");
- return NULL;
- }
-
- /*
- * The condition failed to parse at EOL.
- * Therefore we try to read another line.
- */
- if (!ptr[end]) {
- int rcode;
+ end = -slen;
+ fr_assert((ptr + end) < (stack->buff[0] + stack->bufsize));
- memcpy(&stack->fill, &ptr, sizeof(ptr)); /* const issues */
- stack->fill += end;
- rcode = cf_file_fill(stack);
- if (rcode < 0) return NULL;
- continue;
- }
+ /*
+ * We hit EOL, so the parse error is really "read more data".
+ */
+ if (!ptr[end]) {
+ int rcode;
- /*
- * @todo - suppress leading spaces
- */
+ memcpy(&stack->fill, &ptr, sizeof(ptr)); /* const issues */
+ stack->fill += end;
+ rcode = cf_file_fill(stack);
+ if (rcode < 0) return NULL;
+ continue;
}
- break;
- }
-
- /*
- * We either read the whole line, OR there was a
- * different error parsing the condition.
- */
- if (slen < 0) {
- char *spaces, *text;
+ /*
+ * We didn't hit EOL, so it's a real error.
+ */
+ parse_error:
fr_canonicalize_error(cs, &spaces, &text, slen, ptr);
cf_log_err(cs, "Parse error in condition");
return NULL;
}
- /*
- * The input file buffer may be larger
- * than the buffer we put the condition
- * into.
- */
- if ((size_t) slen >= (stack->bufsize - 1)) {
- cf_log_err(cs, "Condition is too large after \"%s\"", buff[1]);
- talloc_free(cs);
- return NULL;
- }
+ fr_assert((size_t) slen < (stack->bufsize - 1));
/*
- * Copy the expanded and parsed condition into buff[2].
- * Then suppress any trailing whitespace.
+ * Save the parsed condition (minus trailing whitespace)
+ * into a buffer.
*/
memcpy(buff[2], ptr, slen);
buff[2][slen] = '\0';
p--;
}
+ /*
+ * Now that we know how big the condition is, see if we
+ * need to expand the variables. If so, free the old
+ * condition, expand the variables, and reparse the
+ * condition.
+ */
+ if (strchr(ptr, '$') != NULL) {
+ ssize_t my_slen;
+
+ talloc_free(cond);
+
+ if (!cf_expand_variables(frame->filename, frame->lineno, parent,
+ buff[3], stack->bufsize, buff[2], slen, NULL)) {
+ fr_strerror_const("Failed expanding configuration variable");
+ return NULL;
+ }
+
+ my_slen = fr_cond_tokenize(cs, &cond, &t_rules, &FR_SBUFF_IN(buff[3], strlen(buff[3])));
+ if (my_slen <= 0) {
+ ptr = buff[3];
+ slen = my_slen;
+ goto parse_error;
+ }
+ }
+
MEM(cs->name2 = talloc_typed_strdup(cs, buff[2]));
cs->name2_quote = T_BARE_WORD;
*/
ssize_t fr_cond_tokenize(CONF_SECTION *cs, fr_cond_t **head, tmpl_rules_t const *rules, fr_sbuff_t *in)
{
- char buffer[8192];
- ssize_t diff, slen;
+ ssize_t slen;
+ fr_sbuff_t our_in = FR_SBUFF(in);
*head = NULL;
- if (!cf_expand_variables(cf_filename(cs), cf_lineno(cs), cf_item_to_section(cf_parent(cs)),
- buffer, sizeof(buffer),
- fr_sbuff_current(in), fr_sbuff_remaining(in), NULL)) {
- fr_strerror_const("Failed expanding configuration variable");
- return 0;
- }
-
- diff = fr_sbuff_remaining(in) - strlen(buffer); /* Hack so that we appear to consume more of the string */
- slen = cond_tokenize(cs, head, cs, &FR_SBUFF_IN(buffer, strlen(buffer)), 0, rules);
+ slen = cond_tokenize(cs, head, cs, &our_in, 0, rules);
if (slen <= 0) return slen;
/*
cond_reparent(*head, NULL);
}
- return slen + diff;
+ return fr_sbuff_set(in, &our_in);
}
/** Initialise a cond iterator