diff options
-rw-r--r-- | pttbbs/include/cmsys.h | 9 | ||||
-rw-r--r-- | pttbbs/include/convert.h | 12 | ||||
-rw-r--r-- | pttbbs/include/proto.h | 4 | ||||
-rw-r--r-- | pttbbs/mbbsd/convert.c | 165 | ||||
-rw-r--r-- | pttbbs/mbbsd/io.c | 183 | ||||
-rw-r--r-- | pttbbs/mbbsd/mbbsd.c | 22 | ||||
-rw-r--r-- | pttbbs/pttbbs.mk | 9 |
7 files changed, 155 insertions, 249 deletions
diff --git a/pttbbs/include/cmsys.h b/pttbbs/include/cmsys.h index f80bbd8d..28b1bd3c 100644 --- a/pttbbs/include/cmsys.h +++ b/pttbbs/include/cmsys.h @@ -294,4 +294,13 @@ extern void telnet_ctx_set_ttype_arg (TelnetCtx *ctx, void *arg); extern ssize_t telnet_process (TelnetCtx *ctx, unsigned char *buf, ssize_t size); +/* utf8.c */ +extern int ucs2utf(uint16_t ucs2, uint8_t *utf8); +extern int utf2ucs(uint8_t *utf8, uint16_t *pucs); + +/* big5.c */ +extern const uint16_t const b2u_table[]; +extern const uint16_t const u2b_table[]; + + #endif diff --git a/pttbbs/include/convert.h b/pttbbs/include/convert.h index 73e6192b..835cf28b 100644 --- a/pttbbs/include/convert.h +++ b/pttbbs/include/convert.h @@ -7,18 +7,14 @@ enum ConvertMode { CONV_NORMAL, - CONV_GB, - CONV_UTF8 + CONV_UTF8, }; -typedef ssize_t (*read_write_type)(int, void *, size_t); -typedef ssize_t (*convert_type)(void *, ssize_t); - -extern read_write_type write_type; -extern read_write_type read_type; -extern convert_type input_type; +extern int (*convert_write)(VBUF *v, char c); +extern int (*convert_read)(VBUF *v, const void* buf, size_t len); extern void init_convert(void); +extern void set_converting_type(int which); #endif // CONVERT #endif // _BBS_CONVERT_H diff --git a/pttbbs/include/proto.h b/pttbbs/include/proto.h index f335c1b7..9afcbe71 100644 --- a/pttbbs/include/proto.h +++ b/pttbbs/include/proto.h @@ -281,10 +281,8 @@ ChessInfo* gomoku_replay(FILE* fp); /* guess */ int guess_main(void); -/* convert */ -void set_converting_type(int which); - /* io */ +int init_io(); // output int ochar(int c); diff --git a/pttbbs/mbbsd/convert.c b/pttbbs/mbbsd/convert.c index 611e54ac..15b62ec1 100644 --- a/pttbbs/mbbsd/convert.c +++ b/pttbbs/mbbsd/convert.c @@ -2,106 +2,72 @@ #include "bbs.h" #ifdef CONVERT +int (*convert_write)(VBUF *v, char c) = vbuf_add; +int (*convert_read)(VBUF *v, const void *buf, size_t len) = vbuf_putblk; -#ifdef CONVERT -extern void big2gb_init(void*); -extern void gb2big_init(void*); -extern void big2uni_init(void*); -extern void uni2big_init(void*); -#endif - -extern unsigned char *gb2big(unsigned char *, int *, int); -extern unsigned char *big2gb(unsigned char *, int *, int); -extern unsigned char *utf8_uni(unsigned char *, int *, int); -extern unsigned char *uni_utf8(unsigned char *, int *, int); -extern unsigned char *uni2big(unsigned char *, int *, int); -extern unsigned char *big2uni(unsigned char *, int *, int); - -static ssize_t -gb_input(void *buf, ssize_t icount) -{ - /* is sizeof(ssize_t) == sizeof(int)? not sure */ - int ic = (int) icount; - gb2big((unsigned char *)buf, &ic, 0); - return (ssize_t)ic; -} - -static ssize_t -gb_read(int fd, void *buf, size_t count) -{ - ssize_t icount = read(fd, buf, count); - if (icount > 0) - icount = gb_input(buf, icount); - return icount; -} - -static ssize_t -gb_write(int fd, void *buf, size_t count) -{ - int icount = (int)count; - big2gb((unsigned char *)buf, &icount, 0); - if(icount > 0) - return write(fd, buf, (size_t)icount); - else - return count; /* fake */ -} +int +convert_write_utf8(VBUF *v, char c) { + static char trail[2] = {0}; + static uint8_t utf8[4]; -static ssize_t -utf8_input (void *buf, ssize_t icount) -{ - /* is sizeof(ssize_t) == sizeof(int)? not sure */ - int ic = (int) icount; - utf8_uni(buf, &ic, 0); - uni2big(buf, &ic, 0); - return (ssize_t)ic; -} + // trail must be little endian. + if (trail[1]) { + trail[0] = c; + int len, i; + uint16_t ucs = b2u_table[*(uint16_t*)trail]; -static ssize_t -utf8_read(int fd, void *buf, size_t count) -{ - ssize_t icount = read(fd, buf, count); - if (icount > 0) - icount = utf8_input(buf, icount); - return icount; -} + len = ucs2utf(ucs, utf8); + utf8[len] = 0; -static ssize_t -utf8_write(int fd, void *buf, size_t count) -{ - int icount = (int)count; - static unsigned char *mybuf = NULL; - static int cmybuf = 0; + // assert(len > 0 && len < 4); + for (i = 0; i < len; i++) + vbuf_add(v, utf8[i]); - /* utf8 output is a special case because - * we need larger buffer which can be - * tripple or more in size. - * Current implementation uses 128 for each block. - */ + trail[1] = 0; + return 1; + } - if(cmybuf < count * 4) { - cmybuf = (count*4+0x80) & (~0x7f) ; - mybuf = (unsigned char*) realloc (mybuf, cmybuf); + if (isascii(c)) { + vbuf_add(v, c); + return 1; } - memcpy(mybuf, buf, count); - big2uni(mybuf, &icount, 0); - uni_utf8(mybuf, &icount, 0); - if(icount > 0) - return write(fd, mybuf, (size_t)icount); - else - return count; /* fake */ + trail[1] = c; + return 0; } -static ssize_t -norm_input(void *buf, ssize_t icount) -{ - return icount; +int convert_read_utf8(VBUF *v, const void *buf, size_t len) { + static uint8_t trail[6]; + static int ctrail = 0; + uint16_t ucs; + uint8_t c; + int written = 0; + + while (len-- > 0) { + c = *(uint8_t*)buf ++; + if (ctrail) { + trail[ctrail++] = c; + // TODO this may create invalid chars. + if (utf2ucs(trail, &ucs) > ctrail) + continue; + ucs = u2b_table[ucs]; + vbuf_add(v, ucs >> 8); + vbuf_add(v, ucs & 0xFF); + written += 2; + ctrail = 0; + continue; + } + + if (isascii(c)) { + vbuf_add(v, c); + written++; + } else { + trail[0] = c; + ctrail = 1; + } + } + return written; } -/* global function pointers */ -read_write_type write_type = (read_write_type)write; -read_write_type read_type = read; -convert_type input_type = norm_input; - // enable this in case some day we want to detect // current type. but right now disable for less memory cost // int bbs_convert_type = CONV_NORMAL; @@ -109,30 +75,17 @@ convert_type input_type = norm_input; void set_converting_type(int which) { if (which == CONV_NORMAL) { - read_type = read; - write_type = (read_write_type)write; - /* for speed up, NULL is better.. */ - input_type = NULL; /* norm_input; */ - } - else if (which == CONV_GB) { - read_type = gb_read; - write_type = gb_write; - input_type = gb_input; + convert_read = vbuf_putblk; + convert_write = vbuf_add; } else if (which == CONV_UTF8) { - read_type = utf8_read; - write_type = utf8_write; - input_type = utf8_input; + convert_read = convert_read_utf8; + convert_write = convert_write_utf8; } - // bbs_convert_type = which; } void init_convert() { - big2gb_init(NULL); - gb2big_init(NULL); - big2uni_init(NULL); - uni2big_init(NULL); } #endif diff --git a/pttbbs/mbbsd/io.c b/pttbbs/mbbsd/io.c index 75de3537..a3e2578a 100644 --- a/pttbbs/mbbsd/io.c +++ b/pttbbs/mbbsd/io.c @@ -6,29 +6,20 @@ #define OBUFSIZE 3072 #define IBUFSIZE 128 -/* realXbuf is Xbuf+3 because hz convert library requires buf[-2]. */ -#define CVTGAP (3) +// Size of space to be preserved, usually for char convertion. +#define BUF_PRESERVE_SPACE_SIZE (4) #ifdef DEBUG #define register +#define inline // #define DBG_OUTRPT #endif -static unsigned char real_outbuf[OBUFSIZE + CVTGAP*2] = " "; -static unsigned char real_inbuf [IBUFSIZE + CVTGAP*2] = " "; +static VBUF vout, *pvout = &vout, vin, *pvin = &vin; // we've seen such pattern - make it accessible for movie mode. #define CLIENT_ANTI_IDLE_STR ESC_STR "OA" ESC_STR "OB" -// use defines instead - it is discovered that sometimes the input/output buffer was overflow, -// without knowing why. -// static unsigned char *outbuf = real_outbuf + 3, *inbuf = real_inbuf + 3; -#define inbuf (real_inbuf +CVTGAP) -#define outbuf (real_outbuf+CVTGAP) - -static int obufsize = 0; -static int ibufsize = 0, icurrchar = 0; - #ifdef DBG_OUTRPT // output counter static unsigned long szTotalOutput = 0, szLastOutput = 0; @@ -48,35 +39,6 @@ static unsigned char fakeEscFilter(unsigned char c) #endif // DBG_OUTRPT /* ----------------------------------------------------- */ -/* convert routines */ -/* ----------------------------------------------------- */ -#ifdef CONVERT - -static inline ssize_t input_wrapper(void *buf, ssize_t count) { - /* input_wrapper is a special case. - * because we may do nothing, - * a if-branch is better than a function-pointer call. - */ - if(input_type) - return (*input_type)(buf, count); - else - return count; -} - -static inline int read_wrapper(int fd, void *buf, size_t count) { - return (*read_type)(fd, buf, count); -} - -static inline int write_wrapper(int fd, void *buf, size_t count) { - return (*write_type)(fd, buf, count); -} -#else -#define write_wrapper write -#define read_wrapper read -// #define input_wrapper(buf,count) count -#endif - -/* ----------------------------------------------------- */ /* debug reporting */ /* ----------------------------------------------------- */ @@ -115,6 +77,15 @@ debug_print_input_buffer(char *s, size_t len) move_ansi(y, x); } #endif +/* ----------------------------------------------------- */ +/* Input Output System */ +/* ----------------------------------------------------- */ +int +init_io() { + vbuf_new(pvout, OBUFSIZE + BUF_PRESERVE_SPACE_SIZE); + vbuf_new(pvin, IBUFSIZE + BUF_PRESERVE_SPACE_SIZE); + return 0; +} /* ----------------------------------------------------- */ /* output routines */ @@ -122,14 +93,12 @@ debug_print_input_buffer(char *s, size_t len) void oflush(void) { - if (obufsize) { - STATINC(STAT_SYSWRITESOCKET); - write_wrapper(1, outbuf, obufsize); - obufsize = 0; + if (!vbuf_is_empty(pvout)) { + STATINC(STAT_SYSWRITESOCKET); + vbuf_write(pvout, 1, VBUF_RWSZ_ALL); } #ifdef DBG_OUTRPT - // if (0) { static char xbuf[128]; sprintf(xbuf, ESC_STR "[s" ESC_STR "[H" " [%lu/%lu] " ESC_STR "[u", @@ -144,48 +113,32 @@ oflush(void) // fsync(1); } -void +inline void output(const char *s, int len) { -#ifdef DBG_OUTRPT - int i = 0; - if (fakeEscape) - for (i = 0; i < obufsize; i++) - outbuf[i] = fakeEscFilter(outbuf[i]); - - szTotalOutput += len; - szLastOutput += len; -#endif // DBG_OUTRPT - - /* Invalid if len >= OBUFSIZE */ - assert(len<OBUFSIZE); - - if (obufsize + len > OBUFSIZE) { - STATINC(STAT_SYSWRITESOCKET); - write_wrapper(1, outbuf, obufsize); - obufsize = 0; - } - memcpy(outbuf + obufsize, s, len); - obufsize += len; + while (len-- > 0) + ochar(*s++); } int ochar(int c) { - #ifdef DBG_OUTRPT + // TODO we can support converted output in future. c = fakeEscFilter(c); szTotalOutput ++; szLastOutput ++; #endif // DBG_OUTRPT - if (obufsize > OBUFSIZE - 1) { - STATINC(STAT_SYSWRITESOCKET); - /* suppose one byte data doesn't need to be converted. */ - write(1, outbuf, obufsize); - obufsize = 0; - } - outbuf[obufsize++] = c; + if (vbuf_is_full(pvout) || vbuf_size(pvout) >= OBUFSIZE) + oflush(); + +#ifdef CONVERT + convert_write(pvout, c); +#else + vbuf_add(pvout, c); +#endif + return 0; } @@ -388,45 +341,47 @@ add_io(int fd, int timeout) inline int num_in_buf(void) { - if (ibufsize <= icurrchar) - return 0; - return ibufsize - icurrchar; + return vbuf_size(pvin); } static inline int input_isfull(void) { - return ibufsize >= IBUFSIZE; + return vbuf_size(pvin) >= IBUFSIZE; } static inline void drop_input(void) { - icurrchar = ibufsize = 0; + vbuf_clear(pvin); } +/* returns: + * >0 if read something + * =0 if nothing read + * <0 if need to read again + */ static inline ssize_t -wrapped_tty_read(unsigned char *buf, size_t max) -{ +read_vin() { + unsigned char buf[IBUFSIZE]; /* tty_read will handle abort_bbs. * len <= 0: read more */ - ssize_t len = tty_read(buf, max); + ssize_t len = tty_read(buf, vbuf_space(pvin)); if (len <= 0) - return len; + return len; // apply additional converts #ifdef DBCSAWARE if (ISDBCSAWARE() && HasUserFlag(UF_DBCS_DROP_REPEAT)) len = vtkbd_ignore_dbcs_evil_repeats(buf, len); + if (len <= 0) + return len; #endif -#ifdef CONVERT - len = input_wrapper(inbuf, len); -#endif -#ifdef DBG_OUTRPT +#ifdef DBG_OUTRPT #if 1 if (len > 0) - debug_print_input_buffer((char*)inbuf, len); + debug_print_input_buffer(buf, len); #else { static char xbuf[128]; @@ -435,15 +390,21 @@ wrapped_tty_read(unsigned char *buf, size_t max) write(1, xbuf, strlen(xbuf)); } #endif - #endif // DBG_OUTRPT + + // len = 1 if success +#ifdef CONVERT + len = convert_read(pvin, buf, len); +#else + len = vbuf_putblk(pvin, buf, len); +#endif return len; } /* * dogetch() is not reentrant-safe. SIGUSR[12] might happen at any time, and - * dogetch() might be called again, and then ibufsize/icurrchar/inbuf might - * be inconsistent. We try to not segfault here... + * dogetch() might be called again, and then input buffer state may be + * inconsistent. We try to not segfault here... */ static int @@ -451,8 +412,8 @@ dogetch(void) { ssize_t len; static time4_t lastact; - if (ibufsize <= icurrchar) { + while (vbuf_is_empty(pvin)) { refresh(); if (i_newfd) { @@ -498,11 +459,9 @@ dogetch(void) STATINC(STAT_SYSREADSOCKET); do { - len = wrapped_tty_read(inbuf, IBUFSIZE); + len = read_vin(); + // warning: len is 1/0/-1 now, not real length. } while (len <= 0); - - ibufsize = len; - icurrchar = 0; } if (currutmp) { @@ -515,15 +474,15 @@ dogetch(void) } // see vtkbd.c for CR/LF Rules + assert(!vbuf_is_empty(pvin)); { - unsigned char c = (unsigned char) inbuf[icurrchar++]; - + unsigned char c = vbuf_pop(pvin); // CR LF are treated as one. if (c == KEY_CR) { - // peak next character. - if (icurrchar < ibufsize && inbuf[icurrchar] == KEY_LF) - icurrchar ++; + // peak next character. (peek return EOF for empty) + if (vbuf_peek(pvin) == KEY_LF) + vbuf_pop(pvin); return KEY_ENTER; } else if (c == KEY_LF) @@ -662,22 +621,16 @@ wait_input(float f, int bIgnoreBuf) inline int peek_input(float f, int c) { - int i = 0; assert (c == EOF || (c > 0 && c < ' ')); // only ^x keys are safe to be detected. // other keys may fall into escape sequence. - if (wait_input(f, 1) && (IBUFSIZE > ibufsize)) - { - int len = wrapped_tty_read(inbuf + ibufsize, IBUFSIZE - ibufsize); - if (len > 0) - ibufsize += len; - } + if (wait_input(f, 1) && vbuf_size(pvin) < IBUFSIZE) + read_vin(); + if (c == EOF) return 0; - // scan inbuf - for (i = icurrchar; i < ibufsize && inbuf[i] != c; i++) ; - return i < ibufsize ? 1 : 0; + return vbuf_strchr(pvin, c) >= 0 ? 1 : 0; } @@ -705,12 +658,12 @@ inline void vkey_purge(void) { int max_try = 64; - unsigned char garbage[4096]; drop_input(); STATINC(STAT_SYSREADSOCKET); while (wait_input(0.01, 1) && max_try-- > 0) { - wrapped_tty_read(garbage, sizeof(garbage)); + read_vin(); + drop_input(); } } diff --git a/pttbbs/mbbsd/mbbsd.c b/pttbbs/mbbsd/mbbsd.c index 45bfdaff..b12dbc07 100644 --- a/pttbbs/mbbsd/mbbsd.c +++ b/pttbbs/mbbsd/mbbsd.c @@ -795,16 +795,15 @@ login_query(char *ruid) #ifdef CONVERT /* switch to gb mode if uid end with '.' */ len = strlen(uid); - if (uid[0] && uid[len - 1] == '.') { - set_converting_type(CONV_GB); - uid[len - 1] = 0; - redrawwin(); - } - else if (uid[0] && uid[len - 1] == ',') { + if (uid[0] && uid[len - 1] == ',') { set_converting_type(CONV_UTF8); uid[len - 1] = 0; redrawwin(); } + else if (uid[0] && uid[len - 1] == '.') { + outs("Sorry, GB encoding is not supported anymore. Please use UTF-8 (id,)"); + continue; + } else if (len >= IDLEN + 1) uid[IDLEN] = 0; #endif @@ -1532,6 +1531,10 @@ static int check_banip (char *host); static void init(void) { start_time = time(NULL); + init_io(); +#ifdef CONVERT + init_convert(); +#endif /* avoid SIGPIPE */ Signal(SIGPIPE, SIG_IGN); @@ -1552,9 +1555,6 @@ static void init(void) mallopt (M_TOP_PAD, MY__TOP_PAD); #endif -#ifdef CONVERT - init_convert(); -#endif } @@ -1578,7 +1578,7 @@ static void usage(char *argv0) "\n" "flags\n" "\t-t type terminal mode, telnet | tty\n" - "\t-e encoding encoding (default big5), big5 | gb | utf8\n" + "\t-e encoding encoding (default big5), big5 | utf8\n" "\n" "testing flags\n" "\t-F don't fork\n" @@ -1709,8 +1709,6 @@ bool parse_argv(int argc, char *argv[], struct ProgramOption *option) #ifdef CONVERT if (strcmp(optarg, "big5") == 0) { set_converting_type(CONV_NORMAL); - } else if (strcmp(optarg, "gb") == 0) { - set_converting_type(CONV_GB); } else if (strcmp(optarg, "utf8") == 0) { set_converting_type(CONV_UTF8); } else { diff --git a/pttbbs/pttbbs.mk b/pttbbs/pttbbs.mk index b3aef2c4..90c1124e 100644 --- a/pttbbs/pttbbs.mk +++ b/pttbbs/pttbbs.mk @@ -3,12 +3,14 @@ BBSHOME?= $(HOME) BBSHOME?= /home/bbs +WITH_PFTERM=1 + SRCROOT?= . OSTYPE!= uname -CC:= gcc -CXX:= g++ +#CC:= clang -Qunused-arguments +#CXX:= clang -Qunused-arguments CCACHE!= which ccache|sed -e 's/^.*\///' WANTS_CONVERT!= sh -c 'grep "^\#define CONVERT" $(SRCROOT)/pttbbs.conf || echo NO' @@ -20,9 +22,6 @@ CXX:= ccache $(CXX) PTT_CFLAGS:= -W -Wall -Wunused -pipe -DBBSHOME='"$(BBSHOME)"' -I$(SRCROOT)/include PTT_CXXFLAGS:= -W -Wall -Wunused -pipe -DBBSHOME='"$(BBSHOME)"' -I$(SRCROOT)/include PTT_LDFLAGS:= -Wl,--as-needed -.if $(WANTS_CONVERT) != "NO" -PTT_LDLIBS+= -lhz -.endif # enable assert() #PTT_CFLAGS+= -DNDEBUG |