diff options
-rw-r--r-- | bftw.c | 20 | ||||
-rw-r--r-- | color.c | 33 | ||||
-rw-r--r-- | color.h | 1 | ||||
-rw-r--r-- | eval.c | 8 | ||||
-rw-r--r-- | util.c | 15 | ||||
-rw-r--r-- | util.h | 9 |
6 files changed, 60 insertions, 26 deletions
@@ -761,24 +761,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. */ static void bftw_init_buffers(struct bftw_state *state, const struct dirent *de) { @@ -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; @@ -11,6 +11,7 @@ #include "color.h" #include "bftw.h" +#include "util.h" #include <errno.h> #include <stdarg.h> #include <stdbool.h> @@ -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); @@ -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. */ @@ -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; } } @@ -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; +} @@ -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 |