]> Sergey Matveev's repositories - nnn.git/commitdiff
Simplify batch rename
authorArun Prakash Jana <engineerarun@gmail.com>
Wed, 22 May 2019 15:02:29 +0000 (20:32 +0530)
committerArun Prakash Jana <engineerarun@gmail.com>
Wed, 22 May 2019 15:21:53 +0000 (20:51 +0530)
README.md
src/nnn.c

index 34f2570c8bf8e237c586b5394bde0ad97ec426cb..08c163687c95dae550b283dc17a0dd1621c8d469 100644 (file)
--- a/README.md
+++ b/README.md
@@ -105,7 +105,7 @@ It runs on Linux, macOS, Raspberry Pi, BSD, Cygwin, Linux subsystem for Windows
   - FreeDesktop compliant trash (needs trash-cli)
   - Plugin repository
   - SSHFS mounts (needs sshfs)
-  - Batch rename
+  - Batch rename selection or dir entries
   - Show copy, move progress on Linux (needs avdcpmv)
   - Per-context directory color (default: blue)
   - Spawn a shell in the current directory
index 1a106ce7b7ad72b206789b4c23e307f0d5f63446..75201d51699c6809d2d815ad5901028effaa0905 100644 (file)
--- a/src/nnn.c
+++ b/src/nnn.c
@@ -769,12 +769,20 @@ static void appendfpath(const char *path, const size_t len)
 }
 
 /* Write selected file paths to fd, linefeed separated */
-static ssize_t selectiontofd(int fd)
+static ssize_t selectiontofd(int fd, uint *pcount)
 {
-       uint lastpos = copybufpos - 1;
+       uint lastpos, count = 0;
        char *pbuf = pcopybuf;
        ssize_t pos = 0, len, r;
 
+       if (pcount)
+               *pcount = 0;
+
+       if (!copybufpos)
+               return 0;
+
+       lastpos = copybufpos - 1;
+
        while (pos <= lastpos) {
                len = strlen(pbuf);
                pos += len;
@@ -789,8 +797,12 @@ static ssize_t selectiontofd(int fd)
                        pbuf += len + 1;
                }
                ++pos;
+               ++count;
        }
 
+       if (pcount)
+               *pcount = count;
+
        return pos;
 }
 
@@ -808,7 +820,7 @@ static void showcplist(void)
                return;
        }
 
-       pos = selectiontofd(fd);
+       pos = selectiontofd(fd, NULL);
 
        close(fd);
        if (pos && pos == copybufpos)
@@ -1121,78 +1133,79 @@ static void xrm(char *path)
        }
 }
 
