Files
th/dir.c
2026-05-25 23:00:17 +02:00

409 lines
12 KiB
C

#include <curses.h>
#include <pthread.h>
#include <dirent.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "sorting.h"
#include "defines.h"
#include "config.h"
extern dir mid_dir;
extern unsigned int settings;
extern unsigned int file_modifiers;
extern unsigned int color_count;
extern unsigned int terminal_height;
extern char *global_path;
extern color *colors;
int (*order_func)() = sort_natural;
linked_dir *list_beginning;
linked_dir *current_linked_dir;
unsigned long get_dir_size(char *path){
DIR *dir = opendir(path);
unsigned long entry_count = 0;
struct dirent *entry;
if (dir && file_modifiers & FILE_MODIFIERS_HIDDEN_FILES) {
while ((entry=readdir(dir))) {
entry_count++;
}
/* removes files "." and ".." */
entry_count -= 2;
} else if (dir) {
while ((entry=readdir(dir))) {
if (entry->d_name[0] != '.') {
entry_count++;
}
}
}
closedir(dir);
return entry_count;
}
void get_dir_content(char *path, dir *dir){
struct dirent **entry = NULL;
if (file_modifiers & FILE_MODIFIERS_HIDDEN_FILES) { /* print hidden files */
scandir(path, &entry, skip_dot, NULL);
} else {
scandir(path, &entry, skip_hidden_files, NULL);
}
char *full_path = NULL;
unsigned long i = 0;
for (i = 0; i < dir->file_count; i++ ) {
dir->file_list[i].file_name = NULL;
if (entry[i]->d_name[0] == '.' && !(file_modifiers & FILE_MODIFIERS_HIDDEN_FILES)) {
} else {
dir->file_list[i].file_name = malloc(strlen(entry[i]->d_name)+1);
memcpy(dir->file_list[i].file_name, entry[i]->d_name, strlen(entry[i]->d_name) + 1);
dir->file_list[i].status = 0;
struct stat *file;
file = malloc(sizeof(struct stat));
/* using the full path allows using the same function for all windows */
full_path = malloc(strlen(path) + strlen(entry[i]->d_name) + 1 + sizeof("/"));
memcpy(full_path, path, strlen(path));
memcpy(full_path + strlen(path) + sizeof("/") - 1, entry[i]->d_name, strlen(entry[i]->d_name) + 1);
full_path[strlen(path)] = '/';
lstat(full_path, file);
dir->file_list[i].file_size = file->st_size;
dir->file_list[i].permissions = file->st_mode;
if (S_ISLNK(file->st_mode)) {
stat(full_path, file);
if (S_ISDIR(file->st_mode)) {
dir->file_list[i].file_type = FILE_TYPE_DIR | FILE_TYPE_SYMLINK;
dir->file_list[i].color_pair = COLOR_SYMLINK;
dir->file_list[i].file_size = get_dir_size(full_path);
} else {
dir->file_list[i].file_type = FILE_TYPE_REGULAR | FILE_TYPE_SYMLINK;
dir->file_list[i].color_pair = COLOR_SYMLINK;
}
} else if (S_ISDIR(file->st_mode)) {
dir->file_list[i].file_type = FILE_TYPE_DIR;
dir->file_list[i].color_pair = COLOR_DIR;
dir->file_list[i].file_size = get_dir_size(full_path);
} else if (file->st_mode & S_IXUSR) {
dir->file_list[i].file_type = FILE_TYPE_EXEC;
dir->file_list[i].color_pair = COLOR_EXEC;
} else if (S_ISREG(file->st_mode)) {
dir->file_list[i].file_type = FILE_TYPE_REGULAR;
dir->file_list[i].color_pair = COLOR_REGULAR;
unsigned long j = 0;
char *extension = strrchr(entry[i]->d_name, '.');
if (extension) {
for (j = 0; j < color_count; j++) {
if (!strcmp(colors[j].file_extension, extension)) {
dir->file_list[i].color_pair = colors[j].color_pair;
}
}
}
} else if (S_ISBLK(file->st_mode)) {
dir->file_list[i].file_type = FILE_TYPE_BLOCK;
dir->file_list[i].color_pair = COLOR_BLOCK;
} else if (S_ISCHR(file->st_mode)) {
dir->file_list[i].file_type = COLOR_CHARDEV;
} else if (S_ISFIFO(file->st_mode)) {
dir->file_list[i].file_type = FILE_TYPE_FIFO;
dir->file_list[i].color_pair = COLOR_FIFO;
} else if (S_ISSOCK(file->st_mode)) {
dir->file_list[i].file_type = FILE_TYPE_SOCK;
dir->file_list[i].color_pair = COLOR_SOCK;
} else {
dir->file_list[i].file_type = COLOR_REGULAR;
dir->file_list[i].color_pair = COLOR_REGULAR;
unsigned long j = 0;
char *extension = strrchr(entry[i]->d_name, '.');
if (extension) {
for (j = 0; j < color_count; j++) {
if (!strcmp(colors[j].file_extension, extension)) {
dir->file_list[i].color_pair = colors[j].color_pair;
}
}
} else {
}
}
free(full_path);
free(file);
free(entry[i]);
}
}
qsort(dir->file_list, dir->file_count, sizeof(file), order_func);
free(entry);
}
void print_dir(WINDOW *win, char print_info, dir *dir){
/* i am not proud of this function */
unsigned long line_width = getmaxx(win);
unsigned long i = 0;
float file_size;
float printed_size = 0;
char size_char = ' ';
char is_selected = 0;
unsigned long offset_vertical = 0;
unsigned long offset_back = 0;
#if SETTINGS_LINE_NUMBERS == 0
unsigned long offset_front = 0;
#else
long offset_front = 2;
#endif
unsigned long selected_file_current = dir->current_file - dir->file_list;
long offset_index = 2; /* only used for the index of the file itself */
if (print_info) {
if (dir->file_count > 9) {
#if SETTINGS_LINE_NUMBERS != 0
unsigned long dir_file_count_ = dir->file_count;
while(dir_file_count_ > 9) {
offset_front++;
dir_file_count_ /= 10;
}
#endif
}
if (selected_file_current > (terminal_height/3)*2 && dir->file_count > terminal_height - 2) {
if (selected_file_current + (terminal_height/3) >= dir->file_count) {
offset_vertical = dir->file_count - terminal_height+2;
} else {
offset_vertical = selected_file_current - (terminal_height/3)*2;
}
}
} else {
offset_front = 0;
}
for (i = offset_vertical; i < dir->file_count && i < (terminal_height + offset_vertical); i++) {
if (print_info) {
file_size = dir->file_list[i].file_size;
char size_index = -1;
do {
printed_size=file_size;
file_size /= 1024;
size_index++;
} while (file_size > 1 && size_index < size_unit_count);
size_char = size_unit[(unsigned)size_index];
if (dir->file_list[i].file_type & FILE_TYPE_DIR) {
offset_back = line_width - (snprintf(NULL,0,"%ld", dir->file_list[i].file_size) + 1);
} else if (size_char =='B') {
offset_back = line_width - (snprintf(NULL,0,"%0.0lf %c", printed_size, size_char) + 1);
} else {
offset_back = line_width - (snprintf(NULL,0,"%0.2lf %c", printed_size, size_char) + 1);
}
} else {
offset_back = line_width;
}
if (dir->file_list[i].status & FILE_STATUS_SELECTED) {
is_selected = 1;
} else {
is_selected = 0;
}
if (dir->file_list[i].status & FILE_STATUS_SELECTED) {
wattron(win, COLOR_PAIR(8));
} else {
wattron(win, COLOR_PAIR(dir->file_list[i].color_pair));
}
if (&dir->file_list[i] == dir->current_file) {
wattron(win, A_REVERSE);
unsigned long bg = 0;
for (bg = 0; bg < line_width; bg++) {
mvwaddch(win, i-offset_vertical, bg, ' ');
}
} else {
wattroff(win, A_REVERSE);
}
if(print_info) {
#if SETTINGS_LINE_NUMBERS == 2
long i_ = (selected_file_current) - i;
offset_index = 0;
while(i_) {
offset_index++;
i_ /= 10;
}
long relative_index = selected_file_current - i;
if (relative_index < 0) {
relative_index = relative_index * -1;
} else if (relative_index == 0) {
i_ = (selected_file_current != 0) ? (selected_file_current) : 1;
while(i_) {
offset_index++;
i_ /= 10;
}
relative_index = i;
}
mvwprintw(win, i-offset_vertical, offset_front-offset_index-1, "%ld", relative_index);
#elif SETTINGS_LINE_NUMBERS == 1
unsigned long i_ = i;
offset_index = 2;
while(i_ > 9) {
offset_index++;
i_ /= 10;
}
mvwprintw(win, i-offset_vertical, offset_front-offset_index, "%ld", i);
#endif
if (dir->file_list[i].file_type & FILE_TYPE_DIR) {
mvwprintw(win, i-offset_vertical, offset_back, "%ld", dir->file_list[i].file_size);
}else if (size_char =='B') {
mvwprintw(win, i-offset_vertical, offset_back, "%0.0lf %c", printed_size, size_char);
} else {
mvwprintw(win, i-offset_vertical, offset_back, "%0.2lf %c", printed_size, size_char);
}
}
char *extension = strrchr(dir->file_list[i].file_name, '.');
unsigned long printable_size = offset_back-offset_front-is_selected-2;
mvwaddnstr(win, i-offset_vertical, offset_front+is_selected, dir->file_list[i].file_name, printable_size);
if (extension && printable_size <= strlen(dir->file_list[i].file_name)) {
mvwaddnstr(win, i-offset_vertical, offset_back-strlen(extension)-1, extension, strlen(extension));
mvwaddnstr(win, i-offset_vertical, offset_back-strlen(extension)-2, "~", 1);
}
if (dir->file_list[i].status & FILE_STATUS_SELECTED) {
wattroff(win, COLOR_PAIR(8));
} else {
wattroff(win, COLOR_PAIR(dir->file_list[i].color_pair));
}
}
}
void dir_changed(){
char *path = getcwd(NULL, 0);
current_linked_dir = list_beginning;
while (current_linked_dir->next != NULL) {
if(strcmp(current_linked_dir->path, path) == 0) {
break;
} else {
current_linked_dir = current_linked_dir->next;
}
}
if(strcmp(current_linked_dir->path, path) == 0) {
mid_dir.current_file = &mid_dir.file_list[current_linked_dir->index];
} else {
/**/
current_linked_dir->next = malloc(sizeof(linked_dir));
current_linked_dir->next->path = malloc(strlen(global_path)+1);
memcpy(current_linked_dir->next->path, global_path, strlen(global_path)+1);
current_linked_dir->next->next = NULL;
current_linked_dir->next->index = 0;
mid_dir.current_file = mid_dir.file_list;
}
}
void change_dir(char *new_path){
char *old_path = getcwd(NULL, 0);
current_linked_dir = list_beginning;
while (current_linked_dir->next != NULL) {
if(strcmp(current_linked_dir->path, old_path) == 0) {
break;
} else {
current_linked_dir = current_linked_dir->next;
}
}
if(strcmp(current_linked_dir->path, old_path) == 0) {
current_linked_dir->index = mid_dir.current_file - mid_dir.file_list;
}
chdir(new_path);
char *new_path_real = getcwd(NULL, 0);
current_linked_dir = list_beginning;
while (current_linked_dir->next != NULL) {
if(strcmp(current_linked_dir->path, new_path_real) == 0) {
break;
} else {
current_linked_dir = current_linked_dir->next;
}
}
if(strcmp(current_linked_dir->path, new_path_real) != 0) {
current_linked_dir->next = malloc(sizeof(linked_dir));
current_linked_dir = current_linked_dir->next;
current_linked_dir->path = malloc(strlen(new_path_real)+1);
memcpy(current_linked_dir->path, new_path_real, strlen(new_path_real)+1);
current_linked_dir->next = NULL;
current_linked_dir->index = 0;
/*TODO(2026-05-25T22:49:30)
*handle if new_path == "..", should this case be true, focus the index on which the old_path falls on*/
}
mid_dir.current_file = &mid_dir.file_list[current_linked_dir->index];
free(old_path);
free(new_path_real);
}
void dir_init(){
list_beginning = malloc(sizeof(linked_dir));
list_beginning->path = getcwd(NULL, 0);
list_beginning->index = 0;
list_beginning->next = NULL;
current_linked_dir = list_beginning;
}
void recursive_delete(file current_file){
/*
if (S_ISLNK(current_file.permissions)) {
remove(current_file.file_name);
} else if (current_file.file_type & FILE_TYPE_DIR ) {
unsigned int file_modifiers_tmp = file_modifiers;
file_modifiers |= FILE_MODIFIERS_HIDDEN_FILES;
unsigned long current_file_count = get_dir_size(current_file.file_name);
if (current_file_count != 0) {
file *current_dir = malloc(current_file_count * sizeof(file));
memset(current_dir, '\0', current_file_count * sizeof(file));
get_dir_content(current_file.file_name, &current_file_count, current_dir);
if (chdir(current_file.file_name) != 0) {
return;
}
unsigned long i;
for (i = 0; i < current_file_count; i++) {
recursive_delete(current_dir[i]);
free(current_dir[i].file_name);
}
free(current_dir);
if (chdir("..") != 0) {
return;
}
}
remove(current_file.file_name);
file_modifiers = file_modifiers_tmp;
} else {
remove(current_file.file_name);
}
*/
}