diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/evaluate.c | 21 | ||||
-rw-r--r-- | src/expression.c | 39 | ||||
-rw-r--r-- | src/parser_bison.y | 9 | ||||
-rw-r--r-- | src/rule.c | 39 |
4 files changed, 88 insertions, 20 deletions
diff --git a/src/evaluate.c b/src/evaluate.c index 40a9292f..cc8eac83 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -168,7 +168,6 @@ static struct table *table_lookup_global(struct eval_ctx *ctx) static int expr_evaluate_symbol(struct eval_ctx *ctx, struct expr **expr) { struct error_record *erec; - struct symbol *sym; struct table *table; struct set *set; struct expr *new; @@ -183,14 +182,6 @@ static int expr_evaluate_symbol(struct eval_ctx *ctx, struct expr **expr) return -1; } break; - case SYMBOL_DEFINE: - sym = symbol_lookup((*expr)->scope, (*expr)->identifier); - if (sym == NULL) - return expr_error(ctx->msgs, *expr, - "undefined identifier '%s'", - (*expr)->identifier); - new = expr_clone(sym->expr); - break; case SYMBOL_SET: ret = cache_update(ctx->nf_sock, ctx->cache, ctx->cmd->op, ctx->msgs, ctx->debug_mask & NFT_DEBUG_NETLINK, ctx->octx); @@ -1776,6 +1767,16 @@ static int expr_evaluate_meta(struct eval_ctx *ctx, struct expr **exprp) return expr_evaluate_primary(ctx, exprp); } +static int expr_evaluate_variable(struct eval_ctx *ctx, struct expr **exprp) +{ + struct expr *new = expr_clone((*exprp)->sym->expr); + + expr_free(*exprp); + *exprp = new; + + return expr_evaluate(ctx, exprp); +} + static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr) { if (ctx->debug_mask & NFT_DEBUG_EVALUATION) { @@ -1791,6 +1792,8 @@ static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr) switch ((*expr)->ops->type) { case EXPR_SYMBOL: return expr_evaluate_symbol(ctx, expr); + case EXPR_VARIABLE: + return expr_evaluate_variable(ctx, expr); case EXPR_SET_REF: return 0; case EXPR_VALUE: diff --git a/src/expression.c b/src/expression.c index 393c1b2b..ee75284e 100644 --- a/src/expression.c +++ b/src/expression.c @@ -254,6 +254,45 @@ struct expr *symbol_expr_alloc(const struct location *loc, return expr; } +static void variable_expr_print(const struct expr *expr, + struct output_ctx *octx) +{ + nft_print(octx, "$%s", expr->sym->identifier); +} + +static void variable_expr_clone(struct expr *new, const struct expr *expr) +{ + new->scope = expr->scope; + new->sym = expr->sym; + + expr->sym->refcnt++; +} + +static void variable_expr_destroy(struct expr *expr) +{ + expr->sym->refcnt--; +} + +static const struct expr_ops variable_expr_ops = { + .type = EXPR_VARIABLE, + .name = "variable", + .print = variable_expr_print, + .clone = variable_expr_clone, + .destroy = variable_expr_destroy, +}; + +struct expr *variable_expr_alloc(const struct location *loc, + struct scope *scope, struct symbol *sym) +{ + struct expr *expr; + + expr = expr_alloc(loc, &variable_expr_ops, &invalid_type, + BYTEORDER_INVALID, 0); + expr->scope = scope; + expr->sym = sym; + return expr; +} + static void constant_expr_print(const struct expr *expr, struct output_ctx *octx) { diff --git a/src/parser_bison.y b/src/parser_bison.y index 58bc6805..ee6729f1 100644 --- a/src/parser_bison.y +++ b/src/parser_bison.y @@ -771,8 +771,6 @@ common_block : INCLUDE QUOTED_STRING stmt_separator { struct scope *scope = current_scope(state); - /* ignore missing identifier */ - symbol_unbind(scope, $2); symbol_bind(scope, $2, $4); xfree($2); } @@ -2584,16 +2582,17 @@ match_stmt : relational_expr variable_expr : '$' identifier { struct scope *scope = current_scope(state); + struct symbol *sym; - if (symbol_lookup(scope, $2) == NULL) { + sym = symbol_get(scope, $2); + if (!sym) { erec_queue(error(&@2, "unknown identifier '%s'", $2), state->msgs); xfree($2); YYERROR; } - $$ = symbol_expr_alloc(&@$, SYMBOL_DEFINE, - scope, $2); + $$ = variable_expr_alloc(&@$, scope, sym); xfree($2); } ; @@ -467,6 +467,7 @@ void scope_release(const struct scope *scope) struct symbol *sym, *next; list_for_each_entry_safe(sym, next, &scope->symbols, list) { + assert(sym->refcnt == 1); list_del(&sym->list); xfree(sym->identifier); expr_free(sym->expr); @@ -481,22 +482,48 @@ void symbol_bind(struct scope *scope, const char *identifier, struct expr *expr) sym = xzalloc(sizeof(*sym)); sym->identifier = xstrdup(identifier); sym->expr = expr; + sym->refcnt = 1; - list_add_tail(&sym->list, &scope->symbols); + list_add(&sym->list, &scope->symbols); } -int symbol_unbind(struct scope *scope, const char *identifier) +struct symbol *symbol_get(const struct scope *scope, const char *identifier) { struct symbol *sym; sym = symbol_lookup(scope, identifier); if (!sym) - return -1; + return NULL; + + sym->refcnt++; + return sym; +} + +static void symbol_put(struct symbol *sym) +{ + if (--sym->refcnt == 0) { + xfree(sym->identifier); + expr_free(sym->expr); + xfree(sym); + } +} + +static void symbol_remove(struct symbol *sym) +{ list_del(&sym->list); - xfree(sym->identifier); - expr_free(sym->expr); - xfree(sym); + symbol_put(sym); +} + +int symbol_unbind(const struct scope *scope, const char *identifier) +{ + struct symbol *sym, *next; + + list_for_each_entry_safe(sym, next, &scope->symbols, list) { + if (!strcmp(sym->identifier, identifier)) + symbol_remove(sym); + } + return 0; } |