]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
lsfd: use filter and counters from libsmartcols
authorKarel Zak <kzak@redhat.com>
Mon, 2 Oct 2023 17:52:40 +0000 (19:52 +0200)
committerKarel Zak <kzak@redhat.com>
Mon, 20 Nov 2023 21:25:46 +0000 (22:25 +0100)
Signed-off-by: Karel Zak <kzak@redhat.com>
misc-utils/Makemodule.am
misc-utils/lsfd-counter.c [deleted file]
misc-utils/lsfd-counter.h [deleted file]
misc-utils/lsfd-filter.c [deleted file]
misc-utils/lsfd-filter.h [deleted file]
misc-utils/lsfd.c

index f55faf3d062fc37ea092583ea110470515a6c143..9e23c24e90c95cd0153bb5a4c93813563d0ad4de 100644 (file)
@@ -255,10 +255,6 @@ dist_noinst_DATA += misc-utils/lsfd.1.adoc
 lsfd_SOURCES = \
        misc-utils/lsfd.c \
        misc-utils/lsfd.h \
-       misc-utils/lsfd-filter.h \
-       misc-utils/lsfd-filter.c \
-       misc-utils/lsfd-counter.h \
-       misc-utils/lsfd-counter.c \
        misc-utils/lsfd-decode-file-flags.c \
        misc-utils/lsfd-file.c \
        misc-utils/lsfd-cdev.c \
