libsmartcols/src/walk.c \
libsmartcols/src/init.c \
\
- libsmartcols/src/filter-nodes.c \
libsmartcols/src/filter-parser.y \
libsmartcols/src/filter-scanner.l \
+ libsmartcols/src/filter-parser.h \
+ libsmartcols/src/filter-scanner.h \
libsmartcols/src/filter.c
-BUILT_SOURCES = libsmartcols/src/filter-scanner.c \
- libsmartcols/src/filter-scanner.h \
- libsmartcols/src/filter-parser.h \
- libsmartcols/src/filter-parser.c
-AM_YFLAGS = -d
+BUILT_SOURCES += libsmartcols/src/filter-parser.c \
+ libsmartcols/src/filter-scanner.c
+
+
+# Scanner and parser header files are maintained in git and generated
+# manually by only if necessary.
+#
+libsmartcols/src/filter-scanner.h: libsmartcols/src/filter-scanner.l
+ $(AM_V_LEX) $(LEX) --header-file=$@ $<
+
+libsmartcols/src/filter-parser.h: libsmartcols/src/filter-parser.y
+ $(AM_V_YACC) $(YACC) --header=$@ $<
+
libsmartcols_la_LIBADD = $(LDADD) libcommon.la
+++ /dev/null
-
-#include "smartcolsP.h"
-
-/* This is generic allocater for a new node, always use the node type specific
- * functions (e.g. filter_new_param() */
-static struct filter_node *new_node(enum filter_ntype type, size_t sz)
-{
- void *x = calloc(1, sz);
- struct filter_node *n = (struct filter_node *) x;
-
- if (!x)
- return NULL;
-
- n->type = type;
- n->refcount = 1;
- return n;
-}
-
-struct filter_node *filter_new_param(struct libscols_filter *fltr __attribute__((__unused__)),
- enum filter_ptype type,
- void *data)
-{
- struct filter_param *n = (struct filter_param *) new_node(
- F_NODE_PARAM,
- sizeof(struct filter_param));
- n->type = type;
-
- switch (type) {
- case F_PARAM_NAME:
- case F_PARAM_STRING:
- n->val.str = strdup((char *) data);
- break;
- case F_PARAM_NUMBER:
- n->val.num = *((unsigned long long *) data);
- break;
- case F_PARAM_FLOAT:
- n->val.fnum = *((long double *) data);
- break;
- case F_PARAM_BOOLEAN:
- n->val.boolean = *((bool *) data) == 0 ? 0 : 1;
- break;
- }
- return (struct filter_node *) n;
-}
-
-static void free_param(struct filter_param *n)
-{
- if (n->type == F_PARAM_NAME || n->type == F_PARAM_STRING)
- free(n->val.str);
- free(n);
-}
-
-#define plus_indent(i) ((i) + 5)
-#define indent(f, i) fprintf(f, "%*s", (i), "");
-#define indent_inside(f, i) indent(f, plus_indent(i))
-
-static void dump_param(FILE *out, int i __attribute__((__unused__)), struct filter_param *n)
-{
- fprintf(out, "param { ");
-
- switch (n->type) {
- case F_PARAM_NAME:
- fprintf(out, "name: '%s'", n->val.str);
- break;
- case F_PARAM_STRING:
- fprintf(out, "string: '%s'", n->val.str);
- break;
- case F_PARAM_NUMBER:
- fprintf(out, "number: %llu", n->val.num);
- break;
- case F_PARAM_FLOAT:
- fprintf(out, "float: %Lg", n->val.fnum);
- break;
- case F_PARAM_BOOLEAN:
- fprintf(out, "bool: %s", n->val.boolean ? "true" : "false");
- break;
- }
- fprintf(out, " }\n");
-}
-
-struct filter_node *filter_new_expr(struct libscols_filter *fltr __attribute__((__unused__)),
- enum filter_etype type,
- struct filter_node *left,
- struct filter_node *right)
-{
- struct filter_expr *n = (struct filter_expr *) new_node(
- F_NODE_EXPR, sizeof(struct filter_expr));
-
- n->type = type;
- switch (type) {
- case F_EXPR_AND:
- case F_EXPR_OR:
- case F_EXPR_EQ:
- case F_EXPR_NE:
- case F_EXPR_LE:
- case F_EXPR_LT:
- case F_EXPR_GE:
- case F_EXPR_GT:
- case F_EXPR_REG:
- case F_EXPR_NREG:
- n->left = left;
- n->right = right;
- break;
- case F_EXPR_NEG:
- n->right = right;
- break;
-
- }
- return (struct filter_node *) n;
-}
-
-static void free_expr(struct filter_expr *n)
-{
- filter_unref_node(n->left);
- filter_unref_node(n->right);
- free(n);
-}
-
-static void dump_expr(FILE *out, int i, struct filter_expr *n)
-{
- fprintf(out, "expr {\n");
-
- indent_inside(out, i);
- fprintf(out, "type: ");
-
- switch (n->type) {
- case F_EXPR_AND:
- fprintf(out, "AND");
- break;
- case F_EXPR_OR:
- fprintf(out, "OR");
- break;
- case F_EXPR_EQ:
- fprintf(out, "EQ");
- break;
- case F_EXPR_NE:
- fprintf(out, "NE");
- break;
- case F_EXPR_LE:
- fprintf(out, "LE");
- break;
- case F_EXPR_LT:
- fprintf(out, "LT");
- break;
- case F_EXPR_GE:
- fprintf(out, "GE");
- break;
- case F_EXPR_GT:
- fprintf(out, "GT");
- break;
- case F_EXPR_REG:
- fprintf(out, "REG");
- break;
- case F_EXPR_NREG:
- fprintf(out, "NREG");
- break;
- case F_EXPR_NEG:
- fprintf(out, "NOT");
- break;
- }
-
- fprintf(out, "\n");
-
- if (n->left) {
- indent_inside(out, i);
- fprintf(out, "left: ");
- filter_dump_node(out, plus_indent(i), n->left);
- }
-
- if (n->right) {
- indent_inside(out, i);
- fprintf(out, "right: ");
- filter_dump_node(out, plus_indent(i), n->right);
- }
-
- indent(out, i);
- fprintf(out, "}\n");
-}
-
-
-void filter_unref_node(struct filter_node *n)
-{
- if (!n || --n->refcount > 0)
- return;
-
- switch (n->type) {
- case F_NODE_EXPR:
- free_expr((struct filter_expr *) n);
- break;
- case F_NODE_PARAM:
- free_param((struct filter_param *) n);
- break;
- }
-}
-
-void filter_dump_node(FILE *out, int i, struct filter_node *n)
-{
- if (!n)
- return;
-
- switch (n->type) {
- case F_NODE_EXPR:
- dump_expr(out, i, (struct filter_expr *) n);
- break;
- case F_NODE_PARAM:
- dump_param(out, i, (struct filter_param *) n);
- break;
- }
- if (i == 0)
- fprintf(out, "\n");
-}
%lex-param {void *scanner}
%parse-param {void *scanner}{struct libscols_filter *fltr}
-%define parse.trace
%define parse.error verbose
-%header "filter-parser.h"
+/*%header "filter-parser.h"*/
%code requires
{
struct filter_node *param;
struct filter_node *expr;
}
-%token <param_number> param_number
-%token <param_string> param_string
-%token <param_name> param_name
-%token <param_float> param_float
+%token <param_number> T_NUMBER
+%token <param_string> T_STRING
+%token <param_name> T_NAME
+%token <param_float> T_FLOAT
%type <param> param expr
%token T_OR T_AND T_EQ T_NE T_LT T_LE T_GT T_GE T_REG T_NREG T_TRUE T_FALSE T_NEG
;
param:
- param_number { $$ = filter_new_param(fltr, F_PARAM_NUMBER, (void *) (&$1)); }
- | param_float { $$ = filter_new_param(fltr, F_PARAM_FLOAT, (void *) (&$1)); }
- | param_name { $$ = filter_new_param(fltr, F_PARAM_NAME, (void *) $1); }
- | param_string { $$ = filter_new_param(fltr, F_PARAM_STRING, (void *) $1); }
+ T_NUMBER { $$ = filter_new_param(fltr, F_PARAM_NUMBER, (void *) (&$1)); }
+ | T_FLOAT { $$ = filter_new_param(fltr, F_PARAM_FLOAT, (void *) (&$1)); }
+ | T_NAME { $$ = filter_new_param(fltr, F_PARAM_NAME, (void *) $1); }
+ | T_STRING { $$ = filter_new_param(fltr, F_PARAM_STRING, (void *) $1); }
| T_TRUE {
bool x = true;
$$ = filter_new_param(fltr, F_PARAM_BOOLEAN, (void *) &x);
%%
-void yyerror (yyscan_t *locp, struct libscols_filter *fltr, char const *msg)
+void yyerror (yyscan_t *locp __attribute__((__unused__)),
+ struct libscols_filter *fltr,
+ char const *msg)
{
- fprintf(stderr, "--> %s\n", msg);
+ if (msg) {
+ fltr->errmsg = strdup(msg);
+ if (!fltr->errmsg)
+ return;
+ }
+ errno = EINVAL;
}
")" return ')';
"'" return '\'';
+and|AND|"&&" return T_AND;
+or|OR|"||" return T_OR;
+"!"|not|NOT return T_NEG;
+
+eq|"==" return T_EQ;
+ne|"!=" return T_NE;
+
+le|"<=" return T_LE;
+lt|"<" return T_LT;
+
+ge|">=" return T_GE;
+gt|">" return T_GT;
+
+"=~" return T_REG;
+"!~" return T_NREG;
+
false|FALSE return T_FALSE;
true|TRUE return T_TRUE;
{int}+\.{int}+ {
yylval->param_float = strtold(yytext, NULL);
- return param_float;
+ return T_FLOAT;
}
{int}+ {
yylval->param_number = (int64_t) strtoumax(yytext, NULL, 10);
- return param_number;
+ return T_NUMBER;
}
{id} {
yylval->param_name = yytext;
- return param_name;
+ return T_NAME;
}
{string} {
yylval->param_string = yytext;
- return param_string;
+ return T_STRING;
}
-and|AND|"&&" return T_AND;
-or|OR|"||" return T_OR;
-"!"|not|NOT return T_NEG;
-
-eq|"==" return T_EQ;
-ne|"!=" return T_NE;
-le|"<=" return T_LE;
-lt|"<" return T_LT;
-
-ge|">=" return T_GE;
-gt|">" return T_GT;
-
-"=~" return T_REG;
-"!~" return T_NREG;
#include "filter-parser.h"
#include "filter-scanner.h"
-struct libscols_filter *scols_new_filter()
+static void filter_unref_node(struct filter_node *n);
+static void filter_dump_node(struct ul_jsonwrt *json, struct filter_node *n);
+
+struct libscols_filter *scols_new_filter(const char *str)
{
struct libscols_filter *fltr = calloc(1, sizeof(*fltr));
+ if (!fltr)
+ return NULL;
+ fltr->refcount = 1;
+
+ if (str && scols_filter_parse_string(fltr, str) != 0) {
+ scols_unref_filter(fltr);
+ return NULL;
+ }
+
return fltr;
}
+void scols_ref_filter(struct libscols_filter *fltr)
+{
+ if (fltr)
+ fltr->refcount++;
+}
+
static void reset_filter(struct libscols_filter *fltr)
{
if (!fltr)
if (fltr->src)
fclose(fltr->src);
fltr->src = NULL;
+
+ free(fltr->errmsg);
+ fltr->errmsg = NULL;
+}
+
+void scols_unref_filter(struct libscols_filter *fltr)
+{
+ if (fltr && --fltr->refcount <= 0) {
+ DBG(FLTR, ul_debugobj(fltr, "dealloc"));
+ reset_filter(fltr);
+ free(fltr);
+ }
+}
+
+/* This is generic allocater for a new node, always use the node type specific
+ * functions (e.g. filter_new_param() */
+static struct filter_node *new_node(enum filter_ntype type, size_t sz)
+{
+ void *x = calloc(1, sz);
+ struct filter_node *n = (struct filter_node *) x;
+
+ if (!x)
+ return NULL;
+
+ n->type = type;
+ n->refcount = 1;
+ return n;
+}
+
+struct filter_node *filter_new_param(
+ struct libscols_filter *fltr __attribute__((__unused__)),
+ enum filter_ptype type,
+ void *data)
+{
+ char *p;
+ struct filter_param *n = (struct filter_param *) new_node(
+ F_NODE_PARAM,
+ sizeof(struct filter_param));
+ n->type = type;
+
+ switch (type) {
+ case F_PARAM_STRING:
+ p = data;
+ if (*p == '"') {
+ /* remove quotation marks */
+ size_t len = strlen(p);
+ if (*(p + (len - 1)) == '"')
+ *(p + (len - 1)) = '\0';
+ data = p + 1;
+ }
+ /* fallthrough */
+ case F_PARAM_NAME:
+ n->val.str = strdup((char *) data);
+ break;
+ case F_PARAM_NUMBER:
+ n->val.num = *((unsigned long long *) data);
+ break;
+ case F_PARAM_FLOAT:
+ n->val.fnum = *((long double *) data);
+ break;
+ case F_PARAM_BOOLEAN:
+ n->val.boolean = *((bool *) data) == 0 ? 0 : 1;
+ break;
+ }
+ return (struct filter_node *) n;
+}
+
+static void free_param(struct filter_param *n)
+{
+ if (n->type == F_PARAM_NAME || n->type == F_PARAM_STRING)
+ free(n->val.str);
+ free(n);
+}
+
+static void dump_param(struct ul_jsonwrt *json, struct filter_param *n)
+{
+ ul_jsonwrt_object_open(json, "param");
+
+ switch (n->type) {
+ case F_PARAM_NAME:
+ ul_jsonwrt_value_s(json, "name", n->val.str);
+ break;
+ case F_PARAM_STRING:
+ ul_jsonwrt_value_s(json, "string", n->val.str);
+ break;
+ case F_PARAM_NUMBER:
+ ul_jsonwrt_value_u64(json, "number", n->val.num);
+ break;
+ case F_PARAM_FLOAT:
+ ul_jsonwrt_value_double(json, "float", n->val.fnum);
+ break;
+ case F_PARAM_BOOLEAN:
+ ul_jsonwrt_value_boolean(json, "bool", n->val.boolean);
+ break;
+ }
+ ul_jsonwrt_object_close(json);
+}
+
+struct filter_node *filter_new_expr(
+ struct libscols_filter *fltr __attribute__((__unused__)),
+ enum filter_etype type,
+ struct filter_node *left,
+ struct filter_node *right)
+{
+ struct filter_expr *n = (struct filter_expr *) new_node(
+ F_NODE_EXPR, sizeof(struct filter_expr));
+
+ n->type = type;
+ switch (type) {
+ case F_EXPR_AND:
+ case F_EXPR_OR:
+ case F_EXPR_EQ:
+ case F_EXPR_NE:
+ case F_EXPR_LE:
+ case F_EXPR_LT:
+ case F_EXPR_GE:
+ case F_EXPR_GT:
+ case F_EXPR_REG:
+ case F_EXPR_NREG:
+ n->left = left;
+ n->right = right;
+ break;
+ case F_EXPR_NEG:
+ n->right = right;
+ break;
+
+ }
+ return (struct filter_node *) n;
+}
+
+static void free_expr(struct filter_expr *n)
+{
+ filter_unref_node(n->left);
+ filter_unref_node(n->right);
+ free(n);
+}
+
+static const char *expr_type_as_string(struct filter_expr *n)
+{
+ switch (n->type) {
+ case F_EXPR_AND:
+ return "AND";
+ case F_EXPR_OR:
+ return "OR";
+ case F_EXPR_EQ:
+ return "EQ";
+ case F_EXPR_NE:
+ return "NE";
+ case F_EXPR_LE:
+ return "LE";
+ case F_EXPR_LT:
+ return "LT";
+ case F_EXPR_GE:
+ return "GE";
+ case F_EXPR_GT:
+ return "GT";
+ case F_EXPR_REG:
+ return "REG";
+ case F_EXPR_NREG:
+ return "NREG";
+ case F_EXPR_NEG:
+ return "NOT";
+ }
+ return "";
}
-int scols_filter_parse_string(struct libscols_filter *fltr, const char *string)
+static void dump_expr(struct ul_jsonwrt *json, struct filter_expr *n)
+{
+ ul_jsonwrt_object_open(json, "expr");
+ ul_jsonwrt_value_s(json, "type", expr_type_as_string(n));
+
+ if (n->left)
+ filter_dump_node(json, n->left);
+ if (n->right)
+ filter_dump_node(json, n->right);
+
+ ul_jsonwrt_object_close(json);
+}
+
+static void filter_unref_node(struct filter_node *n)
+{
+ if (!n || --n->refcount > 0)
+ return;
+
+ switch (n->type) {
+ case F_NODE_EXPR:
+ free_expr((struct filter_expr *) n);
+ break;
+ case F_NODE_PARAM:
+ free_param((struct filter_param *) n);
+ break;
+ }
+}
+
+/*
+static void filter_ref_node(struct filter_node *n)
+{
+ if (n)
+ n->refcount++;
+}
+*/
+
+static void filter_dump_node(struct ul_jsonwrt *json, struct filter_node *n)
+{
+ if (!n)
+ return;
+
+ switch (n->type) {
+ case F_NODE_EXPR:
+ dump_expr(json, (struct filter_expr *) n);
+ break;
+ case F_NODE_PARAM:
+ dump_param(json, (struct filter_param *) n);
+ break;
+ }
+}
+
+extern int yyparse(void *scanner, struct libscols_filter *fltr);
+
+int scols_filter_parse_string(struct libscols_filter *fltr, const char *str)
{
yyscan_t sc;
int rc;
reset_filter(fltr);
- fltr->src = fmemopen((void *) string, strlen(string) + 1, "r");
+ fltr->src = fmemopen((void *) str, strlen(str) + 1, "r");
if (!fltr->src)
return -errno;
rc = yyparse(sc, fltr);
yylex_destroy(sc);
+ fclose(fltr->src);
+ fltr->src = NULL;
+
return rc;
}
-/* TODO:
+int scols_dump_filter(struct libscols_filter *fltr, FILE *out)
+{
+ struct ul_jsonwrt json;
+
+ if (!fltr || !out)
+ return -EINVAL;
+
+ ul_jsonwrt_init(&json, out, 0);
+ ul_jsonwrt_root_open(&json);
-scols_dump_filter()
-scols_line_apply_filter()
-scols_table_apply_filter()
- */
+ filter_dump_node(&json, fltr->root);
+ ul_jsonwrt_root_close(&json);
+ return 0;
+}
+
+const char *scols_filter_get_errmsg(struct libscols_filter *fltr)
+{
+ return fltr ? fltr->errmsg : NULL;
+}
{ "group", SCOLS_DEBUG_GROUP, "lines grouping utils" },
{ "line", SCOLS_DEBUG_LINE, "table line utils" },
{ "tab", SCOLS_DEBUG_TAB, "table utils" },
+ { "filter", SCOLS_DEBUG_FLTR, "lines filter" },
{ NULL, 0, NULL }
};
*/
struct libscols_column;
+/**
+ * libscols_filter:
+ *
+ * A filter - defines the filtering
+ */
+struct libscols_filter;
+
/* iter.c */
enum {
int scols_line_link_group(struct libscols_line *ln, struct libscols_line *member, int id);
int scols_table_group_lines(struct libscols_table *tb, struct libscols_line *ln,
struct libscols_line *member, int id);
+
+/* filter.c */
+extern int scols_filter_parse_string(struct libscols_filter *fltr, const char *str);
+extern struct libscols_filter *scols_new_filter(const char *str);
+extern void scols_ref_filter(struct libscols_filter *fltr);
+extern void scols_unref_filter(struct libscols_filter *fltr);
+extern int scols_dump_filter(struct libscols_filter *fltr, FILE *out);
+extern const char *scols_filter_get_errmsg(struct libscols_filter *fltr);
+
#ifdef __cplusplus
}
#endif
scols_cell_get_datasiz;
scols_wrapzero_nextchunk;
scols_column_get_wrap_data;
+ scols_dump_filter;
+ scols_filter_parse_string;
+ scols_new_filter;
+ scols_unref_filter;
+ scols_filter_get_errmsg;
} SMARTCOLS_2.39;
#define SCOLS_DEBUG_COL (1 << 5)
#define SCOLS_DEBUG_BUFF (1 << 6)
#define SCOLS_DEBUG_GROUP (1 << 7)
+#define SCOLS_DEBUG_FLTR (1 << 8)
#define SCOLS_DEBUG_ALL 0xFFFF
UL_DEBUG_DECLARE_MASK(libsmartcols);
};
struct libscols_filter {
+ int refcount;
+ char *errmsg;
struct filter_node *root;
FILE *src;
};
-void filter_unref_node(struct filter_node *n);
-void filter_dump_node(FILE *out, int i, struct filter_node *n);
-
-/* reuiqred by parser */
+/* required by parser */
struct filter_node *filter_new_param(struct libscols_filter *filter,
enum filter_ptype type,
void *data);