summaryrefslogtreecommitdiffstats
path: root/console/edit.c
diff options
context:
space:
mode:
Diffstat (limited to 'console/edit.c')
-rw-r--r--console/edit.c3886
1 files changed, 3886 insertions, 0 deletions
diff --git a/console/edit.c b/console/edit.c
new file mode 100644
index 00000000..c6b3a544
--- /dev/null
+++ b/console/edit.c
@@ -0,0 +1,3886 @@
+/* $Id$ */
+/**
+ * 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ªº
+ * ª©¥» (Revision 782)
+ *
+ * ­ì¥» ve ªº°µªk¬O, ¦]¬°¨C¤@¦æ³Ì¤j¥i¥H¿é¤J WRAPMARGIN ­Ó¦r, ©ó¬O´N´À¨C¤@
+ * ¦æ«O¯d¤F WRAPMARGIN ³o»ò¤jªºªÅ¶¡ (¬ù 512 bytes) . ¦ý¬O¹ê»Ú¤W, ¯¸¦b­×¥¿
+ * ¦¨¥»³Ì¤pªº¦Ò¶q¤W, §Ú­Ì¥u¶·­n¨Ï±o´å¼Ð©Ò¦b³o¤@¦æºû«ù WRAPMARGIN ³o»ò¤j,
+ * ¨ä¥L¨C¤@¦æ¨ä¹ê¤£¶·­n³o»ò¦hªºªÅ¶¡. ©ó¬O³o­Ó patch´N¦b¨C¦¸´å¼Ð¦b¦æ¶¡²¾°Ê
+ * ªº®É­Ô, ±N­ì¥»ªº¨º¦æ°O¾ÐÅéÁY¤p, ¦A±N·s²¾¨ìªº¨º¦æ­«·s¥[¤j, ¥H¹F¦¨³Ì¤pªº
+ * °O¾ÐÅé¥Î¶q.
+ * ¥H¤W»¡ªº³o­Ó°Ê§@¦b adjustline() ¤¤§¹¦¨, adjustline()¥t¥~¥]¬A­×¥¿¼Æ­Ó
+ * global pointer, ¥HÁקK dangling pointer .
+ * ¥t¥~­Y©w¸q DEBUG, ¦b textline_t µ²ºc¤¤±N¥[¤J mlength, ªí¥Ü¸Ó¦æ¹ê»Ú¦ûªº
+ * °O¾ÐÅé¤j¤p. ¥H¤è«K´ú¸Õµ²ªG.
+ * ³o­Óª©¥»¦ü¥GÁÙ¦³¦a¤è¨S¦³­×¥¿¦n, ¥i¯à¾É­P segmentation fault .
+ *
+ * FIXME ¦b°Ï¶ô¼Ð°O¼Ò¦¡(blockln>=0)¤¤¹ï¼W§R­×§ï¥i¯à·|³y¦¨ blockln, blockpnt,
+ * and/or blockline ¿ù»~. ¬Æ¦Ü§â blockline ¬å±¼·| access ¨ì¤w³Q free ±¼ªº
+ * memory. ¥i¯à­n§ï¦¨¼Ð°O¼Ò¦¡ readonly, ©Î¬O°µ¬Y¨Ç°Ê§@®É¦Û°Ê¨ú®ø¼Ð°O¼Ò¦¡
+ * (blockln=-1)
+ *
+ * FIXME 20071201 piaip
+ * block selection ¤£ª¾¦ó®É¤wÅܬ° line level ¦Ó«D character level ¤F¡A
+ * ³o¼Ë¤]¤ñ¸û¦n¼g¡A©Ò¥H§â blockpnt ®³±¼§a¡I
+ *
+ * 20071230 piaip
+ * BBSmovie ¦³¤H§@¥X¤F 1.9G ªºÀÉ®×, ¬Ý¨Ó­n¤À hard limit ¸ò soft limit
+ * [²Ä 7426572/7426572 ­¶ (100%) ¥Ø«eÅã¥Ü: ²Ä 163384551~163384573 ¦æ]
+ * ·í¤é½Õ¬d BBSmovie ¬ÝªO»PºëµØ°Ï¡A¥­§¡Àɮ׬Ҧb 5M ¥H¤U
+ * ³Ì¤jªº¬° 16M ªº Haruhi OP (avi ÂàÀÉ with massive ANSI)
+ * [²Ä 2953/2953 ­¶ (100%) ¥Ø«eÅã¥Ü: ²Ä 64942~64964 ¦æ]
+ * ¥t¥~¤¬°Ê°g®cªº¤j¤p¬°
+ * [²Ä 1408/1408 ­¶ (100%) ¥Ø«eÅã¥Ü: ²Ä 30940~30962 ¦æ]
+ * ¬O¥H©w¸q:
+ * 32M ¬° size limit
+ * 1M ¬° line limit
+ * ¤S¡A©¿µMµo²{¤§«e totaln ¤§Ãþ³£¬O short... ©Ò¥H 65536 ´N°÷¤F?
+ * «áµù: ¦ü¥G¬O¥Î announce ªº append §@¥X¨Óªº¡A¦³¬Ý¨ì > --- <- mark¡C
+ */
+#include "bbs.h"
+
+#define EDIT_SIZE_LIMIT (32768*1024)
+#define EDIT_LINE_LIMIT (65530) // (1048576)
+
+#if 0
+#define register
+#define DEBUG
+#define inline
+#endif
+
+/**
+ * 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;
+ short len;
+#ifdef DEBUG
+ short mlength;
+#endif
+ char data[1];
+} textline_t;
+
+#define KEEP_EDITING -2
+
+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¦³¤°»ò¥Î? ¬Ý°_¨Ó¬O modem ¤W¶Ç¥Î (¨S¤H¦b¥Î³o­Ó¤F§a)
+ * ®³¨Ó·í dbcs option §a
+ *
+ * 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
+ *
+ * TODO
+ * vedit ¸Ì­±¦³­Ó curr_buf->oldcurrline¡A¥Î¨Ó°O¤W¤@¦¸ªº currline¡C¥Ñ©ó¥u¦³ currline ¾Ö
+ * ¦³ WRAPMARGIN ªºªÅ¶¡¡A©Ò¥H¥Ø«eªº§@ªk¬O·í curr_buf->oldcurrline != currline ®É¡A´N
+ * resize curr_buf->oldcurrline ¸ò currline¡C¦ý¬OÁV¿|ªº¬O¥Ø«e¥²¶·¤H¤u°lÂÜ currline ªº¦æ
+ * ¬°¡A¦Ó¥B­Y¤£©¯¹J¨ì curr_buf->oldcurrline «ü¨ìªº¨º¤@¦æ¤w¸g³Q free ±¼¡A´N§¹¤F¡C³Ì¦n¬O
+ * §â³o¨ÇªF¦è¥]°_¨Ó¡C¤£¹L§Ú¨SªÅ°µ¤F¡Apatch is welcome :P
+ *
+ * Victor Hsieh <victor@csie.org>
+ * Thu, 03 Feb 2005 15:18:00 +0800
+ */
+typedef struct editor_internal_t {
+
+ 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. */
+ textline_t *oldcurrline;
+
+ int currln; /* current line of the article. */
+ short currpnt; /* current column of the article. */
+ int totaln; /* total lines of the article. */
+ int 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;
+ int blockln; /* the row 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 insert_mode :1;
+ char ansimode :1;
+ char indent_mode :1;
+ char phone_mode :1;
+ char raw_mode :1;
+
+ char *searched_string;
+ char *sitesig_string;
+ char *(*substr_fp) ();
+
+ char synparser; // syntax parser
+
+ struct editor_internal_t *prev;
+
+} editor_internal_t;
+// } __attribute__ ((packed))
+
+static editor_internal_t *curr_buf = NULL;
+
+static const char fp_bak[] = "bak";
+
+static const char * const 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ùþ ",
+ "¡³¡ó¡·¡´¡¸¡¹¡¼¡½¡¿¡¶¡¾¡µ¡º¡»¡ð¡ñ",
+ "¡Ë¡\\¡[¡Â¡Ä¡X¡ü¡ý¢y¡þ¢@¢®¢¬¢­¢A¢B",
+ "¡Ï¡Ð¡Ñ¡Ò¡Ô¡Ó¡×¡Ý¡Ú¡Ü¡Ø¡Ù¡Õ¡Ö¡î¡ï",
+ "¡Û¡ã¡ä¡å¡ì¡í¡®¡æ¡ç¡è¡é¡Þ¡ß¡à¡á¡â",
+ "¡ô¡õ¡ö¡÷¡ø¡ù¡ú¡û",
+ "¡i¡j¡u¡v¡y¡z¡q¡r¡m¡n¡e¡f¡a¡b¡_¡`",
+ "¡g¡h¡c¡d¡k¡l¡s¡t¡o¡p¡w¡x¡{¡|",
+ "¢¨¢©¢ª¢«¡Î¡¯¡°¡±¢I¡ò¡À¡K¡L¡Æ¡È",
+ "£\\£]£^£_£`£a£b£c£d£e£f£g£h£i£j£k",
+ "£l£m£n£o£p£q£r£s£G£K£N£S£U£X£Z£[",
+ "¢¹¢º¢»¢¼¢½¢¾¢¿¢À¢Á¢Â"
+};
+
+static const char * const BIG_mode[13] = {
+ "¼ÐÂI",
+ "¹Ï¶ô",
+ "¼Ð°O",
+ "¼Ð½u",
+ "¼Æ¤@",
+ "¼Æ¤G",
+ "½bÀY",
+ "¬A¤@",
+ "¬A¤G",
+ "¨ä¥L",
+ "§Æ¤@",
+ "§Æ¤G",
+ "¼Æ¦r"
+};
+
+static const char *table[8] = {
+ "¢x¢w¢|¢r¢}¢u¢q¢t¢z¢s¢{",
+ "ùø¢¤ùãùäùåùàùáùâùÝùÞùß",
+ "ùø¢wùõùöù÷ùòùóùôùïùðùñ",
+ "¢x¢¤ùìùíù¢¦¢§ùæùçùè",
+ "¢x¢w¢¢¢r¢£¢u¢q¢t¢~¢s¢¡",
+ "ùø¢¤¢¢ù䢣ùàùáùâ¢~ùÞ¢¡",
+ "ùø¢wùõùöù÷ùòùóùôùïùðùñ",
+ "¢x¢¤ùìùíù¢¦¢§ùæùçùè"
+};
+
+static const char *table_mode[6] = {
+ "ª½¨¤",
+ "Ås©·",
+ "¢q",
+ "ùá",
+ "ùó",
+ "¢¦"
+};
+
+#ifdef DBCSAWARE
+static char mbcs_mode =1;
+
+#define IS_BIG5_HI(x) (0x81 <= (x) && (x) <= 0xfe)
+#define IS_BIG5_LOS(x) (0x40 <= (x) && (x) <= 0x7e)
+#define IS_BIG5_LOE(x) (0x80 <= (x) && (x) <= 0xfe)
+#define IS_BIG5_LO(x) (IS_BIG5_LOS(x) || IS_BIG5_LOE(x))
+#define IS_BIG5(hi,lo) (IS_BIG5_HI(hi) && IS_BIG5_LO(lo))
+
+int mchar_len(unsigned char *str)
+{
+ return ((str[0] != '\0' && str[1] != '\0' && IS_BIG5(str[0], str[1])) ?
+ 2 :
+ 1);
+}
+
+#define FC_RIGHT (0)
+#define FC_LEFT (~FC_RIGHT)
+
+int fix_cursor(char *str, int pos, unsigned int dir)
+{
+ int newpos, w;
+
+ for(newpos = 0;
+ *str != '\0' &&
+ (w = mchar_len((unsigned char*)str),
+ newpos + 1 + (dir & (w - 1))) <= pos;
+ str += w, newpos += w)
+ ;
+
+ return newpos;
+}
+
+#endif
+
+/* °O¾ÐÅéºÞ²z»P½s¿è³B²z */
+static void
+indigestion(int i)
+{
+ vmsgf("ÄY­«¤º¶Ë (%d)\n", i);
+ u_exit("EDITOR FAILED");
+ assert(0);
+ exit(0);
+}
+
+static inline void
+edit_buffer_constructor(editor_internal_t *buf)
+{
+ /* all unspecified columns are 0 */
+ buf->blockln = -1;
+ buf->insert_c = ' ';
+ buf->insert_mode = 1;
+ buf->redraw_everything = 1;
+ buf->lastindent = -1;
+}
+
+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
+free_line(textline_t *p)
+{
+ p->next = (textline_t*)0x12345678;
+ p->prev = (textline_t*)0x87654321;
+ p->len = -12345;
+ free(p);
+}
+
+static inline void
+edit_buffer_destructor(void)
+{
+ if (curr_buf->deleted_line != NULL)
+ free_line(curr_buf->deleted_line);
+
+ if (curr_buf->searched_string != NULL)
+ free(curr_buf->searched_string);
+ if (curr_buf->sitesig_string != NULL)
+ free(curr_buf->sitesig_string);
+}
+
+static inline void
+exit_edit_buffer(void)
+{
+ editor_internal_t *p = curr_buf;
+
+ edit_buffer_destructor();
+ curr_buf = p->prev;
+ free(p);
+}
+
+/**
+ * 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)
+{
+ register char *data, *tmp;
+ register char ch;
+
+ data = tmp = line->data;
+
+ while (*tmp) {
+ if (*tmp == KEY_ESC) {
+ while ((ch = *tmp) && !isalpha((int)ch))
+ tmp++;
+ if (ch)
+ tmp++;
+ continue;
+ }
+ if (ansix <= 0)
+ break;
+ tmp++;
+ ansix--;
+ }
+ 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)
+{
+ register short ansix = 0;
+ register char *tmp, *nxp;
+ register char ch;
+
+ tmp = nxp = line->data;
+ nxp += nx;
+
+ while (*tmp) {
+ if (*tmp == KEY_ESC) {
+ while ((ch = *tmp) && !isalpha((int)ch))
+ tmp++;
+ if (ch)
+ tmp++;
+ continue;
+ }
+ if (tmp >= nxp)
+ break;
+ tmp++;
+ ansix++;
+ }
+ return ansix;
+}
+
+/* ¿Ã¹õ³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(ANSI_COLOR(1;46) "¡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(ANSI_COLOR(37) "%c" ANSI_COLOR(34) "%2.2s",
+ i + 'A', BIG5[curr_buf->last_phone_mode - 1] + i * 2);
+ for (i = 0; i < 16 - len; i++)
+ outs(" ");
+ outs(ANSI_COLOR(37) " `1~9-=¤Á´« Zªí®æ" ANSI_RESET);
+ }
+ else {
+ prints(ANSI_COLOR(1;46) "¡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(ANSI_COLOR(37) "%c" ANSI_COLOR(34) "%2.2s", i ? i + '/' : '.',
+ table[curr_buf->last_phone_mode - 20] + i * 2);
+ outs(ANSI_COLOR(37) " Z¤º½X " ANSI_RESET);
+ }
+}
+
+/**
+ * Show the bottom status/help bar, and BIG5/table in phone_mode.
+ */
+static void
+edit_msg(void)
+{
+ int n = curr_buf->currpnt;
+
+ if (curr_buf->ansimode) /* Thor: §@ ansi ½s¿è */
+ n = n2ansi(n, curr_buf->currline);
+
+ if (curr_buf->phone_mode)
+ show_phone_mode_panel();
+
+ move(b_lines, 0);
+ clrtoeol();
+ outs( ANSI_COLOR(37;44) " ½s¿è¤å³¹ "
+ ANSI_COLOR(31;47) " (^Z/F1)" ANSI_COLOR(30) "»¡©ú "
+ ANSI_COLOR(31;47) "(^P/^G)" ANSI_COLOR(30) "´¡¤J²Å¸¹/¹Ï¤ù "
+ ANSI_COLOR(31) "(^X/^Q)" ANSI_COLOR(30) "Â÷¶}");
+
+ prints( "ùø%s¢x%c%c%c%cùø %3d:%3d ",
+ 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 + 1);
+ outslr("", 78, ANSI_RESET, 0);
+}
+
+/**
+ * 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)
+{
+ while (num-- > 0) {
+ register textline_t *item;
+
+ if (pos && (item = pos->prev)) {
+ pos = item;
+ curr_buf->currln--;
+ }
+ else
+ break;
+ }
+ return pos;
+}
+
+/* calculate if cursor is at bottom, scroll required?
+ * currently vedit does NOT handle if curr_window_line > b_lines,
+ * take care if you changed curr_window_line!
+ */
+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);
+}
+
+
+/**
+ * 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)
+{
+ while (num-- > 0) {
+ register textline_t *item;
+
+ if (pos && (item = pos->next)) {
+ 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)
+{
+ curr_buf->curr_window_line = b_lines - (curr_buf->phone_mode ? 2 : 1);
+
+ 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
+get_lineno_in_window(void)
+{
+ int cnt = 0;
+ textline_t *p = curr_buf->currline;
+
+ while (p && (p != curr_buf->top_of_win)) {
+ cnt++;
+ p = p->prev;
+ }
+ return cnt;
+}
+
+/**
+ * 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)
+{
+ textline_t *p;
+
+ if ((p = (textline_t *) malloc(length + sizeof(textline_t)))) {
+ memset(p, 0, length + sizeof(textline_t));
+#ifdef DEBUG
+ p->mlength = length;
+#endif
+ return p;
+ }
+ indigestion(13);
+ abort_bbs(0);
+ return NULL;
+}
+
+/**
+ * Insert p after line in list. Keeps up with last line
+ */
+static void
+insert_line(textline_t *line, textline_t *p)
+{
+ textline_t *n;
+
+ if ((p->next = n = line->next))
+ n->prev = p;
+ else
+ curr_buf->lastline = p;
+ line->next = p;
+ p->prev = line;
+}
+
+/**
+ * delete_line deletes 'line' from the line list.
+ * @param saved true if you want to keep the line in deleted_line
+ */
+static void
+delete_line(textline_t * line, int saved)
+{
+ register textline_t *p = line->prev;
+ register textline_t *n = line->next;
+
+ if (!p && !n) {
+ line->data[0] = line->len = 0;
+ return;
+ }
+ assert(line != curr_buf->top_of_win);
+ if (n)
+ n->prev = p;
+ else
+ curr_buf->lastline = p;
+ if (p)
+ p->next = n;
+ else
+ curr_buf->firstline = n;
+
+ curr_buf->totaln--;
+
+ if (saved) {
+ if (curr_buf->deleted_line != NULL)
+ free_line(curr_buf->deleted_line);
+ curr_buf->deleted_line = line;
+ curr_buf->deleted_line->next = NULL;
+ curr_buf->deleted_line->prev = NULL;
+ }
+ else {
+ free_line(line);
+ }
+}
+
+/**
+ * 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_space(void)
+{
+ textline_t *p;
+ int spcs;
+
+ if (!curr_buf->indent_mode)
+ return 0;
+
+ 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»òªø.
+ *
+ * ©I¥s¤F adjustline «á°O±oÀˬd¦³°Ê¨ì currline, ¦pªG¬Oªº¸Ü oldcurrline ¤]­n°Ê
+ *
+ * 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)
+{
+ // XXX write a generic version ?
+ char tmpl[sizeof(textline_t) + WRAPMARGIN];
+ textline_t *newp;
+
+#ifdef deBUG
+ if(oldp->len > WRAPMARGIN || oldp->len < 0) {
+ kill(currpid, SIGSEGV);
+ }
+#endif
+
+ memcpy(tmpl, oldp, oldp->len + sizeof(textline_t));
+ free_line(oldp);
+
+ newp = alloc_line(len);
+ memcpy(newp, tmpl, len + sizeof(textline_t));
+#ifdef DEBUG
+ newp->mlength = len;
+#endif
+ if( oldp == curr_buf->firstline ) curr_buf->firstline = newp;
+ if( oldp == curr_buf->lastline ) curr_buf->lastline = newp;
+ if( oldp == curr_buf->currline ) curr_buf->currline = newp;
+ if( oldp == curr_buf->blockline ) curr_buf->blockline = newp;
+ if( oldp == curr_buf->top_of_win) curr_buf->top_of_win= newp;
+ if( newp->prev != NULL ) newp->prev->next = newp;
+ if( newp->next != NULL ) newp->next->prev = newp;
+ // vmsg("adjust %x to %x, length: %d", (int)oldp, (int)newp, len);
+ return newp;
+}
+
+/**
+ * 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_space();
+
+ curr_buf->totaln++;
+
+ p->len = line->len - pos + spcs;
+ line->len = pos;
+
+ memset(p->data, ' ', spcs);
+ p->data[spcs] = 0;
+
+ ptr = line->data + pos;
+ if (curr_buf->indent_mode)
+ ptr = next_non_space_char(ptr);
+ strcat(p->data + spcs, ptr);
+ ptr[0] = '\0';
+
+ if (line == curr_buf->currline && pos <= curr_buf->currpnt) {
+ line = adjustline(line, line->len);
+ insert_line(line, p);
+ // because p is allocated with fullsize, we can skip adjust.
+ // curr_buf->oldcurrline = line;
+ curr_buf->oldcurrline = curr_buf->currline = p;
+ if (pos == curr_buf->currpnt)
+ curr_buf->currpnt = spcs;
+ else
+ curr_buf->currpnt -= pos;
+ curr_buf->curr_window_line++;
+ curr_buf->currln++;
+
+ /* split may cause cursor hit bottom */
+ if (cursor_at_bottom_line())
+ window_scroll_up();
+ } else {
+ p = adjustline(p, p->len);
+ insert_line(line, p);
+ }
+ curr_buf->redraw_everything = YEA;
+ }
+ 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)
+{
+ register textline_t *p = curr_buf->currline;
+ register int i = p->len;
+ register char *s;
+ int wordwrap = YEA;
+
+ if (curr_buf->currpnt > i) {
+ indigestion(1);
+ return;
+ }
+ 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->ansimode)
+ curr_buf->currpnt = ansi2n(n2ansi(curr_buf->currpnt, p), p);
+ } else {
+ raw_shift_right(p->data + curr_buf->currpnt, i - curr_buf->currpnt + 1);
+ p->data[curr_buf->currpnt++] = ch;
+ i = ++(p->len);
+ }
+ if (i < WRAPMARGIN)
+ return;
+ s = p->data + (i - 1);
+ while (s != p->data && *s == ' ')
+ s--;
+ while (s != p->data && *s != ' ')
+ s--;
+ if (s == p->data) {
+ wordwrap = NA;
+ s = p->data + (i - 2);
+ }
+ p = split(p, (s - p->data) + 1);
+ p = p->next;
+ i = p->len;
+ if (wordwrap && i >= 1) {
+ if (p->data[i - 1] != ' ') {
+ p->data[i] = ' ';
+ p->data[i + 1] = '\0';
+ p->len++;
+ }
+ }
+}
+
+/**
+ * insert_char twice.
+ */
+static void
+insert_dchar(const char *dchar)
+{
+ insert_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 ESC_CHR 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)
+{
+ char ch;
+
+ while ((ch = *str++)) {
+ if (isprint2(ch) || ch == ESC_CHR)
+ insert_char(ch);
+ else if (ch == '\t')
+ insert_tab();
+ else if (ch == '\n')
+ split(curr_buf->currline, curr_buf->currpnt);
+ }
+}
+
+/**
+ * undelete the deleted line.
+ *
+ * return NULL if there's no deleted_line, otherwise, return currline.
+ */
+static textline_t *
+undelete_line(void)
+{
+ editor_internal_t tmp;
+
+ if (!curr_buf->deleted_line)
+ return NULL;
+
+ tmp.top_of_win = curr_buf->top_of_win;
+ tmp.indent_mode = curr_buf->indent_mode;
+ tmp.curr_window_line = curr_buf->curr_window_line;
+
+ curr_buf->indent_mode = 0;
+ curr_buf->currpnt = 0;
+ curr_buf->currln++;
+ insert_string(curr_buf->deleted_line->data);
+ insert_string("\n");
+
+ curr_buf->top_of_win = tmp.top_of_win;
+ curr_buf->indent_mode = tmp.indent_mode;
+ curr_buf->curr_window_line = tmp.curr_window_line;
+
+ assert(curr_buf->currline->prev);
+ 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);
+ curr_buf->oldcurrline = curr_buf->currline;
+
+ if (curr_buf->currline->prev == NULL) {
+ curr_buf->top_of_win = curr_buf->currline;
+ curr_buf->currln = 0;
+ }
+ return curr_buf->currline;
+}
+
+/*
+ * join $line and $line->next
+ *
+ * line: A1 A2
+ * next: B1 B2
+ * ....: C1 C2
+ *
+ * case B=empty:
+ * return YEA
+ *
+ * case A+B < WRAPMARGIN:
+ * line: A1 A2 B1 B2
+ * next: C1 C2
+ * return YEA
+ * NOTE It assumes $line has allocated WRAPMARGIN length of data buffer.
+ *
+ * case A+B1+B2 > WRAPMARGIN, A+B1<WRAPMARGIN
+ * line: A1 A2 B1
+ * next: B2 " "
+ * call join($next)
+ */
+static int
+join(textline_t * line)
+{
+ register textline_t *n;
+ register int ovfl;
+
+ if (!(n = line->next))
+ return YEA;
+ if (!*next_non_space_char(n->data))
+ return YEA;
+
+ ovfl = line->len + n->len - WRAPMARGIN;
+ if (ovfl < 0) {
+ strcat(line->data, n->data);
+ line->len += n->len;
+ delete_line(n, 0);
+ return YEA;
+ } else {
+ register char *s; /* the split point */
+
+ s = n->data + n->len - ovfl - 1;
+ while (s != n->data && *s == ' ')
+ s--;
+ while (s != n->data && *s != ' ')
+ s--;
+ if (s == n->data)
+ return YEA;
+ split(n, (s - n->data) + 1);
+ if (line->len + line->next->len >= WRAPMARGIN) {
+ indigestion(0);
+ return YEA;
+ }
+ join(line);
+ n = line->next;
+ ovfl = n->len - 1;
+ if (ovfl >= 0 && ovfl < WRAPMARGIN - 2) {
+ s = &(n->data[ovfl]);
+ if (*s != ' ') {
+ strcpy(s, " ");
+ n->len++;
+ }
+ }
+ line->next=adjustline(line->next, WRAPMARGIN);
+ join(line->next);
+ line->next=adjustline(line->next, line->next->len);
+ return NA;
+ }
+}
+
+static void
+delete_char(void)
+{
+ register int len;
+
+ if ((len = curr_buf->currline->len)) {
+ if (unlikely(curr_buf->currpnt >= len)) {
+ indigestion(1);
+ return;
+ }
+ 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, off_t offSig)
+{
+ char buf[WRAPMARGIN + 2];
+ int indent_mode0 = curr_buf->indent_mode;
+ size_t szread = 0;
+
+ assert(fp);
+ curr_buf->indent_mode = 0;
+ while (fgets(buf, sizeof(buf), fp))
+ {
+ szread += strlen(buf);
+ if (offSig < 0 || szread <= offSig)
+ {
+ insert_string(buf);
+ }
+ else
+ {
+ // this is the site sig
+ break;
+ }
+ }
+ curr_buf->indent_mode = indent_mode0;
+}
+
+/* ¼È¦sÀÉ */
+char *
+ask_tmpbuf(int y)
+{
+ static char fp_buf[10] = "buf.0";
+ static char msg[] = "½Ð¿ï¾Ü¼È¦sÀÉ (0-9)[0]: ";
+
+ msg[19] = fp_buf[4];
+ do {
+ if (!getdata(y, 0, msg, fp_buf + 4, 4, DOECHO))
+ fp_buf[4] = msg[19];
+ } while (fp_buf[4] < '0' || fp_buf[4] > '9');
+ return fp_buf;
+}
+
+static void
+read_tmpbuf(int n)
+{
+ FILE *fp;
+ char fp_tmpbuf[80];
+ char tmpfname[] = "buf.0";
+ char *tmpf;
+ char ans[4] = "y";
+
+ if (curr_buf->totaln >= EDIT_LINE_LIMIT)
+ {
+ vmsg("Àɮפw¶W¹L³Ì¤j­­¨î¡AµLªk¦AŪ¤J¼È¦sÀÉ¡C");
+ return;
+ }
+
+ if (0 <= n && n <= 9) {
+ tmpfname[4] = '0' + n;
+ tmpf = tmpfname;
+ } else {
+ tmpf = ask_tmpbuf(3);
+ n = tmpf[4] - '0';
+ }
+
+ setuserfile(fp_tmpbuf, tmpf);
+ if (n != 0 && n != 5 && more(fp_tmpbuf, NA) != -1)
+ 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, -1);
+ 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;
+ }
+ }
+}
+
+static void
+write_tmpbuf(void)
+{
+ FILE *fp;
+ char fp_tmpbuf[80], ans[4];
+ textline_t *p;
+ off_t sz = 0;
+
+ setuserfile(fp_tmpbuf, ask_tmpbuf(3));
+ if (dashf(fp_tmpbuf)) {
+ more(fp_tmpbuf, NA);
+ getdata(b_lines - 1, 0, "¼È¦sÀɤw¦³¸ê®Æ (A)ªþ¥[ (W)Âмg (Q)¨ú®ø¡H[A] ",
+ ans, sizeof(ans), LCECHO);
+
+ if (ans[0] == 'q')
+ return;
+ }
+ if (ans[0] != 'w') // 'a'
+ {
+ sz = dashs(fp_tmpbuf);
+ if (sz > EDIT_SIZE_LIMIT)
+ {
+ vmsg("¼È¦sÀɤw¶W¹L¤j¤p­­¨î¡AµLªk¦Aªþ¥[¡C");
+ return;
+ }
+ }
+ if ((fp = fopen(fp_tmpbuf, (ans[0] == 'w' ? "w" : "a+")))) {
+ for (p = curr_buf->firstline; p; p = p->next) {
+ if (p->next || p->data[0])
+ fprintf(fp, "%s\n", p->data);
+ }
+ fclose(fp);
+ }
+}
+
+static void
+erase_tmpbuf(void)
+{
+ char fp_tmpbuf[80];
+ char ans[4] = "n";
+
+ setuserfile(fp_tmpbuf, ask_tmpbuf(3));
+ if (more(fp_tmpbuf, NA) != -1)
+ getdata(b_lines - 1, 0, "½T©w§R°£¶Ü(Y/N)?[N]",
+ ans, sizeof(ans), LCECHO);
+ if (*ans == 'y')
+ unlink(fp_tmpbuf);
+}
+
+/**
+ * ½s¿è¾¹¦Û°Ê³Æ¥÷
+ *(³Ì¦h³Æ¥÷ 512 ¦æ (?))
+ */
+void
+auto_backup(void)
+{
+ if (curr_buf == NULL)
+ return;
+
+ if (curr_buf->currline) {
+ FILE *fp;
+ textline_t *p, *v;
+ char bakfile[PATHLEN];
+ int count = 0;
+
+ setuserfile(bakfile, fp_bak);
+ if ((fp = fopen(bakfile, "w"))) {
+ for (p = curr_buf->firstline; p != NULL && count < 512; p = v, count++) {
+ v = p->next;
+ fprintf(fp, "%s\n", p->data);
+ free_line(p);
+ }
+ fclose(fp);
+ }
+ curr_buf->currline = NULL;
+ }
+}
+
+/**
+ * ¨ú¦^½s¿è¾¹³Æ¥÷
+ */
+void
+restore_backup(void)
+{
+ char bakfile[80], buf[80];
+
+ setuserfile(bakfile, fp_bak);
+ if (dashf(bakfile)) {
+ stand_title("½s¿è¾¹¦Û°Ê´_­ì");
+ getdata(1, 0, "±z¦³¤@½g¤å³¹©|¥¼§¹¦¨¡A(S)¼g¤J¼È¦sÀÉ (Q)ºâ¤F¡H[S] ",
+ buf, 4, LCECHO);
+ if (buf[0] != 'q') {
+ setuserfile(buf, ask_tmpbuf(3));
+ Rename(bakfile, buf);
+ } else
+ unlink(bakfile);
+ }
+}
+
+/* ¤Þ¥Î¤å³¹ */
+
+static int
+garbage_line(const char *str)
+{
+ int qlevel = 0;
+
+ while (*str == ':' || *str == '>') {
+ if (*(++str) == ' ')
+ str++;
+ if (qlevel++ >= 1)
+ return 1;
+ }
+ while (*str == ' ' || *str == '\t')
+ str++;
+ if (qlevel >= 1) {
+ if (!strncmp(str, "¡° ", 3) || !strncmp(str, "==>", 3) ||
+ strstr(str, ") ´£¨ì:\n"))
+ return 1;
+ }
+ return (*str == '\n');
+}
+
+static void
+quote_strip_ansi_inline(unsigned char *is)
+{
+ unsigned char *os = is;
+
+ while (*is)
+ {
+ if(*is != ESC_CHR)
+ *os++ = *is;
+ else
+ {
+ is ++;
+ if(*is == '*')
+ {
+ /* ptt prints, keep it as normal */
+ *os++ = '*';
+ *os++ = '*';
+ }
+ else
+ {
+ /* normal ansi, strip them out. */
+ while (*is && ANSI_IN_ESCAPE(*is))
+ is++;
+ }
+ }
+ is++;
+
+ }
+
+ *os = 0;
+}
+
+static void
+do_quote(void)
+{
+ int op;
+ char buf[512];
+
+ getdata(b_lines - 1, 0, "½Ð°Ý­n¤Þ¥Î­ì¤å¶Ü(Y/N/All/Repost)¡H[Y] ",
+ buf, 3, LCECHO);
+ op = buf[0];
+
+ if (op != 'n') {
+ FILE *inf;
+
+ if ((inf = fopen(quote_file, "r"))) {
+ char *ptr;
+ int indent_mode0 = curr_buf->indent_mode;
+
+ fgets(buf, sizeof(buf), inf);
+ if ((ptr = strrchr(buf, ')')))
+ ptr[1] = '\0';
+ else if ((ptr = strrchr(buf, '\n')))
+ ptr[0] = '\0';
+
+ if ((ptr = strchr(buf, ':'))) {
+ char *str;
+
+ while (*(++ptr) == ' ');
+
+ /* ¶¶¤â²o¦Ï¡A¨ú±o author's address */
+ if ((curredit & EDIT_BOTH) && (str = strchr(quote_user, '.'))) {
+ strcpy(++str, ptr);
+ str = strchr(str, ' ');
+ assert(str);
+ str[0] = '\0';
+ }
+ } else
+ ptr = quote_user;
+
+ curr_buf->indent_mode = 0;
+ insert_string("¡° ¤Þ­z¡m");
+ insert_string(ptr);
+ insert_string("¡n¤§»Ê¨¥¡G\n");
+
+ if (op != 'a') /* ¥h±¼ header */
+ while (fgets(buf, sizeof(buf), inf) && buf[0] != '\n');
+ /* FIXME by MH:
+ ¦pªG header ¨ì¤º¤å¤¤¶¡¨S¦³ªÅ¦æ¤À¹j¡A·|³y¦¨ All ¥H¥~ªº¼Ò¦¡
+ ³£¤Þ¤£¨ì¤º¤å¡C
+ */
+
+ if (op == 'a')
+ while (fgets(buf, sizeof(buf), inf)) {
+ insert_char(':');
+ insert_char(' ');
+ quote_strip_ansi_inline((unsigned char *)buf);
+ insert_string(buf);
+ }
+ else if (op == 'r')
+ while (fgets(buf, sizeof(buf), inf)) {
+ /* repost, keep anything */
+ // quote_strip_ansi_inline((unsigned char *)buf);
+ insert_string(buf);
+ }
+ else {
+ if (curredit & EDIT_LIST) /* ¥h±¼ mail list ¤§ header */
+ while (fgets(buf, sizeof(buf), inf) && (!strncmp(buf, "¡° ", 3)));
+ while (fgets(buf, sizeof(buf), inf)) {
+ if (!strcmp(buf, "--\n"))
+ break;
+ if (!garbage_line(buf)) {
+ insert_char(':');
+ insert_char(' ');
+ quote_strip_ansi_inline((unsigned char *)buf);
+ insert_string(buf);
+ }
+ }
+ }
+ curr_buf->indent_mode = indent_mode0;
+ fclose(inf);
+ }
+ }
+}
+
+/**
+ * ¼f¬d user ¤Þ¨¥ªº¨Ï¥Î
+ */
+static int
+check_quote(void)
+{
+ register textline_t *p = curr_buf->firstline;
+ register char *str;
+ int post_line;
+ int included_line;
+
+ post_line = included_line = 0;
+ while (p) {
+ if (!strcmp(str = p->data, "--"))
+ break;
+ if (str[1] == ' ' && ((str[0] == ':') || (str[0] == '>')))
+ included_line++;
+ else {
+ while (*str == ' ' || *str == '\t')
+ str++;
+ if (*str)
+ post_line++;
+ }
+ p = p->next;
+ }
+
+ if ((included_line >> 2) > post_line) {
+ move(4, 0);
+ outs("¥»½g¤å³¹ªº¤Þ¨¥¤ñ¨Ò¶W¹L 80%¡A½Ð±z°µ¨Ç·Lªº­×¥¿¡G\n\n"
+ ANSI_COLOR(1;33) "1) ¼W¥[¤@¨Ç¤å³¹ ©Î 2) §R°£¤£¥²­n¤§¤Þ¨¥" ANSI_RESET);
+ {
+ char ans[4];
+
+ getdata(12, 12, "(E)Ä~Äò½s¿è (W)±j¨î¼g¤J¡H[E] ",
+ ans, sizeof(ans), LCECHO);
+ if (ans[0] == 'w')
+ return 0;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+/* Àɮ׳B²z¡GŪÀÉ¡B¦sÀÉ¡B¼ÐÃD¡Bñ¦WÀÉ */
+off_t loadsitesig(const char *fname);
+
+static void
+read_file(const char *fpath, int splitSig)
+{
+ FILE *fp;
+ off_t offSig = -1;
+
+ if (splitSig)
+ offSig = loadsitesig(fpath);
+
+ if ((fp = fopen(fpath, "r")) == NULL) {
+ int fd;
+ if ((fd = creat(fpath, 0600)) >= 0) {
+ close(fd);
+ return;
+ }
+ indigestion(4);
+ abort_bbs(0);
+ }
+ load_file(fp, offSig);
+ fclose(fp);
+}
+
+void
+write_header(FILE * fp, char *mytitle) // FIXME unused
+{
+
+ if (curredit & EDIT_MAIL || curredit & EDIT_LIST) {
+ fprintf(fp, "%s %s (%s)\n", str_author1, cuser.userid,
+ cuser.nickname
+ );
+ } else {
+ char *ptr = mytitle;
+ struct {
+ char author[IDLEN + 1];
+ char board[IDLEN + 1];
+ char title[66];
+ time4_t date; /* last post's date */
+ int number; /* post number */
+ } postlog;
+
+ memset(&postlog, 0, sizeof(postlog));
+ strlcpy(postlog.author, cuser.userid, sizeof(postlog.author));
+ if (curr_buf)
+ curr_buf->ifuseanony = 0;
+#ifdef HAVE_ANONYMOUS
+ if (currbrdattr & BRD_ANONYMOUS) {
+ int defanony = (currbrdattr & BRD_DEFAULTANONYMOUS);
+ if (defanony)
+ getdata(3, 0, "½Ð¿é¤J§A·Q¥ÎªºID¡A¤]¥iª½±µ«ö[Enter]¡A"
+ "©Î¬O«ö[r]¥Î¯u¦W¡G", real_name, sizeof(real_name), DOECHO);
+ else
+ getdata(3, 0, "½Ð¿é¤J§A·Q¥ÎªºID¡A¤]¥iª½±µ«ö[Enter]¨Ï¥Î­ìID¡G",
+ real_name, sizeof(real_name), DOECHO);
+ if (!real_name[0] && defanony) {
+ strlcpy(real_name, "Anonymous", sizeof(real_name));
+ strlcpy(postlog.author, real_name, sizeof(postlog.author));
+ if (curr_buf)
+ curr_buf->ifuseanony = 1;
+ } else {
+ if (!strcmp("r", real_name) || (!defanony && !real_name[0]))
+ strlcpy(postlog.author, cuser.userid, sizeof(postlog.author));
+ else {
+ snprintf(postlog.author, sizeof(postlog.author),
+ "%s.", real_name);
+ if (curr_buf)
+ curr_buf->ifuseanony = 1;
+ }
+ }
+ }
+#endif
+ strlcpy(postlog.board, currboard, sizeof(postlog.board));
+ if (!strncmp(ptr, str_reply, 4))
+ ptr += 4;
+ strlcpy(postlog.title, ptr, sizeof(postlog.title));
+ postlog.date = now;
+ postlog.number = 1;
+ append_record(".post", (fileheader_t *) & postlog, sizeof(postlog));
+#ifdef HAVE_ANONYMOUS
+ if (currbrdattr & BRD_ANONYMOUS) {
+ int defanony = (currbrdattr & BRD_DEFAULTANONYMOUS);
+
+ fprintf(fp, "%s %s (%s) %s %s\n", str_author1, postlog.author,
+ (((!strcmp(real_name, "r") && defanony) ||
+ (!real_name[0] && (!defanony))) ? cuser.nickname :
+ "²q²q§Ú¬O½Ö ? ^o^"),
+ local_article ? str_post2 : str_post1, currboard);
+ } else {
+ fprintf(fp, "%s %s (%s) %s %s\n", str_author1, cuser.userid,
+ cuser.nickname,
+ local_article ? str_post2 : str_post1, currboard);
+ }
+#else /* HAVE_ANONYMOUS */
+ fprintf(fp, "%s %s (%s) %s %s\n", str_author1, cuser.userid,
+ cuser.nickname,
+ local_article ? str_post2 : str_post1, currboard);
+#endif /* HAVE_ANONYMOUS */
+
+ }
+ mytitle[72] = '\0';
+ fprintf(fp, "¼ÐÃD: %s\n®É¶¡: %s\n", mytitle, ctime4(&now));
+}
+
+off_t
+loadsitesig(const char *fname)
+{
+ int fd = 0;
+ off_t sz = 0, ret = -1;
+ char *start, *sp;
+
+ sz = dashs(fname);
+ if (sz < 1)
+ return -1;
+ fd = open(fname, O_RDONLY);
+ if (fd < 0)
+ return -1;
+ start = (char*)mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
+ if (start)
+ {
+ sp = start + sz - 4 - 1; // 4 = \n--\n
+ while (sp > start)
+ {
+ if ((*sp == '\n' && strncmp(sp, "\n--\n", 4) == 0) ||
+ (*sp == '\r' && strncmp(sp, "\r--\r", 4) == 0) )
+ {
+ size_t szSig = sz - (sp-start+1);
+ ret = sp - start + 1;
+ // allocate string
+ curr_buf->sitesig_string = (char*) malloc (szSig + 1);
+ if (curr_buf->sitesig_string)
+ {
+ memcpy(curr_buf->sitesig_string, sp+1, szSig);
+ curr_buf->sitesig_string[szSig] = 0;
+ }
+ break;
+ }
+ sp --;
+ }
+ munmap(start, sz);
+ }
+
+ close(fd);
+ return ret;
+}
+
+void
+addsignature(FILE * fp, int ifuseanony)
+{
+ FILE *fs;
+ int i;
+ char buf[WRAPMARGIN + 1];
+ char fpath[STRLEN];
+
+ char ch;
+
+ if (!strcmp(cuser.userid, STR_GUEST)) {
+ fprintf(fp, "\n--\n¡° µo«H¯¸ :" BBSNAME "(" MYHOSTNAME
+ ") \n¡» From: %s\n", fromhost);
+ return;
+ }
+ if (!ifuseanony) {
+
+ int browsing = 0;
+ SigInfo si;
+ memset(&si, 0, sizeof(si));
+
+browse_sigs:
+ showsignature(fpath, &i, &si);
+
+ if (si.total > 0){
+ char msg[64];
+
+ ch = isdigit(cuser.signature) ? cuser.signature : 'x';
+ sprintf(msg,
+ (browsing || (si.max > si.show_max)) ?
+ "½Ð¿ï¾Üñ¦WÀÉ (1-9, 0=¤£¥[ n=½­¶ x=ÀH¾÷)[%c]: ":
+ "½Ð¿ï¾Üñ¦WÀÉ (1-9, 0=¤£¥[ x=ÀH¾÷)[%c]: ",
+ ch);
+ getdata(0, 0, msg, buf, 4, LCECHO);
+
+ if(buf[0] == 'n')
+ {
+ si.show_start = si.show_max + 1;
+ if(si.show_start > si.max)
+ si.show_start = 0;
+ browsing = 1;
+ goto browse_sigs;
+ }
+
+ if (!buf[0])
+ buf[0] = ch;
+
+ if (isdigit((int)buf[0]))
+ ch = buf[0];
+ else
+ ch = '1' + random() % (si.max+1);
+ cuser.signature = buf[0];
+
+ if (ch != '0') {
+ fpath[i] = ch;
+ do
+ {
+ if ((fs = fopen(fpath, "r"))) {
+ fputs("\n--\n", fp);
+ for (i = 0; i < MAX_SIGLINES &&
+ fgets(buf, sizeof(buf), fs); i++)
+ fputs(buf, fp);
+ fclose(fs);
+ fpath[i] = ch;
+ }
+ else
+ fpath[i] = '1' + (fpath[i] - '1' + 1) % (si.max+1);
+ } while (!isdigit((int)buf[0]) && si.max > 0 && ch != fpath[i]);
+ }
+ }
+ }
+#ifdef HAVE_ORIGIN
+#ifdef HAVE_ANONYMOUS
+ if (ifuseanony)
+ fprintf(fp, "\n--\n¡° µo«H¯¸: " BBSNAME "(" MYHOSTNAME
+ ") \n¡» From: %s\n", "°Î¦W¤Ñ¨Ïªº®a");
+ else
+#endif
+ {
+ char temp[33];
+
+ strlcpy(temp, fromhost, sizeof(temp));
+ fprintf(fp, "\n--\n¡° µo«H¯¸: " BBSNAME "(" MYHOSTNAME
+ ") \n¡» From: %s\n", temp);
+ }
+#endif
+}
+
+#ifdef EXP_EDIT_UPLOAD
+static void upload_file(void);
+#endif // EXP_EDIT_UPLOAD
+
+static int
+write_file(char *fpath, int saveheader, int *islocal, char *mytitle, int upload, int chtitle)
+{
+ struct tm *ptime;
+ FILE *fp = NULL;
+ textline_t *p, *v;
+ char ans[TTLEN], *msg;
+ int aborted = 0, line = 0, checksum[3], sum = 0, po = 1;
+
+ stand_title("Àɮ׳B²z");
+ move(1,0);
+
+#ifdef EDIT_UPLOAD_ALLOWALL
+ upload = 1;
+#endif // EDIT_UPLOAD_ALLOWALL
+
+ // common trail
+
+ if (currstat == SMAIL)
+ outs("[S]Àx¦s");
+ else if (local_article)
+ outs("[L]¯¸¤º«H¥ó (S)Àx¦s");
+ else
+ outs("[S]Àx¦s (L)¯¸¤º«H¥ó");
+
+#ifdef EXP_EDIT_UPLOAD
+ if (upload)
+ outs(" (U)¤W¶Ç¸ê®Æ");
+#endif // EXP_EDIT_UPLOAD
+
+ if (chtitle)
+ outs(" (T)§ï¼ÐÃD");
+
+ outs(" (A)©ñ±ó (E)Ä~Äò (R/W/D)Ū¼g§R¼È¦sÀÉ");
+
+ getdata(2, 0, "½T©w­nÀx¦sÀɮ׶ܡH ", ans, 2, LCECHO);
+
+ // avoid lots pots
+ sleep(1);
+
+ switch (ans[0]) {
+ case 'a':
+ outs("¤å³¹" ANSI_COLOR(1) " ¨S¦³ " ANSI_RESET "¦s¤J");
+ aborted = -1;
+ break;
+ case 'e':
+ return KEEP_EDITING;
+#ifdef EXP_EDIT_UPLOAD
+ case 'u':
+ if (upload)
+ upload_file();
+ return KEEP_EDITING;
+#endif // EXP_EDIT_UPLOAD
+ case 'r':
+ read_tmpbuf(-1);
+ return KEEP_EDITING;
+ case 'w':
+ write_tmpbuf();
+ return KEEP_EDITING;
+ case 'd':
+ erase_tmpbuf();
+ return KEEP_EDITING;
+ case 't':
+ if (!chtitle)
+ return KEEP_EDITING;
+ move(3, 0);
+ prints("¼ÐÃD¡G%s", mytitle);
+ strlcpy(ans, mytitle, sizeof(ans));
+ if (getdata_buf(4, 0, "·s¼ÐÃD¡G", ans, sizeof(ans), DOECHO))
+ strlcpy(mytitle, ans, STRLEN);
+ return KEEP_EDITING;
+ case 's':
+ if (!HasUserPerm(PERM_LOGINOK)) {
+ local_article = 1;
+ move(2, 0);
+ outs("±z©|¥¼³q¹L¨­¥÷½T»{¡A¥u¯à Local Save¡C\n");
+ pressanykey();
+ } else
+ local_article = 0;
+ break;
+ case 'l':
+ local_article = 1;
+ }
+
+ if (!aborted) {
+
+ if (saveheader && !(curredit & EDIT_MAIL) && check_quote())
+ return KEEP_EDITING;
+
+ if (!(*fpath))
+ setuserfile(fpath, "ve_XXXXXX");
+ if ((fp = fopen(fpath, "w")) == NULL) {
+ indigestion(5);
+ abort_bbs(0);
+ }
+ if (saveheader)
+ write_header(fp, mytitle);
+ }
+ for (p = curr_buf->firstline; p; p = v) {
+ v = p->next;
+ if (!aborted) {
+ assert(fp);
+ msg = p->data;
+ if (v || msg[0]) {
+ trim(msg);
+
+ line++;
+
+ /* check crosspost */
+ if (currstat == POSTING && po ) {
+ int msgsum = StringHash(msg);
+ if (msgsum) {
+ if (postrecord.last_bid != currbid &&
+ postrecord.checksum[po] == msgsum) {
+ po++;
+ if (po > 3) {
+ postrecord.times++;
+ postrecord.last_bid = currbid;
+ po = 0;
+ }
+ } else
+ po = 1;
+ if (line >= curr_buf->totaln / 2 && sum < 3) {
+ checksum[sum++] = msgsum;
+ }
+ }
+ }
+ fprintf(fp, "%s\n", msg);
+ }
+ }
+ free_line(p);
+ }
+ curr_buf->currline = NULL;
+
+ // what if currbid == 0? add currstat checking.
+ if (currstat == POSTING &&
+ postrecord.times > MAX_CROSSNUM-1 &&
+ !is_hidden_board_friend(currbid, currutmp->uid))
+ anticrosspost();
+
+ if (po && sum == 3) {
+ memcpy(&postrecord.checksum[1], checksum, sizeof(int) * 3);
+ if(postrecord.last_bid != currbid)
+ postrecord.times = 0;
+ }
+
+ if (aborted)
+ return aborted;
+
+ if (islocal)
+ *islocal = local_article;
+
+ if (curr_buf->sitesig_string)
+ fprintf(fp, curr_buf->sitesig_string);
+
+ if (currstat == POSTING || currstat == SMAIL)
+ {
+ addsignature(fp, curr_buf->ifuseanony);
+ }
+ else if (currstat == REEDIT)
+ {
+#ifndef ALL_REEDIT_LOG
+ // why force signature in SYSOP board?
+ if(strcmp(currboard, GLOBAL_SYSOP) == 0)
+#endif
+ {
+ ptime = localtime4(&now);
+ fprintf(fp,
+ "¡° ½s¿è: %-15s ¨Ó¦Û: %-20s (%02d/%02d %02d:%02d)\n",
+ cuser.userid, fromhost,
+ ptime->tm_mon + 1, ptime->tm_mday,
+ ptime->tm_hour, ptime->tm_min);
+ }
+ }
+
+ fclose(fp);
+ return 0;
+}
+
+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
+block_cancel(void)
+{
+ if (has_block_selection()) {
+ curr_buf->blockln = -1;
+ curr_buf->redraw_everything = YEA;
+ }
+}
+
+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 {
+ *begin = curr_buf->currline;
+ *end = curr_buf->blockline;
+ }
+}
+
+#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
+block_save_to_file(const char *fname, int mode)
+{
+ textline_t *begin, *end;
+ char fp_tmpbuf[80];
+ FILE *fp;
+
+ if (!has_block_selection())
+ return;
+
+ setup_block_begin_end(&begin, &end);
+
+ setuserfile(fp_tmpbuf, fname);
+ if ((fp = fopen(fp_tmpbuf, mode == BLOCK_APPEND ? "a+" : "w+"))) {
+
+ textline_t *p;
+
+ for (p = begin; p != end; p = p->next)
+ fprintf(fp, "%s\n", p->data);
+ fprintf(fp, "%s\n", end->data);
+ fclose(fp);
+ }
+}
+
+/**
+ * delete selected block
+ */
+static void
+block_delete(void)
+{
+ textline_t *begin, *end;
+ textline_t *p;
+
+ if (!has_block_selection())
+ return;
+
+ setup_block_begin_end(&begin, &end);
+
+ // the block region is (currln, block) or (blockln, currln).
+
+ if (curr_buf->currln > curr_buf->blockln) {
+ // case (blockln, currln)
+ // piaip 2007/1201 ¦b³o¸Ì­ì¦³ offset-by-one issue
+ // ¦pªG¤S¹J¨ì¡A½ÐÀˬd³oªþªñ¡C
+ 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 {
+ // case (currln, blockln)
+ }
+
+ // adjust buffer after delete
+ 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;
+ }
+
+ // adjust current line
+ if (end->next) {
+ curr_buf->currline = end->next;
+ curr_buf->currline->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--;
+ }
+
+ // remove buffer
+ for (p = begin; p != end; curr_buf->totaln--)
+ free_line((p = p->next)->prev);
+
+ free_line(end);
+ curr_buf->totaln--;
+
+ curr_buf->currpnt = 0;
+}
+
+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)
+{
+ curr_buf->blockln = curr_buf->currln;
+ curr_buf->blockline = curr_buf->currline;
+}
+
+enum {
+ EOATTR_NORMAL = 0x00,
+ EOATTR_SELECTED = 0x01, // selected (reverse)
+ EOATTR_MOVIECODE= 0x02, // pmore movie
+ EOATTR_BBSLUA = 0x04, // BBS Lua (header)
+ EOATTR_COMMENT = 0x08, // comment syntax
+
+};
+
+static const char *luaKeywords[] = {
+ "and", "break", "do", "else", "elseif",
+ "end", "for", "if", "in", "not", "or",
+ "repeat","return","then","until","while",
+ NULL
+};
+
+static const char *luaDataKeywords[] = {
+ "false", "function", "local", "nil", "true",
+ NULL
+};
+
+static const char *luaFunctions[] = {
+ "assert", "print", "tonumber", "tostring", "type",
+ NULL
+};
+
+static const char *luaMath[] = {
+ "abs", "acos", "asin", "atan", "atan2", "ceil", "cos", "cosh", "deg",
+ "exp", "floor", "fmod", "frexp", "ldexp", "log", "log10", "max", "min",
+ "modf", "pi", "pow", "rad", "random", "randomseed", "sin", "sinh",
+ "sqrt", "tan", "tanh",
+ NULL
+};
+
+static const char *luaTable[] = {
+ "concat", "insert", "maxn", "remove", "sort",
+ NULL
+};
+
+static const char *luaString[] = {
+ "byte", "char", "dump", "find", "format", "gmatch", "gsub", "len",
+ "lower", "match", "rep", "reverse", "sub", "upper", NULL
+};
+
+static const char *luaBbs[] = {
+ "ANSI_COLOR", "ANSI_RESET", "ESC", "addstr", "clear", "clock",
+ "clrtobot", "clrtoeol", "color", "ctime", "getch","getdata",
+ "getmaxyx", "getstr", "getyx", "interface", "kball", "kbhit", "kbreset",
+ "move", "moverel", "now", "outs", "pause", "print", "rect", "refresh",
+ "setattr", "sitename", "sleep", "strip_ansi", "time", "title",
+ "userid", "usernick",
+ NULL
+};
+
+static const char *luaToc[] = {
+ "author", "date", "interface", "latestref",
+ "notes", "title", "version",
+ NULL
+};
+
+static const char *luaBit[] = {
+ "arshift", "band", "bnot", "bor", "bxor", "cast", "lshift", "rshift",
+ NULL
+};
+
+static const char *luaStore[] = {
+ "USER", "GLOBAL", "iolimit", "limit", "load", "save",
+ NULL
+};
+
+static const char *luaLibs[] = {
+ "bbs", "bit", "math", "store", "string", "table", "toc",
+ NULL
+};
+static const char**luaLibAPI[] = {
+ luaBbs, luaBit, luaMath, luaStore, luaString, luaTable, luaToc,
+ NULL
+};
+
+int synLuaKeyword(const char *text, int n, char *wlen)
+{
+ int i = 0;
+ const char **tbl = NULL;
+ if (*text >= 'A' && *text <= 'Z')
+ {
+ // normal identifier
+ while (n-- > 0 && (isalnum(*text) || *text == '_'))
+ {
+ text++;
+ (*wlen) ++;
+ }
+ return 0;
+ }
+ if (*text >= '0' && *text <= '9')
+ {
+ // digits
+ while (n-- > 0 && (isdigit(*text) || *text == '.' || *text == 'x'))
+ {
+ text++;
+ (*wlen) ++;
+ }
+ return 5;
+ }
+ if (*text == '#')
+ {
+ text++;
+ (*wlen) ++;
+ // length of identifier
+ while (n-- > 0 && (isalnum(*text) || *text == '_'))
+ {
+ text++;
+ (*wlen) ++;
+ }
+ return -2;
+ }
+
+ // ignore non-identifiers
+ if (!(*text >= 'a' && *text <= 'z'))
+ return 0;
+
+ // 1st, try keywords
+ for (i = 0; luaKeywords[i] && *text >= *luaKeywords[i]; i++)
+ {
+ int l = strlen(luaKeywords[i]);
+ if (n < l)
+ continue;
+ if (isalnum(text[l]))
+ continue;
+ if (strncmp(text, luaKeywords[i], l) == 0)
+ {
+ *wlen = l;
+ return 3;
+ }
+ }
+ for (i = 0; luaDataKeywords[i] && *text >= *luaDataKeywords[i]; i++)
+ {
+ int l = strlen(luaDataKeywords[i]);
+ if (n < l)
+ continue;
+ if (isalnum(text[l]))
+ continue;
+ if (strncmp(text, luaDataKeywords[i], l) == 0)
+ {
+ *wlen = l;
+ return 2;
+ }
+ }
+ for (i = 0; luaFunctions[i] && *text >= *luaFunctions[i]; i++)
+ {
+ int l = strlen(luaFunctions[i]);
+ if (n < l)
+ continue;
+ if (isalnum(text[l]))
+ continue;
+ if (strncmp(text, luaFunctions[i], l) == 0)
+ {
+ *wlen = l;
+ return 6;
+ }
+ }
+ for (i = 0; luaLibs[i]; i++)
+ {
+ int l = strlen(luaLibs[i]);
+ if (n < l)
+ continue;
+ if (text[l] != '.' && text[l] != ':')
+ continue;
+ if (strncmp(text, luaLibs[i], l) == 0)
+ {
+ *wlen = l+1;
+ text += l; text ++;
+ n -= l; n--;
+ break;
+ }
+ }
+
+ tbl = luaLibAPI[i];
+ if (!tbl)
+ {
+ // calcualte wlen
+ while (n-- > 0 && (isalnum(*text) || *text == '_'))
+ {
+ text++;
+ (*wlen) ++;
+ }
+ return 0;
+ }
+
+ for (i = 0; tbl[i]; i++)
+ {
+ int l = strlen(tbl[i]);
+ if (n < l)
+ continue;
+ if (isalnum(text[l]))
+ continue;
+ if (strncmp(text, tbl[i], l) == 0)
+ {
+ *wlen += l;
+ return 6;
+ }
+ }
+ // luaLib. only
+ return -6;
+}
+
+/**
+ * Just like outs, but print out '*' instead of 27(decimal) in the given string.
+ *
+ * FIXME column could not start from 0
+ */
+
+static void
+edit_outs_attr_n(const char *text, int n, int attr)
+{
+ int column = 0;
+ register unsigned char inAnsi = 0;
+ register unsigned char ch;
+ int doReset = 0;
+ const char *reset = ANSI_RESET;
+
+ // syntax attributes
+ char fComment = 0,
+ fSingleQuote = 0,
+ fDoubleQuote = 0,
+ fSquareQuote = 0,
+ fWord = 0;
+
+#ifdef COLORED_SELECTION
+ if ((attr & EOATTR_SELECTED) &&
+ (attr & ~EOATTR_SELECTED))
+ {
+ reset = ANSI_COLOR(0;7;36);
+ doReset = 1;
+ outs(reset);
+ }
+ else
+#endif // if not defined, color by priority - selection first
+ if (attr & EOATTR_SELECTED)
+ {
+ reset = ANSI_COLOR(0;7);
+ doReset = 1;
+ outs(reset);
+ }
+ else if (attr & EOATTR_MOVIECODE)
+ {
+ reset = ANSI_COLOR(0;36);
+ doReset = 1;
+ outs(reset);
+ }
+ else if (attr & EOATTR_BBSLUA)
+ {
+ reset = ANSI_COLOR(0;1;31);
+ doReset = 1;
+ outs(reset);
+ }
+ else if (attr & EOATTR_COMMENT)
+ {
+ reset = ANSI_COLOR(0;1;34);
+ doReset = 1;
+ outs(reset);
+ }
+
+#ifdef DBCSAWARE
+ /* 0 = N/A, 1 = leading byte printed, 2 = ansi in middle */
+ register unsigned char isDBCS = 0;
+#endif
+
+ while ((ch = *text++) && (++column < t_columns) && n-- > 0)
+ {
+ if(inAnsi == 1)
+ {
+ if(ch == ESC_CHR)
+ outc('*');
+ else
+ {
+ outc(ch);
+
+ if(!ANSI_IN_ESCAPE(ch))
+ {
+ inAnsi = 0;
+ outs(reset);
+ }
+ }
+
+ }
+ else if(ch == ESC_CHR)
+ {
+ inAnsi = 1;
+#ifdef DBCSAWARE
+ if(isDBCS == 1)
+ {
+ isDBCS = 2;
+ outs(ANSI_COLOR(1;33) "?");
+ outs(reset);
+ }
+#endif
+ outs(ANSI_COLOR(1) "*");
+ }
+ else
+ {
+#ifdef DBCSAWARE
+ if(isDBCS == 1)
+ isDBCS = 0;
+ else if (isDBCS == 2)
+ {
+ /* ansi in middle. */
+ outs(ANSI_COLOR(0;33) "?");
+ outs(reset);
+ isDBCS = 0;
+ continue;
+ }
+ else
+ if(IS_BIG5_HI(ch))
+ {
+ isDBCS = 1;
+ // peak next char
+ if(n > 0 && *text == ESC_CHR)
+ continue;
+ }
+#endif
+ // Lua Parser!
+ if (!attr && curr_buf->synparser && !fComment)
+ {
+ // syntax highlight!
+ if (fSquareQuote) {
+ if (ch == ']' && n > 0 && *(text) == ']')
+ {
+ fSquareQuote = 0;
+ doReset = 0;
+ // directly print quotes
+ outc(ch); outc(ch);
+ text++, n--;
+ outs(ANSI_RESET);
+ continue;
+ }
+ } else if (fSingleQuote) {
+ if (ch == '\'')
+ {
+ fSingleQuote = 0;
+ doReset = 0;
+ // directly print quotes
+ outc(ch);
+ outs(ANSI_RESET);
+ continue;
+ }
+ } else if (fDoubleQuote) {
+ if (ch == '"')
+ {
+ fDoubleQuote = 0;
+ doReset = 0;
+ // directly print quotes
+ outc(ch);
+ outs(ANSI_RESET);
+ continue;
+ }
+ } else if (ch == '-' && n > 0 && *(text) == '-') {
+ fComment = 1;
+ doReset = 1;
+ outs(ANSI_COLOR(0;1;34));
+ } else if (ch == '[' && n > 0 && *(text) == '[') {
+ fSquareQuote = 1;
+ doReset = 1;
+ fWord = 0;
+ outs(ANSI_COLOR(1;35));
+ } else if (ch == '\'' || ch == '"') {
+ if (ch == '"')
+ fDoubleQuote = 1;
+ else
+ fSingleQuote = 1;
+ doReset = 1;
+ fWord = 0;
+ outs(ANSI_COLOR(1;35));
+ } else {
+ // normal words
+ if (fWord)
+ {
+ // inside a word.
+ if (--fWord <= 0){
+ fWord = 0;
+ doReset = 0;
+ outc(ch);
+ outs(ANSI_RESET);
+ continue;
+ }
+ } else if (isalnum(tolower(ch)) || ch == '#') {
+ char attr[] = ANSI_COLOR(0;1;37);
+ int x = synLuaKeyword(text-1, n+1, &fWord);
+ if (fWord > 0)
+ fWord --;
+ if (x != 0)
+ {
+ // sorry, fixed string here.
+ // 7 = *[0;1;3?
+ if (x<0) { attr[4] = '0'; x= -x; }
+ attr[7] = '0' + x;
+ prints(attr);
+ doReset = 1;
+ }
+ if (!fWord)
+ {
+ outc(ch);
+ outs(ANSI_RESET);
+ doReset = 0;
+ continue;
+ }
+ }
+ }
+ }
+ outc(ch);
+ }
+ }
+
+ // this must be ANSI_RESET, not "reset".
+ if(inAnsi || doReset)
+ outs(ANSI_RESET);
+}
+
+static void
+edit_outs_attr(const char *text, int attr)
+{
+ edit_outs_attr_n(text, scr_cols, attr);
+}
+
+static void
+edit_ansi_outs_n(const char *str, int n, int attr)
+{
+ char c;
+ while (n-- > 0 && (c = *str++)) {
+ if(c == ESC_CHR && *str == '*')
+ {
+ // ptt prints
+ /* Because moving within ptt_prints is too hard
+ * let's just display it as-is.
+ */
+ outc('*');
+ } else {
+ outc(c);
+ }
+ }
+}
+
+static void
+edit_ansi_outs(const char *str, int attr)
+{
+ return edit_ansi_outs_n(str, strlen(str), attr);
+}
+
+// old compatible API
+void
+edit_outs(const char *text)
+{
+ edit_outs_attr(text, 0);
+}
+
+void
+edit_outs_n(const char *text, int n)
+{
+ edit_outs_attr_n(text, n, 0);
+}
+
+
+#define PMORE_USE_ASCII_MOVIE // disable this if you don't enable ascii movie
+
+#ifdef PMORE_USE_ASCII_MOVIE
+// pmore movie header support
+unsigned char *
+ mf_movieFrameHeader(unsigned char *p, unsigned char *end);
+
+#endif // PMORE_USE_ASCII_MOVIE
+
+static int
+detect_attr(const char *ps, size_t len)
+{
+ int attr = 0;
+
+#ifdef PMORE_USE_ASCII_MOVIE
+ if (mf_movieFrameHeader((unsigned char*)ps, (unsigned char*)ps+len))
+ attr |= EOATTR_MOVIECODE;
+#endif
+#ifdef USE_BBSLUA
+ if (bbslua_isHeader(ps, ps + len))
+ {
+ attr |= EOATTR_BBSLUA;
+ if (!curr_buf->synparser)
+ {
+ curr_buf->synparser = 1;
+ // if you need indent, toggle by hotkey.
+ // enabling indent by default may cause trouble to copy pasters
+ // curr_buf->indent_mode = 1;
+ }
+ }
+#endif
+ return attr;
+}
+
+static inline void
+display_textline_internal(textline_t *p, int i)
+{
+ short tmp;
+ void (*output)(const char *, int) = edit_outs_attr;
+ void (*output_n)(const char *, int, int)= edit_outs_attr_n;
+
+ int attr = EOATTR_NORMAL;
+
+ move(i, 0);
+ clrtoeol();
+
+ if (!p) {
+ outc('~');
+ outs(ANSI_CLRTOEND);
+ return;
+ }
+
+ if (curr_buf->ansimode) {
+ output = edit_ansi_outs;
+ output_n = edit_ansi_outs_n;
+ }
+
+ tmp = curr_buf->currln - curr_buf->curr_window_line + i;
+
+ // parse attribute of line
+
+ // selected attribute?
+ 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(ANSI_COLOR(7)); // remove me when EOATTR is ready...
+ attr |= EOATTR_SELECTED;
+ }
+
+ attr |= detect_attr(p->data, p->len);
+
+#ifdef DBCSAWARE
+ if(mbcs_mode && curr_buf->edit_margin > 0)
+ {
+ if(curr_buf->edit_margin >= p->len)
+ {
+ (*output)("", attr);
+ } else {
+
+ int newpnt = curr_buf->edit_margin;
+ unsigned char *pdata = (unsigned char*)
+ (&p->data[0] + curr_buf->edit_margin);
+
+ if(mbcs_mode)
+ newpnt = fix_cursor(p->data, newpnt, FC_LEFT);
+
+ if(newpnt == curr_buf->edit_margin-1)
+ {
+ /* this should be always 'outs'? */
+ // (*output)(ANSI_COLOR(1) "<" ANSI_RESET);
+ outs(ANSI_COLOR(1) "<" ANSI_RESET);
+ pdata++;
+ }
+ (*output)((char*)pdata, attr);
+ }
+
+ } else
+#endif
+ (*output)((curr_buf->edit_margin < p->len) ?
+ &p->data[curr_buf->edit_margin] : "", attr);
+
+ if (attr)
+ outs(ANSI_RESET);
+
+ // workaround poor terminal
+ outs(ANSI_CLRTOEND);
+}
+
+static void
+refresh_window(void)
+{
+ register textline_t *p;
+ register int i;
+
+ for (p = curr_buf->top_of_win, i = 0; i < b_lines; i++) {
+ display_textline_internal(p, i);
+
+ 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(void)
+{
+ 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 = (*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 = (*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 < 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;
+ }
+ }
+ if (!mode)
+ curr_buf->redraw_everything = YEA;
+}
+
+/**
+ * move the cursor from bracket to corresponding bracket.
+ */
+static void
+match_paren(void)
+{
+ char *parens = "()[]{}";
+ int type;
+ int parenum = 0;
+ char *ptype;
+ textline_t *p;
+ int lino;
+ int c, i = 0;
+
+ if (!(ptype = strchr(parens, curr_buf->currline->data[curr_buf->currpnt])))
+ return;
+
+ type = (ptype - parens) / 2;
+ 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);
+ for (i = (lino == curr_buf->currln) ? curr_buf->currpnt + 1 : 0; i < len; i++) {
+ if (p->data[i] == '/' && p->data[++i] == '*') {
+ ++i;
+ while (1) {
+ while (i < len &&
+ !(p->data[i] == '*' && p->data[i + 1] == '/')) {
+ i++;
+ }
+ if (i >= len && p->next) {
+ p = p->next;
+ len = strlen(p->data);
+ ++lino;
+ i = 0;
+ } else
+ break;
+ }
+ } else if ((c = p->data[i]) == '\'' || c == '"') {
+ while (1) {
+ while (i < len - 1) {
+ if (p->data[++i] == '\\' && (size_t)i < len - 2)
+ ++i;
+ else if (p->data[i] == c)
+ goto end_quote;
+ }
+ if ((size_t)i >= len - 1 && p->next) {
+ p = p->next;
+ len = strlen(p->data);
+ ++lino;
+ i = -1;
+ } else
+ break;
+ }
+ end_quote:
+ ;
+ } else if ((ptype = strchr(parens, p->data[i])) &&
+ (ptype - parens) / 2 == type) {
+ if (!(parenum += ((ptype - parens) % 2) ? -1 : 1))
+ goto p_outscan;
+ }
+ }
+ }
+ } else {
+ for (lino = curr_buf->currln, p = curr_buf->currline; p; p = p->prev, lino--) {
+ int len = strlen(p->data);
+ for (i = ((lino == curr_buf->currln) ? curr_buf->currpnt - 1 : len - 1); i >= 0; i--) {
+ if (p->data[i] == '/' && p->data[--i] == '*' && i > 0) {
+ --i;
+ while (1) {
+ while (i > 0 &&
+ !(p->data[i] == '*' && p->data[i - 1] == '/')) {
+ i--;
+ }
+ if (i <= 0 && p->prev) {
+ p = p->prev;
+ len = strlen(p->data);
+ --lino;
+ i = len - 1;
+ } else
+ break;
+ }
+ } else if ((c = p->data[i]) == '\'' || c == '"') {
+ while (1) {
+ while (i > 0)
+ if (i > 1 && p->data[i - 2] == '\\')
+ i -= 2;
+ else if ((p->data[--i]) == c)
+ goto begin_quote;
+ if (i <= 0 && p->prev) {
+ p = p->prev;
+ len = strlen(p->data);
+ --lino;
+ i = len;
+ } else
+ break;
+ }
+begin_quote:
+ ;
+ } else if ((ptype = strchr(parens, p->data[i])) &&
+ (ptype - parens) / 2 == type) {
+ if (!(parenum += ((ptype - parens) % 2) ? -1 : 1))
+ goto p_outscan;
+ }
+ }
+ }
+ }
+p_outscan:
+ if (!parenum) {
+ int top = curr_buf->currln - curr_buf->curr_window_line;
+ int bottom = curr_buf->currln - curr_buf->curr_window_line + b_lines - 1;
+
+ curr_buf->currpnt = i;
+ curr_buf->currline = p;
+ curr_buf->curr_window_line += lino - curr_buf->currln;
+ curr_buf->currln = lino;
+
+ if (lino < top || lino > bottom) {
+ 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 = 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
+currline_shift_left(void)
+{
+ int currpnt0;
+
+ if (curr_buf->currline->len <= 0)
+ return;
+
+ 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
+currline_shift_right(void)
+{
+ int currpnt0;
+
+ if (curr_buf->currline->len >= WRAPMARGIN - 1)
+ return;
+
+ currpnt0 = curr_buf->currpnt;
+ curr_buf->currpnt = 0;
+ insert_char(' ');
+ curr_buf->currpnt = currpnt0;
+}
+
+static void
+cursor_to_next_word(void)
+{
+ 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]));
+}
+
+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++;
+}
+
+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;
+ }
+}
+
+/**
+ * transform every "*[" in given string to KEY_ESC "["
+ */
+static void
+transform_to_color(char *line)
+{
+ while (line[0] && line[1])
+ if (line[0] == '*' && line[1] == '[') {
+ line[0] = KEY_ESC;
+ line += 2;
+ } else
+ ++line;
+}
+
+static void
+block_color(void)
+{
+ textline_t *begin, *end, *p;
+
+ setup_block_begin_end(&begin, &end);
+
+ p = begin;
+ while (1) {
+ // FIXME CRASH p will be NULL here.
+ assert(p);
+ transform_to_color(p->data);
+ if (p == end)
+ break;
+ else
+ p = p->next;
+ }
+ block_cancel();
+}
+
+/**
+ * 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(ANSI_COLOR(1;33;40) "B" ANSI_COLOR(41) "R" ANSI_COLOR(42) "G" ANSI_COLOR(43) "Y" ANSI_COLOR(44) "L"
+ ANSI_COLOR(45) "P" ANSI_COLOR(46) "C" ANSI_COLOR(47) "W" ANSI_RESET);
+ 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, ESC_STR "[");
+ 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;
+}
+
+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->last_phone_mode - 1] + (tolower(c) - 'a') * 2;
+ }
+ else if (curr_buf->last_phone_mode >= 20) {
+ if (c == '.') c = '/';
+
+ if (c < '/' || c > '9')
+ return 0;
+
+ 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;
+}
+
+#ifdef EXP_EDIT_UPLOAD
+
+static void
+upload_file(void)
+{
+ size_t szdata = 0;
+ int c = 1;
+ char promptmsg = 0;
+
+ clear();
+ block_cancel();
+ stand_title("¤W¶Ç¤å¦rÀÉ®×");
+ move(3,0);
+ outs("§Q¥Î¥»ªA°È±z¥i¥H¤W¶Ç¸û¤jªº¤å¦rÀÉ (¦ý¤£­p¤J½Z¶O)¡C\n"
+ "\n"
+ "¤W¶Ç´Á¶¡±z¥´ªº¦r¼È®É¤£·|¥X²{¦b¿Ã¹õ¤W¡A°£¤F Ctrl-U ·|³QÂà´«¬° ANSI \n"
+ "±±¨î½Xªº ESC ¥~¡A¨ä¥¦¯S®íÁä¤@«ß¨S¦³§@¥Î¡C\n"
+ "\n"
+ "½Ð¦b±zªº¹q¸£¥»¾÷ºÝ½Æ»s¦n¤º®e«á¶K¤W§Y¥i¶}©l¶Ç°e¡C\n");
+
+ do {
+ if (!num_in_buf())
+ {
+ move(10, 0); clrtobot();
+ prints("\n\n¸ê®Æ±µ¦¬¤¤... %u ¦ì¤¸²Õ¡C\n", (unsigned int)szdata);
+ outs(ANSI_COLOR(1)
+ "¡»¥þ³¡§¹¦¨«á«ö¤U End ©Î ^X/^Q/^C §Y¥i¦^¨ì½s¿èµe­±¡C"
+ ANSI_RESET "\n");
+ promptmsg = 0;
+ }
+
+ c = igetch();
+ if (c < 0x100 && isprint2(c))
+ {
+ insert_char(c);
+ szdata ++;
+ }
+ else if (c == Ctrl('U') || c == ESC_CHR)
+ {
+ insert_char(ESC_CHR);
+ szdata ++;
+ }
+ else if (c == Ctrl('I'))
+ {
+ insert_tab();
+ szdata ++;
+ }
+ else if (c == '\r' || c == '\n')
+ {
+ split(curr_buf->currline, curr_buf->currpnt);
+ curr_buf->oldcurrline = curr_buf->currline;
+ szdata ++;
+ promptmsg = 1;
+ }
+
+ if (!promptmsg)
+ promptmsg = (szdata && szdata % 1024 == 0);
+
+ // all other keys are ignored.
+ } while (c != KEY_END && c != Ctrl('X') &&
+ c != Ctrl('C') && c != Ctrl('Q') &&
+ curr_buf->totaln <= EDIT_LINE_LIMIT &&
+ szdata <= EDIT_SIZE_LIMIT);
+
+ move(12, 0);
+ prints("¶Ç°eµ²§ô: ¦¬¨ì %u ¦ì¤¸²Õ¡C", (unsigned int)szdata);
+ vmsgf("¦^¨ì½s¿èµe­±");
+}
+
+#endif // EXP_EDIT_UPLOAD
+
+
+/* ½s¿è³B²z¡G¥Dµ{¦¡¡BÁä½L³B²z */
+int
+vedit2(char *fpath, int saveheader, int *islocal, int flags)
+{
+ char last = 0; /* the last key you press */
+ int ch, tmp;
+
+ int mode0 = currutmp->mode;
+ int destuid0 = currutmp->destuid;
+ int money = 0;
+ int interval = 0;
+ time4_t th = now;
+ int count = 0, tin = 0, quoted = 0;
+ char trans_buffer[256];
+ char mytitle[STRLEN];
+
+ STATINC(STAT_VEDIT);
+ currutmp->mode = EDITING;
+ currutmp->destuid = currstat;
+
+ strlcpy(mytitle, save_title, sizeof(mytitle));
+
+#ifdef DBCSAWARE
+ mbcs_mode = (cuser.uflag & DBCSAWARE_FLAG) ? 1 : 0;
+#endif
+
+ enter_edit_buffer();
+
+ curr_buf->oldcurrline = curr_buf->currline = curr_buf->top_of_win =
+ curr_buf->firstline = curr_buf->lastline = alloc_line(WRAPMARGIN);
+
+ if (*fpath) {
+ read_file(fpath, (flags & EDITFLAG_TEXTONLY) ? 1 : 0);
+ }
+
+ if (*quote_file) {
+ do_quote();
+ *quote_file = '\0';
+ quoted = 1;
+ }
+
+ if( curr_buf->oldcurrline != curr_buf->firstline ||
+ curr_buf->currline != curr_buf->firstline) {
+ /* we must adjust because cursor (currentline) moved. */
+ curr_buf->oldcurrline = curr_buf->currline = curr_buf->top_of_win =
+ curr_buf->firstline= adjustline(curr_buf->firstline, WRAPMARGIN);
+ }
+
+ /* No matter you quote or not, just start the cursor from (0,0) */
+ curr_buf->currpnt = curr_buf->currln = curr_buf->curr_window_line =
+ curr_buf->edit_margin = curr_buf->last_margin = 0;
+
+ /* if quote, move to end of file. */
+ if(quoted)
+ {
+ /* maybe do this in future. */
+ }
+
+ while (1) {
+ if (curr_buf->redraw_everything || has_block_selection()) {
+ refresh_window();
+ curr_buf->redraw_everything = NA;
+ }
+ if( curr_buf->oldcurrline != curr_buf->currline ){
+ curr_buf->oldcurrline = adjustline(curr_buf->oldcurrline, curr_buf->oldcurrline->len);
+ curr_buf->oldcurrline = curr_buf->currline = adjustline(curr_buf->currline, WRAPMARGIN);
+ }
+
+ 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);
+
+#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))) {
+ th = now;
+ if ((char)ch != last) {
+ money++;
+ last = (char)ch;
+ }
+ }
+ if (interval && interval == tin)
+ { // Ptt : +- 1 ¬í¤]ºâ
+ count++;
+ if(count>60)
+ {
+ money = 0;
+ count = 0;
+/*
+ log_file("etc/illegal_money", LOG_CREAT | LOG_VF,
+ ANSI_COLOR(1;33;46) "%s " ANSI_COLOR(37;45) " ¥Î¾÷¾¹¤Hµoªí¤å³¹ " ANSI_COLOR(37) " %s" ANSI_RESET "\n",
+ cuser.userid, ctime4(&now));
+ post_violatelaw(cuser.userid, BBSMNAME "¨t²Îĵ¹î",
+ "¥Î¾÷¾¹¤Hµoªí¤å³¹", "±j¨îÂ÷¯¸");
+ abort_bbs(0);
+*/
+ }
+ }
+ else if(interval){
+ count = 0;
+ tin = interval;
+ }
+#ifndef DBCSAWARE
+ /* this is almost useless! */
+ if (curr_buf->raw_mode) {
+ switch (ch) {
+ case Ctrl('S'):
+ case Ctrl('Q'):
+ case Ctrl('T'):
+ continue;
+ }
+ }
+#endif
+
+ 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);
+ curr_buf->lastindent = -1;
+ } else {
+ if (ch == KEY_UP || ch == KEY_DOWN ){
+ if (curr_buf->lastindent == -1)
+ curr_buf->lastindent = curr_buf->currpnt;
+ } else
+ curr_buf->lastindent = -1;
+ if (ch == KEY_ESC)
+ switch (KEY_ESC_arg) {
+ case ',':
+ ch = Ctrl(']');
+ break;
+ case '.':
+ ch = Ctrl('T');
+ break;
+ case 'v':
+ ch = KEY_PGUP;
+ break;
+ case 'a':
+ case 'A':
+ ch = Ctrl('V');
+ break;
+ case 'X':
+ ch = Ctrl('X');
+ break;
+ case 'q':
+ ch = Ctrl('Q');
+ break;
+ 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;
+ }
+
+ switch (ch) {
+ case KEY_F10:
+ case Ctrl('X'): /* Save and exit */
+ tmp = write_file(fpath, saveheader, islocal, mytitle,
+ (flags & EDITFLAG_UPLOAD) ? 1 : 0,
+ (flags & EDITFLAG_ALLOWTITLE) ? 1 : 0);
+ if (tmp != KEEP_EDITING) {
+ strlcpy(save_title, mytitle, sizeof(save_title));
+ save_title[STRLEN-1] = 0;
+ currutmp->mode = mode0;
+ currutmp->destuid = destuid0;
+
+ exit_edit_buffer();
+ if (!tmp)
+ return money;
+ else
+ return tmp;
+ }
+ curr_buf->oldcurrline = curr_buf->currline;
+ curr_buf->redraw_everything = YEA;
+ break;
+ case KEY_F5:
+ prompt_goto_line();
+ curr_buf->redraw_everything = YEA;
+ break;
+ case KEY_F8:
+ t_users();
+ curr_buf->redraw_everything = YEA;
+ break;
+ case Ctrl('W'):
+ block_cut();
+ // curr_buf->oldcurrline is freed in block_cut, and currline is
+ // well adjusted now. This will avoid re-adjusting later.
+ // It's not a good implementation, try to find a better
+ // solution!
+ curr_buf->oldcurrline = curr_buf->currline;
+ break;
+ case Ctrl('Q'): /* Quit without saving */
+ grayout(0, b_lines-1, GRAYOUT_DARK);
+ ch = vmsg("µ²§ô¦ý¤£Àx¦s [y/N]? ");
+ if (ch == 'y' || ch == 'Y') {
+ currutmp->mode = mode0;
+ currutmp->destuid = destuid0;
+ exit_edit_buffer();
+ return -1;
+ }
+ curr_buf->redraw_everything = YEA;
+ break;
+ case Ctrl('C'):
+ insert_ansi_code();
+ break;
+ case KEY_ESC:
+ switch (KEY_ESC_arg) {
+ case 'U':
+ t_users();
+ curr_buf->redraw_everything = YEA;
+ break;
+ case 'i':
+ t_idle();
+ curr_buf->redraw_everything = YEA;
+ break;
+ case 'n':
+ search_str(1);
+ break;
+ case 'p':
+ search_str(-1);
+ break;
+ case 'L':
+ case 'J':
+ prompt_goto_line();
+ curr_buf->redraw_everything = YEA;
+ break;
+ case ']':
+ match_paren();
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ read_tmpbuf(KEY_ESC_arg - '0');
+ curr_buf->oldcurrline = curr_buf->currline;
+ curr_buf->redraw_everything = YEA;
+ break;
+ case 'l': /* block delete */
+ case ' ':
+ if (has_block_selection()) {
+ block_prompt();
+ // curr_buf->oldcurrline is freed in block_cut, and currline is
+ // well adjusted now. This will avoid re-adjusting later.
+ // It's not a good implementation, try to find a better
+ // solution!
+ curr_buf->oldcurrline = curr_buf->currline;
+ }
+ else
+ block_select();
+ break;
+ case 'u':
+ block_cancel();
+ break;
+ case 'c':
+ block_copy();
+ break;
+ case 'y':
+ curr_buf->oldcurrline = undelete_line();
+ if (curr_buf->oldcurrline == NULL)
+ curr_buf->oldcurrline = curr_buf->currline;
+ break;
+ case 'R':
+#ifdef DBCSAWARE
+ case 'r':
+ mbcs_mode =! mbcs_mode;
+#endif
+ curr_buf->raw_mode ^= 1;
+ break;
+ case 'I':
+ curr_buf->indent_mode ^= 1;
+ break;
+ case 'j':
+ currline_shift_left();
+ break;
+ case 'k':
+ currline_shift_right();
+ break;
+ case 'f':
+ cursor_to_next_word();
+ break;
+ case 'b':
+ cursor_to_prev_word();
+ break;
+ case 'd':
+ delete_current_word();
+ break;
+ }
+ break;
+ case Ctrl('S'):
+ case KEY_F3:
+ search_str(0);
+ break;
+ case Ctrl('U'):
+ insert_char(ESC_CHR);
+ break;
+ case Ctrl('V'): /* Toggle ANSI color */
+ curr_buf->ansimode ^= 1;
+ if (curr_buf->ansimode && has_block_selection())
+ block_color();
+ clear();
+ curr_buf->redraw_everything = YEA;
+ break;
+ case Ctrl('I'):
+ insert_tab();
+ break;
+ case '\r':
+ case '\n':
+ block_cancel();
+ if (curr_buf->totaln >= EDIT_LINE_LIMIT)
+ {
+ vmsg("Àɮפw¶W¹L³Ì¤j­­¨î¡AµLªk¦A¼W¥[¦æ¼Æ¡C");
+ break;
+ }
+
+#ifdef MAX_EDIT_LINE
+ if(curr_buf->totaln ==
+ ((flags & EDITFLAG_ALLOWLARGE) ?
+ MAX_EDIT_LINE_LARGE : MAX_EDIT_LINE))
+ {
+ vmsg("¤w¨ì¹F³Ì¤j¦æ¼Æ­­¨î¡C");
+ break;
+ }
+#endif
+ split(curr_buf->currline, curr_buf->currpnt);
+ curr_buf->oldcurrline = curr_buf->currline;
+ break;
+ case Ctrl('G'):
+ {
+ unsigned int currstat0 = currstat;
+ setutmpmode(EDITEXP);
+ a_menu("½s¿è»²§U¾¹", "etc/editexp",
+ (HasUserPerm(PERM_SYSOP) ? SYSOP : NOBODY),
+ 0,
+ trans_buffer);
+ currstat = currstat0;
+ }
+ if (trans_buffer[0]) {
+ FILE *fp1;
+ if ((fp1 = fopen(trans_buffer, "r"))) {
+ int indent_mode0 = curr_buf->indent_mode;
+ char buf[WRAPMARGIN + 2];
+
+ curr_buf->indent_mode = 0;
+ while (fgets(buf, sizeof(buf), fp1)) {
+ if (!strncmp(buf, "§@ªÌ:", 5) ||
+ !strncmp(buf, "¼ÐÃD:", 5) ||
+ !strncmp(buf, "®É¶¡:", 5))
+ continue;
+ insert_string(buf);
+ }
+ fclose(fp1);
+ curr_buf->indent_mode = indent_mode0;
+ while (curr_buf->curr_window_line >= b_lines) {
+ curr_buf->curr_window_line--;
+ curr_buf->top_of_win = curr_buf->top_of_win->next;
+ }
+ }
+ }
+ curr_buf->redraw_everything = YEA;
+ break;
+ case Ctrl('P'):
+ phone_mode_switch();
+ curr_buf->redraw_everything = YEA;
+ break;
+
+ case KEY_F1:
+ case Ctrl('Z'): /* Help */
+ more("etc/ve.hlp", YEA);
+ curr_buf->redraw_everything = YEA;
+ break;
+ case Ctrl('L'):
+ clear();
+ curr_buf->redraw_everything = YEA;
+ break;
+ case KEY_LEFT:
+ if (curr_buf->currpnt) {
+ if (curr_buf->ansimode)
+ curr_buf->currpnt = n2ansi(curr_buf->currpnt, curr_buf->currline);
+ curr_buf->currpnt--;
+ if (curr_buf->ansimode)
+ curr_buf->currpnt = ansi2n(curr_buf->currpnt, curr_buf->currline);
+#ifdef DBCSAWARE
+ if(mbcs_mode)
+ curr_buf->currpnt = fix_cursor(curr_buf->currline->data, curr_buf->currpnt, FC_LEFT);
+#endif
+ } 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;
+ }
+ break;
+ case KEY_RIGHT:
+ if (curr_buf->currline->len != curr_buf->currpnt) {
+ if (curr_buf->ansimode)
+ curr_buf->currpnt = n2ansi(curr_buf->currpnt, curr_buf->currline);
+ curr_buf->currpnt++;
+ if (curr_buf->ansimode)
+ curr_buf->currpnt = ansi2n(curr_buf->currpnt, curr_buf->currline);
+#ifdef DBCSAWARE
+ if(mbcs_mode)
+ curr_buf->currpnt = fix_cursor(curr_buf->currline->data, curr_buf->currpnt, FC_RIGHT);
+#endif
+ } 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;
+ }
+ break;
+ case KEY_UP:
+ cursor_to_prev_line();
+ break;
+ case KEY_DOWN:
+ cursor_to_next_line();
+ break;
+
+ case Ctrl('B'):
+ case KEY_PGUP: {
+ short tmp = curr_buf->currln;
+ curr_buf->top_of_win = back_line(curr_buf->top_of_win, t_lines - 2);
+ curr_buf->currln = tmp;
+ curr_buf->currline = back_line(curr_buf->currline, t_lines - 2);
+ 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;
+ break;
+ }
+
+ case Ctrl('F'):
+ case KEY_PGDN: {
+ short tmp = curr_buf->currln;
+ curr_buf->top_of_win = forward_line(curr_buf->top_of_win, t_lines - 2);
+ curr_buf->currln = tmp;
+ curr_buf->currline = forward_line(curr_buf->currline, t_lines - 2);
+ 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;
+ break;
+ }
+
+ case KEY_END:
+ case Ctrl('E'):
+ curr_buf->currpnt = curr_buf->currline->len;
+ 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;
+ break;
+ case Ctrl('T'): /* tail of file */
+ curr_buf->top_of_win = back_line(curr_buf->lastline, t_lines - 1);
+ curr_buf->currline = curr_buf->lastline;
+ curr_buf->curr_window_line = get_lineno_in_window();
+ curr_buf->currln = curr_buf->totaln;
+ curr_buf->redraw_everything = YEA;
+ curr_buf->currpnt = 0;
+ break;
+ case KEY_HOME:
+ case Ctrl('A'):
+ curr_buf->currpnt = 0;
+ break;
+ case Ctrl('O'): // better not use ^O - UNIX not sending.
+ case KEY_INS: /* Toggle insert/overwrite */
+ if (has_block_selection() && curr_buf->insert_mode) {
+ char ans[4];
+
+ getdata(b_lines - 1, 0,
+ "°Ï¶ô·L½Õ¥k²¾´¡¤J¦r¤¸(¹w³]¬°ªÅ¥Õ¦r¤¸)",
+ ans, sizeof(ans), LCECHO);
+ curr_buf->insert_c = ans[0] ? ans[0] : ' ';
+ }
+ curr_buf->insert_mode ^= 1;
+ break;
+ case Ctrl('H'):
+ case '\177': /* backspace */
+ block_cancel();
+ if (curr_buf->ansimode) {
+ curr_buf->ansimode = 0;
+ clear();
+ curr_buf->redraw_everything = YEA;
+ } else {
+ if (curr_buf->currpnt == 0) {
+ if (!curr_buf->currline->prev)
+ break;
+ 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);
+ curr_buf->oldcurrline = curr_buf->currline;
+
+ curr_buf->currpnt = curr_buf->currline->len;
+ curr_buf->redraw_everything = YEA;
+ if (curr_buf->currline->next == curr_buf->top_of_win) {
+ curr_buf->top_of_win = curr_buf->currline;
+ curr_buf->curr_window_line = 0;
+ }
+ if (*next_non_space_char(curr_buf->currline->next->data) == '\0') {
+ delete_line(curr_buf->currline->next, 0);
+ break;
+ }
+ join(curr_buf->currline);
+ break;
+ }
+#ifndef DBCSAWARE
+ curr_buf->currpnt--;
+ delete_char();
+#else
+ {
+ int newpnt = curr_buf->currpnt - 1;
+
+ if(mbcs_mode)
+ newpnt = fix_cursor(curr_buf->currline->data, newpnt, FC_LEFT);
+
+ for(; curr_buf->currpnt > newpnt;)
+ {
+ curr_buf->currpnt --;
+ delete_char();
+ }
+ }
+#endif
+ }
+ break;
+ case Ctrl('D'):
+ case KEY_DEL: /* delete current character */
+ block_cancel();
+ if (curr_buf->currline->len == curr_buf->currpnt) {
+ join(curr_buf->currline);
+ curr_buf->redraw_everything = YEA;
+ } else {
+#ifndef DBCSAWARE
+ delete_char();
+#else
+ {
+ int w = 1;
+
+ if(mbcs_mode)
+ w = mchar_len((unsigned char*)(curr_buf->currline->data + curr_buf->currpnt));
+
+ for(; w > 0; w --)
+ delete_char();
+ }
+#endif
+ if (curr_buf->ansimode)
+ curr_buf->currpnt = ansi2n(n2ansi(curr_buf->currpnt, curr_buf->currline), curr_buf->currline);
+ }
+ break;
+ case Ctrl('Y'): /* delete current line */
+ curr_buf->currline->len = curr_buf->currpnt = 0;
+ case Ctrl('K'): /* delete to end of line */
+ block_cancel();
+ if (curr_buf->currline->len == 0) {
+ textline_t *p = curr_buf->currline->next;
+ if (!p) {
+ p = curr_buf->currline->prev;
+ if (!p) {
+ curr_buf->currline->data[0] = 0;
+ break;
+ }
+ if (curr_buf->curr_window_line > 0) {
+ curr_buf->curr_window_line--;
+ }
+ curr_buf->currln--;
+ }
+ if (curr_buf->currline == curr_buf->top_of_win)
+ curr_buf->top_of_win = p;
+
+ delete_line(curr_buf->currline, 1);
+ curr_buf->currline = p;
+ curr_buf->redraw_everything = YEA;
+ curr_buf->oldcurrline = curr_buf->currline = adjustline(curr_buf->currline, WRAPMARGIN);
+ break;
+ }
+ else if (curr_buf->currline->len == curr_buf->currpnt) {
+ join(curr_buf->currline);
+ curr_buf->redraw_everything = YEA;
+ break;
+ }
+ curr_buf->currline->len = curr_buf->currpnt;
+ curr_buf->currline->data[curr_buf->currpnt] = '\0';
+ break;
+ }
+
+ if (curr_buf->currln < 0)
+ curr_buf->currln = 0;
+
+ if (curr_buf->curr_window_line < 0)
+ window_scroll_down();
+ else if (cursor_at_bottom_line())
+ window_scroll_up();
+#ifdef DBCSAWARE
+ if(mbcs_mode)
+ curr_buf->currpnt = fix_cursor(curr_buf->currline->data, curr_buf->currpnt, FC_LEFT);
+#endif
+ }
+
+ if (curr_buf->ansimode)
+ tmp = n2ansi(curr_buf->currpnt, curr_buf->currline);
+ else
+ tmp = curr_buf->currpnt;
+
+ if (tmp < t_columns - 1)
+ curr_buf->edit_margin = 0;
+ else
+ curr_buf->edit_margin = tmp / (t_columns - 8) * (t_columns - 8);
+
+ if (!curr_buf->redraw_everything) {
+ 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->ansimode)
+ outs(curr_buf->currline->data);
+ else
+ {
+ int attr = EOATTR_NORMAL;
+ attr |= detect_attr(curr_buf->currline->data, curr_buf->currline->len);
+ edit_outs_attr(&curr_buf->currline->data[curr_buf->edit_margin], attr);
+ }
+ outs(ANSI_RESET ANSI_CLRTOEND);
+ edit_msg();
+ }
+ } /* redraw */
+ } /* main event loop */
+
+ exit_edit_buffer();
+}
+
+int
+vedit(char *fpath, int saveheader, int *islocal)
+{
+ return vedit2(fpath, saveheader, islocal, EDITFLAG_ALLOWTITLE);
+}
+
+/* vim:sw=4:nofoldenable
+ */