You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tedflex/program3-4.c

744 lines
22 KiB
C

/*
_______ ________ _____ ________ __ _______ __ __
|__ __| | ______| | _ \ | ______| | | | _____| \ \ / /
| | | |___ | | \ | | |___ | | | |__ \ \/ /
| | | ____| | | | | | ____| | | | ___| / /\ \
| | | |______ | |_ / | | | | |____ | |_____ / / \ \
|_| |________| |_____ / |_| |_______| |_______| /__/ \__\
*/
/* TedFlex - A File Explorer, File Viewer, and Text Editor.
A combination of two of my programs: Ted (Text EDitor) and Flex (FiLe EXplorer).
This is an ncurses tool allows you to browse your files and view/edit them in the same window.
*/
#include "texted.h"
#include "fileman.h"
#include <locale.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#define MAX_LINE_LENGTH 142857 //This is the maximum length of a line that we can read from a file.
#define START_WIN 5 //This is the position on the terminal window from where we will start drawing our ncurses window.
int main(int argc,char** argv) {
int xLen,yLen,mainX,mainY; //values for the x-length and y-length of stdscr (i.e. the terminal window), and the 'main window' inside it.
int fileCountNum; //Number of files in a given directory
int highlighted=0; //Index of the highlighted file
int choice; //stores the user's key press
int fileRow; //Line number that the user is on when they choose to open a file
int fileCol; //ISN'T USED ELSEWHERE IN THE PROGRAM - SHOULD BE REMOVED
int numNewLines; //Number of new-line characters read in a file
int rowCounter; //Number of rows to skip reading in a file, when the user presses Page Down
bool eofFound; //Self-explanatory; is EOF found?
int colorScheme; //stores the value of the color scheme - changes when user hits Ctrl-D
// int colCounter; //ISN'T USED ELSEWHERE IN THE PROGRAM - SHOULD BE REMOVED
char tempChar; //Holds the 'current' character while reading from a file.
int numCharsToPrint; //Weird naming - should be renamed to 'numLinesToPrint' - Number of lines to print in the file explorer.
int numDowns=0; //Stores the number of times the user has pressed the Down Arrow / Page Down
bool hasExited; //Has the user exited from TextView mode?
bool hasChosen; //Has the user chosen to edit or view a file?
char editOrView; //Did the user choose to edit or view a file?
char line[MAX_LINE_LENGTH]; //Holds a line in a text file when the user chooses to view a file
FILE* ptrFile; //Used to open a file to read from
bool hasCopied;
FILE* tempFileCopy;
char* curDir;
char* fileCopied;
setlocale(LC_CTYPE,"");
initscr(); //NCURSES - Initializes screen to begin doing stuff in ncurses
getmaxyx(stdscr,yLen,xLen); /*NCURSES - Gets the maximum x- and y-length of stdscr, which represents the terminal/TTY window
that is running the program. Used to make calculations for the 'main' window based on the size. */
curs_set(0); //NCURSES - Makes the cursor (the white rectangle) invisible.
noecho(); //NCURSES - prevents echoing of user choices.
cbreak(); //NCURSES - Similar to Raw Mode, key presses are registered immediately after they are typed.
if (has_colors() == TRUE) {
start_color(); //NCURSES - Initialize color - TODO - Disable colors if color support is not found.
}
/* NCURSES - The next block of code creates colors and color pairs for our window. */
init_color(COLOR_CYAN,500,500,500);
init_color(COLOR_MAGENTA,150,150,150);
init_color(COLOR_YELLOW,650,650,650);
init_color(COLOR_GREEN,40,291,177);
init_pair(0,COLOR_WHITE,COLOR_BLACK);
init_pair(1,COLOR_BLACK,COLOR_CYAN);
init_pair(2,COLOR_WHITE,COLOR_MAGENTA);
init_pair(4,COLOR_GREEN,COLOR_CYAN);
init_pair(6,COLOR_WHITE,COLOR_BLUE);
init_pair(8,COLOR_BLACK,COLOR_CYAN);
init_pair(10,COLOR_BLACK,COLOR_BLACK);
init_pair(11,COLOR_BLACK,COLOR_YELLOW);
init_pair(12,COLOR_WHITE,COLOR_BLACK);
/* BLOCK ENDS HERE */
colorScheme=1; // Default value for the color scheme.
rowCounter = 1; // Set this to zero, because we don't want to skip anything
// colCounter = 1;
WINDOW* mainwin = newwin(yLen-7,xLen-9,START_WIN,START_WIN); /*NCURSES - This creates our 'main' window, that will be
used to display ~99% of the actual content.*/
wbkgd(stdscr,COLOR_PAIR(6)); //NCURSES - Sets the default foreground and background color for stdscr.
wbkgd(mainwin,COLOR_PAIR(8)); //NCURSES - Sets the default foreground and background color for mainwin.
keypad(mainwin,true); //NCURSES - Allows the use of 'keypad' values: Arrow Keys, Function Keys, etc.
getmaxyx(mainwin,mainY,mainX); //NCURSES - Gets the maximum x- and y-values of the mainwin, and stores them in the appropriate variables.
wattron(stdscr,COLOR_PAIR(10)); //NCURSES - Sets the color for the 'shadows' in the following block of code.
/* NCURSES - The following block of code adds 'shadows' to the mainwin. */
for (int i=START_WIN+1;i<mainY+START_WIN;i++) {
mvwaddch(stdscr,i,mainX+START_WIN,32);
mvwaddch(stdscr,i,mainX+START_WIN+1,32);
}
mvwaddch(stdscr,mainY+START_WIN,mainX+START_WIN+1,32); //Fills in an empty 'shadow' spot that was missed by the previous for loop.
for (int i=START_WIN+1;i<=mainX+START_WIN;i++) {
mvwaddch(stdscr,mainY+START_WIN,i,32);
}
wattroff(stdscr,COLOR_PAIR(10));
/* BLOCK ENDS HERE */
char* dir = malloc(sizeof(char) * FILE_ARR_SIZE); //Char array for storing the name of the current file/directory
char* tempDir = malloc(sizeof(char) * FILE_ARR_SIZE); //Char array for temporarily storing the name of the highlighted file/directory
if (argv[1] == NULL) { //If no argument is provided for file path...
dir[0]='/'; //Use root as a default file path
dir[1]='\0';
} else { //If there is a default path provided...
dir = argv[1]; //Use that as the default path
if (dir[0] == '.' || dir[0] != '/') {
// DONE - ACCOUNT FOR THE POSSIBILITY THAT USER DIDN'T USE ./ BEFORE FILE NAME
curDir = malloc(sizeof(char) * FILE_ARR_SIZE);
getcwd(curDir,FILE_ARR_SIZE);
int i=strlen(curDir);
int a;
if (dir[0] != '.') {
a = 0;
*(curDir+i) = '/';
i++;
} else {
a = 1;
}
while (*(dir+a) != '\0') {
// strcat(curDir,*(dir+i));
*(curDir+i) = *(dir+a);
i++;
a++;
}
for (int i=0;i<FILE_ARR_SIZE;i++) {
*(dir+i) = '\0';
}
strcpy(dir,curDir);
}
if (!(isFile(dir))) {
addSlash(dir); //If it doesn't have a forward slash at the end, add one
}
}
fileCountNum = findFileCount(dir); //Set the number of files in the directory using a function
char** fileList = calloc(FILE_ARR_SIZE,1000); //Allocating memory for the fileList: I used calloc because the list is a double-pointer
for (int i=0;i<FILE_ARR_SIZE;i++) { //Initializing the values of the list
fileList[i] = NULL;
}
/*
Adds <mainY+5> files in the directory 'dir' to the fileList. The reason behind the limit
in the number of files added is that, with large directories (e.g. /lib), I encountered a
weird bug where, after a certain number of files, the list corrupts itself. My solution
was to add a limited number of files at a given time, and change those files depending on
where the user is in the file list.
*/
if (!(isFile(dir))) {
addFiles(dir,fileList,0,mainY+5);
}
int firstItemIndex = 0; //Initializes the index of the first item in the list
/* This block prints some helpful information regarding the controls to navigte within the program */
wmove(stdscr,1,0);
wclrtoeol(stdscr);
mvwaddstr(stdscr,1,17,"<Up Arrow> - Move Up | <Down Arrow> - Move Down | <Left Arrow> - Go Back | <Right Arrow>/Enter - Enter Directory/Open File\n");
wmove(stdscr,2,0);
wclrtoeol(stdscr);
mvwaddstr(stdscr,2,40,"<Page Up> - Scroll Up | <Page Down> - Scroll Down\n");
/* BlOCK ENDS HERE */
while (true) {
// getmaxyx(stdscr,yLen,xLen);
// getmaxyx(mainwin,mainY,mainX);
wmove(stdscr,3,0);
wclrtoeol(stdscr);
if (highlighted == firstItemIndex+mainY) {
firstItemIndex++;
refresh();
wrefresh(mainwin);
}
if (isFile(dir)) {
if (hasChosen == false) {
mvwaddstr(mainwin,5,5,"Do you want to (e)dit or (v)iew this file? ");
editOrView='$';
if (!(fileExists(dir))) {
while (editOrView != 'e') {
editOrView = wgetch(mainwin);
}
}
else {
while (editOrView != 'e' && editOrView != 'v') {
editOrView = wgetch(mainwin);
}
}
if (editOrView == 'e') {
curs_set(2);
run(dir);
curs_set(0);
wmove(stdscr,1,0);
wclrtoeol(stdscr);
wmove(stdscr,2,0);
wclrtoeol(stdscr);
hasExited = true;
}
}
if (editOrView == 'v' /*&& hasChosen == false*/) {
wclear(mainwin);
refresh();
wrefresh(mainwin);
mvwprintw(stdscr,3,0,"Line %d",rowCounter);
ptrFile = fopen(dir,"r");
rewind(ptrFile);
fileRow=1;
for (int i=0;i<(rowCounter-1);i++) {
fgets(line,MAX_LINE_LENGTH,ptrFile);
}
while(fgets(line, MAX_LINE_LENGTH, ptrFile)) {
mvwprintw(mainwin,fileRow,1,"%s",line);
fileRow++;
}
fclose(ptrFile);
refresh();
wrefresh(mainwin);
hasChosen=true;
}
} else {
if (mainY < fileCountNum) {
if (mainY < fileCountNum-firstItemIndex){
numCharsToPrint = mainY;
} else {
numCharsToPrint = mainY-1;
}
} else {
numCharsToPrint = fileCountNum;
}
for (int i=0,a=0;i<numCharsToPrint;i++,a++) {
for (int i=0;i<FILE_ARR_SIZE;i++){
*(tempDir+i) = '\0';
}
if (i == highlighted) {
wattron(mainwin,A_REVERSE);
}
strcpy(tempDir,dir);
strcat(tempDir, (char *)(*(fileList+i)));
strcat(tempDir,"\0");
if (isFile(tempDir)) {
wattron(mainwin,COLOR_PAIR(4));
}
mvwprintw(mainwin,a+1,5,"%s",*(i+fileList));
refresh();
wrefresh(mainwin);
wattroff(mainwin,COLOR_PAIR(4));
wattroff(mainwin,A_REVERSE);
}
refresh();
wrefresh(mainwin);
}
mvwprintw(stdscr,0,1,"%s\n",dir);
refresh();
wrefresh(mainwin);
//break;
if (hasExited) {
removeDirFromPath(dir);
highlighted=0;
move(0,0);
wclrtoeol(stdscr);
refresh();
wrefresh(mainwin);
mvwprintw(stdscr,0,1,"%s",dir);
fileCountNum = findFileCount(dir);
addFiles(dir,(char **)fileList,0,mainY+5);
firstItemIndex=0;
highlighted=0;
wclear(mainwin);
refresh();
wrefresh(mainwin);
hasChosen=false;
rowCounter=1;
hasExited=false;
wmove(stdscr,1,0);
wclrtoeol(stdscr);
mvwaddstr(stdscr,1,17,"<Up Arrow> - Move Up | <Down Arrow> - Move Down | <Left Arrow> - Go Back | <Right Arrow>/Enter - Enter Directory/Open File\n");
wmove(stdscr,2,0);
wclrtoeol(stdscr);
mvwaddstr(stdscr,2,40,"<Page Up> - Scroll Up | <Page Down> - Scroll Down");
} else {
choice=wgetch(mainwin);
switch (choice) {
case (('d' & 0x1f)):
if (colorScheme == 0) {
wbkgd(stdscr,COLOR_PAIR(6));
init_color(COLOR_GREEN,40,291,177);
init_pair(4,COLOR_GREEN,COLOR_CYAN);
wbkgd(mainwin,COLOR_PAIR(8));
colorScheme++;
refresh();
wrefresh(mainwin);
break;
} else if (colorScheme == 1){
wbkgd(stdscr,COLOR_PAIR(2));
init_pair(4,COLOR_GREEN,COLOR_BLACK);
wbkgd(mainwin,COLOR_PAIR(0));
colorScheme++;
refresh();
wrefresh(mainwin);
break;
} else if (colorScheme == 2) {
wbkgd(stdscr,COLOR_PAIR(12));
init_color(COLOR_GREEN,40,438,7);
init_pair(4,COLOR_GREEN,COLOR_YELLOW);
wbkgd(mainwin,COLOR_PAIR(11));
colorScheme=0;
refresh();
wrefresh(mainwin);
break;
}
break;
case KEY_UP:
if (isFile(dir)) {
if (rowCounter <= 1) {
rowCounter = 1;
break;
}
rowCounter--;
wclear(mainwin);
refresh();
wrefresh(mainwin);
break;
}
highlighted--;
if (highlighted == -1) {
highlighted=0;
}
if (highlighted < 1) {
if (firstItemIndex > 0) {
firstItemIndex--;
highlighted++;
addFiles(dir,(char **)fileList,firstItemIndex,mainY+5);
numDowns--;
if (highlighted > mainY-3)
highlighted=mainY-3;
wclear(mainwin);
refresh();
wrefresh(mainwin);
}
}
break;
case KEY_DOWN:
if (isFile(dir)) {
numNewLines = 0;
eofFound = false;
ptrFile = fopen(dir,"r");
for (int i=0;i<(rowCounter-1);i++) {
fgets(line,MAX_LINE_LENGTH,ptrFile);
}
while (true) {
tempChar = fgetc(ptrFile);
if (tempChar == '\n') {
numNewLines++;
}
if (tempChar == EOF) {
eofFound = true;
break;
}
if (numNewLines >= (mainY-5)) {
break;
}
}
if (eofFound) {
break;
}
fclose(ptrFile);
rowCounter++;
wclear(mainwin);
refresh();
wrefresh(mainwin);
break;
}
if (highlighted > mainY-3) {
break;
}
if (fileCountNum < mainY-1 && highlighted+numDowns+1 >= fileCountNum) {
break;
}
highlighted++;
/*
if (highlighted+numDowns >= fileCountNum) {
if (numCharsToPrint-1 < mainY-2) {
highlighted = numCharsToPrint-1;
} else {
highlighted = mainY-2;
}
break;
}
*/
/*
if (highlighted > mainY-2) {
if (firstItemIndex < fileCountNum-1) {
firstItemIndex++;
highlighted--;
numDowns++;
addFiles(dir,(char **)fileList,firstItemIndex,mainY+5);
wclear(mainwin);
refresh();
wrefresh(mainwin);
}
}
*/
break;
case KEY_NPAGE:
if (isFile(dir)) {
numNewLines = 0;
eofFound = false;
ptrFile = fopen(dir,"r");
for (int i=0;i<(rowCounter-1);i++) {
fgets(line,MAX_LINE_LENGTH,ptrFile);
}
while (true) {
tempChar = fgetc(ptrFile);
if (tempChar == '\n') {
numNewLines++;
}
if (tempChar == EOF) {
eofFound = true;
break;
}
if (numNewLines >= (mainY-5)) {
break;
}
}
if (eofFound) {
break;
}
fclose(ptrFile);
rowCounter += mainY-5;
wclear(mainwin);
refresh();
wrefresh(mainwin);
break;
}
if (strcmp("linux",getenv("TERM")) == 0) {
mainY+=1;
}
if (fileCountNum - firstItemIndex > mainY-3) {
firstItemIndex++;
numDowns++;
addFiles(dir,(char **)fileList,firstItemIndex,mainY+5);
wclear(mainwin);
refresh();
wrefresh(mainwin);
}
if (strcmp("linux",getenv("TERM")) == 0) {
mainY-=1;
}
break;
case KEY_PPAGE:
if (isFile(dir)) {
if (rowCounter-mainY+5 <= 1) {
rowCounter = 1;
break;
}
rowCounter -= mainY+5;
wclear(mainwin);
refresh();
wrefresh(mainwin);
break;
}
if (firstItemIndex > 0) {
firstItemIndex--;
addFiles(dir,(char **)fileList,firstItemIndex,mainY+5);
if (highlighted > firstItemIndex+mainY-3)
highlighted=firstItemIndex+mainY-3;
wclear(mainwin);
refresh();
wrefresh(mainwin);
}
break;
/* *************************************************************************************** */
// STUFF TO IMPLEMENT
//
// 1. Show the content of files in another ncurses window
//////////// 2. Use Arrow Keys to scroll in file (line-by-line)
//////////// 3. Define symbolic constants for commonly used values
/* *************************************************************************************** */
case KEY_RIGHT:
case 10:
if (!(isFile(dir))) {
strcat(dir,*(fileList+highlighted));
if (!(isFile(dir))) {
strcat(dir,"/");
}
move(0,1);
printw("%s",dir);
fileCountNum = findFileCount(dir);
firstItemIndex=0;
addFiles(dir,(char **)fileList,firstItemIndex,mainY+5);
numDowns=0;
highlighted=0;
wclear(mainwin);
refresh();
wrefresh(mainwin);
}
break;
case KEY_LEFT:
removeDirFromPath(dir);
highlighted=0;
move(0,0);
wclrtoeol(stdscr);
refresh();
wrefresh(mainwin);
mvwprintw(stdscr,0,1,"%s",dir);
fileCountNum = findFileCount(dir);
addFiles(dir,(char **)fileList,0,mainY+5);
numDowns=0;
firstItemIndex=0;
highlighted=0;
wclear(mainwin);
refresh();
wrefresh(mainwin);
hasChosen=false;
rowCounter=1;
break;
case ('n' & 0x1f):
// WINDOW* newFileWin = newwin(6,50,mainY/2-3,mainX/2-25);
// mvwaddstr(newFileWin,1,1,"Enter the name of the file you wish to create");
char* newFileLoc = getSaveLoc(mainX,mainY,"$$$");
char* newSaveLoc = malloc(sizeof(char) * (strlen(dir) + strlen(newFileLoc)) + 1);
strcpy(newSaveLoc,dir);
// strcat(newSaveLoc,"/");
strcat(newSaveLoc,newFileLoc);
curs_set(2);
run(newSaveLoc);
curs_set(0);
refresh();
wmove(mainwin,2,0);
wclrtoeol(mainwin);
wrefresh(mainwin);
break;
case ('p' & 0x1f):
char* tempFileDir = malloc(sizeof(char) * MAX_LINE_LENGTH);
strcpy(tempFileDir,dir);
// strcat(tempFileDir,"/");
strcat(tempFileDir,fileList[highlighted]);
fileCopied = malloc(sizeof(char) * strlen(fileList[highlighted]) * 2);
strcpy(fileCopied,fileList[highlighted]);
ptrFile = fopen(tempFileDir,"r");
tempFileCopy = fopen("/tmp/tedflexTempFile","w");
char tempChar = 'a';
while(!feof(ptrFile)) {
fscanf(ptrFile,"%c",&tempChar);
if (!feof(ptrFile)) {
fprintf(tempFileCopy,"%c",tempChar);
}
}
hasCopied = true;
fclose(tempFileCopy);
fclose(ptrFile);
// rewind(ptrFile);
addFiles(dir,(char **)fileList,0,mainY+5);
wclear(mainwin);
refresh();
wrefresh(mainwin);
break;
case ('v' & 0x1f):
if (hasCopied) {
char* tempFileDir = malloc(sizeof(char) * MAX_LINE_LENGTH);
strcpy(tempFileDir,dir);
tempFileCopy = fopen("/tmp/tedflexTempFile","r");
char* tempFileCopied = malloc((strlen(tempFileDir)+strlen(fileCopied))*2);
strcpy(tempFileCopied,tempFileDir);
strcat(tempFileCopied,fileCopied);
int fd = open(tempFileCopied,O_CREAT | O_WRONLY | O_EXCL, S_IRUSR | S_IWUSR);
if (errno != EEXIST) {
strcat(tempFileDir,fileCopied);
ptrFile = fopen(tempFileDir,"w");
char tempChar = 'a';
while(!feof(tempFileCopy)) {
fscanf(tempFileCopy,"%c",&tempChar);
if (!feof(tempFileCopy)) {
fprintf(ptrFile,"%c",tempChar);
}
}
hasCopied=0;
free(fileCopied);
}
}
fileCountNum = findFileCount(dir);
addFiles(dir,(char **)fileList,0,mainY+5);
wclear(mainwin);
refresh();
wrefresh(mainwin);
default:
break;
}
}
if (choice == 113){
endwin();
break;
}
}
return 0;
}