summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2017-03-16 23:30:21 -0400
committerTavian Barnes <tavianator@tavianator.com>2017-03-16 23:30:21 -0400
commit4da8ba603b588bef38f772c18d883fbf5ddc9e65 (patch)
tree583b6182ebc22baf1c1ce39a4686da0375ff0f04
parentc85f569daf3e0e99c9e8941d0234711afdb58cd7 (diff)
downloadbfs-4da8ba603b588bef38f772c18d883fbf5ddc9e65.tar.xz
Color link targets for -ls
Fixes #18.
-rw-r--r--bftw.c20
-rw-r--r--color.c33
-rw-r--r--color.h1
-rw-r--r--eval.c8
-rw-r--r--util.c15
-rw-r--r--util.h9
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
@@ -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;
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 <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);
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