diff --git a/misc-utils/lsfd-counter.c b/misc-utils/lsfd-counter.c
deleted file mode 100644 (file)
index 55f0fde..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * lsfd-counter.c - counter implementation used in --summary option
- *
- * Copyright (C) 2021 Red Hat, Inc.
- * Copyright (C) 2021 Masatake YAMATO <yamato@redhat.com>
- *
- * This file may be redistributed under the terms of the
- * GNU Lesser General Public License.
- */
-
-#include "lsfd-counter.h"
-
-#include "xalloc.h"
-
-struct lsfd_counter {
-       char *name;
-       size_t value;
-       struct lsfd_filter *filter;
-};
-
-struct lsfd_counter *lsfd_counter_new(const char *const name, struct lsfd_filter *filter)
-{
-       struct lsfd_counter *counter = xmalloc(sizeof(struct lsfd_counter));
-
-       counter->name = xstrdup(name);
-       counter->value = 0;
-       counter->filter = filter;
-
-       return counter;
-}
-
-void lsfd_counter_free(struct lsfd_counter *counter)
-{
-       lsfd_filter_free(counter->filter);
-       free(counter->name);
-       free(counter);
-}
-
-bool lsfd_counter_accumulate(struct lsfd_counter *counter, struct libscols_line *ln)
-{
-       if (lsfd_filter_apply(counter->filter, ln)) {
-               counter->value++;
-               return true;
-       }
-       return false;
-}
-
-const char *lsfd_counter_name(struct lsfd_counter *counter)
-{
-       return counter->name;
-}
-
-size_t lsfd_counter_value(struct lsfd_counter *counter)
-{
-       return counter->value;
-}
diff --git a/misc-utils/lsfd-counter.h b/misc-utils/lsfd-counter.h
deleted file mode 100644 (file)
index bac11a9..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * lsfd-counter.h - counter implementation used in --summary option
- *
- * Copyright (C) 2021 Red Hat, Inc.
- * Copyright (C) 2021 Masatake YAMATO <yamato@redhat.com>
- *
- * This file may be redistributed under the terms of the
- * GNU Lesser General Public License.
- */
-#ifndef UTIL_LINUX_LSFD_COUNTER_H
-#define UTIL_LINUX_LSFD_COUNTER_H
-
-#include "libsmartcols.h"
-#include "lsfd-filter.h"
-#include <stdbool.h>
-
-struct lsfd_counter;
-
-/* The created counter takes the ownership of the filter; the filter is
- * freed in lsfd_counter_free().
- */
-struct lsfd_counter *lsfd_counter_new(const char *const name, struct lsfd_filter *filter);
-void lsfd_counter_free(struct lsfd_counter *counter);
-
-bool lsfd_counter_accumulate(struct lsfd_counter *counter, struct libscols_line *ln);
-
-const char *lsfd_counter_name(struct lsfd_counter *counter);
-size_t lsfd_counter_value(struct lsfd_counter *counter);
-
-#endif /* UTIL_LINUX_LSFD_COUNTER_H */
diff --git a/misc-utils/lsfd-filter.c b/misc-utils/lsfd-filter.c
deleted file mode 100644 (file)
index 6f5561b..0000000
+++ /dev/null
@@ -1,1499 +0,0 @@
-/*
- * lsfd-filter.c - filtering engine for lsfd
- *
- * Copyright (C) 2021 Red Hat, Inc.
- * Copyright (C) 2021 Masatake YAMATO <yamato@redhat.com>
- *
- * This file may be redistributed under the terms of the
- * GNU Lesser General Public License.
- */
-
-#include "lsfd-filter.h"
-
-#include "nls.h"
-#include "strutils.h"
-#include "xalloc.h"
-
-#include <string.h>
-#include <ctype.h>
-#include <regex.h>             /* regcomp(), regexec() */
-
-/*
- * Definitions
- */
-#define COL_HEADER_EXTRA_CHARS ":-_%." /* ??? */
-#define GOT_ERROR(PARSERorFILTER)(*((PARSERorFILTER)->errmsg))
-
-/*
- * Types
- */
-
-enum token_type {
-       TOKEN_NAME,             /* [A-Za-z_][-_:%.A-Za-z0-9]* */
-       TOKEN_STR,              /* "...", '...' */
-       TOKEN_DEC,              /* [1-9][0-9]+, NOTE: negative value has not handled. */
-       TOKEN_FDEC,             /* [1-9][0-9]+\.[0-9]+ */
-       TOKEN_HEX,              /* 0x[0-9a-f]+ not implemented */
-       TOKEN_OCT,              /* 0[1-7]+ not implemented */
-       TOKEN_TRUE,             /* true */
-       TOKEN_FALSE,            /* false */
-       TOKEN_OPEN,             /* ( */
-       TOKEN_CLOSE,            /* ) */
-       TOKEN_OP1,              /* !, not */
-       TOKEN_OP2,              /* TODO: =*, !* (glob match with fnmatch() */
-       TOKEN_EOF,
-};
-
-enum op1_type {
-       OP1_NOT,
-};
-
-enum op2_type {
-       OP2_EQ,
-       OP2_NE,
-       OP2_AND,
-       OP2_OR,
-       OP2_LT,
-       OP2_LE,
-       OP2_GT,
-       OP2_GE,
-       OP2_RE_MATCH,
-       OP2_RE_UNMATCH,
-};
-
-struct token {
-       enum token_type type;
-       union {
-               char *str;
-               unsigned long long num;
-               long double fnum;
-               enum op1_type op1;
-               enum op2_type op2;
-       } val;
-};
-
-struct token_class {
-       const char * const name;
-       void (*free)(struct token *);
-       void (*dump)(struct token *, FILE *);
-};
-
-struct parameter {
-       struct libscols_column *cl;
-       bool has_value;
-       bool floating_point_num;
-       union {
-               const char *str;
-               unsigned long long num;
-               long double fnum;
-               bool boolean;
-       } val;
-};
-
-struct parser {
-       const char *expr;
-       const char *cursor;
-       int paren_level;
-       struct libscols_table *tb;
-       int (*column_name_to_id)(const char *, void *);
-       struct libscols_column *(*add_column_by_id)(struct libscols_table *, int, void*);
-       void *data;
-       struct parameter *parameters;
-       char errmsg[128];
-};
-
-enum node_type {
-       NODE_STR,
-       NODE_NUM,
-       NODE_FNUM,
-       NODE_BOOL,
-       NODE_RE,
-       NODE_OP1,
-       NODE_OP2,
-};
-
-struct node {
-       enum node_type type;
-};
-
-struct op1_class {
-       const char * const name;
-       /* Return true if acceptable. */
-       bool (*is_acceptable)(struct node *, struct parameter *, struct libscols_line *);
-       /* Return true if o.k. */
-       bool (*check_type)(struct parser *, const struct op1_class *, struct node *);
-};
-
-struct op2_class {
-       const char * const name;
-       /* Return true if acceptable. */
-       bool (*is_acceptable)(struct node *, struct node *, struct parameter *, struct libscols_line *);
-       /* Return true if o.k. */
-       bool (*check_type)(struct parser *, const struct op2_class *, struct node *, struct node *);
-};
-
-#define VAL(NODE,FIELD) (((struct node_val *)(NODE))->val.FIELD)
-#define PINDEX(NODE) (((struct node_val *)(NODE))->pindex)
-struct node_val {
-       struct node base;
-       int pindex;
-       union {
-               char *str;
-               unsigned long long num;
-               long double fnum;
-               bool boolean;
-               regex_t re;
-       } val;
-};
-
-struct node_op1 {
-       struct node base;
-       const struct op1_class *opclass;
-       struct node *arg;
-};
-
-struct node_op2 {
-       struct node base;
-       const struct op2_class *opclass;
-       struct node *args[2];
-};
-
-struct node_class {
-       const char * const name;
-       void (*free)(struct node *);
-       void (*dump)(struct node *, struct parameter*, int, FILE *);
-};
-
-struct lsfd_filter {
-       struct libscols_table *table;
-       struct node  *node;
-       struct parameter *parameters;
-       int nparams;
-       char errmsg[ sizeof_member(struct parser, errmsg) ];
-};
-
-/*
- * Prototypes
- */
-static struct node *node_val_new(enum node_type, int pindex);
-static void node_free (struct node *);
-static bool node_apply(struct node *, struct parameter *, struct libscols_line *);
-static void node_dump (struct node *, struct parameter *, int, FILE *);
-
-static struct token *token_new (void);
-static void          token_free(struct token *);
-#ifdef DEBUG
-static void          token_dump(struct token *, FILE *);
-#endif /* DEBUG */
-
-static void token_free_str(struct token *);
-
-static void token_dump_str(struct token *, FILE *);
-static void token_dump_num(struct token *, FILE *);
-static void token_dump_fnum(struct token *, FILE *);
-static void token_dump_op1(struct token *, FILE *);
-static void token_dump_op2(struct token *, FILE *);
-
-static bool op1_not(struct node *, struct parameter*, struct libscols_line *);
-static bool op1_check_type_bool_or_op(struct parser *, const struct op1_class *, struct node *);
-
-static bool op2_eq (struct node *, struct node *, struct parameter*, struct libscols_line *);
-static bool op2_ne (struct node *, struct node *, struct parameter*, struct libscols_line *);
-static bool op2_and(struct node *, struct node *, struct parameter*, struct libscols_line *);
-static bool op2_or (struct node *, struct node *, struct parameter*, struct libscols_line *);
-static bool op2_lt (struct node *, struct node *, struct parameter*, struct libscols_line *);
-static bool op2_le (struct node *, struct node *, struct parameter*, struct libscols_line *);
-static bool op2_gt (struct node *, struct node *, struct parameter*, struct libscols_line *);
-static bool op2_ge (struct node *, struct node *, struct parameter*, struct libscols_line *);
-static bool op2_re_match (struct node *, struct node *, struct parameter*, struct libscols_line *);
-static bool op2_re_unmatch (struct node *, struct node *, struct parameter*, struct libscols_line *);
-
-static bool op2_check_type_eq_or_bool_or_op(struct parser *, const struct op2_class *, struct node *, struct node *);
-static bool op2_check_type_boolean_or_op   (struct parser *, const struct op2_class *, struct node *, struct node *);
-static bool op2_check_type_num             (struct parser *, const struct op2_class *, struct node *, struct node *);
-static bool op2_check_type_re              (struct parser *, const struct op2_class *, struct node *, struct node *);
-
-static void node_str_free(struct node *);
-static void node_re_free (struct node *);
-static void node_op1_free(struct node *);
-static void node_op2_free(struct node *);
-
-static void node_str_dump (struct node *, struct parameter*, int, FILE *);
-static void node_num_dump (struct node *, struct parameter*, int, FILE *);
-static void node_fnum_dump (struct node *, struct parameter*, int, FILE *);
-static void node_bool_dump(struct node *, struct parameter*, int, FILE *);
-static void node_re_dump  (struct node *, struct parameter*, int, FILE *);
-static void node_op1_dump (struct node *, struct parameter*, int, FILE *);
-static void node_op2_dump (struct node *, struct parameter*, int, FILE *);
-
-static struct node *dparser_compile(struct parser *);
-
-/*
- * Data
- */
-#define TOKEN_CLASS(TOKEN) (&token_classes[(TOKEN)->type])
-static const struct token_class token_classes [] = {
-       [TOKEN_NAME] = {
-               .name = "NAME",
-               .free = token_free_str,
-               .dump = token_dump_str,
-       },
-       [TOKEN_STR] = {
-               .name = "STR",
-               .free = token_free_str,
-               .dump = token_dump_str,
-       },
-       [TOKEN_DEC] = {
-               .name = "DEC",
-               .dump = token_dump_num,
-       },
-       [TOKEN_FDEC] = {
-               .name = "FDEC",
-               .dump = token_dump_fnum,
-       },
-       [TOKEN_TRUE] = {
-               .name = "true",
-       },
-       [TOKEN_FALSE] = {
-               .name = "false",
-       },
-       [TOKEN_OPEN] = {
-               .name = "OPEN",
-       },
-       [TOKEN_CLOSE] = {
-               .name = "CLOSE",
-       },
-       [TOKEN_OP1] = {
-               .name = "OP1",
-               .dump = token_dump_op1,
-       },
-       [TOKEN_OP2] = {
-               .name = "OP2",
-               .dump = token_dump_op2,
-       },
-       [TOKEN_EOF] = {
-               .name = "TOKEN_EOF",
-       },
-};
-
-#define TOKEN_OP1_CLASS(TOKEN) (&(op1_classes[(TOKEN)->val.op1]))
-static const struct op1_class op1_classes [] = {
-       [OP1_NOT] = {
-               .name = "!",
-               .is_acceptable = op1_not,
-               .check_type = op1_check_type_bool_or_op,
-       },
-};
-
-#define TOKEN_OP2_CLASS(TOKEN) (&(op2_classes[(TOKEN)->val.op2]))
-static const struct op2_class op2_classes [] = {
-       [OP2_EQ] = {
-               .name = "==",
-               .is_acceptable = op2_eq,
-               .check_type = op2_check_type_eq_or_bool_or_op
-       },
-       [OP2_NE] = {
-               .name = "!=",
-               .is_acceptable = op2_ne,
-               .check_type = op2_check_type_eq_or_bool_or_op,
-       },
-       [OP2_AND] = {
-               .name = "&&",
-               .is_acceptable = op2_and,
-               .check_type = op2_check_type_boolean_or_op,
-       },
-       [OP2_OR] = {
-               .name = "||",
-               .is_acceptable = op2_or,
-               .check_type = op2_check_type_boolean_or_op,
-       },
-       [OP2_LT] = {
-               .name = "<",
-               .is_acceptable = op2_lt,
-               .check_type = op2_check_type_num,
-       },
-       [OP2_LE] = {
-               .name = "<=",
-               .is_acceptable = op2_le,
-               .check_type = op2_check_type_num,
-       },
-       [OP2_GT] = {
-               .name = ">",
-               .is_acceptable = op2_gt,
-               .check_type = op2_check_type_num,
-       },
-       [OP2_GE] = {
-               .name = ">=",
-               .is_acceptable = op2_ge,
-               .check_type = op2_check_type_num,
-       },
-       [OP2_RE_MATCH] = {
-               .name = "=~",
-               .is_acceptable = op2_re_match,
-               .check_type = op2_check_type_re,
-       },
-       [OP2_RE_UNMATCH] = {
-               .name = "!~",
-               .is_acceptable = op2_re_unmatch,
-               .check_type = op2_check_type_re,
-       },
-};
-
-#define NODE_CLASS(NODE) (&node_classes[(NODE)->type])
-static const struct node_class node_classes[] = {
-       [NODE_STR] = {
-               .name = "STR",
-               .free = node_str_free,
-               .dump = node_str_dump,
-       },
-       [NODE_NUM] = {
-               .name = "NUM",
-               .dump = node_num_dump,
-       },
-       [NODE_FNUM] = {
-               .name = "FNUM",
-               .dump = node_fnum_dump,
-       },
-       [NODE_BOOL] = {
-               .name = "BOOL",
-               .dump = node_bool_dump,
-       },
-       [NODE_RE] = {
-               .name = "STR",
-               .free = node_re_free,
-               .dump = node_re_dump,
-       },
-       [NODE_OP1]   = {
-               .name = "OP1",
-               .free = node_op1_free,
-               .dump = node_op1_dump,
-       },
-       [NODE_OP2]   = {
-               .name = "OP2",
-               .free = node_op2_free,
-               .dump = node_op2_dump,
-       }
-};
-
-/*
- * Functions
- */
-static int strputc(char **a, const char b)
-{
-       return strappend(a, (char [2]){b, '\0'});
-}
-
-static void xstrputc(char **a, const char b)
-{
-       int rc = strputc(a, b);
-       if (rc < 0)
-               errx(EXIT_FAILURE, _("failed to allocate memory"));
-}
-
-static void parser_init(struct parser *parser, const char *const expr, struct libscols_table *tb,
-                       int ncols,
-                       int (*column_name_to_id)(const char *, void *),
-                       struct libscols_column *(*add_column_by_id)(struct libscols_table *, int, void*),
-                       void *data)
-{
-       parser->expr = expr;
-       parser->cursor = parser->expr;
-       parser->paren_level = 0;
-       parser->tb = tb;
-       parser->column_name_to_id = column_name_to_id;
-       parser->add_column_by_id = add_column_by_id;
-       parser->data = data;
-       parser->parameters = xcalloc(ncols, sizeof(struct parameter));
-       parser->errmsg[0] = '\0';
-}
-
-static char parser_getc(struct parser *parser)
-{
-       char c = *parser->cursor;
-       if (c != '\0')
-               parser->cursor++;
-       return c;
-}
-
-static void parser_ungetc(struct parser *parser, char c)
-{
-       assert(parser->cursor > parser->expr);
-       if (c != '\0')
-               parser->cursor--;
-}
-
-static void parser_read_str(struct parser *parser, struct token *token, char delimiter)
-{
-       bool escape = false;
-       while (1) {
-               char c = parser_getc(parser);
-
-               if (c == '\0') {
-                       snprintf(parser->errmsg, sizeof(parser->errmsg),
-                                _("error: string literal is not terminated: %s"),
-                                token->val.str? : "");
-                       return;
-               } else if (escape) {
-                       switch (c) {
-                       case '\\':
-                       case '\'':
-                       case '"':
-                               xstrputc(&token->val.str, c);
-                               break;
-                       case 'n':
-                               xstrputc(&token->val.str, '\n');
-                               break;
-                       case 't':
-                               xstrputc(&token->val.str, '\t');
-                               break;
-                               /* TODO: \f, \r, ... */
-                       default:
-                               xstrputc(&token->val.str, '\\');
-                               xstrputc(&token->val.str, c);
-                               return;
-                       }
-                       escape = false;
-               } else if (c == delimiter) {
-                       if (token->val.str == NULL)
-                               token->val.str = xstrdup("");
-                       return;
-               } else if (c == '\\')
-                       escape = true;
-               else
-                       xstrputc(&token->val.str, c);
-       }
-}
-
-static void parser_read_name(struct parser *parser, struct token *token)
-{
-       while (1) {
-               char c = parser_getc(parser);
-               if (c == '\0')
-                       break;
-               if (strchr(COL_HEADER_EXTRA_CHARS, c) || isalnum((unsigned char)c)) {
-                       xstrputc(&token->val.str, c);
-                       continue;
-               }
-               parser_ungetc(parser, c);
-               break;
-       }
-}
-
-static int parser_read_dec(struct parser *parser, struct token *token)
-{
-       int rc = 0;
-       int found_point = 0;
-       while (1) {
-               char c = parser_getc(parser);
-               if (c == '\0')
-                       break;
-               if (isdigit((unsigned char)c)
-                   || (found_point == 0 && c == '.')) {
-                       xstrputc(&token->val.str, c);
-                       if (c == '.')
-                               found_point++;
-                       continue;
-               }
-               parser_ungetc(parser, c);
-               break;
-       }
-
-       char *endptr = NULL;
-       errno = 0;
-       unsigned long long num = strtoull(token->val.str, &endptr, 10);
-       rc = errno;
-       if (rc)
-               return rc;
-
-       if (endptr && *endptr == '.') {
-               errno = 0;
-               long double fnum = strtold(endptr, NULL);
-               rc = errno;
-               if (rc)
-                       return rc;
-               free(token->val.str);
-               token->type = TOKEN_FDEC;
-               token->val.fnum = ((long double)num) + fnum;
-       } else {
-               free(token->val.str);
-               token->type = TOKEN_DEC;
-               token->val.num = num;
-       }
-
-       return 0;
-}
-
-static struct token *parser_read(struct parser *parser)
-{
-       struct token *t = token_new();
-       char c, c0;
-
-       do
-               c = parser_getc(parser);
-       while (isspace((unsigned char)c));
-
-       switch (c) {
-       case '\0':
-               t->type = TOKEN_EOF;
-               break;
-       case '(':
-               t->type = TOKEN_OPEN;
-               parser->paren_level++;
-               break;
-       case ')':
-               t->type = TOKEN_CLOSE;
-               parser->paren_level--;
-               if (parser->paren_level < 0)
-                       snprintf(parser->errmsg, sizeof(parser->errmsg),
-                                _("error: unbalanced parenthesis: %s"), parser->cursor - 1);
-               break;
-       case '!':
-               c0 = parser_getc(parser);
-               if (c0 == '=') {
-                       t->type = TOKEN_OP2;
-                       t->val.op2 = OP2_NE;
-                       break;
-               } else if (c0 == '~') {
-                       t->type = TOKEN_OP2;
-                       t->val.op2 = OP2_RE_UNMATCH;
-                       break;
-               }
-               parser_ungetc(parser, c0);
-               t->type = TOKEN_OP1;
-               t->val.op1 = OP1_NOT;
-               break;
-       case '<':
-               t->type = TOKEN_OP2;
-               c0 = parser_getc(parser);
-               if (c0 == '=') {
-                       t->val.op2 = OP2_LE;
-                       break;
-               }
-               parser_ungetc(parser, c0);
-               t->val.op2 = OP2_LT;
-               break;
-       case '>':
-               t->type = TOKEN_OP2;
-               c0 = parser_getc(parser);
-               if (c0 == '=') {
-                       t->val.op2 = OP2_GE;
-                       break;
-               }
-               parser_ungetc(parser, c0);
-               t->val.op2 = OP2_GT;
-               break;
-       case '=':
-               c0 = parser_getc(parser);
-               if (c0 == '=') {
-                       t->type = TOKEN_OP2;
-                       t->val.op2 = OP2_EQ;
-                       break;
-               } else if (c0 == '~') {
-                       t->type = TOKEN_OP2;
-                       t->val.op2 = OP2_RE_MATCH;
-                       break;
-               }
-               snprintf(parser->errmsg, sizeof(parser->errmsg),
-                        _("error: unexpected character %c after ="), c0);
-               break;
-       case '&':
-               c0 = parser_getc(parser);
-               if (c0 == '&') {
-                       t->type = TOKEN_OP2;
-                       t->val.op2 = OP2_AND;
-                       break;
-               }
-               snprintf(parser->errmsg, sizeof(parser->errmsg),
-                        _("error: unexpected character %c after ="), c0);
-               break;
-       case '|':
-               c0 = parser_getc(parser);
-               if (c0 == '|') {
-                       t->type = TOKEN_OP2;
-                       t->val.op2 = OP2_OR;
-                       break;
-               }
-               snprintf(parser->errmsg, sizeof(parser->errmsg),
-                        _("error: unexpected character %c after ="), c0);
-               break;
-       case '"':
-       case '\'':
-               t->type = TOKEN_STR;
-               parser_read_str(parser, t, c);
-               break;
-       default:
-               if (isalpha((unsigned char)c) || c == '_') {
-                       xstrputc(&t->val.str, c);
-                       parser_read_name(parser, t);
-                       if (strcmp(t->val.str, "true") == 0) {
-                               free(t->val.str);
-                               t->type = TOKEN_TRUE;
-                       } else if (strcmp(t->val.str, "false") == 0) {
-                               free(t->val.str);
-                               t->type = TOKEN_FALSE;
-                       } else if (strcmp(t->val.str, "or") == 0) {
-                               free(t->val.str);
-                               t->type = TOKEN_OP2;
-                               t->val.op2 = OP2_OR;
-                       } else if (strcmp(t->val.str, "and") == 0) {
-                               free(t->val.str);
-                               t->type = TOKEN_OP2;
-                               t->val.op2 = OP2_AND;
-                       } else if (strcmp(t->val.str, "eq") == 0) {
-                               free(t->val.str);
-                               t->type = TOKEN_OP2;
-                               t->val.op2 = OP2_EQ;
-                       } else if (strcmp(t->val.str, "ne") == 0) {
-                               free(t->val.str);
-                               t->type = TOKEN_OP2;
-                               t->val.op2 = OP2_NE;
-                       } else if (strcmp(t->val.str, "lt") == 0) {
-                               free(t->val.str);
-                               t->type = TOKEN_OP2;
-                               t->val.op2 = OP2_LT;
-                       } else if (strcmp(t->val.str, "le") == 0) {
-                               free(t->val.str);
-                               t->type = TOKEN_OP2;
-                               t->val.op2 = OP2_LE;
-                       } else if (strcmp(t->val.str, "gt") == 0) {
-                               free(t->val.str);
-                               t->type = TOKEN_OP2;
-                               t->val.op2 = OP2_GT;
-                       } else if (strcmp(t->val.str, "ge") == 0) {
-                               free(t->val.str);
-                               t->type = TOKEN_OP2;
-                               t->val.op2 = OP2_GE;
-                       } else if (strcmp(t->val.str, "not") == 0) {
-                               free(t->val.str);
-                               t->type = TOKEN_OP1;
-                               t->val.op1 = OP1_NOT;
-                       } else
-                               t->type = TOKEN_NAME;
-                       break;
-               } else if (isdigit((unsigned char)c)) {
-                       xstrputc(&t->val.str, c);
-                       if (parser_read_dec(parser, t) != 0) {
-                               snprintf(parser->errmsg, sizeof(parser->errmsg),
-                                        _("error: failed to convert input to number: %s"),
-                                        t->val.str);
-                               free(t->val.str);
-                       }
-                       break;
-               }
-               snprintf(parser->errmsg, sizeof(parser->errmsg),
-                        _("error: unexpected character %c"), c);
-               break;
-       }
-       return t;
-}
-
-static void parameter_init(struct parameter *param, struct libscols_column *cl)
-{
-       param->cl = cl;
-       param->has_value = false;
-       param->floating_point_num = false;
-}
-
-static struct node *dparser_compile1(struct parser *parser, struct node *last)
-{
-       struct token *t = parser_read(parser);
-
-       if (GOT_ERROR(parser)) {
-               token_free(t);
-               return NULL;
-       }
-
-       if (t->type == TOKEN_EOF) {
-               token_free(t);
-               return last;
-       }
-       if (t->type == TOKEN_CLOSE) {
-               token_free(t);
-               return last;
-       }
-
-       if (last) {
-               switch (t->type) {
-               case TOKEN_NAME:
-               case TOKEN_STR:
-               case TOKEN_DEC:
-               case TOKEN_FDEC:
-               case TOKEN_TRUE:
-               case TOKEN_FALSE:
-               case TOKEN_OPEN:
-               case TOKEN_OP1:
-                       snprintf(parser->errmsg, sizeof(parser->errmsg),
-                                _("error: unexpected token: %s after %s"), t->val.str,
-                                NODE_CLASS(last)->name);
-                       token_free(t);
-                       return NULL;
-               default:
-                       break;
-               }
-       } else {
-               switch (t->type) {
-               case TOKEN_OP2:
-                       snprintf(parser->errmsg, sizeof(parser->errmsg),
-                                _("error: empty left side expression: %s"),
-                                TOKEN_OP2_CLASS(t)->name);
-                       token_free(t);
-                       return NULL;
-               default:
-                       break;
-               }
-       }
-
-       struct node *node = NULL;
-       switch (t->type) {
-       case TOKEN_NAME: {
-               int col_id = parser->column_name_to_id(t->val.str, parser->data);
-               if (col_id == LSFD_FILTER_UNKNOWN_COL_ID) {
-                       snprintf(parser->errmsg, sizeof(parser->errmsg),
-                                _("error: no such column: %s"), t->val.str);
-                       token_free(t);
-                       return NULL;
-
-               }
-
-               struct libscols_column *cl = scols_table_get_column_by_name(parser->tb, t->val.str);
-               if (!cl) {
-                       cl = parser->add_column_by_id(parser->tb, col_id, parser->data);
-                       if (!cl) {
-                               snprintf(parser->errmsg, sizeof(parser->errmsg),
-                                        _("error: cannot add a column to table: %s"), t->val.str);
-                               token_free(t);
-                               return NULL;
-                       }
-                       scols_column_set_flags(cl, SCOLS_FL_HIDDEN);
-               }
-               parameter_init(parser->parameters + col_id, cl);
-
-               int jtype = scols_column_get_json_type(cl);
-               int ntype;
-               switch (jtype) {
-               case SCOLS_JSON_STRING:
-               case SCOLS_JSON_ARRAY_STRING:
-               case SCOLS_JSON_ARRAY_NUMBER:
-                       /* We handles SCOLS_JSON_ARRAY_* as a string
-                        * till we implement operators for arrays. */
-                       ntype = NODE_STR;
-                       break;
-               case SCOLS_JSON_NUMBER:
-                       ntype = NODE_NUM;
-                       break;
-               case SCOLS_JSON_BOOLEAN:
-                       ntype = NODE_BOOL;
-                       break;
-               default:
-                       snprintf(parser->errmsg, sizeof(parser->errmsg),
-                                _("error: unsupported column data type: %d, column: %s"),
-                                jtype, t->val.str);
-                       return NULL;
-               }
-               node = node_val_new(ntype, col_id);
-               token_free(t);
-               return node;
-       }
-
-       case TOKEN_STR:
-               node = node_val_new(NODE_STR, -1);
-               VAL(node, str) = xstrdup(t->val.str);
-               token_free(t);
-               return node;
-
-       case TOKEN_DEC:
-               node = node_val_new(NODE_NUM, -1);
-               VAL(node, num) = t->val.num;
-               token_free(t);
-               return node;
-       case TOKEN_FDEC:
-               node = node_val_new(NODE_FNUM, -1);
-               VAL(node, fnum) = t->val.fnum;
-               token_free(t);
-               return node;
-
-       case TOKEN_TRUE:
-       case TOKEN_FALSE:
-               node = node_val_new(NODE_BOOL, -1);
-               VAL(node, boolean) = (t->type == TOKEN_TRUE);
-               token_free(t);
-               return node;
-
-       case TOKEN_OPEN:
-               token_free(t);
-               return dparser_compile(parser);
-
-       case TOKEN_OP1: {
-               struct node *op1_right = dparser_compile1(parser, NULL);
-               const struct op1_class *op1_class = TOKEN_OP1_CLASS(t);
-
-               token_free(t);
-
-               if (GOT_ERROR(parser)) {
-                       node_free(op1_right);
-                       return NULL;
-               }
-
-               if (op1_right == NULL) {
-                       snprintf(parser->errmsg, sizeof(parser->errmsg),
-                                _("error: empty right side expression: %s"),
-                                op1_class->name);
-                       return NULL;
-               }
-
-               if (!op1_class->check_type(parser, op1_class, op1_right)) {
-                       node_free(op1_right);
-                       return NULL;
-               }
-
-               node = xmalloc(sizeof(struct node_op1));
-               node->type = NODE_OP1;
-               ((struct node_op1 *)node)->opclass = op1_class;
-               ((struct node_op1 *)node)->arg = op1_right;
-
-               return node;
-       }
-
-       case TOKEN_OP2: {
-               struct node *op2_right = dparser_compile1(parser, NULL);
-               const struct op2_class *op2_class = TOKEN_OP2_CLASS(t);
-
-               token_free(t);
-
-               if (GOT_ERROR(parser)) {
-                       node_free(op2_right);
-                       return NULL;
-               }
-               if (op2_right == NULL) {
-                       snprintf(parser->errmsg, sizeof(parser->errmsg),
-                                _("error: empty right side expression: %s"),
-                                op2_class->name);
-                       return NULL;
-               }
-
-               if (!op2_class->check_type(parser, op2_class, last, op2_right)) {
-                       node_free(op2_right);
-                       return NULL;
-               }
-
-               node = xmalloc(sizeof(struct node_op2));
-               node->type = NODE_OP2;
-               ((struct node_op2 *)node)->opclass = op2_class;
-               ((struct node_op2 *)node)->args[0] = last;
-               ((struct node_op2 *)node)->args[1] = op2_right;
-
-               return node;
-       }
-
-       default:
-               warnx("unexpected token type: %d", t->type);
-               token_free(t);
-               return NULL;
-       }
-}
-
-static struct node *dparser_compile(struct parser *parser)
-{
-       struct node *node = NULL;
-
-       while (true) {
-               struct node *node0 = dparser_compile1(parser, node);
-               if (GOT_ERROR(parser)) {
-                       node_free(node);
-                       return NULL;
-               }
-
-               if (node == node0) {
-                       if (node == NULL)
-                               xstrncpy(parser->errmsg,
-                                       _("error: empty filter expression"),
-                                       sizeof(parser->errmsg));
-                       return node;
-               }
-               node = node0;
-       }
-}
-
-static struct token *token_new(void)
-{
-       return xcalloc(1, sizeof(struct token));
-}
-
-static void token_free(struct token *token)
-{
-       if (TOKEN_CLASS(token)->free)
-               TOKEN_CLASS(token)->free(token);
-       free(token);
-}
-
-#ifdef DEBUG
-static void token_dump(struct token *token, FILE *stream)
-{
-       fprintf(stream, "<%s>", TOKEN_CLASS(token)->name);
-       if (TOKEN_CLASS(token)->dump)
-               TOKEN_CLASS(token)->dump(token, stream);
-       fputc('\n', stream);
-}
-#endif /* DEBUG */
-
-static void token_free_str(struct token *token)
-{
-       free(token->val.str);
-}
-
-static void token_dump_str(struct token *token, FILE *stream)
-{
-       fputs(token->val.str, stream);
-}
-
-static void token_dump_num(struct token *token, FILE *stream)
-{
-       fprintf(stream, "%llu", token->val.num);
-}
-
-static void token_dump_fnum(struct token *token, FILE *stream)
-{
-       fprintf(stream, "%Lf", token->val.fnum);
-}
-
-static void token_dump_op1(struct token *token, FILE *stream)
-{
-       fputs(TOKEN_OP1_CLASS(token)->name, stream);
-}
-
-static void token_dump_op2(struct token *token, FILE *stream)
-{
-       fputs(TOKEN_OP2_CLASS(token)->name, stream);
-}
-
-static struct node *node_val_new(enum node_type type, int pindex)
-{
-       struct node *node = xmalloc(sizeof(struct node_val));
-       node->type = type;
-       PINDEX(node) = pindex;
-       return node;
-}
-
-static void node_free(struct node *node)
-{
-       if (node == NULL)
-               return;
-       if (NODE_CLASS(node)->free)
-               NODE_CLASS(node)->free(node);
-       free(node);
-}
-
-static bool node_apply(struct node *node, struct parameter *params, struct libscols_line *ln)
-{
-       if (!node)
-               return true;
-
-       switch (node->type) {
-       case NODE_OP1: {
-               struct node_op1 *node_op1 = (struct node_op1*)node;
-               return node_op1->opclass->is_acceptable(node_op1->arg, params, ln);
-       }
-       case NODE_OP2: {
-               struct node_op2 *node_op2 = (struct node_op2*)node;
-               return node_op2->opclass->is_acceptable(node_op2->args[0], node_op2->args[1], params, ln);
-       }
-       case NODE_BOOL:
-               if (PINDEX(node) < 0)
-                       return VAL(node,boolean);
-
-               if (!params[PINDEX(node)].has_value) {
-                       const char *data = scols_line_get_column_data(ln, params[PINDEX(node)].cl);
-                       if (data == NULL)
-                               return false;
-                       params[PINDEX(node)].val.boolean = !*data ? false :
-                               *data == '0' ? false :
-                               *data == 'N' || *data == 'n' ? false : true;
-                       params[PINDEX(node)].has_value = true;
-               }
-               return params[PINDEX(node)].val.boolean;
-       default:
-               warnx(_("unexpected type in filter application: %s"), NODE_CLASS(node)->name);
-               return false;
-       }
-}
-
-static void node_dump(struct node *node, struct parameter *param, int depth, FILE *stream)
-{
-       int i;
-
-       if (!node)
-               return;
-
-       for (i = 0; i < depth; i++)
-               fputc(' ', stream);
-       fputs(NODE_CLASS(node)->name, stream);
-       if (NODE_CLASS(node)->dump)
-               NODE_CLASS(node)->dump(node, param, depth, stream);
-}
-
-static void node_str_dump(struct node *node, struct parameter* params, int depth __attribute__((__unused__)), FILE *stream)
-{
-       if (PINDEX(node) >= 0)
-               fprintf(stream, ": |%s|\n", scols_column_get_name(params[PINDEX(node)].cl));
-       else
-               fprintf(stream, ": '%s'\n", VAL(node,str));
-}
-
-static void node_num_dump(struct node *node, struct parameter* params, int depth __attribute__((__unused__)), FILE *stream)
-{
-       if (PINDEX(node) >= 0)
-               fprintf(stream, ": |%s|\n", scols_column_get_name(params[PINDEX(node)].cl));
-       else
-               fprintf(stream, ": %llu\n", VAL(node,num));
-}
-
-static void node_fnum_dump(struct node *node, struct parameter* params, int depth __attribute__((__unused__)), FILE *stream)
-{
-       if (PINDEX(node) >= 0)
-               fprintf(stream, ": |%s|\n", scols_column_get_name(params[PINDEX(node)].cl));
-       else
-               fprintf(stream, ": %Lf\n", VAL(node,fnum));
-}
-
-static void node_bool_dump(struct node *node, struct parameter* params, int depth __attribute__((__unused__)), FILE *stream)
-{
-       if (PINDEX(node) >= 0)
-               fprintf(stream, ": |%s|\n", scols_column_get_name(params[PINDEX(node)].cl));
-       else
-               fprintf(stream, ": %s\n",
-                       VAL(node,boolean)
-                       ? token_classes[TOKEN_TRUE].name
-                       : token_classes[TOKEN_FALSE].name);
-}
-
-static void node_re_dump(struct node *node, struct parameter* params __attribute__((__unused__)),
-                        int depth __attribute__((__unused__)), FILE *stream)
-{
-       fprintf(stream, ": #<regexp %p>\n", &VAL(node,re));
-}
-
-static void node_op1_dump(struct node *node, struct parameter* params, int depth, FILE *stream)
-{
-       fprintf(stream, ": %s\n", ((struct node_op1 *)node)->opclass->name);
-       node_dump(((struct node_op1 *)node)->arg, params, depth + 4, stream);
-}
-
-static void node_op2_dump(struct node *node, struct parameter* params, int depth, FILE *stream)
-{
-       int i;
-
-       fprintf(stream, ": %s\n", ((struct node_op2 *)node)->opclass->name);
-       for (i = 0; i < 2; i++)
-               node_dump(((struct node_op2 *)node)->args[i], params, depth + 4, stream);
-}
-
-static void node_str_free(struct node *node)
-{
-       if (PINDEX(node) < 0)
-               free(VAL(node,str));
-}
-
-static void node_re_free(struct node *node)
-{
-       regfree(&VAL(node,re));
-}
-
-static void node_op1_free(struct node *node)
-{
-       node_free(((struct node_op1 *)node)->arg);
-}
-
-static void node_op2_free(struct node *node)
-{
-       int i;
-
-       for (i = 0; i < 2; i++)
-               node_free(((struct node_op2 *)node)->args[i]);
-}
-
-static bool op1_not(struct node *node, struct parameter* params, struct libscols_line * ln)
-{
-       return !node_apply(node, params, ln);
-}
-
-static bool op1_check_type_bool_or_op(struct parser* parser, const struct op1_class *op1_class,
-                                     struct node *node)
-{
-       if (! (node->type == NODE_OP1 || node->type == NODE_OP2 || node->type == NODE_BOOL)) {
-               snprintf(parser->errmsg, sizeof(parser->errmsg),
-                        _("error: unexpected operand type %s for: %s"),
-                        NODE_CLASS(node)->name,
-                        op1_class->name);
-               return false;
-       }
-       return true;
-}
-
-#define OP2_GET_STR(NODE,DEST) do {                                    \
-       int pindex = PINDEX(NODE);                                      \
-       if (pindex < 0)                                                 \
-               DEST = VAL(NODE,str);                                   \
-       else {                                                          \
-               struct parameter *p = params + pindex;                  \
-               if (!p->has_value) {                                    \
-                       p->val.str = scols_line_get_column_data(ln, p->cl); \
-                       if (p->val.str == NULL) return false;           \
-                       p->has_value = true;                            \
-               }                                                       \
-               DEST = p->val.str;                                      \
-       }                                                               \
-} while(0)
-
-struct compnum {
-       bool floating_point_num;
-       union {
-               unsigned long long v;
-               long double fv;
-       };
-};
-
-#define OP2_GET_NUM(NODE,DEST) do {                                    \
-       int pindex = PINDEX(NODE);                                      \
-       if (pindex < 0) {                                               \
-               if (NODE->type == NODE_NUM) {                           \
-                       DEST.v = VAL(NODE,num);                         \
-                       DEST.floating_point_num = false;                \
-               } else {                                                \
-                       DEST.fv = VAL(NODE,fnum);                       \
-                       DEST.floating_point_num = true;                 \
-               }                                                       \
-       } else {                                                        \
-               struct parameter *p = params + pindex;                  \
-               if (!p->has_value) {                                    \
-                       unsigned long long val;                         \
-                       char *endptr = NULL;                            \
-                       const char *tmp = scols_line_get_column_data(ln, p->cl); \
-                       if (tmp == NULL) return false;                  \
-                       val = strtoull(tmp, &endptr, 10);               \
-                       if (endptr && endptr[0] == '.') {               \
-                               long double fval = strtold(endptr, NULL); \
-                               if (fval != 0.0) {                      \
-                                       p->val.fnum = val + fval;       \
-                                       p->floating_point_num = true;   \
-                               } else {                                \
-                                       p->val.num = val;               \
-                                       p->floating_point_num = false;  \
-                               }                                       \
-                       } else {                                        \
-                               p->val.num = val;                       \
-                               p->floating_point_num = false;          \
-                       }                                               \
-                       p->has_value = true;                            \
-               }                                                       \
-               if (p->floating_point_num) {                            \
-                       DEST.fv = p->val.fnum;                          \
-                       DEST.floating_point_num = true;                 \
-               } else {                                                \
-                       DEST.v = p->val.num;                            \
-                       DEST.floating_point_num = false;                \
-               }                                                       \
-       }                                                               \
-} while(0)
-
-#define OP2_NUM_CMP_BODY(OP) do {                                      \
-       struct compnum lv, rv;                                          \
-       OP2_GET_NUM(left,lv);                                           \
-       OP2_GET_NUM(right,rv);                                          \
-       if (lv.floating_point_num && rv.floating_point_num)             \
-               return lv.fv OP rv.fv;                                  \
-       else if (! (lv.floating_point_num || rv.floating_point_num))    \
-               return lv.v OP rv.v;                                    \
-       else if (lv.floating_point_num)                                 \
-               return lv.fv OP ((long double)rv.v);                    \
-       else                                                            \
-               return ((long double)lv.v) OP rv.fv;                    \
-} while(0)
-
-#define OP2_EQ_BODY(OP,ELSEVAL) do {                                   \
-       if (left->type == NODE_STR) {                                   \
-               const char *lv, *rv;                                    \
-               OP2_GET_STR(left,lv);                                   \
-               OP2_GET_STR(right,rv);                                  \
-               return strcmp(lv, rv) OP 0;                             \
-       } else if (left->type == NODE_NUM || left->type == NODE_FNUM) { \
-               OP2_NUM_CMP_BODY(OP);                                   \
-       } else {                                                        \
-               return node_apply(left, params, ln) OP node_apply(right, params, ln); \
-       }                                                               \
-} while(0)
-
-static bool op2_eq(struct node *left, struct node *right, struct parameter *params, struct libscols_line *ln)
-{
-       OP2_EQ_BODY(==, false);
-}
-
-static bool op2_ne(struct node *left, struct node *right, struct parameter *params, struct libscols_line *ln)
-{
-       OP2_EQ_BODY(!=, true);
-}
-
-static bool op2_and(struct node *left, struct node *right, struct parameter *params, struct libscols_line *ln)
-{
-       return node_apply(left, params, ln) && node_apply(right, params, ln);
-}
-
-static bool op2_or(struct node *left, struct node *right, struct parameter *params, struct libscols_line *ln)
-{
-       return node_apply(left, params, ln) || node_apply(right, params, ln);
-}
-
-static bool op2_lt(struct node *left, struct node *right, struct parameter *params, struct libscols_line *ln)
-{
-       OP2_NUM_CMP_BODY(<);
-}
-
-static bool op2_le(struct node *left, struct node *right, struct parameter *params, struct libscols_line *ln)
-{
-       OP2_NUM_CMP_BODY(<=);
-}
-
-static bool op2_gt(struct node *left, struct node *right, struct parameter *params, struct libscols_line *ln)
-{
-       OP2_NUM_CMP_BODY(>);
-}
-
-static bool op2_ge(struct node *left, struct node *right, struct parameter *params, struct libscols_line *ln)
-{
-       OP2_NUM_CMP_BODY(>=);
-}
-
-static bool op2_re_match(struct node *left, struct node *right,
-                        struct parameter *params, struct libscols_line *ln)
-{
-       const char *str;
-       OP2_GET_STR(left, str);
-
-       return (regexec(&VAL(right,re), str, 0, NULL, 0) == 0);
-}
-
-static bool op2_re_unmatch(struct node *left, struct node *right,
-                        struct parameter *params, struct libscols_line *ln)
-{
-       return !op2_re_match(left, right, params, ln);
-}
-
-static bool op2_check_type_boolean_or_op(struct parser* parser, const struct op2_class *op2_class,
-                                        struct node *left, struct node *right)
-{
-       enum node_type lt = left->type, rt = right->type;
-
-       if (!(lt == NODE_OP1 || lt == NODE_OP2 || lt == NODE_BOOL)) {
-               snprintf(parser->errmsg, sizeof(parser->errmsg),
-                        _("error: unexpected left operand type %s for: %s"),
-                        NODE_CLASS(left)->name,
-                        op2_class->name);
-               return false;
-       }
-
-       if (! (rt == NODE_OP1 || rt == NODE_OP2 || rt == NODE_BOOL)) {
-               snprintf(parser->errmsg, sizeof(parser->errmsg),
-                        _("error: unexpected right operand type %s for: %s"),
-                        NODE_CLASS(right)->name,
-                        op2_class->name);
-               return false;
-       }
-
-       return true;
-}
-
-static bool op2_check_type_eq_or_bool_or_op(struct parser* parser, const struct op2_class *op2_class,
-                                           struct node *left, struct node *right)
-{
-       enum node_type lt = left->type, rt = right->type;
-
-       if (lt == rt)
-               return true;
-       else if ((lt == NODE_NUM && rt == NODE_FNUM)
-                || (lt == NODE_FNUM && rt == NODE_NUM))
-               return true;
-
-       return op2_check_type_boolean_or_op(parser, op2_class, left, right);
-}
-
-static bool op2_check_type_num(struct parser* parser, const struct op2_class *op2_class,
-                              struct node *left, struct node *right)
-{
-       if (left->type != NODE_NUM && left->type != NODE_FNUM) {
-               snprintf(parser->errmsg, sizeof(parser->errmsg),
-                        _("error: unexpected left operand type %s for: %s"),
-                        NODE_CLASS(left)->name,
-                        op2_class->name);
-               return false;
-       }
-
-       if (right->type != NODE_NUM && right->type != NODE_FNUM) {
-               snprintf(parser->errmsg, sizeof(parser->errmsg),
-                        _("error: unexpected right operand type %s for: %s"),
-                        NODE_CLASS(right)->name,
-                        op2_class->name);
-               return false;
-       }
-
-       return true;
-}
-
-static bool op2_check_type_re(struct parser* parser, const struct op2_class *op2_class,
-                             struct node *left, struct node *right)
-{
-       if (left->type != NODE_STR) {
-               snprintf(parser->errmsg, sizeof(parser->errmsg),
-                        _("error: unexpected left operand type %s for: %s"),
-                        NODE_CLASS(left)->name,
-                        op2_class->name);
-               return false;
-       }
-
-       if (right->type != NODE_STR) {
-               snprintf(parser->errmsg, sizeof(parser->errmsg),
-                        _("error: unexpected right operand type %s for: %s"),
-                        NODE_CLASS(right)->name,
-                        op2_class->name);
-               return false;
-       }
-       if (PINDEX(right) >= 0) {
-               snprintf(parser->errmsg, sizeof(parser->errmsg),
-                        _("error: string literal is expected as right operand for: %s"),
-                        op2_class->name);
-               return false;
-       }
-
-       char *regex = VAL(right, str);
-       VAL(right, str) = NULL;
-
-       int err = regcomp(&VAL(right, re), regex, REG_NOSUB | REG_EXTENDED);
-       if (err != 0) {
-               size_t size = regerror(err, &VAL(right, re), NULL, 0);
-               char *buf = xmalloc(size + 1);
-
-               regerror(err, &VAL(right, re), buf, size);
-
-               snprintf(parser->errmsg, sizeof(parser->errmsg),
-                        _("error: could not compile regular expression %s: %s"),
-                        regex, buf);
-               free(buf);
-               return false;
-       }
-       right->type = NODE_RE;
-       free(regex);
-       return true;
-}
-
-struct lsfd_filter *lsfd_filter_new(const char *const expr, struct libscols_table *tb,
-                                     int ncols,
-                                     int (*column_name_to_id)(const char *, void *),
-                                     struct libscols_column *(*add_column_by_id)(struct libscols_table *, int, void*),
-                                     void *data)
-{
-       struct parser parser;
-       int i;
-       struct node *node;
-       struct lsfd_filter *filter;
-
-       parser_init(&parser, expr, tb, ncols,
-                   column_name_to_id,
-                   add_column_by_id,
-                   data);
-
-       node = dparser_compile(&parser);
-       filter = xcalloc(1, sizeof(struct lsfd_filter));
-
-       if (GOT_ERROR(&parser)) {
-               xstrncpy(filter->errmsg, parser.errmsg, sizeof(filter->errmsg));
-               return filter;
-       }
-       assert(node);
-       if (parser.paren_level > 0) {
-               node_free(node);
-               xstrncpy(filter->errmsg, _("error: unbalanced parenthesis: ("), sizeof(filter->errmsg));
-               return filter;
-       }
-       if (*parser.cursor  != '\0') {
-               node_free(node);
-               snprintf(filter->errmsg, sizeof(filter->errmsg),
-                        _("error: garbage at the end of expression: %s"), parser.cursor);
-               return filter;
-       }
-       if (node->type == NODE_STR || node->type == NODE_NUM) {
-               /* FNUM like 3.14 is not considered as a bool expression. */
-               node_free(node);
-               snprintf(filter->errmsg, sizeof(filter->errmsg),
-                        _("error: bool expression is expected: %s"), expr);
-               return filter;
-       }
-
-       filter->table = tb;
-       scols_ref_table(filter->table);
-       filter->node = node;
-       filter->parameters = parser.parameters;
-       filter->nparams = ncols;
-       for (i = 0; i < filter->nparams; i++) {
-               if (filter->parameters[i].cl)
-                       scols_ref_column(filter->parameters[i].cl);
-       }
-       return filter;
-}
-
-const char *lsfd_filter_get_errmsg(struct lsfd_filter *filter)
-{
-       if (GOT_ERROR(filter))
-               return filter->errmsg;
-
-       return NULL;
-}
-
-void lsfd_filter_dump(struct lsfd_filter *filter, FILE *stream)
-{
-       if (!filter) {
-               fputs("EMPTY\n", stream);
-               return;
-       }
-
-       if (GOT_ERROR(filter)) {
-               fprintf(stream, "ERROR: %s\n", filter->errmsg);
-               return;
-       }
-
-       node_dump(filter->node, filter->parameters, 0, stream);
-}
-
-void lsfd_filter_free(struct lsfd_filter *filter)
-{
-       int i;
-
-       if (!filter)
-               return;
-
-       if (!GOT_ERROR(filter)) {
-               for (i = 0; i < filter->nparams; i++) {
-                       if (filter->parameters[i].cl)
-                               scols_unref_column(filter->parameters[i].cl);
-               }
-               scols_unref_table(filter->table);
-               node_free(filter->node);
-       }
-       free(filter->parameters);
-       free(filter);
-}
-
-bool lsfd_filter_apply(struct lsfd_filter *filter, struct libscols_line * ln)
-{
-       int i;
-
-       if (!filter)
-               return true;
-
-       if (GOT_ERROR(filter))
-               return false;
-
-       for (i = 0; i < filter->nparams; i++) {
-               filter->parameters[i].has_value = false;
-               filter->parameters[i].floating_point_num = false;
-       }
-
-       return node_apply(filter->node, filter->parameters, ln);
-}
diff --git a/misc-utils/lsfd-filter.h b/misc-utils/lsfd-filter.h
deleted file mode 100644 (file)
index db5cbd6..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * lsfd-filter.c - filtering engine for lsfd
- *
- * Copyright (C) 2021 Red Hat, Inc.
- * Copyright (C) 2021 Masatake YAMATO <yamato@redhat.com>
- *
- * This file may be redistributed under the terms of the
- * GNU Lesser General Public License.
- */
-#ifndef UTIL_LINUX_LSFD_FILTER_H
-#define UTIL_LINUX_LSFD_FILTER_H
-
-#include "libsmartcols.h"
-#include <stdio.h>
-#include <stdbool.h>
-
-#define LSFD_FILTER_UNKNOWN_COL_ID -1
-
-struct lsfd_filter;
-
-/*
- * @column_name_to_id: a function converting a column name to its id.
- *
- * @column_name_to_id should return LSFD_FILTER_UNKNOWN_COL_ID if
- * an unknown column name is given.
- */
-struct lsfd_filter *lsfd_filter_new(const char *const expr, struct libscols_table *tb,
-                                     int ncols,
-                                     int (*column_name_to_id)(const char *, void *),
-                                     struct libscols_column *(*add_column_by_id)(struct libscols_table *, int, void*),
-                                     void *data);
-
-/* Call lsfd_filter_get_errmsg() after lsfd_filter_new() to detect
- * whether lsfd_filter_new() is failed or not. Returning NULL means,
- * lsfd_filter_new() is successful. */
-const char *lsfd_filter_get_errmsg(struct lsfd_filter *filter);
-void lsfd_filter_free(struct lsfd_filter *filter);
-bool lsfd_filter_apply(struct lsfd_filter *filter, struct libscols_line *ln);
-
-/* Dumping AST. */
-void lsfd_filter_dump(struct lsfd_filter *filter, FILE *stream);
-
-#endif /* UTIL_LINUX_LSFD_FILTER_H */
index 76e0e66e1796b367c81300084c71817dff780704..243e30b8db7c5e6b806c564dc602850b1be885e4 100644 (file)
@@ -58,8 +58,6 @@ static int kcmp(pid_t pid1, pid_t pid2, int type,
 #include "pathnames.h"
 
 #include "lsfd.h"
-#include "lsfd-filter.h"
-#include "lsfd-counter.h"
 
 /*
  * /proc/$pid/mountinfo entries
@@ -488,6 +486,12 @@ static const struct counter_spec default_counter_specs[] = {
        }
 };
 
+/* "userdata" used by callback for libsmartcols filter */
+struct filler_data {
+       struct proc *proc;
+       struct file *file;
+};
+
 struct lsfd_control {
        struct libscols_table *tb;              /* output */
        struct list_head procs;                 /* list of all processes */
@@ -502,8 +506,8 @@ struct lsfd_control {
                        sockets_only : 1,       /* display only SOCKETS */
                        show_xmode : 1;         /* XMODE column is enabled. */
 
-       struct lsfd_filter *filter;
-       struct lsfd_counter **counters;         /* NULL terminated array. */
+       struct libscols_filter *filter;         /* filter */
+       struct libscols_filter **ct_filters;    /* counters (NULL terminated array) */
 };
 
 static void *proc_tree;                        /* for tsearch/tfind */
@@ -532,13 +536,7 @@ static int column_name_to_id(const char *name, size_t namesz)
                        return i;
        }
        warnx(_("unknown column: %s"), name);
-
-       return LSFD_FILTER_UNKNOWN_COL_ID;
-}
-
-static int column_name_to_id_cb(const char *name, void *data __attribute__((__unused__)))
-{
-       return column_name_to_id(name, strlen(name));
+       return -1;
 }
 
 static int get_column_id(int num)
