commit
1b202d5df1
6 changed files with 233 additions and 311 deletions
2
Makefile
2
Makefile
|
@ -12,7 +12,7 @@ MANDIR = $(PREFIX)/share/man/man1
|
||||||
|
|
||||||
# Flags
|
# Flags
|
||||||
LDFLAGS = $(shell pkg-config --libs ncurses)
|
LDFLAGS = $(shell pkg-config --libs ncurses)
|
||||||
CFLAGS = -O3 -pipe -s -std=c99 -pedantic -Wall $(shell pkg-config --cflags ncurses)
|
CFLAGS = -O3 -march=native -mtune=native -pipe -s -std=c99 -pedantic -Wall $(shell pkg-config --cflags ncurses)
|
||||||
|
|
||||||
SRC = ccc.c util.c file.c
|
SRC = ccc.c util.c file.c
|
||||||
|
|
||||||
|
|
19
README.md
19
README.md
|
@ -49,30 +49,37 @@ $ sudo make install
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```
|
```
|
||||||
|
h: go to parent dir
|
||||||
j: scroll down
|
j: scroll down
|
||||||
k: scroll up
|
k: scroll up
|
||||||
h: go to parent dir
|
|
||||||
l: go to child dir
|
l: go to child dir
|
||||||
|
|
||||||
|
left: go to parent dir
|
||||||
down: scroll down
|
down: scroll down
|
||||||
up: scroll up
|
up: scroll up
|
||||||
left: go to parent dir
|
|
||||||
right: go to child dir
|
right: go to child dir
|
||||||
|
|
||||||
enter: go to child dir/open file
|
enter: go to child dir/open file
|
||||||
backspace: go to parent dir
|
backspace: go to parent dir
|
||||||
|
|
||||||
g: go to top
|
gg: go to top
|
||||||
G: go to bottom
|
G: go to bottom
|
||||||
|
|
||||||
t: go to trash
|
ctrl+u: jump up
|
||||||
~: go to home
|
ctrl+d: jump down
|
||||||
|
|
||||||
|
t: go to trash dir
|
||||||
|
~: go to home dir
|
||||||
|
-: go to previous dir
|
||||||
z: refresh current dir
|
z: refresh current dir
|
||||||
|
|
||||||
|
A: show directory disk usage/block size
|
||||||
space: mark file
|
space: mark file
|
||||||
a: mark all files in directory
|
a: mark all files in directory
|
||||||
|
|
||||||
q: exit
|
?: show help
|
||||||
|
q: exit with last dir written to file
|
||||||
|
ctrl+c exit without writing last dir
|
||||||
```
|
```
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
176
ccc.c
176
ccc.c
|
@ -16,11 +16,13 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
/* functions' definitions */
|
/* functions' definitions */
|
||||||
|
void show_help();
|
||||||
|
void start_ccc();
|
||||||
void change_dir(const char *buf, int selection);
|
void change_dir(const char *buf, int selection);
|
||||||
int mkdir_p(const char *destdir);
|
int mkdir_p(const char *destdir);
|
||||||
void populate_files(const char *path, int ftype);
|
void populate_files(const char *path, int ftype);
|
||||||
int get_directory_size(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf);
|
int get_directory_size(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf);
|
||||||
long add_file_stat(char *filepath, int ftype);
|
void add_file_stat(char *filepath, int ftype);
|
||||||
void highlight_current_line();
|
void highlight_current_line();
|
||||||
void show_file_content();
|
void show_file_content();
|
||||||
void edit_file();
|
void edit_file();
|
||||||
|
@ -33,8 +35,13 @@ void draw_border_title(WINDOW *window, bool active);
|
||||||
unsigned int focus = 0;
|
unsigned int focus = 0;
|
||||||
long current_selection = 0;
|
long current_selection = 0;
|
||||||
bool dirs_size = DIRS_SIZE;
|
bool dirs_size = DIRS_SIZE;
|
||||||
|
bool show_hidden = SHOW_HIDDEN;
|
||||||
|
bool file_details = SHOW_DETAILS;
|
||||||
char *cwd;
|
char *cwd;
|
||||||
|
char *p_cwd; /* previous cwd */
|
||||||
int half_width;
|
int half_width;
|
||||||
|
ArrayList *files;
|
||||||
|
ArrayList *marked;
|
||||||
WINDOW *directory_border;
|
WINDOW *directory_border;
|
||||||
WINDOW *directory_content;
|
WINDOW *directory_content;
|
||||||
WINDOW *preview_border;
|
WINDOW *preview_border;
|
||||||
|
@ -80,15 +87,14 @@ int main(int argc, char** argv)
|
||||||
init_pair(7, COLOR_CYAN, -1); /* MARKED FILES */
|
init_pair(7, COLOR_CYAN, -1); /* MARKED FILES */
|
||||||
init_pair(8, COLOR_WHITE, -1); /* REG */
|
init_pair(8, COLOR_WHITE, -1); /* REG */
|
||||||
|
|
||||||
half_width = COLS / 2;
|
/* init files and marked arrays */
|
||||||
init_windows();
|
files = arraylist_init(100);
|
||||||
refresh();
|
marked = arraylist_init(100);
|
||||||
|
|
||||||
cwd = memalloc(PATH_MAX * sizeof(char));
|
cwd = memalloc(PATH_MAX * sizeof(char));
|
||||||
|
p_cwd = memalloc(PATH_MAX * sizeof(char));
|
||||||
getcwd(cwd, PATH_MAX);
|
getcwd(cwd, PATH_MAX);
|
||||||
|
start_ccc();
|
||||||
populate_files(cwd, 0);
|
|
||||||
highlight_current_line();
|
|
||||||
|
|
||||||
int ch, ch2;
|
int ch, ch2;
|
||||||
while (1) {
|
while (1) {
|
||||||
|
@ -118,6 +124,7 @@ int main(int argc, char** argv)
|
||||||
case LEFT:
|
case LEFT:
|
||||||
case 'h':;
|
case 'h':;
|
||||||
/* get parent directory */
|
/* get parent directory */
|
||||||
|
strcpy(p_cwd, cwd);
|
||||||
char *last_slash = strrchr(cwd, '/');
|
char *last_slash = strrchr(cwd, '/');
|
||||||
if (last_slash != NULL) {
|
if (last_slash != NULL) {
|
||||||
*last_slash = '\0';
|
*last_slash = '\0';
|
||||||
|
@ -129,15 +136,14 @@ int main(int argc, char** argv)
|
||||||
case ENTER:
|
case ENTER:
|
||||||
case RIGHT:
|
case RIGHT:
|
||||||
case 'l':;
|
case 'l':;
|
||||||
file *file = get_file(current_selection);
|
strcpy(p_cwd, cwd);
|
||||||
if (file != NULL) {
|
file c_file = files->items[current_selection];
|
||||||
/* check if it is directory or a regular file */
|
/* check if it is directory or a regular file */
|
||||||
if (strncmp(file->type, "DIR", 3) == 0) {
|
if (strncmp(c_file.type, "DIR", 3) == 0) {
|
||||||
/* change cwd to directory */
|
/* change cwd to directory */
|
||||||
change_dir(file->path, 0);
|
change_dir(c_file.path, 0);
|
||||||
} else if (strncmp(file->type, "REG", 3) == 0) {
|
} else if (strncmp(c_file.type, "REG", 3) == 0) {
|
||||||
edit_file();
|
edit_file();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -162,10 +168,10 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
/* jump down (ctrl d) */
|
/* jump down (ctrl d) */
|
||||||
case CTRLD:
|
case CTRLD:
|
||||||
if ((current_selection + JUMP_NUM) < (files_len() - 1))
|
if ((current_selection + JUMP_NUM) < (files->length - 1))
|
||||||
current_selection += JUMP_NUM;
|
current_selection += JUMP_NUM;
|
||||||
else
|
else
|
||||||
current_selection = (files_len() - 1);
|
current_selection = (files->length - 1);
|
||||||
|
|
||||||
highlight_current_line();
|
highlight_current_line();
|
||||||
break;
|
break;
|
||||||
|
@ -173,7 +179,7 @@ int main(int argc, char** argv)
|
||||||
/* go down by j or down arrow */
|
/* go down by j or down arrow */
|
||||||
case DOWN:
|
case DOWN:
|
||||||
case 'j':
|
case 'j':
|
||||||
if (current_selection < (files_len() - 1))
|
if (current_selection < (files->length - 1))
|
||||||
current_selection++;
|
current_selection++;
|
||||||
|
|
||||||
highlight_current_line();
|
highlight_current_line();
|
||||||
|
@ -181,7 +187,7 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
/* jump to the bottom */
|
/* jump to the bottom */
|
||||||
case 'G':
|
case 'G':
|
||||||
current_selection = (files_len() - 1);
|
current_selection = (files->length - 1);
|
||||||
highlight_current_line();
|
highlight_current_line();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -234,14 +240,33 @@ int main(int argc, char** argv)
|
||||||
/* show directories' sizes */
|
/* show directories' sizes */
|
||||||
case 'A':
|
case 'A':
|
||||||
dirs_size = !dirs_size;
|
dirs_size = !dirs_size;
|
||||||
clear_files();
|
change_dir(cwd, 0);
|
||||||
populate_files(cwd, 0);
|
|
||||||
highlight_current_line();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/* go to previous dir */
|
||||||
|
case '-':
|
||||||
|
change_dir(p_cwd, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* show help */
|
||||||
|
case '?':
|
||||||
|
show_help();
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* toggle hidden files */
|
||||||
|
case '.':
|
||||||
|
show_hidden = !show_hidden;
|
||||||
|
change_dir(cwd, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* toggle file details */
|
||||||
|
case 'i':
|
||||||
|
file_details = !file_details;
|
||||||
|
change_dir(cwd, 0);
|
||||||
|
|
||||||
/* mark one file */
|
/* mark one file */
|
||||||
case SPACE:
|
case SPACE:
|
||||||
add_file_stat(get_filepath(current_selection), 1);
|
add_file_stat(files->items[current_selection].path, 1);
|
||||||
highlight_current_line();
|
highlight_current_line();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -254,35 +279,35 @@ int main(int argc, char** argv)
|
||||||
/* mark actions: */
|
/* mark actions: */
|
||||||
/* delete */
|
/* delete */
|
||||||
case 'd':;
|
case 'd':;
|
||||||
if (marked_len()) {
|
if (marked->length) {
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* move */
|
/* move */
|
||||||
case 'm':;
|
case 'm':;
|
||||||
if (marked_len()) {
|
if (marked->length) {
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* copy */
|
/* copy */
|
||||||
case 'c':;
|
case 'c':;
|
||||||
if (marked_len()) {
|
if (marked->length) {
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* symbolic link */
|
/* symbolic link */
|
||||||
case 's':;
|
case 's':;
|
||||||
if (marked_len()) {
|
if (marked->length) {
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* bulk rename */
|
/* bulk rename */
|
||||||
case 'b':;
|
case 'b':;
|
||||||
if (marked_len()) {
|
if (marked->length) {
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -298,29 +323,54 @@ int main(int argc, char** argv)
|
||||||
delwin(preview_content);
|
delwin(preview_content);
|
||||||
delwin(panel);
|
delwin(panel);
|
||||||
endwin();
|
endwin();
|
||||||
half_width = COLS / 2;
|
start_ccc();
|
||||||
init_windows();
|
|
||||||
refresh();
|
|
||||||
populate_files(cwd, 0);
|
|
||||||
highlight_current_line();
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
clear_files();
|
arraylist_free(files);
|
||||||
clear_marked();
|
arraylist_free(marked);
|
||||||
endwin();
|
endwin();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
wpprintw("Visit https://github.com/piotr-marendowski/ccc or use 'man ccc' for help");
|
||||||
|
wrefresh(directory_content);
|
||||||
|
wrefresh(preview_content);
|
||||||
|
}
|
||||||
|
|
||||||
|
void start_ccc()
|
||||||
|
{
|
||||||
|
half_width = COLS / 2;
|
||||||
|
init_windows();
|
||||||
|
refresh();
|
||||||
|
populate_files(cwd, 0);
|
||||||
|
highlight_current_line();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Change directory in window with selection
|
* Change directory in window with selection
|
||||||
*/
|
*/
|
||||||
void change_dir(const char *buf, int selection)
|
void change_dir(const char *buf, int selection)
|
||||||
{
|
{
|
||||||
strcpy(cwd, buf);
|
char *buf_dup;
|
||||||
clear_files();
|
if (buf == p_cwd) {
|
||||||
|
buf_dup = strdup(p_cwd);
|
||||||
|
if (buf_dup == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
buf_dup = (char *) buf;
|
||||||
|
}
|
||||||
|
strcpy(cwd, buf_dup);
|
||||||
|
arraylist_free(files);
|
||||||
|
files = arraylist_init(100);
|
||||||
populate_files(cwd, 0);
|
populate_files(cwd, 0);
|
||||||
current_selection = selection;
|
current_selection = selection;
|
||||||
highlight_current_line();
|
highlight_current_line();
|
||||||
|
@ -398,8 +448,8 @@ void populate_files(const char *path, int ftype)
|
||||||
filename[0] = '\0';
|
filename[0] = '\0';
|
||||||
strcat(filename, ep->d_name);
|
strcat(filename, ep->d_name);
|
||||||
|
|
||||||
/* can't be strncmp as that would filter out the dotfiles */
|
/* use strncmp to filter out dotfiles */
|
||||||
if (strcmp(filename, ".") && strcmp(filename, "..")) {
|
if ((show_hidden && strncmp(filename, ".", 1) && strncmp(filename, "..", 2)) || (!show_hidden && strcmp(filename, ".") && strcmp(filename, ".."))) {
|
||||||
/* construct full file path */
|
/* construct full file path */
|
||||||
filename[0] = '\0';
|
filename[0] = '\0';
|
||||||
strcat(filename, cwd);
|
strcat(filename, cwd);
|
||||||
|
@ -428,13 +478,13 @@ int get_directory_size(const char *fpath, const struct stat *sb, int typeflag, s
|
||||||
* Add that file into list
|
* Add that file into list
|
||||||
* ftype: normal file = 0, normal marked = 1, marking ALL = 2
|
* ftype: normal file = 0, normal marked = 1, marking ALL = 2
|
||||||
*/
|
*/
|
||||||
long add_file_stat(char *filepath, int ftype)
|
void add_file_stat(char *filepath, int ftype)
|
||||||
{
|
{
|
||||||
struct stat file_stat;
|
struct stat file_stat;
|
||||||
if (stat(filepath, &file_stat) == -1) {
|
if (stat(filepath, &file_stat) == -1) {
|
||||||
/* can't be triggered? */
|
/* can't be triggered? */
|
||||||
if (errno == EACCES)
|
if (errno == EACCES)
|
||||||
return add_file(filepath, "", "", 8);
|
arraylist_add(files, filepath, "", "", 8, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get file type and color, 4 chars for the type */
|
/* get file type and color, 4 chars for the type */
|
||||||
|
@ -469,14 +519,10 @@ long add_file_stat(char *filepath, int ftype)
|
||||||
if (ftype == 1 || ftype == 2) {
|
if (ftype == 1 || ftype == 2) {
|
||||||
/* force if user is marking all files */
|
/* force if user is marking all files */
|
||||||
bool force = ftype == 2 ? true : false;
|
bool force = ftype == 2 ? true : false;
|
||||||
long index = add_marked(filepath, type, force);
|
arraylist_add(marked, filepath, NULL, type, 8, true, force);
|
||||||
/* free type and return without allocating more stuff */
|
/* free type and return without allocating more stuff */
|
||||||
free(type);
|
free(type);
|
||||||
if (index != -1) {
|
return;
|
||||||
return index; /* just marked */
|
|
||||||
} else {
|
|
||||||
return -1; /* already marked */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get last modified time */
|
/* get last modified time */
|
||||||
|
@ -511,13 +557,12 @@ long add_file_stat(char *filepath, int ftype)
|
||||||
snprintf(total_stat, 45, "%-18s %-8s", time, size);
|
snprintf(total_stat, 45, "%-18s %-8s", time, size);
|
||||||
total_stat[strlen(total_stat)] = '\0';
|
total_stat[strlen(total_stat)] = '\0';
|
||||||
|
|
||||||
long index = add_file(filepath, total_stat, type, color);
|
arraylist_add(files, filepath, total_stat, type, color, false, false);
|
||||||
|
|
||||||
free(time);
|
free(time);
|
||||||
free(size);
|
free(size);
|
||||||
free(total_stat);
|
free(total_stat);
|
||||||
free(type);
|
free(type);
|
||||||
return index;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -533,7 +578,7 @@ void highlight_current_line()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* calculate range of files to show */
|
/* calculate range of files to show */
|
||||||
long range = files_len();
|
long range = files->length;
|
||||||
/* not highlight if no files in directory */
|
/* not highlight if no files in directory */
|
||||||
if (range == 0) {
|
if (range == 0) {
|
||||||
#if DRAW_PREVIEW
|
#if DRAW_PREVIEW
|
||||||
|
@ -560,24 +605,24 @@ void highlight_current_line()
|
||||||
wclear(panel);
|
wclear(panel);
|
||||||
|
|
||||||
/* check for marked files */
|
/* check for marked files */
|
||||||
long num_marked = marked_len();
|
long num_marked = marked->length;
|
||||||
if (num_marked > 0) {
|
if (num_marked > 0) {
|
||||||
/* Determine length of formatted string */
|
/* Determine length of formatted string */
|
||||||
int m_len = snprintf(NULL, 0, "[%ld] selected", num_marked);
|
int m_len = snprintf(NULL, 0, "[%ld] selected", num_marked);
|
||||||
char *selected = memalloc((m_len + 1) * sizeof(char));
|
char *selected = memalloc((m_len + 1) * sizeof(char));
|
||||||
|
|
||||||
snprintf(selected, m_len + 1, "[%ld] selected", num_marked);
|
snprintf(selected, m_len + 1, "[%ld] selected", num_marked);
|
||||||
wprintw(panel, "(%ld/%ld) %s %s", current_selection + 1, files_len(), selected, cwd);
|
wprintw(panel, "(%ld/%ld) %s %s", current_selection + 1, files->length, selected, cwd);
|
||||||
} else {
|
} else {
|
||||||
wprintw(panel, "(%ld/%ld) %s", current_selection + 1, files_len(), cwd);
|
wprintw(panel, "(%ld/%ld) %s", current_selection + 1, files->length, cwd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* print the actual filename and stats */
|
/* print the actual filename and stats */
|
||||||
char *line = get_line(i);
|
char *line = get_line(files, i, file_details);
|
||||||
int color = get_color(i);
|
int color = files->items[i].color;
|
||||||
/* check is file marked for action */
|
/* check is file marked for action */
|
||||||
bool marked = in_marked(get_filepath(i));
|
bool is_marked = arraylist_includes(marked, files->items[i].path);
|
||||||
if (marked) {
|
if (is_marked) {
|
||||||
/* show file is selected */
|
/* show file is selected */
|
||||||
wattron(directory_content, COLOR_PAIR(7));
|
wattron(directory_content, COLOR_PAIR(7));
|
||||||
} else {
|
} else {
|
||||||
|
@ -590,7 +635,7 @@ void highlight_current_line()
|
||||||
else
|
else
|
||||||
mvwprintw(directory_content, i, 0, "%s", line);
|
mvwprintw(directory_content, i, 0, "%s", line);
|
||||||
|
|
||||||
if (marked) {
|
if (is_marked) {
|
||||||
wattroff(directory_content, COLOR_PAIR(7));
|
wattroff(directory_content, COLOR_PAIR(7));
|
||||||
} else {
|
} else {
|
||||||
wattroff(directory_content, COLOR_PAIR(color));
|
wattroff(directory_content, COLOR_PAIR(color));
|
||||||
|
@ -616,14 +661,14 @@ void highlight_current_line()
|
||||||
void show_file_content()
|
void show_file_content()
|
||||||
{
|
{
|
||||||
wclear(preview_content);
|
wclear(preview_content);
|
||||||
file *current_file = get_file((long) current_selection);
|
file current_file = files->items[current_selection];
|
||||||
|
|
||||||
if (strncmp(current_file->type, "DIR", 3) == 0)
|
if (strncmp(current_file.type, "DIR", 3) == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
FILE *file = fopen(current_file->path, "r");
|
FILE *file = fopen(current_file.path, "r");
|
||||||
if (file == NULL) {
|
if (file == NULL) {
|
||||||
mvwprintw(preview_content, 0, 0, "Unable to read %s", current_file->path);
|
mvwprintw(preview_content, 0, 0, "Unable to read %s", current_file.path);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#if DRAW_BORDERS
|
#if DRAW_BORDERS
|
||||||
|
@ -673,7 +718,7 @@ void edit_file()
|
||||||
def_prog_mode(); /* save the tty modes */
|
def_prog_mode(); /* save the tty modes */
|
||||||
endwin(); /* end curses mode temporarily */
|
endwin(); /* end curses mode temporarily */
|
||||||
|
|
||||||
char *filename = get_filepath(current_selection);
|
char *filename = files->items[current_selection].path;
|
||||||
int length = strlen(editor) + strlen(filename) + 2; /* one for space one for null */
|
int length = strlen(editor) + strlen(filename) + 2; /* one for space one for null */
|
||||||
char command[length];
|
char command[length];
|
||||||
|
|
||||||
|
@ -685,7 +730,8 @@ void edit_file()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int write_last_d() {
|
int write_last_d()
|
||||||
|
{
|
||||||
#ifdef LAST_D
|
#ifdef LAST_D
|
||||||
char *last_d = memalloc(PATH_MAX * sizeof(char));
|
char *last_d = memalloc(PATH_MAX * sizeof(char));
|
||||||
strcpy(last_d, LAST_D);
|
strcpy(last_d, LAST_D);
|
||||||
|
|
2
config.h
2
config.h
|
@ -8,6 +8,8 @@
|
||||||
|
|
||||||
#define DRAW_BORDERS true /* Draw borders around windows? */
|
#define DRAW_BORDERS true /* Draw borders around windows? */
|
||||||
#define DRAW_PREVIEW true /* Draw file preview? */
|
#define DRAW_PREVIEW true /* Draw file preview? */
|
||||||
|
#define SHOW_HIDDEN true /* show hidden files/dotfiles in preview */
|
||||||
|
#define SHOW_DETAILS true /* show file details */
|
||||||
|
|
||||||
/* set width offset for windows:
|
/* set width offset for windows:
|
||||||
+-------------%-------------+
|
+-------------%-------------+
|
||||||
|
|
316
file.c
316
file.c
|
@ -5,274 +5,142 @@
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
/* files in a link list data structure */
|
|
||||||
typedef struct file {
|
typedef struct file {
|
||||||
char *path;
|
char *path;
|
||||||
char *stats;
|
char *stats;
|
||||||
char *type;
|
char *type;
|
||||||
int color;
|
int color;
|
||||||
struct file *next;
|
|
||||||
} file;
|
} file;
|
||||||
|
|
||||||
file *files = NULL;
|
typedef struct ArrayList {
|
||||||
file *marked = NULL;
|
size_t length;
|
||||||
|
size_t capacity;
|
||||||
|
file *items;
|
||||||
|
} ArrayList;
|
||||||
|
|
||||||
/*
|
ArrayList *arraylist_init(size_t capacity)
|
||||||
* Get length of files linked list
|
|
||||||
*/
|
|
||||||
long files_len()
|
|
||||||
{
|
{
|
||||||
file *current = files;
|
ArrayList *list = memalloc(sizeof(ArrayList));
|
||||||
int count = 0;
|
list->length = 0;
|
||||||
while (current != NULL) {
|
list->capacity = capacity;
|
||||||
count++;
|
list->items = memalloc(capacity * sizeof(file));
|
||||||
current = current->next;
|
return list;
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
void arraylist_free(ArrayList *list)
|
||||||
* Get length of marked files
|
|
||||||
*/
|
|
||||||
long marked_len()
|
|
||||||
{
|
{
|
||||||
file *current = marked;
|
for (size_t i = 0; i < list->length; i++) {
|
||||||
int count = 0;
|
if (list->items[i].type != NULL)
|
||||||
while (current != NULL) {
|
free(list->items[i].type);
|
||||||
count++;
|
if (list->items[i].path != NULL)
|
||||||
current = current->next;
|
free(list->items[i].path);
|
||||||
|
if (list->items[i].stats != NULL)
|
||||||
|
free(list->items[i].stats);
|
||||||
}
|
}
|
||||||
return count;
|
free(list->items);
|
||||||
|
list->length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_file(file *toremove)
|
bool arraylist_includes(ArrayList *list, char *path)
|
||||||
{
|
{
|
||||||
if (toremove->type != NULL)
|
for (int i = 0; i < list->length; i++) {
|
||||||
free(toremove->type);
|
if (strcmp(list->items[i].path, path) == 0) {
|
||||||
if (toremove->path != NULL)
|
return true;
|
||||||
free(toremove->path);
|
}
|
||||||
if (toremove->stats != NULL)
|
}
|
||||||
free(toremove->stats);
|
return false;
|
||||||
free(toremove);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear_files()
|
void arraylist_remove(ArrayList *list, long index)
|
||||||
{
|
{
|
||||||
file *tmp;
|
if (index >= list->length) {
|
||||||
while (files != NULL) {
|
|
||||||
tmp = files;
|
|
||||||
files = files->next;
|
|
||||||
free_file(tmp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear_marked()
|
|
||||||
{
|
|
||||||
file *tmp;
|
|
||||||
while (marked != NULL) {
|
|
||||||
tmp = marked;
|
|
||||||
files = marked->next;
|
|
||||||
free_file(tmp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
long add_file(char *filepath, char *stats, char *type, int color)
|
|
||||||
{
|
|
||||||
file *current = files;
|
|
||||||
file *new_file = memalloc(sizeof(file));
|
|
||||||
char *buf = strdup(filepath);
|
|
||||||
char *buf2 = strdup(stats);
|
|
||||||
char *buf3 = strdup(type);
|
|
||||||
int buf4 = color;
|
|
||||||
|
|
||||||
if (buf == NULL || buf2 == NULL || buf3 == NULL)
|
|
||||||
perror("ccc");
|
|
||||||
|
|
||||||
new_file->path = buf;
|
|
||||||
new_file->stats = buf2;
|
|
||||||
new_file->type = buf3;
|
|
||||||
new_file->color = buf4;
|
|
||||||
new_file->next = NULL;
|
|
||||||
|
|
||||||
if (current == NULL) {
|
|
||||||
files = new_file;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
long index = 1;
|
|
||||||
while (current->next != NULL) {
|
|
||||||
current = current->next;
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
current->next = new_file;
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
void remove_marked(file *marked_file)
|
|
||||||
{
|
|
||||||
/* If the head node itself is marked for removal */
|
|
||||||
if (marked == marked_file) {
|
|
||||||
marked = marked->next;
|
|
||||||
free_file(marked_file);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Search for the marked file node in the list */
|
free(list->items[index].path);
|
||||||
file* temp = marked;
|
free(list->items[index].stats);
|
||||||
while (temp != NULL && temp->next != marked_file) {
|
free(list->items[index].type);
|
||||||
temp = temp->next;
|
|
||||||
|
for (long i = index; i < list->length - 1; i++) {
|
||||||
|
list->items[i] = list->items[i + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the marked file node is found, remove it from the list */
|
list->length--;
|
||||||
if (temp != NULL) {
|
|
||||||
temp->next = marked_file->next;
|
|
||||||
free_file(marked_file);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* force will not remove duplicate marked files, instead it just skip adding
|
* force will not remove duplicate marked files, instead it just skip adding
|
||||||
*/
|
*/
|
||||||
long add_marked(char *filepath, char *type, bool force)
|
void arraylist_add(ArrayList *list, char *filepath, char *stats, char *type, int color, bool marked, bool force)
|
||||||
{
|
{
|
||||||
file *current = marked;
|
char *filepath_cp = NULL;
|
||||||
file *new_file = memalloc(sizeof(file));
|
char *stats_cp = NULL;
|
||||||
char *buf = strdup(filepath);
|
char *type_cp = NULL;
|
||||||
char *buf2 = strdup(type);
|
if (filepath != NULL) {
|
||||||
if (buf == NULL || buf2 == NULL) {
|
filepath_cp = strdup(filepath);
|
||||||
perror("ccc");
|
if (filepath_cp == NULL) {
|
||||||
|
perror("ccc");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
new_file->path = buf;
|
if (stats != NULL) {
|
||||||
new_file->type = buf2;
|
stats_cp = strdup(stats);
|
||||||
new_file->stats = NULL;
|
if (stats_cp == NULL) {
|
||||||
new_file->color = 0;
|
perror("ccc");
|
||||||
new_file->next = NULL;
|
}
|
||||||
if (current == NULL) {
|
|
||||||
marked = new_file;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
if (type != NULL) {
|
||||||
long index = 1;
|
type_cp = strdup(type);
|
||||||
while (current->next != NULL) {
|
if (type_cp == NULL) {
|
||||||
if (strcmp(current->path, new_file->path) == 0) {
|
perror("ccc");
|
||||||
if (force) {
|
}
|
||||||
return index;
|
}
|
||||||
} else {
|
|
||||||
remove_marked(current);
|
/* path, stats, type, color */
|
||||||
free_file(new_file);
|
file new_file = { filepath_cp, stats_cp, type_cp, color };
|
||||||
return -1;
|
|
||||||
|
if (list->capacity != list->length) {
|
||||||
|
if (marked) {
|
||||||
|
for (int i = 0; i < list->length; i++) {
|
||||||
|
if (strcmp(list->items[i].path, new_file.path) == 0) {
|
||||||
|
if (!force) {
|
||||||
|
arraylist_remove(list, i);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
current = current->next;
|
list->items[list->length] = new_file;
|
||||||
index++;
|
|
||||||
}
|
|
||||||
if (strcmp(current->path, new_file->path) == 0){
|
|
||||||
if (force) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
remove_marked(current);
|
|
||||||
free_file(new_file);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
current->next = new_file;
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
file *get_marked(long index)
|
|
||||||
{
|
|
||||||
file *current = marked;
|
|
||||||
if (index == 0) {
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
if (index > files_len()) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
for (long i = 0; i < index; i++) {
|
|
||||||
current = current->next;
|
|
||||||
}
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool in_marked(char *path)
|
|
||||||
{
|
|
||||||
file *tmp = marked;
|
|
||||||
if (tmp == NULL)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
while (tmp != NULL) {
|
|
||||||
if (strcmp(path, tmp->path) == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
tmp = tmp->next;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
file *get_file(long index)
|
|
||||||
{
|
|
||||||
file *current = files;
|
|
||||||
if (index == 0) {
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
if (index > files_len()) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
for (long i = 0; i < index; i++) {
|
|
||||||
current = current->next;
|
|
||||||
}
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *get_filepath(long index)
|
|
||||||
{
|
|
||||||
file *file = get_file(index);
|
|
||||||
if (file != NULL) {
|
|
||||||
char *name = strdup(file->path);
|
|
||||||
if (!name) {
|
|
||||||
perror("ccc");
|
|
||||||
}
|
|
||||||
return name;
|
|
||||||
} else {
|
} else {
|
||||||
return NULL;
|
int new_cap = list->capacity * 2;
|
||||||
}
|
file *new_items = memalloc(new_cap * sizeof(file));
|
||||||
}
|
file *old_items = list->items;
|
||||||
|
list->capacity = new_cap;
|
||||||
int get_color(long index)
|
list->items = new_items;
|
||||||
{
|
for (int i = 0; i < list->length; i++) {
|
||||||
file *file = get_file(index);
|
new_items[i] = old_items[i];
|
||||||
if (file != NULL) {
|
|
||||||
int color = file->color;
|
|
||||||
if (!color) {
|
|
||||||
perror("ccc");
|
|
||||||
}
|
}
|
||||||
return color;
|
free(old_items);
|
||||||
} else {
|
list->items[list->length] = new_file;
|
||||||
return 8; /* white */
|
|
||||||
}
|
}
|
||||||
|
list->length++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Construct a formatted line for display
|
* Construct a formatted line for display
|
||||||
*/
|
*/
|
||||||
char *get_line(long index)
|
char *get_line(ArrayList *list, long index, bool detail)
|
||||||
{
|
{
|
||||||
file *file = get_file(index);
|
file file = list->items[index];
|
||||||
if (file != NULL) {
|
char *name = strdup(file.path);
|
||||||
char *name = strdup(file->path);
|
char *stats = strdup(file.stats);
|
||||||
char *stats = strdup(file->stats);
|
size_t length = strlen(name) + strlen(stats) + 2; /* one for space and one for null */
|
||||||
size_t length = strlen(name) + strlen(stats) + 2; /* one for space and one for null */
|
char *line = memalloc(length * sizeof(char));
|
||||||
char *line = memalloc(length * sizeof(char));
|
|
||||||
|
|
||||||
name = basename(name);
|
name = basename(name);
|
||||||
if (name == NULL || stats == NULL)
|
if (name == NULL || stats == NULL)
|
||||||
perror("ccc");
|
perror("ccc");
|
||||||
|
|
||||||
snprintf(line, length, "%s %s", stats, name);
|
snprintf(line, length, "%s %s", stats, name);
|
||||||
|
|
||||||
return line;
|
return line;
|
||||||
} else {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
29
file.h
29
file.h
|
@ -1,27 +1,26 @@
|
||||||
#ifndef FILE_H_
|
#ifndef FILE_H_
|
||||||
#define FILE_H_
|
#define FILE_H_
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
typedef struct file {
|
typedef struct file {
|
||||||
char *path;
|
char *path;
|
||||||
char *stats;
|
char *stats;
|
||||||
char *type;
|
char *type;
|
||||||
int color;
|
int color;
|
||||||
struct file *next;
|
|
||||||
} file;
|
} file;
|
||||||
|
|
||||||
long files_len();
|
typedef struct ArrayList {
|
||||||
long marked_len();
|
size_t length;
|
||||||
void free_file(file *toremove);
|
size_t capacity;
|
||||||
void clear_files();
|
file *items;
|
||||||
void clear_marked();
|
} ArrayList;
|
||||||
long add_file(char *filepath, char *stats, char *type, int color);
|
|
||||||
void remove_marked(file *marked_file);
|
ArrayList *arraylist_init(size_t capacity);
|
||||||
long add_marked(char *filepath, char *type, bool force);
|
void arraylist_free(ArrayList *list);
|
||||||
file *get_marked(long index);
|
bool arraylist_includes(ArrayList *list, char *path);
|
||||||
bool in_marked(char *path);
|
void arraylist_remove(ArrayList *list, long index);
|
||||||
file *get_file(long index);
|
void arraylist_add(ArrayList *list, char *filepath, char *stats, char *type, int color, bool marked, bool force);
|
||||||
char *get_filepath(long index);
|
char *get_line(ArrayList *list, long index, bool detail);
|
||||||
int get_color(long index);
|
|
||||||
char *get_line(long index);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue