From 0487addce5ddefe4bbd9736aaa46644271787315 Mon Sep 17 00:00:00 2001 From: piaip Date: Thu, 17 Apr 2008 12:02:18 +0000 Subject: - (internal) change chat to use vgetstring with new callback system - (internal) move DBCS API to string lib git-svn-id: http://opensvn.csie.org/pttbbs/trunk/pttbbs@4176 63ad8ddf-47c3-0310-b6dd-a9e9d9715204 --- common/sys/string.c | 60 +++++++++++ include/cmsys.h | 1 + include/visio.h | 18 ++-- mbbsd/admin.c | 14 +-- mbbsd/announce.c | 2 +- mbbsd/chat.c | 296 +++++++++++++++++++--------------------------------- mbbsd/pfterm.c | 12 +-- mbbsd/pmore.c | 12 +-- mbbsd/read.c | 75 +------------ mbbsd/visio.c | 127 +++++++++++++++++----- 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 // 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 * 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 * 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); +} + -- cgit v1.2.3