diff --git a/nnn.c b/nnn.c index 4fe5ebbe..62fb2f3d 100644 --- a/nnn.c +++ b/nnn.c @@ -129,7 +129,7 @@ disabledbg() #define DPRINTF_D(x) xprintf(DEBUG_FD, #x "=%d\n", x) #define DPRINTF_U(x) xprintf(DEBUG_FD, #x "=%u\n", x) #define DPRINTF_S(x) xprintf(DEBUG_FD, #x "=%s\n", x) -#define DPRINTF_P(x) xprintf(DEBUG_FD, #x "=0x%p\n", x) +#define DPRINTF_P(x) xprintf(DEBUG_FD, #x "=%p\n", x) #else #define DPRINTF_D(x) #define DPRINTF_U(x) @@ -140,6 +140,7 @@ disabledbg() /* Macro definitions */ #define VERSION "1.5" #define GENERAL_INFO "License: BSD 2-Clause\nWebpage: https://github.com/jarun/nnn" + #define LEN(x) (sizeof(x) / sizeof(*(x))) #undef MIN #define MIN(x, y) ((x) < (y) ? (x) : (y)) @@ -154,6 +155,8 @@ disabledbg() #define FILTER '/' #define REGEX_MAX 128 #define BM_MAX 10 +#define ENTRY_INCR 64 /* Number of dir 'entry' structures to allocate per shot */ +#define NAMEBUF_INCR 0x1000 /* 64 dir entries at a time, avg. 64 chars per filename = 64*64B = 4KB */ /* Macros to define process spawn behaviour as flags */ #define F_NONE 0x00 /* no flag set */ @@ -192,13 +195,10 @@ typedef struct entry { time_t t; off_t size; blkcnt_t blocks; /* number of 512B blocks allocated */ + size_t noff; mode_t mode; } *pEntry; -typedef struct { - char pname[NAME_MAX + 1]; -} namebuf; - /* Bookmark */ typedef struct { char *key; @@ -225,7 +225,7 @@ typedef struct { static settings cfg = {0, 0, 0, 0, 0, 1, 1, 0, 0, 4}; static struct entry *dents; -static namebuf *pnamebuf; +static char *pnamebuf; static int ndents, cur, total_dents; static uint idle; static uint idletimeout; @@ -1765,12 +1765,14 @@ dentfill(char *path, struct entry **dents, { static DIR *dirp; static struct dirent *dp; - static struct stat sb_path, sb; - static int fd, n, count; - static char *namep; - static ulong num_saved; + static char *namep, *pnb; static struct entry *dentp; - static namebuf *pnb; + static size_t off, namebuflen = NAMEBUF_INCR; + static ulong num_saved; + static int fd, n, count; + static struct stat sb_path, sb; + + off = 0; dirp = opendir(path); if (dirp == NULL) @@ -1836,28 +1838,41 @@ dentfill(char *path, struct entry **dents, } if (n == total_dents) { - total_dents += 64; + total_dents += ENTRY_INCR; *dents = realloc(*dents, total_dents * sizeof(**dents)); - if (*dents == NULL) + if (*dents == NULL) { + if (pnamebuf) + free(pnamebuf); errexit(); + } + } + + /* If there's not enough bytes left to copy a file name of length NAME_MAX, re-allocate */ + if (namebuflen - off < NAME_MAX + 1) { + namebuflen += NAMEBUF_INCR; pnb = pnamebuf; - pnamebuf = (namebuf *)realloc(pnamebuf, total_dents * sizeof(namebuf)); + pnamebuf = (char *)realloc(pnamebuf, namebuflen); + DPRINTF_P(pnamebuf); if (pnamebuf == NULL) { free(*dents); errexit(); } /* realloc() may result in memory move, we must re-adjust if that happens */ - if (pnb && pnb != pnamebuf) + if (pnb != pnamebuf) for (count = 0; count < n; ++count) - (&(*dents)[count])->name = pnamebuf[count].pname; + (*dents + count)->name = pnamebuf + (*dents + count)->noff; } - dentp = &(*dents)[n]; - xstrlcpy(pnamebuf[n].pname, namep, NAME_MAX + 1); - dentp->name = pnamebuf[n].pname; + dentp = *dents + n; + /* Copy file name */ + dentp->name = pnamebuf + off; + dentp->noff = off; + off += xstrlcpy(dentp->name, namep, NAME_MAX + 1); + + /* Copy other fields */ dentp->mode = sb.st_mode; dentp->t = sb.st_mtime; dentp->size = sb.st_size; @@ -1947,10 +1962,20 @@ populate(char *path, char *oldpath, char *fltr) refresh(); } +#ifdef DEBUGMODE + struct timespec ts1, ts2; + clock_gettime(CLOCK_REALTIME, &ts1); /* Use CLOCK_MONOTONIC on FreeBSD */ +#endif + ndents = dentfill(path, &dents, visible, &re); qsort(dents, ndents, sizeof(*dents), entrycmp); +#ifdef DEBUGMODE + clock_gettime(CLOCK_REALTIME, &ts2); + DPRINTF_U(ts2.tv_nsec - ts1.tv_nsec); +#endif + /* Find cur from history */ cur = dentfind(dents, ndents, oldpath); return 0; @@ -2103,6 +2128,11 @@ browse(char *ipath, char *ifilter) else presel = 0; + /* Allocate buffer to hold names */ + pnamebuf = (char *)malloc(NAMEBUF_INCR); + if (pnamebuf == NULL) + errexit(); + begin: #ifdef LINUX_INOTIFY if (dir_changed && inotify_wd >= 0) {