mirror of
https://github.com/hnhx/fx.git
synced 2025-01-09 02:57:31 -03:00
547 lines
12 KiB
C
547 lines
12 KiB
C
#ifdef __linux__
|
|
#define _GNU_SOURCE
|
|
#endif
|
|
|
|
#include <time.h>
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <dirent.h>
|
|
#include <string.h>
|
|
#include <libgen.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <termios.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/wait.h>
|
|
#include <sys/ioctl.h>
|
|
|
|
#include "utils.h"
|
|
#include "config.h"
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
static struct termios oldt, newt;
|
|
tcgetattr(STDIN_FILENO, &oldt);
|
|
newt = oldt;
|
|
newt.c_lflag &= ~(ICANON | ECHO);
|
|
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
|
|
|
|
struct winsize w;
|
|
struct stat st;
|
|
|
|
struct dirent *entry;
|
|
|
|
char c = -1;
|
|
|
|
char buf[10];
|
|
|
|
char entry_name[256];
|
|
char search_term[256];
|
|
char last_entry_name[256] = { 0 };
|
|
|
|
char path[4096];
|
|
char new_path[4096];
|
|
char temp_path[4096];
|
|
char symlink_path[4096];
|
|
char current_entry[4096];
|
|
char entry_to_work_with[4096] = { 0 };
|
|
|
|
char tags[9][4096] = { 0 };
|
|
|
|
char selected_entries[1024][1024] = { 0 };
|
|
|
|
int chr;
|
|
int rows;
|
|
int entry_count;
|
|
|
|
int hidden = 0;
|
|
int position = 0;
|
|
int current_tag = 0;
|
|
|
|
double size;
|
|
double file_size_sum;
|
|
|
|
DIR *dir;
|
|
|
|
FILE *fp, *fptr1, *fptr2;
|
|
|
|
if (argc == 1)
|
|
{
|
|
getcwd(path, 4096);
|
|
}
|
|
else
|
|
{
|
|
strcpy(path, argv[1]);
|
|
}
|
|
|
|
dir = opendir(path);
|
|
if (dir == NULL)
|
|
{
|
|
printf("This directory doesn't exist or you lack permissions! (%s)\n", path);
|
|
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
|
|
return 1;
|
|
}
|
|
|
|
do
|
|
{
|
|
switch (c)
|
|
{
|
|
case LEFT: // enter the parent directory
|
|
case LEFT2:
|
|
if (strcmp(path, "/") == 0)
|
|
{
|
|
break;
|
|
}
|
|
strcpy(last_entry_name, remove_path(path));
|
|
strcpy(temp_path, dirname(path));
|
|
strcpy(path, temp_path);
|
|
break;
|
|
|
|
case UP: // go up
|
|
case UP2:
|
|
if (position)
|
|
{
|
|
position--;
|
|
}
|
|
break;
|
|
|
|
case DOWN: // go down
|
|
case DOWN2:
|
|
if (entry_count - 1 > position)
|
|
{
|
|
position++;
|
|
}
|
|
break;
|
|
|
|
case RIGHT: // enter a directory
|
|
case RIGHT2:
|
|
stat(current_entry, &st);
|
|
if (S_ISDIR(st.st_mode))
|
|
{
|
|
if (opendir(current_entry) == NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
strcpy(path, current_entry);
|
|
position = 0;
|
|
|
|
}
|
|
break;
|
|
|
|
case JUMP_FIRST: // go to the top of the directory
|
|
position = 0;
|
|
break;
|
|
|
|
case JUMP_LAST: // go to the bottom of the directory
|
|
position = entry_count - 1;
|
|
break;
|
|
|
|
case MOVE: // move or rename an entry
|
|
case SYMLINK: // create a symlink
|
|
case COPY: // copy a file
|
|
case REMOVE: // remove an entry
|
|
if (selected_entries[0][0])
|
|
{
|
|
if (c == REMOVE)
|
|
{
|
|
printf(SECONDARY_FG"\n\nAre you sure that you want to remove the selected entries? (" PRIMARY_FG "y" SECONDARY_FG "/" PRIMARY_FG "N" SECONDARY_FG ")" RESET " ");
|
|
if (getchar() != 'y')
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
for (int i = 0; 1024 > i; i++)
|
|
{
|
|
if (selected_entries[i][0] == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
strcpy(entry_to_work_with, selected_entries[i]);
|
|
|
|
if (selected_entries[1][0] == 0 && c != 'r')
|
|
{
|
|
printf(SECONDARY_FG "\n\nUse a different name? (" PRIMARY_FG "y" SECONDARY_FG "/" PRIMARY_FG "N" SECONDARY_FG ")" RESET " ");
|
|
|
|
if (getchar() == 'y')
|
|
{
|
|
printf(SECONDARY_FG "\nEntry name:" RESET " " PRIMARY_FG);
|
|
tcsetattr( STDIN_FILENO, TCSANOW, &oldt);
|
|
scanf("%255s", entry_name);
|
|
tcsetattr( STDIN_FILENO, TCSANOW, &newt);
|
|
|
|
strcpy(temp_path, entry_name);
|
|
}
|
|
else
|
|
{
|
|
strcpy(temp_path, remove_path(entry_to_work_with));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
strcpy(temp_path, remove_path(entry_to_work_with));
|
|
}
|
|
|
|
printf(RESET);
|
|
|
|
strcpy(new_path, combine_file_path(path, temp_path));
|
|
|
|
switch (c)
|
|
{
|
|
case MOVE:
|
|
rename(entry_to_work_with, new_path);
|
|
break;
|
|
case SYMLINK:
|
|
symlink(entry_to_work_with, new_path);
|
|
break;
|
|
case COPY:
|
|
|
|
if (strcmp(entry_to_work_with, new_path) == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
fptr1 = fopen(entry_to_work_with, "r");
|
|
if (fptr1 != NULL)
|
|
{
|
|
fptr2 = fopen(new_path, "w");
|
|
chr = fgetc(fptr1);
|
|
while (chr != EOF)
|
|
{
|
|
fputc(chr, fptr2);
|
|
chr = fgetc(fptr1);
|
|
}
|
|
|
|
fclose(fptr2);
|
|
}
|
|
|
|
fclose(fptr1);
|
|
break;
|
|
case REMOVE:
|
|
stat(entry_to_work_with, &st);
|
|
|
|
if (S_ISDIR(st.st_mode))
|
|
{
|
|
recursive_remove(entry_to_work_with);
|
|
}
|
|
else
|
|
{
|
|
remove(entry_to_work_with);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
position = 0;
|
|
memset(selected_entries, 0, 1024 * 1024);
|
|
}
|
|
break;
|
|
|
|
case MAKE_FILE: // create a new file
|
|
case MAKE_DIR: // create a new directory
|
|
printf(SECONDARY_FG "\n\nEntry name:" RESET " " PRIMARY_FG);
|
|
tcsetattr( STDIN_FILENO, TCSANOW, &oldt);
|
|
scanf("%255s", entry_name);
|
|
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
|
|
|
|
strcpy(temp_path, combine_file_path(path, entry_name));
|
|
|
|
printf(RESET);
|
|
|
|
if (c == MAKE_FILE)
|
|
{
|
|
fp = fopen(temp_path, "w");
|
|
fclose(fp);
|
|
}
|
|
else
|
|
{
|
|
mkdir(temp_path, 0755);
|
|
}
|
|
break;
|
|
|
|
case TEXT_OPEN: // open current file with the text editor
|
|
external_open(current_entry, TEXT_EDITOR);
|
|
break;
|
|
|
|
case MEDIA_OPEN:
|
|
external_open(current_entry, MEDIA_PLAYER);
|
|
break;
|
|
|
|
case IMAGE_OPEN:
|
|
external_open(current_entry, IMAGE_VIEWER);
|
|
break;
|
|
|
|
case DOCUMENT_OPEN:
|
|
external_open(current_entry, DOCUMENT_READER);
|
|
break;
|
|
|
|
case BROWSER_OPEN:
|
|
external_open(current_entry, BROWSER);
|
|
break;
|
|
|
|
case EXECUTE:
|
|
tcsetattr( STDIN_FILENO, TCSANOW, &oldt);
|
|
external_open(current_entry, current_entry);
|
|
tcsetattr( STDIN_FILENO, TCSANOW, &newt);
|
|
break;
|
|
|
|
case SEARCH: // search entry names
|
|
printf(SECONDARY_FG "\n\nSearch entry:" RESET " " PRIMARY_FG);
|
|
tcsetattr( STDIN_FILENO, TCSANOW, &oldt);
|
|
scanf("%255s", search_term);
|
|
tcsetattr( STDIN_FILENO, TCSANOW, &newt);
|
|
position = 0;
|
|
break;
|
|
|
|
case OPEN: // open a given path
|
|
printf(SECONDARY_FG "\n\nPath to open:" RESET " " PRIMARY_FG);
|
|
tcsetattr( STDIN_FILENO, TCSANOW, &oldt);
|
|
scanf("%255s", temp_path);
|
|
tcsetattr( STDIN_FILENO, TCSANOW, &newt);
|
|
|
|
if (strcmp(temp_path, "..") == 0 || strcmp(temp_path, ".") == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
dir = opendir(temp_path);
|
|
if (dir != NULL)
|
|
{
|
|
strcpy(path, temp_path);
|
|
position = 0;
|
|
}
|
|
break;
|
|
|
|
|
|
case UNHIDE: // unhide hidden entries
|
|
if (hidden)
|
|
{
|
|
hidden = 0;
|
|
}
|
|
else
|
|
{
|
|
hidden = 1;
|
|
}
|
|
|
|
position = 0;
|
|
break;
|
|
|
|
case '1' ... '9': // switch between tags
|
|
current_tag = c - '0' - 1;
|
|
|
|
strcpy(temp_path, tags[current_tag]);
|
|
|
|
if (temp_path[0])
|
|
{
|
|
strcpy(path, temp_path);
|
|
}
|
|
else
|
|
{
|
|
strcpy(tags[current_tag], path);
|
|
}
|
|
|
|
position = 0;
|
|
break;
|
|
|
|
case SELECT: // select entries
|
|
for (int i = 0; 1024 > i; i++)
|
|
{
|
|
if (selected_entries[i][0])
|
|
{
|
|
if (strcmp(selected_entries[i], current_entry) == 0)
|
|
{
|
|
for (int j = i; 1024 > j; j++)
|
|
{
|
|
if (selected_entries[j][0])
|
|
{
|
|
strcpy(selected_entries[j], selected_entries[j + 1]);
|
|
}
|
|
else
|
|
{
|
|
memset(selected_entries[j - 1], 0, 1024);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
strcpy(selected_entries[i], current_entry);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case NORMAL_RESET: // resets everything
|
|
position = 0;
|
|
|
|
memset(selected_entries, 0, 1024 * 1024);
|
|
memset(search_term, 0, 256);
|
|
memset(last_entry_name, 0, 256);
|
|
|
|
break;
|
|
}
|
|
|
|
printf(CLEAR);
|
|
|
|
for (int i = 0; 9 > i; i++)
|
|
{
|
|
if (current_tag == i)
|
|
{
|
|
printf("[" SECONDARY_FG "%d" RESET "] ", i + 1);
|
|
}
|
|
else
|
|
{
|
|
printf("[%d] ", i + 1);
|
|
}
|
|
}
|
|
|
|
printf(SECONDARY_FG "\n\nPath: " PRIMARY_FG "%s\n" RESET, path);
|
|
|
|
if (selected_entries[0][0])
|
|
{
|
|
|
|
printf(SECONDARY_FG "Selected entries: [ ");
|
|
for (int i = 0; 1024 > i; i++)
|
|
{
|
|
if (selected_entries[i][0])
|
|
{
|
|
printf(PRIMARY_FG "%s" SECONDARY_FG ", " RESET, remove_path(selected_entries[i]));
|
|
}
|
|
}
|
|
printf(SECONDARY_FG "]\n");
|
|
}
|
|
|
|
printf(RESET);
|
|
|
|
if (hidden)
|
|
{
|
|
puts(SECONDARY_FG "Hidden files:" PRIMARY_FG " ON" RESET);
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
entry_count = 0;
|
|
file_size_sum = 0;
|
|
|
|
strcpy(tags[current_tag], path);
|
|
dir = opendir(path);
|
|
|
|
while ((entry = readdir(dir)) != NULL)
|
|
{
|
|
|
|
strcpy(entry_name, entry->d_name);
|
|
|
|
if (strcmp(entry_name, "..") == 0 || strcmp(entry_name, ".") == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!hidden && entry_name[0] == '.')
|
|
{
|
|
continue;
|
|
}
|
|
|
|
strcpy(temp_path, combine_file_path(path, entry_name));
|
|
|
|
for (int i = 0; 1024 > i; i++)
|
|
{
|
|
|
|
if (selected_entries[i][0] == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (strcmp(selected_entries[i], temp_path) == 0)
|
|
{
|
|
printf(SECONDARY_FG);
|
|
}
|
|
}
|
|
|
|
// the user entered the parent directory so we want to highlight that
|
|
if (strcmp(entry_name, last_entry_name) == 0)
|
|
{
|
|
position = entry_count;
|
|
memset(last_entry_name, 0, 256);
|
|
printf(SELECTED_BG SELECTED_FG);
|
|
}
|
|
// the user searched for an entry so we want to highlight that
|
|
else if (search_term[0] &&
|
|
strcasestr(entry_name, search_term))
|
|
{
|
|
position = entry_count;
|
|
memset(search_term, 0, 256);
|
|
printf(SELECTED_BG SELECTED_FG);
|
|
}
|
|
else if (entry_count == position &&
|
|
last_entry_name[0] == 0)
|
|
{
|
|
printf(SELECTED_BG SELECTED_FG);
|
|
}
|
|
|
|
if (position == entry_count)
|
|
{
|
|
strcpy(current_entry, temp_path);
|
|
}
|
|
|
|
stat(temp_path, &st);
|
|
size = st.st_size;
|
|
|
|
if(entry->d_type == DT_REG)
|
|
{
|
|
file_size_sum += size;
|
|
}
|
|
|
|
ioctl(0, TIOCGWINSZ, &w);
|
|
rows = (w.ws_row / 2) - 7;
|
|
|
|
if ((position + rows > entry_count
|
|
&& entry_count > position - rows))
|
|
{
|
|
if (entry->d_type == DT_DIR)
|
|
{
|
|
printf(DIRECTORY_FG "[%s]\n", entry_name);
|
|
}
|
|
else if(entry->d_type == DT_LNK)
|
|
{
|
|
readlink(temp_path, symlink_path, 4096);
|
|
printf(SYMLINK_FG "[%s] -> [%s]\n", entry_name, symlink_path);
|
|
memset(symlink_path, 0, 4096);
|
|
}
|
|
else
|
|
{
|
|
printf("[%s] [%s]\n", entry_name, readable_file_size(size, buf));
|
|
}
|
|
}
|
|
|
|
entry_count++;
|
|
|
|
printf(RESET);
|
|
|
|
}
|
|
|
|
if (entry_count == 0)
|
|
{
|
|
puts("Empty directory...");
|
|
}
|
|
|
|
printf(SECONDARY_FG "\nPermissions: " PRIMARY_FG);
|
|
stat(current_entry, &st);
|
|
print_permissions(st);
|
|
printf(RESET SECONDARY_FG "Last changed: " PRIMARY_FG "%s" RESET, ctime(&st.st_ctime));
|
|
|
|
printf(RESET SECONDARY_FG "\nNumber of entries: " PRIMARY_FG "%d" RESET, entry_count);
|
|
if (file_size_sum != 0)
|
|
{
|
|
printf(SECONDARY_FG "\nFile size sum: " PRIMARY_FG "%s" RESET, readable_file_size(file_size_sum, buf));
|
|
}
|
|
|
|
} while((c=getchar()) != QUIT);
|
|
|
|
printf(CLEAR);
|
|
tcsetattr( STDIN_FILENO, TCSANOW, &oldt);
|
|
|
|
return 0;
|
|
}
|