1
0
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:
Peter Rajnoha 2014-05-29 09:38:22 +02:00
parent 0103738ef5
commit d33280a978

View File

@ -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;