summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/sys/string.c60
-rw-r--r--include/cmsys.h1
-rw-r--r--include/visio.h18
-rw-r--r--mbbsd/admin.c14
-rw-r--r--mbbsd/announce.c2
-rw-r--r--mbbsd/chat.c296
-rw-r--r--mbbsd/pfterm.c12
-rw-r--r--mbbsd/pmore.c12
-rw-r--r--mbbsd/read.c75
-rw-r--r--mbbsd/visio.c127
10 files changed, 299 insertions, 318 deletions
diff --git a/common/sys/string.c b/common/sys/string.c
index 908f1fb4..8754e00c 100644
--- a/common/sys/string.c
+++ b/common/sys/string.c
@@ -59,6 +59,9 @@ void chomp(char *src)
}
}
+/* ----------------------------------------------------- */
+/* ANSI 處理函數 */
+/* ----------------------------------------------------- */
int
strip_blank(char *cbuf, char *buf)
{
@@ -220,6 +223,10 @@ strlen_noansi(const char *s)
return count;
}
+/* ----------------------------------------------------- */
+/* DBCS 處理函數 */
+/* ----------------------------------------------------- */
+
void
strip_nonebig5(unsigned char *str, int maxlen)
{
@@ -250,6 +257,9 @@ strip_nonebig5(unsigned char *str, int maxlen)
str[len]='\0';
}
+/**
+ * DBCS_RemoveIntrEscape(buf, len): 去除 buf 中的一字雙色。
+ */
int DBCS_RemoveIntrEscape(unsigned char *buf, int *len)
{
register int isInAnsi = 0, isInDBCS = 0;
@@ -311,6 +321,9 @@ int DBCS_RemoveIntrEscape(unsigned char *buf, int *len)
return (oldl != l) ? 1 : 0;
}
+/**
+ * DBCS_Status(dbcstr, pos): 傳回 dbcstr 中 pos 位置字元的狀態。
+ */
int DBCS_Status(const char *dbcstr, int pos)
{
int sts = DBCS_ASCII;
@@ -331,6 +344,53 @@ int DBCS_Status(const char *dbcstr, int pos)
return sts;
}
+// return: 1 - found, 0 - fail.
+int
+DBCS_strcasestr(const char* pool, const char *ptr)
+{
+ int i = 0, i2 = 0, found = 0,
+ szpool = strlen(pool),
+ szptr = strlen(ptr);
+
+ for (i = 0; i <= szpool-szptr; i++)
+ {
+ found = 1;
+
+ // compare szpool[i..szptr] with ptr
+ for (i2 = 0; i2 < szptr; i2++)
+ {
+ if (pool[i + i2] > 0)
+ {
+ // ascii
+ if (ptr[i2] < 0 ||
+ tolower(ptr[i2]) != tolower(pool[i+i2]))
+ {
+ // printf("break on ascii (i=%d, i2=%d).\n", i, i2);
+ found = 0;
+ break;
+ }
+ } else {
+ // non-ascii
+ if (ptr[i2] != pool[i+i2] ||
+ ptr[i2+1] != pool[i+i2+1])
+ {
+ // printf("break on non-ascii (i=%d, i2=%d).\n", i, i2);
+ found = 0;
+ break;
+ }
+ i2 ++;
+ }
+ }
+
+ if (found) break;
+
+ // next iteration: if target is DBCS, skip one more byte.
+ if (pool[i] < 0)
+ i++;
+ }
+ return found;
+}
+
/* ----------------------------------------------------- */
/* 字串檢查函數:英文、數字、檔名、E-mail address */
/* ----------------------------------------------------- */
diff --git a/include/cmsys.h b/include/cmsys.h
index 879b75e9..3f051d09 100644
--- a/include/cmsys.h
+++ b/include/cmsys.h
@@ -93,6 +93,7 @@ extern int strip_ansi(char *buf, const char *str, enum STRIP_FLAG flag);
extern void strip_nonebig5(unsigned char *str, int maxlen);
extern int DBCS_RemoveIntrEscape(unsigned char *buf, int *len);
extern int DBCS_Status(const char *dbcstr, int pos);
+extern int DBCS_strcasestr(const char* pool, const char *ptr);
extern int invalid_pname(const char *str);
extern int is_number(const char *p);
extern char * qp_encode (char *s, size_t slen, const char *d, const char *tocode);
diff --git a/include/visio.h b/include/visio.h
index aafcd0af..bfc9c945 100644
--- a/include/visio.h
+++ b/include/visio.h
@@ -71,12 +71,17 @@ typedef struct {
} VCOL;
-typedef int (*VGET_CALLBACK)(char *buf, int *pcurr, int len, void *ptr);
+#define VGETCB_NONE (0) // do nothing
+#define VGETCB_NEXT (1) // skip to next event loop
+#define VGETCB_END (2) // finish input
+#define VGETCB_ABORT (3) // clear buffer and finish
+
+typedef int (*VGET_FCALLBACK)(int key, char *buf, int *picurr, int *piend, int len, void *param);
typedef struct {
- VGET_CALLBACK peek; // called immediately after key hit
- VGET_CALLBACK accept; // called before inserting character data
- // ... ?
-} VGET_EXTENSION;
+ VGET_FCALLBACK peek; // called immediately after key hit
+ VGET_FCALLBACK data; // called before inserting character data
+ VGET_FCALLBACK post; // called after every data inserted into buffer.
+} VGET_CALLBACKS;
// API DEFINITION ----------------------------------------------------
@@ -108,7 +113,8 @@ void vshowmsg(const char *msg); /// draw standard pause/message
// vget: (y, x, ...)
int vgets (char *buf, int len, int flags); /// input with edit box control
int vgetstr (char *buf, int len, int flags, const char *str);/// input with default value
-int vget(int y, int x, const char *prompt, char *buf, int len, int mode);
+int vget (int y, int x, const char *prompt, char *buf, int len, int mode);
+int vgetstring(char *_buf, int len, int flags, const char *defstr, const VGET_CALLBACKS *pcb, void *cbparam);
// vs_*: formatted and themed virtual screen layout
// you cannot use ANSI escapes in these APIs.
diff --git a/mbbsd/admin.c b/mbbsd/admin.c
index 66aec48a..6855daf0 100644
--- a/mbbsd/admin.c
+++ b/mbbsd/admin.c
@@ -145,25 +145,25 @@ search_key_user(const char *passwdfile, int mode)
} else {
// search by keytype
if ((!keytype || keytype == 1) &&
- strcasestr(user.userid, key))
+ DBCS_strcasestr(user.userid, key))
keymatch = user.userid;
else if ((!keytype || keytype == 2) &&
- strcasestr(user.realname, key))
+ DBCS_strcasestr(user.realname, key))
keymatch = user.realname;
else if ((!keytype || keytype == 3) &&
- strcasestr(user.nickname, key))
+ DBCS_strcasestr(user.nickname, key))
keymatch = user.nickname;
else if ((!keytype || keytype == 4) &&
- strcasestr(user.address, key))
+ DBCS_strcasestr(user.address, key))
keymatch = user.address;
else if ((!keytype || keytype == 5) &&
- strcasestr(user.email, key))
+ DBCS_strcasestr(user.email, key))
keymatch = user.email;
else if ((!keytype || keytype == 6) &&
- strcasestr(user.lasthost, key))
+ DBCS_strcasestr(user.lasthost, key))
keymatch = user.lasthost;
else if ((!keytype || keytype == 7) &&
- strcasestr(user.justify, key))
+ DBCS_strcasestr(user.justify, key))
keymatch = user.justify;
}
diff --git a/mbbsd/announce.c b/mbbsd/announce.c
index 4d785908..ef8f83d6 100644
--- a/mbbsd/announce.c
+++ b/mbbsd/announce.c
@@ -302,7 +302,7 @@ a_searchtitle(menu_t * pm, int rev)
if (!a_loadname(pm))
return pm->now;
}
- if (strcasestr(pm->header[pos - pm->page].title, search_str))
+ if (DBCS_strcasestr(pm->header[pos - pm->page].title, search_str))
return pos;
} while (pos != pm->now);
return pm->now;
diff --git a/mbbsd/chat.c b/mbbsd/chat.c
index fe954bfc..4e931199 100644
--- a/mbbsd/chat.c
+++ b/mbbsd/chat.c
@@ -260,21 +260,64 @@ chat_cmd(char *buf, int fd)
return 0;
}
-#define MAXLASTCMD 6
+typedef struct {
+ struct ChatBuf *chatbuf;
+ int cfd;
+ char *chatroom;
+ char *chatid;
+ int *chatting;
+} ChatCbParam;
+
+// static
+int
+_vgetcb_peek(int key, char *buf, int *picurr, int *piend, int len, void *ptr)
+{
+ ChatCbParam *p = (ChatCbParam*) ptr;
+ assert(p);
+
+ switch (key) {
+ case I_OTHERDATA: // incoming
+ // XXX why 9? I don't know... just copied from old code.
+ if (chat_recv(p->chatbuf, p->cfd, p->chatroom, p->chatid, 9) == -1) {
+ chat_send(p->cfd, "/b");
+ *(p->chatting) = 0;
+ return VGETCB_ABORT;
+ }
+ return VGETCB_NEXT;
+
+ case Ctrl('C'):
+ chat_send(p->cfd, "/b");
+ *(p->chatting) = 0;
+ return VGETCB_ABORT;
+
+ case Ctrl('I'):
+ {
+ VREFSCR scr = vscr_save();
+ add_io(0, 0);
+ t_idle();
+ vscr_restore(scr);
+ add_io(p->cfd, 0);
+ }
+ return VGETCB_NEXT;
+ }
+ return VGETCB_NONE;
+}
+
static int chatid_len = 10;
-static time4_t lastEnter = 0;
int
t_chat(void)
{
- char chatroom[IDLEN+1];/* Chat-Room Name */
- char inbuf[80], chatid[20], lastcmd[MAXLASTCMD][80], *ptr = "";
+ static time4_t lastEnter = 0;
+
+ char chatroom[IDLEN+1] = "";/* Chat-Room Name */
+ char inbuf[80], chatid[20] = "", *ptr = "";
struct sockaddr_in sin;
- int cfd, cmdpos, ch;
- int currchar;
+ int cfd;
int chatting = YEA;
- char fpath[80];
- struct ChatBuf chatbuf;
+ char fpath[PATHLEN];
+ struct ChatBuf chatbuf;
+ ChatCbParam vgetparam = {0};
if(HasUserPerm(PERM_VIOLATELAW))
{
@@ -356,10 +399,6 @@ t_chat(void)
add_io(cfd, 0);
- currchar = 0;
- cmdpos = -1;
- memset(lastcmd, 0, sizeof(lastcmd));
-
setutmpmode(CHATING);
currutmp->in_chat = YEA;
strlcpy(currutmp->chatid, chatid, sizeof(currutmp->chatid));
@@ -379,191 +418,70 @@ t_chat(void)
setuserfile(fpath, "chat_XXXXXX");
flog = fdopen(mkstemp(fpath), "w");
+ // set up vgetstring callback parameter
+ VGET_CALLBACKS vge = { _vgetcb_peek };
+
+ vgetparam.chatbuf = &chatbuf;
+ vgetparam.cfd = cfd;
+ vgetparam.chatid = chatid;
+ vgetparam.chatroom = chatroom;
+ vgetparam.chatting = &chatting;
+
while (chatting) {
- move(b_lines - 1, currchar + chatid_len);
- ch = igetch();
-
- switch (ch) {
- case KEY_DOWN:
- cmdpos += MAXLASTCMD - 2;
- case KEY_UP:
- cmdpos++;
- cmdpos %= MAXLASTCMD;
- strlcpy(inbuf, lastcmd[cmdpos], sizeof(inbuf));
- move(b_lines - 1, chatid_len);
- clrtoeol();
- outs(inbuf);
- currchar = strlen(inbuf);
- continue;
- case KEY_LEFT:
- if (currchar)
- {
- --currchar;
-#ifdef DBCSAWARE
- if(currchar > 0 &&
- ISDBCSAWARE() &&
- DBCS_Status(inbuf, currchar) == DBCS_TRAILING)
- currchar --;
-#endif
- }
- continue;
- case KEY_RIGHT:
- if (inbuf[currchar])
- {
- ++currchar;
-#ifdef DBCSAWARE
- if(inbuf[currchar] &&
- ISDBCSAWARE() &&
- DBCS_Status(inbuf, currchar) == DBCS_TRAILING)
- currchar++;
-#endif
- }
- continue;
- case KEY_UNKNOWN:
- continue;
- }
+ print_chatid(chatid);
+ move(b_lines-1, chatid_len);
- if (ISNEWMAIL(currutmp)) {
- printchatline("◆ 噹!郵差又來了...");
- }
- if (ch == I_OTHERDATA) {/* incoming */
- if (chat_recv(&chatbuf, cfd, chatroom, chatid, 9) == -1) {
- chatting = chat_send(cfd, "/b");
- break;
- }
- } else if (isprint2(ch)) {
- if (currchar < 68) {
- if (inbuf[currchar]) { /* insert */
- int i;
-
- for (i = currchar; inbuf[i] && i < 68; i++);
- inbuf[i + 1] = '\0';
- for (; i > currchar; i--)
- inbuf[i] = inbuf[i - 1];
- } else /* append */
- inbuf[currchar + 1] = '\0';
- inbuf[currchar] = ch;
- move(b_lines - 1, currchar + chatid_len);
- outs(&inbuf[currchar++]);
- }
- } else if (ch == '\n' || ch == '\r') {
- if (*inbuf) {
+ // chatid_len = 10, quote(:) occupies 1, so 79-11=68
+ vgetstring(inbuf, 68, VGET_TRANSPARENT, "", &vge, &vgetparam);
-#ifdef EXP_ANTIFLOOD
- // prevent flooding */
- static time4_t lasttime = 0;
- static int flood = 0;
-
- /* // debug anti flodding
- move(b_lines-3, 0); clrtoeol();
- prints("lasttime=%d, now=%d, flood=%d\n",
- lasttime, now, flood);
- refresh();
- */
- syncnow();
- if (now - lasttime < 3 )
- {
- // 3 秒內洗半面是不行的 ((25-5)/2)
- if( ++flood > 10 ){
- // flush all input!
- drop_input();
- while (wait_input(1, 0))
- {
- if (num_in_buf())
- drop_input();
- else
- tty_read((unsigned char*)inbuf, sizeof(inbuf));
- }
- drop_input();
- vmsg("請勿大量剪貼或造成洗板面的效果。");
- // log?
- sleep(2);
- continue;
- }
- } else {
- lasttime = now;
- flood = 0;
- }
-#endif // anti-flood
+ // quick check for end flag or exit command.
+ if (!chatting || strncmp(inbuf, "/b", 2) == 0)
+ break;
- chatting = chat_cmd(inbuf, cfd);
- if (chatting == 0)
- chatting = chat_send(cfd, inbuf);
- if (!strncmp(inbuf, "/b", 2))
- break;
+ // quick continue for empty input
+ if (!*inbuf)
+ continue;
- for (cmdpos = MAXLASTCMD - 1; cmdpos; cmdpos--)
- strlcpy(lastcmd[cmdpos],
- lastcmd[cmdpos - 1], sizeof(lastcmd[cmdpos]));
- strlcpy(lastcmd[0], inbuf, sizeof(lastcmd[0]));
+#ifdef EXP_ANTIFLOOD
+ {
+ // prevent flooding */
+ static time4_t lasttime = 0;
+ static int flood = 0;
- inbuf[0] = '\0';
- currchar = 0;
- cmdpos = -1;
- }
- print_chatid(chatid);
- move(b_lines - 1, chatid_len);
- } else if (ch == Ctrl('H') || ch == KEY_BS2) {
- if (currchar) {
-#ifdef DBCSAWARE
- int dbcs_off = 1;
- if (ISDBCSAWARE() &&
- DBCS_Status(inbuf, currchar-1) == DBCS_TRAILING)
- dbcs_off = 2;
-#endif
- currchar -= dbcs_off;
- inbuf[69] = '\0';
- memcpy(&inbuf[currchar], &inbuf[currchar + dbcs_off],
- 69 - currchar);
- move(b_lines - 1, currchar + chatid_len);
- clrtoeol();
- outs(&inbuf[currchar]);
- }
- } else if (ch == Ctrl('Z') || ch == Ctrl('Y')) {
- inbuf[0] = '\0';
- currchar = 0;
- print_chatid(chatid);
- move(b_lines - 1, chatid_len);
- } else if (ch == Ctrl('C')) {
- chat_send(cfd, "/b");
- break;
- } else if (ch == Ctrl('D')) {
- if ((size_t)currchar < strlen(inbuf)) {
-#ifdef DBCSAWARE
- int dbcs_off = 1;
- if (ISDBCSAWARE() && inbuf[currchar+1] &&
- DBCS_Status(inbuf, currchar+1) == DBCS_TRAILING)
- dbcs_off = 2;
-#endif
- inbuf[69] = '\0';
- memcpy(&inbuf[currchar], &inbuf[currchar + dbcs_off],
- 69 - currchar);
- move(b_lines - 1, currchar + chatid_len);
- clrtoeol();
- outs(&inbuf[currchar]);
+ syncnow();
+ if (now - lasttime < 3 )
+ {
+ // 3 秒內洗半面是不行的 ((25-5)/2)
+ if( ++flood > 10 ){
+ // flush all input!
+ drop_input();
+ while (wait_input(1, 0))
+ {
+ if (num_in_buf())
+ drop_input();
+ else
+ tty_read((unsigned char*)inbuf, sizeof(inbuf));
+ }
+ drop_input();
+ vmsg("請勿大量剪貼或造成洗板面的效果。");
+ // log?
+ sleep(2);
+ continue;
+ }
+ } else {
+ lasttime = now;
+ flood = 0;
}
- } else if (ch == Ctrl('K')) {
- inbuf[currchar] = 0;
- move(b_lines - 1, currchar + chatid_len);
- clrtoeol();
- } else if (ch == Ctrl('A')) {
- currchar = 0;
- } else if (ch == Ctrl('E')) {
- currchar = strlen(inbuf);
- } else if (ch == Ctrl('I')) {
- screen_backup_t old_screen;
-
- scr_dump(&old_screen);
- add_io(0, 0);
- t_idle();
- scr_restore(&old_screen);
- add_io(cfd, 0);
- } else if (ch == Ctrl('Q')) {
- print_chatid(chatid);
- move(b_lines - 1, chatid_len);
- outs(inbuf);
- continue;
}
+#endif // anti-flood
+
+ // send message to server if possible.
+ if (!chat_cmd(inbuf, cfd))
+ chatting = chat_send(cfd, inbuf);
+
+ // print mail message if possible.
+ if (ISNEWMAIL(currutmp))
+ printchatline("◆ 噹!郵差又來了...");
}
close(cfd);
diff --git a/mbbsd/pfterm.c b/mbbsd/pfterm.c
index ebfad7e5..d1284ec0 100644
--- a/mbbsd/pfterm.c
+++ b/mbbsd/pfterm.c
@@ -96,7 +96,7 @@
// Copyright (c) 2007-2008 Hung-Te Lin <piaip@csie.ntu.edu.tw>
// All rights reserved.
//
-// This is distributed under a Non-Commercial 4clause-BSD alike license.
+// Distributed under a Non-Commercial 4clause-BSD alike license.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
@@ -108,13 +108,9 @@
// documentation and/or other materials provided with the distribution.
// 3. All advertising materials mentioning features or use of this software
// must display appropriate acknowledgement, like:
-// This product includes software developed by Hung-Te Lin (piaip)
-// and its contributors.
-// The acknowledgement can be localized in any language or style.
-// 4. Neither the name of Hung-Te Lin nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-// 5. You may not exercise any of the rights granted to you above in any
+// This product includes software developed by Hung-Te Lin (piaip).
+// The acknowledgement can be localized with the name unchanged.
+// 4. You may not exercise any of the rights granted to you above in any
// manner that is primarily intended for or directed toward commercial
// advantage or private monetary compensation. For avoidance of doubt,
// using in a program providing commercial network service is also
diff --git a/mbbsd/pmore.c b/mbbsd/pmore.c
index d3d542e2..b055539d 100644
--- a/mbbsd/pmore.c
+++ b/mbbsd/pmore.c
@@ -15,7 +15,7 @@
* Copyright (c) 2005-2008 Hung-Te Lin <piaip@csie.ntu.edu.tw>
* All rights reserved.
*
- * This is distributed under a Non-Commercial 4clause-BSD alike license.
+ * Distributed under a Non-Commercial 4clause-BSD alike license.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -27,13 +27,9 @@
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display appropriate acknowledgement, like:
- * This product includes software developed by Hung-Te Lin (piaip)
- * and its contributors.
- * The acknowledgement can be localized in any language or style.
- * 4. Neither the name of Hung-Te Lin nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * 5. You may not exercise any of the rights granted to you above in any
+ * This product includes software developed by Hung-Te Lin (piaip).
+ * The acknowledgement can be localized with the name unchanged.
+ * 4. You may not exercise any of the rights granted to you above in any
* manner that is primarily intended for or directed toward commercial
* advantage or private monetary compensation. For avoidance of doubt,
* using in a program providing commercial network service is also
diff --git a/mbbsd/read.c b/mbbsd/read.c
index c2aff26c..4da10dbd 100644
--- a/mbbsd/read.c
+++ b/mbbsd/read.c
@@ -407,75 +407,6 @@ mail_forward(const fileheader_t * fhdr, const char *direct, int mode)
}
#endif
-// return: 1 - found, 0 - fail.
-inline static int
-dbcs_strcasestr(const char* pool, const char *ptr)
-{
-#if 0
- // old method
- int len = strlen(ptr);
-
- while(*pool)
- {
- // FIXME 用 strncasecmp 還是會錯
- if(strncasecmp(pool, ptr, len) == 0)
- return 1;
- /* else */
- if(*pool < 0)
- {
- pool ++;
- if(*pool == 0)
- return 0;
- }
- pool ++;
- }
- return 0;
-
-#endif
-
- int i = 0, i2 = 0, found = 0,
- szpool = strlen(pool),
- szptr = strlen(ptr);
-
- for (i = 0; i <= szpool-szptr; i++)
- {
- found = 1;
-
- // compare szpool[i..szptr] with ptr
- for (i2 = 0; i2 < szptr; i2++)
- {
- if (pool[i + i2] > 0)
- {
- // ascii
- if (ptr[i2] < 0 ||
- tolower(ptr[i2]) != tolower(pool[i+i2]))
- {
- // printf("break on ascii (i=%d, i2=%d).\n", i, i2);
- found = 0;
- break;
- }
- } else {
- // non-ascii
- if (ptr[i2] != pool[i+i2] ||
- ptr[i2+1] != pool[i+i2+1])
- {
- // printf("break on non-ascii (i=%d, i2=%d).\n", i, i2);
- found = 0;
- break;
- }
- i2 ++;
- }
- }
-
- if (found) break;
-
- // next iteration: if target is DBCS, skip one more byte.
- if (pool[i] < 0)
- i++;
- }
- return found;
-}
-
static int
select_read(const keeploc_t * locmem, int sr_mode)
{
@@ -661,13 +592,13 @@ select_read(const keeploc_t * locmem, int sr_mode)
!strncmp(fhs[i].title, "Re:", 3))
continue;
else if((sr_mode & RS_AUTHOR) &&
- !dbcs_strcasestr(fhs[i].owner, keyword))
+ !DBCS_strcasestr(fhs[i].owner, keyword))
continue;
else if((sr_mode & RS_KEYWORD) &&
- !dbcs_strcasestr(fhs[i].title, keyword))
+ !DBCS_strcasestr(fhs[i].title, keyword))
continue;
else if(sr_mode & RS_KEYWORD_EXCLUDE &&
- dbcs_strcasestr(fhs[i].title, keyword))
+ DBCS_strcasestr(fhs[i].title, keyword))
continue;
else if((sr_mode & RS_TITLE) &&
strcasecmp(subject(fhs[i].title), keyword))
diff --git a/mbbsd/visio.c b/mbbsd/visio.c
index 56628cf0..b0949d01 100644
--- a/mbbsd/visio.c
+++ b/mbbsd/visio.c
@@ -21,7 +21,7 @@
* Copyright (c) 2005-2008 Hung-Te Lin <piaip@csie.ntu.edu.tw>
* All rights reserved.
*
- * This is distributed under a Non-Commercial 4clause-BSD alike license.
+ * Distributed under a Non-Commercial 4clause-BSD alike license.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -33,13 +33,9 @@
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display appropriate acknowledgement, like:
- * This product includes software developed by Hung-Te Lin (piaip)
- * and its contributors.
- * The acknowledgement can be localized in any language or style.
- * 4. Neither the name of Hung-Te Lin nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * 5. You may not exercise any of the rights granted to you above in any
+ * This product includes software developed by Hung-Te Lin (piaip).
+ * The acknowledgement can be localized with the name unchanged.
+ * 4. You may not exercise any of the rights granted to you above in any
* manner that is primarily intended for or directed toward commercial
* advantage or private monetary compensation. For avoidance of doubt,
* using in a program providing commercial network service is also
@@ -746,10 +742,12 @@ InputHistoryAdd(const char *s)
int i = 0;
if (!s || !*s || !*(s+1))
return 0;
+
// TODO if already in queue, change order...?
for (i = 0; i < IH_MAX_ENTRIES; i++)
if (strcmp(s, ih.buf[i]) == 0)
return 0;
+
strlcpy(ih.buf[ih.iappend], s, sizeof(ih.buf[ih.iappend]));
ih.icurr = ih.iappend;
ih.iappend ++;
@@ -767,13 +765,17 @@ InputHistoryDelta(char *s, int sz, int d)
if (ih.buf[xcurr][0])
{
ih.icurr = xcurr;
+
+ // copy buffer
+ strlcpy(s, ih.buf[ih.icurr], sz);
+
+ // DBCS safe
+ i = strlen(s);
+ if (DBCS_Status(s, i) == DBCS_TRAILING)
+ s[i-1] = 0;
break;
}
}
- if (ih.buf[ih.icurr][0])
- {
- strlcpy(s, ih.buf[ih.icurr], sz);
- }
}
void
@@ -791,14 +793,38 @@ InputHistoryNext(char *s, int sz)
////////////////////////////////////////////////////////////////////////
// vget*: mini editbox
////////////////////////////////////////////////////////////////////////
-int
-vgets(char *buf, int len, int flags)
+
+static inline int
+_vgetcbhandler(VGET_FCALLBACK cbptr, int *pabort,
+ int c, char *buf, int *picurr, int *piend, int len, void *cbparam)
{
- return vgetstr(buf, len, flags, "");
+ if (!cbptr)
+ return 0;
+
+ switch(cbptr(c, buf, picurr, piend, len, cbparam))
+ {
+ case VGETCB_NONE:
+ return 0;
+
+ case VGETCB_NEXT:
+ return 1;
+
+ case VGETCB_END:
+ *pabort = 1;
+ return 1;
+
+ case VGETCB_ABORT:
+ *pabort = 1;
+ *picurr = *piend = 0;
+ buf[0] = 0;
+ return 1;
+ }
+ assert(0); // shall never reach here
+ return 0;
}
int
-vgetstr(char *_buf, int len, int flags, const char *defstr)
+vgetstring(char *_buf, int len, int flags, const char *defstr, const VGET_CALLBACKS *pcb, void *cbparam)
{
// iend points to NUL address, and
// icurr points to cursor.
@@ -809,6 +835,9 @@ vgetstr(char *_buf, int len, int flags, const char *defstr)
// always use internal buffer to prevent temporary input issue.
char buf[STRLEN] = ""; // zero whole.
+ // callback
+ VGET_CALLBACKS cb = {NULL};
+
// it is wrong to design input with larger buffer
// than STRLEN. Although we support large screen,
// inputting huge line will just make troubles...
@@ -823,6 +852,14 @@ vgetstr(char *_buf, int len, int flags, const char *defstr)
icurr = iend = strlen(buf);
}
+ // setup callbacks
+ if (pcb)
+ {
+ if (pcb->peek) cb.peek = pcb->peek;
+ if (pcb->data) cb.data = pcb->data;
+ if (pcb->post) cb.post = pcb->post;
+ }
+
getyx(&line, &col); // now (line,col) is the beginning of our new fields.
while (!abort)
@@ -844,6 +881,12 @@ vgetstr(char *_buf, int len, int flags, const char *defstr)
}
c = vkey();
+ // callback 1: peek
+ if (_vgetcbhandler(cb.peek, &abort,
+ c, buf, &icurr, &iend, len, cbparam))
+ continue;
+
+ // standard key bindings
switch(c) {
// history navigation
case KEY_DOWN: case Ctrl('N'):
@@ -947,28 +990,29 @@ vgetstr(char *_buf, int len, int flags, const char *defstr)
default:
// content filter
- if (c < ' ' || c >= 0xFF ||
- iend+1 >= len)
+ if (c < ' ' || c >= 0xFF)
{
- bell();
- continue;
+ bell(); continue;
}
if ((flags & VGET_DIGITS) &&
( !isascii(c) || !isdigit(c)))
{
- bell();
- continue;
+ bell(); continue;
}
if (flags & VGET_LOWERCASE)
{
if (!isascii(c))
{
- bell();
- continue;
+ bell(); continue;
}
c = tolower(c);
}
+ // size check
+ if(iend+1 >= len)
+ {
+ bell(); continue;
+ }
// prevent incomplete DBCS
// this check only works if DBCS-aware is active.
// Otherwise, non-DBCS-aware users will fail to
@@ -978,15 +1022,31 @@ vgetstr(char *_buf, int len, int flags, const char *defstr)
c > 0x80 && iend+2 >= len &&
!CHKDBCSTRAIL(buf, icurr) )
{
- bell();
- continue;
+ bell(); continue;
}
#endif // DBCSAWARE
+ // callback 2: data
+ if (_vgetcbhandler(cb.data, &abort,
+ c, buf, &icurr, &iend, len, cbparam))
+ continue;
+
+ // size check again, due to data callback.
+ if(iend+1 >= len)
+ {
+ bell(); continue;
+ }
+
// add one character.
memmove(buf+icurr+1, buf+icurr, iend-icurr+1);
buf[icurr++] = c;
iend++;
+
+ // callback 3: post
+ if (_vgetcbhandler(cb.post, &abort,
+ c, buf, &icurr, &iend, len, cbparam))
+ continue;
+
break;
}
}
@@ -999,10 +1059,23 @@ vgetstr(char *_buf, int len, int flags, const char *defstr)
buf[0] = tolower(buf[0]);
// save the history except password mode
- if (!(flags & VGET_NOECHO))
+ if (buf[0] && !(flags & VGET_NOECHO))
InputHistoryAdd(buf);
// copy buffer!
memcpy(_buf, buf, len);
return iend;
}
+
+int
+vgets(char *buf, int len, int flags)
+{
+ return vgetstr(buf, len, flags, "");
+}
+
+int
+vgetstr(char *buf, int len, int flags, const char *defstr)
+{
+ return vgetstring(buf, len, flags, defstr, NULL, NULL);
+}
+