/* ----------------------- editor.c ---------------------- */ #include #include #include #include #include #include "twindow.h" #include "keys.h" #define TRUE 1 #define FALSE 0 #define TAB 4 #define NEXTTAB (TAB-(x%TAB)) #define LASTTAB (((wwd-1)/TAB)*TAB) #define PREVTAB (((x-1)%TAB)+1) #define curr(x,y) (bfptr+(y)*wwd+(x)) #define lineno(y) ((int)(bfptr-topptr)/wwd+(y)) extern int VSG; int last_x, last_y; static int wht; static int wwd; static int wsz; static char *topptr; static char *bfptr; static char *lstptr; static int lines; static char *endptr; static int blkbeg; static int blkend; static int inserting; static WINDOW *wnd; static int do_display_text = 1; /*page*/ /* ---------- local function prototypes ----------- */ void erase_buffer(int *x, int *y); int lastword(int x, int y); void last_char(int *x, int *y); void test_para(int x, int y); int trailing_spaces(int y); int first_wordlen(int y); void paraform(int x, int y); int blankline(int line); void delete_word(int x, int y); void delete_line(int y); void delete_block(void); void copy_block(int y); void move_block(int y); void mvblock(int y, int moving); void findlast(void); void find_end(int *x, int *y); void carrtn(int *x, int *y, int insert); void backspace(int *x, int *y); void fore_word(int *x, int *y, char *bf); int spaceup(int *x, int *y, char **bf); void back_word(int *x, int *y, char *bf); int spacedn(int *x, int *y, char **bf); void forward(int *x, int *y); int downward(int *y); void upward(int *y); void display_text(void); void disp_line(int y); void insert_line(void); /*page*/ /* ----- Process text entry for a window. ---- */ void text_editor(WINDOW *wnd1, char *bf, unsigned bsize) { char *b, *buff; int depart = FALSE, i, c; int x, y, svx, svlw, tx, tabctr = 0; wnd = wnd1; wht = HEIGHT-2; wwd = WIDTH-2; wsz = wwd * wht; topptr = bfptr = bf; lines = bsize / wwd; endptr = bf + wwd * lines; blkbeg = 0; blkend = 0; inserting = FALSE; x = 0; y = 0; display_text(); /* --------- read in text from the keyboard ---------- */ findlast(); while (TRUE) { last_x = COL + 1 + x; last_y = ROW + 1 + y; cursor(last_x, last_y); buff = curr(x, y); if (tabctr) { --tabctr; c = ' '; } else { c = get_char(); clear_message(); } switch (c) { case '\r': carrtn(&x, &y, inserting); break; case DN: downward(&y); break; case PGUP: y = 0; for (i = 0; i < wht; i++) upward(&y); break; case PGDN: y = HEIGHT - 2; for (i = 0; i < wht; i++) downward(&y); y = 0; break; case '\t': if (x + NEXTTAB < wwd) { if (inserting) tabctr = NEXTTAB; else x += NEXTTAB; } else carrtn(&x, &y, inserting); break; case SHIFT_HT: if (x < TAB) { upward(&y); x = LASTTAB; } else x -= PREVTAB; break; case CTRL_FWD: fore_word(&x, &y, buff); break; case CTRL_BS: back_word(&x, &y, buff); break; case CTRL_B: y = wht - 1; break; case CTRL_T: y = 0; break; case CTRL_HOME: x = y = 0; bfptr = topptr; display_text(); break; case HOME: x = 0; break; case CTRL_END: find_end(&x, &y); display_text(); break; case END: last_char(&x, &y); break; case UP: upward(&y); break; case F2: case ESC: depart = TRUE; break; case '\b': case BS: if (curr(x, y) == topptr) break; backspace(&x, &y); if (x == wwd - 1) last_char(&x, &y); if (c == BS) break; buff = curr(x, y); case DEL: movmem(buff+1, buff, wwd-1-x); *(buff+wwd-1-x) = ' '; disp_line(y); test_para(x+1, y); break; case ALT_D: delete_line(y); break; case CTRL_D:delete_word(x, y); test_para(x, y); break; case INS: inserting ^= TRUE; insert_line(); break; case F3: erase_buffer(&x, &y); break; case F4: paraform(0, y); break; case F5: blkbeg = lineno(y) + 1; if (blkbeg > blkend) blkend = lines; display_text(); break; case F6: blkend = lineno(y) + 1; if (blkend < blkbeg) blkbeg = 1; display_text(); break; case F7: move_block(y); break; case F8: copy_block(y); break; case F9: delete_block(); break; case F10: blkbeg = blkend = 0; display_text(); break; case FWD: forward(&x, &y); break; default: if (!isprint(c)) break; if (curr(x, y) == endptr-1 || (lineno(y)+1 >= lines && inserting && *curr(wwd-2, y) != ' ')) { error_message(" End of Buffer "); break; } if (inserting) { buff = curr(x, y); movmem(buff, buff + 1, wwd-1-x); } buff = curr(x, y); if (buff < endptr) { if (buff >= lstptr) lstptr = buff + 1; *buff = c; disp_line(y); } buff = curr(wwd-1, y); if (endptr && *buff != ' ') { for (b = buff+1; b < endptr; b++) if (*b==' ' && *(b + 1)==' ') break; movmem(buff+1, buff+2, b-buff-1); *(buff+1) = ' '; svx = x; svlw = lastword(x, y); x = wwd-1; if (*(buff-1) != ' ') back_word(&x, &y, buff); tx = x; carrtn(&x, &y, TRUE); if (svlw) x = svx-tx; else { x = svx; --y; } } forward(&x, &y); break; } if (depart) break; } inserting = FALSE; insert_line(); } /*page*/ /* -------- erase the buffer --------------- */ static void erase_buffer(int *x, int *y) { int c = 0; WINDOW *sur; sur = establish_window(28, 11, 4, 24); set_colors(sur, ALL, RED, YELLOW, BRIGHT); display_window(sur); wprintf(sur, " Erase text window\n Are you sure? (y/n)"); while (c != 'y' && c != 'n') { c = get_char(); c = tolower(c); if (c == 'y') { lstptr = bfptr = topptr; *x = *y = 0; setmem(bfptr, lines * wwd, ' '); blkbeg = blkend = 0; display_text(); } } delete_window(sur); } /* ----- see if a word is the last word on the line ------ */ static int lastword(int x, int y) { char *bf = curr(x, y); while (x++ < wwd-1) if (*bf++ == ' ') return 0; return 1; } /*page*/ /* --- go to last displayable character on the line --- */ static void last_char(int *x, int *y) { char *bf; *x = wwd-1; bf = curr(0, *y); while (*x && *(bf + *x) == ' ') --(*x); if (*x && *x < wwd - 1) (*x)++; } /* ----- test to see if paragraph should be reformed ----- */ static void test_para(int x, int y) { int ts, fw; if (!scroll_lock() && y < lines) { ts = trailing_spaces(y); fw = first_wordlen(y+1); if (fw && ts > fw) paraform(x, y); } } /* ---- count the trailing spaces on a line ----- */ static int trailing_spaces(int y) { int x = wwd-1, ct = 0; char *bf = curr(0, y); while (x >= 0) { if (*(bf + x) != ' ') break; --x; ct++; } return ct; } /* ----- count the length of the first word on a line --- */ static int first_wordlen(int y) { int ct = 0, x = 0; char *bf = curr(0, y); while (x < wwd-1 && *(bf+x) == ' ') x++; while (x+ct < wwd-1 && *(bf+x+ct) != ' ') ct++; return ct; } /* ------------ form a paragraph -------------- */ static void paraform(int x, int y) { char *cp1, *cp2, *cpend, *svcp; int x1; if (blankline(lineno(y)+1)) return; if (!blkbeg) { blkbeg = blkend = lineno(y)+1; blkend++; while (blkend < lines) { if (blankline(blkend)) break; blkend++; } --blkend; } if (lineno(y) != blkbeg-1) x = 0; x1 = x; cp1 = cp2 = topptr + (blkbeg - 1) * wwd + x; cpend = topptr + blkend * wwd; while (cp2 < cpend) { while (*cp2 == ' ' && cp2 < cpend) cp2++; if (cp2 == cpend) break; /* at a word */ while (*cp2 != ' ' && cp2 < cpend) { if (x1 >= wwd - 1) { /* wrap the word */ svcp = cp1 + (wwd - x1); while (*--cp1 != ' ') { *cp1 = ' '; --cp2; } x1 = 0; blkbeg++; cp1 = svcp; } *cp1++ = *cp2++; x1++; } if (cp2 < cpend) { *cp1++ = ' '; x1++; } } while (cp1 < cpend) *cp1++ = ' '; blkbeg++; if (blkbeg <= blkend) delete_block(); blkbeg = blkend = 0; display_text(); findlast(); } /*page*/ /* ------- test for a blank line ---------- */ static int blankline(int line) { char *cp; int x; cp = topptr + (line-1) * wwd; for (x = 0; x < wwd; x++) if (*(cp + x) != ' ') break; return (x == wwd); } /* ------------- delete a word -------------- */ static void delete_word(int x, int y) { int wct = 0; char *cp1, *cp2; cp1 = cp2 = curr(x, y); if (*cp2 == ' ') while (*cp2 == ' ' && x + wct < wwd) { wct++; cp2++; } else { while (*cp2 != ' ' && x + wct < wwd) { wct++; cp2++; } while (*cp2 == ' ' && x + wct < wwd) { wct++; cp2++; } } movmem(cp2, cp1, wwd - x - wct); setmem(cp1 + wwd - x - wct, wct, ' '); display_text(); findlast(); } /* ----------- delete a line --------------- */ static void delete_line(int y) { char *cp1, *cp2; int len; cp1 = bfptr + y * wwd; cp2 = cp1 + wwd; if (cp1 < lstptr) { len = endptr - cp2; movmem(cp2, cp1, len); lstptr -= wwd; setmem(endptr - wwd, wwd, ' '); display_text(); } } /* ----------- delete a block ------------- */ static void delete_block() { char *cp1, *cp2; int len; if (!blkbeg || !blkend) { putchar(BELL); return; } cp1 = topptr + blkend * wwd; cp2 = topptr + (blkbeg - 1) * wwd; len = endptr - cp1; movmem(cp1, cp2, len); setmem(cp2 + len, endptr - (cp2 + len), ' '); blkbeg = blkend = 0; lstptr -= (cp1 - cp2); display_text(); } /*page*/ /* ------- move and copy text blocks -------- */ static void mvblock(int y, int moving) { char *cp1, *cp2, *hd; int len; if (!blkbeg || !blkend) { putchar(BELL); return; } if (lineno(y) >= blkbeg-1 && lineno(y) <= blkend-1) { error_message("Can't move/copy a block into itself"); return; } len = (blkend - blkbeg + 1) * wwd; if ((hd = malloc(len)) == 0) return; cp1 = topptr + (blkbeg-1) * wwd; movmem(cp1, hd, len); cp2 = topptr + lineno(y) * wwd; if (moving) { if (lineno(y) > blkbeg-1) cp2 -= len; do_display_text = 0; delete_block(); do_display_text = 1; } if (cp2+len <= endptr) { movmem(cp2, cp2 + len, endptr - cp2 - len); movmem(hd, cp2, len); } free(hd); blkbeg = blkend = 0; display_text(); } /* ------------- copy a block ---------------- */ static void copy_block(int y) { mvblock(y, FALSE); findlast(); } /* --------- move a block ------------ */ static void move_block(int y) { mvblock(y, TRUE); } /* ------- find the last character in the buffer -------- */ static void findlast() { register char *lp = endptr - 1; register char *tp = topptr; while (lp > tp && (*lp == ' ' || *lp == '\0')) { if (*lp == '\0') *lp = ' '; --lp; } if (*lp != ' ') lp++; lstptr = lp; } /* ------- go to the end of the data in the buffer ------- */ static void find_end(int *x, int *y) { int ct; bfptr = lstptr; ct = (lstptr - topptr) % wsz; bfptr -= ct; if (bfptr + wsz > endptr) bfptr = endptr - wsz; *y = (ct / wwd); *x = 0; downward(y); } /*page*/ /* -------- carriage return -------- */ static void carrtn(int *x, int *y, int insert) { int insct; char *cp, *nl; int ctl = 2; cp = curr(*x, *y); nl = cp + ((cp - topptr) % wwd); if (lineno(*y) + 2 < lines) if (insert && nl < endptr) { insct = wwd - *x; while (ctl--) { if (endptr > cp + insct) { movmem(cp, cp+insct, endptr-insct-cp); setmem(cp, insct, ' '); } else if (ctl == 1) setmem(cp, endptr - cp, ' '); cp += insct * 2; insct = *x; } } *x = 0; downward(y); if (insert) { test_para(*x, *y); display_text(); } if (lineno(*y) + 2 < lines) if (insert) if ((lstptr + wwd) <= endptr) if (lstptr > curr(*x, *y)) lstptr += wwd; } /*page*/ /* ------- move the buffer offset back one position ------ */ static void backspace(int *x, int *y) { if (*x == 0) { *x = wwd - 1; upward(y); } else --(*x); } /* -------- move the buffer offset forward one word ------ */ static void fore_word(int *x, int *y, char *bf) { while (*bf != ' ') { if (spaceup(x, y, &bf) == 0) return; if (*x == 0) break; } while (*bf == ' ') if (spaceup(x, y, &bf) == 0) return; } static int spaceup(int *x, int *y, char **bf) { if (*bf == lstptr) return 0; (*bf)++; forward(x, y); return 1; } /*page*/ /* ------- move the buffer offset backward one word ------ */ static void back_word(int *x, int *y, char *bf) { spacedn(x, y, &bf); while (*bf == ' ') if (spacedn(x, y, &bf) == 0) return; while (*bf != ' ') { if (*x == 0) return; if (spacedn(x, y, &bf) == 0) return; } spaceup(x, y, &bf); } static int spacedn(int *x, int *y, char **bf) { if (*bf == topptr) return 0; --(*bf); backspace(x, y); return 1; } /* ----- move the buffer offset forward one position ----- */ static void forward(int *x, int *y) { int ww = wwd; (*x)++; if (*x == ww) { downward(y); *x = 0; } } /*page*/ /* ------- move the buffer offset down one position ------ */ static int downward(int *y) { if (*y < wht - 1) { (*y)++; return 1; } else if ((bfptr + wsz) < endptr) { bfptr += wwd; scroll(wnd, UP); disp_line(wht-1); return 1; } return 0; } /* -------- move the buffer offset up one position ------ */ static void upward(int *y) { if (*y) --(*y); else if ((topptr + wwd) <= bfptr) { bfptr -= wwd; scroll(wnd, DN); disp_line(0); } } /* ---- display all the lines in a window ------ */ static void display_text() { int y = 0; if (do_display_text) while (y < wht) disp_line(y++); } /*page*/ /* ---------- Display a line -------- */ static void disp_line(int y) { int x = 0, atr = WNORMAL; if (blkbeg || blkend) if (lineno(y) >= blkbeg-1) if (lineno(y) <= blkend-1) atr = WACCENT; while (x < wwd) { displ(wnd, x+1, y+1, *(bfptr+y * wwd+x), atr); x++; } } /* ---------- set insert/exchange cursor shape ----------- */ static void insert_line() { set_cursor_type(inserting ? 0x0106 : 0x0607); }