diff options
author | Chris Hall <chris.hall@highwayman.com> | 2011-03-31 00:37:47 +0100 |
---|---|---|
committer | Chris Hall <chris.hall@highwayman.com> | 2011-03-31 00:37:47 +0100 |
commit | 9a9466f1fdad6fb6c94c5ef8ddb1a687a7bcd874 (patch) | |
tree | c4ae426872560a5e070f2054072607f2578e1f7d /lib | |
parent | f3255d1e9f062e7783b05ab5b32ca70085170d79 (diff) | |
download | quagga-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')
-rw-r--r-- | lib/command.c | 3 | ||||
-rw-r--r-- | lib/command.h | 1 | ||||
-rw-r--r-- | lib/command_common.h | 3 | ||||
-rw-r--r-- | lib/command_parse.c | 286 | ||||
-rw-r--r-- | lib/command_parse.h | 38 | ||||
-rw-r--r-- | lib/elstring.c | 51 | ||||
-rw-r--r-- | lib/elstring.h | 10 | ||||
-rw-r--r-- | lib/list_util.c | 62 | ||||
-rw-r--r-- | lib/list_util.h | 213 | ||||
-rw-r--r-- | lib/qstring.h | 6 | ||||
-rw-r--r-- | lib/vty.c | 10 | ||||
-rw-r--r-- | lib/vty_cli.c | 70 | ||||
-rw-r--r-- | lib/vty_io_file.c | 2 | ||||
-rw-r--r-- | lib/vty_io_term.c | 4 |
14 files changed, 606 insertions, 153 deletions
diff --git a/lib/command.c b/lib/command.c index 4057bcfc..f9747a33 100644 --- a/lib/command.c +++ b/lib/command.c @@ -2159,6 +2159,8 @@ cmd_init (bool terminal) { srand(time(NULL)) ; + cmd_parser_init() ; + if (host.cwd == NULL) /* in case cmd_cwd() not called, yet */ cmd_getcwd() ; @@ -2333,7 +2335,6 @@ cmd_terminate () cmd->items = NULL ; /* gone */ - XFREE (MTYPE_CMD_STRING, cmd->r_string) ; /* sets NULL */ XFREE (MTYPE_CMD_STRING, cmd->r_doc) ; } ; } diff --git a/lib/command.h b/lib/command.h index 3ad758d5..bb8b0bd9 100644 --- a/lib/command.h +++ b/lib/command.h @@ -55,7 +55,6 @@ .nt = 0, \ .nt_max = 0, \ .vararg = NULL, \ - .r_string = NULL, \ .r_doc = NULL, \ } ; diff --git a/lib/command_common.h b/lib/command_common.h index 26f2909f..3621a4b6 100644 --- a/lib/command_common.h +++ b/lib/command_common.h @@ -278,8 +278,7 @@ struct cmd_command struct cmd_item* vararg ; /* if there is a vararg item */ - char* r_string ; - char* r_doc ; + char* r_doc ; /* rendered documentation */ //char* config ; /* Configuration string */ //vector subconfig ; /* Sub configuration string */ 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>") ; +} ; diff --git a/lib/command_parse.h b/lib/command_parse.h index 5f17d083..d2c53385 100644 --- a/lib/command_parse.h +++ b/lib/command_parse.h @@ -30,6 +30,7 @@ #include "vector.h" #include "vio_fifo.h" #include "qstring.h" +#include "elstring.h" #include "qpath.h" #include "elstring.h" #include "memory.h" @@ -117,6 +118,22 @@ enum { CONFIRM(LONG_MAX >= item_max_number) ; +enum cmd_item_type_bit +{ + item_null_bit = BIT(item_null), + item_eol_bit = BIT(item_eol), + item_option_word_bit = BIT(item_option_word), + item_vararg_bit = BIT(item_vararg), + item_word_bit = BIT(item_word), + item_ipv6_prefix_bit = BIT(item_ipv6_prefix), + item_ipv6_address_bit = BIT(item_ipv6_address), + item_ipv4_prefix_bit = BIT(item_ipv4_prefix), + item_ipv4_address_bit = BIT(item_ipv4_address), + item_range_bit = BIT(item_range), + item_keyword_bit = BIT(item_keyword), +} ; +typedef enum cmd_item_type_bit cmd_item_type_bit_t ; + /*------------------------------------------------------------------------------ * Sex cmd_item_type and return whether it is an "option" type, or not. * @@ -191,15 +208,16 @@ cmd_item_is_vararg(cmd_item_type_t itt) typedef struct cmd_item* cmd_item ; struct cmd_item { - const char* str ; /* in r_string -- original string form */ - const char* doc ; /* in r_doc -- description text */ + elstring_t str ; /* in some word_lump */ - cmd_item next ; /* Next possibility (if any) */ + const char* doc ; /* in r_doc -- description text */ + + cmd_item next ; /* Next possibility (if any) */ cmd_item_type_t type ; - bool arg ; /* include in argv */ + bool arg ; /* include in argv */ - /* For item_range values */ + /* For item_range values */ bool range_sign_allowed ; bool range_sign_required ; long range_min ; @@ -522,6 +540,14 @@ struct cmd_token qstring_t qs ; /* token string */ elstring_t ot ; /* original token in the line */ + + const void* word ; /* set when a word match is done */ + ulen w_len ; /* length of word match */ + int cw ; /* result of the word match */ + + cmd_item_type_bit_t seen ; /* bit set when match done */ + match_type_t match[item_type_count] ; + /* result of match seen */ } ; typedef struct cmd_token* cmd_token ; @@ -727,7 +753,7 @@ extern void cmd_complete_keyword(cmd_parsed parsed, extern void cmd_get_parse_error(vio_fifo ebuf, cmd_parsed parsed, uint indent) ; - +extern void cmd_parser_init(void) ; diff --git a/lib/elstring.c b/lib/elstring.c index 64756a64..51089cdd 100644 --- a/lib/elstring.c +++ b/lib/elstring.c @@ -77,23 +77,13 @@ els_free(elstring els) */ /*------------------------------------------------------------------------------ - * Compare two elstrings -- returns the usual -ve, 0, +ve cmp result. - * - * NULL elstring is treated as empty. + * Basic string/length vs string/length comparison */ -extern int -els_cmp(elstring a, elstring b) +inline static int +str_nn_cmp(const uchar* ap, ulen al, const uchar* bp, ulen bl) { - const uchar* ap ; - const uchar* bp ; - ulen al, bl ; ulen n ; - ap = els_body(a) ; /* NULL if a is NULL */ - bp = els_body(b) ; - al = els_len(a) ; /* zero if a is NULL */ - bl = els_len(b) ; - n = (al <= bl) ? al : bl ; /* min(al, bl) */ while (n) @@ -108,7 +98,29 @@ els_cmp(elstring a, elstring b) } ; /*------------------------------------------------------------------------------ - * Compare elstring against word. + * Compare two elstrings -- returns the usual -ve, 0, +ve cmp result. + * + * NULL elstring is treated as empty. + */ +extern int +els_cmp(elstring a, elstring b) +{ + return str_nn_cmp(els_body(a), els_len(a), els_body(b), els_len(b)) ; +} ; + +/*------------------------------------------------------------------------------ + * Compare two string/length values -- returns the usual -ve, 0, +ve cmp result + * + * (Not really an elstring function, but the infrastructure is here.) + */ +extern int +els_nn_cmp(const void* ap, ulen al, const void* bp, ulen bl) +{ + return str_nn_cmp(ap, al, bp, bl) ; +} ; + +/*------------------------------------------------------------------------------ + * Compare elstring against word elstring. * * Returns: -1 => elstring and word match to end of elstring * 0 => elstring and word match completely @@ -120,13 +132,13 @@ els_cmp(elstring a, elstring b) * An empty elstring will partly match any non-empty word. */ extern int -els_cmp_word(elstring a, const char* w) +els_cmp_word(elstring a, elstring w) { - const uchar* ap, * ep ; + const uchar* ap, * ep, * wp ; ulen al, wl ; al = els_len(a) ; /* zero if a is NULL */ - wl = (w != NULL) ? strlen(w) : 0 ; /* zero if w is NULL */ + wl = els_len(w) ; /* zero if w is NULL */ if (al > wl) return +1 ; /* no match if longer */ @@ -135,16 +147,17 @@ els_cmp_word(elstring a, const char* w) return (wl == 0) ? 0 : -1 ; /* exact or partial if empty */ ap = els_body_nn(a) ; + wp = els_body_nn(w) ; /* Neither string is empty */ - if (*ap != *w) + if (*ap != *wp) return +1 ; /* quick out if no match for 1st char */ ep = ap + al - 1 ; while (ap < ep) { - if (*++ap != *++w) + if (*++ap != *++wp) return 1 ; } ; diff --git a/lib/elstring.h b/lib/elstring.h index 8ab1c58d..2b8e77fc 100644 --- a/lib/elstring.h +++ b/lib/elstring.h @@ -52,10 +52,9 @@ typedef struct elstring* elstring ; /* Setting an elstring object to all zeros is enough to initialise it to * an empty string. */ -enum -{ - ELSTRING_INIT_ALL_ZEROS = true -} ; +enum { ELSTRING_INIT_ALL_ZEROS = true } ; + +#define ELSTRING_INIT { { { NULL }, 0 } } /*============================================================================== * Pointer pair and unsigned pointer pair and const versions. @@ -177,7 +176,8 @@ extern elstring els_new(void) ; extern elstring els_free(elstring els) ; extern int els_cmp(elstring a, elstring b) ; -extern int els_cmp_word(elstring a, const char* w) ; +extern int els_nn_cmp(const void* ap, ulen al, const void* bp, ulen bl) ; +extern int els_cmp_word(elstring a, elstring w) ; extern int els_cmp_sig(elstring a, elstring b) ; extern bool els_equal(elstring a, elstring b) ; extern bool els_substring(elstring a, elstring b) ; diff --git a/lib/list_util.c b/lib/list_util.c index 0f7e8a02..09ddb6b5 100644 --- a/lib/list_util.c +++ b/lib/list_util.c @@ -53,14 +53,14 @@ * false => item not found on list (or item == NULL) */ extern bool -ssl_del_func(void* p_this, void* item, size_t link_offset) +ssl_del_func(void** p_this, void* item, size_t link_offset) { void* this ; if (item == NULL) return false ; - while ((this = *(void**)p_this) != item) + while ((this = *p_this) != item) { if (this == NULL) return false ; @@ -68,12 +68,66 @@ ssl_del_func(void* p_this, void* item, size_t link_offset) p_this = _sl_p_next(this, link_offset) ; } ; - *(void**)p_this = _sl_next(item, link_offset) ; + *p_this = _sl_next(item, link_offset) ; return true ; } ; /*============================================================================== - * Single Base, Double Link + * Double Base, Single Link */ +/*------------------------------------------------------------------------------ + * Deleting item + * + * Have to chase down list to find item. + * + * Note that p_this: + * + * * starts as pointer to the base pointer, so should really be void**, + * but that causes all sorts of problems with strict-aliasing. + * + * So: have to cast to (void**) before dereferencing to get the address + * of the first item on the list. + * + * * as steps along the list p_this points to the "next pointer" in the + * previous item. + * + * The _sl_p_next() macro adds the offset of the "next pointer" to the + * address of the this item. + * + * * at the end, assigns the item's "next pointer" to the "next pointer" + * field pointed at by p_this. + * + * Note again the cast to (void**). + * + * Returns: true => removed item from list + * false => item not found on list (or item == NULL) + */ +extern bool +dsl_del_func(struct dl_void_base_pair* p_base, void* item, size_t link_offset) +{ + void* this ; + void** p_this ; + + if (item == NULL) + return false ; + + p_this = &p_base->head ; + + while ((this = *p_this) != item) + { + if (this == NULL) + return false ; + + p_this = _sl_p_next(this, link_offset) ; + } ; + + *p_this = _sl_next(item, link_offset) ; + + if (item == p_base->tail) + p_base->tail = *p_this ; + + return true ; +} ; + diff --git a/lib/list_util.h b/lib/list_util.h index f6a01d93..0ce3e6fa 100644 --- a/lib/list_util.h +++ b/lib/list_util.h @@ -109,15 +109,17 @@ #define dl_base_pair(ptr_t) { ptr_t head ; ptr_t tail ; } -struct dl_void_list_pair list_pair(void*) ; -struct dl_void_base_pair base_pair(void*) ; +#define INIT_DL_BASE_PAIR { NULL, NULL } + +struct dl_void_list_pair dl_list_pair(void*) ; +struct dl_void_base_pair dl_base_pair(void*) ; #define _lu_off(obj, field) ((char*)&((obj)->field) - (char*)(obj)) /*============================================================================== * Single Base, Single Link * - * To delete entry must chase down list to find it. + * To delete entry must chase down list to find it. Cannot insert at tail. * * Supports: * @@ -237,11 +239,11 @@ struct dl_void_base_pair base_pair(void*) ; (base) = item ; \ } while (0) -extern bool ssl_del_func(void* p_this, void* obj, size_t link_offset) +Private bool ssl_del_func(void** p_this, void* obj, size_t link_offset) __attribute__((noinline)) ; #define ssl_del(base, item, next) \ - ssl_del_func((void*)(&base), item, _lu_off(item, next)) + ssl_del_func((void**)(&base), item, _lu_off(item, next)) #define ssl_del_head(base, next) \ do { if ((base) != NULL) \ @@ -261,10 +263,10 @@ extern bool ssl_del_func(void* p_this, void* obj, size_t link_offset) */ #define _sl_p_next(item, off) \ - ( (char*)(item) + (off) ) + ((void**)( (char*)(item) + (off) )) #define _sl_next(item, off) \ - *(void**)_sl_p_next(item, off) + *_sl_p_next(item, off) /*============================================================================== * Single Base, Double Link @@ -721,4 +723,201 @@ extern bool ssl_del_func(void* p_this, void* obj, size_t link_offset) #define ddl_prev(item, list) \ ((item) != NULL ? (item)->list.prev : NULL) + /*============================================================================== + * Double Base, Single Link + * + * To delete entry must chase down list to find it. Can insert at tail, but + * not remove (except by chasing down list). + * + * Supports: + * + * dsl_init(base) -- initialise base + * + * An empty list has *both* head and tail pointers NULL. + * + * NB: confusion will arise if only one of these pointers is NULL. + * + * dsl_push(base, item, next) -- insert at head of list + * + * Treat as void function. The item may *not* be NULL. + * + * Undefined if item is already on any list (including this one). + * + * dsl_append(base, item, next) -- insert at tail of list + * + * Treat as void function. The item may *not* be NULL. + * + * Undefined if item is already on any list (including this one). + * + * dsl_in_after(after, base, item, next) -- insert after + * + * Treat as void function. The after & item may *not* be NULL. + * + * Undefined if item is already on any list (including this one), or if + * after is not on the list. + * + * dsl_pop(&dst, base, next) -- pop head of list, if any + * + * Treat as function returning void*. + * + * Returns old head in dst and as return from "function". + * + * Returns NULL and sets dst == NULL if list is empty. + * + * dsl_del(base, item, next) -- delete from list + * + * Treat as void function. Does nothing if the item is NULL. + * + * Undefined if item is not on the list. + * + * dsl_del_head(base, next) -- delete head of list + * + * Treat as void function. Does nothing if the list is empty. + * + * dsl_del_tail(base, next) -- delete tail of list + * + * Treat as void function. Does nothing if the list is empty. + * + * dsl_head(base) -- return head of list + * + * Treat as function returning void*. + * + * dsl_tail(base) -- return tail of list + * + * Treat as function returning void*. + * + * dsl_next(item, next) -- step to next item, if any + * + * Treat as function returning void*. Returns NULL if the item is NULL. + * + * Note that dsl_del() and dsl_pop() do NOT affect the item->next pointer. + * + * Where: + * + * "base" to be an r-value of type: struct base_pair(struct item*)* + * + * That is... a variable or field which is a pointer to + * + * "item" to be an l-value of type struct item* + * + * "dst" to be an r-value of type struct item* + * + * "next" to be the name of a field in struct item of type struct item* + * + *------------------------------------------------------------------------------ + * For example: + * + * struct item // definition for list items + * { + * ... + * struct item* bar_next ; + * ... + * } ; + * + * static struct base_pair(struct item*) bar_base ; + * // declaration of the list base + * + * // create item and add to list (adds at front) + * struct item* q = calloc(1, sizeof(struct item)) ; + * dsl_push(bar_base, q, bar_next) ; + * + * // remove item from list + * dsl_del(bar_base, q, bar_next) ; + * + * // walk a list + * struct item* t = dsl_head(bar_base) ; + * while (t != NULL) + * { + * .... + * t = dsl_next(t, bar_next) ; + * } + * + * // walk and empty out a list -- removing item before processing + * struct item* t ; + * while (dsl_pop(&t, bar_base, bar_next) != NULL) + * { + * .... // t points to old head of list + * } + * + * // walk and empty out a list -- removing after processing + * struct item* t ; + * while ((t = dsl_head(bar_base) != NULL) + * { + * .... + * dsl_del_head(bar_base, bar_next) ; + * } + * + * And for example: + * + * struct parent_item // parent structure containing list + * { + * .... + * struct base_pair(struct item*) bar_base ; + * .... + * } + * + * void footle(struct parent_item* parent, struct item* item) + * { + * .... + * dsl_push(parent->bar_base, item, bar_next) ; + * .... + * } + */ + + #define dsl_init(base) \ + ((base).head = (base).tail = NULL) + + #define dsl_push(base, item, next) \ + do { (item)->next = (base).head ; \ + if ((base).tail == NULL) \ + (base).tail = (item) ; \ + (base).head = (item) ; \ + } while (0) + + #define dsl_append(base, item, next) \ + do { (item)->next = NULL ; \ + if ((base).tail != NULL) \ + (base).tail->next = (item) ; \ + else \ + (base).head = (item) ; \ + (base).tail = (item) ; \ + } while (0) + + #define dsl_in_after(after, base, item, next) \ + do { (item)->next = (after)->next ; \ + (after)->next = (item) ; \ + if ((base).tail == (after)) \ + (base).tail = (item) ; \ + } while (0) + + Private bool dsl_del_func(struct dl_void_base_pair* p_base, + void* obj, size_t link_offset) + __attribute__((noinline)) ; + #define dsl_del(base, item, list) \ + dsl_del_func((struct dl_void_base_pair*)(&base), item, \ + _lu_off(item, next)) + + #define dsl_del_head(base, list) \ + do { if ((base).head != NULL) \ + { \ + (base).head = (base).head->next ; \ + if ((base).head == NULL) \ + (base).tail = NULL ; \ + } \ + } while (0) + + #define dsl_pop(dst, base, list) \ + ((*(dst) = (base).head) != NULL \ + ? ( ((base).head = (base).head->next) == NULL \ + ? ( (base).tail = NULL, *(dst) ) \ + : *(dst) ) \ + : NULL) + + #define dsl_head(base) ((base).head) + + #define dsl_tail(base) ((base).tail) + + #define dsl_next(item, list) \ + ((item) != NULL ? (item)->next : NULL) + #endif /* _ZEBRA_LIST_UTIL_H */ diff --git a/lib/qstring.h b/lib/qstring.h index b05c738b..536105d0 100644 --- a/lib/qstring.h +++ b/lib/qstring.h @@ -454,7 +454,7 @@ Inline usize qs_delete(qstring qs, usize n) } ; Inline int qs_cmp(qstring a, qstring b) ; -Inline int qs_cmp_word(qstring a, const char* w) ; +Inline int qs_cmp_word(qstring a, qstring w) ; Inline int qs_cmp_sig(qstring a, qstring b) ; Inline bool qs_equal(qstring a, qstring b) ; Inline bool qs_substring(qstring a, qstring b) ; @@ -666,9 +666,9 @@ qs_cmp(qstring a, qstring b) * Compare qstrings to given word -- see els_cmp_word */ Inline int -qs_cmp_word(qstring a, const char* w) +qs_cmp_word(qstring a, qstring w) { - return els_cmp_word(qs_els(a), w) ; + return els_cmp_word(qs_els(a), qs_els(w)) ; } ; /*------------------------------------------------------------------------------ @@ -982,17 +982,21 @@ vty_read_config_file (int fd, const char* name, cmd_command first_cmd, { cmd_return_code_t ret ; vty vty ; + qtime_t taking ; vty = vty_config_read_open(fd, name, full_lex) ; vty_cmd_loop_prepare(vty) ; - zlog_info("Started reading configuration: %s", name) ; + taking = qt_get_monotonic() ; ret = cmd_read_config(vty, first_cmd, ignore_warnings) ; - zlog_info("Finished reading configuration%s", - (ret == CMD_SUCCESS) ? "." : " -- FAILED") ; + taking = (qt_get_monotonic() - taking) / (QTIME_SECOND / 1000) ; + + zlog_info("Finished reading configuration '%s' in %d.%d secs%s", + name, (int)(taking / 1000), (int)(taking % 1000), + (ret == CMD_SUCCESS) ? "." : " -- FAILED") ; vty_cmd_loop_exit(vty) ; diff --git a/lib/vty_cli.c b/lib/vty_cli.c index 311d950c..cf85fb6c 100644 --- a/lib/vty_cli.c +++ b/lib/vty_cli.c @@ -2556,12 +2556,12 @@ uty_cli_hist_show(vty_cli cli) */ static uint uty_cli_help_parse(vty_cli cli) ; -static void uty_cli_complete_keyword(vty_cli cli, const char* keyword) ; +static void uty_cli_complete_keyword(vty_cli cli, elstring keyword) ; static void uty_cli_complete_list(vty_cli cli, vector item_v) ; static void uty_cli_describe_list(vty_cli cli, vector item_v) ; static void uty_cli_describe_line(vty_cli cli, uint str_width, const char* str, - const char* doc, uint len) ; + ulen str_len, const char* doc, ulen doc_len) ; static uint uty_cli_width_to_use(vty_cli cli) ; static void uty_cli_help_message(vty_cli cli, const char* msg) ; @@ -2717,14 +2717,14 @@ uty_cli_help_parse(vty_cli cli) * Can complete a keyword. */ static void -uty_cli_complete_keyword(vty_cli cli, const char* keyword) +uty_cli_complete_keyword(vty_cli cli, elstring keyword) { int pre, rep, ins, mov ; cmd_complete_keyword(cli->parsed, &pre, &rep, &ins, &mov) ; uty_cli_move(cli->cl, pre) ; /* move to start of token */ - uty_cli_replace(cli->cl, rep, keyword, strlen(keyword)) ; + uty_cli_replace(cli->cl, rep, els_body_nn(keyword), els_len_nn(keyword)) ; assert(ins <= 2) ; if (ins > 0) @@ -2747,22 +2747,20 @@ uty_cli_complete_keyword(vty_cli cli, const char* keyword) static void uty_cli_complete_list(vty_cli cli, vector item_v) { - uint i, len, n ; + uint i, str_width, n ; - len = 6 ; + str_width = 6 ; for (i = 0 ; i < vector_length(item_v) ; ++i) { cmd_item item ; - uint sl ; item = vector_get_item(item_v, i) ; - sl = strlen(item->str) ; - if (len < sl) - len = sl ; + if (str_width < els_len_nn(item->str)) + str_width = els_len_nn(item->str) ; } ; - n = uty_cli_width_to_use(cli) / (len + 2) ; + n = uty_cli_width_to_use(cli) / (str_width + 2) ; if (n == 0) n = 1 ; @@ -2770,12 +2768,20 @@ uty_cli_complete_list(vty_cli cli, vector item_v) for (i = 0 ; i < vector_length(item_v) ; ++i) { cmd_item item ; + ulen str_len ; + ulen pad ; + item = vector_get_item(item_v, i) ; if ((i % n) == 0) uty_cli_out_newline(cli) ; /* clears cli_drawn */ - uty_cli_out(cli, "%-*s ", len, item->str) ; + str_len = els_len_nn(item->str) ; + uty_cli_write(cli, els_body_nn(item->str), str_len) ; + + pad = (str_len < str_width) ? str_width - str_len : 0 ; + + uty_cli_write_n(cli, telnet_spaces, pad + 2) ; } uty_cli_help_newline(cli) ; } ; @@ -2811,8 +2817,8 @@ uty_cli_describe_list(vty_cli cli, vector item_v) item = vector_get_item(item_v, i) ; - len = strlen(item->str) ; - if (item->str[0] == '.') + len = els_len_nn(item->str) ; + if (*((char*)els_body_nn(item->str)) == '.') len--; if (len > str_width) @@ -2844,10 +2850,18 @@ uty_cli_describe_list(vty_cli cli, vector item_v) { cmd_item item ; const char* str, * dp, * ep ; + ulen str_len ; item = vector_get_item(item_v, i) ; - str = item->str[0] == '.' ? item->str + 1 : item->str; + str = els_body_nn(item->str) ; + str_len = els_len_nn(item->str) ; + if (*str == '.') + { + ++str ; + --str_len ; + } ; + dp = item->doc ; ep = dp + strlen(dp) ; @@ -2866,9 +2880,9 @@ uty_cli_describe_list(vty_cli cli, vector item_v) if (np == dp) /* if no space... */ np = dp + doc_width ; /* ...force break */ - uty_cli_describe_line(cli, str_width, str, dp, np - dp) ; + uty_cli_describe_line(cli, str_width, str, str_len, dp, np - dp) ; - str = ""; /* for 2nd and subsequent lines */ + str_len = 0 ; /* for 2nd and subsequent lines */ dp = np ; /* step past what just wrote */ while (*dp == ' ') @@ -2876,7 +2890,7 @@ uty_cli_describe_list(vty_cli cli, vector item_v) } ; } ; - uty_cli_describe_line(cli, str_width, str, dp, ep - dp) ; + uty_cli_describe_line(cli, str_width, str, str_len, dp, ep - dp) ; } ; uty_cli_help_newline(cli) ; @@ -2887,19 +2901,27 @@ uty_cli_describe_list(vty_cli cli, vector item_v) */ static void uty_cli_describe_line(vty_cli cli, uint str_width, const char* str, - const char* doc, uint len) + ulen str_len, const char* doc, ulen doc_len) { - if ((*str == '\0') && (len == 0)) + if ((str_len == 0) && (doc_len == 0)) return ; /* quit if nothing to say */ uty_cli_help_newline(cli) ; - if (len == 0) - uty_cli_out(cli, " %s", str) ; /* left justify */ + if (str_len > 0) + { + uty_cli_write(cli, " ", 2) ; + uty_cli_write(cli, str, str_len) ; + } else + str_width += 2 ; + + if (doc_len > 0) { - uty_cli_out(cli, " %-*s ", str_width, str) ; - uty_cli_write(cli, doc, len) ; + ulen pad ; + pad = (str_len < str_width) ? str_width - str_len : 0 ; + uty_cli_write_n(cli, telnet_spaces, pad + 2) ; + uty_cli_write(cli, doc, doc_len) ; } ; } ; diff --git a/lib/vty_io_file.c b/lib/vty_io_file.c index 4b1a8cfa..b98dd694 100644 --- a/lib/vty_io_file.c +++ b/lib/vty_io_file.c @@ -700,7 +700,7 @@ uty_file_read_close(vio_vf vf, bool final) extern cmd_return_code_t uty_file_write_close(vio_vf vf, bool final, bool base) { - VTY_ASSERT_CLI_THREAD_LOCKED() ; + VTY_ASSERT_CAN_CLOSE_VF(vf) ; assert(vf->vout_state == vf_closing) ; assert((vf->vout_type == VOUT_FILE) || (vf->vout_type == VOUT_CONFIG)) ; diff --git a/lib/vty_io_term.c b/lib/vty_io_term.c index 416968bf..857e457a 100644 --- a/lib/vty_io_term.c +++ b/lib/vty_io_term.c @@ -515,7 +515,7 @@ uty_term_ready(vio_vf vf) vio_lc_counter_reset(vf->cli->olc) ; /* do one tranche */ done = uty_term_write(vf) ; - signal = done == utw_done ; + signal = ((done == utw_done) || (done == utw_stopped)) ; while (done != utw_error) { @@ -538,7 +538,7 @@ uty_term_ready(vio_vf vf) if (done == done_before) break ; /* quit if no change in response */ - if (done == utw_done) + if ((done == utw_done) || (done == utw_stopped)) signal = true ; } ; |