diff --git a/ccc.c b/ccc.c index 3c324c6..db8f2e3 100644 --- a/ccc.c +++ b/ccc.c @@ -23,11 +23,13 @@ int mkdir_p(const char *destdir); void populate_files(const char *path, int ftype); int get_directory_size(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf); void add_file_stat(char *filepath, int ftype); +char *get_file_mode(mode_t mode); void highlight_current_line(); void show_file_content(); void edit_file(); +void toggle_executable(); int write_last_d(); -void wpprintw(const char *line); +void wpprintw(const char *fmt, ...); void init_windows(); void draw_border_title(WINDOW *window, bool active); @@ -54,6 +56,13 @@ int main(int argc, char** argv) { if (argc > 1 && strcmp(argv[1], "-h") == 0) die("Usage: ccc filename"); + if (argc == 2) { + struct stat st; + if (lstat(argv[1], &st) != 0) { + perror("ccc"); + die("Error from lstat"); + } + } /* check if it is interactive shell */ if (!isatty(STDIN_FILENO)) @@ -92,10 +101,14 @@ int main(int argc, char** argv) marked = arraylist_init(100); cwd = memalloc(PATH_MAX * sizeof(char)); + if (argc == 2) { + strcpy(cwd, argv[1]); + } else { + getcwd(cwd, PATH_MAX); + } p_cwd = memalloc(PATH_MAX * sizeof(char)); - getcwd(cwd, PATH_MAX); - populate_files(cwd, 0); start_ccc(); + populate_files(cwd, 0); int ch, ch2; while (1) { @@ -268,6 +281,11 @@ int main(int argc, char** argv) case 'i': file_details = !file_details; change_dir(cwd, 0, 0); + break; + + case 'X': + toggle_executable(); + break; /* mark one file */ case SPACE: @@ -328,6 +346,7 @@ int main(int argc, char** argv) delwin(panel); endwin(); start_ccc(); + highlight_current_line(); break; default: break; @@ -343,7 +362,7 @@ void show_help() { wclear(directory_content); wclear(preview_content); - wprintw(directory_content,"h: go to parent dir\nj: scroll down\nk: scroll up\nl: go to child dir\n\nleft: go to parent dir\ndown: scroll down\nup: scroll up\nright: go to child dir\n\nenter: go to child dir/open file\nbackspace: go to parent dir\n\ngg: go to top\nG: go to bottom\n\nctrl+u: jump up\nctrl+d: jump down\n\nt: go to trash dir\n~: go to home dir\n-: go to previous dir\nz: refresh current dir\n\nA: show directory disk usage/block size\nspace: mark file\na: mark all files in directory\n\n?: show help\nq: exit with last dir written to file\nctrl+c exit without writing last dir"); + wprintw(directory_content,"h: go to parent dir\nj: scroll down\nk: scroll up\nl: go to child dir\n\nleft: go to parent dir\ndown: scroll down\nup: scroll up\nright: go to child dir\n\nenter: go to child dir/open file\nbackspace: go to parent dir\n\ngg: go to top\nG: go to bottom\n\nctrl+u: jump up\nctrl+d: jump down\n\nt: go to trash dir\n~: go to home dir\n-: go to previous dir\nz: refresh current dir\n\nA: show directory disk usage/block size\nX: toggle executable\nspace: mark file\na: mark all files in directory\n\n?: show help\nq: exit with last dir written to file\nctrl+c exit without writing last dir"); wpprintw("Visit https://github.com/piotr-marendowski/ccc or use 'man ccc' for help"); wrefresh(directory_content); wrefresh(preview_content); @@ -353,7 +372,6 @@ void start_ccc() { half_width = COLS / 2; init_windows(); - highlight_current_line(); } /* @@ -373,9 +391,8 @@ void change_dir(const char *buf, int selection, int ftype) strcpy(cwd, buf_dup); arraylist_free(files); files = arraylist_init(100); - populate_files(cwd, ftype); current_selection = selection; - highlight_current_line(); + populate_files(cwd, ftype); } /* @@ -461,12 +478,10 @@ void populate_files(const char *path, int ftype) } closedir(dp); wrefresh(directory_content); + highlight_current_line(); } else { - perror("ccc"); + wpprintw("stat failed: %s\n", strerror(errno)); } - #if DRAW_BORDERS - draw_border_title(directory_border, true); - #endif } int get_directory_size(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) @@ -555,8 +570,11 @@ void add_file_stat(char *filepath, int ftype) /* display sizes */ sprintf(size, "%.3g%s", bytes, units[unit]); - char *total_stat = memalloc(45 * sizeof(char)); - snprintf(total_stat, 45, "%-18s %-8s", time, size); + /* get file mode string */ + char *mode_str = get_file_mode(file_stat.st_mode); + + char *total_stat = memalloc(56 * sizeof(char)); + snprintf(total_stat, 56, "%s %s %-8s", mode_str, time, size); total_stat[strlen(total_stat)] = '\0'; arraylist_add(files, filepath, total_stat, type, color, false, false); @@ -565,14 +583,39 @@ void add_file_stat(char *filepath, int ftype) free(size); free(total_stat); free(type); + free(mode_str); } +/* + * get file mode string from stat mode + * eg: drwxr-sr-x + */ +char *get_file_mode(mode_t mode) +{ + char *mode_str = memalloc(sizeof(char) * 11); + mode_str[0] = S_ISDIR(mode) ? 'd' : '-'; // Check if it's a directory + mode_str[1] = (mode & S_IRUSR) ? 'r' : '-'; + mode_str[2] = (mode & S_IWUSR) ? 'w' : '-'; + mode_str[3] = (mode & S_IXUSR) ? 'x' : '-'; + mode_str[4] = (mode & S_IRGRP) ? 'r' : '-'; + mode_str[5] = (mode & S_IWGRP) ? 'w' : '-'; + mode_str[6] = (mode & S_IXGRP) ? 'x' : '-'; + mode_str[7] = (mode & S_IROTH) ? 'r' : '-'; + mode_str[8] = (mode & S_IWOTH) ? 'w' : '-'; + mode_str[9] = (mode & S_IXOTH) ? 'x' : '-'; + mode_str[10] = '\0'; // Null terminator + return mode_str; +} /* * Highlight current line by reversing the color */ void highlight_current_line() { + #if DRAW_BORDERS + draw_border_title(directory_border, true); + #endif + long overflow = 0; if (current_selection > LINES - 4) { /* overflown */ @@ -582,7 +625,7 @@ void highlight_current_line() /* calculate range of files to show */ long range = files->length; /* not highlight if no files in directory */ - if (range == 0) { + if (range == 0 && errno == 0) { #if DRAW_PREVIEW wprintw(preview_content, "empty directory"); wrefresh(preview_content); @@ -603,9 +646,6 @@ void highlight_current_line() if ((overflow == 0 && i == current_selection) || (overflow != 0 && i == current_selection)) { wattron(directory_content, A_REVERSE); - /* update the panel */ - wclear(panel); - /* check for marked files */ long num_marked = marked->length; if (num_marked > 0) { @@ -614,9 +654,9 @@ void highlight_current_line() char *selected = memalloc((m_len + 1) * sizeof(char)); snprintf(selected, m_len + 1, "[%ld] selected", num_marked); - wprintw(panel, "(%ld/%ld) %s %s", current_selection + 1, files->length, selected, cwd); + wpprintw("(%ld/%ld) %s %s", current_selection + 1, files->length, selected, cwd); } else { - wprintw(panel, "(%ld/%ld) %s", current_selection + 1, files->length, cwd); + wpprintw("(%ld/%ld) %s", current_selection + 1, files->length, cwd); } } /* print the actual filename and stats */ @@ -655,6 +695,9 @@ void highlight_current_line() show_file_content(); #endif wrefresh(preview_content); + #if DRAW_BORDERS + draw_border_title(preview_border, true); + #endif } /* @@ -673,10 +716,7 @@ void show_file_content() mvwprintw(preview_content, 0, 0, "Unable to read %s", current_file.path); return; } - #if DRAW_BORDERS - draw_border_title(preview_border, true); - #endif - + int c; /* check if its binary */ while ((c = fgetc(file)) != EOF) { @@ -732,6 +772,22 @@ void edit_file() } } +void toggle_executable() +{ + file current_file = files->items[current_selection]; + struct stat st; + if (stat(current_file.path, &st) == -1) { + wpprintw("stat failed: %s\n", strerror(errno)); + } + if (strncmp(current_file.type, "DIR", 3) == 0) + return; + /* chmod by xor executable bits */ + if (chmod(current_file.path, st.st_mode ^ (S_IXUSR | S_IXGRP | S_IXOTH)) == -1) { + wpprintw("Error toggling executable: %s", strerror(errno)); + } + +} + int write_last_d() { #ifdef LAST_D @@ -772,10 +828,13 @@ int write_last_d() /* * Print line to the panel */ -void wpprintw(const char *line) +void wpprintw(const char *fmt, ...) { + va_list args; + va_start(args, fmt); wclear(panel); - wprintw(panel, "%s", line); + vw_printw(panel, fmt, args); + va_end(args); wrefresh(panel); } diff --git a/file.c b/file.c index e954dd3..6430419 100644 --- a/file.c +++ b/file.c @@ -132,15 +132,27 @@ char *get_line(ArrayList *list, long index, bool detail) { file file = list->items[index]; char *name = strdup(file.path); - char *stats = strdup(file.stats); - size_t length = strlen(name) + strlen(stats) + 2; /* one for space and one for null */ + char *stats = NULL; + size_t length; + if (detail) { + stats = strdup(file.stats); + length = strlen(name) + strlen(stats) + 2; /* one for space and one for null */ + if (stats == NULL) { + perror("ccc"); + } + } else { + length = strlen(name) + 2; /* one for space and one for null */ + } char *line = memalloc(length * sizeof(char)); name = basename(name); - if (name == NULL || stats == NULL) + if (name == NULL) perror("ccc"); - - snprintf(line, length, "%s %s", stats, name); + if (detail) { + snprintf(line, length, "%s %s", stats, name); + } else { + snprintf(line, length, "%s", name); + } return line; }