diff options
| author | Tom Smeding <tom@tomsmeding.com> | 2024-09-08 18:25:40 +0200 | 
|---|---|---|
| committer | Tom Smeding <tom@tomsmeding.com> | 2024-09-08 18:26:03 +0200 | 
| commit | 43d5a40971b825cb78ce9ff56211c0c021109d07 (patch) | |
| tree | 9a6e3dcceb41d40f28dd1e7deb42301dd01493e2 | |
| parent | ac5cad753c7dbac31756a2fffd85625b1431eaa5 (diff) | |
boom: unicode takjes
| -rw-r--r-- | src/boom.c | 143 | 
1 files changed, 94 insertions, 49 deletions
| @@ -1,13 +1,11 @@ -#include <assert.h> -#include <ftw.h> +#include <dirent.h> +#include <fcntl.h>  #include <getopt.h>  #include <limits.h> -#include <pwd.h>  #include <stdbool.h>  #include <stdio.h>  #include <stdlib.h>  #include <string.h> -#include <sys/types.h>  #include <unistd.h>  #include "util/versie.h" @@ -23,9 +21,9 @@ static void usage(FILE *f) {        "\n"        "Geef inhoud van mapjes weer in een boom-achtig formaat.\n"        "\n" -      "  -a          Alle bestanden worden weergegeven, ookal beginnen ze met een puntje\n" +      "  -a          Alle bestanden worden weergegeven, ook al beginnen ze met een puntje\n"        "  -m          Geef alleen mapjes weer\n" -      "  -d          Maximale diepte\n" +      "  -d DIEPTE   Maximale diepte\n"        "  -h          Toon deze hulptekst\n"        "  -V          Toon versienummer\n");  } @@ -68,69 +66,116 @@ static char** parse_options(int argc, char **argv) {    return argv + optind;  } -static int prev_level = -1; -static int skip_level = -1; +static int scandir_filterfunc(const struct dirent *ent) { +  if (dirs_only && ent->d_type != DT_DIR) return 0; +  if (!show_hidden && ent->d_name[0] == '.') return 0; +  return 1; +} + +static const char *branches[] = { +  "├── ", +  "└── ", +  "│   ", +  "    " +}; + +// Contains indices into 'branches' +static int8_t prefix[PATH_MAX / 2 + 1]; + +// Buffer to store the target of a symlink in +static char linknamebuf[PATH_MAX]; -static int f(const char *fpath, const struct stat *, int typeflag, struct FTW *ftwbuf) { -  int level = ftwbuf->level; -  bool is_dir -     = typeflag == FTW_D -    || typeflag == FTW_DNR -    || typeflag == FTW_DP; +static size_t total_dirs = 0; +static size_t total_files = 0; -  if (level < skip_level) { -    skip_level = -1; -  } else if (skip_level != -1 && level >= skip_level) { -    return 0; +static bool encountered_error = false; + +static void print_prefix(int depth) { +  for (int i = 0; i < depth; i++) { +    printf("%s", branches[prefix[i]]);    } +} -  // check max depth -  if (max_depth >= 0 && level >= (max_depth + 1)) return 0; +// Pass -1 as parentdirfd if dirname is to be resolved relative to $PWD or is absolute. +static void boom(int parentdirfd, const char *dirname, unsigned depth) { +  total_dirs++; -  const char *fname = basename(fpath); +  if (depth > (unsigned)max_depth) return; -  // don't show hidden files -  if (!show_hidden && fname[0] == '.' && strlen(fpath) > 2 && level != 0) { -    skip_level = level + 1; -    goto done; +  struct dirent **list; +  const int nitems = +    parentdirfd == -1 +      ? scandir(dirname, &list, scandir_filterfunc, alphasort) +      : scandirat(parentdirfd, dirname, &list, scandir_filterfunc, alphasort); + +  if (nitems == -1) { +    printf("%s  [kon mapje niet openen]\n", dirname); +    total_dirs--;  // not a directory after all +    encountered_error = true; +    return;    } -  // don't show files in dirs only mode -  if (dirs_only && !is_dir) return 0; -  for (int i = 1; i < level; i++) { -    printf("|   "); +  const int dirfd = parentdirfd == -1 +                      ? open(dirname, O_DIRECTORY) +                      : openat(parentdirfd, dirname, O_DIRECTORY); + +  if (dirfd == -1) { +    printf("%s  [kon mapje niet open(2)en]\n", dirname); +    total_dirs--;  // not a directory after all +    encountered_error = true; +    return;    } -  if (level != 0) { -    printf("|-- "); +  if (parentdirfd == -1) { +    printf("%s\n", dirname);    } -  printf("%s", fname); -  if (typeflag == FTW_SL) { -    char real_name[PATH_MAX] = {0}; -    if (readlink(fpath, real_name, PATH_MAX-1) != -1) -      printf(" -> %s", real_name); + +  for (int i = 0; i < nitems; i++) { +    if (i < nitems - 1) prefix[depth-1] = 0; +    else prefix[depth-1] = 1; + +    print_prefix(depth); +    if (list[i]->d_type == DT_LNK) { +      ssize_t len = parentdirfd == -1 +                      ? readlink(list[i]->d_name, linknamebuf, PATH_MAX - 1) +                      : readlinkat(dirfd, list[i]->d_name, linknamebuf, PATH_MAX - 1); +      if (len == -1) { +        printf("%s -> [kon niet leeslinken]\n", list[i]->d_name); +      } else { +        linknamebuf[len] = '\0'; +        printf("%s -> %s\n", list[i]->d_name, linknamebuf); +      } +    } else printf("%s\n", list[i]->d_name); + +    if (list[i]->d_type == DT_DIR) { +      if (i < nitems - 1) prefix[depth-1] = 2; +      else prefix[depth-1] = 3; +      boom(dirfd, list[i]->d_name, depth + 1); +    } else { +      total_files++; +    } + +    free(list[i]);    } -  printf("\n"); -done: -  prev_level = level; -  return 0; +  close(dirfd); + +  free(list);  }  int entry_boom(int argc, char **argv) {    char **args = parse_options(argc, argv); -  int flags = 0; -  flags |= FTW_PHYS; -    if (*args == NULL) { -    nftw(".", f, 4096, flags); -    return 0; +    boom(-1, ".", 1); +  } else for (int i = 0; args[i]; i++) { +    boom(-1, args[i], 1);    } -  for (int i = 0; args[i]; i++) { -    nftw(args[i], f, 4096, flags); -  } +  putchar('\n'); +  printf("%zu map%s", total_dirs, total_dirs == 1 ? "" : "jes"); +  if (!dirs_only) printf(", %zu bestand%s", total_files, total_files == 1 ? "" : "en"); +  putchar('\n'); -  return 0; +  return encountered_error;  } | 
