From 9a9466f1fdad6fb6c94c5ef8ddb1a687a7bcd874 Mon Sep 17 00:00:00 2001 From: Chris Hall Date: Thu, 31 Mar 2011 00:37:47 +0100 Subject: Small improvements to speed of reading of configuration file. Tidy up signalling of "ready" to command loop, and checking of appropriate state to close written configuration file. --- lib/command_parse.c | 286 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 211 insertions(+), 75 deletions(-) (limited to 'lib/command_parse.c') diff --git a/lib/command_parse.c b/lib/command_parse.c index ba1b217e..81e4ad74 100644 --- a/lib/command_parse.c +++ b/lib/command_parse.c @@ -29,6 +29,8 @@ #include "command_local.h" #include "command_parse.h" #include "memory.h" +#include "list_util.h" +#include "elstring.h" /*============================================================================== * Command Description objects. @@ -44,13 +46,35 @@ static int cmd_cmp_item(const cmd_item* a, const cmd_item* b) ; static int cmd_cmp_range_items(const cmd_item a, const cmd_item b) ; static bool cmd_item_is_option(cmd_item_type_t it) ; static bool cmd_item_is_vararg(cmd_item_type_t it) ; +static void cmd_set_str(cmd_item n, const char* str) ; /*------------------------------------------------------------------------------ - * Dummy eol_item + * Table of known "words" -- so that a word can be represented by its + * address in this table and its length. + * + * See: cmd_set_str() + */ +enum { word_lump_length = 500 * 8 } ; /* plenty ? */ +enum { command_specification_length = 500 } ; /* plenty !! */ + +typedef struct word_lump* word_lump ; + +struct word_lump +{ + word_lump next ; + + char* end ; /* points at the terminating '\0' */ + char words[word_lump_length] ; +} ; + +static struct dl_base_pair(word_lump) word_lumps = INIT_DL_BASE_PAIR ; + +/*------------------------------------------------------------------------------ + * Dummy eol_item -- completed in cmd_parse_init() */ static struct cmd_item eol_item = { - .str = "", + .str = ELSTRING_INIT, /* see cmd_parse_init() */ .doc = "", .next = NULL, @@ -152,15 +176,18 @@ extern void cmd_compile(cmd_command cmd) { vector multvec ; + const char* p ; char* cp ; char* qp ; char* dp ; bool opt ; bool vararg ; + char spec[command_specification_length + 1] ; + /* Initialise the compiled version of the command */ - assert((cmd->r_doc == NULL) && (cmd->r_string == NULL)) ; + assert(cmd->r_doc == NULL) ; cmd->items = vector_init_new(NULL, 10) ; /* plenty ! */ cmd->nt_min = 0 ; @@ -168,63 +195,68 @@ cmd_compile(cmd_command cmd) cmd->nt_max = 0 ; cmd->vararg = NULL ; cmd->r_doc = XSTRDUP(MTYPE_CMD_STRING, cmd->doc) ; /* NULL => "" */ - cmd->r_string = XSTRDUP(MTYPE_CMD_STRING, cmd->string) ; + + if (strlen(cmd->string) > command_specification_length) + cmd_fail_item(cmd, "command specification *too* long") ; /* Simplify the command line string by replacing TABs by spaces, and barfing * on control characters. Strip leading and trailing spaces and any spaces - * between brackets... checking for matching brackets. + * between brackets -- checking for matching brackets -- and squeeze out + * multiple spaces. */ - cp = cmd->r_string ; - while (*cp != '\0') + qp = spec ; + p = cmd->string ; + + while ((*p == ' ') || (*p == '\t')) + ++p ; /* squeeze out leading spaces */ + + while (*p != '\0') /* starts with not ' ' and not '\t' */ { - if (!iscntrl(*cp)) - ++cp ; - else if (*cp == '\t') - *cp++ = ' ' ; + if (!iscntrl(*p)) + *qp = *p ; + else if (*p == '\t') + *qp = ' ' ; else cmd_fail_item(cmd, "improper control character in string") ; + + if ((*qp != ' ') || (*(qp - 1) != ' ')) + ++qp ; /* squeeze out multiple spaces */ + + ++p ; } ; - cp = cmd->r_string ; - while (*cp == ' ') - ++cp ; + while ((qp > spec) && (*(qp - 1) == ' ')) + --qp ; /* squeeze out trailing spaces */ + + *qp = '\0' ; - qp = cmd->r_string ; + cp = spec ; + qp = spec ; while (*cp != '\0') { - if (*cp != ' ') + if ((*cp == '(') || (*cp == '[') || (*cp == '<') || (*cp == '{')) { - if ((*cp == '(') || (*cp == '[') || (*cp == '<') || (*cp == '{')) + /* Check for balanced brackets and remove any spaces between. + * + * Checks for enclosed brackets being balanced as well. + * + * Leaves cp pointing at the trailing bracket. + */ + char* sp = cp ; + cp = cmd_item_brackets(cmd, cp) ; + while (sp < cp) { - /* Check for balanced brackets and remove any spaces between. - * - * Checks for enclosed brackets being balanced as well. - * - * Leaves cp pointing at the trailing bracket. - */ - char* sp = cp ; - cp = cmd_item_brackets(cmd, cp) ; - while (sp < cp) - { - if (*sp != ' ') - *qp++ = *sp++ ; - else - ++sp ; - } ; + if (*sp != ' ') + *qp++ = *sp++ ; + else + ++sp ; } ; - } - else - { - while (*(cp + 1) == ' ') - ++cp ; - if (*(cp + 1) == '\0') - break ; } ; *qp++ = *cp++ ; } ; - *qp++ = '\0' ; /* terminate reduced string */ + *qp = '\0' ; /* terminate reduced string */ /* Simplify the documentation string by replacing TABs by spaces, and barfing * on control characters other than '\n'. @@ -265,11 +297,11 @@ cmd_compile(cmd_command cmd) *qp++ = *dp++ ; } ; - *qp++ = '\0' ; /* terminate reduced string */ + *qp = '\0' ; /* terminate reduced string */ /* Processing loop */ - cp = cmd->r_string ; + cp = spec ; dp = cmd->r_doc ; opt = false ; @@ -380,7 +412,7 @@ cmd_compile(cmd_command cmd) if (cmd_item_is_option(n->type)) opt = true ; else if (opt) - cmd_fail_item(cmd, "can only have [option] after [option]") ; + cmd_fail_item(cmd, "can only have [option] after [option]") ; /* Check vararg item state -- can only be trailing */ if (vararg) @@ -434,7 +466,8 @@ cmd_compile(cmd_command cmd) bool repeat ; if (n->type == item_keyword) - repeat = strcmp(n->str, p->str) == 0 ; + repeat = (els_body_nn(n->str) == els_body_nn(p->str)) + && (els_len_nn(n->str) == els_len_nn(p->str)) ; else if (n->type == item_range) repeat = cmd_cmp_range_items(n, p) == 0 ; else @@ -478,7 +511,6 @@ cmd_compile_check(cmd_command cmd) if ( (cmd->string == NULL) || (cmd->func == NULL) || (cmd->items == NULL) - || (cmd->r_string == NULL) || (cmd->r_doc == NULL) ) ok = false ; @@ -666,7 +698,8 @@ cmd_make_item(cmd_command cmd, char* cp, char* dp) /* Zeroising has set: * - * * cmd = NULL -- set below + * * str = NULL -- set below + * * str_len = 0 -- set below * * doc = NULL -- set below * * * next = NULL -- set elsewhere if multiple. @@ -681,7 +714,7 @@ cmd_make_item(cmd_command cmd, char* cp, char* dp) */ confirm(item_null == 0) ; - n->str = cp ; + cmd_set_str(n, cp) ; n->doc = dp ; /* Worry about option state */ @@ -931,7 +964,7 @@ cmd_cmp_item(const cmd_item* a, const cmd_item* b) if ((*a)->type == item_range) return cmd_cmp_range_items(*a, *b) ; else - return strcmp ((*a)->str, (*b)->str); + return els_cmp((*a)->str, (*b)->str) ; } ; } ; @@ -958,6 +991,59 @@ cmd_cmp_range_items(const cmd_item a, const cmd_item b) return 0 ; } ; +/*------------------------------------------------------------------------------ + * Set the str and str_len entries for a given item. + * + * The str entry of a cmd_item is set to point at a pool of known values. + * This means that where two str entries are the same, they will have the + * same address ! + */ +static void +cmd_set_str(cmd_item n, const char* str) +{ + uint len ; + word_lump lump ; + char* word ; + + len = strlen(str) ; + + lump = dsl_head(word_lumps) ; + while (1) + { + if (lump == NULL) + { + lump = XCALLOC(MTYPE_CMD_STRING, sizeof(struct word_lump)) ; + lump->end = lump->words ; + + dsl_append(word_lumps, lump, next) ; + } ; + + word = strstr(lump->words, str) ; + if (word != NULL) + break ; + + if (dsl_next(lump, next) != NULL) + { + lump = dsl_next(lump, next) ; + continue ; + } ; + + if (len >= (&lump->words[word_lump_length] - lump->end)) + { + lump = NULL ; + continue ; + } ; + + word = lump->end ; + memcpy(word, str, len) ; + lump->end += len ; + *lump->end = '\0' ; + break ; + } ; + + els_set_n_nn(n->str, word, len) ; +} ; + /*============================================================================== * Token objects */ @@ -1062,6 +1148,9 @@ cmd_token_set(token_vector tv, vector_index_t i, qs_set_alias_n(t->qs, p, len) ; qs_els_copy_nn(t->ot, t->qs) ; + + t->w_len = 0 ; /* no words matched to, yet */ + t->seen = 0 ; /* no matches attempted, yet */ } ; @@ -2249,15 +2338,23 @@ static match_type_t cmd_ipv4_address_match(cmd_token t) { match_strength_t ms ; + match_type_t mt ; + + if ((t->seen & item_ipv4_address_bit) != 0) + return t->match[item_ipv4_address] ; ms = cmd_ipv4_match(cmd_token_make_string(t), 0) ; - if (ms == ms_var_complete) - return mt_ipv4_address_complete ; - if (ms == ms_partial) - return mt_ipv4_address_partial ; + if (ms == ms_var_complete) + mt = mt_ipv4_address_complete ; + else if (ms == ms_partial) + mt = mt_ipv4_address_partial ; + else + mt = mt_no_match ; - return mt_no_match ; + t->seen |= item_ipv4_address_bit ; + + return t->match[item_ipv4_address] = mt ; } ; /*------------------------------------------------------------------------------ @@ -2277,15 +2374,23 @@ static match_type_t cmd_ipv4_prefix_match(cmd_token t) { match_strength_t ms ; + match_type_t mt ; + + if ((t->seen & item_ipv4_prefix_bit) != 0) + return t->match[item_ipv4_prefix] ; ms = cmd_ipv4_match(cmd_token_make_string(t), 32) ; - if (ms == ms_var_complete) - return mt_ipv4_prefix_complete ; - if (ms == ms_partial) - return mt_ipv4_prefix_partial ; + if (ms == ms_var_complete) + mt = mt_ipv4_prefix_complete ; + else if (ms == ms_partial) + mt = mt_ipv4_prefix_partial ; + else + mt = mt_no_match ; + + t->seen |= item_ipv4_prefix_bit ; - return mt_no_match ; + return t->match[item_ipv4_prefix] = mt ; } ; /*------------------------------------------------------------------------------ @@ -2425,15 +2530,23 @@ static match_type_t cmd_ipv6_address_match (cmd_token t) { match_strength_t ms ; + match_type_t mt ; + + if ((t->seen & item_ipv6_address_bit) != 0) + return t->match[item_ipv6_address] ; ms = cmd_ipv6_match(cmd_token_make_string(t), 0) ; - if (ms == ms_var_complete) - return mt_ipv6_address_complete ; - if (ms == ms_partial) - return mt_ipv6_address_partial ; + if (ms == ms_var_complete) + mt = mt_ipv6_address_complete ; + else if (ms == ms_partial) + mt = mt_ipv6_address_partial ; + else + mt = mt_no_match ; + + t->seen |= item_ipv6_address_bit ; - return mt_no_match ; + return t->match[item_ipv6_address] = mt ; } ; /*------------------------------------------------------------------------------ @@ -2452,15 +2565,23 @@ static match_type_t cmd_ipv6_prefix_match(cmd_token t) { match_strength_t ms ; + match_type_t mt ; + + if ((t->seen & item_ipv6_prefix_bit) != 0) + return t->match[item_ipv6_prefix] ; ms = cmd_ipv6_match(cmd_token_make_string(t), 128) ; - if (ms == ms_var_complete) - return mt_ipv6_prefix_complete ; - if (ms == ms_partial) - return mt_ipv6_prefix_partial ; + if (ms == ms_var_complete) + mt = mt_ipv6_prefix_complete ; + else if (ms == ms_partial) + mt = mt_ipv6_prefix_partial ; + else + mt = mt_no_match ; + + t->seen |= item_ipv6_prefix_bit ; - return mt_no_match ; + return t->match[item_ipv6_prefix] = mt ; } ; /*------------------------------------------------------------------------------ @@ -2988,7 +3109,7 @@ cmd_item_filter(cmd_parsed parsed, cmd_item item, cmd_token t) */ if (t->type == cmd_tok_eol) { -// mt = (item->type == item_eol) ? mt_eol : mt_eol_partial ; + mt = (item->type == item_eol) ? mt_eol : mt_eol_partial ; mt = mt_eol_partial ; } else @@ -3003,7 +3124,16 @@ cmd_item_filter(cmd_parsed parsed, cmd_item item, cmd_token t) break ; case item_keyword: - cw = els_cmp_word(t->ot, item->str) ; + if ((t->word == els_body_nn(item->str)) + && (t->w_len == els_len_nn(item->str))) + cw = t->cw ; + else + { + cw = els_cmp_word(t->ot, item->str) ; + t->word = els_body_nn(item->str) ; + t->w_len = els_len_nn(item->str) ; + t->cw = cw ; + } ; if (cw > 0) /* nope */ mt = mt_no_match ; @@ -4738,8 +4868,14 @@ cmd_complete_command (vector tokens, int node, int *status) return NULL; } ; - - - - - +/*============================================================================== + * Initialise command parsing -- done before first command is installed. + * + * Complete the (much used) eol_item. + */ +extern void +cmd_parser_init(void) +{ + dsl_init(word_lumps) ; + cmd_set_str(&eol_item, "") ; +} ; -- cgit v1.2.3