From 04b1132b2b0b8eff300ad3c7fa5f576f0bc64d7a Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Wed, 13 Sep 2023 11:59:13 +0200 Subject: [PATCH] libsmartcols: (filter) support empty values Signed-off-by: Karel Zak --- libsmartcols/samples/filter.c | 39 ++++++++++++--------- libsmartcols/src/filter-param.c | 61 +++++++++++++++++++-------------- 2 files changed, 58 insertions(+), 42 deletions(-) diff --git a/libsmartcols/samples/filter.c b/libsmartcols/samples/filter.c index 844fc7d2f9..ceba8be582 100644 --- a/libsmartcols/samples/filter.c +++ b/libsmartcols/samples/filter.c @@ -54,28 +54,33 @@ fail: err(EXIT_FAILURE, "failed to create output columns"); } -static struct libscols_line *add_line(struct libscols_table *tb, int n) +static struct libscols_line *add_line(struct libscols_table *tb, int n, int empty) { char *data = NULL; struct libscols_line *ln = scols_table_new_line(tb, NULL); if (!ln) err(EXIT_FAILURE, "failed to create output line"); - xasprintf(&data, "#%d", n); - if (scols_line_refer_data(ln, COL_NAME, data)) - goto fail; - - xasprintf(&data, "%d", n); - if (scols_line_refer_data(ln, COL_NUM, data)) - goto fail; - - xasprintf(&data, "%d.%d", n, n); - if (scols_line_refer_data(ln, COL_FLOAT, data)) - goto fail; - - xasprintf(&data, "str%dstr", n); - if (scols_line_refer_data(ln, COL_STRING, data)) - goto fail; + if (empty != 1) { + xasprintf(&data, "#%d", n); + if (scols_line_refer_data(ln, COL_NAME, data)) + goto fail; + } + if (empty != 2) { + xasprintf(&data, "%d", n); + if (scols_line_refer_data(ln, COL_NUM, data)) + goto fail; + } + if (empty != 3) { + xasprintf(&data, "%d.%d", n, n); + if (scols_line_refer_data(ln, COL_FLOAT, data)) + goto fail; + } + if (empty != 4) { + xasprintf(&data, "str%dstr", n); + if (scols_line_refer_data(ln, COL_STRING, data)) + goto fail; + } return ln; fail: scols_unref_table(tb); @@ -156,7 +161,7 @@ int main(int argc, char *argv[]) } for (i = 0; i < 10; i++) { - struct libscols_line *ln = add_line(tb, i + 1); + struct libscols_line *ln = add_line(tb, i + 1, i % 4); int rc, status = 0; if (!fltr) diff --git a/libsmartcols/src/filter-param.c b/libsmartcols/src/filter-param.c index 5a43c845fd..86201ae1b9 100644 --- a/libsmartcols/src/filter-param.c +++ b/libsmartcols/src/filter-param.c @@ -27,26 +27,26 @@ static int param_set_data(struct filter_param *n, enum filter_data type, const v switch (type) { case F_DATA_STRING: p = data; - if (*p == '"') { + if (p && *p == '"') { /* remove quotation marks */ size_t len = strlen(p); if (*(p + (len - 1)) == '"') len -= 2; n->val.str = strndup(p + 1, len); - } else + } else if (data) n->val.str = strdup((char *) data); - if (!n->val.str) + if (data && !n->val.str) return -ENOMEM; break; case F_DATA_NUMBER: - n->val.num = *((unsigned long long *) data); + n->val.num = data ? *((unsigned long long *) data) : 0; break; case F_DATA_FLOAT: - n->val.fnum = *((long double *) data); + n->val.fnum = data ? *((long double *) data) : 0; break; case F_DATA_BOOLEAN: - n->val.boolean = *((bool *) data) == 0 ? 0 : 1; + n->val.boolean = data ? (*((bool *) data) == 0 ? 0 : 1) : 0; break; default: return 0; @@ -193,7 +193,7 @@ static int fetch_holder_data(struct libscols_filter *fltr __attribute__((__unuse { const char *data; enum filter_data type = n->type; - int rc; + int rc = 0; if (n->has_value || n->holder != F_HOLDER_COLUMN) return 0; @@ -251,27 +251,38 @@ done: return rc; } +static int xstrcmp(char *a, char *b) +{ + if (!a && !b) + return 0; + if (!a && b) + return -1; + if (a && !b) + return 1; + return strcmp(a, b); +} + static int string_opers(enum filter_etype oper, struct filter_param *l, struct filter_param *r, int *status) { switch (oper) { case F_EXPR_EQ: - *status = strcmp(l->val.str, r->val.str) == 0; + *status = xstrcmp(l->val.str, r->val.str) == 0; break; case F_EXPR_NE: - *status = strcmp(l->val.str, r->val.str) != 0; + *status = xstrcmp(l->val.str, r->val.str) != 0; break; case F_EXPR_LE: - *status = strcmp(l->val.str, r->val.str) <= 0; + *status = xstrcmp(l->val.str, r->val.str) <= 0; break; case F_EXPR_LT: - *status = strcmp(l->val.str, r->val.str) < 0; + *status = xstrcmp(l->val.str, r->val.str) < 0; break; case F_EXPR_GE: - *status = strcmp(l->val.str, r->val.str) >= 0; + *status = xstrcmp(l->val.str, r->val.str) >= 0; break; case F_EXPR_GT: - *status = strcmp(l->val.str, r->val.str) > 0; + *status = xstrcmp(l->val.str, r->val.str) > 0; break; default: return -EINVAL; @@ -412,19 +423,23 @@ static int string_cast(enum filter_data type, struct filter_param *n) switch (type) { case F_DATA_NUMBER: { - uint64_t num; - int rc = ul_strtou64(str, &num, 10); - if (rc) - return rc; + uint64_t num = 0; + if (str) { + int rc = ul_strtou64(str, &num, 10); + if (rc) + return rc; + } n->val.num = num; break; } case F_DATA_FLOAT: { - long double num; - int rc = ul_strtold(str, &num); - if (rc) - return rc; + long double num = 0; + if (str) { + int rc = ul_strtold(str, &num); + if (rc) + return rc; + } n->val.fnum = num; break; } @@ -521,8 +536,6 @@ static int cast_param(enum filter_data type, struct filter_param *n) int rc; enum filter_data orgtype = n->type; - if (!n->has_value) - return -EINVAL; if (type == orgtype) return 0; @@ -569,8 +582,6 @@ int filter_cast_param(struct libscols_filter *fltr, rc = fetch_holder_data(fltr, n, ln); if (rc) return rc; - if (!n->has_value) - return -EINVAL; if (type == orgtype) { filter_ref_node((struct filter_node *) n); /* caller wants to call filter_unref_node() for the result */ -- 2.47.3