/* _______ ________ _____ ________ __ _______ __ __ |__ __| | ______| | _ \ | ______| | | | _____| \ \ / / | | | |___ | | \ | | |___ | | | |__ \ \/ / | | | ____| | | | | | ____| | | | ___| / /\ \ | | | |______ | |_ / | | | | |____ | |_____ / / \ \ |_| |________| |_____ / |_| |_______| |_______| /__/ \__\ */ /* 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 #include #include #include #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) { putenv("PDC_COLS=1000"); putenv("PDC_LINES=1000"); 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 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," - Move Up | - Move Down | - Go Back | /Enter - Enter Directory/Open File\n"); wmove(stdscr,2,0); wclrtoeol(stdscr); mvwaddstr(stdscr,2,40," - Scroll Up | - 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 - Move Up | - Move Down | - Go Back | /Enter - Enter Directory/Open File\n"); wmove(stdscr,2,0); wclrtoeol(stdscr); mvwaddstr(stdscr,2,40," - Scroll Up | - 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); ; //Dummy statement - Apparently you can't declare a variable in the first line in a case statment in C without curly braces surrounding the case 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): ; //Dummy statement - Apparently you can't declare a variable in the first line in a case statment in C without curly braces surrounding the case 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; }