commit
7a8f8ff881
10 changed files with 570 additions and 190 deletions
4
Makefile
4
Makefile
|
@ -14,9 +14,9 @@ MANDIR = $(PREFIX)/share/man/man1
|
|||
LDFLAGS = $(shell pkg-config --libs ncursesw)
|
||||
CFLAGS = -O3 -march=native -mtune=native -pipe -s -std=c99 -pedantic -Wall -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 $(shell pkg-config --cflags ncursesw)
|
||||
|
||||
SRC = ccc.c util.c file.c
|
||||
SRC = ccc.c util.c file.c icons.c
|
||||
|
||||
$(TARGET): $(SRC)
|
||||
$(TARGET): $(SRC) $(CONF)
|
||||
$(CC) $(SRC) -o $@ $(CFLAGS) $(LDFLAGS)
|
||||
|
||||
dist:
|
||||
|
|
|
@ -13,6 +13,7 @@ Consider this project incomplete and WIP!
|
|||
| Standard movement | X | |
|
||||
| Advanced movement (jumps) | X | |
|
||||
| File details | X | |
|
||||
| File icons! | X | |
|
||||
| Searching for files | | |
|
||||
| Sorting | | |
|
||||
| Marking and marking operations | | |
|
||||
|
@ -32,9 +33,10 @@ Consider this project incomplete and WIP!
|
|||
### Dependencies
|
||||
|
||||
- gcc
|
||||
- ncurses
|
||||
- ncursesw
|
||||
- make
|
||||
- pkg-config
|
||||
- Any [Nerd Font](https://www.nerdfonts.com/) for file icons (optional, but turned on by default)
|
||||
|
||||
### Building
|
||||
|
||||
|
|
319
ccc.c
319
ccc.c
|
@ -10,25 +10,31 @@
|
|||
#include <ftw.h>
|
||||
#include <time.h>
|
||||
#include <ncurses.h>
|
||||
#include <locale.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "file.h"
|
||||
#include "util.h"
|
||||
#include "config.h"
|
||||
#include "file.h"
|
||||
#include "icons.h"
|
||||
#include "util.h"
|
||||
|
||||
/* functions' definitions */
|
||||
void show_help();
|
||||
void start_ccc();
|
||||
char *check_trash_dir();
|
||||
void change_dir(const char *buf, int selection, int ftype);
|
||||
int mkdir_p(const char *destdir);
|
||||
void mkdir_p(const char *destdir);
|
||||
void populate_files(const char *path, int ftype);
|
||||
int get_directory_size(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf);
|
||||
void add_file_stat(char *filepath, int ftype);
|
||||
void add_file_stat(char *filename, char *path, int ftype);
|
||||
char *get_file_mode(mode_t mode);
|
||||
void highlight_current_line();
|
||||
void show_file_content();
|
||||
void edit_file();
|
||||
void toggle_executable();
|
||||
int write_last_d();
|
||||
void create_file();
|
||||
void delete_files();
|
||||
void wpprintw(const char *fmt, ...);
|
||||
void init_windows();
|
||||
void draw_border_title(WINDOW *window, bool active);
|
||||
|
@ -36,9 +42,12 @@ void draw_border_title(WINDOW *window, bool active);
|
|||
/* global variables */
|
||||
unsigned int focus = 0;
|
||||
long current_selection = 0;
|
||||
bool to_open_file = false;
|
||||
bool dirs_size = DIRS_SIZE;
|
||||
bool show_hidden = SHOW_HIDDEN;
|
||||
bool file_details = SHOW_DETAILS;
|
||||
bool show_icons = SHOW_ICONS;
|
||||
char *argv_cp;
|
||||
char *cwd;
|
||||
char *p_cwd; /* previous cwd */
|
||||
int half_width;
|
||||
|
@ -58,10 +67,24 @@ int main(int argc, char** argv)
|
|||
die("Usage: ccc filename");
|
||||
if (argc == 2) {
|
||||
struct stat st;
|
||||
if (lstat(argv[1], &st) != 0) {
|
||||
if (lstat(argv[1], &st)) {
|
||||
perror("ccc");
|
||||
die("Error from lstat");
|
||||
}
|
||||
/* chdir to directory from argument */
|
||||
if (S_ISDIR(st.st_mode) && chdir(argv[1])) {
|
||||
perror("ccc");
|
||||
die("Error from chdir");
|
||||
} 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");
|
||||
}
|
||||
to_open_file = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* check if it is interactive shell */
|
||||
|
@ -71,6 +94,7 @@ int main(int argc, char** argv)
|
|||
/* initialize screen, don't print special chars,
|
||||
* make ctrl + c work, don't show cursor
|
||||
* enable arrow keys */
|
||||
setlocale(LC_ALL, "");
|
||||
initscr();
|
||||
noecho();
|
||||
cbreak();
|
||||
|
@ -99,16 +123,18 @@ int main(int argc, char** argv)
|
|||
/* init files and marked arrays */
|
||||
files = arraylist_init(100);
|
||||
marked = arraylist_init(100);
|
||||
hashtable_init();
|
||||
|
||||
cwd = memalloc(PATH_MAX * sizeof(char));
|
||||
if (argc == 2) {
|
||||
strcpy(cwd, argv[1]);
|
||||
} else {
|
||||
getcwd(cwd, PATH_MAX);
|
||||
}
|
||||
p_cwd = memalloc(PATH_MAX * sizeof(char));
|
||||
start_ccc();
|
||||
|
||||
populate_files(cwd, 0);
|
||||
if (to_open_file) {
|
||||
current_selection = arraylist_search(files, argv_cp, true);
|
||||
highlight_current_line();
|
||||
}
|
||||
|
||||
int ch, ch2;
|
||||
while (1) {
|
||||
|
@ -117,7 +143,6 @@ int main(int argc, char** argv)
|
|||
die("ccc: Terminal size needs to be at least 80x24\n");
|
||||
}
|
||||
ch = getch();
|
||||
/* printf("%d ",ch); */
|
||||
switch (ch) {
|
||||
/* quit */
|
||||
case 'q':
|
||||
|
@ -134,8 +159,8 @@ int main(int argc, char** argv)
|
|||
break;
|
||||
|
||||
/* go back by backspace or h or left arrow */
|
||||
case BACKSPACE:
|
||||
case LEFT:
|
||||
case BACKSPACE: /* PASSTHROUGH */
|
||||
case LEFT: /* PASSTHROUGH */
|
||||
case 'h':;
|
||||
/* get parent directory */
|
||||
strcpy(p_cwd, cwd);
|
||||
|
@ -151,9 +176,9 @@ int main(int argc, char** argv)
|
|||
break;
|
||||
|
||||
/* enter directory/open a file using enter or l or right arrow */
|
||||
case ENTER:
|
||||
case RIGHT:
|
||||
case 'l':;
|
||||
case ENTER: /* PASSTHROUGH */
|
||||
case RIGHT: /* PASSTHROUGH */
|
||||
case 'l':
|
||||
strcpy(p_cwd, cwd);
|
||||
file c_file = files->items[current_selection];
|
||||
/* check if it is directory or a regular file */
|
||||
|
@ -176,7 +201,7 @@ int main(int argc, char** argv)
|
|||
break;
|
||||
|
||||
/* go up by k or up arrow */
|
||||
case UP:
|
||||
case UP: /* PASSTHROUGH */
|
||||
case 'k':
|
||||
if (current_selection > 0)
|
||||
current_selection--;
|
||||
|
@ -195,7 +220,7 @@ int main(int argc, char** argv)
|
|||
break;
|
||||
|
||||
/* go down by j or down arrow */
|
||||
case DOWN:
|
||||
case DOWN: /* PASSTHROUGH */
|
||||
case 'j':
|
||||
if (current_selection < (files->length - 1))
|
||||
current_selection++;
|
||||
|
@ -234,25 +259,9 @@ int main(int argc, char** argv)
|
|||
|
||||
/* go to the trash dir */
|
||||
case 't':;
|
||||
#ifdef TRASH_DIR
|
||||
char *trash_dir = TRASH_DIR;
|
||||
#else
|
||||
char *trash_dir = getenv("CCC_TRASH");
|
||||
#endif
|
||||
if (trash_dir == NULL) {
|
||||
wpprintw("$CCC_TRASH is not defined");
|
||||
} else {
|
||||
if (access(trash_dir, F_OK) != 0) {
|
||||
/* create the directory with 755 perm if it doesn't exit */
|
||||
if (mkdir_p(trash_dir) == -1) {
|
||||
switch (errno) {
|
||||
case EACCES:
|
||||
wpprintw("Parent directory does not allow write permission or one of directories does not allow search access");
|
||||
}
|
||||
}
|
||||
}
|
||||
char *trash_dir = check_trash_dir();
|
||||
if (trash_dir != NULL)
|
||||
change_dir(trash_dir, 0, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
/* show directories' sizes */
|
||||
|
@ -283,13 +292,22 @@ int main(int argc, char** argv)
|
|||
change_dir(cwd, 0, 0);
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
show_icons = !show_icons;
|
||||
change_dir(cwd, 0, 0);
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
create_file();
|
||||
break;
|
||||
|
||||
case 'X':
|
||||
toggle_executable();
|
||||
break;
|
||||
|
||||
/* mark one file */
|
||||
case SPACE:
|
||||
add_file_stat(files->items[current_selection].path, 1);
|
||||
add_file_stat(files->items[current_selection].name, files->items[current_selection].path, 1);
|
||||
highlight_current_line();
|
||||
break;
|
||||
|
||||
|
@ -300,35 +318,33 @@ int main(int argc, char** argv)
|
|||
|
||||
/* mark actions: */
|
||||
/* delete */
|
||||
case 'd':;
|
||||
if (marked->length) {
|
||||
;
|
||||
}
|
||||
case 'd':
|
||||
delete_files();
|
||||
break;
|
||||
|
||||
/* move */
|
||||
case 'm':;
|
||||
case 'm':
|
||||
if (marked->length) {
|
||||
;
|
||||
}
|
||||
break;
|
||||
|
||||
/* copy */
|
||||
case 'c':;
|
||||
case 'c':
|
||||
if (marked->length) {
|
||||
;
|
||||
}
|
||||
break;
|
||||
|
||||
/* symbolic link */
|
||||
case 's':;
|
||||
case 's':
|
||||
if (marked->length) {
|
||||
;
|
||||
}
|
||||
break;
|
||||
|
||||
/* bulk rename */
|
||||
case 'b':;
|
||||
case 'b':
|
||||
if (marked->length) {
|
||||
;
|
||||
}
|
||||
|
@ -352,6 +368,7 @@ int main(int argc, char** argv)
|
|||
break;
|
||||
}
|
||||
}
|
||||
free(argv_cp);
|
||||
arraylist_free(files);
|
||||
arraylist_free(marked);
|
||||
endwin();
|
||||
|
@ -374,6 +391,47 @@ void start_ccc()
|
|||
init_windows();
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if the trash directory is set and returns it
|
||||
*/
|
||||
char *check_trash_dir()
|
||||
{
|
||||
char *path = memalloc(PATH_MAX * sizeof(char));
|
||||
|
||||
char *trash_dir;
|
||||
#ifdef TRASH_DIR
|
||||
trash_dir = TRASH_DIR;
|
||||
#endif
|
||||
|
||||
/* check if there is trash_dir */
|
||||
if (trash_dir == NULL) {
|
||||
wpprintw("No trash directory defined");
|
||||
return NULL;
|
||||
} else {
|
||||
/* if trash_dir has ~ then make it $HOME */
|
||||
/* use path as trash_dir */
|
||||
if (trash_dir[0] == '~') {
|
||||
char *home = getenv("HOME");
|
||||
if (home == NULL) {
|
||||
wpprintw("$HOME is not defined, can't read the trash directory");
|
||||
return NULL;
|
||||
}
|
||||
/* replace ~ with home */
|
||||
snprintf(path, PATH_MAX, "%s%s", home, trash_dir + 1);
|
||||
}
|
||||
else {
|
||||
strcpy(path, trash_dir);
|
||||
}
|
||||
|
||||
/* if has access to trash_dir */
|
||||
if (access(path, F_OK) != 0) {
|
||||
/* create the directory with 755 permissions if it doesn't exist */
|
||||
mkdir_p(path);
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
/*
|
||||
* Change directory in window with selection
|
||||
*/
|
||||
|
@ -381,16 +439,15 @@ void change_dir(const char *buf, int selection, int ftype)
|
|||
{
|
||||
char *buf_dup;
|
||||
if (buf == p_cwd) {
|
||||
buf_dup = strdup(p_cwd);
|
||||
if (buf_dup == NULL) {
|
||||
return;
|
||||
}
|
||||
buf_dup = estrdup(p_cwd);
|
||||
} else {
|
||||
buf_dup = (char *) buf;
|
||||
}
|
||||
strcpy(cwd, buf_dup);
|
||||
if (ftype != 2) {
|
||||
arraylist_free(files);
|
||||
files = arraylist_init(100);
|
||||
}
|
||||
current_selection = selection;
|
||||
populate_files(cwd, ftype);
|
||||
}
|
||||
|
@ -399,7 +456,7 @@ void change_dir(const char *buf, int selection, int ftype)
|
|||
* Recursively create directory by creating each subdirectory
|
||||
* like mkdir -p
|
||||
*/
|
||||
int mkdir_p(const char *destdir)
|
||||
void mkdir_p(const char *destdir)
|
||||
{
|
||||
char *path = memalloc(PATH_MAX * sizeof(char));
|
||||
char dir_path[PATH_MAX] = "";
|
||||
|
@ -408,7 +465,7 @@ int mkdir_p(const char *destdir)
|
|||
char *home = getenv("HOME");
|
||||
if (home == NULL) {
|
||||
wpprintw("$HOME is not defined");
|
||||
return -1;
|
||||
return;
|
||||
}
|
||||
/* replace ~ with home */
|
||||
snprintf(path, PATH_MAX, "%s%s", home, destdir + 1);
|
||||
|
@ -433,21 +490,20 @@ int mkdir_p(const char *destdir)
|
|||
continue;
|
||||
}
|
||||
|
||||
perror("ccc");
|
||||
wpprintw("mkdir failed: %s\n", strerror(errno));
|
||||
free(path);
|
||||
return -1;
|
||||
return;
|
||||
}
|
||||
token = strtok(NULL, "/");
|
||||
}
|
||||
|
||||
free(path);
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the provided directory and add all files in directory to linked list
|
||||
* ftype: normal files = 0, marked = 1, marking ALL = 2
|
||||
* ep->d_name -> filename
|
||||
*/
|
||||
void populate_files(const char *path, int ftype)
|
||||
{
|
||||
|
@ -459,22 +515,22 @@ void populate_files(const char *path, int ftype)
|
|||
wclear(directory_content);
|
||||
|
||||
while ((ep = readdir(dp)) != NULL) {
|
||||
char *path = memalloc(PATH_MAX * sizeof(char));
|
||||
char *filename = memalloc(PATH_MAX * sizeof(char));
|
||||
/* make filename be basename of selected item just to pass check */
|
||||
filename[0] = '\0';
|
||||
strcat(filename, ep->d_name);
|
||||
/* copy filename */
|
||||
strcpy(filename, ep->d_name);
|
||||
|
||||
/* use strncmp to filter out dotfiles */
|
||||
if ((!show_hidden && strncmp(filename, ".", 1) && strncmp(filename, "..", 2)) || (show_hidden && strcmp(filename, ".") && strcmp(filename, ".."))) {
|
||||
/* construct full file path */
|
||||
filename[0] = '\0';
|
||||
strcat(filename, cwd);
|
||||
strcat(filename, "/");
|
||||
strcat(filename, ep->d_name); /* add filename */
|
||||
strcpy(path, cwd);
|
||||
strcat(path, "/");
|
||||
strcat(path, filename); /* add filename */
|
||||
|
||||
add_file_stat(filename, ftype);
|
||||
add_file_stat(filename, path, ftype);
|
||||
}
|
||||
free(filename);
|
||||
free(path);
|
||||
}
|
||||
closedir(dp);
|
||||
wrefresh(directory_content);
|
||||
|
@ -493,40 +549,62 @@ int get_directory_size(const char *fpath, const struct stat *sb, int typeflag, s
|
|||
/*
|
||||
* Get file's last modified time, size, type
|
||||
* Add that file into list
|
||||
* ftype: normal file = 0, normal marked = 1, marking ALL = 2
|
||||
* ftype: normal file = 0, normal marked = 1, marked ALL = 2
|
||||
*/
|
||||
void add_file_stat(char *filepath, int ftype)
|
||||
void add_file_stat(char *filename, char *path, int ftype)
|
||||
{
|
||||
struct stat file_stat;
|
||||
if (stat(filepath, &file_stat) == -1) {
|
||||
if (stat(path, &file_stat) == -1) {
|
||||
/* can't be triggered? */
|
||||
if (errno == EACCES)
|
||||
arraylist_add(files, filepath, "", "", 8, false, false);
|
||||
arraylist_add(files, filename, path, NULL, NULL, NULL, 8, false, false);
|
||||
}
|
||||
|
||||
/* get file type and color, 4 chars for the type */
|
||||
char *type = memalloc(4 * sizeof(char));
|
||||
/* get file type and color, 4 chars for the type and icon */
|
||||
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);
|
||||
|
||||
filename[strlen(filename)] = '\0';
|
||||
/* handle file without extension
|
||||
* ext is the extension if . exist in filename
|
||||
* otherwise is nothing and handled through tenery operator */
|
||||
char *ext = strrchr(filename, '.');
|
||||
if (ext != NULL) {
|
||||
ext += 1;
|
||||
}
|
||||
/* add file extension */
|
||||
icon *ext_icon = hashtable_search(ext != NULL ? ext : filename);
|
||||
if (ext_icon == NULL)
|
||||
wcsncpy(icon_str, L"", 2);
|
||||
else
|
||||
wcsncpy(icon_str, ext_icon->icon, 2);
|
||||
|
||||
int color;
|
||||
|
||||
if (S_ISDIR(file_stat.st_mode)) {
|
||||
strcpy(type, "DIR"); /* directory type */
|
||||
strncpy(type, "DIR", 4); /* directory type */
|
||||
color = 5; /* blue color */
|
||||
wcsncpy(icon_str, L"", 2);
|
||||
} else if (S_ISREG(file_stat.st_mode)) {
|
||||
strcpy(type, "REG"); /* regular file */
|
||||
strncpy(type, "REG", 4); /* regular file */
|
||||
color = 8; /* white color */
|
||||
} else if (S_ISLNK(file_stat.st_mode)) {
|
||||
strcpy(type, "LNK"); /* symbolic link */
|
||||
strncpy(type, "LNK", 4); /* symbolic link */
|
||||
color = 3; /* green color */
|
||||
} else if (S_ISCHR(file_stat.st_mode)) {
|
||||
strcpy(type, "CHR"); /* character device */
|
||||
strncpy(type, "CHR", 4); /* character device */
|
||||
color = 8; /* white color */
|
||||
} else if (S_ISSOCK(file_stat.st_mode)) {
|
||||
strcpy(type, "SOC"); /* socket */
|
||||
strncpy(type, "SOC", 4); /* socket */
|
||||
color = 8; /* white color */
|
||||
} else if (S_ISBLK(file_stat.st_mode)) {
|
||||
strcpy(type, "BLK"); /* block device */
|
||||
strncpy(type, "BLK", 4); /* block device */
|
||||
color = 4; /* yellow color */
|
||||
} else if (S_ISFIFO(file_stat.st_mode)) {
|
||||
strcpy(type, "FIF"); /* FIFO */
|
||||
strncpy(type, "FIF", 4); /* FIFO */
|
||||
color = 8; /* white color */
|
||||
} else {
|
||||
color = 8; /* white color */
|
||||
|
@ -536,16 +614,17 @@ void add_file_stat(char *filepath, int ftype)
|
|||
if (ftype == 1 || ftype == 2) {
|
||||
/* force if user is marking all files */
|
||||
bool force = ftype == 2 ? true : false;
|
||||
arraylist_add(marked, filepath, NULL, type, 8, true, force);
|
||||
arraylist_add(marked, filename, path, NULL, type, icon_str, 8, true, force);
|
||||
/* free type and return without allocating more stuff */
|
||||
free(type);
|
||||
return;
|
||||
}
|
||||
|
||||
/* get last modified time */
|
||||
char *time = memalloc(20 * sizeof(char));
|
||||
size_t time_size = 17 * sizeof(char);
|
||||
char *time = memalloc(time_size);
|
||||
/* format last modified time to a string */
|
||||
strftime(time, 20, "%Y-%m-%d %H:%M", localtime(&file_stat.st_mtime));
|
||||
strftime(time, time_size, "%Y-%m-%d %H:%M", localtime(&file_stat.st_mtime));
|
||||
|
||||
/* get file size */
|
||||
double bytes = file_stat.st_size;
|
||||
|
@ -555,35 +634,44 @@ void add_file_stat(char *filepath, int ftype)
|
|||
if (S_ISDIR(file_stat.st_mode)) {
|
||||
/* at most 15 fd opened */
|
||||
total_dir_size = 0;
|
||||
nftw(filepath, &get_directory_size, 15, FTW_PHYS);
|
||||
nftw(path, &get_directory_size, 15, FTW_PHYS);
|
||||
bytes = total_dir_size;
|
||||
}
|
||||
}
|
||||
/* max 25 chars due to long, space, suffix and null */
|
||||
char *size = memalloc(25 * sizeof(char));
|
||||
/* 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 */
|
||||
int size_size = 4 + 1 + DECIMAL_PLACES + strlen(units[1]) + 1 + 1;
|
||||
char *size = memalloc(size_size * sizeof(char));
|
||||
int unit = 0;
|
||||
const char* units[] = {"B", "KiB", "MiB", "GiB", "TiB", "PiB"};
|
||||
while (bytes > 1024) {
|
||||
bytes /= 1024;
|
||||
unit++;
|
||||
}
|
||||
/* display sizes */
|
||||
sprintf(size, "%.3g%s", bytes, units[unit]);
|
||||
|
||||
/* display sizes and check if there are decimal places */
|
||||
if (bytes == (unsigned int) bytes) {
|
||||
sprintf(size, "%d%s", (unsigned int) bytes, units[unit]);
|
||||
} else {
|
||||
sprintf(size, "%.*f%s", DECIMAL_PLACES, bytes, units[unit]);
|
||||
}
|
||||
/* get file mode string */
|
||||
char *mode_str = get_file_mode(file_stat.st_mode);
|
||||
if (mode_str[0] == '-' && (mode_str[3] == 'x' || mode_str[6] == 'x' || mode_str[9] == 'x')) {
|
||||
|
||||
char *total_stat = memalloc(56 * sizeof(char));
|
||||
snprintf(total_stat, 56, "%s %s %-8s", mode_str, time, size);
|
||||
total_stat[strlen(total_stat)] = '\0';
|
||||
}
|
||||
|
||||
arraylist_add(files, filepath, total_stat, type, color, false, false);
|
||||
/* 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);
|
||||
|
||||
arraylist_add(files, filename, path, total_stat, type, icon_str, color, false, false);
|
||||
|
||||
free(time);
|
||||
free(size);
|
||||
free(total_stat);
|
||||
free(type);
|
||||
free(mode_str);
|
||||
free(icon_str);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -592,8 +680,8 @@ void add_file_stat(char *filepath, int ftype)
|
|||
*/
|
||||
char *get_file_mode(mode_t mode)
|
||||
{
|
||||
char *mode_str = memalloc(sizeof(char) * 11);
|
||||
mode_str[0] = S_ISDIR(mode) ? 'd' : '-'; // Check if it's a directory
|
||||
char *mode_str = memalloc(11 * sizeof(char));
|
||||
mode_str[0] = S_ISDIR(mode) ? 'd' : '-'; /* Check if it's a directory */
|
||||
mode_str[1] = (mode & S_IRUSR) ? 'r' : '-';
|
||||
mode_str[2] = (mode & S_IWUSR) ? 'w' : '-';
|
||||
mode_str[3] = (mode & S_IXUSR) ? 'x' : '-';
|
||||
|
@ -603,7 +691,7 @@ char *get_file_mode(mode_t mode)
|
|||
mode_str[7] = (mode & S_IROTH) ? 'r' : '-';
|
||||
mode_str[8] = (mode & S_IWOTH) ? 'w' : '-';
|
||||
mode_str[9] = (mode & S_IXOTH) ? 'x' : '-';
|
||||
mode_str[10] = '\0'; // Null terminator
|
||||
mode_str[10] = '\0';
|
||||
return mode_str;
|
||||
}
|
||||
|
||||
|
@ -660,10 +748,10 @@ void highlight_current_line()
|
|||
}
|
||||
}
|
||||
/* print the actual filename and stats */
|
||||
char *line = get_line(files, i, file_details);
|
||||
char *line = get_line(files, i, file_details, show_icons);
|
||||
int color = files->items[i].color;
|
||||
/* check is file marked for action */
|
||||
bool is_marked = arraylist_includes(marked, files->items[i].path);
|
||||
bool is_marked = arraylist_search(marked, files->items[i].path, false) != -1;
|
||||
if (is_marked) {
|
||||
/* show file is selected */
|
||||
wattron(directory_content, COLOR_PAIR(7));
|
||||
|
@ -694,10 +782,10 @@ void highlight_current_line()
|
|||
#if DRAW_PREVIEW
|
||||
show_file_content();
|
||||
#endif
|
||||
wrefresh(preview_content);
|
||||
#if DRAW_BORDERS
|
||||
draw_border_title(preview_border, true);
|
||||
#endif
|
||||
wrefresh(preview_content);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -705,15 +793,16 @@ void highlight_current_line()
|
|||
*/
|
||||
void show_file_content()
|
||||
{
|
||||
wclear(preview_content);
|
||||
file current_file = files->items[current_selection];
|
||||
|
||||
if (strncmp(current_file.type, "DIR", 3) == 0)
|
||||
return;
|
||||
|
||||
wclear(preview_content);
|
||||
|
||||
FILE *file = fopen(current_file.path, "r");
|
||||
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.name);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -825,6 +914,42 @@ int write_last_d()
|
|||
return 0;
|
||||
}
|
||||
|
||||
void create_file()
|
||||
{
|
||||
echo();
|
||||
wpprintw("New file: ");
|
||||
char input[PATH_MAX];
|
||||
/* get string at y=0, x=10 */
|
||||
mvwgetstr(panel, 0, 10, input);
|
||||
FILE *f = fopen(input, "w+");
|
||||
fclose(f);
|
||||
wpprintw("Created %s", input);
|
||||
change_dir(cwd, 0, 0);
|
||||
noecho();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
wpprintw("TODO: implement hard delete");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Print line to the panel
|
||||
*/
|
||||
|
|
30
config.h
30
config.h
|
@ -1,17 +1,13 @@
|
|||
/* Settings */
|
||||
#define PH 1 /* panel height */
|
||||
#define JUMP_NUM 14 /* how long ctrl + u/d jump are */
|
||||
#define PATH_MAX 4096
|
||||
#define PATH_MAX 4096 /* max length of the path */
|
||||
#define DECIMAL_PLACES 1 /* how many decimal places show size with */
|
||||
|
||||
/* Calculate directories' sizes RECURSIVELY upon entering? */
|
||||
#define DIRS_SIZE false
|
||||
/* Size units */
|
||||
static const char* units[] = {"B", "K", "M", "G", "T", "P"};
|
||||
|
||||
#define DRAW_BORDERS true /* Draw borders around windows? */
|
||||
#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:
|
||||
+-------------%-------------+
|
||||
| % |
|
||||
| files % preview |
|
||||
|
@ -25,12 +21,28 @@ In COLS:
|
|||
-15 will make preview bigger */
|
||||
#define WINDOW_OFFSET 0
|
||||
|
||||
/* Options */
|
||||
#define DRAW_BORDERS true /* draw borders around windows */
|
||||
#define DRAW_PREVIEW true /* draw file preview */
|
||||
|
||||
#define SHOW_HIDDEN true /* show hidden files/dotfiles at startup */
|
||||
#define SHOW_DETAILS true /* show file details at startup */
|
||||
#define SHOW_ICONS true /* show file icons at startup */
|
||||
|
||||
/* Calculate directories' sizes RECURSIVELY upon entering
|
||||
`A` keybind at the startup
|
||||
**VERY EXPENSIVE**, **CAN TAKE UP TO A MINUTE IN ROOT** */
|
||||
#define DIRS_SIZE false
|
||||
|
||||
/* Default text editor */
|
||||
#define EDITOR "nvim"
|
||||
|
||||
/* File location to write last directory */
|
||||
#define LAST_D "~/.cache/ccc/.ccc_d"
|
||||
|
||||
/* Will create this directory if doesn't exist! */
|
||||
#define TRASH_DIR "~/.cache/ccc/trash/"
|
||||
|
||||
/* Keybindings */
|
||||
#define CTRLD 0x04
|
||||
#define ENTER 0xA
|
||||
|
|
140
file.c
140
file.c
|
@ -2,21 +2,10 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <libgen.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
typedef struct file {
|
||||
char *path;
|
||||
char *stats;
|
||||
char *type;
|
||||
int color;
|
||||
} file;
|
||||
|
||||
typedef struct ArrayList {
|
||||
size_t length;
|
||||
size_t capacity;
|
||||
file *items;
|
||||
} ArrayList;
|
||||
#include "file.h"
|
||||
|
||||
ArrayList *arraylist_init(size_t capacity)
|
||||
{
|
||||
|
@ -24,87 +13,96 @@ ArrayList *arraylist_init(size_t capacity)
|
|||
list->length = 0;
|
||||
list->capacity = capacity;
|
||||
list->items = memalloc(capacity * sizeof(file));
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
void arraylist_free(ArrayList *list)
|
||||
{
|
||||
for (size_t i = 0; i < list->length; i++) {
|
||||
if (list->items[i].type != NULL)
|
||||
free(list->items[i].type);
|
||||
if (list->items[i].name != NULL)
|
||||
free(list->items[i].name);
|
||||
if (list->items[i].path != NULL)
|
||||
free(list->items[i].path);
|
||||
if (list->items[i].type != NULL)
|
||||
free(list->items[i].type);
|
||||
if (list->items[i].stats != NULL)
|
||||
free(list->items[i].stats);
|
||||
if (list->items[i].icon != NULL)
|
||||
free(list->items[i].icon);
|
||||
}
|
||||
|
||||
free(list->items);
|
||||
list->length = 0;
|
||||
}
|
||||
|
||||
bool arraylist_includes(ArrayList *list, char *path)
|
||||
/*
|
||||
* Check if the file is in the arraylist
|
||||
* Treat filepath as base name if bname is true
|
||||
*/
|
||||
long arraylist_search(ArrayList *list, char *filepath, bool bname)
|
||||
{
|
||||
for (int i = 0; i < list->length; i++) {
|
||||
if (strcmp(list->items[i].path, path) == 0) {
|
||||
return true;
|
||||
for (long i = 0; i < list->length; i++) {
|
||||
if (!bname && strcmp(list->items[i].path, filepath) == 0) {
|
||||
return i;
|
||||
}
|
||||
if (bname) {
|
||||
if (strcmp(list->items[i].name, filepath) == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void arraylist_remove(ArrayList *list, long index)
|
||||
{
|
||||
if (index >= list->length) {
|
||||
if (index >= list->length)
|
||||
return;
|
||||
}
|
||||
|
||||
free(list->items[index].name);
|
||||
free(list->items[index].path);
|
||||
free(list->items[index].stats);
|
||||
free(list->items[index].type);
|
||||
free(list->items[index].stats);
|
||||
free(list->items[index].icon);
|
||||
|
||||
for (long i = index; i < list->length - 1; i++) {
|
||||
for (long i = index; i < list->length - 1; i++)
|
||||
list->items[i] = list->items[i + 1];
|
||||
}
|
||||
|
||||
list->length--;
|
||||
}
|
||||
|
||||
/*
|
||||
* force will not remove duplicate marked files, instead it just skip adding
|
||||
* Force will not remove duplicate marked files, instead it just skip adding
|
||||
*/
|
||||
void arraylist_add(ArrayList *list, char *filepath, char *stats, char *type, int color, bool marked, bool force)
|
||||
void arraylist_add(ArrayList *list, char *name, char *path, char *stats, char *type, wchar_t *icon, int color, bool marked, bool force)
|
||||
{
|
||||
char *filepath_cp = NULL;
|
||||
char *stats_cp = NULL;
|
||||
char *name_cp = NULL;
|
||||
char *path_cp = NULL;
|
||||
char *type_cp = NULL;
|
||||
if (filepath != NULL) {
|
||||
filepath_cp = strdup(filepath);
|
||||
if (filepath_cp == NULL) {
|
||||
perror("ccc");
|
||||
}
|
||||
}
|
||||
if (stats != NULL) {
|
||||
stats_cp = strdup(stats);
|
||||
if (stats_cp == NULL) {
|
||||
perror("ccc");
|
||||
}
|
||||
}
|
||||
if (type != NULL) {
|
||||
type_cp = strdup(type);
|
||||
if (type_cp == NULL) {
|
||||
perror("ccc");
|
||||
}
|
||||
}
|
||||
char *stats_cp = NULL;
|
||||
wchar_t *icon_cp = NULL;
|
||||
|
||||
/* path, stats, type, color */
|
||||
file new_file = { filepath_cp, stats_cp, type_cp, color };
|
||||
if (name != NULL)
|
||||
name_cp = estrdup(name);
|
||||
if (path != NULL)
|
||||
path_cp = estrdup(path);
|
||||
if (type != NULL)
|
||||
type_cp = estrdup(type);
|
||||
if (stats != NULL)
|
||||
stats_cp = estrdup(stats);
|
||||
if (icon != NULL)
|
||||
icon_cp = ewcsdup(icon);
|
||||
|
||||
/* name, path, stats, type, icon, color */
|
||||
file new_file = { name_cp, path_cp, type_cp, stats_cp, icon_cp, color };
|
||||
|
||||
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) {
|
||||
if (!force)
|
||||
arraylist_remove(list, i);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -116,9 +114,10 @@ void arraylist_add(ArrayList *list, char *filepath, char *stats, char *type, int
|
|||
file *old_items = list->items;
|
||||
list->capacity = new_cap;
|
||||
list->items = new_items;
|
||||
for (int i = 0; i < list->length; i++) {
|
||||
|
||||
for (int i = 0; i < list->length; i++)
|
||||
new_items[i] = old_items[i];
|
||||
}
|
||||
|
||||
free(old_items);
|
||||
list->items[list->length] = new_file;
|
||||
}
|
||||
|
@ -128,31 +127,36 @@ void arraylist_add(ArrayList *list, char *filepath, char *stats, char *type, int
|
|||
/*
|
||||
* Construct a formatted line for display
|
||||
*/
|
||||
char *get_line(ArrayList *list, long index, bool detail)
|
||||
char *get_line(ArrayList *list, long index, bool detail, bool icons)
|
||||
{
|
||||
file file = list->items[index];
|
||||
char *name = strdup(file.path);
|
||||
char *name = estrdup(file.name);
|
||||
wchar_t *icon = ewcsdup(file.icon);
|
||||
|
||||
size_t name_len = strlen(name);
|
||||
char *stats = NULL;
|
||||
size_t length;
|
||||
if (detail) {
|
||||
stats = strdup(file.stats);
|
||||
length = strlen(name) + strlen(stats) + 2; /* one for space and one for null */
|
||||
if (stats == NULL) {
|
||||
perror("ccc");
|
||||
}
|
||||
stats = estrdup(file.stats);
|
||||
length = name_len + strlen(stats) + 7; /* 4 for icon, 2 for space and 1 for null */
|
||||
} else {
|
||||
length = strlen(name) + 2; /* one for space and one for null */
|
||||
length = name_len + 6; /* 4 for icon, 1 for space and 1 for null */
|
||||
}
|
||||
char *line = memalloc(length * sizeof(char));
|
||||
|
||||
name = basename(name);
|
||||
if (name == NULL)
|
||||
perror("ccc");
|
||||
char *line = memalloc(length * sizeof(char));
|
||||
line[0] = '\0';
|
||||
if (detail) {
|
||||
snprintf(line, length, "%s %s", stats, name);
|
||||
} else {
|
||||
snprintf(line, length, "%s", name);
|
||||
strcat(line, stats);
|
||||
strcat(line, " ");
|
||||
}
|
||||
if (icons) {
|
||||
char *tmp = memalloc(8 * sizeof(char));
|
||||
snprintf(tmp, 8, "%ls", icon);
|
||||
strcat(line, tmp);
|
||||
strcat(line, " ");
|
||||
free(tmp);
|
||||
}
|
||||
strcat(line, name);
|
||||
|
||||
return line;
|
||||
}
|
||||
|
|
12
file.h
12
file.h
|
@ -4,9 +4,11 @@
|
|||
#include <stdio.h>
|
||||
|
||||
typedef struct file {
|
||||
char *path;
|
||||
char *stats;
|
||||
char *name; /* basename */
|
||||
char *path; /* absolute path */
|
||||
char *type;
|
||||
char *stats;
|
||||
wchar_t *icon;
|
||||
int color;
|
||||
} file;
|
||||
|
||||
|
@ -18,9 +20,9 @@ typedef struct ArrayList {
|
|||
|
||||
ArrayList *arraylist_init(size_t capacity);
|
||||
void arraylist_free(ArrayList *list);
|
||||
bool arraylist_includes(ArrayList *list, char *path);
|
||||
long arraylist_search(ArrayList *list, char *filepath, bool bname);
|
||||
void arraylist_remove(ArrayList *list, long index);
|
||||
void arraylist_add(ArrayList *list, char *filepath, char *stats, char *type, int color, bool marked, bool force);
|
||||
char *get_line(ArrayList *list, long index, bool detail);
|
||||
void arraylist_add(ArrayList *list, char *filename, char *path, char *stats, char *type, wchar_t *icon, int color, bool marked, bool force);
|
||||
char *get_line(ArrayList *list, long index, bool detail, bool icons);
|
||||
|
||||
#endif
|
||||
|
|
191
icons.c
Normal file
191
icons.c
Normal file
|
@ -0,0 +1,191 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "icons.h"
|
||||
#include "util.h"
|
||||
|
||||
icon *hash_table[TABLE_SIZE];
|
||||
|
||||
/* Hashes every name with: name and TABLE_SIZE */
|
||||
unsigned int hash(char *name)
|
||||
{
|
||||
int length = strnlen(name, MAX_NAME), i = 0;
|
||||
unsigned int hash_value = 0;
|
||||
|
||||
for (; i < length; i++) {
|
||||
hash_value += name[i];
|
||||
hash_value = (hash_value * name[i]) % TABLE_SIZE;
|
||||
}
|
||||
|
||||
return hash_value;
|
||||
}
|
||||
|
||||
void hashtable_init()
|
||||
{
|
||||
for (int i = 0; i < TABLE_SIZE; i++)
|
||||
hash_table[i] = NULL;
|
||||
|
||||
icon *c = memalloc(sizeof(icon));
|
||||
strcpy(c->name, "c");
|
||||
c->icon = L"";
|
||||
|
||||
icon *h = memalloc(sizeof(icon));
|
||||
strcpy(h->name, "h");
|
||||
h->icon = L"";
|
||||
|
||||
icon *cpp = memalloc(sizeof(icon));
|
||||
strcpy(cpp->name, "cpp");
|
||||
cpp->icon = L"";
|
||||
|
||||
icon *hpp = memalloc(sizeof(icon));
|
||||
strcpy(hpp->name, "hpp");
|
||||
hpp->icon = L"";
|
||||
|
||||
icon *md = memalloc(sizeof(icon));
|
||||
strcpy(md->name, "md");
|
||||
md->icon = L"";
|
||||
|
||||
icon *py = memalloc(sizeof(icon));
|
||||
strcpy(py->name, "py");
|
||||
py->icon = L"";
|
||||
|
||||
icon *java = memalloc(sizeof(icon));
|
||||
strcpy(java->name, "java");
|
||||
java->icon = L"";
|
||||
|
||||
icon *json = memalloc(sizeof(icon));
|
||||
strcpy(json->name, "json");
|
||||
json->icon = L"";
|
||||
|
||||
icon *js = memalloc(sizeof(icon));
|
||||
strcpy(js->name, "js");
|
||||
js->icon = L"";
|
||||
|
||||
icon *html = memalloc(sizeof(icon));
|
||||
strcpy(html->name, "html");
|
||||
html->icon = L"";
|
||||
|
||||
icon *rs = memalloc(sizeof(icon));
|
||||
strcpy(rs->name, "rs");
|
||||
rs->icon = L"";
|
||||
|
||||
icon *sh = memalloc(sizeof(icon));
|
||||
strcpy(sh->name, "sh");
|
||||
sh->icon = L"";
|
||||
|
||||
icon *go = memalloc(sizeof(icon));
|
||||
strcpy(go->name, "go");
|
||||
go->icon = L"";
|
||||
|
||||
icon *r = memalloc(sizeof(icon));
|
||||
strcpy(r->name, "r");
|
||||
r->icon = L"";
|
||||
|
||||
icon *diff = memalloc(sizeof(icon));
|
||||
strcpy(diff->name, "diff");
|
||||
diff->icon = L"";
|
||||
|
||||
icon *hs = memalloc(sizeof(icon));
|
||||
strcpy(hs->name, "hs");
|
||||
hs->icon = L"";
|
||||
|
||||
icon *log = memalloc(sizeof(icon));
|
||||
strcpy(log->name, "log");
|
||||
log->icon = L"";
|
||||
|
||||
icon *rb = memalloc(sizeof(icon));
|
||||
strcpy(rb->name, "rb");
|
||||
rb->icon = L"";
|
||||
|
||||
icon *iso = memalloc(sizeof(icon));
|
||||
strcpy(iso->name, "iso");
|
||||
iso->icon = L"";
|
||||
|
||||
icon *lua = memalloc(sizeof(icon));
|
||||
strcpy(lua->name, "lua");
|
||||
lua->icon = L"";
|
||||
|
||||
icon *license = memalloc(sizeof(icon));
|
||||
strcpy(license->name, "LICENSE");
|
||||
license->icon = L"";
|
||||
|
||||
icon *gitignore = memalloc(sizeof(icon));
|
||||
strcpy(gitignore->name, "gitignore");
|
||||
gitignore->icon = L"";
|
||||
|
||||
hashtable_add(c);
|
||||
hashtable_add(h);
|
||||
hashtable_add(cpp);
|
||||
hashtable_add(hpp);
|
||||
hashtable_add(md);
|
||||
hashtable_add(py);
|
||||
hashtable_add(java);
|
||||
hashtable_add(json);
|
||||
hashtable_add(js);
|
||||
hashtable_add(html);
|
||||
hashtable_add(rs);
|
||||
hashtable_add(sh);
|
||||
hashtable_add(go);
|
||||
hashtable_add(r);
|
||||
hashtable_add(diff);
|
||||
hashtable_add(hs);
|
||||
hashtable_add(log);
|
||||
hashtable_add(rb);
|
||||
hashtable_add(iso);
|
||||
hashtable_add(lua);
|
||||
hashtable_add(license);
|
||||
hashtable_add(gitignore);
|
||||
}
|
||||
|
||||
void hashtable_print()
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (; i < TABLE_SIZE; i++) {
|
||||
if (hash_table[i] == NULL) {
|
||||
printf("%i. ---\n", i);
|
||||
} else {
|
||||
printf("%i. | Name %s | Icon %ls\n", i, hash_table[i]->name, hash_table[i]->icon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Gets hashed name and tries to store the icon struct in that place */
|
||||
bool hashtable_add(icon *p)
|
||||
{
|
||||
if (p == NULL) return false;
|
||||
|
||||
int index = hash(p->name);
|
||||
int initial_index = index;
|
||||
/* linear probing until an empty slot is found */
|
||||
while (hash_table[index] != NULL) {
|
||||
index = (index + 1) % TABLE_SIZE; /* move to next item */
|
||||
/* the hash table is full as no available index back to initial index, cannot fit new item */
|
||||
if (index == initial_index) return false;
|
||||
}
|
||||
|
||||
hash_table[index] = p;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Rehashes the name and then looks in this spot, if found returns icon */
|
||||
icon *hashtable_search(char *name)
|
||||
{
|
||||
int index = hash(name);
|
||||
int initial_index = index;
|
||||
|
||||
/* Linear probing until an empty slot or the desired item is found */
|
||||
while (hash_table[index] != NULL) {
|
||||
if (strncmp(hash_table[index]->name, name, MAX_NAME) == 0)
|
||||
return hash_table[index];
|
||||
|
||||
index = (index + 1) % TABLE_SIZE; /* Move to the next slot */
|
||||
/* back to same item */
|
||||
if (index == initial_index) break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
21
icons.h
Normal file
21
icons.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#ifndef ICONS_H_
|
||||
#define ICONS_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#define MAX_NAME 30
|
||||
#define TABLE_SIZE 100
|
||||
|
||||
typedef struct {
|
||||
char name[MAX_NAME];
|
||||
wchar_t *icon;
|
||||
} icon;
|
||||
|
||||
unsigned int hash(char *name);
|
||||
void hashtable_init();
|
||||
void hashtable_print();
|
||||
bool hashtable_add(icon *p);
|
||||
icon *hashtable_search(char *name);
|
||||
|
||||
#endif
|
25
util.c
25
util.c
|
@ -1,5 +1,7 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
|
||||
void die(char *reason)
|
||||
{
|
||||
|
@ -11,18 +13,37 @@ void *memalloc(size_t size)
|
|||
{
|
||||
void *ptr = malloc(size);
|
||||
if (!ptr) {
|
||||
fprintf(stderr, "ccc: Error allocating memory\n");
|
||||
perror("ccc");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *estrdup(void *ptr)
|
||||
{
|
||||
void *duped = strdup(ptr);
|
||||
if (!duped) {
|
||||
perror("ccc");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return duped;
|
||||
}
|
||||
|
||||
void *ewcsdup(void *ptr)
|
||||
{
|
||||
void *duped = wcsdup(ptr);
|
||||
if (!duped) {
|
||||
perror("ccc");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return duped;
|
||||
}
|
||||
|
||||
void *rememalloc(void *ptr, size_t size)
|
||||
{
|
||||
ptr = realloc(ptr, size);
|
||||
if (!ptr) {
|
||||
perror("ccc");
|
||||
fprintf(stderr, "ccc: Error allocating memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return ptr;
|
||||
|
|
2
util.h
2
util.h
|
@ -5,6 +5,8 @@
|
|||
|
||||
void die(char *reason);
|
||||
void *memalloc(size_t size);
|
||||
void *estrdup(void *ptr);
|
||||
void *ewcsdup(void *ptr);
|
||||
void *rememalloc(void *ptr, size_t size);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue