From d9554c97e8407de309bbd7b4cd8a56b9b0d6c485 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Tue, 8 Apr 2014 12:13:02 +0200 Subject: [PATCH] libsmartcols: rewrite test code to tree(1)-like util Signed-off-by: Karel Zak --- lib/strutils.c | 2 +- libsmartcols/src/test.c | 306 +++++++++++++++++++++++++--------------- 2 files changed, 192 insertions(+), 116 deletions(-) diff --git a/lib/strutils.c b/lib/strutils.c index 450f2f3e3..31bf9e2af 100644 --- a/lib/strutils.c +++ b/lib/strutils.c @@ -394,7 +394,7 @@ void strtotimeval_or_err(const char *str, struct timeval *tv, const char *errmes /* * Converts stat->st_mode to ls(1)-like mode string. The size of "str" must - * be 10 bytes. + * be 11 bytes. */ void strmode(mode_t mode, char *str) { diff --git a/libsmartcols/src/test.c b/libsmartcols/src/test.c index fff3f47e0..90f9df443 100644 --- a/libsmartcols/src/test.c +++ b/libsmartcols/src/test.c @@ -15,26 +15,171 @@ #include #include #include -#include -#include #include +#include +#include +#include +#include #include "c.h" #include "nls.h" -#include "widechar.h" -#include "mbsalign.h" -#include "ttyutils.h" +#include "procutils.h" +#include "strutils.h" #include "colors.h" #include "libsmartcols.h" -enum { MYCOL_NAME, MYCOL_FOO, MYCOL_BAR, MYCOL_PATH }; +static int add_children(struct libscols_table *tb, + struct libscols_line *ln, int fd); + + +enum { COL_MODE, COL_SIZE, COL_NAME }; + +static void set_columns(struct libscols_table *tb, int notree) +{ + if (!scols_table_new_column(tb, "MODE", 0.3, 0)) + goto fail; + if (!scols_table_new_column(tb, "SIZE", 5, SCOLS_FL_RIGHT)) + goto fail; + if (!scols_table_new_column(tb, "NAME", 0.5, + (notree ? 0 : SCOLS_FL_TREE) | SCOLS_FL_NOEXTREMES)) + goto fail; + + return; +fail: + scols_unref_table(tb); + err(EXIT_FAILURE, "faild to create output columns"); +} + +static int add_line_from_stat(struct libscols_table *tb, + struct libscols_line *parent, + int parent_fd, + struct stat *st, + const char *name) +{ + struct libscols_line *ln; + char modbuf[11], *p; + mode_t mode = st->st_mode; + int rc = 0; + + ln = scols_table_new_line(tb, parent); + if (!ln) + err(EXIT_FAILURE, "failed to create output line"); + + /* MODE; local buffer, use scols_line_set_data() that calls strdup() */ + strmode(mode, modbuf); + if (scols_line_set_data(ln, COL_MODE, modbuf)) + goto fail; + + /* SIZE; already allocated string, use scols_line_refer_data() */ + p = size_to_human_string(0, st->st_size); + if (!p || scols_line_refer_data(ln, COL_SIZE, p)) + goto fail; + + /* NAME */ + if (scols_line_set_data(ln, COL_NAME, name)) + goto fail; + + /* colors */ + if (scols_table_colors_wanted(tb)) { + struct libscols_cell *ce = scols_line_get_cell(ln, COL_NAME); + + if (S_ISDIR(mode)) + scols_cell_set_color(ce, "blue"); + else if (S_ISLNK(mode)) + scols_cell_set_color(ce, "cyan"); + else if (S_ISBLK(mode)) + scols_cell_set_color(ce, "magenta"); + else if ((mode & S_IXOTH) || (mode & S_IXGRP) || (mode & S_IXUSR)) + scols_cell_set_color(ce, "green"); + } + + if (S_ISDIR(st->st_mode)) { + int fd; + + if (parent_fd >= 0) + fd = openat(parent_fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC); + else + fd = open(name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC); + if (fd >= 0) { + rc = add_children(tb, ln, fd); + close(fd); + } + } + return rc; +fail: + err(EXIT_FAILURE, "failed to create cell data"); + return -1; +} + +/* read all entrines from directory @fd */ +static int add_children(struct libscols_table *tb, + struct libscols_line *ln, + int fd) +{ + DIR *dir; + struct dirent *d; + + dir = fdopendir(fd); + if (!dir) + return -errno; + + while ((d = readdir(dir))) { + struct stat st; + + if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0) + continue; + if (fstatat(fd, d->d_name, &st, AT_SYMLINK_NOFOLLOW) != 0) + continue; + add_line_from_stat(tb, ln, fd, &st, d->d_name); + } + closedir(dir); + return 0; +} + +static void add_lines(struct libscols_table *tb, const char *dirname) +{ + struct stat st; + + if (lstat(dirname, &st)) + err(EXIT_FAILURE, "%s", dirname); + + add_line_from_stat(tb, NULL, -1, &st, dirname); +} + +static void __attribute__((__noreturn__)) usage(FILE *out) +{ + fputs(USAGE_HEADER, out); + fprintf(out, _(" %s [options] [ ...]\n"), program_invocation_short_name); + fputs(USAGE_OPTIONS, out); + fputs(_(" -i, --ascii use ascii characters only\n"), out); + fputs(_(" -l, --list use list format output\n"), out); + fputs(_(" -n, --noheadings don't print headings\n"), out); + fputs(_(" -p, --pairs use key=\"value\" output format\n"), out); + fputs(_(" -r, --raw use raw output format\n"), out); + + fputs(USAGE_SEPARATOR, out); + fputs(USAGE_HELP, out); + fputs(USAGE_VERSION, out); + + exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); +} int main(int argc, char *argv[]) { struct libscols_table *tb; - struct libscols_column *cl; - int notree = 0, clone = 0, i, color = 0; + int c, notree = 0, clonetb = 0; + + static const struct option longopts[] = { + { "help", 0, 0, 'h' }, + { "noheadings", 0, 0, 'n' }, + { "list", 0, 0, 'l' }, + { "ascii", 0, 0, 'i' }, + { "raw", 0, 0, 'r' }, + { "pairs", 0, 0, 'p' }, + { "clone", 0, 0, 'C' }, + { NULL, 0, 0, 0 }, + }; setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); @@ -44,120 +189,51 @@ int main(int argc, char *argv[]) tb = scols_new_table(); if (!tb) - err(EXIT_FAILURE, "table initialization failed"); + err(EXIT_FAILURE, "faild to create output table"); - if (argc == 2 && !strcmp(argv[1], "--help")) { - printf("%s [--max | --ascii | --raw | --export | --list | " - "--color | --colortree | --clone | --clonetree]\n", - program_invocation_short_name); - scols_unref_table(tb); - return EXIT_SUCCESS; - } else if (argc == 2 && !strcmp(argv[1], "--max")) { - scols_table_enable_maxout(tb, 1); - } else if (argc == 2 && !strcmp(argv[1], "--ascii")) { - scols_table_enable_ascii(tb, 1); - } else if (argc == 2 && !strcmp(argv[1], "--raw")) { - scols_table_enable_raw(tb, 1); - notree = 1; - } else if (argc == 2 && !strcmp(argv[1], "--export")) { - scols_table_enable_export(tb, 1); - notree = 1; - } else if (argc == 2 && !strcmp(argv[1], "--list")) { - notree = 1; - } else if (argc == 2 && !strcmp(argv[1], "--color")) { - notree = 1; - color = 1; - } else if (argc == 2 && !strcmp(argv[1], "--colortree")) { - notree = 0; - color = 1; - } else if (argc == 2 && !strcmp(argv[1], "--clone")) { - notree = 1; - clone = 1; - } else if (argc == 2 && !strcmp(argv[1], "--clonetree")) { - notree = 0; - clone = 1; + while((c = getopt_long(argc, argv, "nlirpC", longopts, NULL)) != -1) { + switch(c) { + case 'h': + usage(stdout); + break; + case 'l': + notree = 1; + break; + case 'n': + scols_table_enable_noheadings(tb, 1); + break; + case 'p': + scols_table_enable_export(tb, 1); + notree = 1; + break; + case 'i': + scols_table_enable_ascii(tb, 1); + break; + case 'r': + scols_table_enable_raw(tb, 1); + notree = 1; + break; + case 'C': + clonetb = 1; + default: + usage(stderr); + } } - cl = scols_table_new_column(tb, "NAME", 0.3, notree ? 0 : SCOLS_FL_TREE); - scols_table_enable_colors(tb, color); + scols_table_enable_colors(tb, 1); + set_columns(tb, notree); - if (color) - scols_column_set_color(cl, UL_COLOR_RED); + while (optind < argc) + add_lines(tb, argv[optind++]); - cl = scols_table_new_column(tb, "FOO", 0.3, SCOLS_FL_TRUNC); - if (color) { - struct libscols_cell *h = scols_column_get_header(cl); - - scols_column_set_color(cl, UL_COLOR_BOLD_GREEN); - scols_cell_set_color(h, "green"); /* a human-readable string is also legal */ - } - scols_table_new_column(tb, "BAR", 0.3, 0); - scols_table_new_column(tb, "PATH", 0.3, 0); - - for (i = 0; i < 2; i++) { - struct libscols_line *ln = scols_table_new_line(tb, NULL); - struct libscols_line *pr, *root = ln; - - scols_line_set_data(ln, MYCOL_NAME, "AAA"); - scols_line_set_data(ln, MYCOL_FOO, "a-foo-foo"); - scols_line_set_data(ln, MYCOL_BAR, "barBar-A"); - scols_line_set_data(ln, MYCOL_PATH, "/mnt/AAA"); - - pr = ln = scols_table_new_line(tb, root); - scols_line_set_data(ln, MYCOL_NAME, "AAA.A"); - scols_line_set_data(ln, MYCOL_FOO, "a.a-foo-foo"); - scols_line_set_data(ln, MYCOL_BAR, "barBar-A.A"); - scols_line_set_data(ln, MYCOL_PATH, "/mnt/AAA/A"); - if (color) - scols_line_set_color(ln, UL_COLOR_BOLD_YELLOW); - - ln = scols_table_new_line(tb, pr); - scols_line_set_data(ln, MYCOL_NAME, "AAA.A.AAA"); - scols_line_set_data(ln, MYCOL_FOO, "a.a.a-foo-foo"); - scols_line_set_data(ln, MYCOL_BAR, "barBar-A.A.A"); - scols_line_set_data(ln, MYCOL_PATH, "/mnt/AAA/A/AAA"); - - ln = scols_table_new_line(tb, root); - scols_line_set_data(ln, MYCOL_NAME, "AAA.B"); - scols_line_set_data(ln, MYCOL_FOO, "a.b-foo-foo"); - scols_line_set_data(ln, MYCOL_BAR, "barBar-A.B"); - scols_line_set_data(ln, MYCOL_PATH, "/mnt/AAA/B"); - - if (color) - scols_cell_set_color(scols_line_get_cell(ln, MYCOL_FOO), - UL_COLOR_MAGENTA); - - ln = scols_table_new_line(tb, pr); - scols_line_set_data(ln, MYCOL_NAME, "AAA.A.BBB"); - scols_line_set_data(ln, MYCOL_FOO, "a.a.b-foo-foo"); - scols_line_set_data(ln, MYCOL_BAR, "barBar-A.A.BBB"); - scols_line_set_data(ln, MYCOL_PATH, "/mnt/AAA/A/BBB"); - - ln = scols_table_new_line(tb, pr); - scols_line_set_data(ln, MYCOL_NAME, "AAA.A.CCC"); - scols_line_set_data(ln, MYCOL_FOO, "a.a.c-foo-foo"); - scols_line_set_data(ln, MYCOL_BAR, "barBar-A.A.CCC"); - scols_line_set_data(ln, MYCOL_PATH, "/mnt/AAA/A/CCC"); - - ln = scols_table_new_line(tb, root); - scols_line_set_data(ln, MYCOL_NAME, "AAA.C"); - scols_line_set_data(ln, MYCOL_FOO, "a.c-foo-foo"); - scols_line_set_data(ln, MYCOL_BAR, "barBar-A.C"); - scols_line_set_data(ln, MYCOL_PATH, "/mnt/AAA/C"); - } - - printf("\nColumns: %d, Lines: %d\n\n", - scols_table_get_ncols(tb), - scols_table_get_nlines(tb)); - - if (clone) { + if (clonetb) { struct libscols_table *xtb = scols_copy_table(tb); - scols_print_table(xtb); - fputs("\n\n", stdout); - scols_unref_table(xtb); - } - scols_print_table(tb); + scols_print_table(xtb); + scols_unref_table(xtb); + } else + scols_print_table(tb); + scols_unref_table(tb); return EXIT_SUCCESS;