@@ -575,7 +573,7 @@ static struct libscols_column *add_column(struct libscols_table *tb, const struc
        return cl;
 }
 
-static struct libscols_column *add_column_by_id_cb(struct libscols_table *tb, int colid, void *data)
+static struct libscols_column *add_column_by_id(struct lsfd_control *ctl, int colid)
 {
        struct libscols_column *cl;
 
@@ -584,15 +582,13 @@ static struct libscols_column *add_column_by_id_cb(struct libscols_table *tb, in
 
        assert(colid < LSFD_N_COLS);
 
-       cl = add_column(tb, infos + colid);
+       cl = add_column(ctl->tb, infos + colid);
        if (!cl)
                err(EXIT_FAILURE, _("failed to allocate output column"));
        columns[ncolumns++] = colid;
 
-       if (colid == COL_TID) {
-               struct lsfd_control *ctl = data;
+       if (colid == COL_TID)
                ctl->threads = 1;
-       }
 
        return cl;
 }
@@ -1165,6 +1161,7 @@ void add_endpoint(struct ipc_endpoint *endpoint, struct ipc *ipc)
        list_add(&endpoint->endpoints, &ipc->endpoints);
 }
 
+
 static void fill_column(struct proc *proc,
                        struct file *file,
                        struct libscols_line *ln,
@@ -1182,6 +1179,18 @@ static void fill_column(struct proc *proc,
        }
 }
 
