diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 21727a9d..258ca7e9 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -34,14 +34,12 @@ static struct keyword { static struct keyword *kw_hash[KW_HASH_SIZE]; static struct symbol **sym_hash; -static int allow_new_symbols; int conf_lino; static int cf_hash(byte *c); static struct symbol *cf_find_sym(byte *c, unsigned int h0); -pool *cfg_pool; linpool *cfg_mem; int (*cf_read_hook)(byte *buf, unsigned int max); @@ -54,7 +52,7 @@ int (*cf_read_hook)(byte *buf, unsigned int max); %option noyywrap -%x COMMENT CCOMM +%x COMMENT CCOMM CLI ALPHA [a-zA-Z_] DIGIT [0-9] @@ -121,6 +119,11 @@ WHITE [ \t] return SYM; } +! { + BEGIN(INITIAL); + return CLI_MARKER; +} + [={}:;,()+*/%-<>~\[\]] { return yytext[0]; } @@ -174,17 +177,18 @@ static struct symbol * cf_find_sym(byte *c, unsigned int h0) { unsigned int h = h0 & (SYM_HASH_SIZE-1); - struct symbol *s = sym_hash[h]; + struct symbol *s; int l; - while (s) - { - if (!strcmp(s->name, c)) - return s; - s = s->next; - } - if (!allow_new_symbols) - return NULL; + if (!sym_hash) + sym_hash = cfg_allocz(SYM_HASH_SIZE * sizeof(struct keyword *)); + else + for(s = sym_hash[h]; s; s=s->next) + { + if (!strcmp(s->name, c)) + return s; + s = s->next; + } l = strlen(c); if (l > SYM_MAX_LEN) cf_error("Symbol too long"); @@ -230,11 +234,15 @@ cf_define_symbol(struct symbol *sym, int type, void *def) } void -cf_lex_init(int flag) +cf_lex_init(int is_cli) { - if (allow_new_symbols = flag) - sym_hash = cfg_allocz(SYM_HASH_SIZE * sizeof(struct keyword *)); + sym_hash = NULL; conf_lino = 1; + yyrestart(NULL); + if (is_cli) + BEGIN(CLI); + else + BEGIN(INITIAL); } void diff --git a/conf/conf.c b/conf/conf.c index d9bf9d88..47d4db4e 100644 --- a/conf/conf.c +++ b/conf/conf.c @@ -39,15 +39,12 @@ config_alloc(byte *name) int config_parse(struct config *c) { - struct proto_config *p; - debug("Parsing configuration file `%s'\n", c->file_name); new_config = c; - cfg_pool = c->pool; cfg_mem = c->mem; if (setjmp(conf_jmpbuf)) return 0; - cf_lex_init(1); + cf_lex_init(0); cf_lex_init_tables(); protos_preconfig(c); rt_preconfig(c); @@ -61,6 +58,18 @@ config_parse(struct config *c) return 1; } +int +cli_parse(struct config *c) +{ + new_config = c; + cfg_mem = c->mem; + if (setjmp(conf_jmpbuf)) + return 0; + cf_lex_init(1); + cf_parse(); + return 1; +} + void config_free(struct config *c) { diff --git a/conf/conf.h b/conf/conf.h index 4f6f030c..d62f1383 100644 --- a/conf/conf.h +++ b/conf/conf.h @@ -30,13 +30,13 @@ extern struct config *config, *new_config; struct config *config_alloc(byte *name); int config_parse(struct config *); +int cli_parse(struct config *); void config_free(struct config *); void config_commit(struct config *); void cf_error(char *msg, ...) NORET; /* Pools */ -extern pool *cfg_pool; extern linpool *cfg_mem; #define cfg_alloc(size) lp_alloc(cfg_mem, size) @@ -71,7 +71,7 @@ extern int conf_lino; void cf_lex_init_tables(void); int cf_lex(void); -void cf_lex_init(int flag); +void cf_lex_init(int is_cli); struct symbol *cf_find_symbol(byte *c); struct symbol *cf_default_name(char *prefix, int *counter); void cf_define_symbol(struct symbol *symbol, int type, void *def); diff --git a/conf/confbase.Y b/conf/confbase.Y index b266d253..4a942878 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -16,8 +16,11 @@ CF_HDR #include "nest/protocol.h" #include "nest/iface.h" #include "nest/route.h" +#include "nest/cli.h" #include "filter/filter.h" +#define cli_msg(x...) cli_printf(this_cli, x) + CF_DECLS %union { @@ -34,7 +37,7 @@ CF_DECLS struct password_item *p; } -%token END +%token END CLI_MARKER %token NUM %token RTRID %token IPA @@ -54,9 +57,8 @@ CF_GRAMMAR /* Basic config file structure */ -config: conf_entries END { - return 0; - } +config: conf_entries END { return 0; } + | CLI_MARKER cli_cmd END { return 0; } ; conf_entries: diff --git a/conf/gen_keywords.m4 b/conf/gen_keywords.m4 index 8bbe4902..37b882b5 100644 --- a/conf/gen_keywords.m4 +++ b/conf/gen_keywords.m4 @@ -2,7 +2,7 @@ m4_divert(-1)m4_dnl # # BIRD -- Generator of Configuration Keyword List # -# (c) 1998 Martin Mares +# (c) 1998--1999 Martin Mares # # Can be freely distributed and used under the terms of the GNU GPL. # @@ -18,6 +18,10 @@ m4_define(CF_keywd, `m4_ifdef([[CF_tok_$1]],,[[m4_define([[CF_tok_$1]],1)CF_hand m4_define(CF_KEYWORDS, `m4_define([[CF_toks]],[[]])CF_iterate([[CF_keywd]], [[$@]])m4_ifelse(CF_toks,,,%token[[]]CF_toks )DNL') +# CLI commands generate keywords as well +m4_define(CF_CLI, `CF_KEYWORDS(m4_translit($1, [[ ]], [[,]])) +') + # As we are processing C source, we must access all M4 primitives via # m4_* and also set different quoting convention: `[[' and ']]' m4_changequote([[,]]) diff --git a/conf/gen_parser.m4 b/conf/gen_parser.m4 index a08b330c..8441c83b 100644 --- a/conf/gen_parser.m4 +++ b/conf/gen_parser.m4 @@ -2,7 +2,7 @@ m4_divert(-1)m4_dnl # # BIRD -- Generator of Configuration Grammar # -# (c) 1998 Martin Mares +# (c) 1998--1999 Martin Mares # # Can be freely distributed and used under the terms of the GNU GPL. # @@ -38,6 +38,12 @@ m4_define(CF_dyn_rules,) m4_define(CF_ADDTO, `m4_define([[CF_rule_$1]],m4_ifdef([[CF_rule_$1]],CF_rule_$1 | ,[[m4_define([[CF_dyn_rules]],CF_dyn_rules[[CF_RULE($1) ]])]])$2)DNL') +# CLI commands +m4_define(CF_CLI, `m4_define([[CF_cmd]], cmd_[[]]m4_translit($1, [[ ]], _))DNL +m4_divert(2)CF_KEYWORDS(m4_translit($1, [[ ]], [[,]])) +m4_divert(3)CF_ADDTO(cli_cmd, CF_cmd) +CF_cmd: $1 ') + # After all configuration templates end, we finally generate the grammar file. m4_m4wrap(` m4_divert(0)DNL diff --git a/nest/cli.c b/nest/cli.c index f094a7c4..41907b33 100644 --- a/nest/cli.c +++ b/nest/cli.c @@ -7,8 +7,9 @@ */ #include "nest/bird.h" -#include "lib/string.h" #include "nest/cli.h" +#include "conf/conf.h" +#include "lib/string.h" pool *cli_pool; @@ -88,6 +89,47 @@ cli_free_out(cli *c) } } +static byte *cli_rh_pos; +static unsigned int cli_rh_len; +static int cli_rh_trick_flag; +struct cli *this_cli; + +static int +cli_cmd_read_hook(byte *buf, unsigned int max) +{ + if (!cli_rh_trick_flag) + { + cli_rh_trick_flag = 1; + buf[0] = '!'; + return 1; + } + if (max > cli_rh_len) + max = cli_rh_len; + memcpy(buf, cli_rh_pos, max); + cli_rh_pos += max; + cli_rh_len -= max; + return max; +} + +static void +cli_command(struct cli *c) +{ + struct config f; + int res; + + f.pool = NULL; + f.mem = c->parser_pool; + cf_read_hook = cli_cmd_read_hook; + cli_rh_pos = c->rx_buf; + cli_rh_len = strlen(c->rx_buf); + cli_rh_trick_flag = 0; + this_cli = c; + res = cli_parse(&f); + lp_flush(c->parser_pool); + if (!res) + cli_printf(c, 9001, f.err_msg); +} + static int cli_event(void *data) { @@ -106,10 +148,7 @@ cli_event(void *data) if (err < 0) cli_printf(c, 9000, "Command too long"); else - { - cli_printf(c, -9001, "Parse error in:"); - cli_printf(c, 9001, c->rx_buf); - } + cli_command(c); } if (cli_write(c)) { @@ -133,6 +172,7 @@ cli_new(void *priv) c->tx_buf = c->tx_pos = c->tx_write = NULL; c->cont = cli_hello; c->last_reply = 0; + c->parser_pool = lp_new(c->pool, 4096); ev_schedule(c->event); return c; } diff --git a/nest/cli.h b/nest/cli.h index 9670f69a..d4413ffb 100644 --- a/nest/cli.h +++ b/nest/cli.h @@ -31,9 +31,11 @@ typedef struct cli { void (*cont)(struct cli *c); void *rover; /* Private to continuation routine */ int last_reply; + struct linpool *parser_pool; /* Pool used during parsing */ } cli; extern pool *cli_pool; +extern struct cli *this_cli; /* Used during parsing */ /* Functions to be called by command handlers */ diff --git a/nest/config.Y b/nest/config.Y index 91cdad11..64594625 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -182,6 +182,11 @@ password_list: } ; +/* Core commands */ + +CF_CLI(TEST LEDS, , [[Flashes each LED times]]) NUM { cli_msg(0, "%d", $3); } ; +CF_CLI(TEST, 1, 2) { cli_msg(0, "OK"); } + CF_CODE CF_END