--- conf/cf-lex.l | 74 +++++++++++++++++++++++++++++++++++++++++-------- conf/conf.h | 37 ++++++++++++++++++++----- conf/confbase.Y | 1 - 3 files changed, 93 insertions(+), 19 deletions(-)
diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 1d6cae2c..9b7df0b2 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -73,10 +73,10 @@ static uint cf_hash(const byte *c); #define KW_FN(k) cf_hash(k) #define KW_ORDER 8 /* Fixed */ -#define SYM_KEY(n) n->name, n->scope->active +#define SYM_KEY(n) n->name, n->scope->active, n->net_type #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_EQ(a,s1,t1,b,s2,t2) !strcmp(a,b) && s1 == s2 && t1 == t2 +#define SYM_FN(k,s,t) cf_hash(k) #define SYM_ORDER 6 /* Initial */ #define SYM_REHASH sym_rehash @@ -544,7 +544,7 @@ check_eof(void) } static struct symbol * -cf_new_symbol(const byte *c) +cf_new_symbol(const byte *c, const u8 net_type) { struct symbol *s; @@ -553,7 +553,11 @@ cf_new_symbol(const byte *c) cf_error("Symbol too long"); s = cfg_allocz(sizeof(struct symbol) + l + 1); - *s = (struct symbol) { .scope = conf_this_scope, .class = SYM_VOID, }; + *s = (struct symbol) { + .scope = conf_this_scope, + .class = SYM_VOID, + .net_type = net_type + }; strcpy(s->name, c); if (!new_config->sym_hash.data) @@ -566,6 +570,21 @@ cf_new_symbol(const byte *c) return s; } +struct symbol * +cf_find_typed_symbol(const struct config *cfg, const byte *c, const u8 net_type) +{ + struct symbol *s, *typed; + s = HASH_FIND(cfg->sym_hash, SYM, c, 1, NET_ANY); + if (!s) return NULL; + if (net_type == NET_ANY) return s; + if (!(s->flags & SYM_FLAG_IS_TYPED)) return NULL; + + typed = HASH_FIND(cfg->sym_hash, SYM, c, 1, net_type); + if (!typed) return NULL; + cf_assert(s->scope == typed->scope, "bug: wrong scope"); + return typed; +} + /** * cf_find_symbol - find a symbol by name * @cfg: specificed config @@ -583,13 +602,13 @@ cf_find_symbol(const struct config *cfg, const byte *c) struct symbol *s; if (cfg->sym_hash.data && - (s = HASH_FIND(cfg->sym_hash, SYM, c, 1))) + (s = HASH_FIND(cfg->sym_hash, SYM, c, 1, NET_ANY))) return s; /* In CLI command parsing, fallback points to the current config, otherwise it is NULL. */ if (cfg->fallback && cfg->fallback->sym_hash.data && - (s = HASH_FIND(cfg->fallback->sym_hash, SYM, c, 1))) + (s = HASH_FIND(cfg->fallback->sym_hash, SYM, c, 1, NET_ANY))) return s; return NULL; @@ -607,7 +626,7 @@ cf_find_symbol(const struct config *cfg, const byte *c) struct symbol * cf_get_symbol(const byte *c) { - return cf_find_symbol(new_config, c) ?: cf_new_symbol(c); + return cf_find_symbol(new_config, c) ?: cf_new_symbol(c, NET_ANY); } /** @@ -625,13 +644,46 @@ cf_localize_symbol(struct symbol *sym) return sym; /* If the scope is the current, it is already defined in this scope. */ - if (sym->scope == conf_this_scope) - cf_error("Symbol already defined"); + if (sym->scope == conf_this_scope) { + if (sym->flags & SYM_FLAGS_TYPED) + return sym; + else + cf_error("Symbol already defined"); + } /* Not allocated here yet, doing it now. */ - return cf_new_symbol(sym->name); + return cf_new_symbol(sym->name, NET_ANY); } +struct symbol * +cf_type_symbol(struct symbol *sym, const int class, const u8 net_type) +{ + if (net_type == NET_ANY) { + if (sym->flags & SYM_FLAG_IS_TYPED) + cf_error("generic definitions not allowed for typed symbol"); + else + return sym; + } + + cf_assert(class & SYM_TYPEABLE, "Symbol not typeable"); + + if (sym->flags & SYM_FLAG_IS_TYPED && sym->class != class) + cf_error("Mixed symbol classes"); + + if (HASH_FIND(new_config->sym_hash, SYM, sym->name, 1, net_type)) + cf_error("Symbol already defined for this channel type"); + + struct symbol *typed = cf_new_symbol(sym->name, net_type); + + sym->class = class; + sym->flags |= SYM_FLAG_IS_TYPED; + + cf_assert(typed->scope == new_config->root_scope, "wrong scope for typed symbol"); + + return typed; +} + + struct symbol * cf_default_name(char *template, int *counter) { diff --git a/conf/conf.h b/conf/conf.h index 39015e62..0104d070 100644 --- a/conf/conf.h +++ b/conf/conf.h @@ -15,6 +15,8 @@ #include "lib/resource.h" #include "lib/timer.h" +#define cf_assert(cond, ...) do { if (!(cond)) cf_error(__VA_ARGS__); } while (0) + /* Configuration structure */ struct config { @@ -112,6 +114,7 @@ struct symbol { struct symbol *next; struct sym_scope *scope; int class; /* SYM_* */ + u8 net_type; /* Routing table network type (NET_*), 0 for undefined */ uint flags; /* SYM_FLAG_* */ union { @@ -184,31 +187,51 @@ void cf_lex_init(int is_cli, struct config *c); void cf_lex_unwind(void); struct symbol *cf_find_symbol(const struct config *cfg, const byte *c); +struct symbol *cf_find_typed_symbol(const struct config *cfg, const byte *c, const u8 net_type); struct symbol *cf_get_symbol(const byte *c); struct symbol *cf_default_name(char *template, int *counter); struct symbol *cf_localize_symbol(struct symbol *sym); +struct symbol *cf_type_symbol(struct symbol *sym, const int class, const u8 net_type); /** - * cf_define_symbol - define meaning of a symbol + * cf_define_typed_symbol - define meaning of a symbol * @sym: symbol to be defined * @type: symbol class to assign * @def: class dependent data + * @net_type: NET_* network type * * 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 cf_error(). + * an error is reported via cf_error(). If net_type is not %NET_ANY, a the + * typed version of the symbol will be returned. + * + * 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. + */ +#define cf_define_typed_symbol(sym_, type_, var_, def_, net_type_) ({ \ + struct symbol *main_sym = cf_localize_symbol(sym_); \ + struct symbol *typed = cf_type_symbol(main_sym, type_, net_type_); \ + typed->class = type_; \ + typed->var_ = def_; \ + typed; }) + +/** + * cf_define_symbol - define meaning of a symbol + * @sym: symbol to be defined + * @type: symbol class to assign + * @def: class dependent data + * + * This is a simple wrapper around %cf_define_typed_symbol, with + * net_type always passed as %NET_ANY. * * 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. */ -#define cf_define_symbol(sym_, type_, var_, def_) ({ \ - struct symbol *sym = cf_localize_symbol(sym_); \ - sym->class = type_; \ - sym->var_ = def_; \ - sym; }) +#define cf_define_symbol(sym_, type_, var_, def_) \ + cf_define_typed_symbol(sym_, type_, var_, def_, NET_ANY) void cf_push_scope(struct symbol *); void cf_pop_scope(void); diff --git a/conf/confbase.Y b/conf/confbase.Y index 75158927..eda5b9c1 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -33,7 +33,6 @@ check_u16(uint val) cf_error("Value %u out of range (0-65535)", val); } -#define cf_assert(cond, ...) do { if (!(cond)) cf_error(__VA_ARGS__); } while (0) static inline void cf_assert_symbol(const struct symbol *sym, uint class) { switch (class) { case SYM_PROTO: cf_assert(sym->class == SYM_PROTO, "Protocol name required"); break; -- 2.24.0