mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
report: select: add _check_selection fn to support checking fields against given selections
This is rebased and edited versions of the original design and patch proposed by Jun'ichi Nomura: http://www.redhat.com/archives/dm-devel/2007-April/msg00025.html The _check_selection implements the actual field checking against the selection tree.
This commit is contained in:
parent
0103738ef5
commit
d33280a978
@ -16,6 +16,8 @@
|
||||
#include "dmlib.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <math.h> /* fabs() */
|
||||
#include <float.h> /* DBL_EPSILON */
|
||||
|
||||
/*
|
||||
* Internal flags
|
||||
@ -797,6 +799,157 @@ static void *_report_get_field_data(struct dm_report *rh,
|
||||
return (void *)(ret + rh->fields[fp->field_num].offset);
|
||||
}
|
||||
|
||||
static int _cmp_field_int(const char *field_id, uint64_t a, uint64_t b, uint32_t flags)
|
||||
{
|
||||
switch(flags & FLD_CMP_MASK) {
|
||||
case FLD_CMP_EQUAL:
|
||||
return a == b;
|
||||
case FLD_CMP_NOT|FLD_CMP_EQUAL:
|
||||
return a != b;
|
||||
case FLD_CMP_NUMBER|FLD_CMP_GT:
|
||||
return a > b;
|
||||
case FLD_CMP_NUMBER|FLD_CMP_GT|FLD_CMP_EQUAL:
|
||||
return a >= b;
|
||||
case FLD_CMP_NUMBER|FLD_CMP_LT:
|
||||
return a < b;
|
||||
case FLD_CMP_NUMBER|FLD_CMP_LT|FLD_CMP_EQUAL:
|
||||
return a <= b;
|
||||
default:
|
||||
log_error(INTERNAL_ERROR "_cmp_field_int: unsupported number "
|
||||
"comparison type for field %s", field_id);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _close_enough(double d1, double d2)
|
||||
{
|
||||
return fabs(d1 - d2) < DBL_EPSILON;
|
||||
}
|
||||
|
||||
static int _cmp_field_double(const char *field_id, double a, double b, uint32_t flags)
|
||||
{
|
||||
switch(flags & FLD_CMP_MASK) {
|
||||
case FLD_CMP_EQUAL:
|
||||
return _close_enough(a, b);
|
||||
case FLD_CMP_NOT|FLD_CMP_EQUAL:
|
||||
return !_close_enough(a, b);
|
||||
case FLD_CMP_NUMBER|FLD_CMP_GT:
|
||||
return (a > b) && !_close_enough(a, b);
|
||||
case FLD_CMP_NUMBER|FLD_CMP_GT|FLD_CMP_EQUAL:
|
||||
return (a > b) || _close_enough(a, b);
|
||||
case FLD_CMP_NUMBER|FLD_CMP_LT:
|
||||
return (a < b) && !_close_enough(a, b);
|
||||
case FLD_CMP_NUMBER|FLD_CMP_LT|FLD_CMP_EQUAL:
|
||||
return a < b || _close_enough(a, b);
|
||||
default:
|
||||
log_error(INTERNAL_ERROR "_cmp_field_double: unsupported number "
|
||||
"comparison type for selection field %s", field_id);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _cmp_field_string(const char *field_id, const char *a, const char *b, uint32_t flags)
|
||||
{
|
||||
switch (flags & FLD_CMP_MASK) {
|
||||
case FLD_CMP_EQUAL:
|
||||
return !strcmp(a, b);
|
||||
case FLD_CMP_NOT|FLD_CMP_EQUAL:
|
||||
return strcmp(a, b);
|
||||
default:
|
||||
log_error(INTERNAL_ERROR "_cmp_field_string: unsupported string "
|
||||
"comparison type for selection field %s", field_id);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _cmp_field_regex(const char *s, struct dm_regex *r, uint32_t flags)
|
||||
{
|
||||
int match = dm_regex_match(r, s) >= 0;
|
||||
return flags & FLD_CMP_NOT ? !match : match;
|
||||
}
|
||||
|
||||
static int _compare_selection_field(struct dm_report *rh,
|
||||
struct dm_report_field *f,
|
||||
struct field_selection *fs)
|
||||
{
|
||||
const char *field_id = rh->fields[f->props->field_num].id;
|
||||
int r = 0;
|
||||
|
||||
if (!f->sort_value) {
|
||||
log_error("_compare_selection_field: field without value :%d",
|
||||
f->props->field_num);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fs->flags & FLD_CMP_REGEX)
|
||||
r = _cmp_field_regex((const char *) f->sort_value, fs->v.r, fs->flags);
|
||||
else {
|
||||
switch(f->props->flags & DM_REPORT_FIELD_TYPE_MASK) {
|
||||
case DM_REPORT_FIELD_TYPE_NUMBER:
|
||||
r = _cmp_field_int(field_id, *(const uint64_t *) f->sort_value, fs->v.i, fs->flags);
|
||||
break;
|
||||
case DM_REPORT_FIELD_TYPE_SIZE:
|
||||
r = _cmp_field_double(field_id, *(const uint64_t *) f->sort_value, fs->v.d, fs->flags);
|
||||
break;
|
||||
case DM_REPORT_FIELD_TYPE_STRING:
|
||||
r = _cmp_field_string(field_id, (const char *) f->sort_value, fs->v.s, fs->flags);
|
||||
break;
|
||||
default:
|
||||
log_error(INTERNAL_ERROR "_compare_selection_field: unknown field type for field %s", field_id);
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _check_selection(struct dm_report *rh, struct selection_node *sn,
|
||||
struct dm_list *fields)
|
||||
{
|
||||
int r;
|
||||
struct selection_node *iter_n;
|
||||
struct dm_report_field *f;
|
||||
|
||||
switch (sn->type & SEL_MASK) {
|
||||
case SEL_ITEM:
|
||||
r = 1;
|
||||
dm_list_iterate_items(f, fields) {
|
||||
if (sn->selection.item->fp != f->props)
|
||||
continue;
|
||||
if (!_compare_selection_field(rh, f, sn->selection.item))
|
||||
r = 0;
|
||||
}
|
||||
break;
|
||||
case SEL_OR:
|
||||
r = 0;
|
||||
dm_list_iterate_items(iter_n, &sn->selection.set)
|
||||
if ((r |= _check_selection(rh, iter_n, fields)))
|
||||
break;
|
||||
break;
|
||||
case SEL_AND:
|
||||
r = 1;
|
||||
dm_list_iterate_items(iter_n, &sn->selection.set)
|
||||
if (!(r &= _check_selection(rh, iter_n, fields)))
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
log_error("Unsupported selection type");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (sn->type & SEL_MODIFIER_NOT) ? !r : r;
|
||||
}
|
||||
|
||||
static int _check_report_selection(struct dm_report *rh, struct dm_list *fields)
|
||||
{
|
||||
if (!rh->selection_root)
|
||||
return 1;
|
||||
|
||||
return _check_selection(rh, rh->selection_root, fields);
|
||||
}
|
||||
|
||||
int dm_report_object(struct dm_report *rh, void *object)
|
||||
{
|
||||
struct field_properties *fp;
|
||||
@ -1356,7 +1509,8 @@ static struct selection_node *_parse_selection(struct dm_report *rh,
|
||||
if (!(last = _tok_value_regex(ft, last, &vs, &ve, &flags)))
|
||||
goto_bad;
|
||||
} else {
|
||||
if (ft->flags == DM_REPORT_FIELD_TYPE_SIZE)
|
||||
if (ft->flags == DM_REPORT_FIELD_TYPE_SIZE ||
|
||||
ft->flags == DM_REPORT_FIELD_TYPE_NUMBER)
|
||||
custom = &factor;
|
||||
else
|
||||
custom = NULL;
|
||||
|
Loading…
Reference in New Issue
Block a user