1998-11-27 19:35:50 +00:00
|
|
|
/*
|
|
|
|
* BIRD -- Configuration Lexer
|
|
|
|
*
|
2000-01-17 11:52:50 +00:00
|
|
|
* (c) 1998--2000 Martin Mares <mj@ucw.cz>
|
1998-11-27 19:35:50 +00:00
|
|
|
*
|
|
|
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
|
|
|
*/
|
|
|
|
|
|
|
|
%{
|
1998-12-06 23:10:28 +00:00
|
|
|
#undef REJECT /* Avoid name clashes */
|
1998-11-27 19:35:50 +00:00
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdlib.h>
|
1998-12-06 23:10:28 +00:00
|
|
|
#include <stdarg.h>
|
1998-11-27 19:35:50 +00:00
|
|
|
|
|
|
|
#include "nest/bird.h"
|
1999-11-15 11:35:41 +00:00
|
|
|
#include "nest/route.h"
|
|
|
|
#include "filter/filter.h"
|
1998-11-27 19:35:50 +00:00
|
|
|
#include "conf/conf.h"
|
|
|
|
#include "conf/cf-parse.tab.h"
|
2000-01-17 11:52:50 +00:00
|
|
|
#include "lib/string.h"
|
1998-11-27 19:35:50 +00:00
|
|
|
|
2000-04-28 15:12:03 +00:00
|
|
|
struct keyword {
|
1998-11-27 19:35:50 +00:00
|
|
|
byte *name;
|
|
|
|
int value;
|
|
|
|
struct keyword *next;
|
2000-04-28 15:12:03 +00:00
|
|
|
};
|
|
|
|
|
1999-01-10 00:18:32 +00:00
|
|
|
#include "conf/keywords.h"
|
1998-11-27 19:35:50 +00:00
|
|
|
|
|
|
|
#define KW_HASH_SIZE 64
|
1999-11-30 14:03:36 +00:00
|
|
|
static struct keyword *kw_hash[KW_HASH_SIZE];
|
|
|
|
static int kw_hash_inited;
|
|
|
|
|
1998-11-27 19:35:50 +00:00
|
|
|
#define SYM_HASH_SIZE 128
|
|
|
|
#define SYM_MAX_LEN 32
|
|
|
|
|
1999-11-04 13:51:52 +00:00
|
|
|
struct sym_scope {
|
|
|
|
struct sym_scope *next; /* Next on scope stack */
|
|
|
|
struct symbol *name; /* Name of this scope */
|
|
|
|
int active; /* Currently entered */
|
|
|
|
};
|
|
|
|
static struct sym_scope *conf_this_scope;
|
|
|
|
|
1999-02-05 21:37:34 +00:00
|
|
|
int conf_lino;
|
|
|
|
|
1998-11-27 19:35:50 +00:00
|
|
|
static int cf_hash(byte *c);
|
|
|
|
static struct symbol *cf_find_sym(byte *c, unsigned int h0);
|
|
|
|
|
1998-12-06 11:59:18 +00:00
|
|
|
linpool *cfg_mem;
|
1998-11-27 19:35:50 +00:00
|
|
|
|
|
|
|
int (*cf_read_hook)(byte *buf, unsigned int max);
|
|
|
|
|
|
|
|
#define YY_INPUT(buf,result,max) result = cf_read_hook(buf, max);
|
|
|
|
#define YY_NO_UNPUT
|
|
|
|
#define YY_FATAL_ERROR(msg) cf_error(msg)
|
|
|
|
|
|
|
|
%}
|
|
|
|
|
|
|
|
%option noyywrap
|
|
|
|
|
Parse CLI commands. We use the same parser as for configuration files (because
we want to allow filter and similar complex constructs to be used in commands
and we should avoid code duplication), only with CLI_MARKER token prepended
before the whole input.
Defined macro CF_CLI(cmd, args, help) for defining CLI commands in .Y files.
The first argument specifies the command itself, the remaining two arguments
are copied to the help file (er, will be copied after the help file starts
to exist). This macro automatically creates a skeleton rule for the command,
you only need to append arguments as in:
CF_CLI(STEAL MONEY, <$>, [[Steal <$> US dollars or equivalent in any other currency]]): NUM {
cli_msg(0, "%d$ stolen", $3);
} ;
Also don't forget to reset lexer state between inputs.
1999-10-31 17:47:47 +00:00
|
|
|
%x COMMENT CCOMM CLI
|
1998-11-27 19:35:50 +00:00
|
|
|
|
|
|
|
ALPHA [a-zA-Z_]
|
|
|
|
DIGIT [0-9]
|
|
|
|
XIGIT [0-9a-fA-F]
|
|
|
|
ALNUM [a-zA-Z_0-9]
|
|
|
|
WHITE [ \t]
|
|
|
|
|
|
|
|
%%
|
|
|
|
|
|
|
|
{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+ {
|
1999-08-03 19:36:06 +00:00
|
|
|
#ifdef IPV6
|
|
|
|
if (ipv4_pton_u32(yytext, &cf_lval.i32))
|
|
|
|
return RTRID;
|
|
|
|
cf_error("Invalid IPv4 address %s", yytext);
|
|
|
|
#else
|
1998-11-27 19:35:50 +00:00
|
|
|
if (ip_pton(yytext, &cf_lval.a))
|
|
|
|
return IPA;
|
1999-08-03 19:36:06 +00:00
|
|
|
cf_error("Invalid IP address %s", yytext);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
({XIGIT}*::|({XIGIT}*:){3,})({XIGIT}*|{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+) {
|
|
|
|
#ifdef IPV6
|
|
|
|
if (ip_pton(yytext, &cf_lval.a))
|
|
|
|
return IPA;
|
|
|
|
cf_error("Invalid IP address %s", yytext);
|
|
|
|
#else
|
|
|
|
cf_error("This is an IPv4 router, therefore IPv6 addresses are not supported");
|
|
|
|
#endif
|
1998-11-27 19:35:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
0x{DIGIT}+ {
|
|
|
|
char *e;
|
|
|
|
long int l;
|
|
|
|
errno = 0;
|
|
|
|
l = strtoul(yytext+2, &e, 16);
|
|
|
|
if (e && *e || errno == ERANGE || (long int)(int) l != l)
|
|
|
|
cf_error("Number out of range");
|
|
|
|
cf_lval.i = l;
|
|
|
|
return NUM;
|
|
|
|
}
|
|
|
|
|
|
|
|
{DIGIT}+ {
|
|
|
|
char *e;
|
|
|
|
long int l;
|
|
|
|
errno = 0;
|
|
|
|
l = strtoul(yytext, &e, 10);
|
|
|
|
if (e && *e || errno == ERANGE || (long int)(int) l != l)
|
|
|
|
cf_error("Number out of range");
|
|
|
|
cf_lval.i = l;
|
|
|
|
return NUM;
|
|
|
|
}
|
|
|
|
|
|
|
|
{ALPHA}{ALNUM}* {
|
|
|
|
unsigned int h = cf_hash(yytext);
|
|
|
|
struct keyword *k = kw_hash[h & (KW_HASH_SIZE-1)];
|
|
|
|
while (k)
|
|
|
|
{
|
|
|
|
if (!strcmp(k->name, yytext))
|
1999-11-15 11:35:41 +00:00
|
|
|
{
|
|
|
|
if (k->value > 0)
|
|
|
|
return k->value;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
cf_lval.i = -k->value;
|
|
|
|
return ENUM;
|
|
|
|
}
|
|
|
|
}
|
1998-11-27 19:35:50 +00:00
|
|
|
k=k->next;
|
|
|
|
}
|
|
|
|
cf_lval.s = cf_find_sym(yytext, h);
|
|
|
|
return SYM;
|
|
|
|
}
|
|
|
|
|
1999-12-02 12:04:39 +00:00
|
|
|
<CLI>(.|\n) {
|
Parse CLI commands. We use the same parser as for configuration files (because
we want to allow filter and similar complex constructs to be used in commands
and we should avoid code duplication), only with CLI_MARKER token prepended
before the whole input.
Defined macro CF_CLI(cmd, args, help) for defining CLI commands in .Y files.
The first argument specifies the command itself, the remaining two arguments
are copied to the help file (er, will be copied after the help file starts
to exist). This macro automatically creates a skeleton rule for the command,
you only need to append arguments as in:
CF_CLI(STEAL MONEY, <$>, [[Steal <$> US dollars or equivalent in any other currency]]): NUM {
cli_msg(0, "%d$ stolen", $3);
} ;
Also don't forget to reset lexer state between inputs.
1999-10-31 17:47:47 +00:00
|
|
|
BEGIN(INITIAL);
|
|
|
|
return CLI_MARKER;
|
|
|
|
}
|
|
|
|
|
2000-05-25 14:58:38 +00:00
|
|
|
[={}:;,()+*/%-<>~\[\]?] {
|
1998-11-27 19:35:50 +00:00
|
|
|
return yytext[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
["][^"\n]*["] {
|
1998-11-29 21:59:37 +00:00
|
|
|
yytext[yyleng-1] = 0;
|
2000-01-16 23:36:53 +00:00
|
|
|
cf_lval.t = cfg_strdup(yytext+1);
|
1998-11-27 19:35:50 +00:00
|
|
|
return TEXT;
|
|
|
|
}
|
|
|
|
|
|
|
|
["][^"\n]*\n cf_error("Unterminated string");
|
|
|
|
|
|
|
|
<INITIAL,COMMENT><<EOF>> return END;
|
|
|
|
|
|
|
|
{WHITE}+
|
|
|
|
|
1999-03-29 19:04:14 +00:00
|
|
|
\n conf_lino++;
|
1998-11-27 19:35:50 +00:00
|
|
|
|
1999-02-13 21:34:33 +00:00
|
|
|
# BEGIN(COMMENT);
|
1998-11-27 19:35:50 +00:00
|
|
|
|
1999-02-13 21:34:33 +00:00
|
|
|
\/\* BEGIN(CCOMM);
|
1998-11-27 19:35:50 +00:00
|
|
|
|
|
|
|
. cf_error("Unknown character");
|
|
|
|
|
|
|
|
<COMMENT>\n {
|
1999-02-05 21:37:34 +00:00
|
|
|
conf_lino++;
|
1998-11-27 19:35:50 +00:00
|
|
|
BEGIN(INITIAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
<COMMENT>.
|
|
|
|
|
|
|
|
<CCOMM>\*\/ BEGIN(INITIAL);
|
1999-02-05 21:37:34 +00:00
|
|
|
<CCOMM>\n conf_lino++;
|
1998-11-27 19:35:50 +00:00
|
|
|
<CCOMM>\/\* cf_error("Comment nesting not supported");
|
|
|
|
<CCOMM><<EOF>> cf_error("Unterminated comment");
|
|
|
|
<CCOMM>.
|
|
|
|
|
2000-03-10 20:21:12 +00:00
|
|
|
\!\= return NEQ;
|
|
|
|
\<\= return LEQ;
|
|
|
|
\>\= return GEQ;
|
|
|
|
|
1998-11-27 19:35:50 +00:00
|
|
|
%%
|
|
|
|
|
|
|
|
static int
|
|
|
|
cf_hash(byte *c)
|
|
|
|
{
|
|
|
|
unsigned int h = 13;
|
|
|
|
|
|
|
|
while (*c)
|
|
|
|
h = (h * 37) + *c++;
|
|
|
|
return h;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct symbol *
|
|
|
|
cf_find_sym(byte *c, unsigned int h0)
|
|
|
|
{
|
|
|
|
unsigned int h = h0 & (SYM_HASH_SIZE-1);
|
1999-11-30 14:03:36 +00:00
|
|
|
struct symbol *s, **ht;
|
1998-11-27 19:35:50 +00:00
|
|
|
int l;
|
|
|
|
|
1999-11-30 14:03:36 +00:00
|
|
|
if (ht = new_config->sym_hash)
|
|
|
|
{
|
|
|
|
for(s = ht[h]; s; s=s->next)
|
|
|
|
if (!strcmp(s->name, c) && s->scope->active)
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
if (new_config->sym_fallback)
|
|
|
|
{
|
|
|
|
/* We know only top-level scope is active */
|
|
|
|
for(s = new_config->sym_fallback[h]; s; s=s->next)
|
1999-11-04 13:51:52 +00:00
|
|
|
if (!strcmp(s->name, c) && s->scope->active)
|
Parse CLI commands. We use the same parser as for configuration files (because
we want to allow filter and similar complex constructs to be used in commands
and we should avoid code duplication), only with CLI_MARKER token prepended
before the whole input.
Defined macro CF_CLI(cmd, args, help) for defining CLI commands in .Y files.
The first argument specifies the command itself, the remaining two arguments
are copied to the help file (er, will be copied after the help file starts
to exist). This macro automatically creates a skeleton rule for the command,
you only need to append arguments as in:
CF_CLI(STEAL MONEY, <$>, [[Steal <$> US dollars or equivalent in any other currency]]): NUM {
cli_msg(0, "%d$ stolen", $3);
} ;
Also don't forget to reset lexer state between inputs.
1999-10-31 17:47:47 +00:00
|
|
|
return s;
|
1999-11-30 14:03:36 +00:00
|
|
|
}
|
|
|
|
if (!ht)
|
|
|
|
ht = new_config->sym_hash = cfg_allocz(SYM_HASH_SIZE * sizeof(struct keyword *));
|
1998-11-27 19:35:50 +00:00
|
|
|
l = strlen(c);
|
|
|
|
if (l > SYM_MAX_LEN)
|
|
|
|
cf_error("Symbol too long");
|
1998-11-29 21:59:37 +00:00
|
|
|
s = cfg_alloc(sizeof(struct symbol) + l);
|
1999-11-30 14:03:36 +00:00
|
|
|
s->next = ht[h];
|
|
|
|
ht[h] = s;
|
1999-11-04 13:51:52 +00:00
|
|
|
s->scope = conf_this_scope;
|
1998-11-27 19:35:50 +00:00
|
|
|
s->class = SYM_VOID;
|
|
|
|
s->def = NULL;
|
1998-11-27 21:32:45 +00:00
|
|
|
s->aux = 0;
|
1998-11-27 19:35:50 +00:00
|
|
|
strcpy(s->name, c);
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
1999-05-17 20:06:19 +00:00
|
|
|
struct symbol *
|
|
|
|
cf_find_symbol(byte *c)
|
|
|
|
{
|
|
|
|
return cf_find_sym(c, cf_hash(c));
|
|
|
|
}
|
|
|
|
|
1998-11-27 21:07:02 +00:00
|
|
|
struct symbol *
|
2000-01-17 11:52:50 +00:00
|
|
|
cf_default_name(char *template, int *counter)
|
1998-11-27 21:07:02 +00:00
|
|
|
{
|
|
|
|
char buf[32];
|
|
|
|
struct symbol *s;
|
2000-01-17 11:52:50 +00:00
|
|
|
char *perc = strchr(template, '%');
|
1998-11-27 21:07:02 +00:00
|
|
|
|
2000-01-17 11:52:50 +00:00
|
|
|
for(;;)
|
1998-11-27 21:07:02 +00:00
|
|
|
{
|
2000-01-17 11:52:50 +00:00
|
|
|
bsprintf(buf, template, ++(*counter));
|
1998-11-27 21:07:02 +00:00
|
|
|
s = cf_find_sym(buf, cf_hash(buf));
|
2000-01-17 11:52:50 +00:00
|
|
|
if (!s)
|
|
|
|
break;
|
|
|
|
if (s->class == SYM_VOID)
|
|
|
|
return s;
|
|
|
|
if (!perc)
|
|
|
|
break;
|
1998-11-27 21:07:02 +00:00
|
|
|
}
|
2000-01-17 11:52:50 +00:00
|
|
|
cf_error("Unable to generate default name");
|
1998-11-27 21:07:02 +00:00
|
|
|
}
|
|
|
|
|
1999-05-17 20:06:19 +00:00
|
|
|
void
|
|
|
|
cf_define_symbol(struct symbol *sym, int type, void *def)
|
|
|
|
{
|
|
|
|
if (sym->class)
|
|
|
|
cf_error("Symbol already defined");
|
|
|
|
sym->class = type;
|
|
|
|
sym->def = def;
|
|
|
|
}
|
|
|
|
|
1999-11-30 14:03:36 +00:00
|
|
|
static void
|
|
|
|
cf_lex_init_kh(void)
|
|
|
|
{
|
|
|
|
struct keyword *k;
|
|
|
|
|
|
|
|
for(k=keyword_list; k->name; k++)
|
|
|
|
{
|
|
|
|
unsigned h = cf_hash(k->name) & (KW_HASH_SIZE-1);
|
|
|
|
k->next = kw_hash[h];
|
|
|
|
kw_hash[h] = k;
|
|
|
|
}
|
|
|
|
kw_hash_inited = 1;
|
|
|
|
}
|
|
|
|
|
1998-11-27 19:35:50 +00:00
|
|
|
void
|
Parse CLI commands. We use the same parser as for configuration files (because
we want to allow filter and similar complex constructs to be used in commands
and we should avoid code duplication), only with CLI_MARKER token prepended
before the whole input.
Defined macro CF_CLI(cmd, args, help) for defining CLI commands in .Y files.
The first argument specifies the command itself, the remaining two arguments
are copied to the help file (er, will be copied after the help file starts
to exist). This macro automatically creates a skeleton rule for the command,
you only need to append arguments as in:
CF_CLI(STEAL MONEY, <$>, [[Steal <$> US dollars or equivalent in any other currency]]): NUM {
cli_msg(0, "%d$ stolen", $3);
} ;
Also don't forget to reset lexer state between inputs.
1999-10-31 17:47:47 +00:00
|
|
|
cf_lex_init(int is_cli)
|
1998-11-27 19:35:50 +00:00
|
|
|
{
|
1999-11-30 14:03:36 +00:00
|
|
|
if (!kw_hash_inited)
|
|
|
|
cf_lex_init_kh();
|
1999-02-05 21:37:34 +00:00
|
|
|
conf_lino = 1;
|
Parse CLI commands. We use the same parser as for configuration files (because
we want to allow filter and similar complex constructs to be used in commands
and we should avoid code duplication), only with CLI_MARKER token prepended
before the whole input.
Defined macro CF_CLI(cmd, args, help) for defining CLI commands in .Y files.
The first argument specifies the command itself, the remaining two arguments
are copied to the help file (er, will be copied after the help file starts
to exist). This macro automatically creates a skeleton rule for the command,
you only need to append arguments as in:
CF_CLI(STEAL MONEY, <$>, [[Steal <$> US dollars or equivalent in any other currency]]): NUM {
cli_msg(0, "%d$ stolen", $3);
} ;
Also don't forget to reset lexer state between inputs.
1999-10-31 17:47:47 +00:00
|
|
|
yyrestart(NULL);
|
|
|
|
if (is_cli)
|
|
|
|
BEGIN(CLI);
|
|
|
|
else
|
|
|
|
BEGIN(INITIAL);
|
1999-11-04 13:51:52 +00:00
|
|
|
conf_this_scope = cfg_allocz(sizeof(struct sym_scope));
|
|
|
|
conf_this_scope->active = 1;
|
1998-11-27 19:35:50 +00:00
|
|
|
}
|
|
|
|
|
1999-11-04 13:51:52 +00:00
|
|
|
void
|
|
|
|
cf_push_scope(struct symbol *sym)
|
|
|
|
{
|
|
|
|
struct sym_scope *s = cfg_alloc(sizeof(struct sym_scope));
|
|
|
|
|
|
|
|
s->next = conf_this_scope;
|
|
|
|
conf_this_scope = s;
|
|
|
|
s->active = 1;
|
|
|
|
s->name = sym;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
cf_pop_scope(void)
|
|
|
|
{
|
|
|
|
conf_this_scope->active = 0;
|
|
|
|
conf_this_scope = conf_this_scope->next;
|
|
|
|
ASSERT(conf_this_scope);
|
|
|
|
}
|
2000-01-19 12:30:19 +00:00
|
|
|
|
|
|
|
struct symbol *
|
|
|
|
cf_walk_symbols(struct config *cf, struct symbol *sym, int *pos)
|
|
|
|
{
|
|
|
|
for(;;)
|
|
|
|
{
|
|
|
|
if (!sym)
|
|
|
|
{
|
|
|
|
if (*pos >= SYM_HASH_SIZE)
|
|
|
|
return NULL;
|
|
|
|
sym = cf->sym_hash[(*pos)++];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
sym = sym->next;
|
|
|
|
if (sym && sym->scope->active)
|
|
|
|
return sym;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
char *
|
|
|
|
cf_symbol_class_name(struct symbol *sym)
|
|
|
|
{
|
|
|
|
switch (sym->class)
|
|
|
|
{
|
|
|
|
case SYM_VOID:
|
|
|
|
return "undefined";
|
|
|
|
case SYM_PROTO:
|
|
|
|
return "protocol";
|
|
|
|
case SYM_NUMBER:
|
|
|
|
return "numeric constant";
|
|
|
|
case SYM_FUNCTION:
|
|
|
|
return "function";
|
|
|
|
case SYM_FILTER:
|
|
|
|
return "filter";
|
|
|
|
case SYM_TABLE:
|
|
|
|
return "routing table";
|
|
|
|
default:
|
|
|
|
return "unknown type";
|
|
|
|
}
|
|
|
|
}
|