From 8bb05ac73a5b448b339ce0bc8d396c82c459b47f Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 14 Apr 2024 21:33:32 +0200 Subject: Merging upstream version 2.40. Signed-off-by: Daniel Baumann --- libsmartcols/samples/Makemodule.am | 8 +- libsmartcols/samples/continuous-json.c | 80 ++++++++++ libsmartcols/samples/continuous.c | 4 +- libsmartcols/samples/fromfile.c | 259 ++++++++++++++++++--------------- libsmartcols/samples/maxout.c | 2 +- libsmartcols/samples/wrap.c | 10 +- 6 files changed, 240 insertions(+), 123 deletions(-) create mode 100644 libsmartcols/samples/continuous-json.c (limited to 'libsmartcols/samples') diff --git a/libsmartcols/samples/Makemodule.am b/libsmartcols/samples/Makemodule.am index c0130b9..b192eba 100644 --- a/libsmartcols/samples/Makemodule.am +++ b/libsmartcols/samples/Makemodule.am @@ -4,13 +4,13 @@ check_PROGRAMS += \ sample-scols-title \ sample-scols-wrap \ sample-scols-continuous \ + sample-scols-continuous-json \ sample-scols-fromfile \ sample-scols-grouping-simple \ sample-scols-grouping-overlay \ sample-scols-maxout -sample_scols_cflags = $(AM_CFLAGS) $(NO_UNUSED_WARN_CFLAGS) \ - -I$(ul_libsmartcols_incdir) +sample_scols_cflags = $(AM_CFLAGS) -I$(ul_libsmartcols_incdir) sample_scols_ldadd = libsmartcols.la $(LDADD) if HAVE_OPENAT @@ -36,6 +36,10 @@ sample_scols_continuous_SOURCES = libsmartcols/samples/continuous.c sample_scols_continuous_LDADD = $(sample_scols_ldadd) libcommon.la sample_scols_continuous_CFLAGS = $(sample_scols_cflags) +sample_scols_continuous_json_SOURCES = libsmartcols/samples/continuous-json.c +sample_scols_continuous_json_LDADD = $(sample_scols_ldadd) libcommon.la +sample_scols_continuous_json_CFLAGS = $(sample_scols_cflags) + sample_scols_maxout_SOURCES = libsmartcols/samples/maxout.c sample_scols_maxout_LDADD = $(sample_scols_ldadd) sample_scols_maxout_CFLAGS = $(sample_scols_cflags) diff --git a/libsmartcols/samples/continuous-json.c b/libsmartcols/samples/continuous-json.c new file mode 100644 index 0000000..ae1f405 --- /dev/null +++ b/libsmartcols/samples/continuous-json.c @@ -0,0 +1,80 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * Copyright (C) 2016 Karel Zak + * Copyright (C) 2023 Thomas Weißschuh + */ +#include +#include +#include +#include + +#include "c.h" +#include "xalloc.h" + +#include "libsmartcols.h" + +/* add columns to the @tb */ +static void setup_columns(struct libscols_table *tb) +{ + scols_table_enable_maxout(tb, 1); + if (!scols_table_new_column(tb, "COUNT", 0.1, SCOLS_FL_RIGHT)) + goto fail; + if (!scols_table_new_column(tb, "TEXT", 0.9, 0)) + goto fail; + return; +fail: + scols_unref_table(tb); + err(EXIT_FAILURE, "failed to create output columns"); +} + +static struct libscols_line *add_line(struct libscols_table *tb, int i) +{ + char *p; + struct libscols_line *ln = scols_table_new_line(tb, NULL); + + if (!ln) + err(EXIT_FAILURE, "failed to create output line"); + + xasprintf(&p, "%d", i); + if (scols_line_refer_data(ln, 0, p)) + goto fail; + + xasprintf(&p, "text%d", i); + if (scols_line_refer_data(ln, 1, p)) + goto fail; + + return ln; +fail: + scols_unref_table(tb); + err(EXIT_FAILURE, "failed to create output line"); +} + +int main(void) +{ + struct libscols_table *tb; + size_t i; + + scols_init_debug(0); + + tb = scols_new_table(); + if (!tb) + err(EXIT_FAILURE, "failed to create output table"); + scols_table_enable_json(tb, 1); + + setup_columns(tb); + + for (i = 0; i < 10; i++) { + struct libscols_line *line; + + line = add_line(tb, i); + + /* print the line */ + scols_table_print_range(tb, line, NULL); + + fflush(scols_table_get_stream(tb)); + } + + scols_unref_table(tb); + return EXIT_SUCCESS; +} diff --git a/libsmartcols/samples/continuous.c b/libsmartcols/samples/continuous.c index 6bdba6e..432b027 100644 --- a/libsmartcols/samples/continuous.c +++ b/libsmartcols/samples/continuous.c @@ -65,7 +65,7 @@ fail: err(EXIT_FAILURE, "failed to create output line"); } -int main(int argc, char *argv[]) +int main(void) { struct libscols_table *tb; size_t i; @@ -85,7 +85,7 @@ int main(int argc, char *argv[]) struct libscols_line *line; struct timeval now; int done = 0; - char *timecell = xmalloc( timecellsz ); + char *timecell = xcalloc(1, timecellsz ); line = add_line(tb, i); diff --git a/libsmartcols/samples/fromfile.c b/libsmartcols/samples/fromfile.c index 0fdc929..cf77cc4 100644 --- a/libsmartcols/samples/fromfile.c +++ b/libsmartcols/samples/fromfile.c @@ -18,136 +18,63 @@ #include "strutils.h" #include "xalloc.h" #include "optutils.h" +#include "mangle.h" +#include "path.h" #include "libsmartcols.h" -struct column_flag { - const char *name; - int mask; -}; - -static const struct column_flag flags[] = { - { "trunc", SCOLS_FL_TRUNC }, - { "tree", SCOLS_FL_TREE }, - { "right", SCOLS_FL_RIGHT }, - { "strictwidth",SCOLS_FL_STRICTWIDTH }, - { "noextremes", SCOLS_FL_NOEXTREMES }, - { "hidden", SCOLS_FL_HIDDEN }, - { "wrap", SCOLS_FL_WRAP }, - { "wrapnl", SCOLS_FL_WRAP }, - { "none", 0 } -}; - -static long name_to_flag(const char *name, size_t namesz) +static struct libscols_column *parse_column(const char *path) { - size_t i; + char buf[BUFSIZ]; + struct libscols_column *cl; - for (i = 0; i < ARRAY_SIZE(flags); i++) { - const char *cn = flags[i].name; + if (ul_path_read_buffer(NULL, buf, sizeof(buf), path) < 0) + err(EXIT_FAILURE, "failed to read column: %s", path); - if (!strncasecmp(name, cn, namesz) && !*(cn + namesz)) - return flags[i].mask; - } - warnx("unknown flag: %s", name); - return -1; -} - -static int parse_column_flags(char *str) -{ - unsigned long num_flags = 0; - - if (string_to_bitmask(str, &num_flags, name_to_flag)) - err(EXIT_FAILURE, "failed to parse column flags"); - - return num_flags; -} - -static struct libscols_column *parse_column(FILE *f) -{ - size_t len = 0; - char *line = NULL; - int nlines = 0; + cl = scols_new_column(); + if (!cl) + err(EXIT_FAILURE, "failed to allocate column"); - struct libscols_column *cl = NULL; + if (scols_column_set_properties(cl, buf) != 0) + err(EXIT_FAILURE, "failed to set column properties"); - while (getline(&line, &len, f) != -1) { - - char *p = strrchr(line, '\n'); - if (p) - *p = '\0'; - - switch (nlines) { - case 0: /* NAME */ - cl = scols_new_column(); - if (!cl) - goto fail; - if (scols_column_set_name(cl, line) != 0) - goto fail; - break; - - case 1: /* WIDTH-HINT */ - { - double whint = strtod_or_err(line, "failed to parse column whint"); - if (scols_column_set_whint(cl, whint)) - goto fail; - break; - } - case 2: /* FLAGS */ - { - int num_flags = parse_column_flags(line); - if (scols_column_set_flags(cl, num_flags)) - goto fail; - if (strcmp(line, "wrapnl") == 0) { - scols_column_set_wrapfunc(cl, - scols_wrapnl_chunksize, - scols_wrapnl_nextchunk, - NULL); - scols_column_set_safechars(cl, "\n"); - } - break; - } - case 3: /* COLOR */ - if (scols_column_set_color(cl, line)) - goto fail; - break; - default: - break; - } - - nlines++; - } - - free(line); return cl; -fail: - free(line); - scols_unref_column(cl); - return NULL; } static int parse_column_data(FILE *f, struct libscols_table *tb, int col) { size_t len = 0, nlines = 0; - int i; - char *str = NULL; + ssize_t i; + char *str = NULL, *p; while ((i = getline(&str, &len, f)) != -1) { - struct libscols_line *ln; - char *p = strrchr(str, '\n'); - if (p) - *p = '\0'; - - while ((p = strrchr(str, '\\')) && *(p + 1) == 'n') { - *p = '\n'; - memmove(p + 1, p + 2, i - (p + 2 - str)); - } + int rc = 0; ln = scols_table_get_line(tb, nlines++); if (!ln) break; - if (*str && scols_line_set_data(ln, col, str) != 0) + p = strrchr(str, '\n'); + if (p) + *p = '\0'; + if (!*str) + continue; + + /* convert \x?? to real bytes */ + if (strstr(str, "\\x")) { + struct libscols_cell *ce = scols_line_get_cell(ln, col); + size_t sz = i + 1; + char *buf = xcalloc(1, sz); + + sz = unhexmangle_to_buffer(str, buf, sz); + if (sz) + rc = scols_cell_refer_memory(ce, buf, sz); + else + free(buf); + } else + rc = scols_line_set_data(ln, col, str); + if (rc) err(EXIT_FAILURE, "failed to add output data"); } @@ -193,6 +120,83 @@ static void compose_tree(struct libscols_table *tb, int parent_col, int id_col) scols_free_iter(itr); } +static struct libscols_filter *init_filter( + struct libscols_table *tb, + const char *query, int dump) +{ + struct libscols_iter *itr; + struct libscols_filter *f = scols_new_filter(NULL); + const char *name = NULL; + int rc = 0; + + if (!f) + err(EXIT_FAILURE, "failed to allocate filter"); + if (scols_filter_parse_string(f, query) != 0) { + warnx("failed to parse filter: %s", scols_filter_get_errmsg(f)); + scols_unref_filter(f); + return NULL; + } + + 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; + + col = scols_table_get_column_by_name(tb, name); + if (!col) { + warnx("unknown column '%s' in filter", name); + rc++; + continue; + } + scols_filter_assign_column(f, itr, name, col); + } + + scols_free_iter(itr); + if (dump && f) + scols_dump_filter(f, stdout); + if (rc) { + scols_unref_filter(f); + errx(EXIT_FAILURE, "failed to initialize filter"); + } + + return f; +} + +/* Note: This is a simple (naive) way to use the filter, employed here for + * testing functionality. + * + * A more effective approach to using the filter is demonstrated in lsblk.c, + * where data manipulation is divided into two steps. The initial step prepares + * only the data necessary for evaluating the filter, and the remaining data is + * gathered later, only if necessary. + */ +static void apply_filter(struct libscols_table *tb, struct libscols_filter *fltr) +{ + struct libscols_iter *itr = scols_new_iter(SCOLS_ITER_FORWARD); + struct libscols_line *ln; + + if (!itr) + err(EXIT_FAILURE, "failed to allocate iterator"); + + while (scols_table_next_line(tb, itr, &ln) == 0) { + int status = 0; + + if (scols_line_apply_filter(ln, fltr, &status) != 0) + err(EXIT_FAILURE, "failed to apply filter"); + if (status == 0) { + struct libscols_line *x = scols_line_get_parent(ln); + + if (x) + scols_line_remove_child(x, ln); + scols_table_remove_line(tb, ln); + ln = NULL; + } + } + + scols_free_iter(itr); +} static void __attribute__((__noreturn__)) usage(void) { @@ -211,6 +215,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(" -w, --width hardcode terminal width\n", out); fputs(" -p, --tree-parent-column parent column\n", out); fputs(" -i, --tree-id-column id column\n", out); + fputs(" -Q, --filter filter\n", out); fputs(" -h, --help this help\n", out); fputs("\n", out); @@ -220,8 +225,11 @@ static void __attribute__((__noreturn__)) usage(void) int main(int argc, char *argv[]) { struct libscols_table *tb; - int c, n, nlines = 0; + int c, n, nlines = 0, rc; int parent_col = -1, id_col = -1; + int fltr_dump = 0; + const char *fltr_str = NULL; + struct libscols_filter *fltr = NULL; static const struct option longopts[] = { { "maxout", 0, NULL, 'm' }, @@ -235,6 +243,8 @@ int main(int argc, char *argv[]) { "raw", 0, NULL, 'r' }, { "export", 0, NULL, 'E' }, { "colsep", 1, NULL, 'C' }, + { "filter", 1, NULL, 'Q' }, + { "filter-dump", 0, NULL, 'd' }, { "help", 0, NULL, 'h' }, { NULL, 0, NULL, 0 }, }; @@ -253,25 +263,23 @@ int main(int argc, char *argv[]) if (!tb) err(EXIT_FAILURE, "failed to create output table"); - while((c = getopt_long(argc, argv, "hCc:Ei:JMmn:p:rw:", longopts, NULL)) != -1) { + while((c = getopt_long(argc, argv, "hCc:dEi:JMmn:p:Q:rw:", longopts, NULL)) != -1) { err_exclusive_options(c, longopts, excl, excl_st); switch(c) { case 'c': /* add column from file */ { - struct libscols_column *cl; - FILE *f = fopen(optarg, "r"); + struct libscols_column *cl = parse_column(optarg); - if (!f) - err(EXIT_FAILURE, "%s: open failed", optarg); - cl = parse_column(f); if (cl && scols_table_add_column(tb, cl)) err(EXIT_FAILURE, "%s: failed to add column", optarg); scols_unref_column(cl); - fclose(f); break; } + case 'd': + fltr_dump = 1; + break; case 'p': parent_col = strtou32_or_err(optarg, "failed to parse tree PARENT column"); break; @@ -300,6 +308,9 @@ int main(int argc, char *argv[]) case 'n': nlines = strtou32_or_err(optarg, "failed to parse number of lines"); break; + case 'Q': + fltr_str = optarg; + break; case 'w': scols_table_set_termforce(tb, SCOLS_TERMFORCE_ALWAYS); scols_table_set_termwidth(tb, strtou32_or_err(optarg, "failed to parse terminal width")); @@ -323,6 +334,14 @@ int main(int argc, char *argv[]) scols_unref_line(ln); } + if (fltr_str) { + fltr = init_filter(tb, fltr_str, fltr_dump); + if (!fltr) { + rc = EXIT_FAILURE; + goto done; + } + } + n = 0; while (optind < argc) { @@ -341,7 +360,13 @@ int main(int argc, char *argv[]) scols_table_enable_colors(tb, isatty(STDOUT_FILENO)); + if (fltr) + apply_filter(tb, fltr); + scols_print_table(tb); + rc = EXIT_SUCCESS; +done: + scols_unref_filter(fltr); scols_unref_table(tb); - return EXIT_SUCCESS; + return rc; } diff --git a/libsmartcols/samples/maxout.c b/libsmartcols/samples/maxout.c index 20c6424..a867697 100644 --- a/libsmartcols/samples/maxout.c +++ b/libsmartcols/samples/maxout.c @@ -19,7 +19,7 @@ enum { COL_LEFT, COL_FOO, COL_RIGHT }; -int main(int argc, char *argv[]) +int main(void) { struct libscols_table *tb; int rc = -1, nlines = 3; diff --git a/libsmartcols/samples/wrap.c b/libsmartcols/samples/wrap.c index 795bef7..8368304 100644 --- a/libsmartcols/samples/wrap.c +++ b/libsmartcols/samples/wrap.c @@ -92,7 +92,15 @@ int main(int argc, char *argv[]) if (!tb) err(EXIT_FAILURE, "failed to create output table"); - scols_table_enable_colors(tb, isatty(STDOUT_FILENO)); + if (argc > 1 && strcmp(argv[1], "--export") == 0) + scols_table_enable_export(tb, 1); + else if (argc > 1 && strcmp(argv[1], "--raw") == 0) + scols_table_enable_raw(tb, 1); + else if (argc > 1 && strcmp(argv[1], "--json") == 0) + scols_table_enable_json(tb, 1); + else + scols_table_enable_colors(tb, isatty(STDOUT_FILENO)); + setup_columns(tb); ln = add_line(tb, NULL, "A"); -- cgit v1.2.3