-static void rename_selection(const char *path)
+static bool batch_rename(const char *path)
 {
+       int fd1 = -1, fd2 = -1, i;
+       uint count = 0, lines = 0;
+       bool dir = FALSE, ret = FALSE;
        const char renamecmd[] = "paste -d'\n' %s %s | xargs -d'\n' -n2 mv 2>/dev/null";
-       char buf[sizeof(renamecmd) + 2 * PATH_MAX];
        char foriginal[TMP_LEN_MAX] = {0};
-       int fd1 = -1, fd2 = -1, i;
-       ssize_t len, len2;
+       char buf[sizeof(renamecmd) + (PATH_MAX << 1)];
 
        if ((fd1 = create_tmp_file()) == -1)
-               return;
+               return ret;
 
        xstrlcpy(foriginal, g_tmpfpath, strlen(g_tmpfpath)+1);
 
        if ((fd2 = create_tmp_file()) == -1) {
                unlink(foriginal);
                close(fd1);
-               return;
+               return ret;
        }
 
-       if (copybufpos > 0) {
-               // Rename selected files with absolute paths:
-               selectiontofd(fd1);
-               if (write(fd1, "\n", 1) < 1)
-                       goto finished_renaming;
-               selectiontofd(fd2);
-               if (write(fd2, "\n", 1) < 1)
-                       goto finished_renaming;
-       } else {
-               // If nothing is selected, use the directory contents with relative paths:
-               for (i = 0; i < ndents; ++i) {
-                       len = strlen(dents[i].name);
-                       if (write(fd1, dents[i].name, len) != len || write(fd1, "\n", 1) != 1)
-                               goto finished_renaming;
-                       if (write(fd2, dents[i].name, len) != len || write(fd2, "\n", 1) != 1)
-                               goto finished_renaming;
-               }
+       if (!copybufpos) {
+               if (!ndents)
+                       return TRUE;
+
+               for (i = 0; i < ndents; ++i)
+                       appendfpath(dents[i].name, NAME_MAX);
+
+               dir = TRUE;
        }
 
+       selectiontofd(fd1, &count);
+       selectiontofd(fd2, NULL);
        close(fd2);
-       fd2 = -1;
 
-       spawn(editor, g_tmpfpath, NULL, path, F_CLI);
+       if (dir)
+               copybufpos = 0;
 
-       // Check that the number of filenames is unchanged:
-       len = 0, len2 = 0;
-       lseek(fd1, 0, SEEK_SET);
-       while ((i = read(fd1, buf, sizeof(buf))) > 0) {
-               while (i) len += buf[--i] == '\n';
-       }
-       if (i < 0) goto finished_renaming;
+       spawn(editor, g_tmpfpath, NULL, path, F_CLI);
 
        // Reopen file descriptor to get updated contents:
        if ((fd2 = open(g_tmpfpath, O_RDONLY)) == -1)
-               goto finished_renaming;
+               goto finish;
+
        while ((i = read(fd2, buf, sizeof(buf))) > 0) {
-               while (i) len2 += buf[--i] == '\n';
+               while (i)
+                       lines += (buf[--i] == '\n');
        }
-       if (i < 0) goto finished_renaming;
 
-       if (len2 != len) {
-               get_input("Error: wrong number of filenames. Press any key to continue...");
-               goto finished_renaming;
+       if (i < 0)
+               goto finish;
+
+       DPRINTF_U(count);
+       DPRINTF_U(lines);
+
+       if (count != lines) {
+               DPRINTF_S("cannot delete files");
+               goto finish;
        }
 
        snprintf(buf, sizeof(buf), renamecmd, foriginal, g_tmpfpath);
        spawn("sh", "-c", buf, path, F_NORMAL);
+       ret = TRUE;
 
-finished_renaming:
-       if (fd2 >= 0) close(fd1);
+finish:
+       if (fd1 >= 0)
+               close(fd1);
        unlink(foriginal);
-       if (fd2 >= 0) close(fd2);
+
+       if (fd2 >= 0)
+               close(fd2);
        unlink(g_tmpfpath);
+
+       return ret;
 }
 
 static void archive_selection(const char *cmd, const char *archive, const char *curpath)
@@ -3659,12 +3672,12 @@ nochange:
                case SEL_FMEDIA: // fallthrough
                case SEL_ARCHIVELS: // fallthrough
                case SEL_EXTRACT: // fallthrough
-               case SEL_RENAMEALL: // fallthrough
                case SEL_RUNEDIT: // fallthrough
                case SEL_RUNPAGE:
                        if (!ndents)
                                break; // fallthrough
                case SEL_REDRAW: // fallthrough
+               case SEL_RENAMEALL: // fallthrough
                case SEL_HELP: // fallthrough
                case SEL_NOTE: // fallthrough
                case SEL_LOCK:
@@ -3691,7 +3704,10 @@ nochange:
                                        copycurname();
                                goto begin;
                        case SEL_RENAMEALL:
-                               rename_selection(path);
+                               if (!batch_rename(path)) {
+                                       printwait("batch rename failed", &presel);
+                                       goto nochange;
+                               }
                                break;
                        case SEL_HELP:
                                r = show_help(path);
@@ -4635,7 +4651,7 @@ int main(int argc, char *argv[])
 
        if (cfg.pickraw) {
                if (copybufpos) {
-                       opt = selectiontofd(1);
+                       opt = selectiontofd(1, NULL);
                        if (opt != (int)(copybufpos))
                                xerror();
                }