#include "text.h" #include "text.xpm" /** * Word Processing Program * Features: * -Real time editing * -Saving * -Loading **/ int winx, winy; int y_offset = 0; // TODO: move to local scope int tab_offset = 0; extern void convert_xpm(char **xpm, unsigned char **buffer); extern unsigned char *QUINN_Icon; WINDOW *menu; WINDOW *editor; WINDOW *linenos; short curs_color(int fg) { switch (7 & fg) { /* RGB */ case 0: /* 000 */ return (COLOR_BLACK); case 1: /* 001 */ return (COLOR_BLUE); case 2: /* 010 */ return (COLOR_GREEN); case 3: /* 011 */ return (COLOR_CYAN); case 4: /* 100 */ return (COLOR_RED); case 5: /* 101 */ return (COLOR_MAGENTA); case 6: /* 110 */ return (COLOR_YELLOW); case 7: /* 111 */ return (COLOR_WHITE); } } void init_colorpairs(void) { int fg, bg; int colorpair; for (bg = 0; bg <= 7; bg++) { for (fg = 0; fg <= 7; fg++) { colorpair = colornum(fg, bg); init_pair(colorpair, curs_color(fg), curs_color(bg)); } } } int colornum(int fg, int bg) { int B, bbb, ffff; B = 1 << 7; bbb = (7 & bg) << 4; ffff = 7 & fg; return (B | bbb | ffff); } void setcolor(int fg, int bg) { /* set the color pair (colornum) and bold/bright (A_BOLD) */ attron(COLOR_PAIR(colornum(fg, bg))); if (is_bold(fg)) { attron(A_BOLD); } } void unsetcolor(int fg, int bg) { /* unset the color pair (colornum) and bold/bright (A_BOLD) */ attroff(COLOR_PAIR(colornum(fg, bg))); if (is_bold(fg)) { attroff(A_BOLD); } } int is_bold(int fg) { /* return the intensity bit */ int i; i = 1 << 3; return (i & fg); } void print_loc(int x, int y) { int oldx, oldy; getyx(stdscr, oldy, oldx); wmove(menu, 0, COLS - 30); wprintw(menu, "X: %d Y: %d Offset: %d", x + 1, y + 1, y_offset); wclrtoeol(menu); move(oldy, oldx); } int main(int argc, char *argv[]) { PAGE page; convert_xpm(text_xpm, &QUINN_Icon); if(argc > 1) { if(file_exists(argv[1])) { load_file(&page, argv[1]); } else { init_page(&page, argv[1], PAGE_SIZE); page.numlines = 1; } } else // initialize { init_page(&page, "untitled.txt", PAGE_SIZE); page.numlines = 1; } /* curses interface */ initscr(); noecho(); keypad(stdscr, 1); start_color(); init_colorpairs(); winx = 0; winy = 0; menu = subwin(stdscr, 2, 80, 23, 0); wbkgd(menu, COLOR_PAIR(colornum(COLOR_BLACK, COLOR_CYAN))); editor = subwin(stdscr, 23, 75, 0, 5); wbkgd(editor, COLOR_PAIR(colornum(COLOR_WHITE, COLOR_BLUE))); linenos = subwin(stdscr, 23, 5, 0, 0); wbkgd(linenos, COLOR_PAIR(colornum(COLOR_BLUE, COLOR_WHITE))); int beg = 0; int i; update_status(&page, ""); print_page(editor, linenos, &page, beg); wmove(editor, winy, winx); while(1) { beg = y_offset; int ch = wgetch(editor); update_status(&page, ""); // default text switch(ch) { case KEY_F(4): if(prompt_yesno("Are you sure you want to quit?")) goto endnc; print_page(editor, linenos, &page, beg); break; case KEY_F(5): save_file(&page); update_status(&page, "Saved!"); break; case KEY_F(6): prompt_string("Save As:", page.filename, NAME_LIMIT); save_file(&page); print_page(editor, linenos, &page, beg); update_status(&page, "Saved!"); break; case KEY_UP: move_up(&page); break; case KEY_DOWN: move_down(&page); break; case KEY_LEFT: move_left(&page); break; case KEY_RIGHT: move_right(&page); break; case KEY_END: move_to_eol(&page); case KEY_DC: case 127: // backspace key... case KEY_BACKSPACE: case '\b': if(strlen(page.text[page.y].line) == 0) { // can only delete blank lines for now remove_line(&page, page.y); move_up(&page); } else if( page.x > 0 ) { remove_char(&page.text[page.y], page.x - 1); // delete move_left(&page); // char behind cursor } print_page(editor, linenos, &page, beg); wmove(editor, winy, winx); page.saved = 0; break; case '\t': for(i = 0; i < TAB_WIDTH; i++) { insert_char(&page.text[page.y], ' ', page.x); print_page(editor, linenos, &page, beg); move_right(&page); } page.saved = 0; break; case '\n': // newline insert_line(&page, page.y + 1); print_page(editor, linenos, &page, beg); move_down(&page); break; default: // all other chars if( isprint(ch) ) { insert_char(&page.text[page.y], ch, page.x); print_page(editor, linenos, &page, beg); move_right(&page); page.saved = 0; } } print_loc(page.x, page.y); wrefresh(menu); wrefresh(editor); } endnc: /* end curses */ endwin(); dest_page(&page); return EXIT_SUCCESS; } // main // prints a message at the bottom of the window void update_status(PAGE *p, char *info) { char title[61]; snprintf(title, 60, "Text: %s%c", p->filename, p->saved == 1 ? ' ' : '*'); PDC_set_title(title); wmove(menu, 0, 0); wprintw(menu, "%s", info); wmove(menu, 1, 0); wprintw(menu, "F4: Quit F5: Save F6: Save As "); wrefresh(menu); } // update_status /* movement */ void move_to_eol(PAGE *p) { while (p->x <= strlen(p->text[p->y].line)) { move_right(p); } } void move_left(PAGE *p) { if(p->x - 1 > 0) { p->x--; winx--; winy = 0; if (p->x > 75) { winx = p->x % 75; winy = p->x / 75; } else { winx = p->x; } for (int j = y_offset; j < p->y; j++) { winy += p->text[j].lines_in_screen; } wmove(editor, winy, winx); } else if (p->x - 1 == 0){ p->x = 0; winx = 0; } } void move_right(PAGE *p) { if(p->x <= strlen(p->text[p->y].line)) { p->x++; winy = 0; if (p->x > 75) { winx = p->x % 75; winy = p->x / 75; } else { winx++; } for (int j = y_offset; j < p->y; j++) { if (strlen(p->text[j].line) > 75) { winy += p->text[j].lines_in_screen; } else { winy++; } } wmove(editor, winy, winx); } } void move_up(PAGE *p) { if (p->y == y_offset && y_offset > 0) { p->y--; y_offset--; if( p->x > strlen(p->text[p->y].line) ) { // cursor adjusts p->x = strlen(p->text[p->y].line); // to smaller lines int oldy = p->x / 75; p->x = strlen(p->text[p->y].line); winx = p->x % 75; winy = winy - (oldy - p->x / 75); } print_page(editor, linenos, p, y_offset); wmove(editor, winy, winx); } else if (p->y > 0) { p->y--; winy -= p->text[p->y].lines_in_screen; if( p->x > strlen(p->text[p->y].line) ) { // cursor adjusts int oldy = p->x / 75; p->x = strlen(p->text[p->y].line); winx = p->x % 75; winy = winy - (oldy - p->x / 75); } wmove(editor, winy, winx); } } void move_down(PAGE *p) { if (p->y < p->numlines - 1) { winy += p->text[p->y].lines_in_screen; p->y++; int new_y_offset = y_offset; while (1) { int count = 0; for (int i = new_y_offset; i <= p->y; i++) { count += p->text[i].lines_in_screen; } if (count > EDITOR_SIZE) { new_y_offset++; } else { break; } } if (new_y_offset != y_offset) { winy = 0; for (int i = new_y_offset;i < p->y; i++) { winy += p->text[i].lines_in_screen; } y_offset = new_y_offset; print_page(editor, linenos, p, y_offset); } if( p->x > strlen(p->text[p->y].line)) { int oldy = p->x / 75; p->x = strlen(p->text[p->y].line); winx = p->x % 75; winy = winy - (oldy - p->x / 75); } wmove(editor, winy, winx); } } /* movement */ int count_lines(FILE *fp) { char ch = '\0'; int count = 0; while((ch = fgetc(fp)) != EOF) if( ch == '\n' ) count++; fseek(fp, 0, SEEK_SET); // go to beginning of file return count; } // count_lines /* saving and loading */ void load_file(PAGE *p, char *filename) { FILE *fp = fopen(filename, "r"); int size = count_lines(fp) * 2; char ch = '\0'; int line; if(size < PAGE_SIZE) size = PAGE_SIZE; init_page(p, filename, size); if(fp == NULL) // file doesn't exist yet. don't bother reading { p->numlines = 1; return; } for(line = 0; line < size && ch != EOF; line++) { ch = fgetc(fp); while(ch != '\n' && ch != EOF) { LINE *currline = &(p->text[line]); if(ch != '\t') { add_char(currline, ch); } else // tab. add 4 spaces instead { int i; for(i = 0; i < TAB_WIDTH; i++) { add_char(currline, ' '); } } ch = fgetc(fp); } p->numlines++; } fclose(fp); } // load_file void save_file(PAGE *p) { FILE *fp = fopen(p->filename, "w"); int line, col; for(line = 0; line < p->numlines; line++) { col = 0; while(p->text[line].line[col] != '\0') { fputc(p->text[line].line[col], fp); col++; } fputc('\n', fp); } fclose(fp); p->saved = 1; } // save_file int file_exists(char *filename) { FILE *fp = fopen(filename, "r"); if(fp != NULL) { fclose(fp); return 1; } return 0; } /* saving and loading */