0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-11-15 07:38:43 +00:00
bird/conf/symbols.c

209 lines
5.2 KiB
C
Raw Normal View History

/*
* BIRD Internet Routing Daemon -- Symbol Handling
*
* (c) 1998--2000 Martin Mares <mj@ucw.cz>
* (c) 2018 Maria Matejka <mq@jmq.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
#include "nest/bird.h"
#include "conf/conf.h"
#include "conf/parser.h"
#include "lib/hash.h"
/**
* cf_push_scope - enter new scope
* @sym: symbol representing scope name
*
* If we want to enter a new scope to process declarations inside
* a nested block, we can just call cf_push_scope() to push a new
* scope onto the scope stack which will cause all new symbols to be
* defined in this scope and all existing symbols to be sought for
* in all scopes stored on the stack.
*/
void
cf_push_scope(struct cf_context *ctx, struct symbol *sym)
{
struct sym_scope *s = cfg_alloc(sizeof(struct sym_scope));
s->next = ctx->sym_scope;
ctx->sym_scope = s;
s->active = 1;
s->name = sym;
}
/**
* cf_pop_scope - leave a scope
*
* cf_pop_scope() pops the topmost scope from the scope stack,
* leaving all its symbols in the symbol table, but making them
* invisible to the rest of the config.
*/
void
cf_pop_scope(struct cf_context *ctx)
{
ctx->sym_scope->active = 0;
ctx->sym_scope = ctx->sym_scope->next;
ASSERT(ctx->sym_scope);
}
/**
* cf_symbol_class_name - get name of a symbol class
* @sym: symbol
*
* This function returns a string representing the class
* of the given symbol.
*/
char *
cf_symbol_class_name(struct symbol *sym)
{
if (cf_symbol_is_constant(sym))
return "constant";
switch (sym->class)
{
case SYM_VOID:
return "undefined";
case SYM_PROTO:
return "protocol";
case SYM_TEMPLATE:
return "protocol template";
case SYM_FUNCTION:
return "function";
case SYM_FILTER:
return "filter";
case SYM_TABLE:
return "routing table";
default:
return "unknown type";
}
}
#define SYM_KEY(n) n->name, n->scope->active
#define SYM_NEXT(n) n->next
#define SYM_EQ(a,s1,b,s2) !strcmp(a,b) && s1 == s2
#define SYM_FN(k,s) cf_hash(k)
#define SYM_ORDER 6 /* Initial */
#define SYM_REHASH sym_rehash
#define SYM_PARAMS /8, *1, 2, 2, 6, 20
HASH_DEFINE_REHASH_FN(SYM, struct symbol)
static struct symbol *
cf_new_symbol(struct cf_context *ctx, byte *c)
{
struct symbol *s;
uint l = strlen(c);
if (l > SYM_MAX_LEN)
cf_error(ctx, "Symbol too long");
s = cfg_alloc(sizeof(struct symbol) + l);
s->scope = ctx->sym_scope;
s->class = SYM_VOID;
s->def = NULL;
s->aux = 0;
strcpy(s->name, c);
if (!ctx->new_config->sym_hash.data)
HASH_INIT(ctx->new_config->sym_hash, ctx->new_config->pool, SYM_ORDER);
HASH_INSERT2(ctx->new_config->sym_hash, SYM, ctx->new_config->pool, s);
return s;
}
/**
* cf_find_symbol - find a symbol by name
* @cfg: specificed config
* @c: symbol name
*
* This functions searches the symbol table in the config @cfg for a symbol of
* given name. First it examines the current scope, then the second recent one
* and so on until it either finds the symbol and returns a pointer to its
* &symbol structure or reaches the end of the scope chain and returns %NULL to
* signify no match.
*/
struct symbol *
cf_find_symbol(struct config *cfg, byte *c)
{
struct symbol *s;
if (cfg->sym_hash.data &&
(s = HASH_FIND(cfg->sym_hash, SYM, c, 1)))
return s;
if (cfg->fallback &&
cfg->fallback->sym_hash.data &&
(s = HASH_FIND(cfg->fallback->sym_hash, SYM, c, 1)))
return s;
return NULL;
}
/**
* cf_get_symbol - get a symbol by name
* @c: symbol name
*
* This functions searches the symbol table of the currently parsed config
* (@new_config) for a symbol of given name. It returns either the already
* existing symbol or a newly allocated undefined (%SYM_VOID) symbol if no
* existing symbol is found.
*/
struct symbol *
cf_get_symbol(struct cf_context *ctx, byte *c)
{
return cf_find_symbol(ctx->new_config, c) ?: cf_new_symbol(ctx, c);
}
struct symbol *
cf_default_name(struct cf_context *ctx, char *template, int *counter)
{
char buf[SYM_MAX_LEN];
struct symbol *s;
char *perc = strchr(template, '%');
for(;;)
{
bsprintf(buf, template, ++(*counter));
s = cf_get_symbol(ctx, buf);
if (s->class == SYM_VOID)
return s;
if (!perc)
break;
}
cf_error(ctx, "Unable to generate default name");
}
/**
* cf_define_symbol - define meaning of a symbol
* @sym: symbol to be defined
* @type: symbol class to assign
* @def: class dependent data
*
* Defines new meaning of a symbol. If the symbol is an undefined
* one (%SYM_VOID), it's just re-defined to the new type. If it's defined
* in different scope, a new symbol in current scope is created and the
* meaning is assigned to it. If it's already defined in the current scope,
* an error is reported via YY_FATAL_ERROR().
*
* Result: Pointer to the newly defined symbol. If we are in the top-level
* scope, it's the same @sym as passed to the function.
*/
struct symbol *
cf_define_symbol(struct cf_context *ctx, struct symbol *sym, int type, void *def)
{
if (sym->class)
{
if (sym->scope == ctx->sym_scope)
cf_error(ctx, "Symbol already defined");
sym = cf_new_symbol(ctx, sym->name);
}
sym->class = type;
sym->def = def;
return sym;
}