+static int filter_filler_cb(
+               struct libscols_filter *fltr __attribute__((__unused__)),
+               struct libscols_line *ln,
+               size_t colnum,
+               void *userdata)
+{
+       struct filler_data *fid = (struct filler_data *) userdata;
+
+       fill_column(fid->proc, fid->file, ln, get_column_id(colnum), colnum);
+       return 0;
+}
+
 static void convert_file(struct proc *proc,
                     struct file *file,
                     struct libscols_line *ln)
@@ -1189,8 +1198,11 @@ static void convert_file(struct proc *proc,
 {
        size_t i;
 
-       for (i = 0; i < ncolumns; i++)
+       for (i = 0; i < ncolumns; i++) {
+               if (scols_line_is_filled(ln, i))
+                       continue;
                fill_column(proc, file, ln, get_column_id(i), i);
+       }
 }
 
 static void convert(struct list_head *procs, struct lsfd_control *ctl)
@@ -1204,23 +1216,34 @@ static void convert(struct list_head *procs, struct lsfd_control *ctl)
                list_for_each (f, &proc->files) {
                        struct file *file = list_entry(f, struct file, files);
                        struct libscols_line *ln = scols_table_new_line(ctl->tb, NULL);
-                       struct lsfd_counter **counter = NULL;
+                       struct libscols_filter **ct_fltr = NULL;
 
                        if (!ln)
                                err(EXIT_FAILURE, _("failed to allocate output line"));
+                       if (ctl->filter) {
+                               int status = 0;
+                               struct filler_data fid = {
+                                       .proc = proc,
+                                       .file = file
+                               };
+
+                               scols_filter_set_filler_cb(ctl->filter,
+                                               filter_filler_cb, (void *) &fid);
+                               if (scols_line_apply_filter(ln, ctl->filter, &status))
+                                       err(EXIT_FAILURE, _("failed to apply filter"));
+                               if (status == 0) {
+                                       scols_table_remove_line(ctl->tb, ln);
+                                       continue;
+                               }
+                       }
 
                        convert_file(proc, file, ln);
 
-                       if (!lsfd_filter_apply(ctl->filter, ln)) {
-                               scols_table_remove_line(ctl->tb, ln);
+                       if (!ctl->ct_filters)
                                continue;
-                       }
 
-                       if (!ctl->counters)
-                               continue;
-
-                       for (counter = ctl->counters; *counter; counter++)
-                               lsfd_counter_accumulate(*counter, ln);
+                       for (ct_fltr = ctl->ct_filters; *ct_fltr; ct_fltr++)
+                               scols_line_apply_filter(ln, *ct_fltr, NULL);
                }
        }
 }
