From 2ada0f2d94034a9716f0061ba7760e82f90f268b Mon Sep 17 00:00:00 2001 From: kcwu Date: Thu, 10 Feb 2005 07:49:44 +0000 Subject: merge from branches/victor.edit git-svn-id: http://opensvn.csie.org/pttbbs/trunk/pttbbs@2488 63ad8ddf-47c3-0310-b6dd-a9e9d9715204 --- docs/proto/cdoc | 2 +- include/proto.h | 4 +- mbbsd/edit.c | 1946 ++++++++++++++++++++++++++++++++++--------------------- mbbsd/screen.c | 24 +- 4 files changed, 1220 insertions(+), 756 deletions(-) diff --git a/docs/proto/cdoc b/docs/proto/cdoc index 6759e84c..60f29a50 100755 --- a/docs/proto/cdoc +++ b/docs/proto/cdoc @@ -64,7 +64,7 @@ sub grep_desc $out = $2; $out =~ s#^/\*\*##; $out =~ s#\s*\*/$##; - $out =~ s/^\s*\* / /mg; + $out =~ s/^\s*\* ?/ /mg; push @buffer, { type => 'comment', data => $out }; } elsif ($3) { diff --git a/include/proto.h b/include/proto.h index 738c9f0f..df2c372b 100644 --- a/include/proto.h +++ b/include/proto.h @@ -490,6 +490,7 @@ char *genpasswd(char *pw); void mouts(int y, int x, char *str); void move(int y, int x); void outs(const char *str); +void outs_n(const char *str, int n); void clrtoeol(void); void clear(void); void refresh(void); @@ -503,7 +504,8 @@ void redoln(void); void clrtoline(int line); void standout(void); void standend(void); -int edit_outs(const char *text); +void edit_outs(const char *text); +void edit_outs_n(const char *text, int n); void outch(unsigned char c); void rscroll(void); void scroll(void); diff --git a/mbbsd/edit.c b/mbbsd/edit.c index 310fd7b3..db6ef395 100644 --- a/mbbsd/edit.c +++ b/mbbsd/edit.c @@ -1,5 +1,6 @@ /* $Id$ */ -/* edit.c, ¥Î¨Ó´£¨Ñ bbs¤Wªº¤å¦r½s¿è¾¹, §Y ve. +/** + * edit.c, ¥Î¨Ó´£¨Ñ bbs¤Wªº¤å¦r½s¿è¾¹, §Y ve. * ²{¦b³o¤@­Ó¬O´c·d¹Lªºª©¥», ¤ñ¸û¤£Ã­©w, ¥Î¤ñ¸û¦hªº cpu, ¦ý¬O¥i¥H¬Ù¤U³\¦h * ªº°O¾ÐÅé (¥H Ptt¬°¨Ò, ¦b¤E¤d¤H¤W¯¸ªº®É­Ô, ¬ù¥i¬Ù¤U 50MB ªº°O¾ÐÅé) * ¦pªG±z»{¬°¡u®³ cpu´«°O¾ÐÅé¡v¨Ã¤£¦X¥G±zªº¶·¨D, ±z¥i¥H¦Ò¼{§ï¨Ï¥Î­×¥¿«eªº @@ -18,6 +19,12 @@ * ³o­Óª©¥»¦ü¥GÁÙ¦³¦a¤è¨S¦³­×¥¿¦n, ¥i¯à¾É­P segmentation fault . */ #include "bbs.h" + +/** + * data Äæ¦ìªº¥Îªk: + * ¨C¦¸ allocate ¤@­Ó textline_t ®É¡A·|°tµ¹¥L (sizeof(textline_t) + string + * length - 1) ªº¤j¤p¡C¦p¦¹¥iª½±µ¦s¨ú data ¦Ó¤£»ÝÃB¥~ªº malloc¡C + */ typedef struct textline_t { struct textline_t *prev; struct textline_t *next; @@ -29,51 +36,117 @@ typedef struct textline_t { } textline_t; #define KEEP_EDITING -2 -#define BACKUP_LIMIT 100 enum { NOBODY, MANAGER, SYSOP }; + +/** + * ³o­Ó»¡©ú·|±N¾ã­Ó edit.c ¹B§@ªº·§©À±a¹L¡A¥D­n·|±q editor_internal_t ªº + * data structure ½Í°_¡C¹ï©ó¨C¤@­Ó data member ªº¸Ô²Ó¥\¯à¡A½Ð¨£ sturcture + * ¤¤ªºµù¸Ñ¡C + * + * ¤å³¹ªº¤º®e (¥H¤UºÙ content) ¥H¡u¦æ¡v¬°³æ¦ì¡A¥D­n¥H firstline, lastline, + * totaln ¨Ó°O¿ý¡C + * + * User ¦bµe­±¤¤¬Ý¨ìªºµe­±¡A¸m©ó¤@­Ó¡u window ¡v¤¤¡A³o­Ó window ·|¦b + * content ¤W²¾°Ê¡Awindow ¸Ì­±ªº½d³ò§Y¬°­n show ¥X¨Óªº½d³ò¡C¥¦¥Î¤F¤£¤Ö + * Äæ¦ì¨Ó°O¿ý¡A¥]¬A currline, top_of_win, currln, currpnt, curr_window_line, + * edit_margin¡CÅã¥Ü¥X¨Óªº®ÄªG·íµM¤£¥u¬O¾a³o´X­Ó¸ê®Æ¡AÁÙ·|¸ò¨ä¥LÄæ¦ì¦³¥æ¤¬ + * §@¥Î¡A¨Ò¦p ±m¦â½s¿è¼Ò¦¡¡B¯S®í²Å¸¹½s¿è µ¥µ¥¡C¨ä¤¤³Ì½ÆÂøªº³¡¤À¬O¦b¿ï¨ú block + * ¡]¨£«á¡^ªº®É­Ô¡C¤ñ¸û¤£ª½Ä±ªº¦æ¬°¬O¡G°£«D´å¼Ð¦b¶}©l¿ï¨ú¸ò¥Ø«e¡]µ²§ô¡^ªº¦ì¸m + * ¬O¦P¤@­Ó¡]¦¹®É³o­Ó½d³ò¬O¿ï¨úªº½d³ò¡^¡A§_«h´N¬O±q¶}©l¨º¤@¦C¤@ª½¨ì¥Ø«e¡]µ²§ô¡^ + * ³o¤@¦C¡C + * + * editor ªº¨Ï¥Î¤W¥Ø«e¦³¤­ºØ inclusive ªº mode¡G + * insert mode: + * ´¡¤J/¨ú¥N + * ansi mode: + * ±m¦â½s¿è + * indent mode: + * ¦Û°ÊÁY±Æ + * phone mode: + * ¯S®í²Å¸¹½s¿è + * raw mode: + * ignore Ctrl('S'), Ctrl('Q'), Ctrl('T') + * ÃÙ¤ê: ³o¦³¤°»ò¥Î? + * + * editor ¤ä´©¤F°Ï¶ô¿ï¾Üªº¥\¯à¡]¦h¦æ¿ï¨ú ©Î ³æ¦æ¤¤ªº¤ù¬q¡^¡A¹ï©ó¤@­Ó selected + * block¡A¥i¥H cut, copy, cancel, ©ÎªÌ¦s¨ì¼È¨úÀÉ¡A¬Æ¦Ü¬O©¹¥ª/¥k shift¡C¸Ô¨£ + * block_XXX¡C + * + * ¥Î Ctrl('Y') §R°£ªº¨º¤@¦æ·|³Q°O¨ì deleted_line ³o­ÓÄæ¦ì¤¤¡Cundelete_line() + * ¥i¥H°µ undelete ªº°Ê§@¡C deleted_line ªì©l­È¬° NULL¡A¨C¦¸¥u¤¹³\¦s¤@¦æ¡A©Ò¥H + * ¦b¦s¤U¨Ó®É¡Aµo²{­È¤£¬° NULL ·|¥ý°µ free ªº°Ê§@¡Ceditor µ²§ô®É¡A¦b + * edit_buffer_destructor() ¤¤¦pªGµo²{¦³ deleted_line¡A·|¦b³oÃäÄÀ©ñ±¼¡C¨ä¥L¦a + * ¤è¤]¦³¬Û¦Pªº§@ªk¡A¨Ò¦p searched_string¡Csearched_string ¬O¦b·j´M¤å³¹¤º®e + * ®É¡A­n´M§äªº key word¡C + * + * ÁÙ¦³¤@­Ó¦³½ìªº¯SÂI¡A¡u¬A¸¹¤Ç°t¡v¡I¦æ¬°´N¦p¦P¦b vim ¸Ì­±¤@¼Ë¡C§c¡A·íµM¨S¨º + * »ò±j°Õ¡A¦ý¦Ü¤Ö¦b§t¦³ c-style comment ¸ò c-style string ®É¬O¹ïªº³á¡C³o­Ó°Ê + * §@©w¸q©ó match_paren() ¤¤¡C + * + * ¥t¥~¡A¦pªG¦³»Ý­n·s¼W·sªºÄæ¦ì¡A½Ð±Nªì©l¤Æ¡]¦³»Ý­nªº¸Ü¡^ªº°Ê§@¼g¦b + * edit_buffer_constructor ¤¤¡C·íµM¤]¦³­Ó edit_buffer_destructor ¥i¥H¨Ï¥Î¡C + * + * ¦¹¥~¡A¬°¤F´£¨Ñ¤@­Ó reentrant ªº editor¡Aprev «ü¦V«e¤@­Ó editor ªº + * editor_internal_t¡Center_edit_buffer ¸ò exit_edit_buffer ´£¨Ñ¶i¥Xªº¤¶­±¡A + * ¸Ì­±¤À§O·|©I¥s constructor ¸ò destructor¡C + * + * Victor Hsieh + * Thu, 03 Feb 2005 15:18:00 +0800 + */ typedef struct editor_internal_t { - textline_t *firstline; - textline_t *lastline; - textline_t *currline; - textline_t *blockline; - textline_t *top_of_win; - textline_t *deleted_lines; - - short currpnt, currln, totaln; - short curr_window_line; - short edit_margin; - short blockln; - short blockpnt; - char insert_c; - - char phone_mode; - char phone_mode0; - char insert_character :1; - char my_ansimode :1; + + textline_t *firstline; /* first line of the article. */ + textline_t *lastline; /* last line of the article. */ + + textline_t *currline; /* current line of the article(window). */ + textline_t *blockline; /* the first selected line of the block. */ + textline_t *top_of_win; /* top line of the article in the window. */ + + textline_t *deleted_line; /* deleted line. Just keep one deleted line. */ + + short currln; /* current line of the article. */ + short currpnt; /* current column of the article. */ + short totaln; /* total lines of the article. */ + short curr_window_line; /* current line to the window. */ + short last_margin; + short edit_margin; /* when the cursor moves out of range (say, + t_columns), shift this length of the string + so you won't see the first edit_margin-th + character. */ + short lastindent; + short blockln; /* the row you started to select block. */ + short blockpnt; /* the column you started to select block. */ + char insert_c; /* insert this character when shift something + in order to compensate the new space. */ + char last_phone_mode; + char ifuseanony :1; char redraw_everything :1; - char raw_mode :1; - char line_dirty :1; + + char insert_mode :1; + char ansimode :1; char indent_mode :1; + char phone_mode :1; + char raw_mode :1; + + char *searched_string; + char *(*substr_fp) (); struct editor_internal_t *prev; } editor_internal_t; -// ?? } __attribute__ ((packed)) +// } __attribute__ ((packed)) -//static editor_internal_t *edit_buf_head = NULL; static editor_internal_t *curr_buf = NULL; -static char editline[WRAPMARGIN + 2]; - static const char fp_bak[] = "bak"; -static char *BIG5[13] = { +static const char *BIG5[13] = { "¡A¡F¡G¡B¡N¡C¡H¡I¡E¡T¡]¡^¡©¡ª¡«¡¬", "¢b¢c¢d¢e¢f¢g¢h¢i¢j¢k¢l¢m¢n¢o¢pùþ ", "¡³¡ó¡·¡´¡¸¡¹¡¼¡½¡¿¡¶¡¾¡µ¡º¡»¡ð¡ñ", @@ -89,7 +162,7 @@ static char *BIG5[13] = { "¢¹¢º¢»¢¼¢½¢¾¢¿¢À¢Á¢Â" }; -static char *BIG_mode[13] = { +static const char *BIG_mode[13] = { "¼ÐÂI", "¹Ï¶ô", "¼Ð°O", @@ -105,7 +178,7 @@ static char *BIG_mode[13] = { "¼Æ¦r" }; -static char *table[8] = { +static const char *table[8] = { "¢x¢w¢|¢r¢}¢u¢q¢t¢z¢s¢{", "ùø¢¤ùãùäùåùàùáùâùÝùÞùß", "ùø¢wùõùöù÷ùòùóùôùïùðùñ", @@ -116,7 +189,7 @@ static char *table[8] = { "¢x¢¤ùìùíù¢¦¢§ùæùçùè" }; -static char *table_mode[6] = { +static const char *table_mode[6] = { "ª½¨¤", "Ås©·", "¢q", @@ -130,34 +203,59 @@ static char *table_mode[6] = { static void indigestion(int i) { - fprintf(stderr, "ÄY­«¤º¶Ë %d\n", i); + char buf[64]; + sprintf(buf, "ÄY­«¤º¶Ë (%d)\n", i); + vmsg(buf); + u_exit("EDITOR FAILED"); + exit(0); } -static void init_edit_buffer(editor_internal_t *buf) +static inline void +edit_buffer_constructor(editor_internal_t *buf) { /* all unspecified columns are 0 */ buf->blockln = -1; buf->insert_c = ' '; - buf->insert_character = 1; + buf->insert_mode = 1; buf->redraw_everything = 1; + buf->lastindent = -1; } -static void enter_edit_buffer(void) +static inline void +enter_edit_buffer(void) { editor_internal_t *p = curr_buf; curr_buf = (editor_internal_t *)malloc(sizeof(editor_internal_t)); memset(curr_buf, 0, sizeof(editor_internal_t)); curr_buf->prev = p; + edit_buffer_constructor(curr_buf); +} + +static inline void +edit_buffer_destructor(void) +{ + if (curr_buf->deleted_line != NULL) + free(curr_buf->deleted_line); + + if (curr_buf->searched_string != NULL) + free(curr_buf->searched_string); } -static void exit_edit_buffer(void) +static inline void +exit_edit_buffer(void) { editor_internal_t *p = curr_buf; + + edit_buffer_destructor(); curr_buf = p->prev; free(p); } -/* Thor: ansi ®y¼ÐÂà´« for color ½s¿è¼Ò¦¡ */ +/** + * transform position ansix in an ansi string of textline_t to the same + * string without escape code. + * @return position in the string without escape code. + */ static int ansi2n(int ansix, textline_t * line) { @@ -182,6 +280,10 @@ ansi2n(int ansix, textline_t * line) return tmp - data; } +/** + * opposite to ansi2n, according to given textline_t. + * @return position in the string with escape code. + */ static short n2ansi(short nx, textline_t * line) { @@ -209,54 +311,78 @@ n2ansi(short nx, textline_t * line) } /* ¿Ã¹õ³B²z¡G»²§U°T®§¡BÅã¥Ü½s¿è¤º®e */ + +static inline void +show_phone_mode_panel(void) +{ + int i; + + move(b_lines - 1, 0); + clrtoeol(); + + if (curr_buf->last_phone_mode < 20) { + int len; + prints("\033[1;46m¡i%s¿é¤J¡j ", BIG_mode[curr_buf->last_phone_mode - 1]); + len = strlen(BIG5[curr_buf->last_phone_mode - 1]) / 2; + for (i = 0; i < len; i++) + prints("\033[37m%c\033[34m%2.2s", + i + 'A', BIG5[curr_buf->last_phone_mode - 1] + i * 2); + for (i = 0; i < 16 - len; i++) + outs(" "); + outs("\033[37m `1~9-=¤Á´« Zªí®æ\033[m"); + } + else { + prints("\033[1;46m¡iªí®æø»s¡j /=%s *=%s§Î ", + table_mode[(curr_buf->last_phone_mode - 20) / 4], + table_mode[(curr_buf->last_phone_mode - 20) % 4 + 2]); + for (i = 0;i < 11;i++) + prints("\033[37m%c\033[34m%2.2s", i ? i + '/' : '.', + table[curr_buf->last_phone_mode - 20] + i * 2); + outs("\033[37m Z¤º½X \033[m"); + } +} + +/** + * Show the bottom status/help bar, and BIG5/table in phone_mode. + */ static void edit_msg() { - const char *edit_mode[2] = {"¨ú¥N", "´¡¤J"}; - register int n = curr_buf->currpnt; - int i; + int n = curr_buf->currpnt; - if (curr_buf->my_ansimode) /* Thor: §@ ansi ½s¿è */ + if (curr_buf->ansimode) /* Thor: §@ ansi ½s¿è */ n = n2ansi(n, curr_buf->currline); - n++; - if(curr_buf->phone_mode) { - move(b_lines - 1, 0); - clrtoeol(); - if(curr_buf->phone_mode < 20) { - prints("\033[1;46m¡i%s¿é¤J¡j ", BIG_mode[curr_buf->phone_mode - 1]); - for (i = 0;i < 16;i++) - if (i < strlen(BIG5[curr_buf->phone_mode - 1]) / 2) - prints("\033[37m%c\033[34m%2.2s", - i + 'A', BIG5[curr_buf->phone_mode - 1] + i * 2); - else - outs(" "); - outs("\033[37m `-=¤Á´« Zªí®æ \033[m"); - } - else { - prints("\033[1;46m¡iªí®æø»s¡j /=%s *=%s§Î ", - table_mode[(curr_buf->phone_mode - 20) / 4], - table_mode[(curr_buf->phone_mode - 20) % 4 + 2]); - for (i = 0;i < 11;i++) - prints("\033[37m%c\033[34m%2.2s", i ? i + '/' : '.', - table[curr_buf->phone_mode - 20] + i * 2); - outs("\033[37m Z¤º½X \033[m"); - } - } + + if (curr_buf->phone_mode) + show_phone_mode_panel(); + move(b_lines, 0); clrtoeol(); - prints("\033[%sm ½s¿è¤å³¹ \033[31;47m (^Z)\033[30m»¡©ú " + prints("\033[37;44m ½s¿è¤å³¹ \033[31;47m (^Z)\033[30m»¡©ú " "\033[31;47m(^P)\033[30m²Å¸¹ " "\033[31;47m(^G)\033[30m´¡¤J¹Ï¤å®w \033[31m(^X,^Q)" "\033[30mÂ÷¶}ùø%s¢x%c%c%c%cùø %3d:%3d \033[m", - "37;44", - edit_mode[curr_buf->insert_character ? 1 : 0], - curr_buf->my_ansimode ? 'A' : 'a', + curr_buf->insert_mode ? "´¡¤J" : "¨ú¥N", + curr_buf->ansimode ? 'A' : 'a', curr_buf->indent_mode ? 'I' : 'i', curr_buf->phone_mode ? 'P' : 'p', curr_buf->raw_mode ? 'R' : 'r', - curr_buf->currln + 1, n); + curr_buf->currln + 1, n + 1); +} + +/** + * return the middle line of the window. + */ +static inline int +middle_line(void) +{ + return p_lines / 2 + 1; } +/** + * Return the previous 'num' line. Stop at the first line if there's + * not enough lines. + */ static textline_t * back_line(textline_t * pos, int num) { @@ -267,10 +393,16 @@ back_line(textline_t * pos, int num) pos = item; curr_buf->currln--; } + else + break; } return pos; } +/** + * Return the next 'num' line. Stop at the last line if there's not + * enough lines. + */ static textline_t * forward_line(textline_t * pos, int num) { @@ -281,12 +413,96 @@ forward_line(textline_t * pos, int num) pos = item; curr_buf->currln++; } + else + break; } return pos; } +/** + * move the cursor to the next line with ansimode fixed. + */ +static inline void +cursor_to_next_line(void) +{ + short pos; + + if (curr_buf->currline->next == NULL) + return; + + curr_buf->currline = curr_buf->currline->next; + curr_buf->curr_window_line++; + curr_buf->currln++; + + if (curr_buf->ansimode) { + pos = n2ansi(curr_buf->currpnt, curr_buf->currline->prev); + curr_buf->currpnt = ansi2n(pos, curr_buf->currline); + } + else { + curr_buf->currpnt = (curr_buf->currline->len > curr_buf->lastindent) + ? curr_buf->lastindent : curr_buf->currline->len; + } +} + +/** + * opposite to cursor_to_next_line. + */ +static inline void +cursor_to_prev_line(void) +{ + short pos; + + if (curr_buf->currline->prev == NULL) + return; + + curr_buf->curr_window_line--; + curr_buf->currln--; + curr_buf->currline = curr_buf->currline->prev; + + if (curr_buf->ansimode) { + pos = n2ansi(curr_buf->currpnt, curr_buf->currline->next); + curr_buf->currpnt = ansi2n(pos, curr_buf->currline); + } + else { + curr_buf->currpnt = (curr_buf->currline->len > curr_buf->lastindent) + ? curr_buf->lastindent : curr_buf->currline->len; + } +} + +static inline void +window_scroll_down(void) +{ + curr_buf->curr_window_line = 0; + + if (!curr_buf->top_of_win->prev) + indigestion(6); + else { + curr_buf->top_of_win = curr_buf->top_of_win->prev; + rscroll(); + } +} + +static inline void +window_scroll_up(void) +{ + if (unlikely(!curr_buf->top_of_win->next)) + indigestion(7); + else { + curr_buf->top_of_win = curr_buf->top_of_win->next; + if(curr_buf->phone_mode) + move(b_lines-1, 0); + else + move(b_lines, 0); + clrtoeol(); + scroll(); + } +} + +/** + * Get the current line number in the window now. + */ static int -getlineno() +get_lineno_in_window() { int cnt = 0; textline_t *p = curr_buf->currline; @@ -298,18 +514,46 @@ getlineno() return cnt; } -static char * -killsp(char *s) +/** + * shift given raw data s with length len to left by one byte. + */ +static void +raw_shift_left(char *s, int len) +{ + int i; + for (i = 0; i < len && s[i] != 0; ++i) + s[i] = s[i + 1]; +} + +/** + * shift given raw data s with length len to right by one byte. + */ +static void +raw_shift_right(char *s, int len) +{ + int i; + for (i = len - 1; i >= 0; --i) + s[i + 1] = s[i]; +} + +/** + * Return the pointer to the next non-space position. + */ +static char * +next_non_space_char(char *s) { while (*s == ' ') s++; return s; } +/** + * allocate a textline_t with length length. + */ static textline_t * alloc_line(short length) { - register textline_t *p; + textline_t *p; if ((p = (textline_t *) malloc(length + sizeof(textline_t)))) { memset(p, 0, length + sizeof(textline_t)); @@ -323,11 +567,25 @@ alloc_line(short length) return NULL; } -/* append p after line in list. keeps up with last line */ +/** + * deleted_line will be assigned to 'line'. If deleted_line is not NULL, + * it'll be freed first. + */ +static inline void +set_deleted_line(textline_t *line) +{ + if (curr_buf->deleted_line != NULL) + free(curr_buf->deleted_line); + curr_buf->deleted_line = line; +} + +/** + * Insert p after line in list. Keeps up with last line + */ static void -append(textline_t * p, textline_t * line) +insert_line(textline_t *line, textline_t *p) { - register textline_t *n; + textline_t *n; if ((p->next = n = line->next)) n->prev = p; @@ -337,11 +595,9 @@ append(textline_t * p, textline_t * line) p->prev = line; } -/* - * delete_line deletes 'line' from the list, and maintains the lastline, and - * firstline pointers. +/** + * delete_line deletes 'line' from the line list. */ - static void delete_line(textline_t * line) { @@ -360,16 +616,14 @@ delete_line(textline_t * line) p->next = n; else curr_buf->firstline = n; - strcat(line->data, "\n"); - line->prev = curr_buf->deleted_lines; - curr_buf->deleted_lines = line; + curr_buf->totaln--; } static int ask(char *prompt) { - int ch; + int ch; move(0, 0); clrtoeol(); @@ -382,8 +636,14 @@ ask(char *prompt) return (ch); } +/** + * Return the indent space number according to CURRENT line and the FORMER + * line. It'll be the first line contains non-space character. + * @return space number from the beginning to the first non-space character, + * return 0 if non or not in indent mode. + */ static int -indent_spcs() +indent_space() { textline_t *p; int spcs; @@ -393,23 +653,28 @@ indent_spcs() for (p = curr_buf->currline; p; p = p->prev) { for (spcs = 0; p->data[spcs] == ' '; ++spcs); + /* empty loop */ if (p->data[spcs]) return spcs; } return 0; } +/** + * adjustline(oldp, len); + * ¥Î¨Ó±N oldp «ü¨ìªº¨º¤@¦æ, ­«·s­×¥¿¦¨ len³o»òªø. + * + * In FreeBSD: + * ¦b³oÃä¤@¦@°µ¤F¨â¦¸ªº memcpy() , ²Ä¤@¦¸±q heap «þ¨ì stack , + * §â­ì¨Ó°O¾ÐÅé free() «á, ¤S­«·s¦b stack¤W malloc() ¤@¦¸, + * µM«á¦A«þ¨©¦^¨Ó. + * ¥D­n¬O¥Î sbrk() Æ[¹î¨ìªºµ²ªG, ³o¼Ë¤l¤~¯uªº¯àÁY´î°O¾ÐÅé¥Î¶q. + * ¸Ô¨£ /usr/share/doc/papers/malloc.ascii.gz (in FreeBSD) + */ static textline_t * adjustline(textline_t *oldp, short len) { - /* adjustline(oldp, len); - * ¥Î¨Ó±N oldp «ü¨ìªº¨º¤@¦æ, ­«·s­×¥¿¦¨ len³o»òªø. - * ¦b³oÃä¤@¦@°µ¤F¨â¦¸ªº memcpy() , ²Ä¤@¦¸±q heap «þ¨ì stack , - * §â­ì¨Ó°O¾ÐÅé free() «á, ¤S­«·s¦b stack¤W malloc() ¤@¦¸, - * µM«á¦A«þ¨©¦^¨Ó. - * ¥D­n¬O¥Î sbrk() Æ[¹î¨ìªºµ²ªG, ³o¼Ë¤l¤~¯uªº¯àÁY´î°O¾ÐÅé¥Î¶q. - * ¸Ô¨£ /usr/share/doc/papers/malloc.ascii.gz (in FreeBSD) - */ + // XXX write a generic version ? char tmpl[sizeof(textline_t) + WRAPMARGIN]; textline_t *newp; memcpy(tmpl, oldp, oldp->len + sizeof(textline_t)); @@ -431,14 +696,18 @@ adjustline(textline_t *oldp, short len) return newp; } -/* split 'line' right before the character pos */ +/** + * split 'line' right before the character pos + * + * @return the latter line after splitting + */ static textline_t * split(textline_t * line, int pos) { if (pos <= line->len) { register textline_t *p = alloc_line(WRAPMARGIN); register char *ptr; - int spcs = indent_spcs(); + int spcs = indent_space(); curr_buf->totaln++; @@ -447,11 +716,17 @@ split(textline_t * line, int pos) memset(p->data, ' ', spcs); p->data[spcs] = 0; - strcat(p->data, (ptr = line->data + pos)); + + ptr = line->data + pos; + if (curr_buf->indent_mode) + ptr = next_non_space_char(ptr); + strcat(p->data + spcs, ptr); ptr[0] = '\0'; - append(p, line); + + insert_line(line, p); line = adjustline(line, line->len); if (line == curr_buf->currline && pos <= curr_buf->currpnt) { + // XXX never reached !? since line is a new allocated memory curr_buf->currline = p; if (pos == curr_buf->currpnt) curr_buf->currpnt = spcs; @@ -465,6 +740,12 @@ split(textline_t * line, int pos) return line; } +/** + * Insert a character ch to current line. + * + * The line will be split if the length is >= WRAPMARGIN. It'll be split + * from the last space if any, or start a new line after the last character. + */ static void insert_char(int ch) { @@ -477,16 +758,13 @@ insert_char(int ch) indigestion(1); return; } - if (curr_buf->currpnt < i && !curr_buf->insert_character) { + if (curr_buf->currpnt < i && !curr_buf->insert_mode) { p->data[curr_buf->currpnt++] = ch; /* Thor: ansi ½s¿è, ¥i¥Hoverwrite, ¤£»\¨ì ansi code */ - if (curr_buf->my_ansimode) + if (curr_buf->ansimode) curr_buf->currpnt = ansi2n(n2ansi(curr_buf->currpnt, p), p); } else { - while (i >= curr_buf->currpnt) { - p->data[i + 1] = p->data[i]; - i--; - } + raw_shift_right(p->data + curr_buf->currpnt, i - curr_buf->currpnt + 1); p->data[curr_buf->currpnt++] = ch; i = ++(p->len); } @@ -512,6 +790,10 @@ insert_char(int ch) } } } + +/** + * insert_char twice. + */ static void insert_dchar(const char *dchar) { @@ -519,56 +801,79 @@ insert_dchar(const char *dchar) insert_char(*(dchar+1)); } +static void +insert_tab(void) +{ + do { + insert_char(' '); + } while (curr_buf->currpnt & 0x7); +} + +/** + * Insert a string. + * + * All printable and '\033' will be directly printed out. + * '\t' will be printed to align every 8 byte. + * '\n' will split the line. + * The other character will be ignore. + */ static void insert_string(const char *str) { - int ch; + char ch; while ((ch = *str++)) { if (isprint2(ch) || ch == '\033') insert_char(ch); - else if (ch == '\t') { - do { - insert_char(' '); - } while (curr_buf->currpnt & 0x7); - } else if (ch == '\n') + else if (ch == '\t') + insert_tab(); + else if (ch == '\n') split(curr_buf->currline, curr_buf->currpnt); } } -static int -undelete_line() +/** + * undelete the deleted line. + * + * return NULL if there's no deleted_line, otherwise, return currline. + */ +static textline_t * +undelete_line(void) { - textline_t *p = curr_buf->deleted_lines; editor_internal_t tmp; - if (!curr_buf->deleted_lines) - return 0; + if (!curr_buf->deleted_line) + return NULL; - tmp.currline = curr_buf->currline; tmp.top_of_win = curr_buf->top_of_win; - tmp.currpnt = curr_buf->currpnt; - tmp.currln = curr_buf->currln; - tmp.curr_window_line = curr_buf->curr_window_line; tmp.indent_mode = curr_buf->indent_mode; + tmp.curr_window_line = curr_buf->curr_window_line; curr_buf->indent_mode = 0; - insert_string(curr_buf->deleted_lines->data); - curr_buf->indent_mode = tmp.indent_mode; - curr_buf->deleted_lines = curr_buf->deleted_lines->prev; - free(p); + curr_buf->currpnt = 0; + curr_buf->currln++; + insert_string(curr_buf->deleted_line->data); + insert_string("\n"); - curr_buf->currline = tmp.currline; curr_buf->top_of_win = tmp.top_of_win; - curr_buf->currpnt = tmp.currpnt; - curr_buf->currln = tmp.currln; + curr_buf->indent_mode = tmp.indent_mode; curr_buf->curr_window_line = tmp.curr_window_line; - return 0; + + curr_buf->currline = curr_buf->currline->prev; + + if (curr_buf->currline->prev == NULL) { + curr_buf->top_of_win = curr_buf->currline; + curr_buf->currln = 0; + } + return curr_buf->currline; } /* * 1) lines were joined and one was deleted 2) lines could not be joined 3) * next line is empty returns false if: 1) Some of the joined line wrapped + * + * (It assumes line has WRAPMARGIN length of data. It seems to imply + * line == currline .) */ static int join(textline_t * line) @@ -578,7 +883,7 @@ join(textline_t * line) if (!(n = line->next)) return YEA; - if (!*killsp(n->data)) + if (!*next_non_space_char(n->data)) return YEA; ovfl = line->len + n->len - WRAPMARGIN; @@ -588,6 +893,7 @@ join(textline_t * line) delete_line(n); return YEA; } else { + // FIXME segfault register char *s; s = n->data + n->len - ovfl - 1; @@ -622,29 +928,25 @@ delete_char() register int len; if ((len = curr_buf->currline->len)) { - register int i; - register char *s; - - if (curr_buf->currpnt >= len) { + if (unlikely(curr_buf->currpnt >= len)) { indigestion(1); return; } - for (i = curr_buf->currpnt, s = curr_buf->currline->data + i; i != len; i++, s++) - s[0] = s[1]; + raw_shift_left(curr_buf->currline->data + curr_buf->currpnt, curr_buf->currline->len - curr_buf->currpnt + 1); curr_buf->currline->len--; } } static void -load_file(FILE * fp) /* NOTE it will fclose(fp) */ +load_file(FILE * fp) { + char buf[WRAPMARGIN + 2]; int indent_mode0 = curr_buf->indent_mode; assert(fp); curr_buf->indent_mode = 0; - while (fgets(editline, WRAPMARGIN + 2, fp)) - insert_string(editline); - fclose(fp); + while (fgets(buf, sizeof(buf), fp)) + insert_string(buf); curr_buf->indent_mode = indent_mode0; } @@ -685,6 +987,7 @@ read_tmpbuf(int n) getdata(b_lines - 1, 0, "½T©wŪ¤J¶Ü(Y/N)?[Y]", ans, sizeof(ans), LCECHO); if (*ans != 'n' && (fp = fopen(fp_tmpbuf, "r"))) { load_file(fp); + fclose(fp); while (curr_buf->curr_window_line >= b_lines) { curr_buf->curr_window_line--; curr_buf->top_of_win = curr_buf->top_of_win->next; @@ -733,6 +1036,7 @@ erase_tmpbuf() /** * ½s¿è¾¹¦Û°Ê³Æ¥÷ + *(³Ì¦h³Æ¥÷ 512 ¦æ (?)) */ void auto_backup() @@ -781,6 +1085,7 @@ restore_backup() } /* ¤Þ¥Î¤å³¹ */ + static int garbage_line(char *str) { @@ -876,7 +1181,9 @@ do_quote() } } -/* ¼f¬d user ¤Þ¨¥ªº¨Ï¥Î */ +/** + * ¼f¬d user ¤Þ¨¥ªº¨Ï¥Î + */ static int check_quote() { @@ -924,14 +1231,16 @@ read_file(char *fpath) FILE *fp; if ((fp = fopen(fpath, "r")) == NULL) { - if ((fp = fopen(fpath, "w+"))) { - fclose(fp); + int fd; + if ((fd = creat(fpath, 0600)) >= 0) { + close(fd); return; } indigestion(4); abort_bbs(0); } load_file(fp); + fclose(fp); } void @@ -1012,7 +1321,7 @@ write_header(FILE * fp, int ifuseanony) // FIXME unused } save_title[72] = '\0'; - fprintf(fp, "¼ÐÃD: %s\n®É¶¡: %s\n", save_title, ctime4(&now)); + fprintf(fp, "¼ÐÃD: %s\n®É¶¡: %s\n", save_title, ctime(&now)); } void @@ -1216,161 +1525,489 @@ write_file(char *fpath, int saveheader, int *islocal) return aborted; } +static inline int +has_block_selection(void) +{ + return curr_buf->blockln >= 0; +} + +/** + * a block is continual lines of the article. + */ +/** + * stop the block selection. + */ static void -display_buffer() +block_cancel(void) { - register textline_t *p; - register int i; - int inblock; - char buf[WRAPMARGIN + 2]; - int min, max; + if (has_block_selection()) { + curr_buf->blockln = -1; + curr_buf->redraw_everything = YEA; + } +} - if (curr_buf->currpnt > curr_buf->blockpnt) { - min = curr_buf->blockpnt; - max = curr_buf->currpnt; +static inline void +setup_block_begin_end(textline_t **begin, textline_t **end) +{ + if (curr_buf->currln >= curr_buf->blockln) { + *begin = curr_buf->blockline; + *end = curr_buf->currline; } else { - min = curr_buf->currpnt; - max = curr_buf->blockpnt; + *begin = curr_buf->currline; + *end = curr_buf->blockline; } +} - for (p = curr_buf->top_of_win, i = 0; i < b_lines; i++) { - move(i, 0); - clrtoeol(); - if (curr_buf->blockln >= 0 && - ((curr_buf->blockln <= curr_buf->currln && curr_buf->blockln <= (curr_buf->currln - curr_buf->curr_window_line + i) && - (curr_buf->currln - curr_buf->curr_window_line + i) <= curr_buf->currln) || - (curr_buf->currln <= (curr_buf->currln - curr_buf->curr_window_line + i) && - (curr_buf->currln - curr_buf->curr_window_line + i) <= curr_buf->blockln))) { - outs("\033[7m"); - inblock = 1; - } else - inblock = 0; - if (p) { - if (curr_buf->my_ansimode) - if (curr_buf->currln == curr_buf->blockln && p == curr_buf->currline && max > min) { - outs("\033[m"); - strncpy(buf, p->data, min); - buf[min] = 0; - outs(buf); - outs("\033[7m"); - strncpy(buf, p->data + min, max - min); - buf[max - min] = 0; - outs(buf); - outs("\033[m"); - outs(p->data + max); - } else - outs(p->data); - else if (curr_buf->currln == curr_buf->blockln && p == curr_buf->currline && max > min) { - outs("\033[m"); - strncpy(buf, p->data, min); - buf[min] = 0; - edit_outs(buf); - outs("\033[7m"); - strncpy(buf, p->data + min, max - min); - buf[max - min] = 0; - edit_outs(buf); - outs("\033[m"); - edit_outs(p->data + max); - } else - edit_outs((curr_buf->edit_margin < p->len) ? &p->data[curr_buf->edit_margin] : ""); - p = p->next; - if (inblock) - outs("\033[m"); - } else - outc('~'); +static inline void +setup_block_begin_end_number(short *begin, short *end) +{ + if (curr_buf->currpnt > curr_buf->blockpnt) { + *begin = curr_buf->blockpnt; + *end = curr_buf->currpnt; + } else { + *begin = curr_buf->currpnt; + *end = curr_buf->blockpnt; } - edit_msg(); } +#define BLOCK_TRUNCATE 0 +#define BLOCK_APPEND 1 +/** + * save the selected block to file 'fname.' + * mode: BLOCK_TRUNCATE truncate mode + * BLOCK_APPEND append mode + */ static void -goto_line(int lino) +block_save_to_file(char *fname, int mode) { - char buf[10]; + textline_t *begin, *end; + char fp_tmpbuf[80]; + FILE *fp; - if (lino > 0 || - (getdata(b_lines - 1, 0, "¸õ¦Ü²Ä´X¦æ:", buf, sizeof(buf), DOECHO) && - sscanf(buf, "%d", &lino) && lino > 0)) { - textline_t *p; + if (!has_block_selection()) + return; - p = curr_buf->firstline; - curr_buf->currln = lino - 1; + setup_block_begin_end(&begin, &end); - while (--lino && p->next) - p = p->next; + setuserfile(fp_tmpbuf, fname); + if ((fp = fopen(fp_tmpbuf, mode == BLOCK_APPEND ? "a+" : "w+"))) { + if (begin == end && curr_buf->currpnt != curr_buf->blockpnt) { + char buf[WRAPMARGIN + 2]; - if (p) - curr_buf->currline = p; - else { - curr_buf->currln = curr_buf->totaln; - curr_buf->currline = curr_buf->lastline; - } - curr_buf->currpnt = 0; - if (curr_buf->currln < 11) { - curr_buf->top_of_win = curr_buf->firstline; - curr_buf->curr_window_line = curr_buf->currln; + if (curr_buf->currpnt > curr_buf->blockpnt) { + strlcpy(buf, begin->data + curr_buf->blockpnt, sizeof(buf)); + buf[curr_buf->currpnt - curr_buf->blockpnt] = 0; + } else { + strlcpy(buf, begin->data + curr_buf->currpnt, sizeof(buf)); + buf[curr_buf->blockpnt - curr_buf->currpnt] = 0; + } + fputs(buf, fp); } else { - int i; + textline_t *p; - curr_buf->curr_window_line = 11; - for (i = curr_buf->curr_window_line; i; i--) - p = p->prev; - curr_buf->top_of_win = p; + for (p = begin; p != end; p = p->next) + fprintf(fp, "%s\n", p->data); + fprintf(fp, "%s\n", end->data); } + fclose(fp); } - curr_buf->redraw_everything = YEA; } -/* - * mode: 0: prompt 1: forward -1: backward +/** + * delete selected block */ static void -search_str(int mode) +block_delete(void) { - static char str[65]; - typedef char *(*FPTR) (); - static FPTR fptr; - char ans[4] = "n"; + textline_t *begin, *end; - if (!mode) { - if (getdata_buf(b_lines - 1, 0, "[·j´M]ÃöÁä¦r:", - str, sizeof(str), DOECHO)) - if (*str) { - if (getdata(b_lines - 1, 0, "°Ï¤À¤j¤p¼g(Y/N/Q)? [N] ", - ans, sizeof(ans), LCECHO) && *ans == 'y') - fptr = strstr; - else - fptr = strcasestr; - } - } - if (*str && *ans != 'q') { - textline_t *p; - char *pos = NULL; - int lino; + if (!has_block_selection()) + return; - if (mode >= 0) { + setup_block_begin_end(&begin, &end); + + if (begin == end && curr_buf->currpnt != curr_buf->blockpnt) { + short min, max; + + setup_block_begin_end_number(&min, &max); + strcpy(begin->data + min, begin->data + max); + begin->len -= max - min; + curr_buf->currpnt = min; + + } else { +#if 0 + textline_t *p; + + for (p = begin; p != end; p = p->next) + delete_line(p); + delete_line(end); + + curr_buf->top_of_win = ; + curr_buf->curr_window_line -= (curr_buf->currln - curr_buf->blockln); + curr_buf->currpnt = 0; + curr_buf->currline = begin; +#else + textline_t *p; + + if (curr_buf->currln >= curr_buf->blockln) { + curr_buf->curr_window_line -= (curr_buf->currln - curr_buf->blockln); + if (curr_buf->curr_window_line < 0) { + curr_buf->curr_window_line = 0; + if (end->next) + (curr_buf->top_of_win = end->next)->prev = begin->prev; + else + curr_buf->top_of_win = (curr_buf->lastline = begin->prev); + } + curr_buf->currln -= (curr_buf->currln - curr_buf->blockln); + } + + if (begin->prev) + begin->prev->next = end->next; + else if (end->next) + curr_buf->top_of_win = curr_buf->firstline = end->next; + else { + curr_buf->currline = curr_buf->top_of_win = curr_buf->firstline = curr_buf->lastline = alloc_line(WRAPMARGIN); + curr_buf->currln = curr_buf->curr_window_line = curr_buf->edit_margin = 0; + } + + if (end->next) + (curr_buf->currline = end->next)->prev = begin->prev; + else if (begin->prev) { + curr_buf->currline = (curr_buf->lastline = begin->prev); + curr_buf->currln--; + if (curr_buf->curr_window_line > 0) + curr_buf->curr_window_line--; + } + + for (p = begin; p != end; curr_buf->totaln--) + free((p = p->next)->prev); + free(end); + curr_buf->totaln--; + + curr_buf->currpnt = 0; +#endif + } +} + +static void +block_cut(void) +{ + if (!has_block_selection()) + return; + + block_save_to_file("buf.0", BLOCK_TRUNCATE); + block_delete(); + + curr_buf->blockln = -1; + curr_buf->redraw_everything = YEA; +} + +static void +block_copy(void) +{ + if (!has_block_selection()) + return; + + block_save_to_file("buf.0", BLOCK_TRUNCATE); + + curr_buf->blockln = -1; + curr_buf->redraw_everything = YEA; +} + +static void +block_prompt(void) +{ + char fp_tmpbuf[80]; + char tmpfname[] = "buf.0"; + char mode[2]; + + move(b_lines - 1, 0); + clrtoeol(); + + if (!getdata(b_lines - 1, 0, "§â°Ï¶ô²¾¦Ü¼È¦sÀÉ (0:Cut, 5:Copy, 6-9, q: Cancel)[0] ", tmpfname + 4, 4, LCECHO)) + tmpfname[4] = '0'; + + if (tmpfname[4] < '0' || tmpfname[4] > '9') + goto cancel_block; + + if (tmpfname[4] == '0') { + block_cut(); + return; + } + else if (tmpfname[4] == '5') { + block_copy(); + return; + } + + setuserfile(fp_tmpbuf, tmpfname); + if (dashf(fp_tmpbuf)) { + more(fp_tmpbuf, NA); + getdata(b_lines - 1, 0, "¼È¦sÀɤw¦³¸ê®Æ (A)ªþ¥[ (W)Âмg (Q)¨ú®ø¡H[W] ", mode, sizeof(mode), LCECHO); + if (mode[0] == 'q') + goto cancel_block; + else if (mode[0] != 'a') + mode[0] = 'w'; + } + + if (getans("§R°£°Ï¶ô(Y/N)?[N] ") != 'y') + goto cancel_block; + + block_save_to_file(tmpfname, mode[0] == 'a' ? BLOCK_APPEND : BLOCK_TRUNCATE); + +cancel_block: + curr_buf->blockln = -1; + curr_buf->redraw_everything = YEA; +} + +static void +block_select(void) +{ + if (has_block_selection()) { + block_prompt(); + return; + } + curr_buf->blockln = curr_buf->currln; + curr_buf->blockpnt = curr_buf->currpnt; + curr_buf->blockline = curr_buf->currline; +} + +static void +block_shift_left() +{ + textline_t *p, *end; + + setup_block_begin_end(&p, &end); + + while (1) { + if (p->len) { + raw_shift_left(p->data, p->len); + --p->len; + } + if (p == end) + break; + else + p = p->next; + } + if (curr_buf->currpnt > curr_buf->currline->len) + curr_buf->currpnt = curr_buf->currline->len; + curr_buf->redraw_everything = YEA; +} + +/** + * Shift the selected block right. If insert_mode is on, put a ' ' in each + * new place, otherwise, put insert_c instead. + */ +static void +block_shift_right() +{ + textline_t *p, *end; + + setup_block_begin_end(&p, &end); + + while (1) { + if (p->len < WRAPMARGIN) { + raw_shift_right(p->data, ++p->len); + p->data[0] = curr_buf->insert_mode ? ' ' : curr_buf->insert_c; + } + if (p == end) + break; + else + p = p->next; + } + if (curr_buf->currpnt > curr_buf->currline->len) + curr_buf->currpnt = curr_buf->currline->len; + curr_buf->redraw_everything = YEA; +} + +static inline void +display_textline_internal(textline_t *p, int i, int min, int max) +{ + char inblock; + short tmp; + void (*output)(const char *); + void (*output_n)(const char *, int); + + move(i, 0); + clrtoeol(); + + if (!p) { + outc('~'); + return; + } + + if (curr_buf->ansimode) { + output = outs; + output_n = outs_n; + } + else { + output = edit_outs; + output_n = edit_outs_n; + } + + tmp = curr_buf->currln - curr_buf->curr_window_line + i; + + /* if line 'i' is in block's range */ + if (has_block_selection() && ( + (curr_buf->blockln <= curr_buf->currln && + curr_buf->blockln <= tmp && tmp <= curr_buf->currln) || + (curr_buf->currln <= tmp && tmp <= curr_buf->blockln)) ) { + outs("\033[7m"); + inblock = 1; + } else + inblock = 0; + + if (curr_buf->currln == curr_buf->blockln && p == curr_buf->currline && max > min) { + outs("\033[m"); + (*output_n)(p->data, min); + outs("\033[7m"); + (*output_n)(p->data + min, max - min); + outs("\033[m"); + (*output)(p->data + max); + } else + (*output)((curr_buf->edit_margin < p->len) ? &p->data[curr_buf->edit_margin] : ""); + + if (inblock) + outs("\033[m"); +} +/** + * given a textline_t 'text' and the line number 'n' in the content, + * display this line. + */ +static void +display_textline(textline_t *text, int n) +{ + short begin, end; + + setup_block_begin_end_number(&begin, &end); + display_textline_internal(text, n, begin, end); +} + +static void +refresh_window(void) +{ + register textline_t *p; + register int i; + short begin, end; + + setup_block_begin_end_number(&begin, &end); + + for (p = curr_buf->top_of_win, i = 0; i < b_lines; i++) { + display_textline_internal(p, i, begin, end); + + if (p) + p = p->next; + } + edit_msg(); +} + +static void +goto_line(int lino) +{ + if (lino > 0 && lino <= curr_buf->totaln + 1) { + textline_t *p; + + p = curr_buf->firstline; + curr_buf->currln = lino - 1; + + while (--lino && p->next) + p = p->next; + + if (p) + curr_buf->currline = p; + else { + curr_buf->currln = curr_buf->totaln; + curr_buf->currline = curr_buf->lastline; + } + + curr_buf->currpnt = 0; + + /* move window */ + if (curr_buf->currln < middle_line()) { + curr_buf->top_of_win = curr_buf->firstline; + curr_buf->curr_window_line = curr_buf->currln; + } else { + int i; + curr_buf->curr_window_line = middle_line(); + for (i = curr_buf->curr_window_line; i; i--) + p = p->prev; + curr_buf->top_of_win = p; + } + } + curr_buf->redraw_everything = YEA; +} + +static void +prompt_goto_line() +{ + char buf[10]; + + if (getdata(b_lines - 1, 0, "¸õ¦Ü²Ä´X¦æ:", buf, sizeof(buf), DOECHO)) + goto_line(atoi(buf)); +} + +/** + * search string interactively. + * @param mode 0: prompt + * 1: forward + * -1: backward + */ +static void +search_str(int mode) +{ + const int max_keyword = 65; + char *str; + char ans[4] = "n"; + + if (curr_buf->searched_string == NULL) { + if (mode != 0) + return; + curr_buf->searched_string = (char *)malloc(max_keyword * sizeof(char)); + curr_buf->searched_string[0] = 0; + } + + str = curr_buf->searched_string; + + if (!mode) { + if (getdata_buf(b_lines - 1, 0, "[·j´M]ÃöÁä¦r:", + str, max_keyword, DOECHO)) + if (*str) { + if (getdata(b_lines - 1, 0, "°Ï¤À¤j¤p¼g(Y/N/Q)? [N] ", + ans, sizeof(ans), LCECHO) && *ans == 'y') + curr_buf->substr_fp = strstr; + else + curr_buf->substr_fp = strcasestr; + } + } + if (*str && *ans != 'q') { + textline_t *p; + char *pos = NULL; + int lino; + + if (mode >= 0) { for (lino = curr_buf->currln, p = curr_buf->currline; p; p = p->next, lino++) - if ((pos = fptr(p->data + (lino == curr_buf->currln ? curr_buf->currpnt + 1 : 0), + if ((pos = (*curr_buf->substr_fp)(p->data + (lino == curr_buf->currln ? curr_buf->currpnt + 1 : 0), str)) && (lino != curr_buf->currln || pos - p->data != curr_buf->currpnt)) break; } else { for (lino = curr_buf->currln, p = curr_buf->currline; p; p = p->prev, lino--) - if ((pos = fptr(p->data, str)) && + if ((pos = (*curr_buf->substr_fp)(p->data, str)) && (lino != curr_buf->currln || pos - p->data != curr_buf->currpnt)) break; } if (pos) { + /* move window */ curr_buf->currline = p; curr_buf->currln = lino; curr_buf->currpnt = pos - p->data; - if (lino < 11) { + if (lino < middle_line()) { curr_buf->top_of_win = curr_buf->firstline; curr_buf->curr_window_line = curr_buf->currln; } else { int i; - curr_buf->curr_window_line = 11; + curr_buf->curr_window_line = middle_line(); for (i = curr_buf->curr_window_line; i; i--) p = p->prev; curr_buf->top_of_win = p; @@ -1382,6 +2019,9 @@ search_str(int mode) curr_buf->redraw_everything = YEA; } +/** + * move the cursor from bracket to corresponding bracket. + */ static void match_paren() { @@ -1400,6 +2040,7 @@ match_paren() parenum = ((ptype - parens) % 2) ? -1 : 1; /* FIXME CRASH */ + /* FIXME refactoring */ if (parenum > 0) { for (lino = curr_buf->currln, p = curr_buf->currline; p; p = p->next, lino++) { int len = strlen(p->data); @@ -1499,13 +2140,13 @@ p_outscan: curr_buf->currln = lino; if (lino < top || lino > bottom) { - if (lino < 11) { + if (lino < middle_line()) { curr_buf->top_of_win = curr_buf->firstline; curr_buf->curr_window_line = curr_buf->currln; } else { int i; - curr_buf->curr_window_line = 11; + curr_buf->curr_window_line = middle_line(); for (i = curr_buf->curr_window_line; i; i--) p = p->prev; curr_buf->top_of_win = p; @@ -1516,197 +2157,78 @@ p_outscan: } static void -block_del(int hide) +currline_shift_left(void) { - if (curr_buf->blockln < 0) { - curr_buf->blockln = curr_buf->currln; - curr_buf->blockpnt = curr_buf->currpnt; - curr_buf->blockline = curr_buf->currline; - } else { - char fp_tmpbuf[80]; - FILE *fp; - textline_t *begin, *end, *p; - char tmpfname[10] = "buf.0"; - char ans[6] = "w+n"; + int currpnt0; - move(b_lines - 1, 0); - clrtoeol(); - if (hide == 1) - tmpfname[4] = 'q'; - else if (!hide && !getdata(b_lines - 1, 0, "§â°Ï¶ô²¾¦Ü¼È¦sÀÉ " - "(0:Cut, 5:Copy, 6-9, q: Cancel)[0] ", - tmpfname + 4, 4, LCECHO)) - tmpfname[4] = '0'; - if (tmpfname[4] < '0' || tmpfname[4] > '9') - tmpfname[4] = 'q'; - if ('1' <= tmpfname[4] && tmpfname[4] <= '9') { - setuserfile(fp_tmpbuf, tmpfname); - if (tmpfname[4] != '5' && dashf(fp_tmpbuf)) { - more(fp_tmpbuf, NA); - getdata(b_lines - 1, 0, "¼È¦sÀɤw¦³¸ê®Æ (A)ªþ¥[ (W)Âмg " - "(Q)¨ú®ø¡H[W] ", ans, 2, LCECHO); - if (*ans == 'q') - tmpfname[4] = 'q'; - else if (*ans != 'a') - *ans = 'w'; - } - if (tmpfname[4] != '5') { - getdata(b_lines - 1, 0, "§R°£°Ï¶ô(Y/N)?[N] ", - ans + 2, 4, LCECHO); - if (ans[2] != 'y') - ans[2] = 'n'; - } - } else if (hide != 3) - ans[2] = 'y'; - - tmpfname[5] = ans[1] = ans[3] = 0; - if (tmpfname[4] != 'q') { - if (curr_buf->currln >= curr_buf->blockln) { - begin = curr_buf->blockline; - end = curr_buf->currline; - if (ans[2] == 'y' && !(begin == end && curr_buf->currpnt != curr_buf->blockpnt)) { - curr_buf->curr_window_line -= (curr_buf->currln - curr_buf->blockln); - if (curr_buf->curr_window_line < 0) { - curr_buf->curr_window_line = 0; - if (end->next) - (curr_buf->top_of_win = end->next)->prev = begin->prev; - else - curr_buf->top_of_win = (curr_buf->lastline = begin->prev); - } - curr_buf->currln -= (curr_buf->currln - curr_buf->blockln); - } - } else { - begin = curr_buf->currline; - end = curr_buf->blockline; - } - if (ans[2] == 'y' && !(begin == end && curr_buf->currpnt != curr_buf->blockpnt)) { - if (begin->prev) - begin->prev->next = end->next; - else if (end->next) - curr_buf->top_of_win = curr_buf->firstline = end->next; - else { - curr_buf->currline = curr_buf->top_of_win = curr_buf->firstline = - curr_buf->lastline = alloc_line(WRAPMARGIN); - curr_buf->currln = curr_buf->curr_window_line = curr_buf->edit_margin = 0; - } + if (curr_buf->currline->len <= 0) + return; - if (end->next) - (curr_buf->currline = end->next)->prev = begin->prev; - else if (begin->prev) { - curr_buf->currline = (curr_buf->lastline = begin->prev); - curr_buf->currln--; - if (curr_buf->curr_window_line > 0) - curr_buf->curr_window_line--; - } - } - setuserfile(fp_tmpbuf, tmpfname); - if ((fp = fopen(fp_tmpbuf, ans))) { - if (begin == end && curr_buf->currpnt != curr_buf->blockpnt) { - char buf[WRAPMARGIN + 2]; - - if (curr_buf->currpnt > curr_buf->blockpnt) { - strlcpy(buf, begin->data + curr_buf->blockpnt, sizeof(buf)); - buf[curr_buf->currpnt - curr_buf->blockpnt] = 0; - } else { - strlcpy(buf, begin->data + curr_buf->currpnt, sizeof(buf)); - buf[curr_buf->blockpnt - curr_buf->currpnt] = 0; - } - fputs(buf, fp); - } else { - for (p = begin; p != end; p = p->next) - fprintf(fp, "%s\n", p->data); - fprintf(fp, "%s\n", end->data); - } - fclose(fp); - } - if (ans[2] == 'y') { - if (begin == end && curr_buf->currpnt != curr_buf->blockpnt) { - int min, max; - - if (curr_buf->currpnt > curr_buf->blockpnt) { - min = curr_buf->blockpnt; - max = curr_buf->currpnt; - } else { - min = curr_buf->currpnt; - max = curr_buf->blockpnt; - } - strlcpy(begin->data + min, begin->data + max, sizeof(begin->data) - min); - begin->len -= max - min; - curr_buf->currpnt = min; - } else { - for (p = begin; p != end; curr_buf->totaln--) - free((p = p->next)->prev); - free(end); - curr_buf->totaln--; - curr_buf->currpnt = 0; - } - } - } - curr_buf->blockln = -1; - curr_buf->redraw_everything = YEA; - } + currpnt0 = curr_buf->currpnt; + curr_buf->currpnt = 0; + delete_char(); + curr_buf->currpnt = (currpnt0 <= curr_buf->currline->len) ? currpnt0 : currpnt0 - 1; + if (curr_buf->ansimode) + curr_buf->currpnt = ansi2n(n2ansi(curr_buf->currpnt, curr_buf->currline), curr_buf->currline); } static void -block_shift_left() +currline_shift_right(void) { - textline_t *begin, *end, *p; + int currpnt0; - if (curr_buf->currln >= curr_buf->blockln) { - begin = curr_buf->blockline; - end = curr_buf->currline; - } else { - begin = curr_buf->currline; - end = curr_buf->blockline; - } - p = begin; - while (1) { - if (p->len) { - strcpy(p->data, p->data + 1); - --p->len; - } - if (p == end) - break; - else - p = p->next; - } - if (curr_buf->currpnt > curr_buf->currline->len) - curr_buf->currpnt = curr_buf->currline->len; - curr_buf->redraw_everything = YEA; + if (curr_buf->currline->len >= WRAPMARGIN - 1) + return; + + currpnt0 = curr_buf->currpnt; + curr_buf->currpnt = 0; + insert_char(' '); + curr_buf->currpnt = currpnt0; } static void -block_shift_right() +cursor_to_next_word(void) { - textline_t *begin, *end, *p; + while (curr_buf->currpnt < curr_buf->currline->len && + isalnum((int)curr_buf->currline->data[++curr_buf->currpnt])); + while (curr_buf->currpnt < curr_buf->currline->len && + isspace((int)curr_buf->currline->data[++curr_buf->currpnt])); +} - if (curr_buf->currln >= curr_buf->blockln) { - begin = curr_buf->blockline; - end = curr_buf->currline; - } else { - begin = curr_buf->currline; - end = curr_buf->blockline; - } - p = begin; - while (1) { - if (p->len < WRAPMARGIN) { - int i = p->len + 1; +static void +cursor_to_prev_word(void) +{ + while (curr_buf->currpnt && isspace((int)curr_buf->currline->data[--curr_buf->currpnt])); + while (curr_buf->currpnt && isalnum((int)curr_buf->currline->data[--curr_buf->currpnt])); + if (curr_buf->currpnt > 0) + curr_buf->currpnt++; +} - while (i--) - p->data[i + 1] = p->data[i]; - p->data[0] = curr_buf->insert_character ? ' ' : curr_buf->insert_c; - ++p->len; - } - if (p == end) +static inline int +cursor_at_bottom_line(void) +{ + return curr_buf->curr_window_line == b_lines || + (curr_buf->phone_mode && curr_buf->curr_window_line == b_lines - 1); +} + +static void +delete_current_word(void) +{ + while (curr_buf->currpnt < curr_buf->currline->len) { + delete_char(); + if (!isalnum((int)curr_buf->currline->data[curr_buf->currpnt])) + break; + } + while (curr_buf->currpnt < curr_buf->currline->len) { + delete_char(); + if (!isspace((int)curr_buf->currline->data[curr_buf->currpnt])) break; - else - p = p->next; } - if (curr_buf->currpnt > curr_buf->currline->len) - curr_buf->currpnt = curr_buf->currline->len; - curr_buf->redraw_everything = YEA; } +/** + * transform every "*[" in given string to KEY_ESC "[" + */ static void transform_to_color(char *line) { @@ -1723,13 +2245,8 @@ block_color() { textline_t *begin, *end, *p; - if (curr_buf->currln >= curr_buf->blockln) { - begin = curr_buf->blockline; - end = curr_buf->currline; - } else { - begin = curr_buf->currline; - end = curr_buf->blockline; - } + setup_block_begin_end(&begin, &end); + p = begin; while (1) { transform_to_color(p->data); @@ -1738,39 +2255,181 @@ block_color() else p = p->next; } - block_del(1); + block_cancel(); } -static char* -phone_char(char c) +/** + * insert ansi code + */ +static void +insert_ansi_code(void) { + int ch = curr_buf->insert_mode; + curr_buf->insert_mode = curr_buf->redraw_everything = YEA; + if (!curr_buf->ansimode) + insert_string(reset_color); + else { + char ans[4]; + move(b_lines - 2, 55); + outs("\033[1;33;40mB\033[41mR\033[42mG\033[43mY\033[44mL" + "\033[45mP\033[46mC\033[47mW\033[m"); + if (getdata(b_lines - 1, 0, + "½Ð¿é¤J «G«×/«e´º/­I´º[¥¿±`¥Õ¦r¶Â©³][0wb]¡G", + ans, sizeof(ans), LCECHO)) + { + const char t[] = "BRGYLPCW"; + char color[15]; + char *tmp, *apos = ans; + int fg, bg; + + strcpy(color, "\033["); + if (isdigit((int)*apos)) { + sprintf(color,"%s%c", color, *(apos++)); + if (*apos) + strcat(color, ";"); + } + if (*apos) { + if ((tmp = strchr(t, toupper(*(apos++))))) + fg = tmp - t + 30; + else + fg = 37; + sprintf(color, "%s%d", color, fg); + } + if (*apos) { + if ((tmp = strchr(t, toupper(*(apos++))))) + bg = tmp - t + 40; + else + bg = 40; + sprintf(color, "%s;%d", color, bg); + } + strcat(color, "m"); + insert_string(color); + } else + insert_string(reset_color); + } + curr_buf->insert_mode = ch; +} - if (curr_buf->phone_mode > 0 && curr_buf->phone_mode < 20) { - if (tolower(c)<'a'||(tolower(c)-'a') >= strlen(BIG5[curr_buf->phone_mode - 1]) / 2) +static inline void +phone_mode_switch(void) +{ + if (curr_buf->phone_mode) + curr_buf->phone_mode = 0; + else { + curr_buf->phone_mode = 1; + if (!curr_buf->last_phone_mode) + curr_buf->last_phone_mode = 2; + } +} + +/** + * return coresponding phone char of given key c + */ +static const char* +phone_char(char c) +{ + if (curr_buf->last_phone_mode > 0 && curr_buf->last_phone_mode < 20) { + if (tolower(c)<'a'||(tolower(c)-'a') >= strlen(BIG5[curr_buf->last_phone_mode - 1]) / 2) return 0; - return BIG5[curr_buf->phone_mode - 1] + (tolower(c) - 'a') * 2; + return BIG5[curr_buf->last_phone_mode - 1] + (tolower(c) - 'a') * 2; } - else if (curr_buf->phone_mode >= 20) { + else if (curr_buf->last_phone_mode >= 20) { if (c == '.') c = '/'; if (c < '/' || c > '9') return 0; - return table[curr_buf->phone_mode - 20] + (c - '/') * 2; + return table[curr_buf->last_phone_mode - 20] + (c - '/') * 2; } return 0; } +/** + * When get the key for phone mode, handle it (e.g. edit_msg) and return the + * key. Otherwise return 0. + */ +static inline char +phone_mode_filter(char ch) +{ + if (!curr_buf->phone_mode) + return 0; + + switch (ch) { + case 'z': + case 'Z': + if (curr_buf->last_phone_mode < 20) + curr_buf->last_phone_mode = 20; + else + curr_buf->last_phone_mode = 2; + edit_msg(); + return ch; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (curr_buf->last_phone_mode < 20) { + curr_buf->last_phone_mode = ch - '0' + 1; + curr_buf->redraw_everything = YEA; + return ch; + } + break; + case '-': + if (curr_buf->last_phone_mode < 20) { + curr_buf->last_phone_mode = 11; + curr_buf->redraw_everything = YEA; + return ch; + } + break; + case '=': + if (curr_buf->last_phone_mode < 20) { + curr_buf->last_phone_mode = 12; + curr_buf->redraw_everything = YEA; + return ch; + } + break; + case '`': + if (curr_buf->last_phone_mode < 20) { + curr_buf->last_phone_mode = 13; + curr_buf->redraw_everything = YEA; + return ch; + } + break; + case '/': + if (curr_buf->last_phone_mode >= 20) { + curr_buf->last_phone_mode += 4; + if (curr_buf->last_phone_mode > 27) + curr_buf->last_phone_mode -= 8; + curr_buf->redraw_everything = YEA; + return ch; + } + break; + case '*': + if (curr_buf->last_phone_mode >= 20) { + curr_buf->last_phone_mode++; + if ((curr_buf->last_phone_mode - 21) % 4 == 3) + curr_buf->last_phone_mode -= 4; + curr_buf->redraw_everything = YEA; + return ch; + } + break; + } + + return 0; +} /* ½s¿è³B²z¡G¥Dµ{¦¡¡BÁä½L³B²z */ int vedit(char *fpath, int saveheader, int *islocal) { - FILE *fp1; - char last = 0, *pstr; /* the last key you press */ + char last = 0; /* the last key you press */ int ch, ret; - int lastindent = -1; - int last_margin; + int mode0 = currutmp->mode; int destuid0 = currutmp->destuid; int money = 0; @@ -1783,7 +2442,6 @@ vedit(char *fpath, int saveheader, int *islocal) currutmp->destuid = currstat; enter_edit_buffer(); - init_edit_buffer(curr_buf); oldcurrline = curr_buf->currline = curr_buf->top_of_win = curr_buf->firstline = curr_buf->lastline = alloc_line(WRAPMARGIN); @@ -1794,31 +2452,36 @@ vedit(char *fpath, int saveheader, int *islocal) if (*quote_file) { do_quote(); *quote_file = '\0'; + // FIXME it's never used ?? if (quote_file[79] == 'L') local_article = 1; } - // No matter you quote or not, just start from (0,0) + /* No matter you quote or not, just start the cursor from (0,0) */ curr_buf->currline = curr_buf->firstline; - curr_buf->currpnt = curr_buf->currln = curr_buf->curr_window_line = curr_buf->edit_margin = last_margin = 0; + curr_buf->currpnt = curr_buf->currln = curr_buf->curr_window_line = curr_buf->edit_margin = curr_buf->last_margin = 0; while (1) { - if (curr_buf->redraw_everything || curr_buf->blockln >= 0) { - display_buffer(); + if (curr_buf->redraw_everything || has_block_selection()) { + refresh_window(); curr_buf->redraw_everything = NA; } if( oldcurrline != curr_buf->currline ){ oldcurrline = adjustline(oldcurrline, oldcurrline->len); oldcurrline = curr_buf->currline = adjustline(curr_buf->currline, WRAPMARGIN); } - if (curr_buf->my_ansimode) + + if (curr_buf->ansimode) ch = n2ansi(curr_buf->currpnt, curr_buf->currline); else ch = curr_buf->currpnt - curr_buf->edit_margin; move(curr_buf->curr_window_line, ch); - // XXX dont strcmp, just do it ? + +#if 0 // DEPRECATED, it's really not a well known expensive feature if (!curr_buf->line_dirty && strcmp(editline, curr_buf->currline->data)) strcpy(editline, curr_buf->currline->data); +#endif + ch = igetch(); /* jochang debug */ if ((interval = (now - th))) { @@ -1838,7 +2501,7 @@ vedit(char *fpath, int saveheader, int *islocal) /* log_file("etc/illegal_money", LOG_CREAT | LOG_VF, "\033[1;33;46m%s \033[37;45m ¥Î¾÷¾¹¤Hµoªí¤å³¹ \033[37m %s\033[m\n", - cuser.userid, ctime4(&now)); + cuser.userid, ctime(&now)); post_violatelaw(cuser.userid, "Ptt¨t²Îĵ¹î", "¥Î¾÷¾¹¤Hµoªí¤å³¹", "±j¨îÂ÷¯¸"); abort_bbs(0); @@ -1857,94 +2520,23 @@ vedit(char *fpath, int saveheader, int *islocal) continue; } } - if (curr_buf->phone_mode) { - switch (ch) { - case 'z': - case 'Z': - if (curr_buf->phone_mode < 20) - curr_buf->phone_mode = curr_buf->phone_mode0 = 20; - else - curr_buf->phone_mode = curr_buf->phone_mode0 = 2; - curr_buf->line_dirty = 1; - curr_buf->redraw_everything = YEA; - continue; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (curr_buf->phone_mode < 20) { - curr_buf->phone_mode = curr_buf->phone_mode0 = ch - '0' + 1; - curr_buf->line_dirty = 1; - curr_buf->redraw_everything = YEA; - continue; - } - break; - case '-': - if (curr_buf->phone_mode < 20) { - curr_buf->phone_mode = curr_buf->phone_mode0 = 11; - curr_buf->line_dirty = 1; - curr_buf->redraw_everything = YEA; - continue; - } - break; - case '=': - if (curr_buf->phone_mode < 20) { - curr_buf->phone_mode = curr_buf->phone_mode0 = 12; - curr_buf->line_dirty = 1; - curr_buf->redraw_everything = YEA; - continue; - } - break; - case '`': - if (curr_buf->phone_mode < 20) { - curr_buf->phone_mode = curr_buf->phone_mode0 = 13; - curr_buf->line_dirty = 1; - curr_buf->redraw_everything = YEA; - continue; - } - break; - case '/': - if (curr_buf->phone_mode >= 20) { - curr_buf->phone_mode += 4; - if (curr_buf->phone_mode > 27) - curr_buf->phone_mode -= 8; - curr_buf->line_dirty = 1; - curr_buf->redraw_everything = YEA; - continue; - } - break; - case '*': - if (curr_buf->phone_mode >= 20) { - curr_buf->phone_mode++; - if ((curr_buf->phone_mode - 21) % 4 == 3) - curr_buf->phone_mode -= 4; - curr_buf->line_dirty = 1; - curr_buf->redraw_everything = YEA; - continue; - } - break; - } - } + + if (phone_mode_filter(ch)) + continue; if (ch < 0x100 && isprint2(ch)) { + const char *pstr; if(curr_buf->phone_mode && (pstr=phone_char(ch))) insert_dchar(pstr); else insert_char(ch); - lastindent = -1; - curr_buf->line_dirty = 1; + curr_buf->lastindent = -1; } else { if (ch == KEY_UP || ch == KEY_DOWN ){ - if (lastindent == -1) - lastindent = curr_buf->currpnt; + if (curr_buf->lastindent == -1) + curr_buf->lastindent = curr_buf->currpnt; } else - lastindent = -1; + curr_buf->lastindent = -1; if (ch == KEY_ESC) switch (KEY_ESC_arg) { case ',': @@ -1969,9 +2561,11 @@ vedit(char *fpath, int saveheader, int *islocal) case 'o': ch = Ctrl('O'); break; +#if 0 // DEPRECATED, it's really not a well known expensive feature case '-': ch = Ctrl('_'); break; +#endif case 's': ch = Ctrl('S'); break; @@ -1990,13 +2584,10 @@ vedit(char *fpath, int saveheader, int *islocal) else return ret; } - curr_buf->line_dirty = 1; curr_buf->redraw_everything = YEA; break; case Ctrl('W'): - if (curr_buf->blockln >= 0) - block_del(2); - curr_buf->line_dirty = 1; + block_cut(); break; case Ctrl('Q'): /* Quit without saving */ ch = ask("µ²§ô¦ý¤£Àx¦s (Y/N)? [N]: "); @@ -2006,67 +2597,20 @@ vedit(char *fpath, int saveheader, int *islocal) exit_edit_buffer(); return -1; } - curr_buf->line_dirty = 1; curr_buf->redraw_everything = YEA; break; case Ctrl('C'): - ch = curr_buf->insert_character; - curr_buf->insert_character = curr_buf->redraw_everything = YEA; - if (!curr_buf->my_ansimode) - insert_string(reset_color); - else { - char ans[4]; - move(b_lines - 2, 55); - outs("\033[1;33;40mB\033[41mR\033[42mG\033[43mY\033[44mL" - "\033[45mP\033[46mC\033[47mW\033[m"); - if (getdata(b_lines - 1, 0, - "½Ð¿é¤J «G«×/«e´º/­I´º[¥¿±`¥Õ¦r¶Â©³][0wb]¡G", - ans, sizeof(ans), LCECHO)) { - char t[] = "BRGYLPCW"; - char color[15]; - char *tmp, *apos = ans; - int fg, bg; - - strcpy(color, "\033["); - if (isdigit((int)*apos)) { - sprintf(color,"%s%c", color, *(apos++)); - if (*apos) - strcat(color, ";"); - } - if (*apos) { - if ((tmp = strchr(t, toupper(*(apos++))))) - fg = tmp - t + 30; - else - fg = 37; - sprintf(color, "%s%d", color, fg); - } - if (*apos) { - if ((tmp = strchr(t, toupper(*(apos++))))) - bg = tmp - t + 40; - else - bg = 40; - sprintf(color, "%s;%d", color, bg); - } - strcat(color, "m"); - insert_string(color); - } else - insert_string(reset_color); - } - curr_buf->insert_character = ch; - curr_buf->line_dirty = 1; + insert_ansi_code(); break; case KEY_ESC: - curr_buf->line_dirty = 0; switch (KEY_ESC_arg) { case 'U': t_users(); curr_buf->redraw_everything = YEA; - curr_buf->line_dirty = 1; break; case 'i': t_idle(); curr_buf->redraw_everything = YEA; - curr_buf->line_dirty = 1; break; case 'n': search_str(1); @@ -2076,7 +2620,7 @@ vedit(char *fpath, int saveheader, int *islocal) break; case 'L': case 'J': - goto_line(0); + prompt_goto_line(); break; case ']': match_paren(); @@ -2096,87 +2640,51 @@ vedit(char *fpath, int saveheader, int *islocal) break; case 'l': /* block delete */ case ' ': - block_del(0); - curr_buf->line_dirty = 1; + block_select(); break; case 'u': - if (curr_buf->blockln >= 0) - block_del(1); - curr_buf->line_dirty = 1; + block_cancel(); break; case 'c': - if (curr_buf->blockln >= 0) - block_del(3); - curr_buf->line_dirty = 1; + block_copy(); break; case 'y': - undelete_line(); + oldcurrline = undelete_line(); + if (oldcurrline == NULL) + oldcurrline = curr_buf->currline; break; case 'R': curr_buf->raw_mode ^= 1; - curr_buf->line_dirty = 1; break; case 'I': curr_buf->indent_mode ^= 1; - curr_buf->line_dirty = 1; break; case 'j': - if (curr_buf->blockln >= 0) + if (has_block_selection()) block_shift_left(); - else if (curr_buf->currline->len) { - int currpnt0 = curr_buf->currpnt; - curr_buf->currpnt = 0; - delete_char(); - curr_buf->currpnt = (currpnt0 <= curr_buf->currline->len) ? currpnt0 : - currpnt0 - 1; - if (curr_buf->my_ansimode) - curr_buf->currpnt = ansi2n(n2ansi(curr_buf->currpnt, curr_buf->currline), - curr_buf->currline); - } - curr_buf->line_dirty = 1; + else + currline_shift_left(); break; case 'k': - if (curr_buf->blockln >= 0) + if (has_block_selection()) block_shift_right(); - else { - int currpnt0 = curr_buf->currpnt; - - curr_buf->currpnt = 0; - insert_char(' '); - curr_buf->currpnt = currpnt0; - } - curr_buf->line_dirty = 1; + else + currline_shift_right(); break; case 'f': - while (curr_buf->currpnt < curr_buf->currline->len && - isalnum((int)curr_buf->currline->data[++curr_buf->currpnt])); - while (curr_buf->currpnt < curr_buf->currline->len && - isspace((int)curr_buf->currline->data[++curr_buf->currpnt])); - curr_buf->line_dirty = 1; + cursor_to_next_word(); break; case 'b': - while (curr_buf->currpnt && isalnum((int)curr_buf->currline->data[--curr_buf->currpnt])); - while (curr_buf->currpnt && isspace((int)curr_buf->currline->data[--curr_buf->currpnt])); - curr_buf->line_dirty = 1; + cursor_to_prev_word(); break; case 'd': - while (curr_buf->currpnt < curr_buf->currline->len) { - delete_char(); - if (!isalnum((int)curr_buf->currline->data[curr_buf->currpnt])) - break; - } - while (curr_buf->currpnt < curr_buf->currline->len) { - delete_char(); - if (!isspace((int)curr_buf->currline->data[curr_buf->currpnt])) - break; - } - curr_buf->line_dirty = 1; + delete_current_word(); break; - default: - curr_buf->line_dirty = 1; } break; +#if 0 // DEPRECATED, it's really not a well known expensive feature case Ctrl('_'): + // swap editline and currline's data if (strcmp(editline, curr_buf->currline->data)) { char buf[WRAPMARGIN]; @@ -2188,26 +2696,22 @@ vedit(char *fpath, int saveheader, int *islocal) curr_buf->line_dirty = 1; } break; +#endif case Ctrl('S'): search_str(0); break; case Ctrl('U'): insert_char('\033'); - curr_buf->line_dirty = 1; break; case Ctrl('V'): /* Toggle ANSI color */ - curr_buf->my_ansimode ^= 1; - if (curr_buf->my_ansimode && curr_buf->blockln >= 0) + curr_buf->ansimode ^= 1; + if (curr_buf->ansimode && has_block_selection()) block_color(); clear(); curr_buf->redraw_everything = YEA; - curr_buf->line_dirty = 1; break; case Ctrl('I'): - do { - insert_char(' '); - } while (curr_buf->currpnt & 0x7); - curr_buf->line_dirty = 1; + insert_tab(); break; case '\r': case '\n': @@ -2219,7 +2723,6 @@ vedit(char *fpath, int saveheader, int *islocal) #endif split(curr_buf->currline, curr_buf->currpnt); oldcurrline = curr_buf->currline; - curr_buf->line_dirty = 0; break; case Ctrl('G'): { @@ -2230,16 +2733,18 @@ vedit(char *fpath, int saveheader, int *islocal) currstat = currstat0; } if (trans_buffer[0]) { + FILE *fp1; if ((fp1 = fopen(trans_buffer, "r"))) { - int indent_mode0 = curr_buf->indent_mode; + int indent_mode0 = curr_buf->indent_mode; + char buf[WRAPMARGIN + 2]; curr_buf->indent_mode = 0; - while (fgets(editline, WRAPMARGIN + 2, fp1)) { - if (!strncmp(editline, "§@ªÌ:", 5) || - !strncmp(editline, "¼ÐÃD:", 5) || - !strncmp(editline, "®É¶¡:", 5)) + while (fgets(buf, sizeof(buf), fp1)) { + if (!strncmp(buf, "§@ªÌ:", 5) || + !strncmp(buf, "¼ÐÃD:", 5) || + !strncmp(buf, "®É¶¡:", 5)) continue; - insert_string(editline); + insert_string(buf); } fclose(fp1); curr_buf->indent_mode = indent_mode0; @@ -2250,92 +2755,53 @@ vedit(char *fpath, int saveheader, int *islocal) } } curr_buf->redraw_everything = YEA; - curr_buf->line_dirty = 1; break; case Ctrl('P'): - if (curr_buf->phone_mode) - curr_buf->phone_mode = 0; - else { - if (curr_buf->phone_mode0) - curr_buf->phone_mode = curr_buf->phone_mode0; - else - curr_buf->phone_mode = curr_buf->phone_mode0 = 2; - } + phone_mode_switch(); curr_buf->redraw_everything = YEA; - curr_buf->line_dirty = 1; break; case Ctrl('Z'): /* Help */ more("etc/ve.hlp", YEA); curr_buf->redraw_everything = YEA; - curr_buf->line_dirty = 1; break; case Ctrl('L'): clear(); curr_buf->redraw_everything = YEA; - curr_buf->line_dirty = 1; break; case KEY_LEFT: if (curr_buf->currpnt) { - if (curr_buf->my_ansimode) + if (curr_buf->ansimode) curr_buf->currpnt = n2ansi(curr_buf->currpnt, curr_buf->currline); curr_buf->currpnt--; - if (curr_buf->my_ansimode) + if (curr_buf->ansimode) curr_buf->currpnt = ansi2n(curr_buf->currpnt, curr_buf->currline); - curr_buf->line_dirty = 1; } else if (curr_buf->currline->prev) { curr_buf->curr_window_line--; curr_buf->currln--; curr_buf->currline = curr_buf->currline->prev; curr_buf->currpnt = curr_buf->currline->len; - curr_buf->line_dirty = 0; } break; case KEY_RIGHT: if (curr_buf->currline->len != curr_buf->currpnt) { - if (curr_buf->my_ansimode) + if (curr_buf->ansimode) curr_buf->currpnt = n2ansi(curr_buf->currpnt, curr_buf->currline); curr_buf->currpnt++; - if (curr_buf->my_ansimode) + if (curr_buf->ansimode) curr_buf->currpnt = ansi2n(curr_buf->currpnt, curr_buf->currline); - curr_buf->line_dirty = 1; } else if (curr_buf->currline->next) { curr_buf->currpnt = 0; curr_buf->curr_window_line++; curr_buf->currln++; curr_buf->currline = curr_buf->currline->next; - curr_buf->line_dirty = 0; } break; case KEY_UP: - if (curr_buf->currline->prev) { - if (curr_buf->my_ansimode) - ch = n2ansi(curr_buf->currpnt, curr_buf->currline); - curr_buf->curr_window_line--; - curr_buf->currln--; - curr_buf->currline = curr_buf->currline->prev; - if (curr_buf->my_ansimode) - curr_buf->currpnt = ansi2n(ch, curr_buf->currline); - else - curr_buf->currpnt = (curr_buf->currline->len > lastindent) ? lastindent : - curr_buf->currline->len; - curr_buf->line_dirty = 0; - } + cursor_to_prev_line(); break; case KEY_DOWN: - if (curr_buf->currline->next) { - if (curr_buf->my_ansimode) - ch = n2ansi(curr_buf->currpnt, curr_buf->currline); - curr_buf->currline = curr_buf->currline->next; - curr_buf->curr_window_line++; - curr_buf->currln++; - if (curr_buf->my_ansimode) - curr_buf->currpnt = ansi2n(ch, curr_buf->currline); - else - curr_buf->currpnt = (curr_buf->currline->len > lastindent) ? lastindent : - curr_buf->currline->len; - curr_buf->line_dirty = 0; - } + cursor_to_next_line(); break; case Ctrl('B'): @@ -2344,11 +2810,10 @@ vedit(char *fpath, int saveheader, int *islocal) curr_buf->top_of_win = back_line(curr_buf->top_of_win, 22); curr_buf->currln = tmp; curr_buf->currline = back_line(curr_buf->currline, 22); - curr_buf->curr_window_line = getlineno(); + curr_buf->curr_window_line = get_lineno_in_window(); if (curr_buf->currpnt > curr_buf->currline->len) curr_buf->currpnt = curr_buf->currline->len; curr_buf->redraw_everything = YEA; - curr_buf->line_dirty = 0; break; } @@ -2358,42 +2823,37 @@ vedit(char *fpath, int saveheader, int *islocal) curr_buf->top_of_win = forward_line(curr_buf->top_of_win, 22); curr_buf->currln = tmp; curr_buf->currline = forward_line(curr_buf->currline, 22); - curr_buf->curr_window_line = getlineno(); + curr_buf->curr_window_line = get_lineno_in_window(); if (curr_buf->currpnt > curr_buf->currline->len) curr_buf->currpnt = curr_buf->currline->len; curr_buf->redraw_everything = YEA; - curr_buf->line_dirty = 0; break; } case KEY_END: case Ctrl('E'): curr_buf->currpnt = curr_buf->currline->len; - curr_buf->line_dirty = 1; break; case Ctrl(']'): /* start of file */ curr_buf->currline = curr_buf->top_of_win = curr_buf->firstline; curr_buf->currpnt = curr_buf->currln = curr_buf->curr_window_line = 0; curr_buf->redraw_everything = YEA; - curr_buf->line_dirty = 0; break; case Ctrl('T'): /* tail of file */ curr_buf->top_of_win = back_line(curr_buf->lastline, 23); curr_buf->currline = curr_buf->lastline; - curr_buf->curr_window_line = getlineno(); + curr_buf->curr_window_line = get_lineno_in_window(); curr_buf->currln = curr_buf->totaln; curr_buf->redraw_everything = YEA; curr_buf->currpnt = 0; - curr_buf->line_dirty = 0; break; case KEY_HOME: case Ctrl('A'): curr_buf->currpnt = 0; - curr_buf->line_dirty = 1; break; case KEY_INS: /* Toggle insert/overwrite */ case Ctrl('O'): - if (curr_buf->blockln >= 0 && curr_buf->insert_character) { + if (has_block_selection() && curr_buf->insert_mode) { char ans[4]; getdata(b_lines - 1, 0, @@ -2401,14 +2861,12 @@ vedit(char *fpath, int saveheader, int *islocal) ans, sizeof(ans), LCECHO); curr_buf->insert_c = ans[0] ? ans[0] : ' '; } - curr_buf->insert_character ^= 1; - curr_buf->line_dirty = 1; + curr_buf->insert_mode ^= 1; break; case Ctrl('H'): case '\177': /* backspace */ - curr_buf->line_dirty = 1; - if (curr_buf->my_ansimode) { - curr_buf->my_ansimode = 0; + if (curr_buf->ansimode) { + curr_buf->ansimode = 0; clear(); curr_buf->redraw_everything = YEA; } else { @@ -2417,18 +2875,18 @@ vedit(char *fpath, int saveheader, int *islocal) if (!curr_buf->currline->prev) break; - curr_buf->line_dirty = 0; curr_buf->curr_window_line--; curr_buf->currln--; + + curr_buf->currline = adjustline(curr_buf->currline, curr_buf->currline->len); curr_buf->currline = curr_buf->currline->prev; curr_buf->currline = adjustline(curr_buf->currline, WRAPMARGIN); - // FIXME dirty fix. would this cause memory leak? oldcurrline = curr_buf->currline; curr_buf->currpnt = curr_buf->currline->len; curr_buf->redraw_everything = YEA; - if (*killsp(curr_buf->currline->next->data) == '\0') { + if (*next_non_space_char(curr_buf->currline->next->data) == '\0') { delete_line(curr_buf->currline->next); break; } @@ -2448,7 +2906,6 @@ vedit(char *fpath, int saveheader, int *islocal) break; case Ctrl('D'): case KEY_DEL: /* delete current character */ - curr_buf->line_dirty = 1; if (curr_buf->currline->len == curr_buf->currpnt) { textline_t *p = curr_buf->currline; @@ -2459,11 +2916,10 @@ vedit(char *fpath, int saveheader, int *islocal) abort_bbs(0); } } - curr_buf->line_dirty = 0; curr_buf->redraw_everything = YEA; } else { delete_char(); - if (curr_buf->my_ansimode) + if (curr_buf->ansimode) curr_buf->currpnt = ansi2n(n2ansi(curr_buf->currpnt, curr_buf->currline), curr_buf->currline); } break; @@ -2474,8 +2930,10 @@ vedit(char *fpath, int saveheader, int *islocal) textline_t *p = curr_buf->currline->next; if (!p) { p = curr_buf->currline->prev; - if (!p) + if (!p) { + curr_buf->currline->data[0] = 0; break; + } if (curr_buf->curr_window_line > 0) { curr_buf->curr_window_line--; curr_buf->currln--; @@ -2483,14 +2941,16 @@ vedit(char *fpath, int saveheader, int *islocal) } if (curr_buf->currline == curr_buf->top_of_win) curr_buf->top_of_win = p; + delete_line(curr_buf->currline); + set_deleted_line(curr_buf->currline); curr_buf->currline = p; + curr_buf->redraw_everything = YEA; - curr_buf->line_dirty = 0; oldcurrline = curr_buf->currline = adjustline(curr_buf->currline, WRAPMARGIN); break; } - if (curr_buf->currline->len == curr_buf->currpnt) { + else if (curr_buf->currline->len == curr_buf->currpnt) { textline_t *p = curr_buf->currline; while (!join(p)) { @@ -2501,43 +2961,25 @@ vedit(char *fpath, int saveheader, int *islocal) } } curr_buf->redraw_everything = YEA; - curr_buf->line_dirty = 0; break; } curr_buf->currline->len = curr_buf->currpnt; curr_buf->currline->data[curr_buf->currpnt] = '\0'; - curr_buf->line_dirty = 1; break; } + if (curr_buf->currln < 0) curr_buf->currln = 0; - if (curr_buf->curr_window_line < 0) { - curr_buf->curr_window_line = 0; - if (!curr_buf->top_of_win->prev) - indigestion(6); - else { - curr_buf->top_of_win = curr_buf->top_of_win->prev; - rscroll(); - } - } - if (curr_buf->curr_window_line == b_lines || - (curr_buf->phone_mode && curr_buf->curr_window_line == b_lines - 1)) { + + if (curr_buf->curr_window_line < 0) + window_scroll_down(); + else if (cursor_at_bottom_line()) { if(curr_buf->phone_mode) - curr_buf->curr_window_line = t_lines - 3; + curr_buf->curr_window_line = b_lines - 2; else - curr_buf->curr_window_line = t_lines - 2; + curr_buf->curr_window_line = b_lines - 1; - if (!curr_buf->top_of_win->next) - indigestion(7); - else { - curr_buf->top_of_win = curr_buf->top_of_win->next; - if(curr_buf->phone_mode) - move(b_lines-1, 0); - else - move(b_lines, 0); - clrtoeol(); - scroll(); - } + window_scroll_up(); } } if (curr_buf->currpnt < t_columns - 1) @@ -2546,13 +2988,13 @@ vedit(char *fpath, int saveheader, int *islocal) curr_buf->edit_margin = curr_buf->currpnt / (t_columns - 8) * (t_columns - 8); if (!curr_buf->redraw_everything) { - if (curr_buf->edit_margin != last_margin) { - last_margin = curr_buf->edit_margin; + if (curr_buf->edit_margin != curr_buf->last_margin) { + curr_buf->last_margin = curr_buf->edit_margin; curr_buf->redraw_everything = YEA; } else { move(curr_buf->curr_window_line, 0); clrtoeol(); - if (curr_buf->my_ansimode) + if (curr_buf->ansimode) outs(curr_buf->currline->data); else edit_outs(&curr_buf->currline->data[curr_buf->edit_margin]); diff --git a/mbbsd/screen.c b/mbbsd/screen.c index 3232b1af..49ff84a2 100644 --- a/mbbsd/screen.c +++ b/mbbsd/screen.c @@ -354,15 +354,27 @@ outc(unsigned char c) #endif } -int +/** + * Just like outs, but print out '*' instead of 27(decimal) in the given string. + * + * FIXME column could not start from 0 + */ +void edit_outs(const char *text) { register int column = 0; register char ch; while ((ch = *text++) && (++column < t_columns)) outc(ch == 27 ? '*' : ch); +} - return 0; +void +edit_outs_n(const char *text, int n) +{ + register int column = 0; + register char ch; + while ((ch = *text++) && n-- && (++column < t_columns)) + outc(ch == 27 ? '*' : ch); } void @@ -373,6 +385,14 @@ outs(const char *str) } } +void +outs_n(const char *str, int n) +{ + while (*str && n--) { + outc(*str++); + } +} + /* Jaky */ void out_lines(const char *str, int line) -- cgit v1.2.3