mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
select: add support for selection to match string list subset, recognize { } operator
Using "[ ]" operator together with "&&" (or ",") inside causes the string list to be matched if and only if all the items given match the value reported and the number of items also match. This is strict list matching and the original behaviour we already have. In contrast to that, the new "{ }" operator together with "&&" inside causes the string list to be matched if and only if all the items given match the value reported but the number of items don't need to match. So we can provide a subset in selection criteria and if the subset is found, it matches. For example: $ lvs -o name,tags LV LV Tags lvol0 a lvol1 a,b lvol2 b,c,x lvol3 a,b,y $ lvs -o name,tags -S 'tags=[a,b]' LV LV Tags lvol1 a,b $ lvs -o name,tags -S 'tags={a,b}' LV LV Tags lvol1 a,b lvol3 a,b,y So in the example above the a,b is subset of a,b,y and therefore it also matches. Clearly, when using "||" (or "#") inside, the { } and [ ] is the same: $ lvs -o name,tags -S 'tags=[a#b]' LV LV Tags lvol0 a lvol1 a,b lvol2 b,c,x lvol3 a,b,y $ lvs -o name,tags -S 'tags={a#b}' LV LV Tags lvol0 a lvol1 a,b lvol2 b,c,x lvol3 a,b,y Also in addition to the above feature, fix list with single value matching when using [ ]: Before this patch: $ lvs -o name,tags -S 'tags=[a]' LV LV Tags lvol0 a lvol1 a,b lvol3 a,b,y With this patch applied: $ lvs -o name,tags -S 'tags=[a]' LV LV Tags lvol0 a In case neither [] or {} is used, assume {} (the behaviour is not changed here): $ lvs -o name,tags -S 'tags=a' LV LV Tags lvol0 a lvol1 a,b lvol3 a,b,y So in new terms 'tags=a' is equal to 'tags={a}'.
This commit is contained in:
parent
6dd98c1fa8
commit
fa793bed64
@ -1,5 +1,7 @@
|
||||
Version 1.02.89 -
|
||||
=================================
|
||||
Add support for selection to match string list subset, recognize { } operator.
|
||||
Fix string list selection with '[value]' to not match list that's superset.
|
||||
Fix string list selection to match whole words only, not prefixes.
|
||||
|
||||
Version 1.02.88 - 5th August 2014
|
||||
|
@ -131,6 +131,8 @@ static struct op_def _op_cmp[] = {
|
||||
#define SEL_LIST_MASK 0x000F0000
|
||||
#define SEL_LIST_LS 0x00010000
|
||||
#define SEL_LIST_LE 0x00020000
|
||||
#define SEL_LIST_SUBSET_LS 0x00040000
|
||||
#define SEL_LIST_SUBSET_LE 0x00080000
|
||||
|
||||
static struct op_def _op_log[] = {
|
||||
{ "&&", SEL_AND, "All fields must match" },
|
||||
@ -142,6 +144,8 @@ static struct op_def _op_log[] = {
|
||||
{ ")", SEL_PRECEDENCE_PE, "Right parenthesis" },
|
||||
{ "[", SEL_LIST_LS, "List start" },
|
||||
{ "]", SEL_LIST_LE, "List end"},
|
||||
{ "{", SEL_LIST_SUBSET_LS, "List subset start"},
|
||||
{ "}", SEL_LIST_SUBSET_LE, "List subset end"},
|
||||
{ NULL, 0, NULL},
|
||||
};
|
||||
|
||||
@ -1247,9 +1251,9 @@ static int _cmp_field_string(const char *field_id, const char *a, const char *b,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Matches if all items from selection string list match. */
|
||||
static int _cmp_field_string_list_all(const struct str_list_sort_value *val,
|
||||
const struct selection_str_list *sel)
|
||||
/* Matches if all items from selection string list match list value strictly 1:1. */
|
||||
static int _cmp_field_string_list_strict_all(const struct str_list_sort_value *val,
|
||||
const struct selection_str_list *sel)
|
||||
{
|
||||
struct dm_str_list *sel_item;
|
||||
unsigned int i = 1;
|
||||
@ -1269,7 +1273,36 @@ static int _cmp_field_string_list_all(const struct str_list_sort_value *val,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Matches if any item from selection string list matches. */
|
||||
/* Matches if all items from selection string list match a subset of list value. */
|
||||
static int _cmp_field_string_list_subset_all(const struct str_list_sort_value *val,
|
||||
const struct selection_str_list *sel)
|
||||
{
|
||||
struct dm_str_list *sel_item;
|
||||
unsigned int i = 1, last_found = 1;;
|
||||
int r = 0;
|
||||
|
||||
/* if value has no items and selection has at leas one, it's clear there's no match */
|
||||
if ((val->items[0].len == 0) && dm_list_size(sel->list))
|
||||
return 0;
|
||||
|
||||
/* Check selection is a subset of the value. */
|
||||
dm_list_iterate_items(sel_item, sel->list) {
|
||||
r = 0;
|
||||
for (i = last_found; i <= val->items[0].len; i++) {
|
||||
if ((strlen(sel_item->str) == val->items[i].len) &&
|
||||
!strncmp(sel_item->str, val->value + val->items[i].pos, val->items[i].len)) {
|
||||
last_found = i;
|
||||
r = 1;
|
||||
}
|
||||
}
|
||||
if (!r)
|
||||
break;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Matches if any item from selection string list matches list value. */
|
||||
static int _cmp_field_string_list_any(const struct str_list_sort_value *val,
|
||||
const struct selection_str_list *sel)
|
||||
{
|
||||
@ -1299,11 +1332,24 @@ static int _cmp_field_string_list(const char *field_id,
|
||||
const struct str_list_sort_value *value,
|
||||
const struct selection_str_list *selection, uint32_t flags)
|
||||
{
|
||||
int r;
|
||||
int subset, r;
|
||||
|
||||
switch (selection->type & SEL_LIST_MASK) {
|
||||
case SEL_LIST_LS:
|
||||
subset = 0;
|
||||
break;
|
||||
case SEL_LIST_SUBSET_LS:
|
||||
subset = 1;
|
||||
break;
|
||||
default:
|
||||
log_error(INTERNAL_ERROR "_cmp_field_string_list: unknown list type");
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (selection->type & SEL_MASK) {
|
||||
case SEL_AND:
|
||||
r = _cmp_field_string_list_all(value, selection);
|
||||
r = subset ? _cmp_field_string_list_subset_all(value, selection)
|
||||
: _cmp_field_string_list_strict_all(value, selection);
|
||||
break;
|
||||
case SEL_OR:
|
||||
r = _cmp_field_string_list_any(value, selection);
|
||||
@ -1932,11 +1978,11 @@ static const char *_tok_value_string_list(const struct dm_report_field_type *ft,
|
||||
struct selection_str_list *ssl = NULL;
|
||||
struct dm_str_list *item;
|
||||
const char *begin_item, *end_item, *tmp;
|
||||
uint32_t end_op_flags, end_op_flag_hit = 0;
|
||||
uint32_t op_flags, end_op_flag_expected, end_op_flag_hit = 0;
|
||||
struct dm_str_list **arr;
|
||||
size_t list_size;
|
||||
unsigned int i;
|
||||
int list_end;
|
||||
int list_end = 0;
|
||||
char c;
|
||||
|
||||
if (!(ssl = dm_pool_alloc(mem, sizeof(*ssl))) ||
|
||||
@ -1948,8 +1994,8 @@ static const char *_tok_value_string_list(const struct dm_report_field_type *ft,
|
||||
ssl->type = 0;
|
||||
*begin = s;
|
||||
|
||||
if (!_tok_op_log(s, &tmp, SEL_LIST_LS)) {
|
||||
/* Only one item - SEL_LIST_LS and SEL_LIST_LE not used */
|
||||
if (!(op_flags = _tok_op_log(s, &tmp, SEL_LIST_LS | SEL_LIST_SUBSET_LS))) {
|
||||
/* Only one item - SEL_LIST_{SUBSET_}LS and SEL_LIST_{SUBSET_}LE not used */
|
||||
c = _get_and_skip_quote_char(&s);
|
||||
if (!(s = _tok_value_string(s, &begin_item, &end_item, c, SEL_AND | SEL_OR | SEL_PRECEDENCE_PE, NULL))) {
|
||||
log_error(_str_list_item_parsing_failed, ft->id);
|
||||
@ -1957,32 +2003,47 @@ static const char *_tok_value_string_list(const struct dm_report_field_type *ft,
|
||||
}
|
||||
if (!_add_item_to_string_list(mem, begin_item, end_item, ssl->list))
|
||||
goto_bad;
|
||||
ssl->type = SEL_OR;
|
||||
ssl->type = SEL_OR | SEL_LIST_LS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* More than one item - items enclosed in SEL_LIST_LS and SEL_LIST_LE.
|
||||
/* More than one item - items enclosed in SEL_LIST_LS and SEL_LIST_LE
|
||||
* or SEL_LIST_SUBSET_LS and SEL_LIST_SUBSET_LE.
|
||||
* Each element is terminated by AND or OR operator or 'list end'.
|
||||
* The first operator hit is then the one allowed for the whole list,
|
||||
* no mixing allowed!
|
||||
*/
|
||||
end_op_flags = SEL_LIST_LE | SEL_AND | SEL_OR;
|
||||
|
||||
/* Are we using [] or {} for the list? */
|
||||
end_op_flag_expected = (op_flags == SEL_LIST_LS) ? SEL_LIST_LE : SEL_LIST_SUBSET_LE;
|
||||
|
||||
op_flags = SEL_LIST_LE | SEL_LIST_SUBSET_LE | SEL_AND | SEL_OR;
|
||||
s++;
|
||||
while (*s) {
|
||||
s = _skip_space(s);
|
||||
c = _get_and_skip_quote_char(&s);
|
||||
if (!(s = _tok_value_string(s, &begin_item, &end_item, c, end_op_flags, NULL))) {
|
||||
if (!(s = _tok_value_string(s, &begin_item, &end_item, c, op_flags, NULL))) {
|
||||
log_error(_str_list_item_parsing_failed, ft->id);
|
||||
goto bad;
|
||||
}
|
||||
s = _skip_space(s);
|
||||
|
||||
if (!(end_op_flag_hit = _tok_op_log(s, &tmp, end_op_flags))) {
|
||||
if (!(end_op_flag_hit = _tok_op_log(s, &tmp, op_flags))) {
|
||||
log_error("Invalid operator in selection list.");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
list_end = end_op_flag_hit == SEL_LIST_LE;
|
||||
if (end_op_flag_hit & (SEL_LIST_LE | SEL_LIST_SUBSET_LE)) {
|
||||
list_end = 1;
|
||||
if (end_op_flag_hit != end_op_flag_expected) {
|
||||
for (i = 0; _op_log[i].string; i++)
|
||||
if (_op_log[i].flags == end_op_flag_expected)
|
||||
break;
|
||||
log_error("List ended with incorrect character, "
|
||||
"expecting \'%s\'.", _op_log[i].string);
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
||||
if (ssl->type) {
|
||||
if (!list_end && !(ssl->type & end_op_flag_hit)) {
|
||||
@ -1990,8 +2051,12 @@ static const char *_tok_value_string_list(const struct dm_report_field_type *ft,
|
||||
"in selection list at a time.");
|
||||
goto bad;
|
||||
}
|
||||
} else
|
||||
ssl->type = list_end ? SEL_OR : end_op_flag_hit;
|
||||
} else {
|
||||
if (list_end)
|
||||
ssl->type = end_op_flag_expected == SEL_LIST_LE ? SEL_AND : SEL_OR;
|
||||
else
|
||||
ssl->type = end_op_flag_hit;
|
||||
}
|
||||
|
||||
if (!_add_item_to_string_list(mem, begin_item, end_item, ssl->list))
|
||||
goto_bad;
|
||||
@ -2002,11 +2067,17 @@ static const char *_tok_value_string_list(const struct dm_report_field_type *ft,
|
||||
break;
|
||||
}
|
||||
|
||||
if (end_op_flag_hit != SEL_LIST_LE) {
|
||||
if (!(end_op_flag_hit & (SEL_LIST_LE | SEL_LIST_SUBSET_LE))) {
|
||||
log_error("Missing list end for selection field %s", ft->id);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Store information whether [] or {} was used. */
|
||||
if ((end_op_flag_expected == SEL_LIST_LE))
|
||||
ssl->type |= SEL_LIST_LS;
|
||||
else
|
||||
ssl->type |= SEL_LIST_SUBSET_LS;
|
||||
|
||||
/* Sort the list. */
|
||||
if (!(list_size = dm_list_size(ssl->list))) {
|
||||
log_error(INTERNAL_ERROR "_tok_value_string_list: list has no items");
|
||||
|
Loading…
Reference in New Issue
Block a user