@@ -1236,12 +1259,13 @@ static void delete(struct list_head *procs, struct lsfd_control *ctl)
        list_free(procs, struct proc, procs, free_proc);
 
        scols_unref_table(ctl->tb);
-       lsfd_filter_free(ctl->filter);
-       if (ctl->counters) {
-               struct lsfd_counter **counter;
-               for (counter = ctl->counters; *counter; counter++)
-                       lsfd_counter_free(*counter);
-               free(ctl->counters);
+       scols_unref_filter(ctl->filter);
+
+       if (ctl->ct_filters) {
+               struct libscols_filter **ct_fltr;
+               for (ct_fltr = ctl->ct_filters; *ct_fltr; ct_fltr++)
+                       scols_unref_filter(*ct_fltr);
+               free(ctl->ct_filters);
        }
 }
 
@@ -1846,24 +1870,49 @@ static void append_filter_expr(char **a, const char *b, bool and)
        xstrappend(a, ")");
 }
 
-static struct lsfd_filter *new_filter(const char *expr, bool debug, const char *err_prefix, struct lsfd_control *ctl)
+static struct libscols_filter *new_filter(const char *expr, bool debug, struct lsfd_control *ctl)
 {
-       struct lsfd_filter *filter;
-       const char *errmsg;
+       struct libscols_filter *f;
+       struct libscols_iter *itr;
+       int nerrs = 0;
+       const char *name = NULL;
 
-       filter = lsfd_filter_new(expr, ctl->tb,
-                                LSFD_N_COLS,
-                                column_name_to_id_cb,
-                                add_column_by_id_cb, ctl);
-       errmsg = lsfd_filter_get_errmsg(filter);
-       if (errmsg)
-               errx(EXIT_FAILURE, "%s%s", err_prefix, errmsg);
-       if (debug) {
-               lsfd_filter_dump(filter, stdout);
-               exit(EXIT_SUCCESS);
+       f = scols_new_filter(NULL);
+       if (!f)
+               err(EXIT_FAILURE, _("failed to allocate filter"));
+       if (expr && scols_filter_parse_string(f, expr) != 0)
+               errx(EXIT_FAILURE, _("failed to parse \"%s\": %s"), expr,
+                               scols_filter_get_errmsg(f));
+
+       itr = scols_new_iter(SCOLS_ITER_FORWARD);
+       if (!itr)
+               err(EXIT_FAILURE, _("failed to allocate iterator"));
+
+       while (scols_filter_next_holder(f, itr, &name, 0) == 0) {
+               struct libscols_column *col = scols_table_get_column_by_name(ctl->tb, name);
+
+               if (!col) {
+                       int id = column_name_to_id(name, strlen(name));
+                       if (id >= 0)
+                               col = add_column_by_id(ctl, id);
+                       if (!col) {
+                               nerrs++;        /* report all unknown columns */
+                               continue;
+                       }
+               }
+               scols_filter_assign_column(f, itr, name, col);
        }
 
-       return filter;
+       scols_free_iter(itr);
+
+       if (debug)
+               scols_dump_filter(f, stdout);
+       if (nerrs)
+               exit(EXIT_FAILURE);
+       if (debug)
+               exit(EXIT_SUCCESS);
+
+       return f;
 }
 
 static struct counter_spec *new_counter_spec(const char *spec_str)
@@ -1911,47 +1960,54 @@ static void free_counter_spec(struct counter_spec *counter_spec)
        free(counter_spec);
 }
 
