From 4da8ba603b588bef38f772c18d883fbf5ddc9e65 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 16 Mar 2017 23:30:21 -0400 Subject: Color link targets for -ls Fixes #18. --- bftw.c | 20 +------------------- color.c | 33 +++++++++++++++++++++++++++++++++ color.h | 1 + eval.c | 8 +------- util.c | 15 +++++++++++++++ util.h | 9 +++++++++ 6 files changed, 60 insertions(+), 26 deletions(-) diff --git a/bftw.c b/bftw.c index a3f3345..6d0c849 100644 --- a/bftw.c +++ b/bftw.c @@ -760,24 +760,6 @@ static void bftw_set_error(struct bftw_state *state, int error) { } } -/** - * Figure out the name offset in a path. - */ -static size_t basename_offset(const char *path) { - size_t i; - - // Strip trailing slashes - for (i = strlen(path); i > 0 && path[i - 1] == '/'; --i); - - // Find the beginning of the name - for (; i > 0 && path[i - 1] != '/'; --i); - - // Strip leading slashes - for (; path[i] == '/' && path[i + 1]; ++i); - - return i; -} - /** * Initialize the buffers with data about the current path. */ @@ -811,7 +793,7 @@ static void bftw_init_buffers(struct bftw_state *state, const struct dirent *de) if (ftwbuf->depth == 0) { // Compute the name offset for root paths like "foo/bar" - ftwbuf->nameoff = basename_offset(ftwbuf->path); + ftwbuf->nameoff = xbasename(ftwbuf->path) - ftwbuf->path; } ftwbuf->typeflag = BFTW_UNKNOWN; diff --git a/color.c b/color.c index 18a975f..640cd7e 100644 --- a/color.c +++ b/color.c @@ -11,6 +11,7 @@ #include "color.h" #include "bftw.h" +#include "util.h" #include #include #include @@ -413,6 +414,32 @@ static int print_path(CFILE *cfile, const struct BFTW *ftwbuf) { return 0; } +static int print_link(CFILE *cfile, const struct BFTW *ftwbuf) { + int ret = -1; + + char *target = xreadlinkat(ftwbuf->at_fd, ftwbuf->at_path, 0); + if (!target) { + goto done; + } + + struct BFTW altbuf = *ftwbuf; + altbuf.path = target; + altbuf.nameoff = xbasename(target) - target; + + struct stat statbuf; + if (fstatat(ftwbuf->at_fd, ftwbuf->at_path, &statbuf, 0) == 0) { + altbuf.statbuf = &statbuf; + } else { + altbuf.statbuf = NULL; + } + + ret = print_path(cfile, &altbuf); + +done: + free(target); + return ret; +} + int cfprintf(CFILE *cfile, const char *format, ...) { const struct colors *colors = cfile->colors; FILE *file = cfile->file; @@ -449,6 +476,12 @@ int cfprintf(CFILE *cfile, const char *format, ...) { } break; + case 'L': + if (print_link(cfile, va_arg(args, const struct BFTW *)) != 0) { + goto done; + } + break; + case '{': memcpy(name, i + 1, 2); esc = get_color(colors, name); diff --git a/color.h b/color.h index 6ba6fb0..ac5cb7b 100644 --- a/color.h +++ b/color.h @@ -93,6 +93,7 @@ int cfclose(CFILE *cfile); * %c: A single character * %s: A string * %P: A colored file path, from a const struct BFTW * argument + * %L: A colored link target, from a const struct BFTW * argument * %{cc}: Change the color to 'cc' * @return 0 on success, -1 on failure. */ diff --git a/eval.c b/eval.c index 1a8bc02..ded73cb 100644 --- a/eval.c +++ b/eval.c @@ -760,13 +760,7 @@ bool eval_fls(const struct expr *expr, struct eval_state *state) { } if (ftwbuf->typeflag == BFTW_LNK) { - char *target = xreadlinkat(ftwbuf->at_fd, ftwbuf->at_path, statbuf->st_size); - if (!target) { - goto error; - } - int ret = fprintf(file, " -> %s", target); - free(target); - if (ret < 0) { + if (cfprintf(cfile, " -> %L", ftwbuf) < 0) { goto error; } } diff --git a/util.c b/util.c index 98db1d7..55cf2a4 100644 --- a/util.c +++ b/util.c @@ -202,3 +202,18 @@ void format_mode(mode_t mode, char str[11]) { str[9] = 'x'; } } + +const char *xbasename(const char *path) { + const char *i; + + // Skip trailing slashes + for (i = path + strlen(path); i > path && i[-1] == '/'; --i); + + // Find the beginning of the name + for (; i > path && i[-1] != '/'; --i); + + // Skip leading slashes + for (; i[0] == '/' && i[1]; ++i); + + return i; +} diff --git a/util.h b/util.h index 553f37d..971860b 100644 --- a/util.h +++ b/util.h @@ -123,4 +123,13 @@ int xlocaltime(const time_t *timep, struct tm *result); */ void format_mode(mode_t mode, char str[11]); +/** + * basename() variant that doesn't modify the input. + * + * @param path + * The path in question. + * @return A pointer into path at the base name offset. + */ +const char *xbasename(const char *path); + #endif // BFS_UTIL_H -- cgit v1.2.3