return rc;
}
+int filter_count_param(struct libscols_filter *fltr,
+ struct libscols_line *ln,
+ struct libscols_counter *ct)
+{
+ unsigned long long num;
+
+
+ if (ct->func == SCOLS_COUNTER_COUNT) {
+ ct->result++;
+ return 0;
+ }
+
+ if (ct->param) {
+ int rc;
+
+ ct->param->type = F_DATA_NUMBER;
+ rc = fetch_holder_data(fltr, ct->param, ln);
+ if (rc)
+ return rc;
+ }
+ if (!ct->param->has_value)
+ return -EINVAL;
+
+ num = ct->param->val.num;
+
+ switch (ct->func) {
+ case SCOLS_COUNTER_MAX:
+ if (num > ct->result)
+ ct->result = num;
+ break;
+ case SCOLS_COUNTER_MIN:
+ if (num < ct->result)
+ ct->result = num;
+ break;
+ case SCOLS_COUNTER_SUM:
+ ct->result += num;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ DBG(FLTR, ul_debugobj(fltr, "counted '%s' [result: %llu]", ct->name, ct->result));
+ return 0;
+}
+
static int xstrcmp(char *a, char *b)
{
if (!a && !b)
if (!fltr)
return NULL;
+
+ DBG(FLTR, ul_debugobj(fltr, "alloc"));
fltr->refcount = 1;
INIT_LIST_HEAD(&fltr->params);
+ INIT_LIST_HEAD(&fltr->counters);
if (str && scols_filter_parse_string(fltr, str) != 0) {
scols_unref_filter(fltr);
fltr->errmsg = NULL;
}
+static void remove_counters(struct libscols_filter *fltr)
+{
+ if (!fltr)
+ return;
+
+ DBG(FLTR, ul_debugobj(fltr, "remove all counters"));
+ while (!list_empty(&fltr->counters)) {
+ struct libscols_counter *ct = list_entry(fltr->counters.next,
+ struct libscols_counter, counters);
+
+ filter_unref_node((struct filter_node *) ct->param);
+ list_del_init(&ct->counters);
+ free(ct->name);
+ free(ct);
+ }
+}
+
void scols_unref_filter(struct libscols_filter *fltr)
{
if (fltr && --fltr->refcount <= 0) {
DBG(FLTR, ul_debugobj(fltr, "dealloc"));
reset_filter(fltr);
+ remove_counters(fltr);
free(fltr);
}
}
reset_filter(fltr);
+ if (!str || !*str)
+ return 0; /* empty filter is not error */
+
fltr->src = fmemopen((void *) str, strlen(str) + 1, "r");
if (!fltr->src)
return -errno;
int scols_line_apply_filter(struct libscols_line *ln,
struct libscols_filter *fltr, int *status)
{
- int rc;
+ int rc, res = 0;
struct libscols_iter itr;
struct filter_param *prm = NULL;
- if (!ln || !fltr || !fltr->root)
+ if (!ln || !fltr)
return -EINVAL;
/* reset column data and types stored in the filter */
filter_param_reset_holder(prm);
}
- rc = filter_eval_node(fltr, ln, fltr->root, status);
+ if (fltr->root)
+ rc = filter_eval_node(fltr, ln, fltr->root, &res);
+ else
+ rc = 0, res = 1; /* empty filter matches all lines */
+
+ if (rc == 0) {
+ struct libscols_counter *ct = NULL;
- DBG(FLTR, ul_debugobj(fltr, "filter done [rc=%d, status=%d]", rc, *status));
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_filter_next_counter(fltr, &itr, &ct) == 0) {
+ if ((ct->neg && res == 0) || res == 1)
+ filter_count_param(fltr, ln, ct);
+ }
+ }
+
+ if (status)
+ *status = res;
+ DBG(FLTR, ul_debugobj(fltr, "filter done [rc=%d, status=%d]", rc, res));
return rc;
}
return 0;
}
+
+struct libscols_counter *scols_filter_new_counter(struct libscols_filter *fltr)
+{
+ struct libscols_counter *ct;
+
+ if (!fltr)
+ return NULL;
+
+ ct = calloc(1, sizeof(*ct));
+ if (!ct)
+ return NULL;
+
+ DBG(FLTR, ul_debugobj(fltr, "alloc counter"));
+
+ ct->filter = fltr; /* don't use ref.counting here */
+ INIT_LIST_HEAD(&ct->counters);
+ list_add_tail(&ct->counters, &fltr->counters);
+
+
+ return ct;
+}
+
+int scols_counter_set_name(struct libscols_counter *ct, const char *name)
+{
+ if (!ct)
+ return -EINVAL;
+ return strdup_to_struct_member(ct, name, name);
+}
+
+int scols_counter_set_param(struct libscols_counter *ct, const char *name)
+{
+ if (!ct)
+ return -EINVAL;
+
+ if (ct->param) {
+ filter_unref_node((struct filter_node *) ct->param);
+ ct->param = NULL;
+ }
+ if (name) {
+ ct->param = (struct filter_param *)
+ filter_new_param(ct->filter, F_DATA_NUMBER,
+ F_HOLDER_COLUMN, (void *) name);
+ if (!ct->param)
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+int scols_counter_set_func(struct libscols_counter *ct, int func)
+{
+ if (!ct || func < 0 || func >= __SCOLS_NCOUNTES)
+ return -EINVAL;
+
+ ct->func = func;
+ return 0;
+}
+
+unsigned long long scols_counter_get_result(struct libscols_counter *ct)
+{
+ return ct ? ct->result : 0;
+}
+
+const char *scols_counter_get_name(struct libscols_counter *ct)
+{
+ return ct ? ct->name : NULL;;
+}
+
+int scols_filter_next_counter(struct libscols_filter *fltr,
+ struct libscols_iter *itr, struct libscols_counter **ct)
+{
+ int rc = 1;
+
+ if (!fltr || !itr || !ct)
+ return -EINVAL;
+ *ct = NULL;
+
+ if (!itr->head)
+ SCOLS_ITER_INIT(itr, &fltr->counters);
+ if (itr->p != itr->head) {
+ SCOLS_ITER_ITERATE(itr, *ct, struct libscols_counter, counters);
+ rc = 0;
+ }
+
+ return rc;
+}