sfm

simple file manager
git clone git://git.afify.dev/sfm
Log | Files | Refs | README | LICENSE

commit 4e278d8286aa473fd70f0d7fe1ad7c1588feeee3
parent f6e4b139281596c31afb9636d076525bab871d36
Author: afify <hassan@afify.dev>
Date:   Sat, 18 Jul 2020 23:13:39 +0300

[ref] light navigation

- rename long functions
- reorder functions
- new functions for each action

Diffstat:
Mconfig.def.h | 55+++++++++++++++++++++++++++++--------------------------
Msfm.c | 1391+++++++++++++++++++++++++++++++++++++++++++------------------------------------
2 files changed, 786 insertions(+), 660 deletions(-)

diff --git a/config.def.h b/config.def.h @@ -39,12 +39,11 @@ static Bookmark bmarks[] = { static const char *images[] = { "bmp", "jpg", "jpeg", "png", "gif", "xpm" }; static const char *web[] = { "htm", "html" }; static const char *pdf[] = { "epub", "pdf" }; -static const char *videos[] = { "avi", "flv", - "m2v", "m4a", "m4v", "mkv", "mov", "mp3", "mp4", "mpeg", "mpg", - "wav", "webm", "wma", "wmv" }; +static const char *arts[] = { "xcf" }; +static const char *videos[] = { "avi", "flv", "wav", "webm", "wma", "wmv", + "m2v", "m4a", "m4v", "mkv", "mov", "mp3", "mp4", "mpeg", "mpg" }; static const char *documents[] = { "odt", "doc", "docx", "xls", "xlsx", "odp", "ods", "pptx", "odg" }; -static const char *arts[] = { "xcf" }; static Rule rules[] = { {"mpv", videos, LEN(videos) }, @@ -56,33 +55,37 @@ static Rule rules[] = { }; static Key keys[] = { - { {.ch = 'j'}, move_down }, - { {.ch = 'k'}, move_up }, - { {.ch = 'l'}, move_for }, - { {.ch = 'h'}, move_back }, - { {.ch = 'g'}, move_top }, - { {.ch = 'G'}, move_bottom }, - { {.ch = 'M'}, move_mid }, - { {.key = TB_KEY_CTRL_U}, scroll_up}, - { {.key = TB_KEY_CTRL_D}, scroll_down}, - { {.ch = 'n'}, create_nf }, - { {.ch = 'N'}, create_nd }, - { {.ch = 'D'}, delete_fd }, - { {.ch = 'x'}, calc_dir }, - { {.ch = '/'}, filter}, - { {.ch = 'q'}, quit}, - { {.key = TB_KEY_SPACE}, switch_pane}, + { {.ch = 'j'}, mvdwn }, + { {.ch = 'k'}, mvup }, + { {.ch = 'l'}, mvfor }, + { {.ch = 'h'}, mvbk }, + { {.ch = 'g'}, mvtop }, + { {.ch = 'G'}, mvbtm }, + { {.ch = 'M'}, mvmid }, + { {.key = TB_KEY_CTRL_U}, scrup }, + { {.key = TB_KEY_CTRL_D}, scrdwn }, + { {.ch = 'n'}, crnf }, + { {.ch = 'N'}, crnd }, + { {.ch = 'D'}, delfd }, + { {.ch = 'x'}, calcdir }, + { {.ch = '/'}, filter }, + { {.ch = 'q'}, quit }, + { {.key = TB_KEY_SPACE}, switch_pane }, }; -static const size_t move_ud = 10; /* ctrl U, ctrl D movement */ static const mode_t new_dir_perm = 0755; +/* scroll */ +static const size_t scrmv = 10; /* ctrl+u, ctrl+d movement */ +static const size_t scrsp = 3; /* space before scroll */ + /* statusbar */ -static const int show_ug = 1; -static const int show_perm = 1; -static const int show_dt = 1; -static const int show_size = 1; -static const char dt_fmt[] = "%d/%m %I:%M%p"; /* date time format */ +static const int show_ug = 1; +static const int show_perm = 1; +static const int show_dt = 1; +static const int show_size = 1; +static const char dtfmt[] = "%d/%m %I:%M%p"; /* date time format */ +// static const char dtfmt[] = "%F %R"; /* date time format */ /* unicode chars */ static const uint32_t u_cne = 0x2510; diff --git a/sfm.c b/sfm.c @@ -56,6 +56,7 @@ typedef struct { int dirx; // pane cwd x pos size_t dirc; // dir entries sum size_t hdir; // highlighted dir + size_t firstrow; uint16_t dir_bg; uint16_t dir_fg; } Pane; @@ -88,52 +89,54 @@ static void print_status(uint16_t, uint16_t, const char*, ...); static void print_xstatus(char, int); static void print_error(char*); static void print_prompt(char*); +static void print_info(void); +static void print_row(Pane*, size_t, uint16_t, uint16_t); static void clear(int, int, int, uint16_t); static void clear_status(void); static void clear_pane(int); -static void print_row(Pane*, int, int16_t, int16_t); static void add_hi(Pane*, size_t); static void rm_hi(Pane*, size_t); -static char *get_extentions(char*); -static char *get_full_path(char*, char*); -static char *get_file_info(Entry*); -static char *get_file_size(off_t); -static void get_dir_size(char*, off_t*); -static char *get_file_date_time(time_t); -static char *get_file_userowner(uid_t, size_t); -static char *get_file_groupowner(gid_t, size_t); -static char *get_file_perm(mode_t); -static void grabkeys(struct tb_event*); -static void move_up(void); -static void move_down(void); -static void move_back(void); -static void move_for(void); -static void move_top(void); -static void move_bottom(void); -static void move_mid(void); -static void scroll_up(void); -static void scroll_down(void); -static void create_nf(void); -static void create_nd(void); -static void delete_fd(void); -static void calc_dir(void); -static void filter(void); -static void switch_pane(void); -static void quit(void); -static int create_new_dir(char*, char*); -static int create_new_file(char*, char*); -static int delete_ent(char *fullpath); -static int delete_file(char*); -static int delete_dir(char*, int); +static void float_to_string(float, char*); static int check_dir(char*); -static mode_t chech_execf(mode_t mode); -static int open_files(char*); +static mode_t chech_execf(mode_t); static int sort_name(const void *const, const void *const); -static void float_to_string(float, char*); +static char *get_ext(char*); +static char *get_fdt(time_t); +static char *get_fgrp(gid_t, size_t); +static char *get_finfo(Entry*); +static char *get_fperm(mode_t); +static char *get_fsize(off_t); +static char *get_fullpath(char*, char*); +static char *get_fusr(uid_t, size_t); +static void get_dirsize(char*, off_t*); +static void get_hicol(uint16_t*, uint16_t*, mode_t); +static int deldir(char*, int); +static int delent(char *); +static int delf(char*); +static void calcdir(void); +static void crnd(void); +static void crnf(void); +static void delfd(void); +static void mvbk(void); +static void mvbtm(void); +static void mvdwn(void); +static void mvdwns(void); +static void mvfor(void); +static void mvmid(void); +static void mvtop(void); +static void mvup(void); +static void mvups(void); +static void scrdwn(void); +static void scrdwns(void); +static void scrup(void); +static void scrups(void); +static int get_usrinput(char*, size_t, char*); +static int open_files(char*); static ssize_t findbm(char); -static int get_user_input(char*, size_t, char*); -static void print_col(Entry*, size_t, size_t, size_t, int, int); -static size_t scroll(size_t, size_t, size_t); +static void filter(void); +static void switch_pane(void); +static void quit(void); +static void grabkeys(struct tb_event*); static void start_ev(void); static void refresh_pane(void); static int listdir(char*); @@ -145,6 +148,8 @@ static int start(void); /* global variables */ static Pane pane_r, pane_l, *cpane; static int parent_row = 1; // FIX +static size_t scrheight; + static const uint32_t INOTIFY_MASK = IN_CREATE | IN_DELETE | IN_DELETE_SELF \ | IN_MODIFY | IN_MOVE_SELF | IN_MOVED_FROM | IN_MOVED_TO; @@ -213,6 +218,41 @@ print_prompt(char *prompt) } static void +print_info(void) +{ + char *fileinfo; + fileinfo = get_finfo(&cpane->direntr[cpane->hdir-1]); + print_status(status_f, status_b, "%lu/%lu %s", + cpane->hdir, cpane->dirc, fileinfo); + free(fileinfo); +} + +static void +print_row(Pane *pane, size_t entpos, uint16_t fg, uint16_t bg) +{ + int x, y; + char *result; + char buf[MAX_P]; + char lnk_full[MAX_P]; + int width; + + width = (tb_width() / 2) - 4; + result = pane->direntr[entpos].name; + x = pane->dirx; + y = entpos - cpane->firstrow + 1; + + if (S_ISLNK(pane->direntr[entpos].mode) && + realpath(pane->direntr[entpos].name, buf) != NULL) { + strncpy(lnk_full, pane->direntr[entpos].name, MAX_N); + strcat(lnk_full, " -> "); + strncat(lnk_full, buf, MAX_N); + result = lnk_full; + } + + printf_tb(x, y, fg, bg, "%*.*s", ~width, width, result); +} + +static void clear(int sx, int ex, int y, uint16_t bg) { /* clear line from to */ @@ -242,7 +282,7 @@ clear_pane(int pane) height = tb_height(); x = 0, y = 0, i = 0, ex = 0; - if (pane == 2){ + if (pane == 2) { x = 2; ex = (width/2) - 1; } else if (pane == (width/2) + 2) { @@ -263,35 +303,130 @@ clear_pane(int pane) } static void -print_row(Pane *pane, int entpos, int16_t fg, int16_t bg) +add_hi(Pane *pane, size_t entpos) { - int x, y; - char *result; - int width; - - width = (tb_width() / 2) - 4; - result = pane->direntr[entpos-1].name; - x = pane->dirx; - y = entpos; - - printf_tb(x, y, fg, bg, "%*.*s", ~width, width, result); + uint16_t fg, bg; + get_hicol(&fg, &bg, pane->direntr[entpos].mode); + print_row(pane, entpos, fg|TB_REVERSE|TB_BOLD, bg|TB_REVERSE); } static void -add_hi(Pane *pane, size_t entpos) +rm_hi(Pane *pane, size_t entpos) { - print_row(pane, entpos, - TB_DEFAULT|TB_REVERSE|TB_BOLD, TB_DEFAULT|TB_REVERSE); + uint16_t fg, bg; + get_hicol(&fg, &bg, pane->direntr[entpos].mode); + print_row(pane, entpos, fg, bg); } static void -rm_hi(Pane *pane, size_t entpos) +float_to_string(float f, char *r) +{ + int length, length2, i, number, position, tenth; /* length is size of decimal part, length2 is size of tenth part */ + float number2; + + f = (float)(int)(f * 10) / 10; + + number2 = f; + number = (int)f; + length2 = 0; + tenth = 1; + + /* Calculate length2 tenth part */ + while ((number2 - (float)number) != 0.0 && !((number2 - (float)number) < 0.0)) + { + tenth *= 10.0; + number2 = f * (float)tenth; + number = (int)number2; + + length2++; + } + + /* Calculate length decimal part */ + for (length = (f > 1.0) ? 0 : 1; f > 1.0; length++) + f /= 10.0; + + position = length; + length = length + 1 + length2; + number = (int)number2; + + if (length2 > 0) + { + for (i = length; i >= 0; i--) + { + if (i == (length)) + r[i] = '\0'; + else if (i == (position)) + r[i] = '.'; + else + { + r[i] = (char)(number % 10) + '0'; + number /= 10; + } + } + } + else + { + length--; + for (i = length; i >= 0; i--) + { + if (i == (length)) + r[i] = '\0'; + else + { + r[i] = (char)(number % 10) + '0'; + number /= 10; + } + } + } +} + +static int +check_dir(char *path) +{ + DIR *dir; + dir = opendir(path); + + if (dir == NULL) { + if (errno == ENOTDIR) { + return 1; + } else { + return -1; + } + } + + if (closedir(dir) < 0) + return -1; + + return 0; +} + +static mode_t +chech_execf(mode_t mode) +{ + if (S_ISREG(mode)) + return (((S_IXUSR | S_IXGRP | S_IXOTH) & mode)); + return 0; +} + +static int +sort_name(const void *const A, const void *const B) { - print_row(pane, entpos, TB_DEFAULT, TB_DEFAULT); + int result; + mode_t data1 = (*(Entry*) A).mode; + mode_t data2 = (*(Entry*) B).mode; + + if (data1 < data2) { + return -1; + } else if (data1 == data2) { + result = strcmp((*(Entry*) A).name,(*(Entry*) B).name); + return result; + } else { + return 1; + } } static char * -get_extentions(char *str) +get_ext(char *str) { char *ext; char dot; @@ -315,27 +450,42 @@ get_extentions(char *str) } static char * -get_full_path(char *first, char *second) +get_fdt(time_t status) { - char *full_path; - size_t full_path_len; - - full_path_len = strlen(first) + strlen(second) + 2; - full_path = ecalloc(full_path_len, sizeof(char)); + char *result; + struct tm lt; + size_t result_len; - if (strcmp(first, "/") == 0) { - (void)snprintf(full_path, full_path_len, "/%s", second); + result_len = (size_t)14; + result = ecalloc(result_len, sizeof(char)); + localtime_r(&status, &lt); - } else { - (void)snprintf( - full_path, full_path_len, "%s/%s", first, second); + if (strftime(result, result_len, dtfmt, &lt) != sizeof(dtfmt)-1) { + free(result); + return NULL; } - return full_path; + return result; +} + +static char * +get_fgrp(gid_t status, size_t len) +{ + char *result; + struct group *gr; + + result = ecalloc(len, sizeof(char)); + gr = getgrgid(status); + if (gr == NULL) + (void)snprintf(result, len-1, "%d", (int)status); + else + strncpy(result, gr->gr_name, len-1); + + return result; } static char * -get_file_info(Entry *cursor) +get_finfo(Entry *cursor) { char *size, *result, *ur, *gr, *td, *perm; size_t size_len = (size_t)9; @@ -348,15 +498,15 @@ get_file_info(Entry *cursor) if (show_perm == 1) { - perm = get_file_perm(cursor->mode); + perm = get_fperm(cursor->mode); strncpy(result, perm, perm_len); strcat(result, " "); free(perm); } if (show_ug == 1) { - ur = get_file_userowner(cursor->user, ur_len); - gr = get_file_groupowner(cursor->group, gr_len); + ur = get_fusr(cursor->user, ur_len); + gr = get_fgrp(cursor->group, gr_len); strncat(result, ur, ur_len); strcat(result, ":"); strncat(result, gr, gr_len); @@ -367,14 +517,14 @@ get_file_info(Entry *cursor) if (show_dt == 1) { - td = get_file_date_time(cursor->td); + td = get_fdt(cursor->td); strncat(result, td, td_len); strcat(result, " "); free(td); } if (show_size == 1 && S_ISREG(cursor->mode)) { - size = get_file_size(cursor->size); + size = get_fsize(cursor->size); strncat(result, size, size_len); free(size); } @@ -382,47 +532,42 @@ get_file_info(Entry *cursor) return result; } -static void -get_dir_size(char *fullpath, off_t *fullsize) +static char * +get_fperm(mode_t mode) { - DIR *dir; - char *ent_full; - mode_t mode; - struct dirent *entry; - struct stat status; - - dir = opendir(fullpath); - if (dir == NULL) - { - return; - } + char *buf; + size_t i; - while ((entry = readdir(dir)) != 0) - { - if ((strcmp(entry->d_name, ".") == 0 || - strcmp(entry->d_name, "..") == 0)) - continue; + const char chars[] = "rwxrwxrwx"; + buf = ecalloc((size_t)11, sizeof(char)); - ent_full = get_full_path(fullpath, entry->d_name); - if (lstat(ent_full, &status) == 0) { - mode = status.st_mode; - if (S_ISDIR(mode)) { - get_dir_size(ent_full, fullsize); - free(ent_full); - } else { + 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] = '?'; - *fullsize += status.st_size; - free(ent_full); - } - } + for (i = 1; i < 10; i++) { + buf[i] = (mode & (1 << (9-i))) ? chars[i-1] : '-'; } + buf[10] = '\0'; - closedir(dir); - clear_status(); + return buf; } static char * -get_file_size(off_t size) +get_fsize(off_t size) { /* need to be freed */ @@ -465,26 +610,27 @@ get_file_size(off_t size) } static char * -get_file_date_time(time_t status) +get_fullpath(char *first, char *second) { - char *result; - struct tm lt; - size_t result_len; + char *full_path; + size_t full_path_len; - result_len = (size_t)14; - result = ecalloc(result_len, sizeof(char)); - localtime_r(&status, &lt); + full_path_len = strlen(first) + strlen(second) + 2; + full_path = ecalloc(full_path_len, sizeof(char)); - if (strftime(result, result_len, dt_fmt, &lt) != sizeof(dt_fmt)-1) { - free(result); - return NULL; + if (strcmp(first, "/") == 0) { + (void)snprintf(full_path, full_path_len, "/%s", second); + + } else { + (void)snprintf( + full_path, full_path_len, "%s/%s", first, second); } - return result; + return full_path; } static char * -get_file_userowner(uid_t status, size_t len) +get_fusr(uid_t status, size_t len) { char *result; struct passwd *pw; @@ -499,337 +645,69 @@ get_file_userowner(uid_t status, size_t len) return result; } -static char * -get_file_groupowner(gid_t status, size_t len) -{ - char *result; - struct group *gr; - - result = ecalloc(len, sizeof(char)); - gr = getgrgid(status); - if (gr == NULL) - (void)snprintf(result, len-1, "%d", (int)status); - else - strncpy(result, gr->gr_name, len-1); - - return result; -} - -static char * -get_file_perm(mode_t mode) -{ - char *buf; - size_t i; - - const char chars[] = "rwxrwxrwx"; - buf = ecalloc((size_t)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 void -grabkeys(struct tb_event *event) +get_dirsize(char *fullpath, off_t *fullsize) { - size_t i; - for (i = 0; i < LEN(keys); i++) { - if (event->ch == keys[i].evkey.ch || - event->key == keys[i].evkey.key) { - keys[i].func(); - return; - } - } -} - -static void -move_up(void) -{ - if (cpane->hdir > 1) { - cpane->hdir--; - refresh_pane(); - } -} - -static void -move_down(void) -{ - if (cpane->hdir < cpane->dirc) { - cpane->hdir++; - refresh_pane(); - } -} - -static void -move_back(void) -{ - chdir(".."); - getcwd(cpane->dirn, MAX_P); - cpane->hdir = parent_row; - listdir(NULL); - parent_row = 1; -} - -static void -move_for(void) -{ - switch (check_dir(cpane->direntr[cpane->hdir-1].name)) { - case 0: - chdir(cpane->direntr[cpane->hdir-1].name); - getcwd(cpane->dirn, MAX_P); - parent_row = (int)cpane->hdir; - cpane->hdir = 1; - (void)listdir(NULL); - break; - case 1: - /* is not a directory open file */ - if (open_files(cpane->direntr[cpane->hdir-1].name) < 0) { - print_error("procces failed"); - return; - } - if (tb_init() != 0) - die("tb_init"); - t_resize(); - break; - case -1: - /* failed to open directory */ - print_error(strerror(errno)); - } -} - -static void -move_top(void) -{ - cpane->hdir = 1; - refresh_pane(); -} - -static void -move_bottom(void) -{ - cpane->hdir = cpane->dirc; - refresh_pane(); -} - -static void -move_mid(void) -{ - cpane->hdir = (cpane->dirc/2); - refresh_pane(); -} - -static void -scroll_up(void) -{ - if (cpane->hdir > move_ud) - cpane->hdir = cpane->hdir - move_ud; - else - cpane->hdir = 1; - refresh_pane(); -} - -static void -scroll_down(void) -{ - if (cpane->hdir < cpane->dirc - move_ud) - cpane->hdir = cpane->hdir + move_ud; - else - cpane->hdir = cpane->dirc; - refresh_pane(); -} - -static void -calc_dir(void) -{ - if (S_ISDIR(cpane->direntr[cpane->hdir-1].mode)) { - off_t *fullsize = ecalloc(50, sizeof(off_t)); - get_dir_size(cpane->direntr[cpane->hdir-1].name, fullsize); - char *csize = get_file_size(*fullsize); - char *result = get_file_info(&cpane->direntr[cpane->hdir-1]); - clear_status(); - print_status(status_f, status_b, "%lu/%lu %s%s", - cpane->hdir, - cpane->dirc, - result, csize); - free(csize); - free(fullsize); - free(result); - } -} - -static void -create_nf(void) -{ - char *user_input; - user_input = ecalloc(MAX_USRI, sizeof(char)); - if (get_user_input(user_input, MAX_USRI, "new file") < 0) { - free(user_input); - return; - } - if (create_new_file(cpane->dirn, user_input) < 0) { - print_error(strerror(errno)); - } else { - listdir(NULL); - } - free(user_input); -} + DIR *dir; + char *ent_full; + mode_t mode; + struct dirent *entry; + struct stat status; -static void -create_nd(void) -{ - char *user_input; - user_input = ecalloc(MAX_USRI, sizeof(char)); - if (get_user_input(user_input, MAX_USRI, "new directory") < 0) { - free(user_input); + dir = opendir(fullpath); + if (dir == NULL) + { return; } - if (create_new_dir(cpane->dirn, user_input) < 0) { - print_error(strerror(errno)); - } else { - listdir(NULL); - } - free(user_input); -} + while ((entry = readdir(dir)) != 0) + { + if ((strcmp(entry->d_name, ".") == 0 || + strcmp(entry->d_name, "..") == 0)) + continue; -static void -delete_fd(void) -{ - switch (delete_ent(cpane->direntr[cpane->hdir-1].name)) { - case -1: - print_error(strerror(errno)); - break; - case 0: - if (cpane->hdir == cpane->dirc) /* last entry */ - cpane->hdir--; - listdir(NULL); - break; - } -} + 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 { -static void -filter(void) -{ - char *user_input; - user_input = ecalloc(MAX_USRI, sizeof(char)); - if (get_user_input(user_input, MAX_USRI, "filter") < 0) { - free(user_input); - return; - } - if (listdir(user_input) < 0) { - print_error("no match"); + *fullsize += status.st_size; + free(ent_full); + } + } } - free(user_input); -} -static void -switch_pane(void) -{ - if (cpane == &pane_l) { - rm_hi(&pane_l, pane_l.hdir); - add_hi(&pane_r, pane_r.hdir); - chdir(pane_r.dirn); - cpane = &pane_r; - } else if (cpane == &pane_r) { - rm_hi(&pane_r, pane_r.hdir); - add_hi(&pane_l, pane_l.hdir); - chdir(pane_l.dirn); - cpane = &pane_l; - } + closedir(dir); + clear_status(); } static void -quit(void) -{ - free(pane_l.direntr); - free(pane_r.direntr); - tb_shutdown(); - exit(EXIT_SUCCESS); -} - -static int -create_new_dir(char *cwd, char *user_input) -{ - char *path; - path = ecalloc(strlen(cwd)+strlen(user_input)+2, sizeof(char)); - strcpy(path, cwd); - strcat(path, "/"); - strcat(path, user_input); - - if(mkdir(path, new_dir_perm) < 0) { - free(path); - return -1; - } - - free(path); - return 0; -} - -static int -create_new_file(char *cwd, char *user_input) -{ - int rf; - char *path; - path = ecalloc(strlen(cwd)+strlen(user_input)+2, sizeof(char)); - strcpy(path, cwd); - strcat(path, "/"); - strcat(path, user_input); - - rf = open(path, O_CREAT|O_EXCL, S_IRUSR|S_IWUSR); - free(path); - if (rf < 0) - return -1; - - if (close(rf) < 0) - return -1; - return 0; -} - -static int -delete_ent(char *fullpath) +get_hicol(uint16_t *fg, uint16_t *bg, mode_t mode) { - struct stat status; - mode_t mode; - - if (lstat(fullpath, &status) < 0) - return -1; - - mode = status.st_mode; - if(S_ISDIR(mode)) { - return delete_dir(fullpath, (int)AskDel); - } else { - return delete_file(fullpath); + *bg = file_b; + *fg = file_f; + + if (S_ISDIR(mode)) { + *bg = dir_b; + *fg = dir_f; + } else if (S_ISLNK(mode)) { + *bg = other_b; + *fg = other_f; + } else if (chech_execf(mode) > 0) { + *fg = exec_f; } - } static int -delete_dir(char *fullpath, int delchoice) +deldir(char *fullpath, int delchoice) { if (delchoice == (int)AskDel) { char *confirmation; confirmation = ecalloc((size_t)2, sizeof(char)); - if ((get_user_input( + if ((get_usrinput( confirmation, (size_t)2,"delete directory (Y) ?") < 0) || (strcmp(confirmation, "Y") != 0)) { free(confirmation); @@ -857,11 +735,11 @@ delete_dir(char *fullpath, int delchoice) strcmp(entry->d_name, "..") == 0)) continue; - ent_full = get_full_path(fullpath, entry->d_name); + ent_full = get_fullpath(fullpath, entry->d_name); if (lstat(ent_full, &status) == 0) { mode = status.st_mode; if (S_ISDIR(mode)) { - if (delete_dir(ent_full, (int)DAskDel) < 0) { + if (deldir(ent_full, (int)DAskDel) < 0) { free(ent_full); return -1; } @@ -883,12 +761,30 @@ delete_dir(char *fullpath, int delchoice) } static int -delete_file(char *fullpath) +delent(char *fullpath) +{ + struct stat status; + mode_t mode; + + if (lstat(fullpath, &status) < 0) + return -1; + + mode = status.st_mode; + if (S_ISDIR(mode)) { + return deldir(fullpath, (int)AskDel); + } else { + return delf(fullpath); + } + +} + +static int +delf(char *fullpath) { char *confirmation; confirmation = ecalloc((size_t)2, sizeof(char)); - if ((get_user_input(confirmation, (size_t)2, "delete file (Y) ?") < 0) || + if ((get_usrinput(confirmation, (size_t)2, "delete file (Y) ?") < 0) || (strcmp(confirmation, "Y") != 0)) { free(confirmation); return 1; /* canceled by user or wrong confirmation */ @@ -898,188 +794,349 @@ delete_file(char *fullpath) return unlink(fullpath); } -static int -check_dir(char *path) +static void +calcdir(void) { - DIR *dir; - dir = opendir(path); + off_t *fullsize; + char *csize; + char *result; - if (dir == NULL) { - if (errno == ENOTDIR) { - return 1; - } else { - return -1; - } + if (S_ISDIR(cpane->direntr[cpane->hdir-1].mode)) { + fullsize = ecalloc(50, sizeof(off_t)); + get_dirsize(cpane->direntr[cpane->hdir-1].name, fullsize); + csize = get_fsize(*fullsize); + result = get_finfo(&cpane->direntr[cpane->hdir-1]); + + clear_status(); + print_status(status_f, status_b, "%lu/%lu %s%s", + cpane->hdir, cpane->dirc, result, csize); + free(csize); + free(fullsize); + free(result); } +} - if (closedir(dir) < 0) - return -1; +static void +crnd(void) +{ + char *user_input, *path; + size_t pathlen; - return 0; + user_input = ecalloc(MAX_USRI, sizeof(char)); + if (get_usrinput(user_input, MAX_USRI, "new file") < 0) { + free(user_input); + return; + } + + pathlen = strlen(cpane->dirn) + 1 + MAX_USRI + 1; + path = ecalloc(pathlen, sizeof(char)); + if (snprintf(path, pathlen, "%s/%s", cpane->dirn, user_input) < 0) { + free(user_input); + free(path); + return; + } + + if (mkdir(path, new_dir_perm) < 0) + print_error(strerror(errno)); + else + listdir(NULL); + + free(user_input); + free(path); } -static mode_t -chech_execf(mode_t mode) +static void +crnf(void) { - if (S_ISREG(mode)) - return (((S_IXUSR | S_IXGRP | S_IXOTH) & mode)); - return 0; + char *user_input, *path; + size_t pathlen; + int rf; + + user_input = ecalloc(MAX_USRI, sizeof(char)); + if (get_usrinput(user_input, MAX_USRI, "new file") < 0) { + free(user_input); + return; + } + + pathlen = strlen(cpane->dirn) + 1 + MAX_USRI + 1; + path = ecalloc(pathlen, sizeof(char)); + if (snprintf(path, pathlen, "%s/%s", cpane->dirn, user_input) < 0) { + free(user_input); + free(path); + return; + } + + rf = open(path, O_CREAT|O_EXCL, S_IRUSR|S_IWUSR); + + if (rf < 0) { + print_error(strerror(errno)); + } else { + if (close(rf) < 0) + print_error(strerror(errno)); + else + listdir(NULL); + } + + free(user_input); + free(path); } -static int -open_files(char *filename) +static void +delfd(void) { - // TODO - /* open editor in other window */ - /* wait option */ - char *editor, *file_ex, *software, *term; - int status; - size_t d, c; - pid_t pid, r; + switch (delent(cpane->direntr[cpane->hdir-1].name)) { + case -1: + print_error(strerror(errno)); + break; + case 0: + if (cpane->hdir == cpane->dirc) /* last entry */ + cpane->hdir--; + listdir(NULL); + break; + } +} - editor = getenv("EDITOR"); - term = getenv("TERM"); - file_ex = get_extentions(filename); - software = NULL; +static void +mvbk(void) +{ + chdir(".."); + getcwd(cpane->dirn, MAX_P); + cpane->firstrow = 0; + cpane->hdir = parent_row; + listdir(NULL); + parent_row = 1; + add_hi(cpane, cpane->hdir-1); +} - /* find software in rules */ - for (c = 0; c < LEN(rules); c++) { - for (d = 0; d < rules[c].len; d++){ - if (strcmp(rules[c].ext[d], file_ex) == 0) { - software = rules[c].soft; - } - } +static void +mvbtm(void) +{ + if (cpane->dirc > scrheight) { + clear_pane(cpane->dirx); + rm_hi(cpane, cpane->hdir-1); + cpane->hdir = cpane->dirc; + cpane->firstrow = cpane->dirc - scrheight + 1; + refresh_pane(); + add_hi(cpane, cpane->hdir-1); + } else { + rm_hi(cpane, cpane->hdir-1); + cpane->hdir = cpane->dirc; + add_hi(cpane, cpane->hdir-1); } + print_info(); +} - /* default softwares */ - if (term == NULL) - term = "xterm-256color"; - if (editor == NULL) - editor = "vi"; - if (software == NULL) - software = editor; +static void +mvdwn(void) +{ + if (cpane->dirc < scrheight && cpane->hdir < cpane->dirc) { + rm_hi(cpane, cpane->hdir-1); + cpane->hdir++; + add_hi(cpane, cpane->hdir-1); + } else { + mvdwns(); /* scroll */ + } + print_info(); +} - free(file_ex); - char *filex[] = {software, filename, NULL}; - tb_shutdown(); - pid = fork(); +static void +mvdwns(void) +{ + size_t real; + real= cpane->hdir - 1 - cpane->firstrow; - switch (pid) { + if (real > scrheight - 3 - scrsp && cpane->hdir + scrsp < cpane->dirc) { + cpane->firstrow++; + clear_pane(cpane->dirx); + rm_hi(cpane, cpane->hdir-1); + cpane->hdir++; + refresh_pane(); + add_hi(cpane, cpane->hdir-1); + } else if (cpane->hdir < cpane->dirc) { + rm_hi(cpane, cpane->hdir-1); + cpane->hdir++; + add_hi(cpane, cpane->hdir-1); + } +} + +static void +mvfor(void) +{ + switch (check_dir(cpane->direntr[cpane->hdir-1].name)) { + case 0: + chdir(cpane->direntr[cpane->hdir-1].name); + getcwd(cpane->dirn, MAX_P); + parent_row = (int)cpane->hdir; + cpane->hdir = 1; + cpane->firstrow = 0; + (void)listdir(NULL); + add_hi(cpane, cpane->hdir-1); + break; + case 1: + /* is not a directory open file */ + if (open_files(cpane->direntr[cpane->hdir-1].name) < 0) { + print_error("procces failed"); + return; + } + if (tb_init() != 0) + die("tb_init"); + t_resize(); + break; case -1: - return -1; - case 0: - (void)execvp(filex[0], filex); - exit(EXIT_SUCCESS); - default: - while ((r = waitpid(pid, &status, 0)) == (pid_t)-1 && errno == EINTR) - continue; - if (r == (pid_t)-1) - return -1; - if ((WIFEXITED(status) != 0) && (WEXITSTATUS(status) != 0)) - return -1; + /* failed to open directory */ + print_error(strerror(errno)); } - - return 0; } -static int -sort_name(const void *const A, const void *const B) +static void +mvmid(void) { - int result; - mode_t data1 = (*(Entry*) A).mode; - mode_t data2 = (*(Entry*) B).mode; + rm_hi(cpane, cpane->hdir - 1); + cpane->hdir = (scrheight / 2) + cpane->firstrow; + add_hi(cpane, cpane->hdir - 1); + print_info(); +} - if (data1 < data2) { - return -1; - } else if (data1 == data2) { - result = strcmp((*(Entry*) A).name,(*(Entry*) B).name); - return result; +static void +mvtop(void) +{ + if (cpane->dirc > scrheight) { + clear_pane(cpane->dirx); + rm_hi(cpane, cpane->hdir-1); + cpane->hdir = 1; + cpane->firstrow = 0; + refresh_pane(); + add_hi(cpane, cpane->hdir-1); } else { - return 1; + rm_hi(cpane, cpane->hdir-1); + cpane->hdir = 1; + add_hi(cpane, cpane->hdir-1); + print_info(); } } static void -float_to_string(float f, char *r) +mvup(void) { - int length, length2, i, number, position, tenth; /* length is size of decimal part, length2 is size of tenth part */ - float number2; - - f = (float)(int)(f * 10) / 10; - - number2 = f; - number = (int)f; - length2 = 0; - tenth = 1; + if (cpane->dirc < scrheight && cpane->hdir > 1) { + rm_hi(cpane, cpane->hdir-1); + cpane->hdir--; + add_hi(cpane, cpane->hdir-1); + } else { + mvups(); /* scroll */ + } + print_info(); +} - /* Calculate length2 tenth part */ - while ((number2 - (float)number) != 0.0 && !((number2 - (float)number) < 0.0)) - { - tenth *= 10.0; - number2 = f * (float)tenth; - number = (int)number2; +static void +mvups(void) +{ + size_t real; + real= cpane->hdir - 1 - cpane->firstrow; - length2++; + if (cpane->firstrow > 0 && real < 1 + scrsp) { + cpane->firstrow--; + clear_pane(cpane->dirx); + rm_hi(cpane, cpane->hdir-1); + cpane->hdir--; + refresh_pane(); + add_hi(cpane, cpane->hdir-1); + } else if (cpane->hdir > 1) { + rm_hi(cpane, cpane->hdir-1); + cpane->hdir--; + add_hi(cpane, cpane->hdir-1); } +} - /* Calculate length decimal part */ - for (length = (f > 1.0) ? 0 : 1; f > 1.0; length++) - f /= 10.0; - - position = length; - length = length + 1 + length2; - number = (int)number2; +static void +scrdwn(void) +{ + if (cpane->dirc < scrheight && cpane->hdir < cpane->dirc) { + if (cpane->hdir < cpane->dirc - scrmv) { + rm_hi(cpane, cpane->hdir-1); + cpane->hdir += scrmv; + add_hi(cpane, cpane->hdir-1); + } else { + mvbtm(); + } + } else { + scrdwns(); + } + print_info(); +} - if (length2 > 0) - { - for (i = length; i >= 0; i--) - { - if (i == (length)) - r[i] = '\0'; - else if (i == (position)) - r[i] = '.'; - else - { - r[i] = (char)(number % 10) + '0'; - number /= 10; - } +static void +scrdwns(void) +{ + size_t real; + int dynmv; + real = cpane->hdir - cpane->firstrow; + dynmv = MIN(cpane->dirc - cpane->hdir - cpane->firstrow , scrmv); + + if (real + scrmv + 1 > scrheight && + cpane->hdir + scrsp + scrmv < cpane->dirc) { /* scroll */ + cpane->firstrow += dynmv; + clear_pane(cpane->dirx); + rm_hi(cpane, cpane->hdir-1); + cpane->hdir += scrmv; + refresh_pane(); + add_hi(cpane, cpane->hdir-1); + } else { + if (cpane->hdir < cpane->dirc - scrmv) { + rm_hi(cpane, cpane->hdir-1); + cpane->hdir += scrmv; + add_hi(cpane, cpane->hdir-1); + } else { + mvbtm(); } } - else - { - length--; - for (i = length; i >= 0; i--) - { - if (i == (length)) - r[i] = '\0'; - else - { - r[i] = (char)(number % 10) + '0'; - number /= 10; - } +} + +static void +scrup(void) +{ + if (cpane->dirc < scrheight && cpane->hdir > 1) { + if (cpane->hdir > scrmv) { + rm_hi(cpane, cpane->hdir-1); + cpane->hdir = cpane->hdir - scrmv; + add_hi(cpane, cpane->hdir-1); + print_info(); + } else { + mvtop(); } + } else { + scrups(); } } -static ssize_t -findbm(char event) +static void +scrups(void) { - ssize_t i; + size_t real; + int dynmv; + real = cpane->hdir - cpane->firstrow; + dynmv = MIN(cpane->firstrow , scrmv); - for (i = 0; i < (ssize_t)LEN(bmarks); i++) { - if (event == bmarks[i].key) { - if (check_dir(bmarks[i].path) != 0) { - print_error(strerror(errno)); - return -1; - } - return i; + if (cpane->firstrow > 0 && real < scrmv + scrsp) { + cpane->firstrow -= dynmv; + clear_pane(cpane->dirx); + rm_hi(cpane, cpane->hdir-1); + cpane->hdir -= scrmv; + refresh_pane(); + add_hi(cpane, cpane->hdir-1); + } else { + if (cpane->hdir > scrmv + 1) { + rm_hi(cpane, cpane->hdir-1); + cpane->hdir -= scrmv; + add_hi(cpane, cpane->hdir-1); + } else { + mvtop(); } } - return -1; } static int -get_user_input(char *out, size_t sout, char *prompt) +get_usrinput(char *out, size_t sout, char *prompt) { int height = tb_height(); size_t startat; @@ -1141,61 +1198,138 @@ get_user_input(char *out, size_t sout, char *prompt) } -static void -print_col(Entry *entry, size_t hdir, size_t x, size_t y, int dyn_y, int width) +static int +open_files(char *filename) { - uint16_t bg, fg; - char buf[MAX_P]; - char lnk_full[MAX_P]; - char *result; + // TODO + /* open editor in other window */ + /* wait option */ + char *editor, *file_ex, *software, *term; + int status; + size_t d, c; + pid_t pid, r; - bg = file_b; - fg = file_f; + editor = getenv("EDITOR"); + term = getenv("TERM"); + file_ex = get_ext(filename); + software = NULL; - result = entry->name; - if (S_ISDIR(entry->mode)) { - bg = dir_b; - fg = dir_f; - } else if (S_ISLNK(entry->mode) && realpath(entry->name, buf) != NULL) { - strncpy(lnk_full, entry->name, MAX_N); - strcat(lnk_full, " -> "); - strncat(lnk_full, buf, MAX_N); - bg = other_b; - fg = other_f; - result = lnk_full; + /* find software in rules */ + for (c = 0; c < LEN(rules); c++) { + for (d = 0; d < rules[c].len; d++) { + if (strcmp(rules[c].ext[d], file_ex) == 0) { + software = rules[c].soft; + } + } } - /* highlight executable files */ - if (chech_execf(entry->mode) > 0) - fg = exec_f; + /* default softwares */ + if (term == NULL) + term = "xterm-256color"; + if (editor == NULL) + editor = "vi"; + if (software == NULL) + software = editor; + + free(file_ex); + char *filex[] = {software, filename, NULL}; + tb_shutdown(); + pid = fork(); - /* highlighted (cursor) */ - if (y + dyn_y == hdir) { - bg = bg | TB_REVERSE; - fg = fg | TB_REVERSE | TB_BOLD; + switch (pid) { + case -1: + return -1; + case 0: + (void)execvp(filex[0], filex); + exit(EXIT_SUCCESS); + default: + while ((r = waitpid(pid, &status, 0)) == (pid_t)-1 && errno == EINTR) + continue; + if (r == (pid_t)-1) + return -1; + if ((WIFEXITED(status) != 0) && (WEXITSTATUS(status) != 0)) + return -1; } - /* print each element in directory */ - printf_tb((int)x, (int)y, fg, bg, "%*.*s", ~width, width, result); + return 0; } -static size_t -scroll(size_t height, size_t dirc, size_t hdir) +static ssize_t +findbm(char event) { - size_t result, limit; - - result = 0; - limit = (height -1) / 2; - if (dirc > height - 1) { - if (hdir < limit){ - result = 0; - } else if (hdir > dirc - limit) { - result = dirc - height + 1; - } else { - result = hdir - limit; + ssize_t i; + + for (i = 0; i < (ssize_t)LEN(bmarks); i++) { + if (event == bmarks[i].key) { + if (check_dir(bmarks[i].path) != 0) { + print_error(strerror(errno)); + return -1; + } + return i; + } + } + return -1; +} + +static void +filter(void) +{ + char *user_input; + user_input = ecalloc(MAX_USRI, sizeof(char)); + if (get_usrinput(user_input, MAX_USRI, "filter") < 0) { + free(user_input); + return; + } + if (listdir(user_input) < 0) { + print_error("no match"); + } + free(user_input); +} + +static void +switch_pane(void) +{ + if (cpane == &pane_l) { + rm_hi(&pane_l, pane_l.hdir-1); + add_hi(&pane_r, pane_r.hdir-1); + chdir(pane_r.dirn); + cpane = &pane_r; + } else if (cpane == &pane_r) { + rm_hi(&pane_r, pane_r.hdir-1); + add_hi(&pane_l, pane_l.hdir-1); + chdir(pane_l.dirn); + cpane = &pane_l; + } + print_info(); +} + +static void +quit(void) +{ + free(pane_l.direntr); + free(pane_r.direntr); + tb_shutdown(); + exit(EXIT_SUCCESS); +} + +static void +grabkeys(struct tb_event *event) +{ + size_t i; + + for (i = 0; i < LEN(keys); i++) { + if (event->ch != 0) { + if (event->ch == keys[i].evkey.ch) { + keys[i].func(); + return; + } + } else if (event->key != 0) { + if (event->key == keys[i].evkey.key) { + keys[i].func(); + return; + } } } - return result; } static void @@ -1222,40 +1356,28 @@ start_ev(void) static void refresh_pane(void) { - char *fileinfo; - size_t y, dyn_y, dyn_max, start_from; + size_t y, dyn_max, start_from; int width; width = (tb_width() / 2) - 4; - size_t height = (size_t)tb_height() - 2; + uint16_t fg, bg; - /* scroll */ y = 1; - dyn_y = 0; - start_from = scroll(height, cpane->dirc, cpane->hdir); - dyn_y = start_from; - dyn_max = MIN(cpane->dirc, (height - 1) + start_from); + start_from = cpane->firstrow; + dyn_max = MIN(cpane->dirc, (scrheight - 1) + cpane->firstrow); /* print each entry in directory */ while (start_from < dyn_max) { - print_col(&cpane->direntr[start_from], cpane->hdir, - (size_t)cpane->dirx, y, (int)dyn_y, width); - start_from++; - y++; + get_hicol(&fg, &bg, cpane->direntr[start_from].mode); + print_row(cpane, start_from, fg ,bg); + start_from++; + y++; } - fileinfo = get_file_info(&cpane->direntr[cpane->hdir-1]); - - /* print info in statusbar */ - print_status(status_f, status_b, "%lu/%lu %s", - cpane->hdir, - cpane->dirc, - fileinfo); +// print_info(); /* print current directory title */ printf_tb(cpane->dirx, 0, cpane->dir_fg | TB_BOLD, cpane->dir_bg, " %.*s ", width, cpane->dirn); - - free(fileinfo); } static int @@ -1265,11 +1387,10 @@ listdir(char *filter) struct dirent *entry; struct stat status; int width; - size_t i, height; + size_t i; int filtercount = 0; size_t oldc = cpane->dirc; - height = (size_t)tb_height() - 2; width = (tb_width() / 2) - 4; cpane->dirc = 0; i = 0; @@ -1401,6 +1522,7 @@ set_panes(int resize) int width; char *home; char cwd[MAX_P]; + scrheight = tb_height() - 2; home = getenv("HOME"); width = tb_width(); @@ -1412,6 +1534,7 @@ set_panes(int resize) pane_l.dirx = 2; pane_l.dir_fg = pane_l_f; pane_l.dir_bg = pane_l_b; + pane_l.firstrow = 0; if (resize == 0) { pane_l.direntr = ecalloc(0, sizeof(Entry)); strcpy(pane_l.dirn, cwd); @@ -1421,6 +1544,7 @@ set_panes(int resize) pane_r.dirx = (width / 2) + 2; pane_r.dir_fg = pane_r_f; pane_r.dir_bg = pane_r_b; + pane_r.firstrow = 0; if (resize == 0) { pane_r.direntr = ecalloc(0, sizeof(Entry)); strcpy(pane_r.dirn, home); @@ -1467,17 +1591,16 @@ start(void) if (tb_init()!= 0) die("tb_init"); if (tb_select_output_mode(TB_OUTPUT_256) != TB_OUTPUT_256) - if(tb_select_output_mode(TB_OUTPUT_NORMAL) != TB_OUTPUT_NORMAL) + if (tb_select_output_mode(TB_OUTPUT_NORMAL) != TB_OUTPUT_NORMAL) die("output error"); - tb_clear(); draw_frame(); set_panes(0); cpane = &pane_r; listdir(NULL); cpane = &pane_l; listdir(NULL); - rm_hi(&pane_r, pane_r.hdir); + add_hi(&pane_l, pane_l.hdir-1); tb_present(); start_ev(); return 0;