[PATCH v3] Added miscutil/tree.c
rknecht at pm.me
rknecht at pm.me
Sun May 1 11:47:24 UTC 2022
Thanks Tito,
replacing the global variable adds additional 60 bytes in the bloatcheck.
The global variable avoids the stack allocation and zero initialisation.
Regards,
Roger
------- Original Message -------
On Monday, April 25th, 2022 at 7:40 PM, tito <farmatito at tiscali.it> wrote:
>
>
> On Mon, 25 Apr 2022 16:56:50 +0000
> rknecht at pm.me wrote:
>
> > Hi Tito,
> >
> > Thanks again for your valuable feedback for V2. I fixed your remarks in V3.
> > Could you please have a look at V3?
> >
> > If you are ok with the changes I would like to ask you for a sign-off so that we can hopefully merge the tree tool soon.
>
>
> Hi,
> looks good to me, maybe just the global vars could be removed...
> I don't think there is a need for me to sign-off as I have no superpowers,
> you need just to wait for the maintainer to say the final word.
>
> Ciao,
> Tito
>
> > Thanks,
> > Roger
> >
> > ------- Original Message -------
> > On Monday, April 18th, 2022 at 2:54 PM, Roger Knecht rknecht at pm.me wrote:
> >
> > > Adds the tree program to list directories and files in a tree structure.
> > >
> > > function old new delta
> > > tree_print - 388 +388
> > > .rodata 95677 95766 +89
> > > tree_main - 73 +73
> > > tree_print_prefix - 28 +28
> > > globals - 8 +8
> > > applet_main 3192 3200 +8
> > > applet_names 2747 2752 +5
> > > packed_usage 34414 34396 -18
> > > ------------------------------------------------------------------------------
> > > (add/remove: 5/0 grow/shrink: 3/1 up/down: 599/-18) Total: 581 bytes
> > >
> > > Signed-off-by: Roger Knecht rknecht at pm.me
> > >
> > > ---
> > > V4 is addressing Tito's remark regarding the symlink and multiple
> > > directory handling.
> > >
> > > Changelog:
> > >
> > > V3:
> > > - Fixed symlink handling
> > > - Handle multiple directories in command line arguments
> > > - Extended tests for symlink and multiple directories
> > > - Reduced size by using libbb functions
> > >
> > > V2:
> > > - Fixed tree help text
> > > - Reduced size by 644 bytes
> > >
> > > AUTHORS | 3 +
> > > miscutils/tree.c | 135 +++++++++++++++++++++++++++++++++++++++++++
> > > testsuite/tree.tests | 97 +++++++++++++++++++++++++++++++
> > > 3 files changed, 235 insertions(+)
> > > create mode 100644 miscutils/tree.c
> > > create mode 100755 testsuite/tree.tests
> > >
> > > diff --git a/AUTHORS b/AUTHORS
> > > index 5c9a634c9..9ec0e2ee4 100644
> > > --- a/AUTHORS
> > > +++ b/AUTHORS
> > > @@ -181,3 +181,6 @@ Jie Zhang jie.zhang at analog.com
> > >
> > > Maxime Coste mawww at kakoune.org
> > >
> > > paste implementation
> > > +
> > > +Roger Knecht rknecht at pm.me
> > >
> > > + tree
> > > diff --git a/miscutils/tree.c b/miscutils/tree.c
> > > new file mode 100644
> > > index 000000000..e053e8483
> > > --- /dev/null
> > > +++ b/miscutils/tree.c
> > > @@ -0,0 +1,135 @@
> > > +/* vi: set sw=4 ts=4: /
> > > +/
> > > + * Copyright (C) 2022 Roger Knecht rknecht at pm.me
> > >
> > > + *
> > > + * Licensed under GPLv2, see file LICENSE in this source tree.
> > > + /
> > > +//config:config TREE
> > > +//config: bool "tree (0.6 kb)"
> > > +//config: default n
> > > +//config: help
> > > +//config: List files and directories in a tree structure.
> > > +//config:
> > > +
> > > +//applet:IF_TREE(APPLET(tree, BB_DIR_USR_BIN, BB_SUID_DROP))
> > > +
> > > +//kbuild:lib-$(CONFIG_TREE) += tree.o
> > > +
> > > +//usage:#define tree_trivial_usage NOUSAGE_STR
> > > +//usage:#define tree_full_usage ""
> > > +
> > > +#include "libbb.h"
> > > +
> > > +#define PREFIX_CHILD "├── "
> > > +#define PREFIX_LAST_CHILD "└── "
> > > +#define PREFIX_GRAND_CHILD "│ "
> > > +#define PREFIX_LAST_GRAND_CHILD " "
> > > +#define DEFAULT_PATH "."
> > > +
> > > +struct directory {
> > > + struct directory parent;
> > > + const char* prefix;
> > > +};
> > > +
> > > +static struct globals {
> > > + int directories;
> > > + int files;
> > > +} globals;
> > > +
> > > +static void tree_print_prefix(struct directory* directory) {
> > > + if (directory) {
> > > + tree_print_prefix(directory->parent);
> > >
> > > + fputs_stdout(directory->prefix);
> > >
> > > + }
> > > +}
> > > +
> > > +static void tree_print(const char* directory_name, struct directory* directory) {
> > > + struct dirent **entries, dirent;
> > > + struct directory child_directory;
> > > + char symlink_path;
> > > + int index, size;
> > > + bool is_not_last, is_file;
> > > +
> > > + // read directory entries
> > > + size = scandir(directory_name, &entries, NULL, alphasort);
> > > +
> > > + if (size < 0) {
> > > + fputs_stdout(directory_name);
> > > + puts(" [error opening dir]");
> > > + return;
> > > + }
> > > +
> > > + // print directory name
> > > + puts(directory_name);
> > > +
> > > + // switch to sub directory
> > > + xchdir(directory_name);
> > > +
> > > + child_directory.parent = directory;
> > > +
> > > + // print all directory entries
> > > + for (index = 0; index < size; index++) {
> > > + dirent = entries[index];
> > > +
> > > + // filter hidden files and directories
> > > + if (strncmp(dirent->d_name, ".", 1) != 0) {
> > >
> > > + is_file = !is_directory(dirent->d_name, 1);
> > >
> > > + is_not_last = (index + 1) < size;
> > > + symlink_path = xmalloc_readlink(dirent->d_name);
> > >
> > > +
> > > + // print tree line prefix
> > > + tree_print_prefix(directory);
> > > +
> > > + if (is_not_last) {
> > > + child_directory.prefix = PREFIX_GRAND_CHILD;
> > > + fputs_stdout(PREFIX_CHILD);
> > > + } else {
> > > + child_directory.prefix = PREFIX_LAST_GRAND_CHILD;
> > > + fputs_stdout(PREFIX_LAST_CHILD);
> > > + }
> > > +
> > > + // count directories and files
> > > + if (is_file)
> > > + globals.files++;
> > > + else
> > > + globals.directories++;
> > > +
> > > + if (symlink_path) {
> > > + // handle symlink
> > > + printf("%s -> %s\n", dirent->d_name, symlink_path);
> > >
> > > + free(symlink_path);
> > > + } else if (is_file)
> > > + // handle file
> > > + puts(dirent->d_name);
> > >
> > > + else
> > > + // handle directory
> > > + tree_print(dirent->d_name, &child_directory);
> > >
> > > + }
> > > +
> > > + // release directory entry
> > > + free(dirent);
> > > + }
> > > +
> > > + // release directory array
> > > + free(entries);
> > > +
> > > + // switch to parent directory
> > > + xchdir("..");
> > > +}
> > > +
> > > +int tree_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
> > > +int tree_main(int argc, char **argv)
> > > +{
> > > + if (argc == 1)
> > > + // list current working directory
> > > + tree_print(DEFAULT_PATH, NULL);
> > > +
> > > + // list directories given as command line arguments
> > > + while (*(++argv))
> > > + tree_print(*argv, NULL);
> > > +
> > > + // print statistic
> > > + printf("\n%d directories, %d files\n", globals.directories, globals.files);
> > > +
> > > + return EXIT_SUCCESS;
> > > +}
> > > diff --git a/testsuite/tree.tests b/testsuite/tree.tests
> > > new file mode 100755
> > > index 000000000..bad28d46c
> > > --- /dev/null
> > > +++ b/testsuite/tree.tests
> > > @@ -0,0 +1,97 @@
> > > +#!/bin/sh
> > > +
> > > +# Copyright 2022 by Roger Knecht rknecht at pm.me
> > >
> > > +# Licensed under GPLv2, see file LICENSE in this source tree.
> > > +
> > > +. ./testing.sh -v
> > > +
> > > +# testing "description" "command" "result" "infile" "stdin"
> > > +
> > > +testing "tree error opening dir" \
> > > + "tree tree.tempdir" \
> > > + "\
> > > +tree.tempdir [error opening dir]\n\
> > > +\n\
> > > +0 directories, 0 files\n" \
> > > + "" ""
> > > +
> > > +mkdir -p tree2.tempdir
> > > +touch tree2.tempdir/testfile
> > > +
> > > +testing "tree single file" \
> > > + "cd tree2.tempdir && tree" \
> > > + "\
> > > +.\n\
> > > +└── testfile\n\
> > > +\n\
> > > +0 directories, 1 files\n" \
> > > + "" ""
> > > +
> > > +mkdir -p tree3.tempdir/test1 \
> > > + tree3.tempdir/test2/a \
> > > + tree3.tempdir/test2/b \
> > > + tree3.tempdir/test3/c \
> > > + tree3.tempdir/test3/d
> > > +
> > > +touch tree3.tempdir/test2/a/testfile1 \
> > > + tree3.tempdir/test2/a/testfile2 \
> > > + tree3.tempdir/test2/a/testfile3 \
> > > + tree3.tempdir/test2/b/testfile4 \
> > > + tree3.tempdir/test3/c/testfile5 \
> > > + tree3.tempdir/test3/d/testfile6 \
> > > + tree3.tempdir/test3/d/.testfile7
> > > +
> > > +(cd tree3.tempdir/test2/a && ln -s ../b/testfile4 .)
> > > +(cd tree3.tempdir/test2/b && ln -s ../../test3 .)
> > > +
> > > +testing "tree nested directories and files" \
> > > + "cd tree3.tempdir && tree" \
> > > + "\
> > > +.\n\
> > > +├── test1\n\
> > > +├── test2\n\
> > > +│ ├── a\n\
> > > +│ │ ├── testfile1\n\
> > > +│ │ ├── testfile2\n\
> > > +│ │ ├── testfile3\n\
> > > +│ │ └── testfile4 -> ../b/testfile4\n\
> > >
> > > +│ └── b\n\
> > > +│ ├── test3 -> ../../test3\n\
> > >
> > > +│ └── testfile4\n\
> > > +└── test3\n\
> > > + ├── c\n\
> > > + │ └── testfile5\n\
> > > + └── d\n\
> > > + └── testfile6\n\
> > > +\n\
> > > +8 directories, 7 files\n" \
> > > + "" ""
> > > +
> > > +testing "tree multiple directories" \
> > > + "tree tree2.tempdir tree3.tempdir" \
> > > + "\
> > > +tree2.tempdir\n\
> > > +└── testfile\n\
> > > +tree3.tempdir\n\
> > > +├── test1\n\
> > > +├── test2\n\
> > > +│ ├── a\n\
> > > +│ │ ├── testfile1\n\
> > > +│ │ ├── testfile2\n\
> > > +│ │ ├── testfile3\n\
> > > +│ │ └── testfile4 -> ../b/testfile4\n\
> > >
> > > +│ └── b\n\
> > > +│ ├── test3 -> ../../test3\n\
> > >
> > > +│ └── testfile4\n\
> > > +└── test3\n\
> > > + ├── c\n\
> > > + │ └── testfile5\n\
> > > + └── d\n\
> > > + └── testfile6\n\
> > > +\n\
> > > +8 directories, 8 files\n" \
> > > + "" ""
> > > +
> > > +rm -rf tree.tempdir tree2.tempdir tree3.tempdir
> > > +
> > > +exit $FAILCOUNT
> > > --
> > > 2.17.1
>
>
> _______________________________________________
> busybox mailing list
> busybox at busybox.net
> http://lists.busybox.net/mailman/listinfo/busybox
More information about the busybox
mailing list