Thumbnail

rani/cscroll.git

Clone URL: https://git.buni.party/rani/cscroll.git

commit 4f196b5c30fc2261b10ea81cfbcf69f9b76b4162 Author: rani <clagv.randomgames@gmail.com> Date: Wed Dec 31 13:22:17 2025 +0000 Add: handling for entering empty directories and errors on entering directories; Change: cursor returns to correct position when entering the previous directory diff --git a/include/dir.h b/include/dir.h index 132915d..10c6d38 100644 --- a/include/dir.h +++ b/include/dir.h @@ -5812 +5814 @@ typedef struct {  int dir_list(const char * path, dir_t * dir);  void dir_free(dir_t * dir);  const char * dir_get_cwd(void); +int dir_cd_back(const char * cwd); +int dir_cd(const char * cwd, const char * next); +int dir_search_name(const dir_t * dir, const char * name, size_t * idx); +const char * dir_basename(const char * path);  char dirent_crepr(const dirent_t * de); // character representing dir entry  char dirent_creprl(const dirent_t * de); // like above, but for the link  char dirent_longcrepr(const dirent_t * de); // like above, but for long mode  bool dirent_isexec(const dirent_t * de);  const char * dirent_prettymode(const dirent_t * de); -int dir_cd_back(const char * cwd); -int dir_cd(const char * cwd, const char * next);    #endif /* DIR_H */ diff --git a/include/ui.h b/include/ui.h index a59aacd..facf0a5 100644 --- a/include/ui.h +++ b/include/ui.h @@ -287 +288 @@ enum ui_color {  void ui_init(void);  void ui_deinit(void);  void ui_set_title(const char * title); -void ui_set_status(const char * status); +void ui_status_info(const char * status); +void ui_status_error(const char * status);  void ui_erase(void);  void ui_refresh(void);  void ui_print_dir(const dir_t * dir, size_t cursor, bool longmode); diff --git a/src/dir.c b/src/dir.c index 247e502..8a63343 100644 --- a/src/dir.c +++ b/src/dir.c @@ -46 +47 @@  #include <stdlib.h>  #include <string.h>  #include <unistd.h> +#include <errno.h>  #include <fcntl.h>  #include <pwd.h>  #include <grp.h> @@ -146 +159 @@  #define CWDSZ (PATH_MAX + 1)  #define LINKNAMESZ PATH_MAX   +static char cwd_buf[CWDSZ]; +static char * cwd = NULL; +  static void dir_entry(int dirfd, const char * name, dirent_t * dirent);  static char de_crepr(enum de_type de_type);  static void free_dirent(void * p) { @@ -447 +487 @@ int dir_list(const char * path, dir_t * dir) {   struct dirent * de;   DIR * dp = opendir(path);   if (!dp) { - return -1; + return -errno;   }     while ((de = readdir(dp))) { @@ -21617 +22020 @@ const char * dirent_prettymode(const dirent_t * de) {  }    const char * dir_get_cwd(void) { - static char cwd[CWDSZ]; - - getcwd(cwd, CWDSZ); + if (!cwd) { + getcwd(cwd_buf, CWDSZ); + cwd = cwd_buf; + char * p = strrchr(cwd, '/'); + if (*(p + 1) == 0) *p = 0; + }   return cwd;  }   -int dir_cd_back(const char * cwd) { - if (!*cwd) return -1; - if (!strcmp(cwd, "/")) return 0; +int dir_cd_back(const char * wd) { + if (!*wd) return -EPERM; + if (!strcmp(wd, "/")) return 0;   - char * newwd = strdup(cwd); + char * newwd = strdup(wd);   char * p = strrchr(newwd, '/');   *p = 0;   if (*newwd == 0) { @@ -23425 +24151 @@ int dir_cd_back(const char * cwd) {   *(newwd + 1) = 0;   }   int ret = chdir(newwd); + int terrno = errno; + if (ret >= 0) strcpy(cwd, newwd);   free(newwd);   - if (ret < 0) return -1; + if (ret < 0) return -terrno;   return 0;  }   -int dir_cd(const char * cwd, const char * next) { - size_t cwdlen = strlen(cwd); +int dir_cd(const char * wd, const char * next) { + size_t wdlen = strlen(wd);   size_t nextlen = strlen(next);     // extra byte for '/' character - char * newwd = malloc(cwdlen + nextlen + 1 + 1); - strcpy(newwd, cwd); - newwd[cwdlen] = '/'; - strcpy(newwd + cwdlen + 1, next); + char * newwd = malloc(wdlen + nextlen + 1 + 1); + if (strcmp(wd, "/") != 0) { + strcpy(newwd, wd); + newwd[wdlen] = '/'; + strcpy(newwd + wdlen + 1, next); + } else { + newwd[0] = '/'; + strcpy(newwd + 1, next); + }     int ret = chdir(newwd); + int terrno = errno; + if (ret >= 0) strcpy(cwd, newwd);   free(newwd);   - if (ret < 0) return -1; + if (ret < 0) return -terrno;   return 0;  } + +const char * dir_basename(const char * path) { + const char * p = strrchr(path, '/'); + if (!p || *(p + 1) == 0) return NULL; + return p + 1; +} + +int dir_search_name(const dir_t * dir, const char * name, size_t * idx) { + for (size_t i = 0; i < dir->len; i++) { + if (!strcmp(dir->entries[i].name, name)) { + *idx = i; + return 0; + } + } + + return -1; +} diff --git a/src/main.c b/src/main.c index 8948789..017c67d 100644 --- a/src/main.c +++ b/src/main.c @@ -13 +14 @@ +#include <errno.h>  #include <stdio.h>  #include <stddef.h>  #include <ncurses.h> @@ -658 +787 @@  #include "dir.h"    int main(int argc, char ** argv) { - ui_init(); -   const char * cwd = dir_get_cwd();     dir_t dir;   dir_list(cwd, &dir);   + ui_init();   size_t cursor = 0; - ui_set_status(""); + ui_status_info("");   for (;;) {   ui_erase();     ui_set_title(cwd); -   ui_print_dir(&dir, cursor, true);   ui_print_cursor(cursor, dir.len);     ui_refresh();   - dirent_t * cur_de = &dir.entries[cursor]; + dirent_t * cur_de; + if (dir.len == 0) cur_de = NULL; + else cur_de = &dir.entries[cursor];   switch (getch()) {   case KEY_UP:   if (cursor > 0) cursor--; + ui_status_info("");   break;   case KEY_DOWN:   if (cursor < dir.len - 1) cursor++; + ui_status_info("");   break; - case KEY_LEFT: - if (dir_cd_back(cwd) >= 0) { - cursor = 0; + case KEY_LEFT: { + // the string from dir_basename(cwd) may be a static field + // so it might not be safe to use it after changing cwd + const char * truebasename = dir_basename(cwd); + char * basename = NULL; + if (truebasename) basename = strdup(truebasename); + int ret = dir_cd_back(cwd); + if (ret >= 0) {   cwd = dir_get_cwd();   dir_free(&dir); - dir_list(cwd, &dir); + ret = dir_list(cwd, &dir); + if (ret < 0) { + ui_status_error(strerror(-ret)); + } else if (basename) { + size_t idx; + int i = dir_search_name(&dir, basename, &idx); + if (i >= 0) cursor = idx; + ui_status_info(""); + } else { + ui_status_info(""); + } + } else { + ui_status_error(strerror(-ret));   } + free(basename);   break; - case KEY_RIGHT: - if (cur_de->type == DE_DIR) { - if (dir_cd(cwd, cur_de->name) >= 0) { + } case KEY_RIGHT: + if (cur_de && (cur_de->type == DE_DIR || (cur_de->type == DE_LINK + && cur_de->linktype == DE_DIR))) { + int ret = dir_cd(cwd, cur_de->name); + if (ret >= 0) {   cursor = 0;   cwd = dir_get_cwd();   dir_free(&dir);   dir_list(cwd, &dir); + if (dir.len == 0) ui_status_info("Empty Directory"); + } else { + ui_status_error(strerror(-ret));   } + } else { + ui_status_info("");   }   break;   case KEY_HOME:   case 'g':   cursor = 0; + ui_status_info("");   break;   case KEY_END:   case 'G':   cursor = dir.len - 1; + ui_status_info("");   break;   case 'q':   goto finished; diff --git a/src/ui.c b/src/ui.c index 8100059..ef060a5 100644 --- a/src/ui.c +++ b/src/ui.c @@ -6710 +6716 @@ void ui_set_title(const char * title) {   win_set(titlewin, title, 0);  }   -void ui_set_status(const char * status) { +void ui_status_info(const char * status) {   win_set(statuswin, status, 0);  }   +void ui_status_error(const char * status) { + wattron(statuswin, COLOR_PAIR(RED)); + win_set(statuswin, status, 0); + wattroff(statuswin, COLOR_PAIR(RED)); +} +  void ui_erase(void) {   werase(filewin);  } @@ -1787 +18411 @@ void ui_print_cursor(size_t cursor, size_t total) {   if (total < lines - 2) wmove(filewin, total + 1, 0);   else wmove(filewin, lines - 1, 0);   - wprintw(filewin, "%zu/%zu", cursor + 1, total); + if (total > 0) { + wprintw(filewin, "%zu/%zu", cursor + 1, total); + } else { + waddstr(filewin, "0/0"); + }  }    static void ui_get_first_last(size_t dir_len, size_t cursor, size_t * first, size_t * last) {