sfm

Simple file manager
git clone git://git.christosmarg.xyz/sfm.git
Log | Files | Refs | README | LICENSE

commit ed4dcd85c15d7fcfd8c6e300ca7fb2392d3597af
parent 27cb86388296ab76b8b24db9bb5ccf1027d1a57b
Author: Christos Margiolis <christos@margiolis.net>
Date:   Sun,  8 Nov 2020 15:41:51 +0200

now reading dirs with fts, not dirent

Diffstat:
ALICENSE | 29+++++++++++++++++++++++++++++
Mconfig.h | 2--
Msfm.c | 239++++++++++++++++++++++++++++++++++---------------------------------------------
3 files changed, 132 insertions(+), 138 deletions(-)

diff --git a/LICENSE b/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2020-present, Christos Margiolis. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of images.weserv.nl nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/config.h b/config.h @@ -21,8 +21,6 @@ static Key keys[] = { { 0, 'a', nav, {.n = NAV_SHOWALL} }, { 'g', 'h', cd, {.d = "/home/christos"} }, { 'g', 'u', cd, {.d = "/usr"} }, - { 0, 's', entsort, {.n = ENTSORT_NAME_ASC} }, - //{ 's', 'd', entsort, {.n = ENTSORT_NAME_DESC} }, { 'd', 'D', spawn, SHCMD("rm -rf %s") }, { 0, ':', promptget, {.f = NULL} }, { 0, 'q', quit, {.f = NULL} }, diff --git a/sfm.c b/sfm.c @@ -3,6 +3,7 @@ #include <sys/wait.h> #include <dirent.h> +#include <fts.h> #include <limits.h> #include <stdio.h> #include <stdlib.h> @@ -12,21 +13,12 @@ #include <ncurses.h> -// why tho -#ifndef DT_DIR -#define DT_DIR 4 -#endif /* DT_DIR */ - -#ifndef DT_REG -#define DT_REG 8 -#endif /* DT_REG */ - #define PATH_MAX 1024 // syslimits' PATH_MAX? #define HOST_NAME_MAX _POSIX_HOST_NAME_MAX #define LOGIN_NAME_MAX _POSIX_LOGIN_NAME_MAX #define PARENT_COL 0 -#define FOCUS_COL ((XMAX / 2) / 3) +#define MAIN_COL ((XMAX / 2) / 3) #define CHILD_COL (XMAX / 2) #define YMAX (getmaxy(stdscr)) @@ -35,18 +27,22 @@ #define MAX(x, y) ((x) > (y) ? (x) : (y)) #define ARRLEN(x) (sizeof(x) / sizeof(x[0])) #define ISDIGIT(x) ((unsigned int)(x) - '0' <= 9) -#define SEL_CORRECT (msel = ((msel < 0) ? 0 : (msel > nfiles - 1) ? nfiles - 1 : msel)) +#define SEL_CORRECT \ + (msel = ((msel < 0) ? 0 : (msel > nfiles - 1) ? nfiles - 1 : msel)) + +/* typedefs */ +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned int uint; +typedef unsigned long ulong; +typedef long long ll; +typedef unsigned long long ull; /* structs, unions and enums */ typedef struct { - struct stat stat; - char name[FILENAME_MAX]; - char abspath[PATH_MAX]; - /*char parentpath[PATH_MAX];*/ - unsigned int nchld; - unsigned int nparents; - unsigned short nmlen; - unsigned char type; + FTSENT *fts; + ulong nchld; + ulong nparents; } Entry; typedef union { @@ -63,12 +59,6 @@ typedef struct { } Key; enum { - LEVEL_PARENT = -1, - LEVEL_MAIN, - LEVEL_CHILD -}; - -enum { NAV_LEFT, NAV_RIGHT, NAV_UP, @@ -78,36 +68,31 @@ enum { NAV_SHOWALL, }; -enum { - ENTSORT_NAME_ASC, - ENTSORT_NAME_DESC, -}; - /* globals */ -static Entry *entrs = NULL; -static unsigned long nfiles = 0; -// change to ul -static int msel = 0; /* main sel */ -static int psel = 0; /* parent sel */ -static int csel = 0; /* child sel */ -static int showall = 0; -static int needredraw = 0; +static Entry *entrs = NULL; /* main directory's entries */ +static ulong nfiles = 0; /* number of files in directory */ +static long msel = 0; /* main sel */ +static long psel = 0; /* parent sel */ +static long csel = 0; /* child sel */ +static uchar f_showall = 0; /* show hidden files */ +static uchar f_redraw = 0; /* redraw screen */ + +/* function pointers */ +static int (*sortfn)(const FTSENT *, const FTSENT *); /* function declarations */ static void cursesinit(void); -static int entriescount(const char *); -static Entry *entriesget(const char *); +static int entriescount(char *); +static Entry *entriesget(char *); static void pathdraw(const char *); -static void dirpreview(const Entry *, int, int, int, int, int); +static void dirpreview(const Entry *, int, int, int, ulong); static void filepreview(const Entry *); static void statsprint(const Entry *); static void promptget(const Arg *); static void nav(const Arg *); static void cd(const Arg *); -static void entsort(const Arg *); static void spawn(const Arg *); static void quit(const Arg *); -static void run(void); static void *emalloc(size_t); static void die(const char *, ...); @@ -115,15 +100,9 @@ static void die(const char *, ...); /* function implementations */ static inline int -entcmpnameasc(const void *lhs, const void *rhs) -{ - return (strcmp(((Entry *)lhs)->name, ((Entry *)rhs)->name) < 0); -} - -static inline int -entcmpnamedesc(const void *lhs, const void *rhs) +namecmp(const FTSENT *a, const FTSENT *b) { - return (strcmp(((Entry *)lhs)->name, ((Entry *)rhs)->name) < 0); + return (strcoll(a->fts_name, b->fts_name)); } void @@ -138,52 +117,56 @@ cursesinit(void) } int -entriescount(const char *path) +entriescount(char *path) { - DIR *dir; - struct dirent *dp; + FTS *ftsp; + FTSENT *p, *chp, *cur; + char *args[] = {path, NULL}; int n = 0; - - if ((dir = opendir(path)) == NULL) + + if ((ftsp = fts_open(args, FTS_NOCHDIR, NULL)) == NULL) return 0; - while ((dp = readdir(dir)) != NULL) { - if (!showall && dp->d_name[0] == '.') - continue; - if (strcmp(dp->d_name, path) && strcmp(dp->d_name, ".") - && strcmp(dp->d_name, "..")) + while ((p = fts_read(ftsp)) != NULL) { + fts_set(ftsp, p, FTS_SKIP); + chp = fts_children(ftsp, 0); + for (cur = chp; cur; cur = cur->fts_link) { + /*if (!f_showall)*/ + if (cur->fts_name[0] == '.') + continue; n++; + } } - closedir(dir); + fts_close(ftsp); return n; } Entry * -entriesget(const char *path) +entriesget(char *path) { - DIR *dir; - struct dirent *dp; + FTS *ftsp; + FTSENT *p, *chp, *cur; Entry *dents; + char *args[] = {path, NULL}; int i = 0; dents = emalloc(entriescount(path) * sizeof(Entry)); - if ((dir = opendir(path)) == NULL) + if ((ftsp = fts_open(args, FTS_NOCHDIR, NULL)) == NULL) return NULL; - while ((dp = readdir(dir)) != NULL) { - if (!showall && dp->d_name[0] == '.') - continue; - if (strcmp(dp->d_name, path) && strcmp(dp->d_name, ".") - && strcmp(dp->d_name, "..")) { - strcpy(dents[i].name, dp->d_name); - dents[i].nmlen = strlen(dp->d_name); - dents[i].type = dp->d_type; - sprintf(dents[i].abspath, "%s/%s", path, dp->d_name); - dents[i].nchld = entriescount(dents[i].name); - dents[i].nparents = entriescount(".."); - stat(dents[i].abspath, &dents[i].stat); + while ((p = fts_read(ftsp)) != NULL) { + fts_set(ftsp, p, FTS_SKIP); + chp = fts_children(ftsp, 0); + for (cur = chp; cur; cur = cur->fts_link) { + /*if (!f_showall)*/ + if (cur->fts_name[0] == '.') + continue; + dents[i].fts = cur; + /*dents[i].nchld = entriescount(dents[i].fts->fts_name);*/ i++; } + /* TODO: count parents only one time, as it's the same for everyone */ + /*dents[i].nparents = entriescount("..");*/ } - closedir(dir); + fts_close(ftsp); return dents; } @@ -202,7 +185,7 @@ pathdraw(const char *path) } void -dirpreview(const Entry *dents, int n, int col, int len, int sel, int level) +dirpreview(const Entry *dents, int n, int col, int len, ulong sel) { char buf[FILENAME_MAX]; int i = 0; @@ -210,19 +193,23 @@ dirpreview(const Entry *dents, int n, int col, int len, int sel, int level) for (; i < n && i < YMAX; i++) { if (i == sel) attron(A_REVERSE); - if (dents[i].type == DT_DIR) + if (dents[i].fts->fts_info == FTS_D) attron(A_BOLD); - sprintf(buf, "%-*s", len, dents[i].name); + sprintf(buf, "%-*s", len, dents[i].fts->fts_name); // handle empty dir mvprintw(i + 2, col, " %s \n", buf); - if (level == 0) { + if (col == MAIN_COL) { // align numbers properly - if (dents[i].type == DT_DIR) - mvprintw(i + 2, CHILD_COL, "%12d \n", - dents[i].nchld); - else if (dents[i].type == DT_REG) + switch (dents[i].fts->fts_info) { + case FTS_D: + /*mvprintw(i + 2, CHILD_COL, "%12d \n",*/ + /*dents[i].nchld);*/ + break; + case FTS_F: mvprintw(i + 2, CHILD_COL, "%10d B \n", - dents[i].stat.st_size); + dents[i].fts->fts_statp->st_size); + break; + } } attroff(A_BOLD); attroff(A_REVERSE); @@ -234,19 +221,19 @@ statsprint(const Entry *entry) { struct tm *tm; - tm = localtime(&entry->stat.st_ctime); + tm = localtime(&entry->fts->fts_statp->st_ctime); mvprintw(YMAX - 1, 0, "%c%c%c%c%c%c%c%c%c%c %dB %s", - (S_ISDIR(entry->stat.st_mode)) ? 'd' : '-', - entry->stat.st_mode & S_IRUSR ? 'r' : '-', - entry->stat.st_mode & S_IWUSR ? 'w' : '-', - entry->stat.st_mode & S_IXUSR ? 'x' : '-', - entry->stat.st_mode & S_IRGRP ? 'r' : '-', - entry->stat.st_mode & S_IWGRP ? 'w' : '-', - entry->stat.st_mode & S_IXGRP ? 'x' : '-', - entry->stat.st_mode & S_IROTH ? 'r' : '-', - entry->stat.st_mode & S_IWOTH ? 'w' : '-', - entry->stat.st_mode & S_IXOTH ? 'x' : '-', - entry->stat.st_size, asctime(tm)); + (S_ISDIR(entry->fts->fts_statp->st_mode)) ? 'd' : '-', + entry->fts->fts_statp->st_mode & S_IRUSR ? 'r' : '-', + entry->fts->fts_statp->st_mode & S_IWUSR ? 'w' : '-', + entry->fts->fts_statp->st_mode & S_IXUSR ? 'x' : '-', + entry->fts->fts_statp->st_mode & S_IRGRP ? 'r' : '-', + entry->fts->fts_statp->st_mode & S_IWGRP ? 'w' : '-', + entry->fts->fts_statp->st_mode & S_IXGRP ? 'x' : '-', + entry->fts->fts_statp->st_mode & S_IROTH ? 'r' : '-', + entry->fts->fts_statp->st_mode & S_IWOTH ? 'w' : '-', + entry->fts->fts_statp->st_mode & S_IXOTH ? 'x' : '-', + entry->fts->fts_statp->st_size, asctime(tm)); // align mvprintw(YMAX - 1, XMAX - 10, "%ld/%ld\n", msel + 1, nfiles); } @@ -258,8 +245,8 @@ filepreview(const Entry *entry) char buf[BUFSIZ]; int ln = 0; - if ((fp = fopen(entry->name, "r")) == NULL) - return; + /*if ((fp = fopen(entry->name, "r")) == NULL)*/ + /*return;*/ // replace XMAX / 2 while (fgets(buf, BUFSIZ, fp) && ln < YMAX) { if (strlen(buf) > XMAX / 2) @@ -298,13 +285,13 @@ nav(const Arg *arg) chdir(".."); break; case NAV_RIGHT: - if (entrs[msel].name != NULL) { + /*if (entrs[msel].name != NULL) {*/ // handle symlinks - if (entrs[msel].type == DT_DIR) - chdir(entrs[msel].name); + /*if (entrs[msel].type == FTS_D)*/ + /*chdir(entrs[msel].name);*/ /*else if (entrs[msel].type == DT_REG)*/ /*spawn();*/ - } + /*}*/ break; case NAV_UP: msel--; @@ -319,21 +306,8 @@ nav(const Arg *arg) msel = nfiles - 1; break; case NAV_SHOWALL: - showall = !showall; - needredraw = 1; - break; - } -} - -void -entsort(const Arg *arg) -{ - switch (arg->n) { - case ENTSORT_NAME_ASC: - qsort(entrs, nfiles, sizeof(Entry), entcmpnameasc); - break; - case ENTSORT_NAME_DESC: - qsort(entrs, nfiles, sizeof(Entry), entcmpnamedesc); + f_showall = !f_showall; + f_redraw = 1; break; } } @@ -377,12 +351,6 @@ die(const char *fmt, ...) fputc('\n', stderr); exit(EXIT_FAILURE); - -} - -void -run(void) -{ } int @@ -396,13 +364,12 @@ main(int argc, char *argv[]) cursesinit(); if ((curdir = getcwd(cwd, sizeof(cwd))) == NULL) die("can't get cwd"); - run(); for (;;) { erase(); curdir = getcwd(cwd, sizeof(cwd)); - if (strcmp(curdir, prevdir) != 0 || needredraw) { + if (strcmp(curdir, prevdir) != 0 || f_redraw) { if (entrs != NULL) free(entrs); if (parent != NULL) @@ -412,24 +379,24 @@ main(int argc, char *argv[]) nfiles = entriescount(curdir); if ((entrs = entriesget(curdir)) == NULL) continue; - if ((parent = entriesget("..")) == NULL) - continue; + /*if ((parent = entriesget("..")) == NULL)*/ + /*continue;*/ /*if (entrs[msel].type == DT_DIR)*/ /*if ((child = entriesget(entrs[msel].name)) == NULL)*/ /*continue;*/ - // is this a memleak? strcpy(prevdir, curdir); - needredraw = 0; + f_redraw = 0; } SEL_CORRECT; pathdraw(curdir); /*if (strcmp(curdir, "/") != 0)*/ /*dirpreview(parent, entrs[msel].nparents, PARENT_COL,*/ - /*FOCUS_COL - 3, psel, LEVEL_PARENT);*/ - dirpreview(entrs, nfiles, FOCUS_COL, CHILD_COL, msel, LEVEL_MAIN); + /*MAIN_COL - 3, psel);*/ + dirpreview(entrs, nfiles, MAIN_COL, CHILD_COL, msel); statsprint(&entrs[msel]); - /*dirpreview(child, entrs[msel].nchld, CHILD_COL + 2, CHILD_COL - FOCUS_COL, csel, LEVEL_CHILD);*/ + /*dirpreview(child, entrs[msel].nchld, CHILD_COL + 2 + 12,*/ + /*CHILD_COL - MAIN_COL, csel);*/ /*if (entrs[msel].type == DT_REG)*/ /*filepreview(&entrs[msel]);*/