-static struct lsfd_counter *new_counter(const struct counter_spec *spec, struct lsfd_control *ctl)
+static struct libscols_filter *new_counter(const struct counter_spec *spec, struct lsfd_control *ctl)
 {
-       struct lsfd_filter *filter;
+       struct libscols_filter *f;
+       struct libscols_counter *ct;
+
+       f = new_filter(spec->expr, false, ctl);
 
-       filter = new_filter(spec->expr, false,
-                           _("failed in making filter for a counter: "),
-                           ctl);
-       return lsfd_counter_new(spec->name, filter);
+       ct = scols_filter_new_counter(f);
+       if (!ct)
+               err(EXIT_FAILURE, _("failed to allocate counter"));
+
+       scols_counter_set_name(ct, spec->name);
+       scols_counter_set_func(ct, SCOLS_COUNTER_COUNT);
+
+       return f;
 }
 
-static struct lsfd_counter **new_counters(struct list_head *specs, struct lsfd_control *ctl)
+static struct libscols_filter **new_counters(struct list_head *specs, struct lsfd_control *ctl)
 {
-       struct lsfd_counter **counters;
+       struct libscols_filter **ct_filters;
        size_t len = list_count_entries(specs);
        size_t i = 0;
        struct list_head *s;
 
-       counters = xcalloc(len + 1, sizeof(struct lsfd_counter *));
+       ct_filters = xcalloc(len + 1, sizeof(struct libscols_filter *));
        list_for_each(s, specs) {
                struct counter_spec *spec = list_entry(s, struct counter_spec, specs);
-               counters[i++] = new_counter(spec, ctl);
+               ct_filters[i++] = new_counter(spec, ctl);
        }
-       assert(counters[len] == NULL);
+       assert(ct_filters[len] == NULL);
 
-       return counters;
+       return ct_filters;
 }
 
