]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - libsmartcols/src/filter.c
600ed0117bbccf191f7d506da08bcf3aab685197
2 * filter.c - functions for lines filtering
4 * Copyright (C) 2023 Karel Zak <kzak@redhat.com>
6 * This file may be redistributed under the terms of the
7 * GNU Lesser General Public License.
12 * @title: Filters and counters
13 * @short_description: defines lines filter and counter
15 * An API to define and use filter and counters.
23 #include "smartcolsP.h"
25 #include "filter-parser.h"
26 #include "filter-scanner.h"
30 * @str: filter expression or NULL
32 * Allocated and optionally parses a new filter.
34 * Returns: new filter instance or NULL in case of error.
38 struct libscols_filter
*scols_new_filter(const char *str
)
40 struct libscols_filter
*fltr
= calloc(1, sizeof(*fltr
));
45 DBG(FLTR
, ul_debugobj(fltr
, "alloc"));
47 INIT_LIST_HEAD(&fltr
->params
);
48 INIT_LIST_HEAD(&fltr
->counters
);
50 if (str
&& scols_filter_parse_string(fltr
, str
) != 0) {
51 scols_unref_filter(fltr
);
60 * @fltr: filter instance
62 * Increment filter reference counter.
66 void scols_ref_filter(struct libscols_filter
*fltr
)
72 static void reset_filter(struct libscols_filter
*fltr
)
76 filter_unref_node(fltr
->root
);
87 static void remove_counters(struct libscols_filter
*fltr
)
92 DBG(FLTR
, ul_debugobj(fltr
, "remove all counters"));
93 while (!list_empty(&fltr
->counters
)) {
94 struct libscols_counter
*ct
= list_entry(fltr
->counters
.next
,
95 struct libscols_counter
, counters
);
97 filter_unref_node((struct filter_node
*) ct
->param
);
98 list_del_init(&ct
->counters
);
105 * scols_unref_filter:
106 * @fltr: filter instance
108 * Deincrements reference counter, unallocates the filter for the last
113 void scols_unref_filter(struct libscols_filter
*fltr
)
115 if (fltr
&& --fltr
->refcount
<= 0) {
116 DBG(FLTR
, ul_debugobj(fltr
, "dealloc"));
118 remove_counters(fltr
);
123 /* This is generic allocater for a new node, always use the node type specific
124 * functions (e.g. filter_new_param() */
125 struct filter_node
*__filter_new_node(enum filter_ntype type
, size_t sz
)
127 struct filter_node
*n
= calloc(1, sz
);
137 void filter_unref_node(struct filter_node
*n
)
139 if (!n
|| --n
->refcount
> 0)
144 filter_free_expr((struct filter_expr
*) n
);
147 filter_free_param((struct filter_param
*) n
);
152 void filter_ref_node(struct filter_node
*n
)
158 void filter_dump_node(struct ul_jsonwrt
*json
, struct filter_node
*n
)
165 filter_dump_expr(json
, (struct filter_expr
*) n
);
168 filter_dump_param(json
, (struct filter_param
*) n
);
175 extern int yyparse(void *scanner
, struct libscols_filter
*fltr
);
178 * scols_filter_parse_string:
179 * @fltr: filter instance
180 * @str: string with filter expression
182 * Parses filter, see scols_filter_get_errmsg() for errors.
184 * Returns: 0, a negative number in case of an error.
188 int scols_filter_parse_string(struct libscols_filter
*fltr
, const char *str
)
196 return 0; /* empty filter is not error */
198 fltr
->src
= fmemopen((void *) str
, strlen(str
), "r");
203 yyset_in(fltr
->src
, sc
);
205 rc
= yyparse(sc
, fltr
);
211 ON_DBG(FLTR
, scols_dump_filter(fltr
, stderr
));
218 * @fltr: filter instance
219 * @out: output stream
221 * Dumps internal filter nodes in JSON format. This function is mostly designed
222 * for debugging purpose. The fileds in the output are subject to change.
224 * Returns: 0, a negative number in case of an error.
228 int scols_dump_filter(struct libscols_filter
*fltr
, FILE *out
)
230 struct ul_jsonwrt json
;
235 ul_jsonwrt_init(&json
, out
, 0);
236 ul_jsonwrt_root_open(&json
);
238 filter_dump_node(&json
, fltr
->root
);
239 ul_jsonwrt_root_close(&json
);
244 * scols_filter_get_errmsg:
245 * @fltr: filter instance
247 * Returns: string with parse-error message of NULL (if no error)
251 const char *scols_filter_get_errmsg(struct libscols_filter
*fltr
)
253 return fltr
? fltr
->errmsg
: NULL
;
256 int filter_eval_node(struct libscols_filter
*fltr
, struct libscols_line
*ln
,
257 struct filter_node
*n
, int *status
)
261 return filter_eval_param(fltr
, ln
, (struct filter_param
*) n
, status
);
263 return filter_eval_expr(fltr
, ln
, (struct filter_expr
*) n
, status
);
271 * scols_line_apply_filter:
272 * @ln: apply filter to the line
273 * @fltr: filter instance
274 * @status: return 1 or 0 as result of the expression
276 * Applies filter (and also counters assisiated with the filter).
278 * Returns: 0, a negative number in case of an error.
282 int scols_line_apply_filter(struct libscols_line
*ln
,
283 struct libscols_filter
*fltr
, int *status
)
286 struct libscols_iter itr
;
287 struct filter_param
*prm
= NULL
;
292 /* reset column data and types stored in the filter */
293 scols_reset_iter(&itr
, SCOLS_ITER_FORWARD
);
294 while (filter_next_param(fltr
, &itr
, &prm
) == 0) {
295 filter_param_reset_holder(prm
);
299 rc
= filter_eval_node(fltr
, ln
, fltr
->root
, &res
);
301 rc
= 0, res
= 1; /* empty filter matches all lines */
304 struct libscols_counter
*ct
= NULL
;
306 scols_reset_iter(&itr
, SCOLS_ITER_FORWARD
);
307 while (scols_filter_next_counter(fltr
, &itr
, &ct
) == 0) {
308 if ((ct
->neg
&& res
== 0) || res
== 1)
309 filter_count_param(fltr
, ln
, ct
);
315 DBG(FLTR
, ul_debugobj(fltr
, "filter done [rc=%d, status=%d]", rc
, res
));
320 * scols_filter_set_filler_cb:
321 * @fltr: filter instance
322 * @cb: application defined callback
323 * @userdata: pointer to private callback data
325 * The application can apply filter for empty lines to avoid filling the table
326 * with unnecessary data (for example if the line will be later removed from
327 * the table due to filter).
329 * This callback is used by filter to ask application to fill to the line data
330 * which are necessary to evaluate the filter expression. The callback
331 * arguments are filter, column number and userdata.
335 * ln = scols_table_new_line(tab, NULL);
337 * scols_filter_set_filler_cb(filter, my_filler, NULL);
339 * scols_line_apply_filter(line, filter, &status);
341 * scols_table_remove_line(tab, line);
342 * else for (i = 0; i < ncolumns; i++) {
343 * if (scols_line_is_filled(line, i))
345 * my_filler(NULL, ln, i, NULL);
350 * Returns: 0, a negative number in case of an error.
354 int scols_filter_set_filler_cb(struct libscols_filter
*fltr
,
355 int (*cb
)(struct libscols_filter
*,
356 struct libscols_line
*, size_t, void *),
361 fltr
->filler_cb
= cb
;
362 fltr
->filler_data
= userdata
;
368 * scols_filter_new_counter:
369 * @fltr: filter instance
371 * Alocates a new counter instance into the filter.
373 * Returns: new counter or NULL in case of an error.
377 struct libscols_counter
*scols_filter_new_counter(struct libscols_filter
*fltr
)
379 struct libscols_counter
*ct
;
384 ct
= calloc(1, sizeof(*ct
));
388 DBG(FLTR
, ul_debugobj(fltr
, "alloc counter"));
390 ct
->filter
= fltr
; /* don't use ref.counting here */
391 INIT_LIST_HEAD(&ct
->counters
);
392 list_add_tail(&ct
->counters
, &fltr
->counters
);
399 * scols_counter_set_name:
400 * @ct: counter instance
401 * @name: something for humans
403 * The name is not use by library, it's just description usable for application
404 * when prints results from countes.
406 * Returns: 0, a negative number in case of an error.
410 int scols_counter_set_name(struct libscols_counter
*ct
, const char *name
)
414 return strdup_to_struct_member(ct
, name
, name
);
418 * scols_counter_set_param:
419 * @ct: counter instance
420 * @name: holder (column) name
422 * Assigns a counter to the column. The name is used in the same way as names
423 * in the filter expression. This is usable for counter that calcuate with data
424 * from table cells (e.g. max, sum, etc.)
426 * Returns: 0, a negative number in case of an error.
430 int scols_counter_set_param(struct libscols_counter
*ct
, const char *name
)
436 filter_unref_node((struct filter_node
*) ct
->param
);
440 ct
->param
= (struct filter_param
*)
441 filter_new_param(ct
->filter
, SCOLS_DATA_U64
,
442 F_HOLDER_COLUMN
, (void *) name
);
450 * scols_counter_set_func:
451 * @ct: counter instance
452 * @func: SCOLS_COUNTER_{COUNT,MAX,MIN,SUM}
454 * Defines function to calculate data.
456 * Returns: 0, a negative number in case of an error.
460 int scols_counter_set_func(struct libscols_counter
*ct
, int func
)
462 if (!ct
|| func
< 0 || func
>= __SCOLS_NCOUNTES
)
470 * scols_counter_get_result:
471 * @ct: counter instance
473 * Returns: result from the counter
477 unsigned long long scols_counter_get_result(struct libscols_counter
*ct
)
479 return ct
? ct
->result
: 0;
483 * scols_counter_get_name:
484 * @ct: counter instance
486 * Returns: name of the counter.
490 const char *scols_counter_get_name(struct libscols_counter
*ct
)
492 return ct
? ct
->name
: NULL
;;
496 * scols_filter_next_counter:
497 * @fltr: filter instance
498 * @itr: a pointer to a struct libscols_iter instance
499 * @ct: returns the next counter
501 * Finds the next counter and returns a pointer to it via @ct.
503 * Returns: 0, a negative value in case of an error, and 1 at the end.
507 int scols_filter_next_counter(struct libscols_filter
*fltr
,
508 struct libscols_iter
*itr
, struct libscols_counter
**ct
)
512 if (!fltr
|| !itr
|| !ct
)
517 SCOLS_ITER_INIT(itr
, &fltr
->counters
);
518 if (itr
->p
!= itr
->head
) {
519 SCOLS_ITER_ITERATE(itr
, *ct
, struct libscols_counter
, counters
);