nasmfm

sfm rewrite
git clone https://git.afify.dev/nasmfm.git
Log | Files | Refs | LICENSE

commit 996dd0556d696ec21c4ac9f26464ff9b61f68388
parent 7072e37fbe7fd4b2f3c4aa2e7563ff4ea407717c
Author: afify <hassan@afify.dev>
Date:   Sat, 12 Mar 2022 23:51:19 +0300

push

Diffstat:
Mconfig.mk | 2+-
Mnasmfm.c | 544++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Mterm.c | 43+++++++++++++++++++++++++++++++------------
Mterm.h | 1+
Mutil.c | 50+++++++++++++++++++++++++-------------------------
Mutil.h | 2+-
6 files changed, 575 insertions(+), 67 deletions(-)

diff --git a/config.mk b/config.mk @@ -1,5 +1,5 @@ # nasmfm version -VERSION = 0.0 +VERSION = 0.5 # paths PREFIX = /usr/local diff --git a/nasmfm.c b/nasmfm.c @@ -1,11 +1,39 @@ /* See LICENSE file for copyright and license details. */ +#if defined(__linux__) +#define _GNU_SOURCE +#elif defined(__APPLE__) +#define _DARWIN_C_SOURCE +#elif defined(__FreeBSD__) +#define __BSD_VISIBLE 1 +#endif +#include <sys/types.h> +#include <sys/resource.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/wait.h> +#if defined(__linux__) +#include <sys/inotify.h> +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \ + defined(__APPLE__) +#include <sys/event.h> +#endif + +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <grp.h> +#include <libgen.h> +#include <pthread.h> +#include <pwd.h> #include <signal.h> +#include <stdarg.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <termios.h> +#include <time.h> #include <unistd.h> #include "term.h" @@ -26,6 +54,7 @@ /* typedef */ typedef struct { char name[MAX_N]; + char real[MAX_P]; // real dir name cwd gid_t group; mode_t mode; off_t size; @@ -37,12 +66,12 @@ typedef struct { //int pane_id; char dirn[MAX_P]; // dir name cwd //char *filter; - //Entry *direntr; // dir entries - //int dirc; // dir entries sum - //int hdir; // highlighted dir + Entry *direntr; // dir entries + int dirc; // dir entries sum + int hdir; // highlighted dir int x_srt; int x_end; - //int firstrow; + int firstrow; //int parent_firstrow; //int parent_row; // FIX Cpair dircol; @@ -111,11 +140,459 @@ enum { Wait, DontWait }; /* spawn forks */ /* configuration, allows nested code to access above variables */ #include "config.h" + +static void +get_hicol(Cpair *col, mode_t mode) +{ + switch (mode & S_IFMT) { + case S_IFREG: + *col = cfile; + if ((S_IXUSR | S_IXGRP | S_IXOTH) & mode) + *col = cexec; + break; + case S_IFDIR: + *col = cdir; + break; + case S_IFLNK: + *col = clnk; + break; + case S_IFBLK: + *col = cblk; + break; + case S_IFCHR: + *col = cchr; + break; + case S_IFIFO: + *col = cifo; + break; + case S_IFSOCK: + *col = csock; + break; + default: + *col = cother; + break; + } +} + +static void +print_row(Pane *pane, size_t entpos, Cpair col) +{ + int x, y; + char *full_str, *rez_pth; + char lnk_full[MAX_N]; + + int hwidth = pane->x_end - 2; + full_str = basename(pane->direntr[entpos].name); + x = pane->x_srt; + y = entpos - pane->firstrow + 2; + + if (S_ISLNK(pane->direntr[entpos].mode) != 0) { + rez_pth = ecalloc(MAX_P, sizeof(char)); + if (realpath(pane->direntr[entpos].name, rez_pth) != NULL) { + snprintf( + lnk_full, MAX_N, "%s -> %s", full_str, rez_pth); + full_str = lnk_full; + } + free(rez_pth); + } + + //twrite(x, y, full_str, strlen(full_str), col); + tprintf(x, y, col, "%*.*s", + ~(pane->x_end - 2), pane->x_end - 2, full_str); +} +static void +add_hi(Pane *pane, size_t entpos) +{ + Cpair col; + get_hicol(&col, pane->direntr[entpos].mode); + col.attr = 7; + print_row(pane, entpos, col); +} + +static char * +get_fullpath(char *first, char *second) +{ + char *full_path; + + full_path = ecalloc(MAX_P, sizeof(char)); + + if (strncmp(first, "/", MAX_P) == 0) + (void)snprintf(full_path, MAX_P, "/%s", second); + else + (void)snprintf(full_path, MAX_P, "%s/%s", first, second); + + return full_path; +} + +static void +get_dirp(char *cdir) +{ + int counter, len, i; + + counter = 0; + len = strnlen(cdir, MAX_P); + if (len == 1) + return; + + for (i = len - 1; i > 1; i--) { + if (cdir[i] == '/') + break; + else + counter++; + } + + cdir[len - counter - 1] = '\0'; +} + +static char * +get_ext(char *str) +{ + char *ext; + char dot; + size_t counter, len, i; + + dot = '.'; + counter = 0; + len = strnlen(str, MAX_N); + + for (i = len - 1; i > 0; i--) { + if (str[i] == dot) { + break; + } else { + counter++; + } + } + + ext = ecalloc(MAX_EXT + 1, sizeof(char)); + strncpy(ext, &str[len - counter], MAX_EXT); + ext[MAX_EXT] = '\0'; + return ext; +} + +static int +get_fdt(char *result, time_t status) +{ + struct tm lt; + localtime_r(&status, &lt); + return strftime(result, MAX_DTF, dtfmt, &lt); +} + +static char * +get_fgrp(gid_t status) +{ + char *result; + struct group *gr; + + result = ecalloc(MAX_GRPN, sizeof(char)); + gr = getgrgid(status); + if (gr == NULL) + (void)snprintf(result, MAX_GRPN, "%u", status); + else + strncpy(result, gr->gr_name, MAX_GRPN); + + result[MAX_GRPN - 1] = '\0'; + return result; +} +static char * +get_fperm(mode_t mode) +{ + char *buf; + size_t i; + + const char chars[] = "rwxrwxrwx"; + buf = ecalloc(11, sizeof(char)); + + if (S_ISDIR(mode)) + buf[0] = 'd'; + else if (S_ISREG(mode)) + buf[0] = '-'; + else if (S_ISLNK(mode)) + buf[0] = 'l'; + else if (S_ISBLK(mode)) + buf[0] = 'b'; + else if (S_ISCHR(mode)) + buf[0] = 'c'; + else if (S_ISFIFO(mode)) + buf[0] = 'p'; + else if (S_ISSOCK(mode)) + buf[0] = 's'; + else + buf[0] = '?'; + + for (i = 1; i < 10; i++) { + buf[i] = (mode & (1 << (9 - i))) ? chars[i - 1] : '-'; + } + buf[10] = '\0'; + + return buf; +} + +static char * +get_fsize(off_t size) +{ + char *result; /* need to be freed */ + char unit; + int result_len; + int counter; + + counter = 0; + result_len = 6; /* 9999X/0 */ + result = ecalloc(result_len, sizeof(char)); + + while (size >= 1000) { + size /= 1024; + ++counter; + } + + switch (counter) { + case 0: + unit = 'B'; + break; + case 1: + unit = 'K'; + break; + case 2: + unit = 'M'; + break; + case 3: + unit = 'G'; + break; + case 4: + unit = 'T'; + break; + default: + unit = '?'; + } + + if (snprintf(result, result_len, OFF_T "%c", size, unit) < 0) + strncat(result, "???", result_len); + + return result; +} + +static char * +get_fusr(uid_t status) +{ + char *result; + struct passwd *pw; + + result = ecalloc(MAX_USRN, sizeof(char)); + pw = getpwuid(status); + if (pw == NULL) + (void)snprintf(result, MAX_USRN, "%u", status); + else + strncpy(result, pw->pw_name, MAX_USRN); + + result[MAX_USRN - 1] = '\0'; + return result; +} + +static void +get_dirsize(char *fullpath, off_t *fullsize) +{ + DIR *dir; + char *ent_full; + mode_t mode; + struct dirent *entry; + struct stat status; + + dir = opendir(fullpath); + if (dir == NULL) { + return; + } + + while ((entry = readdir(dir)) != 0) { + if ((strncmp(entry->d_name, ".", 2) == 0 || + strncmp(entry->d_name, "..", 3) == 0)) + continue; + + ent_full = get_fullpath(fullpath, entry->d_name); + if (lstat(ent_full, &status) == 0) { + mode = status.st_mode; + if (S_ISDIR(mode)) { + get_dirsize(ent_full, fullsize); + free(ent_full); + } else { + *fullsize += status.st_size; + free(ent_full); + } + } + } + + closedir(dir); + //clear_status(); +} + +static void +print_info(Pane *pane, char *dirsize) +{ + char *sz, *ur, *gr, *dt, *prm; + + dt = ecalloc(MAX_DTF, sizeof(char)); + + prm = get_fperm(CURSOR(pane).mode); + ur = get_fusr(CURSOR(pane).user); + gr = get_fgrp(CURSOR(pane).group); + + if (get_fdt(dt, CURSOR(pane).dt) < 0) + *dt = '\0'; + + if (S_ISREG(CURSOR(pane).mode)) { + sz = get_fsize(CURSOR(pane).size); + } else { + if (dirsize == NULL) { + sz = ecalloc(1, sizeof(char)); + *sz = '\0'; + } else { + sz = dirsize; + } + } + + tprintf_status("%02d/%02d %s %s:%s %s %s", pane->hdir, + pane->dirc, prm, ur, gr, dt, sz); + + free(prm); + free(ur); + free(gr); + free(dt); + free(sz); +} + + +static int +sort_name(const void *const A, const void *const B) +{ + int result; + mode_t data1 = (*(Entry *)A).mode; + mode_t data2 = (*(Entry *)B).mode; + + if (data1 < data2) { + return -1; + } else if (data1 == data2) { + result = strncmp((*(Entry *)A).name, (*(Entry *)B).name, MAX_N); + return result; + } else { + return 1; + } +} + +static void +set_direntr(Pane *pane, struct dirent *entry, DIR *dir, char *filter) +{ + int i; + char *tmpfull; + struct stat status; + + i = 0; + pane->direntr = + erealloc(pane->direntr, (10 + pane->dirc) * sizeof(Entry)); + while ((entry = readdir(dir)) != 0) { + if (show_dotfiles == 1) { + if (entry->d_name[0] == '.' && + (entry->d_name[1] == '\0' || + entry->d_name[1] == '.')) + continue; + } else { + if (entry->d_name[0] == '.') + continue; + } + + tmpfull = get_fullpath(pane->dirn, entry->d_name); + strncpy(pane->direntr[i].name, tmpfull, MAX_N); + if (lstat(tmpfull, &status) == 0) { + pane->direntr[i].size = status.st_size; + pane->direntr[i].mode = status.st_mode; + pane->direntr[i].group = status.st_gid; + pane->direntr[i].user = status.st_uid; + pane->direntr[i].dt = status.st_mtime; + + } + if (S_ISLNK(status.st_mode) != 0) { + realpath(tmpfull, pane->direntr[i].real); + } + i++; + free(tmpfull); + } + + pane->dirc = i; +} + static void +refresh_pane(Pane *pane) +{ + Cpair col; + int x; + char *entry; + + for (x = 0; x < pane->dirc; x++) { + get_hicol(&col, pane->direntr[x].mode); + entry = basename(pane->direntr[x].name); + if (pane->direntr[x].real[0] != '\0') + entry = pane->direntr[x].real; + twrite(pane->x_srt, x+2, + entry, + //pane->direntr[x].real, + //basename(pane->direntr[x].name), + strlen(pane->direntr[x].name), + col); + } + + //size_t y, dyn_max, start_from; + int hwidth = (term->cols / 2) - 4; + //Cpair col; + //col.bg = 0; + + //y = 1; + //start_from = pane->firstrow; + //dyn_max = MIN(pane->dirc, (term->rows - 1) + pane->firstrow); + + //while (start_from < dyn_max) { + // print_row(pane, start_from, col); + // start_from++; + // y++; + //} + + //if (pane->dirc > 0) + // print_info(pane, NULL); +// else + //clear_status(); + + /* print current directory title */ + //tprintf(pane->x_srt, 1, pane->dircol, " %.*s", hwidth, pane->dirn); //349,275 + //twrite(pane->x_srt, 0, pane->dirn, strlen(pane->dirn), pane->dircol); //347,862 +} + +static int listdir(Pane *pane) { - // print pane cwd - twrite(pane->x_srt, 0, pane->dirn, strlen(pane->dirn), pane->dircol); + DIR *dir; + struct dirent *entry; + + pane->dirc = 0; + + dir = opendir(pane->dirn); + if (dir == NULL) + return -1; + + /* get content and filter sum */ + while ((entry = readdir(dir)) != 0) { + pane->dirc++; + } + + rewinddir(dir); /* reset position */ + set_direntr(pane, entry, dir, NULL); /* create array of entries */ + qsort(pane->direntr, pane->dirc, sizeof(Entry), sort_name); /*[5971]*/ + refresh_pane(pane); + + if (pane->hdir > pane->dirc) + pane->hdir = pane->dirc; + + //if (pane == cpane && pane->dirc > 0) + //add_hi(pane, pane->hdir - 1); + + if (closedir(dir) < 0) + return -1; + return 0; } static void @@ -137,10 +614,10 @@ set_panes(void) panes[Left].x_srt = 2; panes[Left].x_end = (term->cols / 2) - 1; panes[Left].dircol = cpanell; - //panes[Left].firstrow = 0; - //panes[Left].direntr = ecalloc(0, sizeof(Entry)); + panes[Left].firstrow = 0; + panes[Left].direntr = ecalloc(0, sizeof(Entry)); strncpy(panes[Left].dirn, cwd, MAX_P); - //panes[Left].hdir = 1; + panes[Left].hdir = 1; //panes[Left].inotify_wd = -1; //panes[Left].parent_row = 1; @@ -148,10 +625,10 @@ set_panes(void) panes[Right].x_srt = (term->cols / 2) + 2; panes[Right].x_end = term->cols - 1; panes[Right].dircol = cpanelr; - //panes[Right].firstrow = 0; - //panes[Right].direntr = ecalloc(0, sizeof(Entry)); + panes[Right].firstrow = 0; + panes[Right].direntr = ecalloc(0, sizeof(Entry)); strncpy(panes[Right].dirn, home, MAX_P); - //panes[Right].hdir = 1; + panes[Right].hdir = 1; //panes[Right].inotify_wd = -1; //panes[Right].parent_row = 1; } @@ -188,7 +665,6 @@ keypress() switch (c) { case 'q': CLEAR_SCREEN - //CURSOR_TOP_LEFT CURSOR_SHOW exit(0); break; @@ -197,7 +673,7 @@ keypress() col.fg = 211; col.attr = RVS; - tprintf(2, term->rows -2, col, "SIGWINCH = %d\n", signo); + tprintf(2, term->rows - 2, col, "SIGWINCH = %d\n", signo); //twrite(2, term->rows - 2, buf, strlen(buf), col); break; } @@ -206,27 +682,17 @@ keypress() void sighandler(int signo) { - Cpair col; - col.bg = 0; - col.fg = 211; - col.attr = RVS; - switch (signo) { case SIGWINCH: get_term_size(&term->rows, &term->cols); CLEAR_SCREEN - //CURSOR_TOP_LEFT draw_frame(); - tprintf(3,3, col, "SIGWINCH = %d [%d-%d]", signo, term->cols,term->rows); break; case SIGUSR1: - tprintf(1, 1, col, "SIGUSR1 = %d", signo); break; case SIGUSR2: - tprintf(1, 1, col, "SIGUSR2 = %d", signo); break; } - } static int @@ -243,19 +709,41 @@ start_signal(void) return 0; } -int -main(int argc, char *argv[]) +void +start(void) { term = init_term(); draw_frame(); set_panes(); get_editor(); get_shell(); - listdir(&panes[Left]); - listdir(&panes[Right]); start_signal(); + + //PERROR(fsev_init() < 0); + + listdir(&panes[Left]); + //listdir(&panes[Right]); + + //pthread_create(&fsev_thread, NULL, read_th, NULL); + while (1) { keypress(); } +} + +int +main(int argc, char *argv[]) +{ +#if defined(__OpenBSD__) + if (pledge("cpath exec getpw proc rpath stdio tmppath tty wpath", + NULL) == -1) + die("pledge"); +#endif /* __OpenBSD__ */ + if (argc == 1) + start(); + else if (argc == 2 && strncmp("-v", argv[1], 2) == 0) + die("sfm-" VERSION); + else + die("usage: sfm [-v]"); return 0; } diff --git a/term.c b/term.c @@ -15,6 +15,7 @@ #include <stdint.h> #include "term.h" +#include "config.h" #include "utf8.h" #include "util.h" @@ -26,14 +27,13 @@ static Term oterm; /* function implementations */ -void -die(const char *s) -{ - CLEAR_SCREEN - //CURSOR_TOP_LEFT - perror(s); - exit(1); -} +//void +//die(const char *s) +//{ +// CLEAR_SCREEN +// perror(s); +// exit(1); +//} void @@ -81,7 +81,6 @@ init_term() { raw_mode(); CLEAR_SCREEN - //CURSOR_TOP_LEFT CURSOR_HIDE oterm.cx = 0; oterm.cy = 0; @@ -128,6 +127,28 @@ tprintf(int x, int y, Cpair col, const char *fmt, ...) } void +tprintf_status(const char *fmt, ...) +{ + int x = 2; + int y = oterm.rows - 1; + + char buf[oterm.cols]; // fmt result + char str[oterm.cols]; // with color and position + size_t full_buf; + va_list vl; + va_start(vl, fmt); + (void)vsnprintf(buf, oterm.cols, fmt, vl); + va_end(vl); + + //print_tb(buf, x, y, col.fg, col.bg); + snprintf(str, oterm.cols, + "\x1b[%d;%df\x1b[%d;48;5;%d;38;5;%dm%s\x1b[0;0m", + y, x, cstatus.attr, cstatus.bg, cstatus.fg, buf); + full_buf = strlen(str); + write(STDOUT_FILENO, str, full_buf); +} + +void move_to_col(int y) { char buf[8]; @@ -149,9 +170,8 @@ draw_frame() // TODO move_to_col char buf[16]; - int colframe = 233; size_t full_buf; - snprintf(buf, 16, "\x1b[38;5;%dm", colframe); + snprintf(buf, 16, "\x1b[38;5;%dm", cframe.fg); full_buf = strlen(buf); write(STDOUT_FILENO, buf, full_buf); @@ -241,7 +261,6 @@ getkey() // struct abuf ab = { NULL, 0 }; // abAppend(&ab, "\x1b[?25l", 6); // abAppend(&ab, "\x1b[H", 3); -// CURSOR_TOP_LEFT // editorDrawRows(&ab); // char buf[32]; // snprintf(buf, sizeof(buf), "\x1b[%d;%dH", term.cy + 1, term.cx + 1); diff --git a/term.h b/term.h @@ -38,4 +38,5 @@ void tprintf(int, int, Cpair, const char *, ...); void move_to_col(int); char getkey(void); int get_term_size(int *, int *); +void tprintf_status(const char *fmt, ...); #endif /* TERM_H */ diff --git a/util.c b/util.c @@ -16,29 +16,29 @@ ecalloc(size_t nmemb, size_t size) return p; } -//void * -//erealloc(void *p, size_t len) -//{ -// if ((p = realloc(p, len)) == NULL) -// die("realloc: %s\n", strerror(errno)); -// return p; -//} +void * +erealloc(void *p, size_t len) +{ + if ((p = realloc(p, len)) == NULL) + die("realloc: %s\n", strerror(errno)); + return p; +} -//void -//die(const char *fmt, ...) -//{ -// va_list ap; -// -// va_start(ap, fmt); -// (void)vfprintf(stderr, fmt, ap); -// va_end(ap); -// -// if (fmt[0] != '\0' && fmt[strlen(fmt)-1] == ':') { -// (void)fputc(' ', stderr); -// perror(NULL); -// } else { -// (void)fputc('\n', stderr); -// } -// -// exit(EXIT_FAILURE); -//} +void +die(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + + if (fmt[0] != '\0' && fmt[strlen(fmt)-1] == ':') { + (void)fputc(' ', stderr); + perror(NULL); + } else { + (void)fputc('\n', stderr); + } + + exit(EXIT_FAILURE); +} diff --git a/util.h b/util.h @@ -12,6 +12,6 @@ void *ecalloc(size_t, size_t); void *erealloc(void*, size_t); -//void die(const char *fmt, ...); +void die(const char *fmt, ...); #endif /* UTIL_H */