summaryrefslogtreecommitdiffstats
path: root/lib/command_parse.c
diff options
context:
space:
mode:
authorChris Hall <chris.hall@highwayman.com>2011-03-31 00:37:47 +0100
committerChris Hall <chris.hall@highwayman.com>2011-03-31 00:37:47 +0100
commit9a9466f1fdad6fb6c94c5ef8ddb1a687a7bcd874 (patch)
treec4ae426872560a5e070f2054072607f2578e1f7d /lib/command_parse.c
parentf3255d1e9f062e7783b05ab5b32ca70085170d79 (diff)
downloadquagga-9a9466f1fdad6fb6c94c5ef8ddb1a687a7bcd874.tar.bz2
quagga-9a9466f1fdad6fb6c94c5ef8ddb1a687a7bcd874.tar.xz
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.
Diffstat (limited to 'lib/command_parse.c')
-rw-r--r--lib/command_parse.c286
1 files changed, 211 insertions, 75 deletions
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 = "<cr>",
+ .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, "<cr>") ;
+} ;