2024-03-14 00:51:05 +01:00
# define _XOPEN_SOURCE 600
2024-03-14 11:52:01 +01:00
2024-03-09 18:37:04 +01:00
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <string.h>
2024-03-09 19:24:38 +01:00
# include <dirent.h> /* directories etc. */
2024-03-11 22:54:14 +01:00
# include <sys/stat.h>
2024-03-13 20:37:26 +01:00
# include <errno.h>
2024-03-14 00:51:05 +01:00
# include <ftw.h>
2024-03-11 22:54:14 +01:00
# include <time.h>
2024-03-09 18:37:04 +01:00
# include <ncurses.h>
2024-03-29 23:34:26 +01:00
# include <locale.h>
# include <wchar.h>
2024-03-09 18:37:04 +01:00
2024-03-30 04:39:02 +01:00
# include "config.h"
2024-03-09 20:14:26 +01:00
# include "file.h"
2024-03-30 04:39:02 +01:00
# include "icons.h"
2024-03-09 18:37:04 +01:00
# include "util.h"
2024-03-09 19:24:38 +01:00
/* functions' definitions */
2024-03-20 17:03:54 +01:00
void show_help ( ) ;
2024-03-20 13:28:08 +01:00
void start_ccc ( ) ;
2024-03-29 23:34:26 +01:00
char * check_trash_dir ( ) ;
2024-03-20 23:43:34 +01:00
void change_dir ( const char * buf , int selection , int ftype ) ;
2024-03-29 23:34:26 +01:00
void mkdir_p ( const char * destdir ) ;
2024-03-16 22:09:47 +01:00
void populate_files ( const char * path , int ftype ) ;
2024-03-14 00:51:05 +01:00
int get_directory_size ( const char * fpath , const struct stat * sb , int typeflag , struct FTW * ftwbuf ) ;
2024-03-31 22:44:05 +02:00
void add_file_stat ( char * filename , char * path , int ftype ) ;
2024-03-29 15:05:01 +01:00
char * get_file_mode ( mode_t mode ) ;
2024-03-09 18:37:04 +01:00
void highlight_current_line ( ) ;
void show_file_content ( ) ;
2024-03-11 16:57:41 +01:00
void edit_file ( ) ;
2024-03-29 15:05:01 +01:00
void toggle_executable ( ) ;
2024-04-07 01:11:01 +02:00
char * replace_home ( char * str ) ;
2024-03-19 23:07:05 +01:00
int write_last_d ( ) ;
2024-04-07 23:25:58 +02:00
void sort_files ( ) ;
2024-04-10 14:51:39 +02:00
char * get_panel_string ( char * prompt ) ;
void rename_file ( ) ;
void goto_dir ( ) ;
void create_dir ( ) ;
2024-04-02 03:30:28 +02:00
void create_file ( ) ;
void delete_files ( ) ;
2024-03-29 15:05:01 +01:00
void wpprintw ( const char * fmt , . . . ) ;
2024-03-09 18:37:04 +01:00
void init_windows ( ) ;
2024-03-17 23:58:31 +01:00
void draw_border_title ( WINDOW * window , bool active ) ;
2024-03-09 18:37:04 +01:00
2024-03-09 19:24:38 +01:00
/* global variables */
2024-03-09 18:37:04 +01:00
unsigned int focus = 0 ;
2024-03-10 21:23:15 +01:00
long current_selection = 0 ;
2024-04-06 22:41:36 +02:00
bool file_picker = false ;
2024-03-31 01:20:29 +01:00
bool to_open_file = false ;
2024-03-16 21:37:56 +01:00
bool dirs_size = DIRS_SIZE ;
2024-03-20 19:21:02 +01:00
bool show_hidden = SHOW_HIDDEN ;
2024-03-20 21:29:04 +01:00
bool file_details = SHOW_DETAILS ;
2024-04-02 02:18:34 +02:00
bool show_icons = SHOW_ICONS ;
2024-04-01 23:23:10 +02:00
char * argv_cp ;
2024-03-12 21:59:36 +01:00
char * cwd ;
2024-03-20 15:45:01 +01:00
char * p_cwd ; /* previous cwd */
2024-03-09 19:39:29 +01:00
int half_width ;
2024-03-20 21:29:04 +01:00
ArrayList * files ;
ArrayList * marked ;
2024-04-06 19:40:42 +02:00
ArrayList * tmp1 ;
ArrayList * tmp2 ;
2024-03-12 21:59:36 +01:00
WINDOW * directory_border ;
WINDOW * directory_content ;
WINDOW * preview_border ;
WINDOW * preview_content ;
WINDOW * panel ;
2024-03-09 18:37:04 +01:00
2024-03-14 00:51:05 +01:00
unsigned long total_dir_size ;
2024-03-09 18:37:04 +01:00
int main ( int argc , char * * argv )
{
2024-04-06 22:41:36 +02:00
if ( argc = = 3 ) {
if ( strncmp ( argv [ 2 ] , " -p " , 2 ) = = 0 )
file_picker = true ;
}
if ( argc < = 3 & & argc ! = 1 ) {
if ( strncmp ( argv [ 1 ] , " -h " , 2 ) = = 0 )
2024-04-03 21:14:36 +02:00
die ( " Usage: ccc filename " ) ;
2024-03-29 15:05:01 +01:00
struct stat st ;
2024-03-31 01:01:29 +01:00
if ( lstat ( argv [ 1 ] , & st ) ) {
2024-03-29 15:05:01 +01:00
perror ( " ccc " ) ;
die ( " Error from lstat " ) ;
}
2024-03-31 01:01:29 +01:00
/* chdir to directory from argument */
2024-03-31 01:20:29 +01:00
if ( S_ISDIR ( st . st_mode ) & & chdir ( argv [ 1 ] ) ) {
2024-03-31 01:01:29 +01:00
perror ( " ccc " ) ;
die ( " Error from chdir " ) ;
2024-04-01 23:23:10 +02:00
} else if ( S_ISREG ( st . st_mode ) ) {
argv_cp = estrdup ( argv [ 1 ] ) ;
char * last_slash = strrchr ( argv_cp , ' / ' ) ;
* last_slash = ' \0 ' ;
if ( chdir ( argv [ 1 ] ) ) {
perror ( " ccc " ) ;
die ( " Error from chdir " ) ;
}
2024-03-31 01:20:29 +01:00
to_open_file = true ;
}
2024-03-29 15:05:01 +01:00
}
2024-03-10 21:23:15 +01:00
2024-03-10 11:54:08 +01:00
/* check if it is interactive shell */
2024-03-09 18:37:04 +01:00
if ( ! isatty ( STDIN_FILENO ) )
die ( " ccc: No tty detected. ccc requires an interactive shell to run. \n " ) ;
2024-03-09 19:24:38 +01:00
2024-03-10 21:23:15 +01:00
/* initialize screen, don't print special chars,
2024-03-14 13:46:38 +01:00
* make ctrl + c work , don ' t show cursor
* enable arrow keys */
2024-03-29 23:34:26 +01:00
setlocale ( LC_ALL , " " ) ;
2024-03-09 18:37:04 +01:00
initscr ( ) ;
noecho ( ) ;
2024-03-10 21:23:15 +01:00
cbreak ( ) ;
2024-03-09 18:37:04 +01:00
curs_set ( 0 ) ;
2024-03-14 11:52:01 +01:00
keypad ( stdscr , TRUE ) ;
2024-03-09 18:37:04 +01:00
2024-03-10 11:54:08 +01:00
/* check terminal has colors */
if ( ! has_colors ( ) ) {
2024-03-09 18:37:04 +01:00
endwin ( ) ;
die ( " ccc: Color is not supported in your terminal. \n " ) ;
2024-03-10 11:54:08 +01:00
} else {
2024-03-13 11:18:35 +01:00
use_default_colors ( ) ;
2024-03-09 19:24:38 +01:00
start_color ( ) ;
}
2024-03-14 15:58:03 +01:00
/* colors */
init_pair ( 1 , COLOR_BLACK , - 1 ) ; /* */
init_pair ( 2 , COLOR_RED , - 1 ) ; /* */
init_pair ( 3 , COLOR_GREEN , - 1 ) ; /* LNK */
init_pair ( 4 , COLOR_YELLOW , - 1 ) ; /* BLK */
init_pair ( 5 , COLOR_BLUE , - 1 ) ; /* DIR */
init_pair ( 6 , COLOR_MAGENTA , - 1 ) ; /* */
2024-03-15 19:28:37 +01:00
init_pair ( 7 , COLOR_CYAN , - 1 ) ; /* MARKED FILES */
2024-03-14 15:58:03 +01:00
init_pair ( 8 , COLOR_WHITE , - 1 ) ; /* REG */
2024-03-09 19:24:38 +01:00
2024-03-20 21:29:04 +01:00
/* init files and marked arrays */
marked = arraylist_init ( 100 ) ;
2024-03-30 04:39:02 +01:00
hashtable_init ( ) ;
2024-03-20 21:29:04 +01:00
2024-03-12 21:59:36 +01:00
cwd = memalloc ( PATH_MAX * sizeof ( char ) ) ;
2024-03-31 01:01:29 +01:00
getcwd ( cwd , PATH_MAX ) ;
2024-03-20 15:45:01 +01:00
p_cwd = memalloc ( PATH_MAX * sizeof ( char ) ) ;
2024-03-29 15:02:52 +01:00
start_ccc ( ) ;
2024-03-31 01:20:29 +01:00
2024-03-29 15:05:01 +01:00
populate_files ( cwd , 0 ) ;
2024-03-31 01:20:29 +01:00
if ( to_open_file ) {
2024-04-01 23:23:10 +02:00
current_selection = arraylist_search ( files , argv_cp , true ) ;
2024-03-31 01:20:29 +01:00
highlight_current_line ( ) ;
}
2024-03-09 19:24:38 +01:00
2024-03-14 11:52:01 +01:00
int ch , ch2 ;
2024-03-10 11:54:08 +01:00
while ( 1 ) {
if ( COLS < 80 | | LINES < 24 ) {
2024-03-09 18:37:04 +01:00
endwin ( ) ;
die ( " ccc: Terminal size needs to be at least 80x24 \n " ) ;
}
ch = getch ( ) ;
2024-03-10 11:54:08 +01:00
switch ( ch ) {
2024-03-12 21:59:36 +01:00
/* quit */
2024-03-10 21:23:15 +01:00
case ' q ' :
2024-03-19 23:07:05 +01:00
if ( write_last_d ( ) = = - 1 ) {
/* prompt user so error message can be shown to user */
getch ( ) ;
}
2024-04-07 00:46:14 +02:00
goto cleanup ;
2024-03-12 21:59:36 +01:00
2024-03-14 15:46:06 +01:00
/* reload using z */
case ' z ' :
2024-03-20 23:43:34 +01:00
change_dir ( cwd , 0 , 0 ) ;
2024-03-09 18:37:04 +01:00
break ;
2024-03-12 21:59:36 +01:00
2024-03-14 11:52:01 +01:00
/* go back by backspace or h or left arrow */
2024-04-01 22:53:19 +02:00
case BACKSPACE : /* PASSTHROUGH */
case LEFT : /* PASSTHROUGH */
2024-03-14 13:46:38 +01:00
case ' h ' : ;
2024-03-12 21:59:36 +01:00
/* get parent directory */
2024-03-20 15:45:01 +01:00
strcpy ( p_cwd , cwd ) ;
2024-03-12 21:59:36 +01:00
char * last_slash = strrchr ( cwd , ' / ' ) ;
if ( last_slash ! = NULL ) {
2024-03-20 23:18:07 +01:00
if ( last_slash = = cwd ) {
2024-03-20 23:43:34 +01:00
change_dir ( " / " , 0 , 0 ) ;
break ;
2024-03-20 23:18:07 +01:00
}
2024-03-12 21:59:36 +01:00
* last_slash = ' \0 ' ;
2024-03-20 23:43:34 +01:00
change_dir ( cwd , 0 , 0 ) ;
2024-03-12 21:59:36 +01:00
}
2024-03-10 21:23:15 +01:00
break ;
2024-03-12 21:59:36 +01:00
2024-03-14 11:52:01 +01:00
/* enter directory/open a file using enter or l or right arrow */
2024-04-01 22:53:19 +02:00
case ENTER : /* PASSTHROUGH */
case RIGHT : /* PASSTHROUGH */
case ' l ' :
2024-03-20 15:45:01 +01:00
strcpy ( p_cwd , cwd ) ;
2024-03-20 21:29:04 +01:00
file c_file = files - > items [ current_selection ] ;
2024-04-06 22:41:36 +02:00
2024-03-20 21:29:04 +01:00
/* check if it is directory or a regular file */
if ( strncmp ( c_file . type , " DIR " , 3 ) = = 0 ) {
/* change cwd to directory */
2024-03-20 23:43:34 +01:00
change_dir ( c_file . path , 0 , 0 ) ;
2024-03-20 21:29:04 +01:00
} else if ( strncmp ( c_file . type , " REG " , 3 ) = = 0 ) {
2024-04-06 22:41:36 +02:00
/* write opened file to a file for file pickers */
if ( file_picker ) {
2024-04-07 19:43:04 +02:00
char * opened_file_path = memalloc ( PATH_MAX * sizeof ( char ) ) ;
strcpy ( opened_file_path , " ~/.cache/ccc/opened_file " ) ;
opened_file_path = replace_home ( opened_file_path ) ;
2024-04-06 22:41:36 +02:00
FILE * opened_file = fopen ( opened_file_path , " w+ " ) ;
fprintf ( opened_file , " %s \n " , c_file . path ) ;
fclose ( opened_file ) ;
endwin ( ) ;
return 0 ;
} else {
edit_file ( ) ;
}
2024-03-12 21:59:36 +01:00
}
break ;
2024-03-12 22:01:11 +01:00
2024-03-16 21:37:56 +01:00
/* jump up (ctrl u) */
2024-03-14 20:47:46 +01:00
case CTRLU :
2024-03-11 21:24:54 +01:00
if ( ( current_selection - JUMP_NUM ) > 0 )
current_selection - = JUMP_NUM ;
else
current_selection = 0 ;
highlight_current_line ( ) ;
break ;
2024-03-12 22:01:11 +01:00
2024-03-14 11:52:01 +01:00
/* go up by k or up arrow */
2024-04-01 22:53:19 +02:00
case UP : /* PASSTHROUGH */
2024-03-09 18:37:04 +01:00
case ' k ' :
2024-03-10 21:23:15 +01:00
if ( current_selection > 0 )
2024-03-09 18:37:04 +01:00
current_selection - - ;
2024-03-10 21:23:15 +01:00
2024-03-11 21:24:54 +01:00
highlight_current_line ( ) ;
break ;
2024-03-13 16:51:52 +01:00
2024-03-16 21:37:56 +01:00
/* jump down (ctrl d) */
2024-03-14 20:47:46 +01:00
case CTRLD :
2024-03-20 21:29:04 +01:00
if ( ( current_selection + JUMP_NUM ) < ( files - > length - 1 ) )
2024-03-11 21:24:54 +01:00
current_selection + = JUMP_NUM ;
else
2024-03-20 21:29:04 +01:00
current_selection = ( files - > length - 1 ) ;
2024-03-11 21:24:54 +01:00
2024-03-09 18:37:04 +01:00
highlight_current_line ( ) ;
break ;
2024-03-13 16:51:52 +01:00
2024-03-14 11:52:01 +01:00
/* go down by j or down arrow */
2024-04-01 22:53:19 +02:00
case DOWN : /* PASSTHROUGH */
2024-03-09 18:37:04 +01:00
case ' j ' :
2024-03-20 21:29:04 +01:00
if ( current_selection < ( files - > length - 1 ) )
2024-03-09 18:37:04 +01:00
current_selection + + ;
2024-03-10 21:23:15 +01:00
2024-03-09 18:37:04 +01:00
highlight_current_line ( ) ;
break ;
2024-03-13 16:51:52 +01:00
2024-03-10 21:23:15 +01:00
/* jump to the bottom */
2024-03-09 20:52:22 +01:00
case ' G ' :
2024-03-20 21:29:04 +01:00
current_selection = ( files - > length - 1 ) ;
2024-03-09 20:52:22 +01:00
highlight_current_line ( ) ;
break ;
2024-03-13 16:51:52 +01:00
2024-03-10 21:23:15 +01:00
/* jump to the top */
case ' g ' :
2024-03-14 11:52:01 +01:00
ch2 = getch ( ) ;
switch ( ch2 ) {
2024-03-10 21:23:15 +01:00
case ' g ' :
current_selection = 0 ;
highlight_current_line ( ) ;
break ;
default :
break ;
}
break ;
2024-03-14 11:52:01 +01:00
2024-03-17 11:09:22 +01:00
/* '~' go to $HOME */
2024-03-14 20:47:46 +01:00
case TILDE : ;
2024-03-14 13:46:38 +01:00
char * home = getenv ( " HOME " ) ;
if ( home = = NULL ) {
2024-04-10 14:51:39 +02:00
wpprintw ( " $HOME not defined " ) ;
2024-03-14 13:46:38 +01:00
} else {
2024-03-20 23:43:34 +01:00
change_dir ( home , 0 , 0 ) ;
2024-03-14 15:46:06 +01:00
}
break ;
2024-03-16 21:59:49 +01:00
/* go to the trash dir */
2024-03-14 15:46:06 +01:00
case ' t ' : ;
2024-03-29 23:34:26 +01:00
char * trash_dir = check_trash_dir ( ) ;
2024-04-07 23:25:58 +02:00
if ( trash_dir ! = NULL ) {
strcpy ( p_cwd , cwd ) ;
2024-03-20 23:43:34 +01:00
change_dir ( trash_dir , 0 , 0 ) ;
2024-04-07 23:25:58 +02:00
}
break ;
/* sort files */
case ' u ' :
sort_files ( ) ;
2024-03-14 13:46:38 +01:00
break ;
2024-03-16 21:59:49 +01:00
/* show directories' sizes */
2024-03-16 22:46:21 +01:00
case ' A ' :
2024-03-16 21:37:56 +01:00
dirs_size = ! dirs_size ;
2024-03-20 23:43:34 +01:00
change_dir ( cwd , 0 , 0 ) ;
2024-03-16 20:26:35 +01:00
break ;
2024-03-20 15:45:01 +01:00
/* go to previous dir */
case ' - ' :
2024-03-20 23:43:34 +01:00
change_dir ( p_cwd , 0 , 0 ) ;
2024-03-20 15:45:01 +01:00
break ;
2024-03-20 19:21:02 +01:00
/* show help */
2024-03-20 17:03:54 +01:00
case ' ? ' :
show_help ( ) ;
break ;
2024-03-20 19:21:02 +01:00
2024-03-20 21:29:04 +01:00
/* toggle hidden files */
2024-03-20 19:21:02 +01:00
case ' . ' :
show_hidden = ! show_hidden ;
2024-03-20 23:43:34 +01:00
change_dir ( cwd , 0 , 0 ) ;
2024-03-20 19:21:02 +01:00
break ;
2024-03-20 17:03:54 +01:00
2024-03-20 21:29:04 +01:00
/* toggle file details */
case ' i ' :
file_details = ! file_details ;
2024-03-20 23:43:34 +01:00
change_dir ( cwd , 0 , 0 ) ;
2024-03-29 15:05:01 +01:00
break ;
2024-04-02 02:18:34 +02:00
case ' w ' :
show_icons = ! show_icons ;
change_dir ( cwd , 0 , 0 ) ;
break ;
2024-04-02 03:30:28 +02:00
case ' f ' :
create_file ( ) ;
break ;
2024-04-10 14:51:39 +02:00
case ' n ' :
create_dir ( ) ;
break ;
case ' r ' :
rename_file ( ) ;
break ;
case ' : ' :
goto_dir ( ) ;
break ;
2024-04-02 03:30:28 +02:00
2024-03-29 15:05:01 +01:00
case ' X ' :
toggle_executable ( ) ;
break ;
2024-03-28 14:05:00 +01:00
2024-03-16 22:09:47 +01:00
/* mark one file */
2024-03-18 00:21:58 +01:00
case SPACE :
2024-04-01 22:53:19 +02:00
add_file_stat ( files - > items [ current_selection ] . name , files - > items [ current_selection ] . path , 1 ) ;
2024-03-14 20:56:36 +01:00
highlight_current_line ( ) ;
2024-03-11 16:57:41 +01:00
break ;
2024-03-16 22:09:47 +01:00
/* mark all files in directory */
2024-03-18 00:21:58 +01:00
case ' a ' :
2024-03-20 23:43:34 +01:00
change_dir ( cwd , current_selection , 2 ) ; /* reload current dir */
2024-03-16 22:09:47 +01:00
break ;
2024-03-17 13:28:27 +01:00
/* mark actions: */
/* delete */
2024-03-31 22:44:05 +02:00
case ' d ' :
2024-04-02 03:30:28 +02:00
delete_files ( ) ;
2024-03-17 13:28:27 +01:00
break ;
/* move */
2024-03-31 22:44:05 +02:00
case ' m ' :
2024-03-20 21:29:04 +01:00
if ( marked - > length ) {
2024-03-17 13:28:27 +01:00
;
}
break ;
/* copy */
2024-03-31 22:44:05 +02:00
case ' c ' :
2024-03-20 21:29:04 +01:00
if ( marked - > length ) {
2024-03-17 13:28:27 +01:00
;
}
break ;
/* symbolic link */
2024-03-31 22:44:05 +02:00
case ' s ' :
2024-03-20 21:29:04 +01:00
if ( marked - > length ) {
2024-03-17 13:28:27 +01:00
;
}
break ;
/* bulk rename */
2024-03-31 22:44:05 +02:00
case ' b ' :
2024-03-20 21:29:04 +01:00
if ( marked - > length ) {
2024-03-17 13:28:27 +01:00
;
}
break ;
2024-03-14 11:52:01 +01:00
/* escape */
2024-03-14 20:47:46 +01:00
case ESC :
2024-03-09 18:37:04 +01:00
break ;
2024-03-14 11:52:01 +01:00
2024-03-09 18:37:04 +01:00
case KEY_RESIZE :
2024-03-17 23:58:31 +01:00
delwin ( directory_border ) ;
delwin ( directory_content ) ;
delwin ( preview_border ) ;
delwin ( preview_content ) ;
delwin ( panel ) ;
2024-03-13 11:18:35 +01:00
endwin ( ) ;
2024-03-20 23:43:34 +01:00
start_ccc ( ) ;
2024-03-29 15:05:01 +01:00
highlight_current_line ( ) ;
2024-03-09 18:37:04 +01:00
break ;
2024-03-10 21:23:15 +01:00
default :
break ;
2024-03-09 18:37:04 +01:00
}
}
2024-04-07 00:46:14 +02:00
cleanup :
2024-04-02 02:18:34 +02:00
free ( argv_cp ) ;
2024-03-20 21:29:04 +01:00
arraylist_free ( files ) ;
arraylist_free ( marked ) ;
2024-03-10 21:23:15 +01:00
endwin ( ) ;
2024-03-09 18:37:04 +01:00
return 0 ;
}
2024-03-20 21:29:04 +01:00
void show_help ( )
{
2024-03-20 17:03:54 +01:00
wclear ( directory_content ) ;
wclear ( preview_content ) ;
2024-04-10 14:51:39 +02:00
wprintw ( directory_content , " h: go to parent dir \n j: scroll down \n k: scroll up \n l: go to child dir \n \n left: go to parent dir \n down: scroll down \n up: scroll up \n right: go to child dir \n \n enter: go to child dir/open file \n backspace: go to parent dir \n \n gg: go to top \n G: go to bottom \n \n ctrl+u: jump up \n ctrl+d: jump down \n \n t: go to trash dir \n ~: go to home dir \n -: go to previous dir \n z: refresh current dir \n :: go to a directory by typing \n u: sort files \n \n .: toggle hidden files \n i: toggle file details \n X: toggle executable \n \n A: show directory disk usage/block size \n \n f: new file \n n: new dir \n r: rename \n \n space: mark file \n a: mark all files in directory \n d: trash \n \n ?: show help \n q: exit with last dir written to file \n ctrl+c exit without writing last dir " ) ;
2024-04-30 18:09:33 +02:00
wpprintw ( " Visit https://github.com/night0721/ccc or use 'man ccc' for help " ) ;
2024-03-20 17:03:54 +01:00
wrefresh ( directory_content ) ;
wrefresh ( preview_content ) ;
}
2024-03-20 13:28:08 +01:00
void start_ccc ( )
{
half_width = COLS / 2 ;
init_windows ( ) ;
}
2024-03-31 22:44:05 +02:00
/*
* Checks if the trash directory is set and returns it
*/
2024-03-29 23:34:26 +01:00
char * check_trash_dir ( )
{
char * path = memalloc ( PATH_MAX * sizeof ( char ) ) ;
2024-04-02 03:30:28 +02:00
char * trash_dir ;
2024-03-29 23:34:26 +01:00
# ifdef TRASH_DIR
trash_dir = TRASH_DIR ;
2024-04-06 22:41:36 +02:00
strcpy ( path , trash_dir ) ;
2024-03-29 23:34:26 +01:00
# endif
/* check if there is trash_dir */
if ( trash_dir = = NULL ) {
2024-04-10 14:51:39 +02:00
wpprintw ( " Trash directory not defined " ) ;
2024-03-29 23:34:26 +01:00
return NULL ;
} else {
/* if trash_dir has ~ then make it $HOME */
/* use path as trash_dir */
if ( trash_dir [ 0 ] = = ' ~ ' ) {
2024-04-07 19:43:04 +02:00
path = replace_home ( path ) ;
2024-03-29 23:34:26 +01:00
}
/* if has access to trash_dir */
if ( access ( path , F_OK ) ! = 0 ) {
2024-03-31 22:44:05 +02:00
/* create the directory with 755 permissions if it doesn't exist */
2024-03-29 23:34:26 +01:00
mkdir_p ( path ) ;
}
}
return path ;
}
2024-03-14 13:46:38 +01:00
/*
2024-03-16 22:46:21 +01:00
* Change directory in window with selection
2024-03-14 13:46:38 +01:00
*/
2024-03-20 23:43:34 +01:00
void change_dir ( const char * buf , int selection , int ftype )
2024-03-14 13:46:38 +01:00
{
2024-04-07 00:46:14 +02:00
if ( cwd ! = buf )
strcpy ( cwd , buf ) ;
if ( ftype = = 0 )
2024-04-02 02:26:52 +02:00
arraylist_free ( files ) ;
2024-04-10 14:51:39 +02:00
chdir ( cwd ) ;
2024-03-29 15:02:52 +01:00
current_selection = selection ;
2024-03-29 15:05:01 +01:00
populate_files ( cwd , ftype ) ;
2024-03-14 13:46:38 +01:00
}
2024-03-14 15:46:06 +01:00
/*
* Recursively create directory by creating each subdirectory
2024-03-19 23:07:05 +01:00
* like mkdir - p
2024-03-14 15:46:06 +01:00
*/
2024-03-29 23:34:26 +01:00
void mkdir_p ( const char * destdir )
2024-03-14 15:46:06 +01:00
{
char * path = memalloc ( PATH_MAX * sizeof ( char ) ) ;
2024-03-16 21:37:56 +01:00
char dir_path [ PATH_MAX ] = " " ;
2024-03-14 15:46:06 +01:00
if ( destdir [ 0 ] = = ' ~ ' ) {
char * home = getenv ( " HOME " ) ;
if ( home = = NULL ) {
2024-04-10 14:51:39 +02:00
wpprintw ( " $HOME not defined " ) ;
2024-03-29 23:34:26 +01:00
return ;
2024-03-14 15:46:06 +01:00
}
/* replace ~ with home */
2024-03-19 23:07:05 +01:00
snprintf ( path , PATH_MAX , " %s%s " , home , destdir + 1 ) ;
} else {
strcpy ( path , destdir ) ;
}
2024-03-16 21:37:56 +01:00
/* fix first / not appearing in the string */
if ( path [ 0 ] = = ' / ' )
2024-03-14 15:46:06 +01:00
strcat ( dir_path , " / " ) ;
2024-03-19 23:07:05 +01:00
char * token = strtok ( path , " / " ) ;
2024-03-14 15:46:06 +01:00
while ( token ! = NULL ) {
strcat ( dir_path , token ) ;
strcat ( dir_path , " / " ) ;
if ( mkdir ( dir_path , 0755 ) = = - 1 ) {
struct stat st ;
if ( stat ( dir_path , & st ) = = 0 & & S_ISDIR ( st . st_mode ) ) {
/* Directory already exists, continue to the next dir */
token = strtok ( NULL , " / " ) ;
continue ;
}
2024-03-29 23:34:26 +01:00
wpprintw ( " mkdir failed: %s \n " , strerror ( errno ) ) ;
2024-03-14 15:46:06 +01:00
free ( path ) ;
2024-03-29 23:34:26 +01:00
return ;
2024-03-14 15:46:06 +01:00
}
token = strtok ( NULL , " / " ) ;
}
free ( path ) ;
2024-03-29 23:34:26 +01:00
return ;
2024-03-14 15:46:06 +01:00
}
2024-03-09 20:14:26 +01:00
/*
2024-04-06 20:58:31 +02:00
* Read the provided directory and add all files in directory to an Arraylist
2024-03-18 00:21:58 +01:00
* ftype : normal files = 0 , marked = 1 , marking ALL = 2
2024-03-09 20:14:26 +01:00
*/
2024-03-16 22:09:47 +01:00
void populate_files ( const char * path , int ftype )
2024-03-09 18:37:04 +01:00
{
DIR * dp ;
struct dirent * ep ;
2024-03-09 19:24:38 +01:00
2024-03-13 11:18:35 +01:00
if ( ( dp = opendir ( path ) ) ! = NULL ) {
2024-03-12 21:59:36 +01:00
/* clear directory window to ready for printing */
wclear ( directory_content ) ;
2024-04-06 19:40:42 +02:00
if ( ftype = = 0 ) {
tmp1 = arraylist_init ( 10 ) ;
tmp2 = arraylist_init ( 10 ) ;
}
2024-03-10 21:23:15 +01:00
2024-03-10 11:54:08 +01:00
while ( ( ep = readdir ( dp ) ) ! = NULL ) {
2024-04-07 00:46:14 +02:00
char * filename = estrdup ( ep - > d_name ) ;
2024-03-12 21:59:36 +01:00
2024-03-20 19:21:02 +01:00
/* use strncmp to filter out dotfiles */
2024-03-20 23:18:07 +01:00
if ( ( ! show_hidden & & strncmp ( filename , " . " , 1 ) & & strncmp ( filename , " .. " , 2 ) ) | | ( show_hidden & & strcmp ( filename , " . " ) & & strcmp ( filename , " .. " ) ) ) {
2024-03-12 21:59:36 +01:00
/* construct full file path */
2024-04-07 00:46:14 +02:00
char * path = memalloc ( ( strlen ( cwd ) + strlen ( filename ) + 2 ) * sizeof ( char ) ) ;
2024-04-01 22:53:19 +02:00
strcpy ( path , cwd ) ;
2024-03-31 22:44:05 +02:00
strcat ( path , " / " ) ;
strcat ( path , filename ) ; /* add filename */
2024-03-12 21:59:36 +01:00
2024-04-01 22:53:19 +02:00
add_file_stat ( filename , path , ftype ) ;
2024-03-09 18:37:04 +01:00
}
2024-04-07 00:46:14 +02:00
else free ( filename ) ;
2024-03-09 18:37:04 +01:00
}
2024-04-06 19:40:42 +02:00
if ( ftype = = 0 ) {
files = arraylist_init ( tmp1 - > length + tmp2 - > length ) ;
files - > length = tmp1 - > length + tmp2 - > length ;
memcpy ( files - > items , tmp1 - > items , tmp1 - > length * sizeof ( file ) ) ;
memcpy ( files - > items + tmp1 - > length , tmp2 - > items , tmp2 - > length * sizeof ( file ) ) ;
free ( tmp1 - > items ) ;
free ( tmp2 - > items ) ;
2024-04-07 00:46:14 +02:00
free ( tmp1 ) ;
free ( tmp2 ) ;
2024-04-06 19:40:42 +02:00
}
2024-03-09 18:37:04 +01:00
closedir ( dp ) ;
2024-03-12 21:59:36 +01:00
wrefresh ( directory_content ) ;
2024-03-29 15:05:01 +01:00
highlight_current_line ( ) ;
2024-03-10 11:54:08 +01:00
} else {
2024-03-29 15:05:01 +01:00
wpprintw ( " stat failed: %s \n " , strerror ( errno ) ) ;
2024-03-09 18:37:04 +01:00
}
}
2024-03-14 00:51:05 +01:00
int get_directory_size ( const char * fpath , const struct stat * sb , int typeflag , struct FTW * ftwbuf )
2024-03-13 11:18:35 +01:00
{
2024-03-14 00:51:05 +01:00
total_dir_size + = sb - > st_size ;
return 0 ;
2024-03-13 11:18:35 +01:00
}
2024-03-11 22:54:14 +01:00
/*
2024-03-13 11:18:35 +01:00
* Get file ' s last modified time , size , type
* Add that file into list
2024-03-29 23:34:26 +01:00
* ftype : normal file = 0 , normal marked = 1 , marked ALL = 2
2024-03-11 22:54:14 +01:00
*/
2024-03-31 22:44:05 +02:00
void add_file_stat ( char * filename , char * path , int ftype )
2024-03-12 21:59:36 +01:00
{
2024-03-11 22:54:14 +01:00
struct stat file_stat ;
2024-04-01 22:53:19 +02:00
if ( stat ( path , & file_stat ) = = - 1 ) {
2024-03-16 21:59:49 +01:00
/* can't be triggered? */
if ( errno = = EACCES )
2024-03-31 22:44:05 +02:00
arraylist_add ( files , filename , path , NULL , NULL , NULL , 8 , false , false ) ;
2024-03-16 21:59:49 +01:00
}
2024-03-29 23:34:26 +01:00
/* get file type and color, 4 chars for the type and icon */
2024-03-31 00:13:14 +01:00
size_t type_size = 4 * sizeof ( char ) ;
size_t icon_size = 2 * sizeof ( wchar_t ) ;
char * type = memalloc ( type_size ) ;
wchar_t * icon_str = memalloc ( icon_size ) ;
2024-03-30 04:39:02 +01:00
2024-03-31 22:44:05 +02:00
filename [ strlen ( filename ) ] = ' \0 ' ;
2024-04-01 22:53:19 +02:00
/* handle file without extension
* ext is the extension if . exist in filename
* otherwise is nothing and handled through tenery operator */
char * ext = strrchr ( filename , ' . ' ) ;
2024-03-30 04:39:02 +01:00
if ( ext ! = NULL ) {
2024-04-01 22:53:19 +02:00
ext + = 1 ;
2024-03-30 04:39:02 +01:00
}
2024-03-31 22:44:05 +02:00
/* add file extension */
2024-04-01 22:53:19 +02:00
icon * ext_icon = hashtable_search ( ext ! = NULL ? ext : filename ) ;
if ( ext_icon = = NULL )
2024-03-31 00:13:14 +01:00
wcsncpy ( icon_str , L " " , 2 ) ;
2024-04-01 22:53:19 +02:00
else
wcsncpy ( icon_str , ext_icon - > icon , 2 ) ;
2024-03-30 04:39:02 +01:00
2024-03-16 21:59:49 +01:00
int color ;
2024-03-29 23:34:26 +01:00
2024-03-16 21:59:49 +01:00
if ( S_ISDIR ( file_stat . st_mode ) ) {
2024-03-29 23:34:26 +01:00
strncpy ( type , " DIR " , 4 ) ; /* directory type */
2024-03-16 21:59:49 +01:00
color = 5 ; /* blue color */
2024-03-31 22:44:05 +02:00
wcsncpy ( icon_str , L " " , 2 ) ;
2024-03-16 21:59:49 +01:00
} else if ( S_ISREG ( file_stat . st_mode ) ) {
2024-03-29 23:34:26 +01:00
strncpy ( type , " REG " , 4 ) ; /* regular file */
2024-03-16 21:59:49 +01:00
color = 8 ; /* white color */
} else if ( S_ISLNK ( file_stat . st_mode ) ) {
2024-03-29 23:34:26 +01:00
strncpy ( type , " LNK " , 4 ) ; /* symbolic link */
2024-03-16 21:59:49 +01:00
color = 3 ; /* green color */
} else if ( S_ISCHR ( file_stat . st_mode ) ) {
2024-03-29 23:34:26 +01:00
strncpy ( type , " CHR " , 4 ) ; /* character device */
2024-03-16 21:59:49 +01:00
color = 8 ; /* white color */
} else if ( S_ISSOCK ( file_stat . st_mode ) ) {
2024-03-29 23:34:26 +01:00
strncpy ( type , " SOC " , 4 ) ; /* socket */
2024-03-16 21:59:49 +01:00
color = 8 ; /* white color */
} else if ( S_ISBLK ( file_stat . st_mode ) ) {
2024-03-29 23:34:26 +01:00
strncpy ( type , " BLK " , 4 ) ; /* block device */
2024-03-16 21:59:49 +01:00
color = 4 ; /* yellow color */
} else if ( S_ISFIFO ( file_stat . st_mode ) ) {
2024-03-29 23:34:26 +01:00
strncpy ( type , " FIF " , 4 ) ; /* FIFO */
2024-03-16 21:59:49 +01:00
color = 8 ; /* white color */
} else {
color = 8 ; /* white color */
}
/* if file is to be marked */
2024-03-18 00:21:58 +01:00
if ( ftype = = 1 | | ftype = = 2 ) {
/* force if user is marking all files */
bool force = ftype = = 2 ? true : false ;
2024-03-31 22:44:05 +02:00
arraylist_add ( marked , filename , path , NULL , type , icon_str , 8 , true , force ) ;
2024-03-17 11:09:22 +01:00
/* free type and return without allocating more stuff */
2024-03-20 21:29:04 +01:00
return ;
2024-03-13 20:37:26 +01:00
}
2024-03-11 22:54:14 +01:00
2024-03-13 11:18:35 +01:00
/* get last modified time */
2024-03-31 00:13:14 +01:00
size_t time_size = 17 * sizeof ( char ) ;
char * time = memalloc ( time_size ) ;
2024-03-12 21:59:36 +01:00
/* format last modified time to a string */
2024-03-31 00:13:14 +01:00
strftime ( time , time_size , " %Y-%m-%d %H:%M " , localtime ( & file_stat . st_mtime ) ) ;
2024-03-11 22:54:14 +01:00
2024-03-13 11:18:35 +01:00
/* get file size */
2024-03-11 22:54:14 +01:00
double bytes = file_stat . st_size ;
2024-03-16 20:26:35 +01:00
2024-03-16 21:37:56 +01:00
if ( dirs_size ) {
/* dirs_size is true, so calculate disk usage */
2024-03-16 20:26:35 +01:00
if ( S_ISDIR ( file_stat . st_mode ) ) {
/* at most 15 fd opened */
total_dir_size = 0 ;
2024-04-01 22:53:19 +02:00
nftw ( path , & get_directory_size , 15 , FTW_PHYS ) ;
2024-03-16 20:26:35 +01:00
bytes = total_dir_size ;
}
2024-03-13 11:18:35 +01:00
}
2024-03-31 22:44:05 +02:00
/* 4 before decimal + 1 dot + DECIMAL_PLACES (after decimal) +
unit length ( 1 for K , 3 for KiB , taking units [ 1 ] as B never changes ) + 1 space + 1 null */
2024-03-31 00:13:14 +01:00
int size_size = 4 + 1 + DECIMAL_PLACES + strlen ( units [ 1 ] ) + 1 + 1 ;
2024-03-30 22:00:57 +01:00
char * size = memalloc ( size_size * sizeof ( char ) ) ;
2024-03-11 22:54:14 +01:00
int unit = 0 ;
while ( bytes > 1024 ) {
bytes / = 1024 ;
unit + + ;
}
2024-03-30 22:00:57 +01:00
/* display sizes and check if there are decimal places */
2024-03-30 14:00:16 +01:00
if ( bytes = = ( unsigned int ) bytes ) {
sprintf ( size , " %d%s " , ( unsigned int ) bytes , units [ unit ] ) ;
} else {
2024-03-30 22:00:57 +01:00
sprintf ( size , " %.*f%s " , DECIMAL_PLACES , bytes , units [ unit ] ) ;
2024-03-30 14:00:16 +01:00
}
2024-03-29 15:05:01 +01:00
/* get file mode string */
char * mode_str = get_file_mode ( file_stat . st_mode ) ;
2024-04-01 23:23:10 +02:00
if ( mode_str [ 0 ] = = ' - ' & & ( mode_str [ 3 ] = = ' x ' | | mode_str [ 6 ] = = ' x ' | | mode_str [ 9 ] = = ' x ' ) ) {
}
2024-03-29 15:05:01 +01:00
2024-03-31 00:13:14 +01:00
/* mode_str(11) + time(17) + size_size + 2 spaces + 1 null */
size_t stat_size = 11 * sizeof ( char ) + time_size + size_size + 3 * sizeof ( char ) ;
char * total_stat = memalloc ( stat_size ) ;
snprintf ( total_stat , stat_size , " %s %s %-*s " , mode_str , time , size_size , size ) ;
2024-03-11 22:54:14 +01:00
2024-04-06 23:09:14 +02:00
/* DIR if color is 5 */
2024-04-06 19:40:42 +02:00
if ( color = = 5 )
arraylist_add ( tmp1 , filename , path , total_stat , type , icon_str , color , false , false ) ;
else
arraylist_add ( tmp2 , filename , path , total_stat , type , icon_str , color , false , false ) ;
2024-03-13 11:18:35 +01:00
2024-03-17 11:09:22 +01:00
free ( time ) ;
free ( size ) ;
2024-03-29 15:05:01 +01:00
free ( mode_str ) ;
2024-03-11 22:54:14 +01:00
}
2024-03-29 15:05:01 +01:00
/*
* get file mode string from stat mode
* eg : drwxr - sr - x
*/
char * get_file_mode ( mode_t mode )
{
2024-03-31 00:13:14 +01:00
char * mode_str = memalloc ( 11 * sizeof ( char ) ) ;
2024-03-29 23:34:26 +01:00
mode_str [ 0 ] = S_ISDIR ( mode ) ? ' d ' : ' - ' ; /* Check if it's a directory */
2024-03-29 15:05:01 +01:00
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 ' : ' - ' ;
2024-03-29 23:34:26 +01:00
mode_str [ 10 ] = ' \0 ' ;
2024-03-29 15:05:01 +01:00
return mode_str ;
}
2024-03-14 16:29:03 +01:00
2024-03-09 20:14:26 +01:00
/*
2024-03-10 21:23:15 +01:00
* Highlight current line by reversing the color
2024-03-09 20:14:26 +01:00
*/
2024-03-09 18:37:04 +01:00
void highlight_current_line ( )
{
2024-03-29 15:05:01 +01:00
# if DRAW_BORDERS
draw_border_title ( directory_border , true ) ;
# endif
2024-03-13 16:51:52 +01:00
long overflow = 0 ;
if ( current_selection > LINES - 4 ) {
/* overflown */
overflow = current_selection - ( LINES - 4 ) ;
}
/* calculate range of files to show */
2024-03-20 21:29:04 +01:00
long range = files - > length ;
2024-03-14 15:46:06 +01:00
/* not highlight if no files in directory */
2024-03-29 15:05:01 +01:00
if ( range = = 0 & & errno = = 0 ) {
2024-03-17 23:58:31 +01:00
# if DRAW_PREVIEW
wprintw ( preview_content , " empty directory " ) ;
wrefresh ( preview_content ) ;
# endif
2024-03-14 15:46:06 +01:00
return ;
}
2024-03-13 16:51:52 +01:00
if ( range > LINES - 3 ) {
2024-03-16 21:37:56 +01:00
/* if there are more files than lines available to display
* shrink range to avaiable lines to display with
* overflow to keep the number of iterations to be constant */
2024-03-13 16:51:52 +01:00
range = LINES - 3 + overflow ;
}
wclear ( directory_content ) ;
long line_count = 0 ;
for ( long i = overflow ; i < range ; i + + ) {
if ( ( overflow = = 0 & & i = = current_selection ) | | ( overflow ! = 0 & & i = = current_selection ) ) {
2024-03-12 21:59:36 +01:00
wattron ( directory_content , A_REVERSE ) ;
2024-03-10 21:23:15 +01:00
2024-03-16 20:26:35 +01:00
/* check for marked files */
2024-03-20 21:29:04 +01:00
long num_marked = marked - > length ;
2024-03-14 20:47:46 +01:00
if ( num_marked > 0 ) {
2024-03-14 20:56:36 +01:00
/* Determine length of formatted string */
2024-03-16 22:09:47 +01:00
int m_len = snprintf ( NULL , 0 , " [%ld] selected " , num_marked ) ;
2024-03-14 20:56:36 +01:00
char * selected = memalloc ( ( m_len + 1 ) * sizeof ( char ) ) ;
2024-03-16 22:09:47 +01:00
snprintf ( selected , m_len + 1 , " [%ld] selected " , num_marked ) ;
2024-03-29 15:05:01 +01:00
wpprintw ( " (%ld/%ld) %s %s " , current_selection + 1 , files - > length , selected , cwd ) ;
2024-03-14 20:56:36 +01:00
} else {
2024-03-29 15:05:01 +01:00
wpprintw ( " (%ld/%ld) %s " , current_selection + 1 , files - > length , cwd ) ;
2024-03-14 20:47:46 +01:00
}
2024-03-09 18:37:04 +01:00
}
2024-03-11 22:54:14 +01:00
/* print the actual filename and stats */
2024-04-02 02:18:34 +02:00
char * line = get_line ( files , i , file_details , show_icons ) ;
2024-03-20 21:29:04 +01:00
int color = files - > items [ i ] . color ;
2024-03-15 19:28:37 +01:00
/* check is file marked for action */
2024-03-31 01:20:29 +01:00
bool is_marked = arraylist_search ( marked , files - > items [ i ] . path , false ) ! = - 1 ;
2024-03-20 21:29:04 +01:00
if ( is_marked ) {
2024-03-15 19:28:37 +01:00
/* show file is selected */
wattron ( directory_content , COLOR_PAIR ( 7 ) ) ;
} else {
/* print the whole directory with default colors */
wattron ( directory_content , COLOR_PAIR ( color ) ) ;
}
2024-03-13 16:51:52 +01:00
if ( overflow > 0 )
mvwprintw ( directory_content , line_count , 0 , " %s " , line ) ;
else
mvwprintw ( directory_content , i , 0 , " %s " , line ) ;
2024-03-14 15:58:03 +01:00
2024-03-20 21:29:04 +01:00
if ( is_marked ) {
2024-03-15 19:28:37 +01:00
wattroff ( directory_content , COLOR_PAIR ( 7 ) ) ;
} else {
wattroff ( directory_content , COLOR_PAIR ( color ) ) ;
}
2024-03-12 21:59:36 +01:00
wattroff ( directory_content , A_REVERSE ) ;
2024-03-11 22:54:14 +01:00
free ( line ) ;
2024-03-13 16:51:52 +01:00
line_count + + ;
2024-03-09 18:37:04 +01:00
}
2024-03-09 19:24:38 +01:00
2024-03-12 21:59:36 +01:00
wrefresh ( directory_content ) ;
wrefresh ( panel ) ;
2024-03-10 21:23:15 +01:00
/* show file content every time cursor changes */
2024-03-17 13:28:27 +01:00
# if DRAW_PREVIEW
show_file_content ( ) ;
# endif
2024-03-29 15:05:01 +01:00
# if DRAW_BORDERS
draw_border_title ( preview_border , true ) ;
# endif
2024-03-29 23:34:26 +01:00
wrefresh ( preview_content ) ;
2024-03-09 18:37:04 +01:00
}
2024-03-09 20:14:26 +01:00
/*
2024-03-10 21:23:15 +01:00
* Get file content into buffer and show it to preview window
2024-03-09 20:14:26 +01:00
*/
2024-03-09 18:37:04 +01:00
void show_file_content ( )
{
2024-03-20 21:29:04 +01:00
file current_file = files - > items [ current_selection ] ;
2024-03-16 21:37:56 +01:00
2024-10-11 20:42:00 +02:00
wclear ( preview_content ) ;
2024-03-20 21:29:04 +01:00
if ( strncmp ( current_file . type , " DIR " , 3 ) = = 0 )
2024-10-11 20:42:00 +02:00
/* Print dir content */
2024-03-16 21:37:56 +01:00
return ;
2024-03-31 22:44:05 +02:00
2024-03-20 21:29:04 +01:00
FILE * file = fopen ( current_file . path , " r " ) ;
2024-03-15 15:02:52 +01:00
if ( file = = NULL ) {
2024-04-01 22:53:19 +02:00
mvwprintw ( preview_content , 0 , 0 , " Unable to read %s " , current_file . name ) ;
2024-03-15 15:02:52 +01:00
return ;
}
2024-03-29 15:05:01 +01:00
2024-03-15 15:02:52 +01:00
int c ;
2024-03-16 21:37:56 +01:00
/* check if its binary */
while ( ( c = fgetc ( file ) ) ! = EOF ) {
2024-03-15 15:02:52 +01:00
if ( c = = ' \0 ' ) {
mvwprintw ( preview_content , 0 , 0 , " binary " ) ;
return ;
2024-03-10 21:23:15 +01:00
}
2024-03-09 18:37:04 +01:00
}
2024-03-15 15:02:52 +01:00
fseek ( file , 0 , SEEK_END ) ;
long length = ftell ( file ) ;
/* check if file isn't empty */
if ( length ! = 0 ) {
fseek ( file , 0 , SEEK_SET ) ; /* set cursor back to start of file */
int max_length = ( LINES - 3 ) * ( COLS / 2 - 2 ) ;
char * buffer = memalloc ( max_length * sizeof ( char ) ) ;
fread ( buffer , 1 , max_length , file ) ;
mvwprintw ( preview_content , 0 , 0 , " %s " , buffer ) ;
free ( buffer ) ;
} else {
wclear ( preview_content ) ;
}
fclose ( file ) ;
2024-03-09 18:37:04 +01:00
}
2024-03-11 16:57:41 +01:00
/*
* Opens $ EDITOR to edit the file
*/
2024-03-12 21:59:36 +01:00
void edit_file ( )
{
2024-03-16 21:37:56 +01:00
# ifdef EDITOR
char * editor = EDITOR ;
# else
char * editor = getenv ( " EDITOR " ) ;
# endif
2024-03-11 16:57:41 +01:00
if ( editor = = NULL ) {
2024-04-10 14:51:39 +02:00
wpprintw ( " $EDITOR not defined " ) ;
2024-03-11 16:57:41 +01:00
return ;
} else {
2024-03-16 21:37:56 +01:00
def_prog_mode ( ) ; /* save the tty modes */
endwin ( ) ; /* end curses mode temporarily */
2024-03-20 21:29:04 +01:00
char * filename = files - > items [ current_selection ] . path ;
2024-03-16 21:37:56 +01:00
int length = strlen ( editor ) + strlen ( filename ) + 2 ; /* one for space one for null */
2024-03-11 16:57:41 +01:00
char command [ length ] ;
2024-03-16 21:37:56 +01:00
2024-03-11 16:57:41 +01:00
snprintf ( command , length , " %s %s " , editor , filename ) ;
system ( command ) ;
2024-03-16 21:37:56 +01:00
reset_prog_mode ( ) ; /* return to previous tty mode */
refresh ( ) ; /* store the screen contents */
2024-03-11 16:57:41 +01:00
}
}
2024-03-29 15:05:01 +01:00
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 ) ) ;
}
}
2024-04-07 01:11:01 +02:00
char * replace_home ( char * str )
2024-04-06 22:41:36 +02:00
{
char * home = getenv ( " HOME " ) ;
if ( home = = NULL ) {
2024-04-10 14:51:39 +02:00
wpprintw ( " $HOME not defined " ) ;
2024-04-07 01:11:01 +02:00
return str ;
2024-04-06 22:41:36 +02:00
}
2024-04-07 01:11:01 +02:00
char * newstr = memalloc ( ( strlen ( str ) + strlen ( home ) ) * sizeof ( char ) ) ;
2024-04-06 22:41:36 +02:00
/* replace ~ with home */
2024-04-07 01:11:01 +02:00
snprintf ( newstr , strlen ( str ) + strlen ( home ) , " %s%s " , home , str + 1 ) ;
free ( str ) ;
return newstr ;
2024-04-06 22:41:36 +02:00
}
2024-03-20 21:29:04 +01:00
int write_last_d ( )
{
2024-03-19 23:07:05 +01:00
# ifdef LAST_D
2024-04-07 01:11:01 +02:00
char * last_d = estrdup ( LAST_D ) ;
2024-03-19 23:07:05 +01:00
# else
char * last_d = getenv ( " CCC_LAST_D " ) ;
# endif
if ( last_d = = NULL ) {
2024-04-10 14:51:39 +02:00
wpprintw ( " $CCC_LAST_D not defined (Press enter to continue) " ) ;
2024-03-19 23:07:05 +01:00
return - 1 ;
} else {
2024-04-06 22:41:36 +02:00
if ( last_d [ 0 ] = = ' ~ ' ) {
2024-04-07 01:11:01 +02:00
last_d = replace_home ( last_d ) ;
2024-03-19 23:07:05 +01:00
}
2024-04-06 22:41:36 +02:00
char * last_ddup = estrdup ( last_d ) ;
char * last_d_dir = strrchr ( last_ddup , ' / ' ) ;
2024-03-19 23:07:05 +01:00
if ( last_d_dir ! = NULL ) {
* last_d_dir = ' \0 ' ; /* truncate string */
}
2024-04-06 22:41:36 +02:00
mkdir_p ( last_ddup ) ;
FILE * last_d_file = fopen ( last_d , " w " ) ;
2024-03-19 23:07:05 +01:00
if ( last_d_file = = NULL ) {
2024-04-10 14:51:39 +02:00
wpprintw ( " Cannot open last directory file (Press enter to continue) " ) ;
2024-03-19 23:07:05 +01:00
return - 1 ;
}
fwrite ( cwd , strlen ( cwd ) , sizeof ( char ) , last_d_file ) ;
fclose ( last_d_file ) ;
2024-04-06 22:41:36 +02:00
free ( last_ddup ) ;
free ( last_d ) ;
2024-03-19 23:07:05 +01:00
}
return 0 ;
}
2024-04-07 23:25:58 +02:00
int sort_compare ( const void * a , const void * b ) {
return strcmp ( ( ( file * ) a ) - > name , ( ( file * ) b ) - > name ) ;
}
void sort_files ( )
{
qsort ( files - > items , files - > length , sizeof ( file ) , sort_compare ) ;
highlight_current_line ( ) ;
}
2024-04-10 14:51:39 +02:00
char * get_panel_string ( char * prompt )
2024-04-02 03:30:28 +02:00
{
echo ( ) ;
2024-04-10 14:51:39 +02:00
wpprintw ( prompt ) ;
char * input = memalloc ( PATH_MAX * sizeof ( char ) ) ;
/* get string at y=0, x=length of prompt */
mvwgetstr ( panel , 0 , strlen ( prompt ) , input ) ;
noecho ( ) ;
if ( input [ 0 ] = = ' ~ ' ) {
input = replace_home ( input ) ;
}
return input ;
}
void rename_file ( )
{
char * filename = files - > items [ current_selection ] . path ;
char * input = get_panel_string ( " Rename file: " ) ;
char * newfilename = estrdup ( filename ) ;
/* remove basename of newfilename */
char * last_slash = strrchr ( newfilename , ' / ' ) ;
* last_slash = ' \0 ' ;
/* add the slash back to newfilename */
strcat ( newfilename , " / " ) ;
strcat ( newfilename , input ) ;
if ( rename ( filename , newfilename ) ) {
wpprintw ( " rename failed: %s (Press enter to continue) " , strerror ( errno ) ) ;
getch ( ) ;
} else {
change_dir ( cwd , 0 , 0 ) ;
wpprintw ( " Renamed %s to %s " , filename , newfilename ) ;
}
free ( input ) ;
free ( newfilename ) ;
}
void goto_dir ( )
{
char * input = get_panel_string ( " Goto dir: " ) ;
struct stat st ;
if ( lstat ( input , & st ) ) {
wpprintw ( " lstat failed: %s (Press enter to continue) " , strerror ( errno ) ) ;
getch ( ) ;
}
/* chdir to directory from argument */
if ( S_ISDIR ( st . st_mode ) & & chdir ( input ) ) {
wpprintw ( " chdir failed: %s (Press enter to continue) " , strerror ( errno ) ) ;
getch ( ) ;
}
getcwd ( cwd , PATH_MAX ) ;
change_dir ( cwd , 0 , 0 ) ;
free ( input ) ;
}
void create_dir ( )
{
char * input = get_panel_string ( " New dir: " ) ;
char * newfilename = memalloc ( PATH_MAX * sizeof ( char ) ) ;
strcpy ( newfilename , cwd ) ;
strcat ( newfilename , " / " ) ;
strcat ( newfilename , input ) ;
if ( access ( newfilename , F_OK ) ! = 0 ) {
mkdir_p ( newfilename ) ;
change_dir ( cwd , 0 , 0 ) ;
wpprintw ( " Created %s " , input ) ;
} else {
wpprintw ( " Directory already exist " ) ;
}
free ( input ) ;
free ( newfilename ) ;
}
void create_file ( )
{
char * input = get_panel_string ( " New file: " ) ;
2024-04-02 03:30:28 +02:00
FILE * f = fopen ( input , " w+ " ) ;
fclose ( f ) ;
change_dir ( cwd , 0 , 0 ) ;
2024-04-10 14:51:39 +02:00
wpprintw ( " Created %s " , input ) ;
free ( input ) ;
2024-04-02 03:30:28 +02:00
}
void delete_files ( )
{
if ( marked - > length ) {
char * trash_dir = check_trash_dir ( ) ;
if ( trash_dir ! = NULL ) {
for ( int i = 0 ; i < marked - > length ; i + + ) {
char * new_path = memalloc ( PATH_MAX * sizeof ( char ) ) ;
strcpy ( new_path , trash_dir ) ;
strcat ( new_path , " / " ) ;
strcat ( new_path , marked - > items [ i ] . name ) ;
if ( rename ( marked - > items [ i ] . path , new_path ) ) {
wpprintw ( " delete failed: %s \n " , strerror ( errno ) ) ;
} else {
change_dir ( cwd , 0 , 0 ) ;
}
}
2024-10-11 21:03:31 +02:00
for ( int i = 0 ; i < marked - > length ; i + + ) {
arraylist_remove ( marked , 0 ) ;
}
2024-04-02 03:30:28 +02:00
} else {
wpprintw ( " TODO: implement hard delete " ) ;
}
}
}
2024-03-14 15:46:06 +01:00
/*
2024-03-17 11:09:22 +01:00
* Print line to the panel
2024-03-14 15:46:06 +01:00
*/
2024-03-29 15:05:01 +01:00
void wpprintw ( const char * fmt , . . . )
2024-03-14 15:46:06 +01:00
{
2024-03-29 15:05:01 +01:00
va_list args ;
va_start ( args , fmt ) ;
2024-03-14 15:46:06 +01:00
wclear ( panel ) ;
2024-03-29 15:05:01 +01:00
vw_printw ( panel , fmt , args ) ;
va_end ( args ) ;
2024-03-14 15:46:06 +01:00
wrefresh ( panel ) ;
}
2024-03-09 18:37:04 +01:00
void init_windows ( )
{
2024-03-17 13:28:27 +01:00
/* offset for width of the content 1 and 2 */
int width_left = half_width ;
int width_right = half_width ;
# ifdef WINDOW_OFFSET
width_left + = WINDOW_OFFSET ;
width_right - = WINDOW_OFFSET ;
# endif
2024-03-11 16:57:41 +01:00
/*------------------------------+
2024-03-12 21:59:36 +01:00
| - - - - border ( 0 ) - - | | - - border ( 2 ) - - | |
| | | | | |
| | content ( 1 ) | | content ( 3 ) | |
2024-03-17 13:28:27 +01:00
| | ( directory ) | | ( preview ) | |
2024-03-12 21:59:36 +01:00
| | | | | |
| - - - - - - - - - - - - - - - | | - - - - - - - - - - - - - | |
+ = = = = = = = = = = panel ( 4 ) = = = = = = = = = = = */
2024-03-09 18:37:04 +01:00
2024-03-17 23:58:31 +01:00
/* lines, cols, y, x */
panel = newwin ( PH , COLS , LINES - PH , 0 ) ;
2024-03-17 13:28:27 +01:00
/* draw border around windows */
# if DRAW_BORDERS
2024-03-17 23:58:31 +01:00
directory_border = newwin ( LINES - PH , width_left , 0 , 0 ) ;
directory_content = newwin ( LINES - PH - 2 , width_left - 2 , 1 , 1 ) ;
2024-03-17 13:28:27 +01:00
preview_border = newwin ( LINES - PH , width_right , 0 , width_left ) ;
preview_content = newwin ( LINES - PH - 2 , width_right - 2 , 1 , width_left + 1 ) ;
2024-03-09 18:37:04 +01:00
2024-03-17 23:58:31 +01:00
draw_border_title ( directory_border , true ) ;
draw_border_title ( preview_border , true ) ;
2024-03-17 13:28:27 +01:00
# else
/* if there are no borders, then draw content in their places */
2024-03-17 23:58:31 +01:00
directory_border = newwin ( 0 , 0 , COLS , LINES ) ;
preview_border = newwin ( 0 , 0 , COLS , LINES ) ;
2024-03-17 13:28:27 +01:00
/* -1 for the one space to the left */
2024-03-17 23:58:31 +01:00
directory_content = newwin ( LINES - PH - 1 , width_left , 0 , 1 ) ;
preview_content = newwin ( LINES - PH , width_right , 0 , width_left ) ;
2024-03-17 13:28:27 +01:00
# endif
2024-03-09 18:37:04 +01:00
2024-03-13 16:51:52 +01:00
scrollok ( directory_content , true ) ;
2024-03-20 23:43:34 +01:00
refresh ( ) ;
2024-03-09 18:37:04 +01:00
}
/*
2024-03-17 13:28:27 +01:00
* Draw the border of the window depending if it ' s active or not ,
2024-03-09 18:37:04 +01:00
*/
2024-03-17 23:58:31 +01:00
void draw_border_title ( WINDOW * window , bool active )
2024-03-09 18:37:04 +01:00
{
2024-03-17 13:28:27 +01:00
/* check if the window is directory of preview */
int width = half_width ;
2024-03-17 23:58:31 +01:00
if ( window = = directory_border ) { /* left */
2024-03-17 23:17:46 +01:00
width + = WINDOW_OFFSET ;
2024-03-17 23:58:31 +01:00
} else if ( window = = preview_border ) { /* right */
2024-03-17 13:28:27 +01:00
width - = WINDOW_OFFSET ;
}
2024-03-10 11:54:08 +01:00
/* turn on color depends on active */
2024-03-09 18:37:04 +01:00
if ( active ) {
2024-03-14 15:58:03 +01:00
wattron ( window , COLOR_PAIR ( 7 ) ) ;
2024-03-09 18:37:04 +01:00
} else {
2024-03-14 15:58:03 +01:00
wattron ( window , COLOR_PAIR ( 5 ) ) ;
2024-03-09 18:37:04 +01:00
}
2024-03-10 11:54:08 +01:00
/* draw top border */
mvwaddch ( window , 0 , 0 , ACS_ULCORNER ) ; /* upper left corner */
2024-03-17 13:28:27 +01:00
mvwhline ( window , 0 , 1 , ACS_HLINE , width - 2 ) ; /* top horizontal line */
mvwaddch ( window , 0 , width - 1 , ACS_URCORNER ) ; /* upper right corner */
2024-03-09 18:37:04 +01:00
2024-03-10 11:54:08 +01:00
/* draw side border */
mvwvline ( window , 1 , 0 , ACS_VLINE , LINES - 2 ) ; /* left vertical line */
2024-03-17 13:28:27 +01:00
mvwvline ( window , 1 , width - 1 , ACS_VLINE , LINES - 2 ) ; /* right vertical line */
2024-03-09 18:37:04 +01:00
2024-03-10 21:23:15 +01:00
/* draw bottom border
* make space for the panel */
mvwaddch ( window , LINES - PH - 1 , 0 , ACS_LLCORNER ) ; /* lower left corner */
2024-03-17 13:28:27 +01:00
mvwhline ( window , LINES - PH - 1 , 1 , ACS_HLINE , width - 2 ) ; /* bottom horizontal line */
mvwaddch ( window , LINES - PH - 1 , width - 1 , ACS_LRCORNER ) ; /* lower right corner */
2024-03-09 20:14:26 +01:00
2024-03-10 11:54:08 +01:00
/* turn color off after turning it on */
2024-03-09 18:37:04 +01:00
if ( active ) {
2024-03-14 15:58:03 +01:00
wattroff ( window , COLOR_PAIR ( 7 ) ) ;
2024-03-09 18:37:04 +01:00
} else {
2024-03-14 15:58:03 +01:00
wattroff ( window , COLOR_PAIR ( 5 ) ) ;
2024-03-09 18:37:04 +01:00
}
2024-03-10 11:54:08 +01:00
wrefresh ( window ) ; /* Refresh the window to see the colored border and title */
2024-03-09 18:37:04 +01:00
}