AM_PROG_CC_C_O
AC_PROG_MKDIR_P
AC_PROG_YACC
+AM_PROG_LEX
AC_CANONICAL_HOST
AC_C_CONST
AC_C_VOLATILE
-
# smartcols.h is generated, so it's stored in builddir!
smartcolsincdir = $(includedir)/libsmartcols
nodist_smartcolsinc_HEADERS = libsmartcols/src/libsmartcols.h
libsmartcols/src/calculate.c \
libsmartcols/src/grouping.c \
libsmartcols/src/walk.c \
- libsmartcols/src/init.c
+ libsmartcols/src/init.c \
+ \
+ libsmartcols/src/filter-nodes.c \
+ libsmartcols/src/filter-parser.y \
+ libsmartcols/src/filter-scanner.l \
+ 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
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");
+}
--- /dev/null
+%{
+#include <stdio.h>
+#include "smartcolsP.h"
+
+#include "filter-parser.h"
+#include "filter-scanner.h"
+
+void yyerror(yyscan_t *locp, struct libscols_filter *fltr, char const *msg);
+%}
+
+%define api.pure full
+
+%lex-param {void *scanner}
+%parse-param {void *scanner}{struct libscols_filter *fltr}
+
+%define parse.trace
+%define parse.error verbose
+
+%header "filter-parser.h"
+
+%code requires
+{
+ #include "smartcolsP.h"
+}
+
+/* Elegant way, but not compatible with biron -y (autotools):
+%define api.value.type union
+%token <unsigned long long> param_number
+%token <const char*> param_string
+%token <const char*> param_name
+%token <long double> param_float
+%type <struct filter_node*> param
+%type <struct filter_node*> expr
+*/
+
+%union {
+ unsigned long long param_number;
+ const char* param_string;
+ const char* param_name;
+ long double param_float;
+ 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
+%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
+%left T_OR T_AND
+%left T_EQ T_NE T_LT T_LE T_GT T_GE T_REG T_NREG T_TRUE T_FALSE T_NEG
+
+%%
+
+%start filter;
+
+filter:
+ expr { fltr->root = $1; }
+;
+
+expr:
+ param { $$ = $1; }
+ | '(' expr ')' { $$ = $2; }
+ | expr T_AND expr { $$ = filter_new_expr(fltr, F_EXPR_AND, $1, $3); }
+ | expr T_OR expr { $$ = filter_new_expr(fltr, F_EXPR_OR, $1, $3); }
+ | T_NEG expr { $$ = filter_new_expr(fltr, F_EXPR_NEG, NULL, $2); }
+ | expr T_EQ expr { $$ = filter_new_expr(fltr, F_EXPR_EQ, $1, $3); }
+ | expr T_NE expr { $$ = filter_new_expr(fltr, F_EXPR_NE, $1, $3); }
+ | expr T_LE expr { $$ = filter_new_expr(fltr, F_EXPR_LE, $1, $3); }
+ | expr T_LT expr { $$ = filter_new_expr(fltr, F_EXPR_LT, $1, $3); }
+ | expr T_GE expr { $$ = filter_new_expr(fltr, F_EXPR_GE, $1, $3); }
+ | expr T_GT expr { $$ = filter_new_expr(fltr, F_EXPR_GT, $1, $3); }
+ | expr T_REG expr { $$ = filter_new_expr(fltr, F_EXPR_REG, $1, $3); }
+ | expr T_NREG expr { $$ = filter_new_expr(fltr, F_EXPR_NREG, $1, $3); }
+;
+
+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_TRUE {
+ bool x = true;
+ $$ = filter_new_param(fltr, F_PARAM_BOOLEAN, (void *) &x);
+ }
+ | T_FALSE {
+ bool x = false;
+ $$ = filter_new_param(fltr, F_PARAM_BOOLEAN, (void *) &x);
+ }
+
+;
+
+
+%%
+
+void yyerror (yyscan_t *locp, struct libscols_filter *fltr, char const *msg)
+{
+ fprintf(stderr, "--> %s\n", msg);
+}
--- /dev/null
+%{
+#include "filter-parser.h" /* define tokens (T_*) */
+%}
+
+%option reentrant bison-bridge noyywrap noinput nounput
+
+id [a-zA-Z][a-zA-Z_0-9]*
+int [0-9]+
+blank [ \t]
+string \"[^\"\n]*\"
+
+%%
+
+{blank}+ ; /* ignore */
+[\n]+ ; /* ignore */
+
+"(" return '(';
+")" return ')';
+"'" return '\'';
+
+false|FALSE return T_FALSE;
+true|TRUE return T_TRUE;
+
+{int}+\.{int}+ {
+ yylval->param_float = strtold(yytext, NULL);
+ return param_float;
+}
+
+{int}+ {
+ yylval->param_number = (int64_t) strtoumax(yytext, NULL, 10);
+ return param_number;
+}
+
+{id} {
+ yylval->param_name = yytext;
+ return param_name;
+}
+
+{string} {
+ yylval->param_string = yytext;
+ return param_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;
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "smartcolsP.h"
+
+#include "filter-parser.h"
+#include "filter-scanner.h"
+
+struct libscols_filter *scols_new_filter()
+{
+ struct libscols_filter *fltr = calloc(1, sizeof(*fltr));
+
+ return fltr;
+}
+
+static void reset_filter(struct libscols_filter *fltr)
+{
+ if (!fltr)
+ return;
+ filter_unref_node(fltr->root);
+ fltr->root = NULL;
+
+ if (fltr->src)
+ fclose(fltr->src);
+ fltr->src = NULL;
+}
+
+int scols_filter_parse_string(struct libscols_filter *fltr, const char *string)
+{
+ yyscan_t sc;
+ int rc;
+
+ reset_filter(fltr);
+
+ fltr->src = fmemopen((void *) string, strlen(string) + 1, "r");
+ if (!fltr->src)
+ return -errno;
+
+ yylex_init(&sc);
+ yyset_in(fltr->src, sc);
+
+ rc = yyparse(sc, fltr);
+ yylex_destroy(sc);
+
+ return rc;
+}
+
+/* TODO:
+
+scols_dump_filter()
+scols_line_apply_filter()
+scols_table_apply_filter()
+ */
#include "debug.h"
#include "buffer.h"
+#include <stdbool.h>
+
#include "libsmartcols.h"
/*
return ln && ln->group && !list_empty(&ln->group->gr_children);
}
+/*
+ * Filter stuff
+ */
+
+/* node types */
+enum filter_ntype {
+ F_NODE_PARAM,
+ F_NODE_EXPR
+};
+
+/* param types */
+enum filter_ptype {
+ F_PARAM_NUMBER,
+ F_PARAM_FLOAT,
+ F_PARAM_NAME,
+ F_PARAM_STRING,
+ F_PARAM_BOOLEAN
+};
+
+/* expresion types */
+enum filter_etype {
+ F_EXPR_AND,
+ F_EXPR_OR,
+ F_EXPR_NEG,
+
+ F_EXPR_EQ,
+ F_EXPR_NE,
+
+ F_EXPR_LT,
+ F_EXPR_LE,
+ F_EXPR_GT,
+ F_EXPR_GE,
+
+ F_EXPR_REG,
+ F_EXPR_NREG,
+};
+
+struct filter_node {
+ enum filter_ntype type;
+ int refcount;
+};
+
+#define filter_node_get_type(n) (((struct filter_node *)(n))->type)
+
+struct filter_param {
+ struct filter_node node;
+ enum filter_ptype type;
+
+ union {
+ char *str;
+ unsigned long long num;
+ long double fnum;
+ bool boolean;
+ } val;
+};
+
+struct filter_expr {
+ struct filter_node node;
+ enum filter_etype type;
+
+ struct filter_node *left;
+ struct filter_node *right;
+};
+
+struct libscols_filter {
+ 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 */
+struct filter_node *filter_new_param(struct libscols_filter *filter,
+ enum filter_ptype type,
+ void *data);
+struct filter_node *filter_new_expr(struct libscols_filter *filter,
+ enum filter_etype type,
+ struct filter_node *left,
+ struct filter_node *right);
+
#endif /* _LIBSMARTCOLS_PRIVATE_H */