From 38338df25425cb7826c2d9ea86d5291206c663d0 Mon Sep 17 00:00:00 2001 From: nova Date: Thu, 17 Apr 2025 01:17:13 +0200 Subject: [PATCH] code base good enough to actually progress --- Makefile | 4 +- backend.c | 129 +++++++++++++++----------------------- backend.h | 8 +-- defines.h | 22 +++---- interactions.c | 6 +- main.c | 167 ++++++++++++++++++++++++++++++++----------------- sorting.c | 65 ++----------------- sorting.h | 7 +-- structs.h | 4 -- threading.c | 153 ++++++++++++++++++++++++++++++++++++++++++++ threading.h | 10 +++ window.c | 134 ++++++++++++++++++++++----------------- window.h | 10 +-- 13 files changed, 430 insertions(+), 289 deletions(-) delete mode 100644 structs.h create mode 100644 threading.c create mode 100644 threading.h diff --git a/Makefile b/Makefile index 656b621..73e2312 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ all: - gcc ./main.c -std=c99 -o th -lncurses -ltinfo -Wall + gcc ./main.c -std=c89 -o th -lncurses -ltinfo -Wall d: - gcc -g -std=c99 ./main.c -o th -lncurses -ltinfo -Wall + gcc -g -std=c89 ./main.c -o th -lncurses -ltinfo -Wall && gdb --tui ./th diff --git a/backend.c b/backend.c index e9058c3..4d1bb8f 100644 --- a/backend.c +++ b/backend.c @@ -1,100 +1,75 @@ #include -#include -#include #include -#include -#include #include "defines.h" #include "sorting.h" extern unsigned int settings; extern unsigned int file_modifiers; -extern file_data *content_l; -extern file_data *content_m; -extern file_data *content_r; -extern char *path; - -unsigned long file_count_l; -unsigned long file_count_m; -unsigned long file_count_r; -void get_dir_size(char *path, unsigned long *file_count, unsigned long *longest_name){ - DIR *dir = opendir(path); - *longest_name = 256; //magic number originates out of readdir(), unless i implement my own name size function, thisll do - unsigned long index = 0; - if (dir) { - struct dirent *entry; - while ( (entry=readdir(dir)) ) { - if (entry->d_name[0] != '.' && !(file_modifiers & FILE_MODIFIERS_HIDDEN_FILES)) { - index++; - } else if (file_modifiers & FILE_MODIFIERS_HIDDEN_FILES){ - index++; - } - } - } - *file_count = index; - closedir(dir); -} - -void get_dir_content(char *path, unsigned long file_count, unsigned long longest_name, file_data *dir_content){ +void get_dir_size(char *path, unsigned long *dir_length_width, unsigned long *dir_width){ DIR *dir = opendir(path); if (dir) { - unsigned long index = 0; + unsigned long entry_count = 0; + unsigned long max_length; struct dirent *entry; - while ( (entry=readdir(dir)) ) { - if (entry->d_name[0] != '.' && !(file_modifiers & FILE_MODIFIERS_HIDDEN_FILES)) { - dir_content[index].file_name = entry->d_name; - dir_content[index].file_type = entry->d_type; - index++; - } else if (file_modifiers & FILE_MODIFIERS_HIDDEN_FILES) { - dir_content[index].file_name = entry->d_name; - dir_content[index].file_type = entry->d_type; - index++; + while ((entry=readdir(dir))) { + if (entry->d_name[0] != '.' || (file_modifiers & FILE_MODIFIERS_HIDDEN_FILES)) { + unsigned int current_length = 0; + unsigned int i = 0; + for (; entry->d_name[i] != '\0'; i++) { + current_length++; + } + if (current_length > max_length) { + /*dynamic filename length to save on memory*/ + max_length = current_length; + } + entry_count++; + } else { } } + dir_length_width[0] = entry_count; + dir_length_width[1] = max_length; } closedir(dir); + } -void print_dir(WINDOW *win, unsigned long file_count, file_data *dir_content){ - for (unsigned long i = 0; i < file_count; i++ ){ //skip index 0 as it is used for metadata like file count - if (dir_content[i].file_name) { - wprintw(win, "%s",dir_content[i].file_name); - wmove(win, i, 1); - } else { - wprintw(win, "NULL"); - wmove(win, i, 1); - } - } -} - -void *populate_dir(void *which){ // 0=left, 1=main, 2=right - char wh = (char)which; - unsigned long longest_name = 0; - - if (wh) { - if (wh == 1) { - free(content_m); - get_dir_size(path, &file_count_m, &longest_name); - content_m = (file_data*)calloc(file_count_m, sizeof(file_data)); - get_dir_content(path, file_count_m, longest_name, content_m); - sort_dir(&file_count_m, &longest_name, content_m); - } else { - free(content_r); - get_dir_size(path, &file_count_r, &longest_name); - content_r = calloc(file_count_r, sizeof(file_data)); - get_dir_content(path, file_count_r, longest_name, content_r); - sort_dir(&file_count_m, &longest_name, content_r); - } +void get_dir_content(char *path, unsigned long *dir_length_width, unsigned long *dir_width, char *dir_content){ + struct dirent **entry; + if (file_modifiers & FILE_MODIFIERS_HIDDEN_FILES) { /* print hidden files */ + dir_length_width[0] = scandir(path, &entry, NULL, alphasort); } else { - free(content_l); - get_dir_size(path, &file_count_l, &longest_name); - content_l = calloc(file_count_l, sizeof(file_data)); - get_dir_content(path, file_count_l, longest_name, content_l); - sort_dir(&file_count_m, &longest_name, content_l); + dir_length_width[0] = scandir(path, &entry, skip_hidden_files, alphasort); } - return NULL; + unsigned long i = 0; + for (i = 0; i < dir_length_width[0]; i++ ) { + if (entry[i]->d_name[0] == '.' && !(file_modifiers & FILE_MODIFIERS_HIDDEN_FILES)) { + } else { + unsigned long j = 0; + for (; entry[i]->d_name[j] != '\0'; j++) { + dir_content[i * dir_length_width[1] + j] = entry[i]->d_name[j]; + } + dir_width[i] = j; + } + } + for (i = 0; i < dir_length_width[0]; i++) { + free(entry[i]); + } + free(entry); + } +void print_dir(WINDOW *win, unsigned long *dir_length_width, unsigned long *file_width, char *dir_content){ + + unsigned long i = 0; + for (i = 0; i #include -#include #include #include +#include "threading.h" #include "window.h" #include "interactions.h" #include "defines.h" unsigned int terminal_height; unsigned int terminal_width; -unsigned int temp_heigth = 0; //used for screen refresh +unsigned int temp_heigth = 0; /*used for screen refresh*/ unsigned int temp_width = 0; unsigned int settings; unsigned int file_modifiers; -unsigned int status; //bit 0 = enable -unsigned short cpu_cores; //amount of cores/threads the host system reports to have -file_data *content_l; //content of parent dir, used in left window -file_data *content_m; //content of current dir, used in main window -file_data *content_r; //content of child dir, used in right window -char *path = "."; +unsigned int status; char input = 0; - +void render_pass(WINDOW *wint, WINDOW *winb, WINDOW *winl, WINDOW *winm, WINDOW *winr); void init(); int main() { - initscr(); //start ncurses - timeout(50); //blocking timeout of getch() - keypad(stdscr, TRUE); init(); getmaxyx(stdscr, terminal_height, terminal_width); - WINDOW *winl = newwin(terminal_height, terminal_width/3, terminal_height, (terminal_width/3)); - WINDOW *winm = newwin(terminal_height, terminal_width/3, 0, 0); - WINDOW *winr = newwin(terminal_height, terminal_width/3, terminal_height, ((terminal_width/3)*2)); + WINDOW *win_t = newwin(1, terminal_width, 0, 0); + WINDOW *win_b = newwin(1, terminal_width, terminal_height-1, 0); + WINDOW *win_l = newwin(terminal_height-2, terminal_width/3, 1, 0); + WINDOW *win_m = newwin(terminal_height-2, terminal_width/3, 1, (terminal_width/3)); + WINDOW *win_r = newwin(terminal_height-2, terminal_width/3, 1, ((terminal_width/3)*2)); + pthread_t thread_b; + pthread_t thread_t; + pthread_t thread_l; + pthread_t thread_m; + pthread_t thread_r; + + char threading = 0; + + while(!(status & STATUS_QUIT_PROGRAM)){ - getmaxyx(stdscr, temp_heigth, temp_width); - - if (status & STATUS_RUN_BACKEND) { - pthread_t populate_l; - pthread_t populate_m; - pthread_t populate_r; - - pthread_create(&populate_l, NULL, populate_dir, (void*)0); //parent_content slash win_l - pthread_create(&populate_m, NULL, populate_dir, (void*)1); //current_content slash win_m - pthread_create(&populate_r, NULL, populate_dir, (void*)2); //child_content slash win_r - - pthread_join(populate_l, NULL); - pthread_join(populate_m, NULL); - pthread_join(populate_r, NULL); - status ^= STATUS_RUN_BACKEND; - status |= STATUS_UPDATE_SCREEN_0; - } - - getmaxyx(stdscr, terminal_height, terminal_width); - temp_heigth -= terminal_height; - temp_width -= terminal_width; - if (!temp_heigth || !temp_width || (status & STATUS_UPDATE_SCREEN_MASK)) { //updates screen - if (status & STATUS_UPDATE_SCREEN_0) { - window_left(winl, 0, 0, content_l); - window_main(winm, 0, terminal_width/3, content_m); - window_right(winr, 0, (terminal_width/3)*2, content_r); - } - wmove(stdscr,0,0); - //status &= ~STATUS_UPDATE_SCREEN_MASK; - status = 0; + if (!(terminal_height == temp_heigth) || !(terminal_width == temp_width)) { + status |= (STATUS_RUN_BACKEND | STATUS_UPDATE_SCREEN_RESIZE); + temp_width = terminal_width; + temp_heigth = terminal_height; + } + if (status & STATUS_RUN_BACKEND || threading) { + if (threading) { + pthread_cancel(thread_t); + pthread_cancel(thread_b); + pthread_cancel(thread_l); + pthread_cancel(thread_m); + pthread_cancel(thread_r); + threading = 0; + status &= ~STATUS_RUN_BACKEND; + status |= STATUS_UPDATE_SCREEN_0; + } else { + pthread_create(&thread_t, NULL, thread_top, win_t); /*top bar*/ + pthread_create(&thread_b, NULL, thread_btm, win_b); /*bottom bar*/ + pthread_create(&thread_m, NULL, thread_mid, win_m); /*parent_content slash win_l*/ + pthread_create(&thread_l, NULL, thread_lft, win_l); /*current_content slash win_m*/ + pthread_create(&thread_r, NULL, thread_rgt, win_r); /*child_content slash win_r*/ + threading = 1; + } } - - if ((input = getch())) { user_interactions(&input, &status, &settings); } + + render_pass(win_t, win_b, win_l, win_m, win_r); + } - free(content_l); - free(content_m); - free(content_r); + threading_free(); + pthread_join(thread_l, NULL); + pthread_join(thread_r, NULL); + pthread_join(thread_m, NULL); + pthread_join(thread_t, NULL); + pthread_join(thread_b, NULL); + curs_set(1); endwin(); + refresh(); return 0; } -//this function exists for things done at startup (initialization, reading config, etc) + +void render_pass(WINDOW *win_t, WINDOW *win_b, WINDOW *win_l, WINDOW *win_m, WINDOW *win_r){ + + if ((status & STATUS_UPDATE_SCREEN_MASK) & STATUS_UPDATE_SCREEN_RESIZE) { + status |= STATUS_LOCK_MASK; + + /*TODO: check if deallocation of window and reallocation is faster than this or not */ + + werase(win_t); + werase(win_b); + werase(win_l); + werase(win_m); + werase(win_r); + + wresize(win_t, 1, terminal_width); + wresize(win_b, terminal_height, terminal_width/3); + wresize(win_m, terminal_height-2, terminal_width/3); + wresize(win_l, terminal_height-2, terminal_width/3); + wresize(win_r, terminal_height-2, terminal_width/3); + + mvwin(win_t, 0, 0); + mvwin(win_b, terminal_height-1, 0); + mvwin(win_l, 1, 0); + mvwin(win_m, 1, (terminal_width/3)); + mvwin(win_r, 1, ((terminal_width/3)*2)); + + + status &= ~STATUS_LOCK_MASK; + status |= STATUS_UPDATE_SCREEN_0; + } + + if (status & STATUS_UPDATE_SCREEN_MASK) { + status &= ~(STATUS_UPDATE_SCREEN_MASK); + window_top(win_t); + window_btm(win_b); + window_lft(win_l); + window_mid(win_m); + window_rgt(win_r); + wrefresh(win_t); + wrefresh(win_b); + wrefresh(win_l); + wrefresh(win_m); + wrefresh(win_r); + } +} +/*this function exists for things done at startup (initialization, reading config, etc)*/ void init() { - cpu_cores = get_nprocs(); - //file_modifiers = (FILE_MODIFIERS_HIDDEN_FILES | FILE_MODIFIERS_SORT_BITMASK); - file_modifiers = FILE_MODIFIERS_SORT_BITMASK; - status = (STATUS_RUN_BACKEND | STATUS_UPDATE_SCREEN_0); + initscr(); /*start ncurses*/ + noecho(); /*hide keyboard input*/ + timeout(50); /*blocking timeout of getch()*/ + keypad(stdscr, TRUE); + curs_set(0); + + /*file_modifiers = (FILE_MODIFIERS_HIDDEN_FILES | FILE_MODIFIERS_SORT_BITMASK);*/ + status = (STATUS_RUN_BACKEND | STATUS_UPDATE_SCREEN_MASK); + + threading_init(); /* found in threading.c */ - content_l = (file_data*)calloc(1, sizeof(file_data)); //allocation in order to allow a more streamlined backend - content_m = (file_data*)calloc(1, sizeof(file_data)); - content_r = (file_data*)calloc(1, sizeof(file_data)); } diff --git a/sorting.c b/sorting.c index 2523986..5f08601 100644 --- a/sorting.c +++ b/sorting.c @@ -1,71 +1,14 @@ #include -#include -#include -#include #include -#include -#include -#include -#include #include "defines.h" extern unsigned int settings; extern unsigned int file_modifiers; -extern unsigned short cpu_cores; //amount of cores/threads the host system reports to have -extern file_data *content_l; -extern file_data *content_m; -extern file_data *content_r; -extern char *path; -int type(const void *f0, const void *f1){ - const char *file0_name = ((file_data*)f0)->file_name; - const char *file1_name = ((file_data*)f1)->file_name; - const char file0_type = ((file_data*)f0)->file_type; - const char file1_type = ((file_data*)f1)->file_type; - if (file0_type > file1_type) { - return -1; - } else if (file0_type < file1_type) { - return 1; - } else { - return strcmp(file0_name, file1_name); +int skip_hidden_files(const struct dirent *entry){ + if (entry->d_name[0] == '.') { + return 0; } -} -int natural(const void *f0, const void *f1){ - const char *file0_name = ((file_data*)f0)->file_name; - const char *file1_name = ((file_data*)f1)->file_name; - const char file0_type = ((file_data*)f0)->file_type; - const char file1_type = ((file_data*)f1)->file_type; - if (S_ISDIR(file0_type) || S_ISDIR(file1_type)) { - if (file0_type == file1_type) { - return strcmp(file0_name, file1_name); - } else if (S_ISDIR(file1_type)) { - return -1; - } - return 1; - } - - //return strcmp(file0_name, file1_name); + return 1; } -int alphabetic(const void *f0, const void *f1){ - const char *file0_name = ((file_data*)f0)->file_name; - const char *file1_name = ((file_data*)f1)->file_name; - return strcmp(file0_name, file1_name); - -} - -void sort_dir(unsigned long *file_count, unsigned long *longest_name, file_data *dir_content){ - - if ((file_modifiers & FILE_MODIFIERS_SORT_BITMASK) == ~FILE_MODIFIERS_SORT_BITMASK) { - qsort(dir_content, *file_count, sizeof(file_data), natural); - - } else if (file_modifiers & FILE_MODIFIERS_SORT_ALPHABETIC) { - qsort(dir_content, *file_count, sizeof(file_data), alphabetic); - - } else if (file_modifiers & FILE_MODIFIERS_SORT_TYPE) { - qsort(dir_content, *file_count, sizeof(file_data), type); - } - - - -} diff --git a/sorting.h b/sorting.h index 62ffb03..8176473 100644 --- a/sorting.h +++ b/sorting.h @@ -1,11 +1,8 @@ #include -#include -#include #include -#include -#include #include "defines.h" #include "sorting.c" -void sort_dir(unsigned long *file_count, unsigned long *longest_name, file_data *dir_content); +void sort_dir(unsigned long *dir_length_width, char *dir_content); +int skip_hidden_files(const struct dirent *entry); diff --git a/structs.h b/structs.h deleted file mode 100644 index 81136c3..0000000 --- a/structs.h +++ /dev/null @@ -1,4 +0,0 @@ -typedef struct data { - char *file_name; - unsigned char file_type; -} file_data; diff --git a/threading.c b/threading.c new file mode 100644 index 0000000..728d40c --- /dev/null +++ b/threading.c @@ -0,0 +1,153 @@ +#include +#include +#include +#include +#include +#include "defines.h" +#include "backend.h" + + +pthread_mutex_t mutex_top; +pthread_mutex_t mutex_btm; +pthread_mutex_t mutex_lft; +pthread_mutex_t mutex_mid; +pthread_mutex_t mutex_rgt; + +/* contains entire directory as 2d array + * may be changed in future to only include parts of the dir (currently includes entire dir) */ +char *mid_content; +char *lft_content; +char *top_content; /* current path */ +/* index 0 = file_count + * index 1 = longest_name */ +unsigned long *mid_length_width; +unsigned long *lft_length_width; +unsigned long *top_length_width; +/* this array exists so that a file with a 3 char long name wont spend the same amount of time printing as a file with 200 chars + * should both exist in the same directory + * currently unused */ +unsigned long *mid_file_name_width; +unsigned long *lft_file_name_width; + + +extern unsigned int status; + +void *thread_mid(void *data){ + pthread_mutex_lock(&mutex_mid); + + free(mid_content); + free(mid_file_name_width); + free(mid_length_width); + mid_length_width = malloc(sizeof(char)*2); + + char *path; + if((path=getcwd(NULL, 0)) == NULL) { + mid_content = malloc(sizeof("cannot open directory")); + mid_length_width[0] = 1; + mid_length_width[1] = sizeof("cannot open directory"); + mid_content = "cannot open directory"; + } else { + + + get_dir_size(path, mid_length_width, mid_file_name_width); + mid_file_name_width = malloc(mid_length_width[0] * sizeof(unsigned long)); + mid_content = malloc(mid_length_width[0] * mid_length_width[1] * sizeof(char)); + memset(mid_content, ' ', mid_length_width[0] * mid_length_width[1] * sizeof(char)); + get_dir_content(path, mid_length_width, mid_file_name_width, mid_content); + + } + free(path); + pthread_mutex_unlock(&mutex_mid); + pthread_exit(NULL); +} +void *thread_lft(void *data){ + pthread_mutex_lock(&mutex_lft); + + free(lft_content); + free(lft_file_name_width); + free(lft_length_width); + lft_length_width = malloc(sizeof(char)*2); + + char *path; + if((path=getcwd(NULL, 0)) == NULL) { + lft_content = malloc(sizeof("cannot open directory")); + lft_length_width[0] = 1; + lft_length_width[1] = sizeof("cannot open directory"); + lft_content = "cannot open directory"; + } else { + + + char *parent ; + if((parent = malloc(strlen(path)+strlen("/..")+1)) != NULL){ + parent[0] = '\0'; /* ensures empty string */ + strcat(parent, path); + strcat(parent, "/.."); + } + + get_dir_size(parent, lft_length_width, lft_file_name_width); + lft_file_name_width = malloc(lft_length_width[0] * sizeof(unsigned long)); + lft_content = malloc(lft_length_width[0] * lft_length_width[1] * sizeof(char)); + memset(lft_content, ' ', lft_length_width[0] * lft_length_width[1] * sizeof(char)); + get_dir_content(parent, lft_length_width, lft_file_name_width, lft_content); + free (parent); + } + free(path); + pthread_mutex_unlock(&mutex_lft); + pthread_exit(NULL); +} +void *thread_rgt(void *data){ + + + pthread_exit(NULL); +} +void *thread_top(void *data){ + pthread_mutex_lock(&mutex_top); + free(top_content); + free(top_length_width); + top_length_width = malloc(sizeof(char)*2); + + char *path; + if((path=getcwd(NULL, 0)) == NULL) { + top_content = malloc(sizeof("cannot open directory")); + top_length_width[0] = 1; + top_length_width[1] = sizeof("cannot open directory"); + top_content = "cannot open directory"; + } else { + top_content = getcwd(NULL, 0); + top_length_width[0] = 1; + top_length_width[1] = strlen(top_content); + } + + free(path); + pthread_mutex_unlock(&mutex_top); + pthread_exit(NULL); +} +void *thread_btm(void *data){ + + pthread_exit(NULL); +} + +void threading_init(){ + mid_content = malloc(sizeof(char)); + mid_file_name_width = malloc(sizeof(char)); + mid_length_width = malloc(sizeof(char)); + lft_content = malloc(sizeof(char)); + lft_file_name_width = malloc(sizeof(char)); + lft_length_width = malloc(sizeof(char)); + top_length_width = malloc(sizeof(char)); + top_content = malloc(sizeof(char)); + + + pthread_mutex_init(&mutex_top, NULL); + pthread_mutex_init(&mutex_mid, NULL); + pthread_mutex_init(&mutex_lft, NULL); +} +void threading_free(){ + free(mid_content); + free(mid_file_name_width); + free(mid_length_width); + + pthread_mutex_destroy(&mutex_top); + pthread_mutex_destroy(&mutex_mid); + pthread_mutex_destroy(&mutex_lft); +} diff --git a/threading.h b/threading.h new file mode 100644 index 0000000..c5ed6b3 --- /dev/null +++ b/threading.h @@ -0,0 +1,10 @@ +#include +#include "threading.c" + +void *thread_lft(void *data); +void *thread_mid(void *data); +void *thread_rgt(void *data); +void *thread_top(void *data); +void *thread_btm(void *data); +void threading_init(); +void threading_free(); diff --git a/window.c b/window.c index 50ecf51..88c928e 100644 --- a/window.c +++ b/window.c @@ -1,72 +1,88 @@ #include -#include -#include "backend.h" +#include +#include "defines.h" -extern unsigned int terminal_height; -extern unsigned int terminal_width; -extern unsigned long file_count_l; -extern unsigned long file_count_m; -extern unsigned long file_count_r; +extern unsigned int status; +extern char *mid_content; +extern unsigned long *mid_width; +extern unsigned long *mid_length_width; +extern unsigned long *mid_file_name_width; +extern char *top_content; +extern unsigned long *top_length_width; +extern char *lft_content; +extern unsigned long *lft_width; +extern unsigned long *lft_length_width; +extern unsigned long *lft_file_name_width; -void window_main(WINDOW *win, unsigned int start_y, unsigned int start_x, file_data *dir_content){ +extern pthread_mutex_t mutex_top; +extern pthread_mutex_t mutex_btm; +extern pthread_mutex_t mutex_lft; +extern pthread_mutex_t mutex_mid; +extern pthread_mutex_t mutex_rgt; - //WINDOW *win = (window_data)window_data.win; - unsigned int local_width; - unsigned int local_height; +void window_top(WINDOW *win){ + unsigned long i = 0; + werase(win); - //{{{ size & positioning - wresize(win, terminal_height, terminal_width/3); - getmaxyx(win, local_height, local_width); - mvwin(win, start_y, start_x); - wclear(win); - //}}} - - wmove(win, 1, 1); + if (pthread_mutex_trylock(&mutex_top)) { + wprintw(win,"loading"); + status |= STATUS_UPDATE_SCREEN_0; - print_dir(win, file_count_m, dir_content); - - - - box(win,0,0); - wrefresh(win); + } else { + for (i = 0; i #include "window.c" -void window_left(WINDOW *win, unsigned int start_y, unsigned int start_x, file_data *dir_content); -void window_main(WINDOW *win, unsigned int start_y, unsigned int start_x, file_data *dir_content); -void window_right(WINDOW *win, unsigned int start_y, unsigned int start_x, file_data *dir_content); - +void window_top(WINDOW *win); +void window_btm(WINDOW *win); +void window_lft(WINDOW *win); +void window_mid(WINDOW *win); +void window_rgt(WINDOW *win);