extern "C" {
#endif
-ssize_t fr_condition_tokenize(const char *start, const char **error);
+typedef struct fr_cond_t fr_cond_t;
+
+typedef enum cond_op_t {
+ COND_NONE = 0,
+ COND_TRUE,
+ COND_NOT = '!',
+ COND_AND = '&',
+ COND_OR = '|'
+} cond_op_t;
+
+
+/*
+ * Allow for the following structures:
+ *
+ * FOO no OP, RHS is NULL
+ * FOO OP BAR
+ * (COND) no LHS/RHS, child is COND, child OP is TRUE
+ * (!(COND)) no LHS/RHS, child is COND, child OP is NOT
+ * (COND1 OP COND2) no LHS/RHS, next is COND2, next OP is OP
+ */
+struct fr_cond_t {
+ char *lhs;
+ char *rhs;
+ FR_TOKEN op;
+ int regex_i;
+
+ cond_op_t next_op;
+ fr_cond_t *next;
+ cond_op_t child_op;
+ fr_cond_t *child;
+};
+
+ssize_t fr_condition_tokenize(TALLOC_CTX *ctx, const char *start, fr_cond_t **head, const char **error);
/*
* In xlat.c for now
int spaces = FALSE;
char *cbuf = buf;
size_t len;
+ fr_cond_t *cond = NULL;
this = current; /* add items here */
if (!server) goto invalid_location;
}
- slen = fr_condition_tokenize(ptr, &error);
+ slen = fr_condition_tokenize(this, ptr, &cond, &error);
if (p) *p = '{';
if (slen < 0) {
}
if ((size_t) slen >= (sizeof(buf2) - 1)) {
- ERROR("%s[%d]: Condition is too large after \"%s\"",
+ talloc_free(cond);
+ DEBUGE("%s[%d]: Condition is too large after \"%s\"",
filename, *lineno, buf1);
return -1;
}
t2 = T_BARE_WORD;
if (gettoken(&ptr, buf3, sizeof(buf3)) != T_LCBRACE) {
- ERROR("%s[%d]: Expected '{'",
+ talloc_free(cond);
+ DEBUGE("%s[%d]: Expected '{'",
filename, *lineno);
return -1;
}
case T_LCBRACE:
section_alloc:
- if (seen_too_much(filename, *lineno, ptr)) return -1;
+ if (seen_too_much(filename, *lineno, ptr)) {
+ if (cond) talloc_free(cond);
+ return -1;
+ }
css = cf_section_alloc(this, buf1,
t2 == T_LCBRACE ? NULL : buf2);
css->item.filename = filename;
css->item.lineno = *lineno;
+ if (cond) {
+ cf_data_add_internal(css, "if", cond, NULL, FALSE);
+ cond = NULL; /* eaten by the above line */
+ }
+
/*
* The current section is now the child section.
*/
#include <freeradius-devel/radiusd.h>
#include <freeradius-devel/modpriv.h>
#include <freeradius-devel/modcall.h>
+#include <freeradius-devel/parser.h>
#include <freeradius-devel/rad_assert.h>
int grouptype; /* after mc */
modcallable *children;
CONF_SECTION *cs;
- value_pair_map_t *map;
+ value_pair_map_t *map; /* update */
+ const fr_cond_t *cond; /* if/elsif */
} modgroup;
typedef struct {
if ((child->type == MOD_IF) || (child->type == MOD_ELSIF)) {
int condition = TRUE;
const char *p = child->name;
+ modgroup *g;
+
+ g = mod_callabletogroup(child);
+ rad_assert(g->cond != NULL);
RDEBUG2("%.*s? %s %s",
stack.pointer + 1, modcall_spaces,
int grouptype,
const char **modname)
{
-#ifdef WITH_UNLANG
- int result;
-#endif
const char *modrefname;
modsingle *single;
modcallable *csingle;
#ifdef WITH_UNLANG
} else if (strcmp(modrefname, "if") == 0) {
+ modgroup *g;
+
if (!cf_section_name2(cs)) {
cf_log_err(ci, "'if' without condition.");
return NULL;
grouptype);
if (!csingle) return NULL;
csingle->type = MOD_IF;
-
- if (!radius_evaluate_condition(NULL, 0, 0, modname,
- FALSE, &result)) {
- modcallable_free(&csingle);
- return NULL;
- }
*modname = name2;
+ g = mod_callabletogroup(csingle);
+ g->cond = cf_data_find(g->cs, "if");
+ rad_assert(g->cond != NULL);
+
return csingle;
} else if (strcmp(modrefname, "elsif") == 0) {
+ modgroup *g;
+
if (parent &&
((parent->type == MOD_LOAD_BALANCE) ||
(parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
grouptype);
if (!csingle) return NULL;
csingle->type = MOD_ELSIF;
-
- if (!radius_evaluate_condition(NULL, 0, 0, modname,
- FALSE, &result)) {
- modcallable_free(&csingle);
- return NULL;
- }
*modname = name2;
+ g = mod_callabletogroup(csingle);
+ g->cond = cf_data_find(g->cs, "if");
+ rad_assert(g->cond != NULL);
+
return csingle;
} else if (strcmp(modrefname, "else") == 0) {
memset(g, 0, sizeof(*g));
g->grouptype = grouptype;
g->children = NULL;
+ g->cs = cs;
c = mod_grouptocallable(g);
c->parent = parent;
#endif
#endif
-typedef enum cond_op_t {
- COND_NONE = 0,
- COND_TRUE,
- COND_NOT = '!',
- COND_AND = '&',
- COND_OR = '|'
-} cond_op_t;
-
-
-typedef struct cond_t cond_t;
-
-/*
- * Allow for the following structures:
- *
- * FOO no OP, RHS is NULL
- * FOO OP BAR
- * (COND) no LHS/RHS, child is COND, child OP is TRUE
- * (!(COND)) no LHS/RHS, child is COND, child OP is NOT
- * (COND1 OP COND2) no LHS/RHS, next is COND2, next OP is OP
- */
-struct cond_t {
- char *lhs;
- char *rhs;
- FR_TOKEN op;
- int regex_i;
-
- cond_op_t next_op;
- cond_t *next;
- cond_op_t child_op;
- cond_t *child;
-};
-
-DIAG_OFF(unused-function)
-static void cond_debug(const cond_t *c)
+W_UNUSEDDEC_OFF
+static void cond_debug(const fr_cond_t *c)
{
next:
* @param[out] error the parse error (if any)
* @return length of the string skipped, or when negative, the offset to the offending error
*/
-static ssize_t condition_tokenize(TALLOC_CTX *ctx, const char *start, int brace, cond_t **pcond, const char **error)
+static ssize_t condition_tokenize(TALLOC_CTX *ctx, const char *start, int brace, fr_cond_t **pcond, const char **error)
{
ssize_t slen;
const char *p = start;
- cond_t *c;
+ fr_cond_t *c;
COND_DEBUG("START %s", p);
- c = talloc_zero(ctx, cond_t);
+ c = talloc_zero(ctx, fr_cond_t);
rad_assert(c != NULL);
p += 2;
} else if (p[1] == '*') {
+ /*
+ * FOO !* BAR
+ *
+ * is really !(FOO)
+ *
+ * FIXME: we should
+ * really re-write it...
+ */
c->op = T_OP_CMP_FALSE;
p += 2;
/** Tokenize a conditional check
*
+ * @param[in] ctx for talloc
* @param[in] start the start of the string to process. Should be "(..."
+ * @param[out] head the parsed condition structure
* @param[out] error the parse error (if any)
* @return length of the string skipped, or when negative, the offset to the offending error
*/
-ssize_t fr_condition_tokenize(const char *start, const char **error)
+ssize_t fr_condition_tokenize(TALLOC_CTX *ctx, const char *start, fr_cond_t **head, const char **error)
{
- ssize_t slen;
- cond_t *c = NULL;
-
- slen = condition_tokenize(NULL, start, FALSE, &c, error);
- if (slen <= 0) return slen;
-
- if (!c) {
- COND_DEBUG("RETURN %d", __LINE__);
- *error = "Empty condition is invalid";
- return -1;
- }
-
- talloc_free(c);
-
- return slen;
+ return condition_tokenize(ctx, start, FALSE, head, error);
}
{
ssize_t slen;
const char *error = NULL;
+ fr_cond_t *cond;
- slen = fr_condition_tokenize(input, &error);
+ slen = fr_condition_tokenize(NULL, input, &cond, &error);
if (slen <= 0) {
snprintf(output, outlen, "ERROR offset %d '%s'", (int) -slen, error);
return;
}
+ talloc_free(cond);
+
input += slen;
if (*input != '\0') {
snprintf(output, outlen, "ERROR offset %d 'Too much text'", (int) slen);