#include #include #include #include #include #include #include #include #include "sorting.h" #include "defines.h" #include "config.h" extern file *mid_content; extern unsigned long mid_file_count; extern unsigned int settings; extern unsigned int file_modifiers; extern unsigned int color_count; extern unsigned int terminal_height; extern volatile unsigned long selected_file_current; extern volatile unsigned long selected_file_last; extern color *colors; int (*order_func)() = sort_natural; linked_dir *visited_dirs; linked_dir *current_dir; unsigned long get_dir_size(char *path); void get_dir_content(char *path, unsigned long *dir_file_count, file *dir_content); void print_dir(WINDOW *win, char print_info, unsigned long *dir_file_count, file *dir_content); 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, unsigned long *dir_file_count, file *dir_content){ struct dirent **entry; if (file_modifiers & FILE_MODIFIERS_HIDDEN_FILES) { /* print hidden files */ scandir(path, &entry, skip_dot, NULL); } else { scandir(path, &entry, skip_hidden_files, NULL); } unsigned long i = 0; for (i = 0; i < *dir_file_count; i++ ) { if (entry[i]->d_name[0] == '.' && !(file_modifiers & FILE_MODIFIERS_HIDDEN_FILES)) { } else { dir_content[i].file_name = malloc(strlen(entry[i]->d_name)+1); strcpy(dir_content[i].file_name, entry[i]->d_name); struct stat *file; file = malloc(sizeof(struct stat)); /* using the full path allows using the same function for all windows */ char *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_content[i].file_size = file->st_size; dir_content[i].permissions = file->st_mode; if (S_ISDIR(file->st_mode)) { dir_content[i].file_type = FILE_TYPE_DIR; dir_content[i].color_pair = COLOR_DIR; dir_content[i].file_size = get_dir_size(full_path); } else if (S_ISLNK(file->st_mode)) { stat(full_path, file); if (S_ISDIR(file->st_mode)) { dir_content[i].file_type = FILE_TYPE_DIR | FILE_TYPE_SYMLINK; dir_content[i].color_pair = COLOR_SYMLINK; dir_content[i].file_size = get_dir_size(full_path); } else { dir_content[i].file_type = FILE_TYPE_REGULAR | FILE_TYPE_SYMLINK; dir_content[i].color_pair = COLOR_SYMLINK; } } else if (file->st_mode & S_IXUSR) { dir_content[i].file_type = FILE_TYPE_EXEC; dir_content[i].color_pair = COLOR_EXEC; } else if (S_ISREG(file->st_mode)) { dir_content[i].file_type = FILE_TYPE_REGULAR; dir_content[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 (!strncmp(colors[j].file_extension, extension, strlen(colors[j].file_extension))) { dir_content[i].color_pair = colors[j].color_pair; } } } } else if (S_ISBLK(file->st_mode)) { dir_content[i].file_type = FILE_TYPE_BLOCK; dir_content[i].color_pair = COLOR_BLOCK; } else if (S_ISCHR(file->st_mode)) { dir_content[i].file_type = COLOR_CHARDEV; } else if (S_ISFIFO(file->st_mode)) { dir_content[i].file_type = FILE_TYPE_FIFO; dir_content[i].color_pair = COLOR_FIFO; } else if (S_ISSOCK(file->st_mode)) { dir_content[i].file_type = FILE_TYPE_SOCK; dir_content[i].color_pair = COLOR_SOCK; } else { dir_content[i].file_type = COLOR_REGULAR; dir_content[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 (!strncmp(colors[j].file_extension, extension, strlen(colors[j].file_extension))) { dir_content[i].color_pair = colors[j].color_pair; } } } else { } } free(full_path); free(file); } } qsort(dir_content, *dir_file_count, sizeof(file), order_func); for (i = 0; i < *dir_file_count; i++) { free(entry[i]); } free(entry); } void print_dir(WINDOW *win, char print_info, unsigned long *dir_file_count, file *dir_content){ /* i am not proud of this function */ unsigned long line_width = getmaxx(win); char *bg = malloc(line_width+1); memset(bg, ' ', line_width); bg[line_width] = '\0'; 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 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_content[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_content[i].file_type &= FILE_TYPE_DIR) { offset_back = line_width - (snprintf(NULL,0,"%ld", dir_content[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_content[i].status & FILE_STATUS_SELECTED) { is_selected = 1; } else { is_selected = 0; } if (dir_content[i].status & FILE_STATUS_SELECTED) { wattron(win, COLOR_PAIR(8)); } else { wattron(win, COLOR_PAIR(dir_content[i].color_pair)); } if (dir_content[i].status & FILE_STATUS_HOVER) { wattron(win, A_REVERSE); } else { wattroff(win, A_REVERSE); } /* shortens the printed file name if it is too long * example input: aaaaaaaa.txt * example output: aaa~.txt * if no extension is found, the name will truncate */ char *file_name; unsigned long printable_size = (offset_back - is_selected - offset_front); if (strlen(dir_content[i].file_name) > printable_size) { char *extension = strrchr(dir_content[i].file_name, '.'); if (extension && extension != dir_content[i].file_name) { file_name = malloc(printable_size); printable_size -= strlen(extension); memcpy(file_name, dir_content[i].file_name, printable_size); memcpy(file_name + printable_size-1, extension, strlen(extension)); file_name[printable_size + strlen(extension)-1] = '\0'; file_name[printable_size - 2] = '~'; } else { file_name = malloc(printable_size-1); memcpy(file_name, dir_content[i].file_name, printable_size); file_name[printable_size-2] = '~'; file_name[printable_size-1] = '\0'; } } else { file_name = malloc(strlen(dir_content[i].file_name)+1); memcpy(file_name, dir_content[i].file_name, strlen(dir_content[i].file_name)+1); } mvwaddstr(win, i-offset_vertical, 0, bg); 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 mvwaddnstr(win, i-offset_vertical, offset_front+is_selected, file_name, line_width-offset_front-is_selected-2); if (dir_content[i].file_type &= FILE_TYPE_DIR) { mvwprintw(win, i-offset_vertical, offset_back, "%ld", dir_content[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); } } else { mvwaddnstr(win, i-offset_vertical, 0, file_name, line_width); } free(file_name); if (dir_content[i].status & FILE_STATUS_SELECTED) { wattroff(win, COLOR_PAIR(8)); } else { wattroff(win, COLOR_PAIR(dir_content[i].color_pair)); } } free(bg); } char update_selected_file(){ char ret = -1; /* -1 on empty or inaccessible file, 0 on unchanged file, 1 on changed file */ if (mid_content->file_name[0] == '\0') { /* only happens if the current path is either empty or inaccessible */ return ret; } if (selected_file_current >= mid_file_count) { selected_file_current = mid_file_count-1; } if (selected_file_current != selected_file_last) { mid_content[selected_file_last].status &= ~FILE_STATUS_HOVER; ret = 1; } else { ret = 0; } mid_content[selected_file_current].status |= FILE_STATUS_HOVER; selected_file_last = selected_file_current; return ret; } void dir_set_selected_file_current(unsigned long selected_file_current){ if (mid_content->file_name[0] != '\0') { current_dir->selected_file_current = selected_file_current; } } unsigned long dir_get_selected_file_current(){ current_dir = visited_dirs; if (mid_content->file_name[0] == '\0') { return 0; } char hit = 0; char *path = getcwd(NULL, 0); while(current_dir->next != NULL) { if (strcmp(path, current_dir->path) == 0) { hit = 1; break; } current_dir = current_dir->next; } if (hit == 0) { current_dir->next = malloc(sizeof(linked_dir)); current_dir->next->next = NULL; current_dir->next->path = path; return 0; } else { free(path); return current_dir->selected_file_current; } } void dir_init(){ visited_dirs = malloc(sizeof(linked_dir)); visited_dirs->path = getcwd(NULL, 0); visited_dirs->selected_file_current = 0; visited_dirs->next = NULL; current_dir = visited_dirs; } void recursive_delete(file current_file){ 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, ¤t_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); } }