-static struct lsfd_counter **new_default_counters(struct lsfd_control *ctl)
+static struct libscols_filter **new_default_counters(struct lsfd_control *ctl)
 {
-       struct lsfd_counter **counters;
+       struct libscols_filter **ct_filters;
        size_t len = ARRAY_SIZE(default_counter_specs);
        size_t i;
 
-       counters = xcalloc(len + 1, sizeof(struct lsfd_counter *));
+       ct_filters = xcalloc(len + 1, sizeof(struct libscols_filter *));
        for (i = 0; i < len; i++) {
                const struct counter_spec *spec = default_counter_specs + i;
-               counters[i] = new_counter(spec, ctl);
+               ct_filters[i] = new_counter(spec, ctl);
        }
-       assert(counters[len] == NULL);
+       assert(ct_filters[len] == NULL);
 
-       return counters;
+       return ct_filters;
 }
 
 static void dump_default_counter_specs(void)
@@ -2009,28 +2065,35 @@ static struct libscols_table *new_summary_table(struct lsfd_control *ctl)
        return tb;
 }
 
-static void fill_summary_line(struct libscols_line *ln, struct lsfd_counter *counter)
+static void emit_summary(struct lsfd_control *ctl)
 {
-       char *str = NULL;
+       struct libscols_iter *itr;
+       struct libscols_filter **ct_fltr;
+       struct libscols_table *tb = new_summary_table(ctl);
 
-       xasprintf(&str, "%llu", (unsigned long long)lsfd_counter_value(counter));
-       if (!str)
-               err(EXIT_FAILURE, _("failed to add summary data"));
-       if (scols_line_refer_data(ln, 0, str))
-               err(EXIT_FAILURE, _("failed to add summary data"));
+       itr = scols_new_iter(SCOLS_ITER_FORWARD);
 
-       if (scols_line_set_data(ln, 1, lsfd_counter_name(counter)))
-               err(EXIT_FAILURE, _("failed to add summary data"));
-}
+       for (ct_fltr = ctl->ct_filters; *ct_fltr; ct_fltr++) {
+               struct libscols_counter *ct = NULL;
 
-static void emit_summary(struct lsfd_control *ctl, struct lsfd_counter **counter)
-{
-       struct libscols_table *tb = new_summary_table(ctl);
+               scols_reset_iter(itr, SCOLS_ITER_FORWARD);
+               while (scols_filter_next_counter(*ct_fltr, itr, &ct) == 0) {
+                       char *str = NULL;
+                       struct libscols_line *ln;
+
+                       ln = scols_table_new_line(tb, NULL);
+                       if (!ln)
+                               err(EXIT_FAILURE, _("failed to allocate summary line"));
 
-       for (; *counter; counter++) {
-               struct libscols_line *ln = scols_table_new_line(tb, NULL);
-               fill_summary_line(ln, *counter);
+                       xasprintf(&str, "%llu", scols_counter_get_result(ct));
+                       if (scols_line_refer_data(ln, 0, str))
+                               err(EXIT_FAILURE, _("failed to add summary data"));
+                       if (scols_line_set_data(ln, 1, scols_counter_get_name(ct)))
+                               err(EXIT_FAILURE, _("failed to add summary data"));
+               }
        }
+
+       scols_free_iter(itr);
        scols_print_table(tb);
 
        scols_unref_table(tb);
@@ -2265,9 +2328,9 @@ int main(int argc, char *argv[])
                }
        }
 
-       /* make fitler */
+       /* make filter */
        if (filter_expr) {
-               ctl.filter = new_filter(filter_expr, debug_filter, "", &ctl);
+               ctl.filter = new_filter(filter_expr, debug_filter, &ctl);
                free(filter_expr);
        }
 
@@ -2282,9 +2345,9 @@ int main(int argc, char *argv[])
        /* make counters */
        if (ctl.show_summary) {
                if (list_empty(&counter_specs))
-                       ctl.counters = new_default_counters(&ctl);
+                       ctl.ct_filters = new_default_counters(&ctl);
                else {
-                       ctl.counters = new_counters(&counter_specs, &ctl);
+                       ctl.ct_filters = new_counters(&counter_specs, &ctl);
                        list_free(&counter_specs, struct counter_spec, specs,
                                  free_counter_spec);
                }
@@ -2320,8 +2383,8 @@ int main(int argc, char *argv[])
        if (ctl.show_main)
                emit(&ctl);
 
-       if (ctl.show_summary && ctl.counters)
-               emit_summary(&ctl, ctl.counters);
+       if (ctl.show_summary && ctl.ct_filters)
+               emit_summary(&ctl);
 
        /* cleanup */
        delete(&ctl.procs, &ctl);