mirror of
https://github.com/hnhx/fx.git
synced 2025-01-09 11:07:25 -03:00
first commit
This commit is contained in:
parent
10e67af670
commit
7082b34900
6 changed files with 681 additions and 0 deletions
10
Makefile
Normal file
10
Makefile
Normal file
|
@ -0,0 +1,10 @@
|
|||
INSTALL_DIR ?= /usr/local/bin
|
||||
|
||||
all:
|
||||
cc *.c -o fx -Wall
|
||||
|
||||
install:
|
||||
cc *.c -o $(INSTALL_DIR)/fx -Wall
|
||||
|
||||
uninstall:
|
||||
rm $(INSTALL_DIR)/fx
|
21
config.h
Normal file
21
config.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
/* Colors */
|
||||
|
||||
#define PRIMARY_FG "\x1B[31m"
|
||||
#define SECONDARY_FG "\x1B[35m"
|
||||
|
||||
#define DIRECTORY_FG "\x1B[32m"
|
||||
#define SYMLINK_FG "\x1B[36m"
|
||||
|
||||
#define SELECTED_FG "\x1B[30m"
|
||||
#define SELECTED_BG "\x1B[47m"
|
||||
|
||||
#define RESET "\x1B[0m"
|
||||
#define CLEAR "\e[1;1H\e[2J"
|
||||
|
||||
/* Software to open files with */
|
||||
|
||||
const char text_editor[256] = "nano";
|
||||
const char media_player[256] = "mpv";
|
||||
const char image_viewer[256] = "feh";
|
||||
const char document_reader[256] = "firefox";
|
||||
const char browser[256] = "firefox";
|
552
fx.c
Normal file
552
fx.c
Normal file
|
@ -0,0 +1,552 @@
|
|||
#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 software[256];
|
||||
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 command[5120];
|
||||
|
||||
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! (%s)\n", path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'a': // enter the parent directory
|
||||
case 'h':
|
||||
if (strcmp(path, "/") == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
strcpy(last_entry_name, remove_path(path));
|
||||
strcpy(temp_path, dirname(path));
|
||||
strcpy(path, temp_path);
|
||||
break;
|
||||
|
||||
case 'w': // go up
|
||||
case 'k':
|
||||
if (position)
|
||||
{
|
||||
position--;
|
||||
}
|
||||
break;
|
||||
|
||||
case 's': // go down
|
||||
case 'j':
|
||||
if (entry_count - 1 > position)
|
||||
{
|
||||
position++;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'd': // enter a directory or open a file
|
||||
case 'l':
|
||||
stat(current_entry, &st);
|
||||
|
||||
if (S_ISDIR(st.st_mode))
|
||||
{
|
||||
strcpy(path, current_entry);
|
||||
position = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
puts(SECONDARY_FG "\n\nOpen file with:\n");
|
||||
puts(SECONDARY_FG "[" PRIMARY_FG "1" SECONDARY_FG"] Text editor");
|
||||
puts(SECONDARY_FG "[" PRIMARY_FG "2" SECONDARY_FG"] Media player");
|
||||
puts(SECONDARY_FG "[" PRIMARY_FG "3" SECONDARY_FG"] Image viewer");
|
||||
puts(SECONDARY_FG "[" PRIMARY_FG "4" SECONDARY_FG"] Document reader");
|
||||
puts(SECONDARY_FG "[" PRIMARY_FG "5" SECONDARY_FG"] Browser");
|
||||
puts(SECONDARY_FG "\n[" PRIMARY_FG "6" SECONDARY_FG"] Execute it");
|
||||
|
||||
c = getchar();
|
||||
switch (c)
|
||||
{
|
||||
case '1':
|
||||
strcpy(software, text_editor);
|
||||
break;
|
||||
case '2':
|
||||
strcpy(software, media_player);
|
||||
break;
|
||||
case '3':
|
||||
strcpy(software, image_viewer);
|
||||
break;
|
||||
case '4':
|
||||
strcpy(software, document_reader);
|
||||
break;
|
||||
case '5':
|
||||
strcpy(software, browser);
|
||||
break;
|
||||
case '6':
|
||||
strcpy(software, current_entry);
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcmp(software, current_entry) == 0)
|
||||
{
|
||||
strcpy(command, software);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(command, "%s %s", software, current_entry);
|
||||
}
|
||||
|
||||
system(command);
|
||||
|
||||
printf(RESET);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'g': // go to the top of the directory
|
||||
position = 0;
|
||||
break;
|
||||
|
||||
case 'G': // go to the bottom of the directory
|
||||
position = entry_count - 1;
|
||||
break;
|
||||
|
||||
case 'm': // move or rename an entry
|
||||
case 'y': // create a symlink
|
||||
case 'c': // copy a file
|
||||
case 'r': // remove an entry
|
||||
if (selected_entries[0][0])
|
||||
{
|
||||
if (c == 'r')
|
||||
{
|
||||
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 'm':
|
||||
rename(entry_to_work_with, new_path);
|
||||
break;
|
||||
case 'y':
|
||||
symlink(entry_to_work_with, new_path);
|
||||
break;
|
||||
case 'c':
|
||||
|
||||
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 'r':
|
||||
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 't': // create a new file
|
||||
case 'T': // 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 == 't')
|
||||
{
|
||||
fp = fopen(temp_path, "w");
|
||||
fclose(fp);
|
||||
}
|
||||
else
|
||||
{
|
||||
mkdir(temp_path, 0755);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case '/': // filter 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 'o': // 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 'u': // 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 32: // space, 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 27: // escape, 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 (strcmp(selected_entries[i], temp_path) == 0)
|
||||
{
|
||||
printf(SECONDARY_FG);
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(entry_name, last_entry_name) == 0)
|
||||
{
|
||||
position = entry_count;
|
||||
memset(last_entry_name, 0, 256);
|
||||
printf(SELECTED_BG SELECTED_FG);
|
||||
}
|
||||
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);
|
||||
printf(SECONDARY_FG "\nFile size sum: " PRIMARY_FG "%s" RESET, readable_file_size(file_size_sum, buf));
|
||||
|
||||
} while((c=getchar()) != 'q');
|
||||
|
||||
tcsetattr( STDIN_FILENO, TCSANOW, &oldt);
|
||||
|
||||
return 0;
|
||||
}
|
BIN
shortcuts.png
Normal file
BIN
shortcuts.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 79 KiB |
92
utils.c
Normal file
92
utils.c
Normal file
|
@ -0,0 +1,92 @@
|
|||
#define _XOPEN_SOURCE 500
|
||||
|
||||
#include <ftw.h>
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int unlink_cb(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf)
|
||||
{
|
||||
int rv = remove(fpath);
|
||||
|
||||
if (rv)
|
||||
perror(fpath);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int print_permissions(struct stat st)
|
||||
{
|
||||
mode_t m = st.st_mode;
|
||||
struct passwd *pw = getpwuid(st.st_uid);
|
||||
struct group *gr = getgrgid(st.st_gid);
|
||||
|
||||
putchar( m & S_IRUSR ? 'r' : '-' );
|
||||
putchar( m & S_IWUSR ? 'w' : '-' );
|
||||
putchar( m & S_IXUSR ? 'x' : '-' );
|
||||
putchar( m & S_IRGRP ? 'r' : '-' );
|
||||
putchar( m & S_IWGRP ? 'w' : '-' );
|
||||
putchar( m & S_IXGRP ? 'x' : '-' );
|
||||
putchar( m & S_IROTH ? 'r' : '-' );
|
||||
putchar( m & S_IWOTH ? 'w' : '-' );
|
||||
putchar( m & S_IXOTH ? 'x' : '-' );
|
||||
|
||||
printf(" %s %s \n", pw->pw_name, gr->gr_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int recursive_remove(char path[4096])
|
||||
{
|
||||
return nftw(path, unlink_cb, 64, FTW_DEPTH | FTW_PHYS);
|
||||
}
|
||||
|
||||
char *remove_path(char path[4096])
|
||||
{
|
||||
static char last_entry_name[256];
|
||||
|
||||
strcpy(last_entry_name, path);
|
||||
char *token = strtok(last_entry_name, "/");
|
||||
while( token != NULL )
|
||||
{
|
||||
strcpy(last_entry_name, token);
|
||||
token = strtok(NULL, "/");
|
||||
}
|
||||
|
||||
free(token);
|
||||
|
||||
return last_entry_name;
|
||||
}
|
||||
|
||||
char *combine_file_path(char path[4096], char file[256])
|
||||
{
|
||||
static char combined_path[4096];
|
||||
|
||||
strcpy(combined_path, path);
|
||||
if (strcmp(path, "/") != 0)
|
||||
{
|
||||
strcat(combined_path, "/");
|
||||
}
|
||||
strcat(combined_path, file);
|
||||
|
||||
return combined_path;
|
||||
}
|
||||
|
||||
char *readable_file_size(double size, char *buf)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
const char* units[] = {"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"};
|
||||
while (size > 1024) {
|
||||
size /= 1024;
|
||||
i++;
|
||||
}
|
||||
|
||||
sprintf(buf, "%.*f %s", i, size, units[i]);
|
||||
|
||||
return buf;
|
||||
}
|
6
utils.h
Normal file
6
utils.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
int open_file(char path[4096]);
|
||||
int recursive_remove(char path[4096]);
|
||||
int print_permissions(struct stat st);
|
||||
char *remove_path(char path[4096]);
|
||||
char *combine_file_path(char path[4096], char file[256]);
|
||||
char *readable_file_size(double size, char *buf);
|
Loading…
Reference in a new issue