summaryrefslogtreecommitdiffstats
path: root/color.c
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2019-08-23 23:20:13 -0400
committerTavian Barnes <tavianator@tavianator.com>2019-08-23 23:22:26 -0400
commit7c474d7e7582d852b20db2d4f868749efc9b62be (patch)
treec30ddc312a1d11461bf04b6ddbe4d02349c0946f /color.c
parent9086b192fb4eaa10bae1bc1a19b8a4559c7f65fa (diff)
downloadbfs-7c474d7e7582d852b20db2d4f868749efc9b62be.tar.xz
color: Color leading directories as errors if they don't exist
Fixes #51.
Diffstat (limited to 'color.c')
-rw-r--r--color.c79
1 files changed, 74 insertions, 5 deletions
diff --git a/color.c b/color.c
index c397050..9c3c200 100644
--- a/color.c
+++ b/color.c
@@ -714,6 +714,79 @@ static int print_colored(const struct colors *colors, const char *esc, const cha
return 0;
}
+/** Find the offset of the first broken path component. */
+static ssize_t first_broken_offset(const char *path, const struct BFTW *ftwbuf, enum bfs_stat_flag flags, size_t max) {
+ if (bftw_typeflag(ftwbuf, flags) != BFTW_ERROR) {
+ return max;
+ }
+
+ int at_fd;
+ if (path != ftwbuf->path) {
+ // We're in print_link_target(), so resolve relative to the parent directory
+ at_fd = ftwbuf->at_fd;
+ } else if (ftwbuf->depth == 0) {
+ at_fd = AT_FDCWD;
+ } else {
+ // The parent must have existed to get here
+ return max;
+ }
+
+ char *copy = dstralloc(max);
+ if (!copy) {
+ return 0;
+ }
+
+ size_t i = 0;
+ while (i < max) {
+ size_t j = i;
+ while (path[j] != '/') {
+ ++j;
+ }
+ while (path[j] == '/') {
+ ++j;
+ }
+
+ if (dstrncat(&copy, path + i, j - i) != 0) {
+ break;
+ }
+
+ if (xfaccessat(at_fd, copy, F_OK) != 0) {
+ break;
+ }
+
+ i = j;
+ }
+
+ dstrfree(copy);
+ return i;
+}
+
+/** Print the directories leading up to a file. */
+static int print_dirs_colored(CFILE *cfile, const char *path, const struct BFTW *ftwbuf, enum bfs_stat_flag flags, size_t nameoff) {
+ const struct colors *colors = cfile->colors;
+ FILE *file = cfile->file;
+
+ size_t broken = first_broken_offset(path, ftwbuf, flags, nameoff);
+
+ if (broken > 0) {
+ if (print_colored(colors, colors->directory, path, broken, file) != 0) {
+ return -1;
+ }
+ }
+
+ if (broken < nameoff) {
+ const char *color = colors->missing;
+ if (!color) {
+ color = colors->orphan;
+ }
+ if (print_colored(colors, color, path + broken, nameoff - broken, file) != 0) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
/** Print a path with colors. */
static int print_path_colored(CFILE *cfile, const char *path, const struct BFTW *ftwbuf, enum bfs_stat_flag flags) {
const struct colors *colors = cfile->colors;
@@ -726,11 +799,7 @@ static int print_path_colored(CFILE *cfile, const char *path, const struct BFTW
nameoff = xbasename(path) - path;
}
- if (nameoff > 0) {
- if (print_colored(colors, colors->directory, path, nameoff, file) != 0) {
- return -1;
- }
- }
+ print_dirs_colored(cfile, path, ftwbuf, flags, nameoff);
const char *filename = path + nameoff;
const char *color = file_color(colors, filename, ftwbuf, flags);