Thumbnail

rani/cscroll.git

Clone URL: https://git.buni.party/rani/cscroll.git

commit 703f91771fff1f77bae318b8a521a22f71f81e21 Author: Raniconduh <clagv.randomgames@gmail.com> Date: Tue Mar 02 20:31:06 2021 +0000 Added scroll.c diff --git a/scroll.c b/scroll.c new file mode 100644 index 0000000..9cb8cc9 --- /dev/null +++ b/scroll.c @@ -00 +1312 @@ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ncurses.h> +#include <dirent.h> +#include <signal.h> + + +#define PWD "PWD" + +#define BLUE 1 +#define HBLUE 2 +#define CYAN 3 +#define HCYAN 4 +#define GREEN 5 +#define HGREEN 6 +#define MAGENTA 7 +#define HMAGENTA 8 +#define YELLOW 9 +#define HYELLOW 10 +#define RED 11 +#define HRED 12 +#define WHITE 13 +#define HWHITE 14 + +void help(void); +void listitems(void); +void sighandler(int); + +bool isdir(const char *); +bool isfifo(const char *); +bool isblock(const char *); +bool islink(const char *); +bool isunknown(const char *); +bool isreg(const char *); + +void print_file(char *, bool); + +void cdback(); +void enter(char *); + +// current working directory +char * cwd; + +// array of files in directory +char ** dirContents; +// number of files in directory +size_t dirCount = 0; + + +int main ( int argc, char ** argv ) { + // cwd is pwd if no args given + if (argc < 2) { + // this is a safer way of storing the home dir + cwd = malloc(sizeof(char) * (strlen(getenv(PWD)) + 3)); + strcpy(cwd, getenv(PWD)); + strcat(cwd, "/"); // append the '\0' with strcat + //help menu + } else if (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")) { + help(); + exit(0); + } else { + cwd = malloc(sizeof(char) * (strlen(argv[1]) + 3)); + strcpy(cwd, argv[1]); + + if (cwd[strlen(cwd) - 1] != '/') { + strcat(cwd, "/"); + } + + } + + initscr(); + // this is here so that endwin() is called after init + signal(SIGINT, sighandler); + signal(SIGSEGV, sighandler); + + curs_set(0); + + // init color pairs + start_color(); + // odd pairs are : color fg on black bg + // even pairs are: black fg on color bg + init_pair(BLUE, COLOR_BLUE, COLOR_BLACK); // blue fg on black bg + init_pair(HBLUE, COLOR_BLACK, COLOR_BLUE); // black fg on blue bg + + init_pair(CYAN, COLOR_CYAN, COLOR_BLACK); // cyan fg on black bg + init_pair(HCYAN, COLOR_BLACK, COLOR_CYAN); // black fg on cyan bg + + init_pair(GREEN, COLOR_GREEN, COLOR_BLACK); // green fg on black bg + init_pair(HGREEN, COLOR_BLACK, COLOR_GREEN); // black fg on green bg + + init_pair(MAGENTA, COLOR_MAGENTA, COLOR_BLACK);// magenta fg on black bg + init_pair(HMAGENTA, COLOR_BLACK, COLOR_MAGENTA);// black fg on magenta bg + + init_pair(YELLOW, COLOR_YELLOW, COLOR_BLACK); // yellow fg on black bg + init_pair(HYELLOW, COLOR_BLACK, COLOR_YELLOW);// black fg on yellow bg + + init_pair(RED, COLOR_RED, COLOR_BLACK); // red fg on black bg + init_pair(HRED, COLOR_BLACK, COLOR_RED); // black fg on red bg + + init_pair(WHITE, COLOR_WHITE, COLOR_BLACK); // white fg on black gb + init_pair(HWHITE, COLOR_BLACK, COLOR_WHITE); // black fg on white bg + + dirContents = malloc(sizeof(char *) + 1); // allocate something to realloc + dirContents[0] = malloc(1); // allocate something to free + + size_t cursor = 0; + + listitems(); // preliminary list to save on disk io + // driver loop -- ig bools are defined in nh + while (true) { + erase(); + + printw("\n%s\n\n", cwd); // print path at top + + for (size_t i = 0; i < dirCount; i++) { + if (cursor == i) + print_file(dirContents[i], true); + else + print_file(dirContents[i], false); + } + + attron(COLOR_PAIR(0)); + printw("\n%lu/%lu\n", cursor + 1, dirCount); + refresh(); + + char c = getch(); + if (c == 'q') goto done; // 'q' command for quit + if (c == 'j') cursor += 1 ? cursor < dirCount - 1 : 0; // down key + else if (c == 'k') cursor -= 1 ? cursor > 0 : 0; // up key + else if (c == 'h') { + cdback(); + listitems(); + cursor = 0; + } + else if (c == 'l') { + enter(dirContents[cursor]); + listitems(); + cursor = 0; + } + + refresh(); + } + + done: + endwin(); + + free(dirContents); + free(cwd); + + return 0; +} + + +// no idea how this works but it does +static int cmp(const void * a, const void * b) { + return strcmp(*(const char**)a, *(const char**)b); +} + +void listitems(void) { + struct dirent * dirItem; + DIR * dir = opendir(cwd); + + // free every single index in the list + // this will prevent future memory leaks + for (long long i = dirCount; i >= 0; i--) { + free(dirContents[dirCount]); + } + + dirCount = 0; + while ((dirItem = readdir(dir)) != NULL) { + // do not append '.' and '..' directories + if (!strcmp(dirItem->d_name, "..") || !strcmp(dirItem->d_name, ".")) { + continue; + } + size_t namelen = strlen(dirItem->d_name); + // allocate memory to store all the pointers + dirContents = realloc(dirContents, sizeof(char*) * (dirCount + 2)); + // allocate memory for each index to store the file name + dirContents[dirCount] = malloc(sizeof(char) * (namelen + 3)); + + strcpy(dirContents[dirCount], dirItem->d_name); + + + // may not work on all machines so this needs to be moved + // to something more universal like stat + switch (dirItem->d_type) { + case DT_DIR: // is a dir + strcat(dirContents[dirCount], "/"); + break; + case DT_FIFO: // is a fifo + strcat(dirContents[dirCount], "|"); + break; + case DT_LNK: // is a symbolic link + strcat(dirContents[dirCount], "@"); + break; + case DT_BLK: // is a block device + strcat(dirContents[dirCount], "#"); + break; + case DT_UNKNOWN: // idk what this file is + strcat(dirContents[dirCount], "?"); + break; + } + + dirCount++; + } + + closedir(dir); + + // sort the files + qsort(dirContents, dirCount, sizeof(char*), cmp); +} + + +void enter(char * dir) { + if (!isdir(dir)) return; + // allocate enough memory to append name of dir + cwd = realloc(cwd, sizeof(char) * (strlen(cwd) + strlen(dir) + 2)); + // since dir will already end with '/', + // it is not necessary to append it to end of cwd + strcat(cwd, dir); +} + + +void cdback() { + if (!strcmp(cwd, "/") || !strcmp(cwd, "//")) return; + size_t clen = strlen(cwd); + cwd[--clen] = '\0'; + while (cwd[--clen] != '/') cwd[clen] = '\0'; + cwd = realloc(cwd, sizeof(char) * (clen + 2)); +} + + +bool isdir(const char * fname) { + return true ? fname[strlen(fname) - 1] == '/' : false; +} + +bool isfifo(const char * fname) { + return true ? fname[strlen(fname) - 1] == '|' : false; +} + +bool isblock(const char * fname) { + return true ? fname[strlen(fname) - 1] == '#' : false; +} + +bool islink(const char * fname) { + return true ? fname[strlen(fname) - 1] == '@' : false; +} + +bool isunknown(const char * fname) { + return true ? fname[strlen(fname) - 1] == '?' : false; +} + +bool isreg(const char * fname) { + if (isdir(fname) || + isfifo(fname) || + isblock(fname)|| + islink(fname) || + isunknown(fname)) return true; + else return false; +} + + +void print_file(char * fname, bool highlight) { + bool c = false; // c flag :) + unsigned int cp; + if (highlight) { + if (isdir(fname)) cp = HBLUE; + else if (isfifo(fname) || isblock(fname)) cp = HYELLOW; + else if (islink(fname)) cp = HCYAN; + else if (isunknown(fname)) cp = HRED; + else cp = HWHITE; + } else { + if (isdir(fname)) cp = BLUE; + else if (isfifo(fname) || isblock(fname)) cp = YELLOW; + else if (islink(fname)) cp = CYAN; + else if (isunknown(fname)) cp = RED; + else cp = WHITE; + } + + size_t flen = strlen(fname); + + attron(COLOR_PAIR(cp)); + if (cp == WHITE || cp == HWHITE) printw("%s\n", fname); + else { + c = true; // set c flag :) + printw("%.*s", flen - 1, fname); // print up to the last character + } + attroff(COLOR_PAIR(cp)); + if (c) printw("%c\n", fname[flen - 1]); +} + + +void help(void) { + printf("cscroll\n" + "Options:\n" + " -h, --help\t\tShow this screen and exit\n"); +} + + +void sighandler(int signo) { + if (signo == SIGINT) { + endwin(); + puts("Exited on SIGINT"); + exit(1); + } else if (signo == SIGSEGV) { + endwin(); + puts("Segmentation Fault"); + exit(2); + } +} +