aboutsummaryrefslogtreecommitdiffstats
path: root/nnn.c
diff options
context:
space:
mode:
Diffstat (limited to 'nnn.c')
-rw-r--r--nnn.c213
1 files changed, 179 insertions, 34 deletions
diff --git a/nnn.c b/nnn.c
index 46d89dd..d6a1927 100644
--- a/nnn.c
+++ b/nnn.c
@@ -169,6 +169,12 @@ disabledbg()
#define F_SIGINT 0x08 /* restore default SIGINT handler */
#define F_NORMAL 0x80 /* spawn child process in non-curses regular CLI mode */
+/* CRC8 macros */
+#define WIDTH (8 * sizeof(unsigned char))
+#define TOPBIT (1 << (WIDTH - 1))
+#define POLYNOMIAL 0xD8 /* 11011 followed by 0's */
+
+/* Function macros */
#define exitcurses() endwin()
#define clearprompt() printmsg("")
#define printwarn() printmsg(strerror(errno))
@@ -217,6 +223,7 @@ typedef struct {
ushort sizeorder : 1; /* Set to sort by file size */
ushort blkorder : 1; /* Set to sort by blocks used (disk usage) */
ushort showhidden : 1; /* Set to show hidden files */
+ ushort copymode : 1; /* Set when copying files */
ushort showdetail : 1; /* Clear to show fewer file info */
ushort showcolor : 1; /* Set to show dirs in blue */
ushort dircolor : 1; /* Current status of dir color */
@@ -227,13 +234,13 @@ typedef struct {
/* GLOBALS */
/* Configuration */
-static settings cfg = {0, 0, 0, 0, 0, 1, 1, 0, 0, 4};
+static settings cfg = {0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 4};
static struct entry *dents;
-static char *pnamebuf;
+static char *pnamebuf, *pcopybuf;
static int ndents, cur, total_dents = ENTRY_INCR;
static uint idle;
-static uint idletimeout;
+static uint idletimeout, copybufpos, copybuflen;
static char *player;
static char *copier;
static char *editor;
@@ -245,6 +252,9 @@ static ulong num_files;
static uint open_max;
static bm bookmark[BM_MAX];
+static uchar crc8table[256];
+static uchar g_crc;
+
#ifdef LINUX_INOTIFY
static int inotify_fd, inotify_wd = -1;
static uint INOTIFY_MASK = IN_ATTRIB | IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF | IN_MOVED_FROM | IN_MOVED_TO;
@@ -274,6 +284,7 @@ static const char *STR_ATROOT = "You are at /";
static const char *STR_NOHOME = "HOME not set";
static const char *STR_INPUT = "No traversal delimiter allowed";
static const char *STR_INVBM = "Invalid bookmark";
+static const char *STR_COPY = "NNN_COPIER is not set";
static const char *STR_DATE = "%a %d %b %Y %T %z";
/* For use in functions which are isolated and don't return the buffer */
@@ -284,6 +295,57 @@ static void redraw(char *path);
/* Functions */
+/*
+ * CRC8 source:
+ * https://barrgroup.com/Embedded-Systems/How-To/CRC-Calculation-C-Code
+ */
+static void
+crc8init()
+{
+ uchar remainder, bit;
+ uint dividend;
+
+ /* Compute the remainder of each possible dividend */
+ for (dividend = 0; dividend < 256; ++dividend)
+ {
+ /* Start with the dividend followed by zeros */
+ remainder = dividend << (WIDTH - 8);
+
+ /* Perform modulo-2 division, a bit at a time */
+ for (bit = 8; bit > 0; --bit)
+ {
+ /* Try to divide the current data bit */
+ if (remainder & TOPBIT)
+ remainder = (remainder << 1) ^ POLYNOMIAL;
+ else
+ remainder = (remainder << 1);
+ }
+
+ /* Store the result into the table */
+ crc8table[dividend] = remainder;
+ }
+}
+
+static uchar
+crc8fast(uchar const message[], size_t n)
+{
+ uchar data;
+ uchar remainder = 0;
+ size_t byte;
+
+
+ /* Divide the message by the polynomial, a byte at a time */
+ for (byte = 0; byte < n; ++byte)
+ {
+ data = message[byte] ^ (remainder >> (WIDTH - 8));
+ remainder = crc8table[data] ^ (remainder << 8);
+ }
+
+ /* The final remainder is the CRC */
+ return (remainder);
+
+}
+
/* Messages show up at the bottom */
static void
printmsg(const char *msg)
@@ -335,6 +397,26 @@ max_openfds()
}
/*
+ * Wrapper to realloc()
+ * Frees current memory if realloc() fails and returns NULL.
+ *
+ * As per the docs, the *alloc() family is supposed to be memory aligned:
+ * Ubuntu: http://manpages.ubuntu.com/manpages/xenial/man3/malloc.3.html
+ * OS X: https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man3/malloc.3.html
+ */
+static void *
+xrealloc(void *pcur, size_t len)
+{
+ static void *pmem;
+
+ pmem = realloc(pcur, len);
+ if (!pmem && pcur)
+ free(pcur);
+
+ return pmem;
+}
+
+/*
* Custom xstrlen()
*/
static size_t
@@ -523,6 +605,25 @@ xbasename(char *path)
return base ? base + 1 : path;
}
+static bool
+appendfilepath(const char *path, const size_t len)
+{
+ if ((copybufpos >= copybuflen) || (len > (copybuflen - (copybufpos + 1)))) {
+ copybuflen += PATH_MAX;
+ pcopybuf = xrealloc(pcopybuf, copybuflen);
+ if (!pcopybuf) {
+ printmsg("No memory!\n");
+ return FALSE;
+ }
+ }
+
+ if (copybufpos)
+ pcopybuf[copybufpos - 1] = '\n';
+
+ copybufpos += xstrlcpy(pcopybuf + copybufpos, path, len);
+ return TRUE;
+}
+
/*
* Return number of dots if all chars in a string are dots, else 0
*/
@@ -1128,22 +1229,24 @@ readinput(void)
}
/*
- * Returns "dir/name or "/name"
+ * Updates out with "dir/name or "/name"
+ * Returns the number of bytes in out including the terminating NULL byte
*/
-static char *
+size_t
mkpath(char *dir, char *name, char *out, size_t n)
{
/* Handle absolute path */
if (name[0] == '/')
- xstrlcpy(out, name, n);
+ return xstrlcpy(out, name, n);
else {
/* Handle root case */
if (istopdir(dir))
- snprintf(out, n, "/%s", name);
+ return (snprintf(out, n, "/%s", name) + 1);
else
- snprintf(out, n, "%s/%s", dir, name);
+ return (snprintf(out, n, "%s/%s", dir, name) + 1);
}
- return out;
+
+ return 0;
}
static void
@@ -1726,6 +1829,7 @@ show_help(char *path)
"eF | List archive\n"
"d^F | Extract archive\n"
"d^K | Invoke file path copier\n"
+ "d^Y | Toggle multi-copy mode\n"
"d^L | Redraw, clear prompt\n"
"e? | Help, settings\n"
"eQ | Quit and cd\n"
@@ -1796,26 +1900,6 @@ sum_bsizes(const char *fpath, const struct stat *sb,
return 0;
}
-/*
- * Wrapper to realloc()
- * Frees current memory if realloc() fails and returns NULL.
- *
- * As per the docs, the *alloc() family is supposed to be memory aligned:
- * Ubuntu: http://manpages.ubuntu.com/manpages/xenial/man3/malloc.3.html
- * OS X: https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man3/malloc.3.html
- */
-static void *
-xrealloc(void *pcur, size_t len)
-{
- static void *pmem;
-
- pmem = realloc(pcur, len);
- if (!pmem && pcur)
- free(pcur);
-
- return pmem;
-}
-
static int
dentfill(char *path, struct entry **dents,
int (*filter)(regex_t *, char *), regex_t *re)
@@ -2057,6 +2141,11 @@ redraw(char *path)
/* Clean screen */
erase();
+ if (cfg.copymode)
+ if (g_crc != crc8fast((uchar *)dents, ndents * sizeof(struct entry))) {
+ cfg.copymode = 0;
+ DPRINTF_S("copymode off");
+ }
/* Fail redraw if < than 10 columns */
if (COLS < 10) {
@@ -2170,7 +2259,7 @@ browse(char *ipath, char *ifilter)
static char oldname[NAME_MAX + 1] __attribute__ ((aligned));
char *dir, *tmp, *run = NULL, *env = NULL;
struct stat sb;
- int r, fd, presel;
+ int r, fd, presel, copystartid = 0, copyendid = 0;
enum action sel = SEL_RUNARG + 1;
bool dir_changed = FALSE;
@@ -2683,6 +2772,7 @@ nochange:
cfg.sizeorder ^= 1;
cfg.mtimeorder = 0;
cfg.blkorder = 0;
+ cfg.copymode = 0;
/* Save current */
if (ndents > 0)
copycurname();
@@ -2695,6 +2785,7 @@ nochange:
}
cfg.mtimeorder = 0;
cfg.sizeorder = 0;
+ cfg.copymode = 0;
/* Save current */
if (ndents > 0)
copycurname();
@@ -2703,6 +2794,7 @@ nochange:
cfg.mtimeorder ^= 1;
cfg.sizeorder = 0;
cfg.blkorder = 0;
+ cfg.copymode = 0;
/* Save current */
if (ndents > 0)
copycurname();
@@ -2714,14 +2806,65 @@ nochange:
goto begin;
case SEL_COPY:
if (copier && ndents) {
- mkpath(path, dents[cur].name, newpath, PATH_MAX);
- spawn(copier, newpath, NULL, NULL, F_NONE);
+ r = mkpath(path, dents[cur].name, newpath, PATH_MAX);
+ if (cfg.copymode) {
+ if (!appendfilepath(newpath, r))
+ goto nochange;
+ } else
+ spawn(copier, newpath, NULL, NULL, F_NONE);
printmsg(newpath);
} else if (!copier)
- printmsg("NNN_COPIER is not set");
+ printmsg(STR_COPY);
+ goto nochange;
+ case SEL_COPYMUL:
+ if (!copier) {
+ printmsg(STR_COPY);
+ goto nochange;
+ } else if (!ndents) {
+ goto nochange;
+ }
+
+ cfg.copymode ^= 1;
+ if (cfg.copymode) {
+ g_crc = crc8fast((uchar *)dents, ndents * sizeof(struct entry));
+ copystartid = cur;
+ copybufpos = 0;
+ DPRINTF_S("copymode on");
+ } else {
+ static size_t len;
+ len = 0;
+
+ /* Handle range selection */
+ if (copybufpos == 0) {
+
+ if (cur < copystartid) {
+ copyendid = copystartid;
+ copystartid = cur;
+ } else
+ copyendid = cur;
+
+ if (copystartid < copyendid) {
+ for (r = copystartid; r <= copyendid; ++r) {
+ len = mkpath(path, dents[r].name, newpath, PATH_MAX);
+ if (!appendfilepath(newpath, len))
+ goto nochange;;
+ }
+
+ sprintf(newpath, "%d files copied", copyendid - copystartid + 1);
+ printmsg(newpath);
+ }
+ }
+
+ if (copybufpos) {
+ spawn(copier, pcopybuf, NULL, NULL, F_NONE);
+ DPRINTF_S(pcopybuf);
+ if (!len)
+ printmsg("files copied");
+ }
+ }
goto nochange;
case SEL_OPEN:
- printprompt("open with: "); // fallthrough
+ printprompt("open with: "); // fallthrough
case SEL_NEW:
if (sel == SEL_NEW)
printprompt("name: ");
@@ -3034,6 +3177,8 @@ main(int argc, char *argv[])
/* Set locale */
setlocale(LC_ALL, "");
+ crc8init();
+
#ifdef DEBUGMODE
enabledbg();
#endif