mirror of
https://github.com/jarun/nnn.git
synced 2024-11-24 11:51:27 +00:00
Utility functions to top, API to get file extn
This commit is contained in:
parent
a1b43ae830
commit
f712441eda
380
src/nnn.c
380
src/nnn.c
|
@ -732,15 +732,10 @@ static haiku_nm_h haiku_hnd;
|
||||||
#endif /* __GNUC__ */
|
#endif /* __GNUC__ */
|
||||||
|
|
||||||
/* Forward declarations */
|
/* Forward declarations */
|
||||||
static size_t xstrsncpy(char *restrict dst, const char *restrict src, size_t n);
|
|
||||||
static void redraw(char *path);
|
static void redraw(char *path);
|
||||||
static int spawn(char *file, char *arg1, char *arg2, uchar flag);
|
static int spawn(char *file, char *arg1, char *arg2, uchar flag);
|
||||||
static int (*nftw_fn)(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf);
|
static int (*nftw_fn)(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf);
|
||||||
static int dentfind(const char *fname, int n);
|
|
||||||
static void move_cursor(int target, int ignore_scrolloff);
|
static void move_cursor(int target, int ignore_scrolloff);
|
||||||
static inline bool getutil(char *util);
|
|
||||||
static size_t mkpath(const char *dir, const char *name, char *out);
|
|
||||||
static bool plugscript(const char *plugin, uchar flags);
|
|
||||||
static char *load_input(int fd, const char *path);
|
static char *load_input(int fd, const char *path);
|
||||||
static int set_sort_flags(int r);
|
static int set_sort_flags(int r);
|
||||||
|
|
||||||
|
@ -824,128 +819,6 @@ static bool test_clear_bit(uint nr)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void clearinfoln(void)
|
|
||||||
{
|
|
||||||
move(xlines - 2, 0);
|
|
||||||
clrtoeol();
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef KEY_RESIZE
|
|
||||||
/* Clear the old prompt */
|
|
||||||
static void clearoldprompt(void)
|
|
||||||
{
|
|
||||||
clearinfoln();
|
|
||||||
tolastln();
|
|
||||||
addch('\n');
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Messages show up at the bottom */
|
|
||||||
static inline void printmsg_nc(const char *msg)
|
|
||||||
{
|
|
||||||
tolastln();
|
|
||||||
addstr(msg);
|
|
||||||
addch('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
static void printmsg(const char *msg)
|
|
||||||
{
|
|
||||||
attron(COLOR_PAIR(cfg.curctx + 1));
|
|
||||||
printmsg_nc(msg);
|
|
||||||
attroff(COLOR_PAIR(cfg.curctx + 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void printwait(const char *msg, int *presel)
|
|
||||||
{
|
|
||||||
printmsg(msg);
|
|
||||||
if (presel) {
|
|
||||||
*presel = MSGWAIT;
|
|
||||||
if (ndents)
|
|
||||||
xstrsncpy(g_ctx[cfg.curctx].c_name, pdents[cur].name, NAME_MAX + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Kill curses and display error before exiting */
|
|
||||||
static void printerr(int linenum)
|
|
||||||
{
|
|
||||||
exitcurses();
|
|
||||||
perror(xitoa(linenum));
|
|
||||||
if (!g_state.picker && selpath)
|
|
||||||
unlink(selpath);
|
|
||||||
free(pselbuf);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool xconfirm(int c)
|
|
||||||
{
|
|
||||||
return (c == 'y' || c == 'Y');
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_input(const char *prompt)
|
|
||||||
{
|
|
||||||
if (prompt)
|
|
||||||
printmsg(prompt);
|
|
||||||
cleartimeout();
|
|
||||||
|
|
||||||
int r = getch();
|
|
||||||
|
|
||||||
#ifdef KEY_RESIZE
|
|
||||||
while (r == KEY_RESIZE) {
|
|
||||||
if (prompt) {
|
|
||||||
clearoldprompt();
|
|
||||||
xlines = LINES;
|
|
||||||
printmsg(prompt);
|
|
||||||
}
|
|
||||||
|
|
||||||
r = getch();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
settimeout();
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_cur_or_sel(void)
|
|
||||||
{
|
|
||||||
if (selbufpos && ndents) {
|
|
||||||
if (cfg.prefersel)
|
|
||||||
return 's';
|
|
||||||
|
|
||||||
int choice = get_input(messages[MSG_CUR_SEL_OPTS]);
|
|
||||||
|
|
||||||
return ((choice == 'c' || choice == 's') ? choice : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selbufpos)
|
|
||||||
return 's';
|
|
||||||
|
|
||||||
if (ndents)
|
|
||||||
return 'c';
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void xdelay(useconds_t delay)
|
|
||||||
{
|
|
||||||
refresh();
|
|
||||||
usleep(delay);
|
|
||||||
}
|
|
||||||
|
|
||||||
static char confirm_force(bool selection)
|
|
||||||
{
|
|
||||||
char str[64];
|
|
||||||
|
|
||||||
snprintf(str, 64, messages[MSG_FORCE_RM],
|
|
||||||
(selection ? xitoa(nselected) : "current"), (selection ? "(s)" : ""));
|
|
||||||
|
|
||||||
int r = get_input(str);
|
|
||||||
|
|
||||||
if (r == 27)
|
|
||||||
return '\0'; /* cancel */
|
|
||||||
if (r == 'y' || r == 'Y')
|
|
||||||
return 'f'; /* forceful */
|
|
||||||
return 'i'; /* interactive */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Increase the limit on open file descriptors, if possible */
|
/* Increase the limit on open file descriptors, if possible */
|
||||||
static rlim_t max_openfds(void)
|
static rlim_t max_openfds(void)
|
||||||
{
|
{
|
||||||
|
@ -1071,6 +944,58 @@ static void *xmemrchr(uchar *restrict s, uchar ch, size_t n)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* A very simplified implementation, changes path */
|
||||||
|
static char *xdirname(char *path)
|
||||||
|
{
|
||||||
|
char *base = xmemrchr((uchar *)path, '/', xstrlen(path));
|
||||||
|
|
||||||
|
if (base == path)
|
||||||
|
path[1] = '\0';
|
||||||
|
else
|
||||||
|
*base = '\0';
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *xbasename(char *path)
|
||||||
|
{
|
||||||
|
char *base = xmemrchr((uchar *)path, '/', xstrlen(path)); // NOLINT
|
||||||
|
|
||||||
|
return base ? base + 1 : path;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *xextension(const char *fname, size_t len)
|
||||||
|
{
|
||||||
|
return xmemrchr((uchar *)fname, '.', len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool getutil(char *util)
|
||||||
|
{
|
||||||
|
return spawn("which", util, NULL, F_NORMAL | F_NOTRACE) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Updates out with "dir/name or "/name"
|
||||||
|
* Returns the number of bytes copied including the terminating NULL byte
|
||||||
|
*/
|
||||||
|
static size_t mkpath(const char *dir, const char *name, char *out)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
/* Handle absolute path */
|
||||||
|
if (name[0] == '/') // NOLINT
|
||||||
|
return xstrsncpy(out, name, PATH_MAX);
|
||||||
|
|
||||||
|
/* Handle root case */
|
||||||
|
if (istopdir(dir))
|
||||||
|
len = 1;
|
||||||
|
else
|
||||||
|
len = xstrsncpy(out, dir, PATH_MAX);
|
||||||
|
|
||||||
|
out[len - 1] = '/'; // NOLINT
|
||||||
|
return (xstrsncpy(out + len, name, PATH_MAX - len) + len);
|
||||||
|
}
|
||||||
|
|
||||||
/* Assumes both the paths passed are directories */
|
/* Assumes both the paths passed are directories */
|
||||||
static char *common_prefix(const char *path, char *prefix)
|
static char *common_prefix(const char *path, char *prefix)
|
||||||
{
|
{
|
||||||
|
@ -1174,26 +1099,6 @@ static char *abspath(const char *path, const char *cwd)
|
||||||
return resolved_path;
|
return resolved_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A very simplified implementation, changes path */
|
|
||||||
static char *xdirname(char *path)
|
|
||||||
{
|
|
||||||
char *base = xmemrchr((uchar *)path, '/', xstrlen(path));
|
|
||||||
|
|
||||||
if (base == path)
|
|
||||||
path[1] = '\0';
|
|
||||||
else
|
|
||||||
*base = '\0';
|
|
||||||
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *xbasename(char *path)
|
|
||||||
{
|
|
||||||
char *base = xmemrchr((uchar *)path, '/', xstrlen(path)); // NOLINT
|
|
||||||
|
|
||||||
return base ? base + 1 : path;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int create_tmp_file(void)
|
static int create_tmp_file(void)
|
||||||
{
|
{
|
||||||
xstrsncpy(g_tmpfpath + tmpfplen - 1, messages[STR_TMPFILE], TMP_LEN_MAX - tmpfplen);
|
xstrsncpy(g_tmpfpath + tmpfplen - 1, messages[STR_TMPFILE], TMP_LEN_MAX - tmpfplen);
|
||||||
|
@ -1207,6 +1112,128 @@ static int create_tmp_file(void)
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void clearinfoln(void)
|
||||||
|
{
|
||||||
|
move(xlines - 2, 0);
|
||||||
|
clrtoeol();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef KEY_RESIZE
|
||||||
|
/* Clear the old prompt */
|
||||||
|
static void clearoldprompt(void)
|
||||||
|
{
|
||||||
|
clearinfoln();
|
||||||
|
tolastln();
|
||||||
|
addch('\n');
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Messages show up at the bottom */
|
||||||
|
static inline void printmsg_nc(const char *msg)
|
||||||
|
{
|
||||||
|
tolastln();
|
||||||
|
addstr(msg);
|
||||||
|
addch('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printmsg(const char *msg)
|
||||||
|
{
|
||||||
|
attron(COLOR_PAIR(cfg.curctx + 1));
|
||||||
|
printmsg_nc(msg);
|
||||||
|
attroff(COLOR_PAIR(cfg.curctx + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printwait(const char *msg, int *presel)
|
||||||
|
{
|
||||||
|
printmsg(msg);
|
||||||
|
if (presel) {
|
||||||
|
*presel = MSGWAIT;
|
||||||
|
if (ndents)
|
||||||
|
xstrsncpy(g_ctx[cfg.curctx].c_name, pdents[cur].name, NAME_MAX + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Kill curses and display error before exiting */
|
||||||
|
static void printerr(int linenum)
|
||||||
|
{
|
||||||
|
exitcurses();
|
||||||
|
perror(xitoa(linenum));
|
||||||
|
if (!g_state.picker && selpath)
|
||||||
|
unlink(selpath);
|
||||||
|
free(pselbuf);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool xconfirm(int c)
|
||||||
|
{
|
||||||
|
return (c == 'y' || c == 'Y');
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_input(const char *prompt)
|
||||||
|
{
|
||||||
|
if (prompt)
|
||||||
|
printmsg(prompt);
|
||||||
|
cleartimeout();
|
||||||
|
|
||||||
|
int r = getch();
|
||||||
|
|
||||||
|
#ifdef KEY_RESIZE
|
||||||
|
while (r == KEY_RESIZE) {
|
||||||
|
if (prompt) {
|
||||||
|
clearoldprompt();
|
||||||
|
xlines = LINES;
|
||||||
|
printmsg(prompt);
|
||||||
|
}
|
||||||
|
|
||||||
|
r = getch();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
settimeout();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_cur_or_sel(void)
|
||||||
|
{
|
||||||
|
if (selbufpos && ndents) {
|
||||||
|
if (cfg.prefersel)
|
||||||
|
return 's';
|
||||||
|
|
||||||
|
int choice = get_input(messages[MSG_CUR_SEL_OPTS]);
|
||||||
|
|
||||||
|
return ((choice == 'c' || choice == 's') ? choice : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selbufpos)
|
||||||
|
return 's';
|
||||||
|
|
||||||
|
if (ndents)
|
||||||
|
return 'c';
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xdelay(useconds_t delay)
|
||||||
|
{
|
||||||
|
refresh();
|
||||||
|
usleep(delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char confirm_force(bool selection)
|
||||||
|
{
|
||||||
|
char str[64];
|
||||||
|
|
||||||
|
snprintf(str, 64, messages[MSG_FORCE_RM],
|
||||||
|
(selection ? xitoa(nselected) : "current"), (selection ? "(s)" : ""));
|
||||||
|
|
||||||
|
int r = get_input(str);
|
||||||
|
|
||||||
|
if (r == 27)
|
||||||
|
return '\0'; /* cancel */
|
||||||
|
if (r == 'y' || r == 'Y')
|
||||||
|
return 'f'; /* forceful */
|
||||||
|
return 'i'; /* interactive */
|
||||||
|
}
|
||||||
|
|
||||||
/* Writes buflen char(s) from buf to a file */
|
/* Writes buflen char(s) from buf to a file */
|
||||||
static void writesel(const char *buf, const size_t buflen)
|
static void writesel(const char *buf, const size_t buflen)
|
||||||
{
|
{
|
||||||
|
@ -2395,8 +2422,8 @@ static int entrycmp(const void *va, const void *vb)
|
||||||
if (pb->blocks < pa->blocks)
|
if (pb->blocks < pa->blocks)
|
||||||
return -1;
|
return -1;
|
||||||
} else if (cfg.extnorder && !(pb->flags & DIR_OR_LINK_TO_DIR)) {
|
} else if (cfg.extnorder && !(pb->flags & DIR_OR_LINK_TO_DIR)) {
|
||||||
char *extna = xmemrchr((uchar *)pa->name, '.', pa->nlen - 1);
|
char *extna = xextension(pa->name, pa->nlen - 1);
|
||||||
char *extnb = xmemrchr((uchar *)pb->name, '.', pb->nlen - 1);
|
char *extnb = xextension(pb->name, pb->nlen - 1);
|
||||||
|
|
||||||
if (extna || extnb) {
|
if (extna || extnb) {
|
||||||
if (!extna)
|
if (!extna)
|
||||||
|
@ -2650,6 +2677,19 @@ static int matches(const char *fltr)
|
||||||
return ndents;
|
return ndents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the position of the matching entry or 0 otherwise
|
||||||
|
* Note there's no NULL check for fname
|
||||||
|
*/
|
||||||
|
static int dentfind(const char *fname, int n)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < n; ++i)
|
||||||
|
if (xstrcmp(fname, pdents[i].name) == 0)
|
||||||
|
return i;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int filterentries(char *path, char *lastname)
|
static int filterentries(char *path, char *lastname)
|
||||||
{
|
{
|
||||||
wchar_t *wln = (wchar_t *)alloca(sizeof(wchar_t) * REGEX_MAX);
|
wchar_t *wln = (wchar_t *)alloca(sizeof(wchar_t) * REGEX_MAX);
|
||||||
|
@ -3055,28 +3095,6 @@ static char *getreadline(const char *prompt)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* Updates out with "dir/name or "/name"
|
|
||||||
* Returns the number of bytes copied including the terminating NULL byte
|
|
||||||
*/
|
|
||||||
static size_t mkpath(const char *dir, const char *name, char *out)
|
|
||||||
{
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
/* Handle absolute path */
|
|
||||||
if (name[0] == '/') // NOLINT
|
|
||||||
return xstrsncpy(out, name, PATH_MAX);
|
|
||||||
|
|
||||||
/* Handle root case */
|
|
||||||
if (istopdir(dir))
|
|
||||||
len = 1;
|
|
||||||
else
|
|
||||||
len = xstrsncpy(out, dir, PATH_MAX);
|
|
||||||
|
|
||||||
out[len - 1] = '/'; // NOLINT
|
|
||||||
return (xstrsncpy(out + len, name, PATH_MAX - len) + len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create symbolic/hard link(s) to file(s) in selection list
|
* Create symbolic/hard link(s) to file(s) in selection list
|
||||||
* Returns the number of links created, -1 on error
|
* Returns the number of links created, -1 on error
|
||||||
|
@ -3889,11 +3907,6 @@ static char *get_output(char *buf, const size_t bytes, const char *file,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool getutil(char *util)
|
|
||||||
{
|
|
||||||
return spawn("which", util, NULL, F_NORMAL | F_NOTRACE) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pipetof(char *cmd, FILE *fout)
|
static void pipetof(char *cmd, FILE *fout)
|
||||||
{
|
{
|
||||||
FILE *fin = popen(cmd, "r");
|
FILE *fin = popen(cmd, "r");
|
||||||
|
@ -4977,19 +4990,6 @@ exit:
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Return the position of the matching entry or 0 otherwise
|
|
||||||
* Note there's no NULL check for fname
|
|
||||||
*/
|
|
||||||
static int dentfind(const char *fname, int n)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < n; ++i)
|
|
||||||
if (xstrcmp(fname, pdents[i].name) == 0)
|
|
||||||
return i;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void populate(char *path, char *lastname)
|
static void populate(char *path, char *lastname)
|
||||||
{
|
{
|
||||||
#ifdef DBGMODE
|
#ifdef DBGMODE
|
||||||
|
@ -5346,7 +5346,7 @@ static void statusbar(char *path)
|
||||||
/* Get the file extension for regular files */
|
/* Get the file extension for regular files */
|
||||||
if (S_ISREG(pent->mode)) {
|
if (S_ISREG(pent->mode)) {
|
||||||
i = (int)(pent->nlen - 1);
|
i = (int)(pent->nlen - 1);
|
||||||
ptr = xmemrchr((uchar *)pent->name, '.', i);
|
ptr = xextension(pent->name, i);
|
||||||
if (ptr)
|
if (ptr)
|
||||||
extnlen = i - (ptr - pent->name);
|
extnlen = i - (ptr - pent->name);
|
||||||
if (!ptr || extnlen > 5 || extnlen < 2)
|
if (!ptr || extnlen > 5 || extnlen < 2)
|
||||||
|
|
Loading…
Reference in a new issue