From f0ca1e778544d852ef04cf637d64ea1f94e43ddc Mon Sep 17 00:00:00 2001 From: Arun Prakash Jana Date: Wed, 15 Aug 2018 08:39:31 +0530 Subject: [PATCH] Document that filenames are not unquoted --- README.md | 2 ++ nnn.1 | 3 ++- nnn.c | 26 +++++++++++++++++++++----- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c7fd3e37..4f0f72d9 100644 --- a/README.md +++ b/README.md @@ -389,6 +389,8 @@ To wrap each file path within single quotes, export `NNN_QUOTE_ON`: export NNN_QUOTE_ON=1 This is particularly useful if you are planning to copy the whole string to the shell to run a command. Quotes can be toggled at runtime using ^T. +Note that the filename is not escaped. So copying may still fail for filenames having quote(s) in them. + #### copy file paths when X is missing A very common scenario on headless remote servers connected via SSH. As the clipboard is missing, `nnn` copies the path names to the tmp file `/tmp/nnncp$USER`. diff --git a/nnn.1 b/nnn.1 index f44281f0..e4205934 100644 --- a/nnn.1 +++ b/nnn.1 @@ -263,7 +263,8 @@ screensaver. .Ed .Pp \fBNNN_QUOTE_ON:\fR wrap copied paths within single quotes. Useful for pasting -names in the shell. +names in the shell. Note that the filename is not escaped. So copying may still fail +for filenames having quote(s) in them. .Pp \fBNNN_SCRIPT:\fR path to a custom script to invoke with currently selected file name as argument 1. .Bd -literal diff --git a/nnn.c b/nnn.c index 3e905094..0e5e5ea7 100644 --- a/nnn.c +++ b/nnn.c @@ -1752,6 +1752,19 @@ xgetgrgid(gid_t gid) return grp->gr_name; } +static bool +istgtdir(const char *tgtpath) +{ + if (tgtpath) { + struct stat tgtsb; + int r = stat(tgtpath, &tgtsb); + if ((r == 0) && (tgtsb.st_mode & S_IFMT) == S_IFDIR) + return TRUE; + } + + return FALSE; +} + /* * Follows the stat(1) output closely */ @@ -1772,16 +1785,19 @@ show_stats(char *fpath, char *fname, struct stat *sb) /* Show file name or 'symlink' -> 'target' */ if (perms[0] == 'l') { /* Note that MAX_CMD_LEN > PATH_MAX */ - ssize_t len = readlink(fpath, g_buf, MAX_CMD_LEN); - - if (len != -1) { - g_buf[len] = '\0'; + char *tgt = realpath(fpath, g_buf); + if (tgt) { + char ch[] = {'\'', '\0', '\0'}; + if (istgtdir(g_buf)) { + ch[1] = ch[0]; + ch[0] = '/'; + } /* * We pass g_buf but unescape() operates on g_buf too! * Read the API notes for information on how this works. */ - dprintf(fd, " -> '%s'", unescape(g_buf, 0)); + dprintf(fd, " -> '%s%s", unescape(g_buf, 0), ch); } }