commit 4f196b5c30fc2261b10ea81cfbcf69f9b76b4162
Author: rani <clagv.randomgames@gmail.com>
Date: Wed Dec 31 13:22:17 2025 +0000
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) {