diff options
author | piaip <piaip@63ad8ddf-47c3-0310-b6dd-a9e9d9715204> | 2008-03-15 22:18:55 +0800 |
---|---|---|
committer | piaip <piaip@63ad8ddf-47c3-0310-b6dd-a9e9d9715204> | 2008-03-15 22:18:55 +0800 |
commit | ea9c870ae1208a0b6032102591dcecc76a897b2f (patch) | |
tree | d4ab8a91388390332849c6026bd46bcd0ccc4390 /mbbsd/pfterm.c | |
parent | 7edce5f16e016665ada2d55aa5528ea947907fab (diff) | |
download | pttbbs-ea9c870ae1208a0b6032102591dcecc76a897b2f.tar pttbbs-ea9c870ae1208a0b6032102591dcecc76a897b2f.tar.gz pttbbs-ea9c870ae1208a0b6032102591dcecc76a897b2f.tar.bz2 pttbbs-ea9c870ae1208a0b6032102591dcecc76a897b2f.tar.lz pttbbs-ea9c870ae1208a0b6032102591dcecc76a897b2f.tar.xz pttbbs-ea9c870ae1208a0b6032102591dcecc76a897b2f.tar.zst pttbbs-ea9c870ae1208a0b6032102591dcecc76a897b2f.zip |
- Happy r4000!
- source code retab.
git-svn-id: http://opensvn.csie.org/pttbbs/trunk/pttbbs@4000 63ad8ddf-47c3-0310-b6dd-a9e9d9715204
Diffstat (limited to 'mbbsd/pfterm.c')
-rw-r--r-- | mbbsd/pfterm.c | 3440 |
1 files changed, 1720 insertions, 1720 deletions
diff --git a/mbbsd/pfterm.c b/mbbsd/pfterm.c index bffb225b..65a09a62 100644 --- a/mbbsd/pfterm.c +++ b/mbbsd/pfterm.c @@ -24,8 +24,8 @@ // # ifdef CONVERT // extern int bbs_convert_type; // # define FT_DBCS_NOINTRESC ( -// (cuser.uflag & DBCS_NOINTRESC) || -// (bbs_convert_type == CONV_UTF8)) +// (cuser.uflag & DBCS_NOINTRESC) || +// (bbs_convert_type == CONV_UTF8)) // # else # define FT_DBCS_NOINTRESC (cuser.uflag & DBCS_NOINTRESC) // # endif @@ -40,7 +40,7 @@ ////////////////////////////////////////////////////////////////////////// // #define DBG_SHOW_DIRTY -// #define DBG_SHOW_REPRINT // will not work if you enable SHOW_DIRTY. +// #define DBG_SHOW_REPRINT // will not work if you enable SHOW_DIRTY. // #define DBG_DISABLE_OPTMOVE // #define DBG_DISABLE_REPRINT @@ -76,8 +76,8 @@ // Typeahead ////////////////////////////////////////////////////////////////////////// #ifndef TYPEAHEAD_NONE -#define TYPEAHEAD_NONE (-1) -#define TYPEAHEAD_STDIN (0) +#define TYPEAHEAD_NONE (-1) +#define TYPEAHEAD_STDIN (0) #endif // TYPEAHEAD ////////////////////////////////////////////////////////////////////////// @@ -159,43 +159,43 @@ #define FTSZ_DEFAULT_ROW (24) #define FTSZ_DEFAULT_COL (80) -#define FTSZ_MIN_ROW (24) -#define FTSZ_MAX_ROW (100) -#define FTSZ_MIN_COL (80) -#define FTSZ_MAX_COL (320) - -#define FTCHAR_ERASE (' ') -#define FTATTR_ERASE (0x07) -#define FTCHAR_BLANK (' ') -#define FTATTR_DEFAULT (FTATTR_ERASE) +#define FTSZ_MIN_ROW (24) +#define FTSZ_MAX_ROW (100) +#define FTSZ_MIN_COL (80) +#define FTSZ_MAX_COL (320) + +#define FTCHAR_ERASE (' ') +#define FTATTR_ERASE (0x07) +#define FTCHAR_BLANK (' ') +#define FTATTR_DEFAULT (FTATTR_ERASE) #define FTCHAR_INVALID_DBCS ('?') // #define FTATTR_TRANSPARENT (0x80) -#define FTDIRTY_CHAR (0x01) -#define FTDIRTY_ATTR (0x02) -#define FTDIRTY_DBCS (0x04) -#define FTDIRTY_INVALID_DBCS (0x08) -#define FTDIRTY_RAWMOVE (0x10) +#define FTDIRTY_CHAR (0x01) +#define FTDIRTY_ATTR (0x02) +#define FTDIRTY_DBCS (0x04) +#define FTDIRTY_INVALID_DBCS (0x08) +#define FTDIRTY_RAWMOVE (0x10) -#define FTDBCS_SAFE (0) // standard DBCS -#define FTDBCS_UNSAFE (1) // not on all systems (better do rawmove) -#define FTDBCS_INVALID (2) // invalid +#define FTDBCS_SAFE (0) // standard DBCS +#define FTDBCS_UNSAFE (1) // not on all systems (better do rawmove) +#define FTDBCS_INVALID (2) // invalid -#define FTCMD_MAXLEN (63) // max escape command sequence length -#define FTATTR_MINCMD (16) +#define FTCMD_MAXLEN (63) // max escape command sequence length +#define FTATTR_MINCMD (16) #ifndef FTCONF_USE_ANSI_RELMOVE -# define FTMV_COST (8) // always ESC[m;nH will costs avg 8 bytes +# define FTMV_COST (8) // always ESC[m;nH will costs avg 8 bytes #else -# define FTMV_COST (5) // ESC[ABCD with ESC[m;nH costs avg 4+ bytes +# define FTMV_COST (5) // ESC[ABCD with ESC[m;nH costs avg 4+ bytes #endif ////////////////////////////////////////////////////////////////////////// // Flat Terminal Data Type ////////////////////////////////////////////////////////////////////////// -typedef unsigned char ftchar; // primitive character type -typedef unsigned char ftattr; // primitive attribute type +typedef unsigned char ftchar; // primitive character type +typedef unsigned char ftattr; // primitive attribute type ////////////////////////////////////////////////////////////////////////// // Flat Terminal Structure @@ -203,42 +203,42 @@ typedef unsigned char ftattr; // primitive attribute type typedef struct { - ftchar **cmap[2]; // character map - ftattr **amap[2]; // attribute map - ftchar *dmap; // dirty map - ftchar *dcmap; // processed display map - ftattr attr; - int rows, cols; - int y, x; - int sy,sx; // stored cursor - int mi; // map index, mi = current map and (1-mi) = old map - int dirty; - int scroll; + ftchar **cmap[2]; // character map + ftattr **amap[2]; // attribute map + ftchar *dmap; // dirty map + ftchar *dcmap; // processed display map + ftattr attr; + int rows, cols; + int y, x; + int sy,sx; // stored cursor + int mi; // map index, mi = current map and (1-mi) = old map + int dirty; + int scroll; - // memory allocation - int mrows, mcols; + // memory allocation + int mrows, mcols; - // raw terminal status - int ry, rx; - ftattr rattr; + // raw terminal status + int ry, rx; + ftattr rattr; - // typeahead - char typeahead; + // typeahead + char typeahead; - // escape command - ftchar cmd[FTCMD_MAXLEN+1]; - int szcmd; + // escape command + ftchar cmd[FTCMD_MAXLEN+1]; + int szcmd; } FlatTerm; static FlatTerm ft; #ifdef _WIN32 - // sorry, we support only 80x24 on Windows now. - HANDLE hStdout; - COORD coordBufSize = {80, 24}, coordBufCoord = {0, 0}; - SMALL_RECT winrect = {0, 0, 79, 23}; - CHAR_INFO winbuf[80*24]; + // sorry, we support only 80x24 on Windows now. + HANDLE hStdout; + COORD coordBufSize = {80, 24}, coordBufCoord = {0, 0}; + SMALL_RECT winrect = {0, 0, 79, 23}; + CHAR_INFO winbuf[80*24]; #endif ////////////////////////////////////////////////////////////////////////// @@ -252,23 +252,23 @@ static FlatTerm ft; #define FTATTR_GETBG(x) ((x >> FTATTR_BGSHIFT) & 0x7) #define FTATTR_FGMASK ((ftattr)(0x7 << FTATTR_FGSHIFT)) #define FTATTR_BGMASK ((ftattr)(0x7 << FTATTR_BGSHIFT)) -#define FTATTR_BOLD (0x08) -#define FTATTR_BLINK (0x80) -#define FTATTR_DEFAULT_FG (FTATTR_GETFG(FTATTR_DEFAULT)) -#define FTATTR_DEFAULT_BG (FTATTR_GETBG(FTATTR_DEFAULT)) -#define FTATTR_MAKE(f,b) (((f)<<FTATTR_FGSHIFT)|((b)<<FTATTR_BGSHIFT)) -#define FTCHAR_ISBLANK(x) ((x) == (FTCHAR_BLANK)) - -#define FTCMAP ft.cmap[ft.mi] -#define FTAMAP ft.amap[ft.mi] -#define FTCROW FTCMAP[ft.y] -#define FTAROW FTAMAP[ft.y] -#define FTC FTCROW[ft.x] -#define FTA FTAROW[ft.x] -#define FTD ft.dmap -#define FTDC ft.dcmap -#define FTPC (FTCROW+ft.x) -#define FTPA (FTAROW+ft.x) +#define FTATTR_BOLD (0x08) +#define FTATTR_BLINK (0x80) +#define FTATTR_DEFAULT_FG (FTATTR_GETFG(FTATTR_DEFAULT)) +#define FTATTR_DEFAULT_BG (FTATTR_GETBG(FTATTR_DEFAULT)) +#define FTATTR_MAKE(f,b) (((f)<<FTATTR_FGSHIFT)|((b)<<FTATTR_BGSHIFT)) +#define FTCHAR_ISBLANK(x) ((x) == (FTCHAR_BLANK)) + +#define FTCMAP ft.cmap[ft.mi] +#define FTAMAP ft.amap[ft.mi] +#define FTCROW FTCMAP[ft.y] +#define FTAROW FTAMAP[ft.y] +#define FTC FTCROW[ft.x] +#define FTA FTAROW[ft.x] +#define FTD ft.dmap +#define FTDC ft.dcmap +#define FTPC (FTCROW+ft.x) +#define FTPA (FTAROW+ft.x) #define FTOCMAP ft.cmap[1-ft.mi] #define FTOAMAP ft.amap[1-ft.mi] @@ -287,7 +287,7 @@ static FlatTerm ft; // #define FTDBCS_ISTAIL(x) (((unsigned char)(x)) & ((unsigned char)~0x3F)) #define FTDBCS_ISSBCSPRINT(x) \ - (((unsigned char)(x))>=' ' && ((unsigned char)(x))<0x80) + (((unsigned char)(x))>=' ' && ((unsigned char)(x))<0x80) #ifndef min #define min(x,y) (((x)<(y))?(x):(y)) @@ -311,102 +311,102 @@ static FlatTerm ft; //// common ncurse-like library interface // initialization -void initscr (void); -int resizeterm (int rows, int cols); -int endwin (void); +void initscr (void); +int resizeterm (int rows, int cols); +int endwin (void); // attributes -ftattr attrget (void); -void attrset (ftattr attr); -void attrsetfg (ftattr attr); -void attrsetbg (ftattr attr); +ftattr attrget (void); +void attrset (ftattr attr); +void attrsetfg (ftattr attr); +void attrsetbg (ftattr attr); // cursor -void getyx (int *y, int *x); -void getmaxyx (int *y, int *x); -void move (int y, int x); +void getyx (int *y, int *x); +void getmaxyx (int *y, int *x); +void move (int y, int x); // clear -void clear (void); // clrscr + move(0,0) -void clrtoeol (void); // end of line -void clrtobot (void); +void clear (void); // clrscr + move(0,0) +void clrtoeol (void); // end of line +void clrtobot (void); // clear (non-ncurses) -void clrtoln (int ln); // clear down to ln ( excluding ln, as [y,ln) ) -void clrcurln (void); // whole line -void clrtobeg (void); // begin of line -void clrtohome (void); -void clrscr (void); // clear and keep cursor untouched -void clrregion (int r1, int r2); // clear [r1,r2], bi-directional. +void clrtoln (int ln); // clear down to ln ( excluding ln, as [y,ln) ) +void clrcurln (void); // whole line +void clrtobeg (void); // begin of line +void clrtohome (void); +void clrscr (void); // clear and keep cursor untouched +void clrregion (int r1, int r2); // clear [r1,r2], bi-directional. // window control -void newwin (int nlines, int ncols, int y, int x); +void newwin (int nlines, int ncols, int y, int x); // flushing -void refresh (void); // optimized refresh -void doupdate (void); // optimized refresh, ignore input queue -void redrawwin (void); // invalidate whole screen -int typeahead (int fd);// prevent refresh if input queue is not empty +void refresh (void); // optimized refresh +void doupdate (void); // optimized refresh, ignore input queue +void redrawwin (void); // invalidate whole screen +int typeahead (int fd);// prevent refresh if input queue is not empty // scrolling -void scroll (void); // scroll up -void rscroll (void); // scroll down -void scrl (int rows); +void scroll (void); // scroll up +void rscroll (void); // scroll down +void scrl (int rows); // output (ncurses flavor) -void addch (unsigned char c); // equivalent to outc() -void addstr (const char *s); // equivalent to outs() -void addnstr (const char *s, int n); +void addch (unsigned char c); // equivalent to outc() +void addstr (const char *s); // equivalent to outs() +void addnstr (const char *s, int n); // output (non-ncurses) -void outc (unsigned char c); -void outs (const char *s); -void outns (const char *s, int n); -void outstr (const char *str); // prepare and print a complete string. -void addstring (const char *str); // ncurses-like of outstr(). +void outc (unsigned char c); +void outs (const char *s); +void outns (const char *s, int n); +void outstr (const char *str); // prepare and print a complete string. +void addstring (const char *str); // ncurses-like of outstr(). // readback -int instr (char *str); -int innstr (char *str, int n); // n includes \0 -int inansistr (char *str, int n); // n includes \0 +int instr (char *str); +int innstr (char *str, int n); // n includes \0 +int inansistr (char *str, int n); // n includes \0 // deprecated -void standout (void); -void standend (void); +void standout (void); +void standend (void); // grayout advanced control -void grayout (int y, int end, int level); +void grayout (int y, int end, int level); //// flat-term internal processor -int fterm_inbuf (void); // raw input adapter -void fterm_rawc (int c); // raw output adapter -void fterm_rawnewline(void); // raw output adapter -void fterm_rawflush (void); // raw output adapter -void fterm_raws (const char *s); -void fterm_rawnc (int c, int n); -void fterm_rawnum (int arg); -void fterm_rawcmd (int arg, int defval, char c); -void fterm_rawcmd2 (int arg1, int arg2, int defval, char c); -void fterm_rawattr (ftattr attr); // optimized changing attribute -void fterm_rawclear (void); -void fterm_rawclreol (void); -void fterm_rawhome (void); -void fterm_rawscroll (int dy); -void fterm_rawcursor (void); -void fterm_rawmove (int y, int x); -void fterm_rawmove_opt(int y, int x); -void fterm_rawmove_rel(int dy, int dx); - -int fterm_chattr (char *s, ftattr oa, ftattr na); // size(s) > FTATTR_MINCMD -void fterm_exec (void); // execute ft.cmd -void fterm_flippage (void); -void fterm_dupe2bk (void); -void fterm_markdirty (void); // mark as dirty -int fterm_strdlen (const char *s); // length of string for display -int fterm_prepare_str(int len); +int fterm_inbuf (void); // raw input adapter +void fterm_rawc (int c); // raw output adapter +void fterm_rawnewline(void); // raw output adapter +void fterm_rawflush (void); // raw output adapter +void fterm_raws (const char *s); +void fterm_rawnc (int c, int n); +void fterm_rawnum (int arg); +void fterm_rawcmd (int arg, int defval, char c); +void fterm_rawcmd2 (int arg1, int arg2, int defval, char c); +void fterm_rawattr (ftattr attr); // optimized changing attribute +void fterm_rawclear (void); +void fterm_rawclreol (void); +void fterm_rawhome (void); +void fterm_rawscroll (int dy); +void fterm_rawcursor (void); +void fterm_rawmove (int y, int x); +void fterm_rawmove_opt(int y, int x); +void fterm_rawmove_rel(int dy, int dx); + +int fterm_chattr (char *s, ftattr oa, ftattr na); // size(s) > FTATTR_MINCMD +void fterm_exec (void); // execute ft.cmd +void fterm_flippage (void); +void fterm_dupe2bk (void); +void fterm_markdirty (void); // mark as dirty +int fterm_strdlen (const char *s); // length of string for display +int fterm_prepare_str(int len); // DBCS supporting -int fterm_DBCS_Big5(unsigned char c1, unsigned char c2); +int fterm_DBCS_Big5(unsigned char c1, unsigned char c2); ////////////////////////////////////////////////////////////////////////// // Flat Terminal Implementation @@ -420,150 +420,150 @@ void initscr(void) { #ifdef _WIN32 - hStdout = GetStdHandle(STD_OUTPUT_HANDLE); - SetConsoleScreenBufferSize(hStdout, coordBufSize); - SetConsoleCursorPosition(hStdout, coordBufCoord); + hStdout = GetStdHandle(STD_OUTPUT_HANDLE); + SetConsoleScreenBufferSize(hStdout, coordBufSize); + SetConsoleCursorPosition(hStdout, coordBufCoord); #endif - memset(&ft, sizeof(ft), 0); - ft.attr = ft.rattr = FTATTR_DEFAULT; - resizeterm(FTSZ_DEFAULT_ROW, FTSZ_DEFAULT_COL); + memset(&ft, sizeof(ft), 0); + ft.attr = ft.rattr = FTATTR_DEFAULT; + resizeterm(FTSZ_DEFAULT_ROW, FTSZ_DEFAULT_COL); - // clear both pages - ft.mi = 0; clrscr(); - ft.mi = 1; clrscr(); - ft.mi = 0; + // clear both pages + ft.mi = 0; clrscr(); + ft.mi = 1; clrscr(); + ft.mi = 0; - // typeahead - ft.typeahead = 1; + // typeahead + ft.typeahead = 1; - fterm_rawclear(); - move(0, 0); + fterm_rawclear(); + move(0, 0); } -int +int endwin(void) { - int r, mi = 0; + int r, mi = 0; - // fterm_rawclear(); - - for (mi = 0; mi < 2; mi++) - { - for (r = 0; r < ft.mrows; r++) - { - free(ft.cmap[mi][r]); - free(ft.amap[mi][r]); - } - } - free(ft.dmap); - free(ft.dcmap); - memset(&ft, sizeof(ft), 0); - return 0; + // fterm_rawclear(); + + for (mi = 0; mi < 2; mi++) + { + for (r = 0; r < ft.mrows; r++) + { + free(ft.cmap[mi][r]); + free(ft.amap[mi][r]); + } + } + free(ft.dmap); + free(ft.dcmap); + memset(&ft, sizeof(ft), 0); + return 0; } int resizeterm(int rows, int cols) { - int dirty = 0, mi = 0, i = 0; - - rows = ranged(rows, FTSZ_MIN_ROW, FTSZ_MAX_ROW); - cols = ranged(cols, FTSZ_MIN_COL, FTSZ_MAX_COL); - - // adjust memory only for increasing buffer - if (rows > ft.mrows || cols > ft.mcols) - { - for (mi = 0; mi < 2; mi++) - { - // allocate rows - if (rows > ft.mrows) - { - ft.cmap[mi] = (ftchar**)realloc(ft.cmap[mi], - sizeof(ftchar*) * rows); - ft.amap[mi] = (ftattr**)realloc(ft.amap[mi], - sizeof(ftattr*) * rows); - - // allocate new columns - for (i = ft.mrows; i < rows; i++) - { - ft.cmap[mi][i] = (ftchar*)malloc((cols+1) * sizeof(ftchar)); - ft.amap[mi][i] = (ftattr*)malloc((cols+1) * sizeof(ftattr)); - // zero at end to prevent over-run - ft.cmap[mi][i][cols] = 0; - ft.amap[mi][i][cols] = 0; - } - } - - // resize cols - if (cols > ft.mcols) - { - for (i = 0; i < ft.mrows; i++) - { - ft.cmap[mi][i] = (ftchar*)realloc(ft.cmap[mi][i], - (cols+1) * sizeof(ftchar)); - ft.amap[mi][i] = (ftattr*)realloc(ft.amap[mi][i], - (cols+1) * sizeof(ftattr)); - // zero at end to prevent over-run - ft.cmap[mi][i][cols] = 0; - ft.amap[mi][i][cols] = 0; - } - } else { - // we have to deal one case: - // expand x, shrink x, expand y -> - // now new allocated lines will have small x(col) instead of mcol. - // the solution is to modify mcols here, or change the malloc above - // to max(ft.mcols, cols). - ft.mcols = cols; - } - } - - // adjusts dirty and display map. - // no need to initialize anyway. - if (cols > ft.mcols) - { - ft.dmap = (ftchar*) realloc(ft.dmap, - (cols+1) * sizeof(ftchar)); - ft.dcmap = (ftchar*) realloc(ft.dcmap, - (cols+1) * sizeof(ftchar)); - } - - // do mrows/mcols assignment here, because we had 2 maps running loop above. - if (cols > ft.mcols) ft.mcols = cols; - if (rows > ft.mrows) ft.mrows = rows; - dirty = 1; - } - - // clear new exposed buffer after resized - // because we will redawwin(), so need to change front buffer only. - for (i = ft.rows; i < rows; i++) - { - memset(FTCMAP[i], FTCHAR_ERASE, - (cols) * sizeof(ftchar)); - memset(FTAMAP[i], FTATTR_ERASE, - (cols) * sizeof(ftattr)); - } - if (cols > ft.cols) - { - for (i = 0; i < ft.rows; i++) - { - memset(FTCMAP[i]+ft.cols, FTCHAR_ERASE, - (cols-ft.cols) * sizeof(ftchar)); - memset(FTAMAP[i]+ft.cols, FTATTR_ERASE, - (cols-ft.cols) * sizeof(ftattr)); - } - } - - if (ft.rows != rows || ft.cols != cols) - { - ft.rows = rows; - ft.cols = cols; - redrawwin(); - } - - ft.x = ranged(ft.x, 0, ft.cols-1); - ft.y = ranged(ft.y, 0, ft.rows-1); - - return dirty; + int dirty = 0, mi = 0, i = 0; + + rows = ranged(rows, FTSZ_MIN_ROW, FTSZ_MAX_ROW); + cols = ranged(cols, FTSZ_MIN_COL, FTSZ_MAX_COL); + + // adjust memory only for increasing buffer + if (rows > ft.mrows || cols > ft.mcols) + { + for (mi = 0; mi < 2; mi++) + { + // allocate rows + if (rows > ft.mrows) + { + ft.cmap[mi] = (ftchar**)realloc(ft.cmap[mi], + sizeof(ftchar*) * rows); + ft.amap[mi] = (ftattr**)realloc(ft.amap[mi], + sizeof(ftattr*) * rows); + + // allocate new columns + for (i = ft.mrows; i < rows; i++) + { + ft.cmap[mi][i] = (ftchar*)malloc((cols+1) * sizeof(ftchar)); + ft.amap[mi][i] = (ftattr*)malloc((cols+1) * sizeof(ftattr)); + // zero at end to prevent over-run + ft.cmap[mi][i][cols] = 0; + ft.amap[mi][i][cols] = 0; + } + } + + // resize cols + if (cols > ft.mcols) + { + for (i = 0; i < ft.mrows; i++) + { + ft.cmap[mi][i] = (ftchar*)realloc(ft.cmap[mi][i], + (cols+1) * sizeof(ftchar)); + ft.amap[mi][i] = (ftattr*)realloc(ft.amap[mi][i], + (cols+1) * sizeof(ftattr)); + // zero at end to prevent over-run + ft.cmap[mi][i][cols] = 0; + ft.amap[mi][i][cols] = 0; + } + } else { + // we have to deal one case: + // expand x, shrink x, expand y -> + // now new allocated lines will have small x(col) instead of mcol. + // the solution is to modify mcols here, or change the malloc above + // to max(ft.mcols, cols). + ft.mcols = cols; + } + } + + // adjusts dirty and display map. + // no need to initialize anyway. + if (cols > ft.mcols) + { + ft.dmap = (ftchar*) realloc(ft.dmap, + (cols+1) * sizeof(ftchar)); + ft.dcmap = (ftchar*) realloc(ft.dcmap, + (cols+1) * sizeof(ftchar)); + } + + // do mrows/mcols assignment here, because we had 2 maps running loop above. + if (cols > ft.mcols) ft.mcols = cols; + if (rows > ft.mrows) ft.mrows = rows; + dirty = 1; + } + + // clear new exposed buffer after resized + // because we will redawwin(), so need to change front buffer only. + for (i = ft.rows; i < rows; i++) + { + memset(FTCMAP[i], FTCHAR_ERASE, + (cols) * sizeof(ftchar)); + memset(FTAMAP[i], FTATTR_ERASE, + (cols) * sizeof(ftattr)); + } + if (cols > ft.cols) + { + for (i = 0; i < ft.rows; i++) + { + memset(FTCMAP[i]+ft.cols, FTCHAR_ERASE, + (cols-ft.cols) * sizeof(ftchar)); + memset(FTAMAP[i]+ft.cols, FTATTR_ERASE, + (cols-ft.cols) * sizeof(ftattr)); + } + } + + if (ft.rows != rows || ft.cols != cols) + { + ft.rows = rows; + ft.cols = cols; + redrawwin(); + } + + ft.x = ranged(ft.x, 0, ft.cols-1); + ft.y = ranged(ft.y, 0, ft.rows-1); + + return dirty; } // attributes @@ -571,27 +571,27 @@ resizeterm(int rows, int cols) ftattr attrget(void) { - return ft.attr; + return ft.attr; } void attrset(ftattr attr) { - ft.attr = attr; + ft.attr = attr; } void attrsetfg(ftattr attr) { - ft.attr &= (~FTATTR_FGMASK); - ft.attr |= ((attr & FTATTR_FGMASK) << FTATTR_FGSHIFT); + ft.attr &= (~FTATTR_FGMASK); + ft.attr |= ((attr & FTATTR_FGMASK) << FTATTR_FGSHIFT); } void attrsetbg(ftattr attr) { - ft.attr &= (~FTATTR_BGMASK); - ft.attr |= ((attr & FTATTR_FGMASK) << FTATTR_BGSHIFT); + ft.attr &= (~FTATTR_BGMASK); + ft.attr |= ((attr & FTATTR_FGMASK) << FTATTR_BGSHIFT); } // clear @@ -599,119 +599,119 @@ attrsetbg(ftattr attr) void clrscr(void) { - int r; - for (r = 0; r < ft.rows; r++) - memset(FTCMAP[r], FTCHAR_ERASE, ft.cols * sizeof(ftchar)); - for (r = 0; r < ft.rows; r++) - memset(FTAMAP[r], FTATTR_ERASE, ft.cols * sizeof(ftattr)); - fterm_markdirty(); + int r; + for (r = 0; r < ft.rows; r++) + memset(FTCMAP[r], FTCHAR_ERASE, ft.cols * sizeof(ftchar)); + for (r = 0; r < ft.rows; r++) + memset(FTAMAP[r], FTATTR_ERASE, ft.cols * sizeof(ftattr)); + fterm_markdirty(); } void clear(void) { - clrscr(); - move(0,0); + clrscr(); + move(0,0); } void clrtoeol(void) { - ft.x = ranged(ft.x, 0, ft.cols-1); - ft.y = ranged(ft.y, 0, ft.rows-1); - memset(FTPC, FTCHAR_ERASE, ft.cols - ft.x); - memset(FTPA, FTATTR_ERASE, ft.cols - ft.x); - fterm_markdirty(); + ft.x = ranged(ft.x, 0, ft.cols-1); + ft.y = ranged(ft.y, 0, ft.rows-1); + memset(FTPC, FTCHAR_ERASE, ft.cols - ft.x); + memset(FTPA, FTATTR_ERASE, ft.cols - ft.x); + fterm_markdirty(); } void clrtobeg(void) { - ft.x = ranged(ft.x, 0, ft.cols-1); - ft.y = ranged(ft.y, 0, ft.rows-1); - memset(FTCROW, FTCHAR_ERASE, ft.x+1); - memset(FTAROW, FTATTR_ERASE, ft.x+1); - fterm_markdirty(); + ft.x = ranged(ft.x, 0, ft.cols-1); + ft.y = ranged(ft.y, 0, ft.rows-1); + memset(FTCROW, FTCHAR_ERASE, ft.x+1); + memset(FTAROW, FTATTR_ERASE, ft.x+1); + fterm_markdirty(); } void clrcurrline(void) { - ft.y = ranged(ft.y, 0, ft.rows-1); - memset(FTCROW, FTCHAR_ERASE, ft.cols); - memset(FTAROW, FTATTR_ERASE, ft.cols); - fterm_markdirty(); + ft.y = ranged(ft.y, 0, ft.rows-1); + memset(FTCROW, FTCHAR_ERASE, ft.cols); + memset(FTAROW, FTATTR_ERASE, ft.cols); + fterm_markdirty(); } void clrtoln(int line) { - if (line <= ft.y) - return; - clrregion(ft.y, line-1); + if (line <= ft.y) + return; + clrregion(ft.y, line-1); } void clrregion(int r1, int r2) { - // bi-direction - if (r1 > r2) - { - int r = r1; - r1 = r2; r2 = r; - } + // bi-direction + if (r1 > r2) + { + int r = r1; + r1 = r2; r2 = r; + } - // check r1, r2 range - r1 = ranged(r1, 0, ft.rows-1); - r2 = ranged(r2, 0, ft.rows-1); + // check r1, r2 range + r1 = ranged(r1, 0, ft.rows-1); + r2 = ranged(r2, 0, ft.rows-1); - for (; r1 <= r2; r1++) - { - memset(FTCMAP[r1], FTCHAR_ERASE, ft.cols); - memset(FTAMAP[r1], FTATTR_ERASE, ft.cols); - } - fterm_markdirty(); + for (; r1 <= r2; r1++) + { + memset(FTCMAP[r1], FTCHAR_ERASE, ft.cols); + memset(FTAMAP[r1], FTATTR_ERASE, ft.cols); + } + fterm_markdirty(); } void clrtobot(void) { - clrtoeol(); - clrregion(ft.y+1, ft.rows-1); + clrtoeol(); + clrregion(ft.y+1, ft.rows-1); } void clrtohome(void) { - clrtobeg(); - clrregion(ft.y-1, 0); + clrtobeg(); + clrregion(ft.y-1, 0); } -void newwin (int nlines, int ncols, int y, int x) +void newwin (int nlines, int ncols, int y, int x) { - int oy, ox; - // check range - - x = ranged(x, 0, ft.cols-1); - y = ranged(y, 0, ft.rows-1); - ncols = ranged(x+ncols-1, x, ft.cols-1); - nlines = ranged(y+nlines-1, y, ft.rows-1); - ncols = ncols - x + 1; - nlines= nlines- y + 1; + int oy, ox; + // check range + + x = ranged(x, 0, ft.cols-1); + y = ranged(y, 0, ft.rows-1); + ncols = ranged(x+ncols-1, x, ft.cols-1); + nlines = ranged(y+nlines-1, y, ft.rows-1); + ncols = ncols - x + 1; + nlines= nlines- y + 1; - if (nlines <= 0 || ncols <= 0) - return; - getyx(&oy, &ox); + if (nlines <= 0 || ncols <= 0) + return; + getyx(&oy, &ox); while (nlines-- > 0) { - move(y++, x); - // use prepare_str to erase character - fterm_prepare_str(ncols); - // memset(FTAMAP[y]+x, ft.attr, ncols); - // memset(FTCMAP[y]+x, FTCHAR_ERASE, ncols); + move(y++, x); + // use prepare_str to erase character + fterm_prepare_str(ncols); + // memset(FTAMAP[y]+x, ft.attr, ncols); + // memset(FTCMAP[y]+x, FTCHAR_ERASE, ncols); } - move(oy, ox); + move(oy, ox); } // dirty and flushing @@ -719,292 +719,292 @@ void newwin (int nlines, int ncols, int y, int x) void redrawwin(void) { - // flip page - fterm_flippage(); - clrscr(); + // flip page + fterm_flippage(); + clrscr(); - // clear raw terminal - fterm_rawclear(); + // clear raw terminal + fterm_rawclear(); - // flip page again - fterm_flippage(); + // flip page again + fterm_flippage(); - // mark for refresh. - fterm_markdirty(); + // mark for refresh. + fterm_markdirty(); } -int +int typeahead(int fd) { - switch(fd) - { - case TYPEAHEAD_NONE: - ft.typeahead = 0; - break; - case TYPEAHEAD_STDIN: - ft.typeahead = 1; - break; - default: // shall never reach here - assert(NULL); - break; - } - return 0; + switch(fd) + { + case TYPEAHEAD_NONE: + ft.typeahead = 0; + break; + case TYPEAHEAD_STDIN: + ft.typeahead = 1; + break; + default: // shall never reach here + assert(NULL); + break; + } + return 0; } void refresh(void) { - // prevent passive update - if(fterm_inbuf() && ft.typeahead) - return; - doupdate(); + // prevent passive update + if(fterm_inbuf() && ft.typeahead) + return; + doupdate(); } void doupdate(void) { - int y, x; - char touched = 0; + int y, x; + char touched = 0; - if (!ft.dirty) - { - fterm_rawcursor(); - return; - } + if (!ft.dirty) + { + fterm_rawcursor(); + return; + } #ifdef _WIN32 - assert(ft.rows == coordBufSize.Y); - assert(ft.cols == coordBufSize.X); - - for (y = 0; y < ft.rows; y++) - { - for (x = 0; x < ft.cols; x++) - { - WORD xAttr = FTAMAP[y][x], xxAttr; - // w32 attribute: bit swap (0,2) and (4, 6) - xxAttr = xAttr & 0xAA; - if (xAttr & 0x01) xxAttr |= 0x04; - if (xAttr & 0x04) xxAttr |= 0x01; - if (xAttr & 0x10) xxAttr |= 0x40; - if (xAttr & 0x40) xxAttr |= 0x10; - - winbuf[y*ft.cols + x].Attributes= xxAttr; - winbuf[y*ft.cols + x].Char.AsciiChar = FTCMAP[y][x]; - } - } - WriteConsoleOutputA(hStdout, winbuf, coordBufSize, coordBufCoord, &winrect); + assert(ft.rows == coordBufSize.Y); + assert(ft.cols == coordBufSize.X); + + for (y = 0; y < ft.rows; y++) + { + for (x = 0; x < ft.cols; x++) + { + WORD xAttr = FTAMAP[y][x], xxAttr; + // w32 attribute: bit swap (0,2) and (4, 6) + xxAttr = xAttr & 0xAA; + if (xAttr & 0x01) xxAttr |= 0x04; + if (xAttr & 0x04) xxAttr |= 0x01; + if (xAttr & 0x10) xxAttr |= 0x40; + if (xAttr & 0x40) xxAttr |= 0x10; + + winbuf[y*ft.cols + x].Attributes= xxAttr; + winbuf[y*ft.cols + x].Char.AsciiChar = FTCMAP[y][x]; + } + } + WriteConsoleOutputA(hStdout, winbuf, coordBufSize, coordBufCoord, &winrect); #else // !_WIN32 - // if scroll, do it first - if (ft.scroll) - fterm_rawscroll(ft.scroll); - - // calculate and optimize dirty - for (y = 0; y < ft.rows; y++) - { - int len = ft.cols, ds = 0, derase = 0; - char dbcs = 0, odbcs = 0; // 0: none, 1: lead, 2: tail - - // reset dirty and display map - memset(FTD, 0, ft.cols * sizeof(ftchar)); - memcpy(FTDC,FTCMAP[y], ft.cols * sizeof(ftchar)); - - // first run: character diff - for (x = 0; x < len; x++) - { - // build base dirty information - if (FTCMAP[y][x] != FTOCMAP[y][x]) - FTD[x] |= FTDIRTY_CHAR, ds++; - if (FTAMAP[y][x] != FTOAMAP[y][x]) - FTD[x] |= FTDIRTY_ATTR, ds++; - - // determine DBCS status - if (dbcs == 1) - { + // if scroll, do it first + if (ft.scroll) + fterm_rawscroll(ft.scroll); + + // calculate and optimize dirty + for (y = 0; y < ft.rows; y++) + { + int len = ft.cols, ds = 0, derase = 0; + char dbcs = 0, odbcs = 0; // 0: none, 1: lead, 2: tail + + // reset dirty and display map + memset(FTD, 0, ft.cols * sizeof(ftchar)); + memcpy(FTDC,FTCMAP[y], ft.cols * sizeof(ftchar)); + + // first run: character diff + for (x = 0; x < len; x++) + { + // build base dirty information + if (FTCMAP[y][x] != FTOCMAP[y][x]) + FTD[x] |= FTDIRTY_CHAR, ds++; + if (FTAMAP[y][x] != FTOAMAP[y][x]) + FTD[x] |= FTDIRTY_ATTR, ds++; + + // determine DBCS status + if (dbcs == 1) + { #ifdef FTCONF_PREVENT_INVALID_DBCS - switch(fterm_DBCS_Big5(FTCMAP[y][x-1], FTCMAP[y][x])) - { - case FTDBCS_SAFE: - // safe to print - FTD[x-1] &= ~FTDIRTY_INVALID_DBCS; - FTDC[x-1] = FTCMAP[y][x-1]; - break; - - case FTDBCS_UNSAFE: - // ok to print, but need to rawmove. - FTD[x-1] &= ~FTDIRTY_INVALID_DBCS; - FTDC[x-1] = FTCMAP[y][x-1]; - FTD[x-1] |= FTDIRTY_CHAR; - FTD[x] |= FTDIRTY_RAWMOVE; - break; - - case FTDBCS_INVALID: - // only SBCS safe characters can be print. - if (!FTDBCS_ISSBCSPRINT(FTCMAP[y][x])) - { - FTD[x] |= FTDIRTY_INVALID_DBCS; - FTDC[x] = FTCHAR_INVALID_DBCS; - } - break; - } + switch(fterm_DBCS_Big5(FTCMAP[y][x-1], FTCMAP[y][x])) + { + case FTDBCS_SAFE: + // safe to print + FTD[x-1] &= ~FTDIRTY_INVALID_DBCS; + FTDC[x-1] = FTCMAP[y][x-1]; + break; + + case FTDBCS_UNSAFE: + // ok to print, but need to rawmove. + FTD[x-1] &= ~FTDIRTY_INVALID_DBCS; + FTDC[x-1] = FTCMAP[y][x-1]; + FTD[x-1] |= FTDIRTY_CHAR; + FTD[x] |= FTDIRTY_RAWMOVE; + break; + + case FTDBCS_INVALID: + // only SBCS safe characters can be print. + if (!FTDBCS_ISSBCSPRINT(FTCMAP[y][x])) + { + FTD[x] |= FTDIRTY_INVALID_DBCS; + FTDC[x] = FTCHAR_INVALID_DBCS; + } + break; + } #endif // FTCONF_PREVENT_INVALID_DBCS - dbcs = 2; - // TAIL: dirty prev and me if any is dirty. - if (FTD[x] || FTD[x-1]) - { - FTD[x] |= FTDIRTY_DBCS; - FTD[x-1]|= FTDIRTY_CHAR; - } - } - else if (FTDBCS_ISLEAD(FTCMAP[y][x])) - { - // LEAD: clear dirty when tail was found. - dbcs = 1; + dbcs = 2; + // TAIL: dirty prev and me if any is dirty. + if (FTD[x] || FTD[x-1]) + { + FTD[x] |= FTDIRTY_DBCS; + FTD[x-1]|= FTDIRTY_CHAR; + } + } + else if (FTDBCS_ISLEAD(FTCMAP[y][x])) + { + // LEAD: clear dirty when tail was found. + dbcs = 1; #ifdef FTCONF_PREVENT_INVALID_DBCS - FTD[x] |= FTDIRTY_INVALID_DBCS; - FTDC[x] = FTCHAR_INVALID_DBCS; + FTD[x] |= FTDIRTY_INVALID_DBCS; + FTDC[x] = FTCHAR_INVALID_DBCS; #endif // FTCONF_PREVENT_INVALID_DBCS - } - else - { - // NON-DBCS - dbcs = 0; - } - - if (odbcs == 1) - { - // TAIL: dirty prev and me if any is dirty. - odbcs = 2; - if (FTD[x] || FTD[x-1]) - { - FTD[x] |= FTDIRTY_CHAR; - FTD[x-1]|= FTDIRTY_CHAR; - } - } - else if (FTDBCS_ISLEAD(FTOCMAP[y][x])) - { - // LEAD: dirty next? - odbcs = 1; - } - else - { - odbcs = 0; - } - } + } + else + { + // NON-DBCS + dbcs = 0; + } + + if (odbcs == 1) + { + // TAIL: dirty prev and me if any is dirty. + odbcs = 2; + if (FTD[x] || FTD[x-1]) + { + FTD[x] |= FTDIRTY_CHAR; + FTD[x-1]|= FTDIRTY_CHAR; + } + } + else if (FTDBCS_ISLEAD(FTOCMAP[y][x])) + { + // LEAD: dirty next? + odbcs = 1; + } + else + { + odbcs = 0; + } + } #ifndef DBG_SHOW_DIRTY - if (!ds) - continue; + if (!ds) + continue; #endif // DBG_SHOW_DIRTY - // Optimization: calculate ERASE section - // TODO ERASE takes 3 bytes (ESC [ K), so enable only if derase >= 3? - // TODO ERASE then print can avoid lots of space, optimize in future. - for (x = ft.cols - 1; x >= 0; x--) - if (FTCMAP[y][x] != FTCHAR_ERASE || - FTAMAP[y][x] != FTATTR_ERASE) - break; - else if (FTD[x]) - derase++; + // Optimization: calculate ERASE section + // TODO ERASE takes 3 bytes (ESC [ K), so enable only if derase >= 3? + // TODO ERASE then print can avoid lots of space, optimize in future. + for (x = ft.cols - 1; x >= 0; x--) + if (FTCMAP[y][x] != FTCHAR_ERASE || + FTAMAP[y][x] != FTATTR_ERASE) + break; + else if (FTD[x]) + derase++; - len = x+1; + len = x+1; - for (x = 0; x < len; x++) - { + for (x = 0; x < len; x++) + { #ifndef DBG_SHOW_DIRTY - if (!FTD[x]) - continue; + if (!FTD[x]) + continue; #endif // !DBG_SHOW_DIRTY - // Optimization: re-print or move? + // Optimization: re-print or move? #ifndef DBG_DISABLE_REPRINT - while (ft.ry == y && x > ft.rx && abs(x-ft.rx) < FTMV_COST) - { - int i; - // Special case: we may be in position of DBCS tail... - // Inside a refresh() loop, this will never happen. - // However it may occur for the first print entering refresh. - // So enable only space if this is the first run (!touched). - - // if we don't need to change attributes, - // just print remaining characters - for (i = ft.rx; i < x; i++) - { - // if same attribute, simply accept. - if (FTAMAP[y][i] == ft.rattr && touched) - continue; - // XXX spaces may accept (BG=rBG), - // but that will also change cached attribute. - if (!FTCHAR_ISBLANK(FTCMAP[y][i])) - break; - if (FTATTR_GETBG(FTAMAP[y][i]) != FTATTR_GETBG(ft.rattr)) - break; - } - if (i != x) - break; - - // safe to print all! - // printf("[re-print %d chars]", i-ft.rx); - + while (ft.ry == y && x > ft.rx && abs(x-ft.rx) < FTMV_COST) + { + int i; + // Special case: we may be in position of DBCS tail... + // Inside a refresh() loop, this will never happen. + // However it may occur for the first print entering refresh. + // So enable only space if this is the first run (!touched). + + // if we don't need to change attributes, + // just print remaining characters + for (i = ft.rx; i < x; i++) + { + // if same attribute, simply accept. + if (FTAMAP[y][i] == ft.rattr && touched) + continue; + // XXX spaces may accept (BG=rBG), + // but that will also change cached attribute. + if (!FTCHAR_ISBLANK(FTCMAP[y][i])) + break; + if (FTATTR_GETBG(FTAMAP[y][i]) != FTATTR_GETBG(ft.rattr)) + break; + } + if (i != x) + break; + + // safe to print all! + // printf("[re-print %d chars]", i-ft.rx); + #ifdef DBG_SHOW_REPRINT - // reverse to hint this is a re-print - fterm_rawattr(FTATTR_MAKE(0, 7) | FTATTR_BOLD); + // reverse to hint this is a re-print + fterm_rawattr(FTATTR_MAKE(0, 7) | FTATTR_BOLD); #endif // DBG_SHOW_REPRINT - for (i = ft.rx; i < x; i++) - { - fterm_rawc(FTDC[i]); - FTAMAP[y][i] = FTOAMAP[y][i]; // spaces may change attr... - ft.rx++; - } + for (i = ft.rx; i < x; i++) + { + fterm_rawc(FTDC[i]); + FTAMAP[y][i] = FTOAMAP[y][i]; // spaces may change attr... + ft.rx++; + } - break; - } + break; + } #endif // !DBG_DISABLE_REPRINT - if (y != ft.ry || x != ft.rx) - fterm_rawmove_opt(y, x); + if (y != ft.ry || x != ft.rx) + fterm_rawmove_opt(y, x); #ifdef DBCSAWARE - if ((FTD[x] & FTDIRTY_DBCS) && (FT_DBCS_NOINTRESC)) - { - // prevent changing attributes inside DBCS - } - else + if ((FTD[x] & FTDIRTY_DBCS) && (FT_DBCS_NOINTRESC)) + { + // prevent changing attributes inside DBCS + } + else #endif // DBCSAWARE #ifdef DBG_SHOW_DIRTY - fterm_rawattr(FTD[x] ? - (FTAMAP[y][x] | FTATTR_BOLD) : (FTAMAP[y][x] & ~FTATTR_BOLD)); + fterm_rawattr(FTD[x] ? + (FTAMAP[y][x] | FTATTR_BOLD) : (FTAMAP[y][x] & ~FTATTR_BOLD)); #else // !DBG_SHOW_DIRTY - fterm_rawattr(FTAMAP[y][x]); + fterm_rawattr(FTAMAP[y][x]); #endif // !DBG_SHOW_DIRTY - fterm_rawc(FTDC[x]); - ft.rx++; - touched = 1; - - if (FTD[x] & FTDIRTY_RAWMOVE) - { - fterm_rawcmd2(ft.ry+1, ft.rx+1, 1, 'H'); - } - } - - if (derase) - { - fterm_rawmove_opt(y, len); - fterm_rawclreol(); - } - } + fterm_rawc(FTDC[x]); + ft.rx++; + touched = 1; + + if (FTD[x] & FTDIRTY_RAWMOVE) + { + fterm_rawcmd2(ft.ry+1, ft.rx+1, 1, 'H'); + } + } + + if (derase) + { + fterm_rawmove_opt(y, len); + fterm_rawclreol(); + } + } #endif // !_WIN32 - // doing fterm_rawcursor() earlier to enable max display time - fterm_rawcursor(); - fterm_dupe2bk(); - ft.dirty = 0; + // doing fterm_rawcursor() earlier to enable max display time + fterm_rawcursor(); + fterm_dupe2bk(); + ft.dirty = 0; } // cursor management @@ -1012,26 +1012,26 @@ doupdate(void) void getyx(int *y, int *x) { - if (y) - *y = ft.y; - if (x) - *x = ft.x; + if (y) + *y = ft.y; + if (x) + *x = ft.x; } void getmaxyx(int *y, int *x) { - if (y) - *y = ft.rows; - if (x) - *x = ft.cols; + if (y) + *y = ft.rows; + if (x) + *x = ft.cols; } void move(int y, int x) { - ft.y = ranged(y, 0, ft.rows-1); - ft.x = ranged(x, 0, ft.cols-1); + ft.y = ranged(y, 0, ft.rows-1); + ft.x = ranged(x, 0, ft.cols-1); } // scrolling @@ -1039,1192 +1039,1192 @@ move(int y, int x) void scrl(int rows) { - if (!rows) - return; - if (rows > 0) - { - for (; rows > 0; rows--) - scroll(); - } else { - for (; rows < 0; rows++) - rscroll(); - } + if (!rows) + return; + if (rows > 0) + { + for (; rows > 0; rows--) + scroll(); + } else { + for (; rows < 0; rows++) + rscroll(); + } } void scroll() { - // scroll up - int y; - ftchar *c0 = FTCMAP[0], *oc0 = FTOCMAP[0]; - ftattr *a0 = FTAMAP[0], *oa0 = FTOAMAP[0]; - - // prevent mixing buffered scroll up+down - if (ft.scroll < 0) - fterm_rawscroll(ft.scroll); - - // smart scroll: move pointers - for (y = 0; y < ft.rows-1; y++) - { - FTCMAP[y] = FTCMAP[y+1]; - FTAMAP[y] = FTAMAP[y+1]; - FTOCMAP[y]= FTOCMAP[y+1]; - FTOAMAP[y]= FTOAMAP[y+1]; - } - FTCMAP[y] = c0; - FTAMAP[y] = a0; - FTOCMAP[y]= oc0; - FTOAMAP[y]= oa0; - - // XXX also clear backup buffer - // must carefully consider if up then down scrolling. - fterm_flippage(); - clrregion(ft.rows-1, ft.rows-1); - fterm_flippage(); - clrregion(ft.rows-1, ft.rows-1); - - ft.scroll ++; - // fterm_markdirty(); // should be already dirty + // scroll up + int y; + ftchar *c0 = FTCMAP[0], *oc0 = FTOCMAP[0]; + ftattr *a0 = FTAMAP[0], *oa0 = FTOAMAP[0]; + + // prevent mixing buffered scroll up+down + if (ft.scroll < 0) + fterm_rawscroll(ft.scroll); + + // smart scroll: move pointers + for (y = 0; y < ft.rows-1; y++) + { + FTCMAP[y] = FTCMAP[y+1]; + FTAMAP[y] = FTAMAP[y+1]; + FTOCMAP[y]= FTOCMAP[y+1]; + FTOAMAP[y]= FTOAMAP[y+1]; + } + FTCMAP[y] = c0; + FTAMAP[y] = a0; + FTOCMAP[y]= oc0; + FTOAMAP[y]= oa0; + + // XXX also clear backup buffer + // must carefully consider if up then down scrolling. + fterm_flippage(); + clrregion(ft.rows-1, ft.rows-1); + fterm_flippage(); + clrregion(ft.rows-1, ft.rows-1); + + ft.scroll ++; + // fterm_markdirty(); // should be already dirty } void rscroll() { - // scroll down - int y; - ftchar *c0 = FTCMAP[ft.rows -1], *oc0 = FTOCMAP[ft.rows -1]; - ftattr *a0 = FTAMAP[ft.rows -1], *oa0 = FTOAMAP[ft.rows -1]; - - // prevent mixing buffered scroll up+down - if (ft.scroll > 0) - fterm_rawscroll(ft.scroll); - - // smart scroll: move pointers - for (y = ft.rows -1; y > 0; y--) - { - FTCMAP[y] = FTCMAP[y-1]; - FTAMAP[y] = FTAMAP[y-1]; - FTOCMAP[y]= FTOCMAP[y-1]; - FTOAMAP[y]= FTOAMAP[y-1]; - } - FTCMAP[y] = c0; - FTAMAP[y] = a0; - FTOCMAP[y]= oc0; - FTOAMAP[y]= oa0; - - // XXX also clear backup buffer - // must carefully consider if up then down scrolling. - fterm_flippage(); - clrregion(0, 0); - fterm_flippage(); - clrregion(0, 0); - - ft.scroll --; - // fterm_markdirty(); // should be already dirty + // scroll down + int y; + ftchar *c0 = FTCMAP[ft.rows -1], *oc0 = FTOCMAP[ft.rows -1]; + ftattr *a0 = FTAMAP[ft.rows -1], *oa0 = FTOAMAP[ft.rows -1]; + + // prevent mixing buffered scroll up+down + if (ft.scroll > 0) + fterm_rawscroll(ft.scroll); + + // smart scroll: move pointers + for (y = ft.rows -1; y > 0; y--) + { + FTCMAP[y] = FTCMAP[y-1]; + FTAMAP[y] = FTAMAP[y-1]; + FTOCMAP[y]= FTOCMAP[y-1]; + FTOAMAP[y]= FTOAMAP[y-1]; + } + FTCMAP[y] = c0; + FTAMAP[y] = a0; + FTOCMAP[y]= oc0; + FTOAMAP[y]= oa0; + + // XXX also clear backup buffer + // must carefully consider if up then down scrolling. + fterm_flippage(); + clrregion(0, 0); + fterm_flippage(); + clrregion(0, 0); + + ft.scroll --; + // fterm_markdirty(); // should be already dirty } // output -void +void addch (unsigned char c) { - outc(c); + outc(c); } -void +void addstr (const char *s) { - outs(s); + outs(s); } void addnstr(const char *s, int n) { - outns(s, n); + outns(s, n); } void addstring(const char *s) { - outstr(s); + outstr(s); } -void +void outs(const char *s) { if (!s) - return; - while (*s) - outc(*s++); + return; + while (*s) + outc(*s++); } -void +void outns(const char *s, int n) { if (!s) - return; - while (*s && n-- > 0) - outc(*s++); + return; + while (*s && n-- > 0) + outc(*s++); } void outstr(const char *str) { - if (!str) - { - fterm_prepare_str(0); - return; - } + if (!str) + { + fterm_prepare_str(0); + return; + } - // calculate real length of str (stripping escapes) - // TODO only print by the returned size - - fterm_prepare_str(fterm_strdlen(str)); + // calculate real length of str (stripping escapes) + // TODO only print by the returned size + + fterm_prepare_str(fterm_strdlen(str)); - outs(str); + outs(str); - // maybe the source string itself is broken... - // basically this check should be done by clients, not term library. + // maybe the source string itself is broken... + // basically this check should be done by clients, not term library. #if 0 - { - int isdbcs = 0; - while (*str) - { - if (isdbcs == 1) isdbcs = 2; - else if (FTDBCS_ISLEAD(*str)) isdbcs = 1; - else isdbcs = 0; - str++; - } - - if (isdbcs == 1) // incomplete string! - outs("\b?"); - } + { + int isdbcs = 0; + while (*str) + { + if (isdbcs == 1) isdbcs = 2; + else if (FTDBCS_ISLEAD(*str)) isdbcs = 1; + else isdbcs = 0; + str++; + } + + if (isdbcs == 1) // incomplete string! + outs("\b?"); + } #endif } void outc(unsigned char c) { - // 0xFF is invalid for most cases (even DBCS), - if (c == 0xFF || c == 0x00) - return; - - fterm_markdirty(); - if (ft.szcmd) - { - // collecting commands - ft.cmd[ft.szcmd++] = c; - - if ((ft.szcmd == 2 && c == '[') || - (ANSI_IS_PARAM(c) && ft.szcmd < FTCMD_MAXLEN)) - return; - - // process as command - fterm_exec(); - ft.szcmd = 0; - } - else if (c == ESC_CHR) - { - // start of escaped commands - ft.cmd[ft.szcmd++] = c; - } - else if (c == '\t') - { - // tab: move by 8, and erase the moved range - int x = ft.x; - if (x % 8 == 0) - x += 8; - else - x += (8-(x%8)); - x = ranged(x, 0, ft.cols-1); - // erase the characters between - if (x > ft.x) - { - memset(FTCROW+ft.x, FTCHAR_ERASE, x - ft.x); - memset(FTAROW+ft.x, ft.attr, x-ft.x); - } - ft.x = x; - } - else if (c == '\b') - { - ft.x = ranged(ft.x-1, 0, ft.cols-1); - } - else if (c == '\r' || c == '\n') - { - // new line: cursor movement, and do not print anything - // XXX old screen.c also calls clrtoeol() for newlins. - clrtoeol(); - ft.x = 0; - ft.y ++; - while (ft.y >= ft.rows) - { - // XXX scroll at next dirty? - // screen.c ignored such scroll. - // scroll(); - ft.y --; - } - } - else if (iscntrl((unsigned char)c)) - { - // unknown control characters: ignore - } - else // normal characters - { - assert (ft.x >= 0 && ft.x < ft.cols); - - // normal characters - FTC = c; + // 0xFF is invalid for most cases (even DBCS), + if (c == 0xFF || c == 0x00) + return; + + fterm_markdirty(); + if (ft.szcmd) + { + // collecting commands + ft.cmd[ft.szcmd++] = c; + + if ((ft.szcmd == 2 && c == '[') || + (ANSI_IS_PARAM(c) && ft.szcmd < FTCMD_MAXLEN)) + return; + + // process as command + fterm_exec(); + ft.szcmd = 0; + } + else if (c == ESC_CHR) + { + // start of escaped commands + ft.cmd[ft.szcmd++] = c; + } + else if (c == '\t') + { + // tab: move by 8, and erase the moved range + int x = ft.x; + if (x % 8 == 0) + x += 8; + else + x += (8-(x%8)); + x = ranged(x, 0, ft.cols-1); + // erase the characters between + if (x > ft.x) + { + memset(FTCROW+ft.x, FTCHAR_ERASE, x - ft.x); + memset(FTAROW+ft.x, ft.attr, x-ft.x); + } + ft.x = x; + } + else if (c == '\b') + { + ft.x = ranged(ft.x-1, 0, ft.cols-1); + } + else if (c == '\r' || c == '\n') + { + // new line: cursor movement, and do not print anything + // XXX old screen.c also calls clrtoeol() for newlins. + clrtoeol(); + ft.x = 0; + ft.y ++; + while (ft.y >= ft.rows) + { + // XXX scroll at next dirty? + // screen.c ignored such scroll. + // scroll(); + ft.y --; + } + } + else if (iscntrl((unsigned char)c)) + { + // unknown control characters: ignore + } + else // normal characters + { + assert (ft.x >= 0 && ft.x < ft.cols); + + // normal characters + FTC = c; #ifdef FTATTR_TRANSPARENT - if (ft.attr != FTATTR_TRANSPARENT) + if (ft.attr != FTATTR_TRANSPARENT) #endif // FTATTR_TRANSPARENT - FTA = ft.attr; - - ft.x++; - // XXX allow x == ft.cols? - if (ft.x >= ft.cols) - { - ft.x = 0; - ft.y ++; - while (ft.y >= ft.rows) - { - // XXX scroll at next dirty? - // screen.c ignored such scroll. - // scroll(); - ft.y --; - } - } - } + FTA = ft.attr; + + ft.x++; + // XXX allow x == ft.cols? + if (ft.x >= ft.cols) + { + ft.x = 0; + ft.y ++; + while (ft.y >= ft.rows) + { + // XXX scroll at next dirty? + // screen.c ignored such scroll. + // scroll(); + ft.y --; + } + } + } } // readback -int -instr (char *str) -{ - int x = ft.cols -1; - *str = 0; - if (ft.y < 0 || ft.y >= ft.rows || ft.x < 0 || ft.x >= ft.cols) - return 0; - - // determine stopping location - while (x >= ft.x && FTCROW[x] == FTCHAR_ERASE) - x--; - if (x < ft.x) return 0; - x = x - ft.x + 1; - memcpy(str, FTCROW+ft.x, x); - str[x] = 0; - return x; -} - -int -innstr (char *str, int n) -{ - int on = n; - int x = ranged(ft.x + n-1, 0, ft.cols-1); - *str = 0; - n = x - ft.x+1; - if (on < 1 || ft.y < 0 || ft.y >= ft.rows || ft.x < 0 || ft.x >= ft.cols) - return 0; - - // determine stopping location - while (x >= ft.x && FTCROW[x] == FTCHAR_ERASE) - x--; - if (x < ft.x) return 0; - n = x - ft.x + 1; - if (n >= on) n = on-1; - memcpy(str, FTCROW+ft.x, n); - str[n] = 0; - return n; -} - -int -inansistr (char *str, int n) -{ - int x = ft.cols -1, i = 0, szTrail = 0; - char *ostr = str; - char cmd[FTATTR_MINCMD*2] = ""; - - ftattr a = FTATTR_DEFAULT; - *str = 0; - if (ft.y < 0 || ft.y >= ft.rows || ft.x < 0 || ft.x >= ft.cols) - return 0; - - if (n < 1) - return 0; - n--; // preserve last zero - - // determine stopping location - while (x >= ft.x && FTCROW[x] == FTCHAR_ERASE && FTAROW[x] == FTATTR_ERASE) - x--; - - // retrieve [rt.x, x] - if (x < ft.x) return 0; - - // preserve some bytes if last attribute is not FTATTR_DEFAULT - for (i = ft.x; n > szTrail && i <= x; i++) - { - *str = 0; - - if (a != FTAROW[i]) - { - fterm_chattr(cmd, a, FTAROW[i]); - a = FTAROW[i]; - - if (a != FTATTR_DEFAULT) - szTrail = 3; // ESC [ m - else - szTrail = 0; - - if (strlen(cmd) >= n-szTrail) - break; - - strcpy(str, cmd); - n -= strlen(cmd); - str += strlen(cmd); - } - - // n should > szTrail - *str ++ = FTCROW[i]; - n--; - } - - if (szTrail && n >= szTrail) - { - *str++ = ESC_CHR; *str++ = '['; *str++ = 'm'; - } - - *str = 0; - return (str - ostr); +int +instr (char *str) +{ + int x = ft.cols -1; + *str = 0; + if (ft.y < 0 || ft.y >= ft.rows || ft.x < 0 || ft.x >= ft.cols) + return 0; + + // determine stopping location + while (x >= ft.x && FTCROW[x] == FTCHAR_ERASE) + x--; + if (x < ft.x) return 0; + x = x - ft.x + 1; + memcpy(str, FTCROW+ft.x, x); + str[x] = 0; + return x; +} + +int +innstr (char *str, int n) +{ + int on = n; + int x = ranged(ft.x + n-1, 0, ft.cols-1); + *str = 0; + n = x - ft.x+1; + if (on < 1 || ft.y < 0 || ft.y >= ft.rows || ft.x < 0 || ft.x >= ft.cols) + return 0; + + // determine stopping location + while (x >= ft.x && FTCROW[x] == FTCHAR_ERASE) + x--; + if (x < ft.x) return 0; + n = x - ft.x + 1; + if (n >= on) n = on-1; + memcpy(str, FTCROW+ft.x, n); + str[n] = 0; + return n; +} + +int +inansistr (char *str, int n) +{ + int x = ft.cols -1, i = 0, szTrail = 0; + char *ostr = str; + char cmd[FTATTR_MINCMD*2] = ""; + + ftattr a = FTATTR_DEFAULT; + *str = 0; + if (ft.y < 0 || ft.y >= ft.rows || ft.x < 0 || ft.x >= ft.cols) + return 0; + + if (n < 1) + return 0; + n--; // preserve last zero + + // determine stopping location + while (x >= ft.x && FTCROW[x] == FTCHAR_ERASE && FTAROW[x] == FTATTR_ERASE) + x--; + + // retrieve [rt.x, x] + if (x < ft.x) return 0; + + // preserve some bytes if last attribute is not FTATTR_DEFAULT + for (i = ft.x; n > szTrail && i <= x; i++) + { + *str = 0; + + if (a != FTAROW[i]) + { + fterm_chattr(cmd, a, FTAROW[i]); + a = FTAROW[i]; + + if (a != FTATTR_DEFAULT) + szTrail = 3; // ESC [ m + else + szTrail = 0; + + if (strlen(cmd) >= n-szTrail) + break; + + strcpy(str, cmd); + n -= strlen(cmd); + str += strlen(cmd); + } + + // n should > szTrail + *str ++ = FTCROW[i]; + n--; + } + + if (szTrail && n >= szTrail) + { + *str++ = ESC_CHR; *str++ = '['; *str++ = 'm'; + } + + *str = 0; + return (str - ostr); } // internal core of piaip's flat-term -void +void fterm_flippage (void) { - // we have only 2 pages now. - ft.mi = 1 - ft.mi; + // we have only 2 pages now. + ft.mi = 1 - ft.mi; } #ifndef fterm_markdirty void fterm_markdirty (void) { - ft.dirty = 1; + ft.dirty = 1; } #endif void fterm_dupe2bk(void) { - int r = 0; - - for (r = 0; r < ft.rows; r++) - { - memcpy(FTOCMAP[r], FTCMAP[r], ft.cols * sizeof(ftchar)); - memcpy(FTOAMAP[r], FTAMAP[r], ft.cols * sizeof(ftattr)); - } + int r = 0; + + for (r = 0; r < ft.rows; r++) + { + memcpy(FTOCMAP[r], FTCMAP[r], ft.cols * sizeof(ftchar)); + memcpy(FTOAMAP[r], FTAMAP[r], ft.cols * sizeof(ftattr)); + } } int fterm_DBCS_Big5(unsigned char c1, unsigned char c2) { - // ref: http://www.cns11643.gov.tw/web/word/big5/index.html - // High byte: 0xA1-0xFE, 0x8E-0xA0, 0x81-0x8D - // Low byte: 0x40-0x7E, 0xA1-0xFE - // C1: 0x80-0x9F - if (FTDBCS_ISBADLEAD(c1)) - return FTDBCS_INVALID; - if (!FTDBCS_ISTAIL(c2)) - return FTDBCS_INVALID; - if (c1 >= 0x80 && c1 <= 0x9F) - return FTDBCS_UNSAFE; - return FTDBCS_SAFE; + // ref: http://www.cns11643.gov.tw/web/word/big5/index.html + // High byte: 0xA1-0xFE, 0x8E-0xA0, 0x81-0x8D + // Low byte: 0x40-0x7E, 0xA1-0xFE + // C1: 0x80-0x9F + if (FTDBCS_ISBADLEAD(c1)) + return FTDBCS_INVALID; + if (!FTDBCS_ISTAIL(c2)) + return FTDBCS_INVALID; + if (c1 >= 0x80 && c1 <= 0x9F) + return FTDBCS_UNSAFE; + return FTDBCS_SAFE; } int fterm_prepare_str(int len) { - // clear and make (cursor, +len) as DBCS-ready. - int x = ranged(ft.x, 0, ft.cols-1); - int y = ranged(ft.y, 0, ft.rows-1); - int dbcs = 0, sdbcs = 0; - - // TODO what if x+len is outside range? - - // check if (x,y) is in valid range - if (x != ft.x || y != ft.y) - return -1; - - len = ranged(x+len, x, ft.cols); - - for (x = 0; x < len; x++) - { - // determine DBCS status - if (dbcs == 1) - dbcs = 2; // TAIL - else if (FTDBCS_ISLEAD(FTCROW[x])) - dbcs = 1; // LEAD - else - dbcs = 0; - if (x == ft.x) sdbcs = dbcs; - } - - x = ft.x; - // fix start and end - if(sdbcs == 2 && x > 0) // TAIL, remove word - x--; - if (dbcs == 1 && len < ft.cols) // LEAD, remove word - len ++; - len = ranged(len, 0, ft.cols); - len -= x; - if (len < 0) len = 0; - - memset(FTCROW + x, FTCHAR_ERASE, len); - memset(FTAROW + x, ft.attr, len); - return len; -} - - -void + // clear and make (cursor, +len) as DBCS-ready. + int x = ranged(ft.x, 0, ft.cols-1); + int y = ranged(ft.y, 0, ft.rows-1); + int dbcs = 0, sdbcs = 0; + + // TODO what if x+len is outside range? + + // check if (x,y) is in valid range + if (x != ft.x || y != ft.y) + return -1; + + len = ranged(x+len, x, ft.cols); + + for (x = 0; x < len; x++) + { + // determine DBCS status + if (dbcs == 1) + dbcs = 2; // TAIL + else if (FTDBCS_ISLEAD(FTCROW[x])) + dbcs = 1; // LEAD + else + dbcs = 0; + if (x == ft.x) sdbcs = dbcs; + } + + x = ft.x; + // fix start and end + if(sdbcs == 2 && x > 0) // TAIL, remove word + x--; + if (dbcs == 1 && len < ft.cols) // LEAD, remove word + len ++; + len = ranged(len, 0, ft.cols); + len -= x; + if (len < 0) len = 0; + + memset(FTCROW + x, FTCHAR_ERASE, len); + memset(FTAROW + x, ft.attr, len); + return len; +} + + +void fterm_exec(void) { - ftchar cmd = ft.cmd[ft.szcmd-1]; - char *p = (char*)ft.cmd + 2; // ESC [ - int n = -1, x = -1, y; - - ft.cmd[ft.szcmd] = 0; - - if (isdigit(*p)) - { - n = atoi(p); - - while (*p && isdigit(*p)) - p++; - - if (*p == ';') - p++; - // p points to next param now - } - - switch(cmd) - { - // Cursor Movement - - case 'A': // CUU: CSI n A - case 'B': // CUD: CSI n B - case 'C': // CUF: CSI n C - case 'D': // CUB: CSI n D - // Moves the cursor n (default 1) cells in the given direction. - // If the cursor is already at the edge of the screen, this has no effect. - if (n < 1) - n = 1; - getyx(&y, &x); - if (cmd == 'A') { y -= n; } - else if (cmd == 'B') { y += n; } - else if (cmd == 'C') { x += n; } - else if (cmd == 'D') { x -= n; } - move(y, x); - break; - - case 'E': // CNL: CSI n E - case 'F': // CPL: CSI n F - // Moves cursor to beginning of the line - // n (default 1) lines up/down (next/previous line). - if (n < 1) - n = 1; - getyx(&y, &x); - if (cmd == 'E') { y -= n; } - else if (cmd == 'F') { y += n; } - move(y, 0); - break; - - case 'G': // CHA: CSI n G - // Moves the cursor to column n. - if (n < 1) - n = 1; - getyx(&y, &x); - move(y, n-1); - break; - - case 'H': // CUP: CSI n ; m H - case 'f': // HVP: CSI n ; m f - // Moves the cursor to row n, column m. - // The values are 1-based, and default to 1 (top left corner) if omitted. - // A sequence such as CSI ;5H is a synonym for CSI 1;5H as well as - // CSI 17;H is the same as CSI 17H and CSI 17;1H - y = n; - if (y >= 0 && isdigit(*p)) - x = atoi((char*)p); - if (y < 0) y = 1; - if (x < 0) x = 1; - move(y-1, x-1); - break; - - // Clear - - case 'J': // ED: CSI n J - // Clears part of the screen. - // If n is zero (or missing), clear from cursor to end of screen. - // If n is one, clear from cursor to beginning of the screen. - // If n is two, clear entire screen - if (n == 0 || n < 0) - clrtobot(); - else if (n == 1) - clrtohome(); - else if (n == 2) - { - clrregion(0, ft.rows-1); - } - break; - - case 'K': // EL: CSI n K - // Erases part of the line. - // If n is zero (or missing), clear from cursor to the end of the line. - // If n is one, clear from cursor to beginning of the line. - // If n is two, clear entire line. Cursor position does not change. - if (n == 0 || n < 0) - clrtoeol(); - else if (n == 1) - clrtobeg(); - else if (n == 2) - clrcurrline(); - break; - - case 's': // SCP: CSI s - // Saves the cursor position. - getyx(&ft.sy, &ft.sx); - break; - - case 'u': // RCP: CSI u - // Restores the cursor position. - move(ft.sy, ft.sx); - break; - - case 'S': // SU: CSI n S - // Scroll whole page up by n (default 1) lines. - // New lines are added at the bottom. - if (n < 1) - n = 1; - scrl(n); - break; - - case 'T': // SD: CSI n T - // Scroll whole page down by n (default 1) lines. - // New lines are added at the top. - if (n < 1) - n = 1; - scrl(-n); - break; - - case 'm': // SGR: CSI n [;k] m - // Sets SGR (Select Graphic Rendition) parameters. - // After CSI can be zero or more parameters separated with ;. - // With no parameters, CSI m is treated as CSI 0 m (reset / normal), - // which is typical of most of the ANSI codes. - // --------------------------------------------------------- - // SGR implementation: - // SGR 0 (reset/normal) is supported. - // SGR 1 (intensity: bold) is supported. - // SGR 2 (intensity: faint) is not supported. - // SGR 3 (italic: on) is not supported. (converted to inverse?) - // SGR 4 (underline: single) is not supported. - // SGR 5 (blink: slow) is supported. - // SGR 6 (blink: rapid) is converted to (blink: slow) - // SGR 7 (image: negative) is partially supported (not a really attribute). - // SGR 8 (conceal) is not supported. - // SGR 21(underline: double) is not supported. - // SGR 22(intensity: normal) is supported. - // SGR 24(underline: none) is not supported. - // SGR 25(blink: off) is supported. - // SGR 27(image: positive) is not supported. - // SGR 28(reveal) is not supported. - // SGR 30-37 (FG) is supported. - // SGR 39 (FG-reset) is supported. - // SGR 40-47 (BG) is supported. - // SGR 49 (BG-reset) is supported. - if (n == -1) // first param - n = 0; - while (n > -1) - { - if (n >= 30 && n <= 37) - { - // set foreground - attrsetfg(n - 30); - } - else if (n >= 40 && n <= 47) - { - // set background - attrsetbg(n - 40); - } - else switch(n) - { - case 0: - attrset(FTATTR_DEFAULT); - break; - case 1: - attrset(attrget() | FTATTR_BOLD); - break; - case 22: - attrset(attrget() & ~FTATTR_BOLD); - break; - case 5: - case 6: - attrset(attrget() | FTATTR_BLINK); - break; - case 25: - attrset(attrget() & ~FTATTR_BLINK); - break; - case 3: - case 7: - { - ftattr a = attrget(); - attrsetfg(FTATTR_GETBG(a)); - attrsetbg(FTATTR_GETFG(a)); - } - break; - case 39: - attrsetfg(FTATTR_DEFAULT_FG); - break; - case 49: - attrsetbg(FTATTR_DEFAULT_BG); - break; - } - - // parse next command - n = -1; - if (*p == ';') - { - n = 0; - p++; - } - else if (isdigit(*p)) - { - n = atoi(p); - while (isdigit(*p)) p++; - if (*p == ';') - p++; - } - } - break; - - default: // unknown command. - break; - } + ftchar cmd = ft.cmd[ft.szcmd-1]; + char *p = (char*)ft.cmd + 2; // ESC [ + int n = -1, x = -1, y; + + ft.cmd[ft.szcmd] = 0; + + if (isdigit(*p)) + { + n = atoi(p); + + while (*p && isdigit(*p)) + p++; + + if (*p == ';') + p++; + // p points to next param now + } + + switch(cmd) + { + // Cursor Movement + + case 'A': // CUU: CSI n A + case 'B': // CUD: CSI n B + case 'C': // CUF: CSI n C + case 'D': // CUB: CSI n D + // Moves the cursor n (default 1) cells in the given direction. + // If the cursor is already at the edge of the screen, this has no effect. + if (n < 1) + n = 1; + getyx(&y, &x); + if (cmd == 'A') { y -= n; } + else if (cmd == 'B') { y += n; } + else if (cmd == 'C') { x += n; } + else if (cmd == 'D') { x -= n; } + move(y, x); + break; + + case 'E': // CNL: CSI n E + case 'F': // CPL: CSI n F + // Moves cursor to beginning of the line + // n (default 1) lines up/down (next/previous line). + if (n < 1) + n = 1; + getyx(&y, &x); + if (cmd == 'E') { y -= n; } + else if (cmd == 'F') { y += n; } + move(y, 0); + break; + + case 'G': // CHA: CSI n G + // Moves the cursor to column n. + if (n < 1) + n = 1; + getyx(&y, &x); + move(y, n-1); + break; + + case 'H': // CUP: CSI n ; m H + case 'f': // HVP: CSI n ; m f + // Moves the cursor to row n, column m. + // The values are 1-based, and default to 1 (top left corner) if omitted. + // A sequence such as CSI ;5H is a synonym for CSI 1;5H as well as + // CSI 17;H is the same as CSI 17H and CSI 17;1H + y = n; + if (y >= 0 && isdigit(*p)) + x = atoi((char*)p); + if (y < 0) y = 1; + if (x < 0) x = 1; + move(y-1, x-1); + break; + + // Clear + + case 'J': // ED: CSI n J + // Clears part of the screen. + // If n is zero (or missing), clear from cursor to end of screen. + // If n is one, clear from cursor to beginning of the screen. + // If n is two, clear entire screen + if (n == 0 || n < 0) + clrtobot(); + else if (n == 1) + clrtohome(); + else if (n == 2) + { + clrregion(0, ft.rows-1); + } + break; + + case 'K': // EL: CSI n K + // Erases part of the line. + // If n is zero (or missing), clear from cursor to the end of the line. + // If n is one, clear from cursor to beginning of the line. + // If n is two, clear entire line. Cursor position does not change. + if (n == 0 || n < 0) + clrtoeol(); + else if (n == 1) + clrtobeg(); + else if (n == 2) + clrcurrline(); + break; + + case 's': // SCP: CSI s + // Saves the cursor position. + getyx(&ft.sy, &ft.sx); + break; + + case 'u': // RCP: CSI u + // Restores the cursor position. + move(ft.sy, ft.sx); + break; + + case 'S': // SU: CSI n S + // Scroll whole page up by n (default 1) lines. + // New lines are added at the bottom. + if (n < 1) + n = 1; + scrl(n); + break; + + case 'T': // SD: CSI n T + // Scroll whole page down by n (default 1) lines. + // New lines are added at the top. + if (n < 1) + n = 1; + scrl(-n); + break; + + case 'm': // SGR: CSI n [;k] m + // Sets SGR (Select Graphic Rendition) parameters. + // After CSI can be zero or more parameters separated with ;. + // With no parameters, CSI m is treated as CSI 0 m (reset / normal), + // which is typical of most of the ANSI codes. + // --------------------------------------------------------- + // SGR implementation: + // SGR 0 (reset/normal) is supported. + // SGR 1 (intensity: bold) is supported. + // SGR 2 (intensity: faint) is not supported. + // SGR 3 (italic: on) is not supported. (converted to inverse?) + // SGR 4 (underline: single) is not supported. + // SGR 5 (blink: slow) is supported. + // SGR 6 (blink: rapid) is converted to (blink: slow) + // SGR 7 (image: negative) is partially supported (not a really attribute). + // SGR 8 (conceal) is not supported. + // SGR 21(underline: double) is not supported. + // SGR 22(intensity: normal) is supported. + // SGR 24(underline: none) is not supported. + // SGR 25(blink: off) is supported. + // SGR 27(image: positive) is not supported. + // SGR 28(reveal) is not supported. + // SGR 30-37 (FG) is supported. + // SGR 39 (FG-reset) is supported. + // SGR 40-47 (BG) is supported. + // SGR 49 (BG-reset) is supported. + if (n == -1) // first param + n = 0; + while (n > -1) + { + if (n >= 30 && n <= 37) + { + // set foreground + attrsetfg(n - 30); + } + else if (n >= 40 && n <= 47) + { + // set background + attrsetbg(n - 40); + } + else switch(n) + { + case 0: + attrset(FTATTR_DEFAULT); + break; + case 1: + attrset(attrget() | FTATTR_BOLD); + break; + case 22: + attrset(attrget() & ~FTATTR_BOLD); + break; + case 5: + case 6: + attrset(attrget() | FTATTR_BLINK); + break; + case 25: + attrset(attrget() & ~FTATTR_BLINK); + break; + case 3: + case 7: + { + ftattr a = attrget(); + attrsetfg(FTATTR_GETBG(a)); + attrsetbg(FTATTR_GETFG(a)); + } + break; + case 39: + attrsetfg(FTATTR_DEFAULT_FG); + break; + case 49: + attrsetbg(FTATTR_DEFAULT_BG); + break; + } + + // parse next command + n = -1; + if (*p == ';') + { + n = 0; + p++; + } + else if (isdigit(*p)) + { + n = atoi(p); + while (isdigit(*p)) p++; + if (*p == ';') + p++; + } + } + break; + + default: // unknown command. + break; + } } int fterm_chattr(char *s, ftattr oattr, ftattr nattr) { - ftattr - fg, bg, bold, blink, - ofg, obg, obold, oblink; - char lead = 1; - - if (oattr == nattr) - return 0; - - *s++ = ESC_CHR; - *s++ = '['; - - // optimization: reset as default - if (nattr == FTATTR_DEFAULT) - { - *s++ = 'm'; - *s++ = 0; - return 1; - } - - fg = FTATTR_GETFG(nattr); - bg = FTATTR_GETBG(nattr); - bold = (nattr & FTATTR_BOLD) ? 1 : 0; - blink = (nattr & FTATTR_BLINK)? 1 : 0; - - ofg = FTATTR_GETFG(oattr); - obg = FTATTR_GETBG(oattr); - obold = (oattr & FTATTR_BOLD) ? 1 : 0; - oblink = (oattr & FTATTR_BLINK)? 1 : 0; - - // we dont use "disable blink/bold" commands, - // so if these settings are changed then we must reset. - // another case is changing background to default background - - // better use "RESET" to override it. - // Same for foreground. - // Possible optimization: when blink/bold on, don't RESET - // for background change? - if ((oblink != blink && !blink) || - (obold != bold && !bold) || - (bg == FTATTR_DEFAULT_BG && obg != bg) || - (fg == FTATTR_DEFAULT_FG && ofg != fg) ) - { - if (lead) lead = 0; else *s++ = ';'; - *s++ = '0'; - - ofg = FTATTR_DEFAULT_FG; - obg = FTATTR_DEFAULT_BG; - obold = 0; oblink = 0; - } - - if (bold && !obold) - { - if (lead) lead = 0; else *s++ = ';'; - *s++ = '1'; + ftattr + fg, bg, bold, blink, + ofg, obg, obold, oblink; + char lead = 1; + + if (oattr == nattr) + return 0; + + *s++ = ESC_CHR; + *s++ = '['; + + // optimization: reset as default + if (nattr == FTATTR_DEFAULT) + { + *s++ = 'm'; + *s++ = 0; + return 1; + } + + fg = FTATTR_GETFG(nattr); + bg = FTATTR_GETBG(nattr); + bold = (nattr & FTATTR_BOLD) ? 1 : 0; + blink = (nattr & FTATTR_BLINK)? 1 : 0; + + ofg = FTATTR_GETFG(oattr); + obg = FTATTR_GETBG(oattr); + obold = (oattr & FTATTR_BOLD) ? 1 : 0; + oblink = (oattr & FTATTR_BLINK)? 1 : 0; + + // we dont use "disable blink/bold" commands, + // so if these settings are changed then we must reset. + // another case is changing background to default background - + // better use "RESET" to override it. + // Same for foreground. + // Possible optimization: when blink/bold on, don't RESET + // for background change? + if ((oblink != blink && !blink) || + (obold != bold && !bold) || + (bg == FTATTR_DEFAULT_BG && obg != bg) || + (fg == FTATTR_DEFAULT_FG && ofg != fg) ) + { + if (lead) lead = 0; else *s++ = ';'; + *s++ = '0'; + + ofg = FTATTR_DEFAULT_FG; + obg = FTATTR_DEFAULT_BG; + obold = 0; oblink = 0; + } + + if (bold && !obold) + { + if (lead) lead = 0; else *s++ = ';'; + *s++ = '1'; #ifdef FTCONF_WORKAROUND_BOLD - // Issue here: - // PacketSite does not understand ESC[1m. It needs ESC[1;37m - // NetTerm defaults bold color to yellow. - // As a result, we use ESC[1;37m for the case. - if (fg == FTATTR_DEFAULT_FG) - ofg = ~ofg; + // Issue here: + // PacketSite does not understand ESC[1m. It needs ESC[1;37m + // NetTerm defaults bold color to yellow. + // As a result, we use ESC[1;37m for the case. + if (fg == FTATTR_DEFAULT_FG) + ofg = ~ofg; #endif // FTCONF_WORKAROUND_BOLD - } - if (blink && !oblink) - { - if (lead) lead = 0; else *s++ = ';'; - *s++ = '5'; // XXX 5(slow) or 6(fast)? - } - if (ofg != fg) - { - if (lead) lead = 0; else *s++ = ';'; - *s++ = '3'; - *s++ = '0' + fg; - } - if (obg != bg) - { - if (lead) lead = 0; else *s++ = ';'; - *s++ = '4'; - *s++ = '0' + bg; - } - *s++ = 'm'; - *s++ = 0; - return 1; -} - -int + } + if (blink && !oblink) + { + if (lead) lead = 0; else *s++ = ';'; + *s++ = '5'; // XXX 5(slow) or 6(fast)? + } + if (ofg != fg) + { + if (lead) lead = 0; else *s++ = ';'; + *s++ = '3'; + *s++ = '0' + fg; + } + if (obg != bg) + { + if (lead) lead = 0; else *s++ = ';'; + *s++ = '4'; + *s++ = '0' + bg; + } + *s++ = 'm'; + *s++ = 0; + return 1; +} + +int fterm_strdlen(const char *s) { - char ansi = 0; - int sz = 0; - - // the logic should match outc(). - - while (s && *s) - { - if (!ansi) // ansi == 0 - { - switch(*s) - { - case ESC_CHR: - ansi++; - break; - - case '\r': - case '\n': - break; - - case '\b': - if (sz) sz--; - break; - - case '\t': - // XXX how to deal with this? - sz ++; - break; - - default: - if (!iscntrl((unsigned char)*s)) - sz++; - break; - } - } - else if (ansi == 1) - { - if (*s == '[') - ansi++; - else - ansi = 0; - } - else if (!ANSI_IS_PARAM(*s)) // ansi == 2 - { - // TODO outc() take max to FTCMD_MAXLEN now... - ansi = 0; - } - s++; - } - return sz; -} - -void + char ansi = 0; + int sz = 0; + + // the logic should match outc(). + + while (s && *s) + { + if (!ansi) // ansi == 0 + { + switch(*s) + { + case ESC_CHR: + ansi++; + break; + + case '\r': + case '\n': + break; + + case '\b': + if (sz) sz--; + break; + + case '\t': + // XXX how to deal with this? + sz ++; + break; + + default: + if (!iscntrl((unsigned char)*s)) + sz++; + break; + } + } + else if (ansi == 1) + { + if (*s == '[') + ansi++; + else + ansi = 0; + } + else if (!ANSI_IS_PARAM(*s)) // ansi == 2 + { + // TODO outc() take max to FTCMD_MAXLEN now... + ansi = 0; + } + s++; + } + return sz; +} + +void fterm_rawattr(ftattr rattr) { - static char cmd[FTATTR_MINCMD*2]; - if (!fterm_chattr(cmd, ft.rattr, rattr)) - return; + static char cmd[FTATTR_MINCMD*2]; + if (!fterm_chattr(cmd, ft.rattr, rattr)) + return; - fterm_raws(cmd); - ft.rattr = rattr; + fterm_raws(cmd); + ft.rattr = rattr; } void fterm_rawnum(int arg) { - if (arg < 0 || arg > 99) - { - // complex. use printf. - char sarg[16]; // max int - sprintf(sarg, "%d", arg); - fterm_raws(sarg); - } else if (arg < 10) { - // 0 .. 10 - fterm_rawc('0' + arg); - } else { - fterm_rawc('0' + arg/10); - fterm_rawc('0' + arg%10); - } + if (arg < 0 || arg > 99) + { + // complex. use printf. + char sarg[16]; // max int + sprintf(sarg, "%d", arg); + fterm_raws(sarg); + } else if (arg < 10) { + // 0 .. 10 + fterm_rawc('0' + arg); + } else { + fterm_rawc('0' + arg/10); + fterm_rawc('0' + arg%10); + } } void fterm_rawcmd(int arg, int defval, char c) { - fterm_rawc(ESC_CHR); - fterm_rawc('['); - if (arg != defval) - fterm_rawnum(arg); - fterm_rawc(c); + fterm_rawc(ESC_CHR); + fterm_rawc('['); + if (arg != defval) + fterm_rawnum(arg); + fterm_rawc(c); } void fterm_rawcmd2(int arg1, int arg2, int defval, char c) { - fterm_rawc(ESC_CHR); - fterm_rawc('['); + fterm_rawc(ESC_CHR); + fterm_rawc('['); - // See FTCONF_ANSICMD2_OMIT - // XXX Win/DOS telnet does now accept omitting first value - // ESC[nX and ESC[n;X works, but ESC[;mX does not work. - if (arg1 != defval || arg2 != defval) - { + // See FTCONF_ANSICMD2_OMIT + // XXX Win/DOS telnet does now accept omitting first value + // ESC[nX and ESC[n;X works, but ESC[;mX does not work. + if (arg1 != defval || arg2 != defval) + { #if (FTCONF_ANSICMD2_OMIT >= 2) - if (arg1 != defval) + if (arg1 != defval) #endif - fterm_rawnum(arg1); + fterm_rawnum(arg1); #if (FTCONF_ANSICMD2_OMIT >= 1) - if (arg2 != defval) + if (arg2 != defval) #endif - { - fterm_rawc(';'); - fterm_rawnum(arg2); - } - } - fterm_rawc(c); + { + fterm_rawc(';'); + fterm_rawnum(arg2); + } + } + fterm_rawc(c); } -void +void fterm_rawclear(void) { - fterm_rawhome(); - // ED: CSI n J, 0 = cursor to bottom, 2 = whole - fterm_raws(ESC_STR "[2J"); + fterm_rawhome(); + // ED: CSI n J, 0 = cursor to bottom, 2 = whole + fterm_raws(ESC_STR "[2J"); } -void +void fterm_rawclreol(void) { #ifdef FTCONF_CLEAR_SETATTR - // ftattr oattr = ft.rattr; - // XXX If we skip with "backround only" here, future updating - // may get wrong attributes. Or not? (consider DBCS...) - // if (FTATTR_GETBG(oattr) != FTATTR_GETBG(FTATTR_ERASE)) - fterm_rawattr(FTATTR_ERASE); + // ftattr oattr = ft.rattr; + // XXX If we skip with "backround only" here, future updating + // may get wrong attributes. Or not? (consider DBCS...) + // if (FTATTR_GETBG(oattr) != FTATTR_GETBG(FTATTR_ERASE)) + fterm_rawattr(FTATTR_ERASE); #endif - // EL: CSI n K, n = 0 - fterm_raws(ESC_STR "[K"); + // EL: CSI n K, n = 0 + fterm_raws(ESC_STR "[K"); #ifdef FTCONF_CLEAR_SETATTR - // No need to do so? because we will always reset attribute... - // fterm_rawattr(oattr); + // No need to do so? because we will always reset attribute... + // fterm_rawattr(oattr); #endif } void fterm_rawhome(void) { - // CUP: CSI n ; m H - fterm_raws(ESC_STR "[H"); - ft.rx = ft.ry = 0; + // CUP: CSI n ; m H + fterm_raws(ESC_STR "[H"); + ft.rx = ft.ry = 0; } void fterm_rawmove_rel(int dy, int dx) { #ifndef FTCONF_USE_ANSI_RELMOVE - // Old BBS system does not output relative moves (ESC[ABCD) . - // Poor terminals (ex, pcman-1.0.5-FF20.xpi) - // do not support relmoves - fterm_rawmove(ft.ry + dy, ft.rx + dx); + // Old BBS system does not output relative moves (ESC[ABCD) . + // Poor terminals (ex, pcman-1.0.5-FF20.xpi) + // do not support relmoves + fterm_rawmove(ft.ry + dy, ft.rx + dx); #else - if (!dx) - { - int y = ranged(dy + ft.ry, 0, ft.rows-1); - dy = y - ft.ry; - if (!dy) - return; - - fterm_rawcmd(abs(dy), 1, dy < 0 ? 'A' : 'B'); - ft.ry = y; - } - else if (!dy) - { - int x = ranged(dx + ft.rx, 0, ft.cols-1); - dx = x - ft.rx; - if (!dx) - return; - - fterm_rawcmd(abs(dx), 1, dx < 0 ? 'D' : 'C'); - ft.rx = x; - } - else - { - // (dy, dx) are given - use fterm_move. - fterm_rawmove(ft.ry + dy, ft.rx + dx); - } + if (!dx) + { + int y = ranged(dy + ft.ry, 0, ft.rows-1); + dy = y - ft.ry; + if (!dy) + return; + + fterm_rawcmd(abs(dy), 1, dy < 0 ? 'A' : 'B'); + ft.ry = y; + } + else if (!dy) + { + int x = ranged(dx + ft.rx, 0, ft.cols-1); + dx = x - ft.rx; + if (!dx) + return; + + fterm_rawcmd(abs(dx), 1, dx < 0 ? 'D' : 'C'); + ft.rx = x; + } + else + { + // (dy, dx) are given - use fterm_move. + fterm_rawmove(ft.ry + dy, ft.rx + dx); + } #endif } void fterm_rawmove(int y, int x) { - y = ranged(y, 0, ft.rows-1); - x = ranged(x, 0, ft.cols-1); + y = ranged(y, 0, ft.rows-1); + x = ranged(x, 0, ft.cols-1); - if (y == ft.ry && x == ft.rx) - return; + if (y == ft.ry && x == ft.rx) + return; - // CUP: CSI n ; m H - fterm_rawcmd2(y+1, x+1, 1, 'H'); + // CUP: CSI n ; m H + fterm_rawcmd2(y+1, x+1, 1, 'H'); - ft.ry = y; - ft.rx = x; + ft.ry = y; + ft.rx = x; } void fterm_rawmove_opt(int y, int x) { - // optimized move - int ady = abs(y-ft.ry), adx=abs(x-ft.rx); + // optimized move + int ady = abs(y-ft.ry), adx=abs(x-ft.rx); - if (!adx && !ady) - return; + if (!adx && !ady) + return; #ifdef DBG_DISABLE_OPTMOVE - return fterm_rawmove(y, x); + return fterm_rawmove(y, x); #endif - // known hacks: \r = (x=0), \b=(x--), \n = (y++) - // - // Warning: any optimization here should not change displayed content, - // because we don't have information about content variation information - // (eg, invalid DBCS bytes will become special marks) here. - // Any hacks which will try to display data from FTCMAP should be done - // inside dirty-map calculation, for ex, using spaces to move right, - // or re-print content. - + // known hacks: \r = (x=0), \b=(x--), \n = (y++) + // + // Warning: any optimization here should not change displayed content, + // because we don't have information about content variation information + // (eg, invalid DBCS bytes will become special marks) here. + // Any hacks which will try to display data from FTCMAP should be done + // inside dirty-map calculation, for ex, using spaces to move right, + // or re-print content. + #ifndef DBG_TEXT_FD - // x=0: the cheapest output. However not work for text mode fd output. - // a special case is "if we have to move y to up". - // and FTCONF_ANSICMD2_OMIT < 1 (cannot omit x). + // x=0: the cheapest output. However not work for text mode fd output. + // a special case is "if we have to move y to up". + // and FTCONF_ANSICMD2_OMIT < 1 (cannot omit x). #if FTCONF_ANSICMD2_OMIT < 1 - if (y >= ft.ry) + if (y >= ft.ry) #endif - if (adx && x == 0) - { - fterm_rawc('\r'); - ft.rx = x = adx = 0; - } + if (adx && x == 0) + { + fterm_rawc('\r'); + ft.rx = x = adx = 0; + } #endif // !DBG_TEXT_FD - // x--: compare with FTMV_COST: ESC[m;nH costs 5-8 bytes - if (x < ft.rx && y >= ft.ry && (adx+ady) < FTMV_COST) - { - while (adx > 0) - fterm_rawc('\b'), adx--; - ft.rx = x; - } - - // finishing movement - if (y > ft.ry && ady < FTMV_COST && adx == 0) - { - while (ft.ry++ < y) - fterm_rawc('\n'); - ft.ry = y; - } - else if (ady && adx) - { - fterm_rawmove(y, x); - } - else if (ady) - { - fterm_rawmove_rel(y-ft.ry, 0); - } - else if (adx) - { - fterm_rawmove_rel(0, x-ft.rx); - } + // x--: compare with FTMV_COST: ESC[m;nH costs 5-8 bytes + if (x < ft.rx && y >= ft.ry && (adx+ady) < FTMV_COST) + { + while (adx > 0) + fterm_rawc('\b'), adx--; + ft.rx = x; + } + + // finishing movement + if (y > ft.ry && ady < FTMV_COST && adx == 0) + { + while (ft.ry++ < y) + fterm_rawc('\n'); + ft.ry = y; + } + else if (ady && adx) + { + fterm_rawmove(y, x); + } + else if (ady) + { + fterm_rawmove_rel(y-ft.ry, 0); + } + else if (adx) + { + fterm_rawmove_rel(0, x-ft.rx); + } } void fterm_rawcursor(void) { #ifdef _WIN32 - COORD cursor; - cursor.X = ft.x; - cursor.Y = ft.y; - SetConsoleCursorPosition(hStdout, cursor); + COORD cursor; + cursor.X = ft.x; + cursor.Y = ft.y; + SetConsoleCursorPosition(hStdout, cursor); #else - // fterm_rawattr(FTATTR_DEFAULT); - fterm_rawattr(ft.attr); - fterm_rawmove_opt(ft.y, ft.x); - fterm_rawflush(); + // fterm_rawattr(FTATTR_DEFAULT); + fterm_rawattr(ft.attr); + fterm_rawmove_opt(ft.y, ft.x); + fterm_rawflush(); #endif // !_WIN32 } -void -fterm_rawscroll (int dy) +void +fterm_rawscroll (int dy) { #ifdef FTCONF_USE_ANSI_SCROLL - // SU: CSI n S (up) - // SD: CSI n T (down) + // SU: CSI n S (up) + // SD: CSI n T (down) - char cmd = (dy > 0) ? 'S' : 'T'; - int ady = abs(dy); - if (ady == 0) - return; - if (ady >= ft.rows) ady = ft.rows; - fterm_rawcmd(ady, 1, cmd); - ft.scroll -= dy; + char cmd = (dy > 0) ? 'S' : 'T'; + int ady = abs(dy); + if (ady == 0) + return; + if (ady >= ft.rows) ady = ft.rows; + fterm_rawcmd(ady, 1, cmd); + ft.scroll -= dy; #else - // VT100 flavor: - // * ESC D: scroll down - // * ESC M: scroll up - // - // Elder BBS systems works in a mixed way: - // \n at (rows-1) as scroll() - // and ESC-M at(0) as rscoll(). - // - // SCP: CSI s / RCP: CSI u - // Warning: cannot use SCP/RCP here, because on Win/DOS telnet - // the position will change after scrolling (ex, (25,0)->(24,0). - // - // Since scroll does not happen very often, let's relax and not - // optimize these commands here... - - int ady = abs(dy); - if (ady == 0) - return; - if (ady >= ft.rows) ady = ft.rows; - - // we are not going to preserve (rx,ry) - // so don't use fterm_move*. - if (dy > 0) - fterm_rawcmd2(ft.rows, 1, 1, 'H'); - else - fterm_rawcmd2(1, 1, 1, 'H'); - - for (; ady > 0; ady--) - { - if (dy >0) - { - // Win/DOS telnet may have extra text in new line, - // because of the IME line. + // VT100 flavor: + // * ESC D: scroll down + // * ESC M: scroll up + // + // Elder BBS systems works in a mixed way: + // \n at (rows-1) as scroll() + // and ESC-M at(0) as rscoll(). + // + // SCP: CSI s / RCP: CSI u + // Warning: cannot use SCP/RCP here, because on Win/DOS telnet + // the position will change after scrolling (ex, (25,0)->(24,0). + // + // Since scroll does not happen very often, let's relax and not + // optimize these commands here... + + int ady = abs(dy); + if (ady == 0) + return; + if (ady >= ft.rows) ady = ft.rows; + + // we are not going to preserve (rx,ry) + // so don't use fterm_move*. + if (dy > 0) + fterm_rawcmd2(ft.rows, 1, 1, 'H'); + else + fterm_rawcmd2(1, 1, 1, 'H'); + + for (; ady > 0; ady--) + { + if (dy >0) + { + // Win/DOS telnet may have extra text in new line, + // because of the IME line. #ifdef FTCONF_USE_VT100_SCROLL - fterm_raws(ESC_STR "D" ESC_STR "[K"); // ESC_STR "[K"); + fterm_raws(ESC_STR "D" ESC_STR "[K"); // ESC_STR "[K"); #else - fterm_raws("\n" ESC_STR "[K"); + fterm_raws("\n" ESC_STR "[K"); #endif - } else { - fterm_raws(ESC_STR "M"); // ESC_STR "[K"); - } - } - - // Do not use optimized move here, because in poor terminals - // the coordinates are already out of sync. - fterm_rawcmd2(ft.ry+1, ft.rx+1, 1, 'H'); - ft.scroll -= dy; + } else { + fterm_raws(ESC_STR "M"); // ESC_STR "[K"); + } + } + + // Do not use optimized move here, because in poor terminals + // the coordinates are already out of sync. + fterm_rawcmd2(ft.ry+1, ft.rx+1, 1, 'H'); + ft.scroll -= dy; #endif } -void +void fterm_raws(const char *s) { - while (*s) - fterm_rawc(*s++); + while (*s) + fterm_rawc(*s++); } -void +void fterm_rawnc(int c, int n) { - while (n-- > 0) - fterm_rawc(c); + while (n-- > 0) + fterm_rawc(c); } ////////////////////////////////////////////////////////////////////////// // grayout advanced control ////////////////////////////////////////////////////////////////////////// -void +void grayout(int y, int end, int level) { - char grattr = FTATTR_DEFAULT; - - y = ranged(y, 0, ft.rows-1); - end = ranged(end, 0, ft.rows-1); - - if (level == GRAYOUT_COLORBOLD) - { - int x = 0; - for (; y < end; y++) - { - for (x = 0; x < ft.cols-1; x++) - FTAMAP[y][x] |= FTATTR_BOLD; - } - return; - } - - if (level == GRAYOUT_COLORNORM) - { - int x = 0; - for (; y < end; y++) - { - for (x = 0; x < ft.cols-1; x++) - FTAMAP[y][x] &= ~(FTATTR_BLINK | FTATTR_BOLD); - } - return; - } - - if (level == GRAYOUT_BOLD) - { - grattr |= FTATTR_BOLD; - } - else if (level == GRAYOUT_DARK) - { - grattr = FTATTR_MAKE(0,0); - grattr |= FTATTR_BOLD; - } - else if (level == GRAYOUT_NORM) - { - // normal text - } - else - { - // not supported yet - } - - for (; y <= end; y++) - { - memset(FTAMAP[y], grattr, ft.cols); - } + char grattr = FTATTR_DEFAULT; + + y = ranged(y, 0, ft.rows-1); + end = ranged(end, 0, ft.rows-1); + + if (level == GRAYOUT_COLORBOLD) + { + int x = 0; + for (; y < end; y++) + { + for (x = 0; x < ft.cols-1; x++) + FTAMAP[y][x] |= FTATTR_BOLD; + } + return; + } + + if (level == GRAYOUT_COLORNORM) + { + int x = 0; + for (; y < end; y++) + { + for (x = 0; x < ft.cols-1; x++) + FTAMAP[y][x] &= ~(FTATTR_BLINK | FTATTR_BOLD); + } + return; + } + + if (level == GRAYOUT_BOLD) + { + grattr |= FTATTR_BOLD; + } + else if (level == GRAYOUT_DARK) + { + grattr = FTATTR_MAKE(0,0); + grattr |= FTATTR_BOLD; + } + else if (level == GRAYOUT_NORM) + { + // normal text + } + else + { + // not supported yet + } + + for (; y <= end; y++) + { + memset(FTAMAP[y], grattr, ft.cols); + } } ////////////////////////////////////////////////////////////////////////// @@ -2234,7 +2234,7 @@ grayout(int y, int end, int level) void standout(void) { - outs(ANSI_COLOR(7)); + outs(ANSI_COLOR(7)); } void @@ -2248,96 +2248,96 @@ standend(void) void scr_dump(screen_backup_t *psb) { - int y = 0; - char *p = NULL; + int y = 0; + char *p = NULL; - psb->row= ft.rows; - psb->col= ft.cols; - psb->y = ft.y; - psb->x = ft.x; - p = psb->raw_memory = - malloc (ft.rows * ft.cols * (sizeof(ftchar) + sizeof(ftattr))); + psb->row= ft.rows; + psb->col= ft.cols; + psb->y = ft.y; + psb->x = ft.x; + p = psb->raw_memory = + malloc (ft.rows * ft.cols * (sizeof(ftchar) + sizeof(ftattr))); - for (y = 0; y < ft.rows; y++) - { - memcpy(p, FTCMAP[y], ft.cols * sizeof(ftchar)); - p += ft.cols * sizeof(ftchar); - memcpy(p, FTAMAP[y], ft.cols * sizeof(ftattr)); - p += ft.cols * sizeof(ftattr); - } + for (y = 0; y < ft.rows; y++) + { + memcpy(p, FTCMAP[y], ft.cols * sizeof(ftchar)); + p += ft.cols * sizeof(ftchar); + memcpy(p, FTAMAP[y], ft.cols * sizeof(ftattr)); + p += ft.cols * sizeof(ftattr); + } } void scr_restore(const screen_backup_t *psb) { - int y = 0; - char *p = NULL; - int c = ft.cols, r = ft.rows; - if (!psb || !psb->raw_memory) - return; + int y = 0; + char *p = NULL; + int c = ft.cols, r = ft.rows; + if (!psb || !psb->raw_memory) + return; - p = psb->raw_memory; - c = ranged(c, 0, psb->col); - r = ranged(r, 0, psb->row); + p = psb->raw_memory; + c = ranged(c, 0, psb->col); + r = ranged(r, 0, psb->row); - ft.y = ranged(psb->y, 0, ft.rows-1); - ft.x = ranged(psb->x, 0, ft.cols-1); - clrscr(); + ft.y = ranged(psb->y, 0, ft.rows-1); + ft.x = ranged(psb->x, 0, ft.cols-1); + clrscr(); - for (y = 0; y < r; y++) - { - memcpy(FTCMAP[y], p, c * sizeof(ftchar)); - p += psb->col * sizeof(ftchar); - memcpy(FTAMAP[y], p, c * sizeof(ftattr)); - p += psb->col * sizeof(ftattr); - } + for (y = 0; y < r; y++) + { + memcpy(FTCMAP[y], p, c * sizeof(ftchar)); + p += psb->col * sizeof(ftchar); + memcpy(FTAMAP[y], p, c * sizeof(ftattr)); + p += psb->col * sizeof(ftattr); + } - free(psb->raw_memory); - ft.dirty = 1; - refresh(); + free(psb->raw_memory); + ft.dirty = 1; + refresh(); } void move_ansi(int y, int x) { - move(y, x); + move(y, x); } void getyx_ansi(int *y, int *x) { - getyx(y, x); + getyx(y, x); } void region_scroll_up(int top, int bottom) { - int i; - ftchar *c0; - ftattr *a0; + int i; + ftchar *c0; + ftattr *a0; - // logic same with old screen.c - if (top > bottom) { - i = top; - top = bottom; - bottom = i; - } + // logic same with old screen.c + if (top > bottom) { + i = top; + top = bottom; + bottom = i; + } if (top < 0 || bottom >= ft.rows) - return; + return; - c0 = FTCMAP[top]; - a0 = FTAMAP[top]; + c0 = FTCMAP[top]; + a0 = FTAMAP[top]; - for (i = top; i < bottom; i++) - { - FTCMAP[i] = FTCMAP[i+1]; - FTAMAP[i] = FTAMAP[i+1]; - } - FTCMAP[bottom] = c0; - FTAMAP[bottom] = a0; + for (i = top; i < bottom; i++) + { + FTCMAP[i] = FTCMAP[i+1]; + FTAMAP[i] = FTAMAP[i+1]; + } + FTCMAP[bottom] = c0; + FTAMAP[bottom] = a0; - clrregion(bottom, bottom); - fterm_markdirty(); + clrregion(bottom, bottom); + fterm_markdirty(); } #endif @@ -2346,24 +2346,24 @@ region_scroll_up(int top, int bottom) // adapter ////////////////////////////////////////////////////////////////////////// -int +int fterm_inbuf(void) { #ifdef _PFTERM_TEST_MAIN - return 0; + return 0; #else - return num_in_buf(); + return num_in_buf(); #endif } -void +void fterm_rawc(int c) { #ifdef _PFTERM_TEST_MAIN - // if (c == ESC_CHR) putchar('*'); else - putchar(c); + // if (c == ESC_CHR) putchar('*'); else + putchar(c); #else - ochar(c); + ochar(c); #endif } @@ -2371,10 +2371,10 @@ void fterm_rawnewline(void) { #ifdef _PFTERM_TEST_MAIN - putchar('\n'); + putchar('\n'); #else - ochar('\r'); - ochar('\n'); + ochar('\r'); + ochar('\n'); #endif } @@ -2382,9 +2382,9 @@ void fterm_rawflush(void) { #ifdef _PFTERM_TEST_MAIN - fflush(stdout); + fflush(stdout); #else - oflush(); + oflush(); #endif } @@ -2395,108 +2395,108 @@ fterm_rawflush(void) #ifdef _PFTERM_TEST_MAIN int main(int argc, char* argv[]) { - char buf[512]; - initscr(); + char buf[512]; + initscr(); - if (argc < 2) - { + if (argc < 2) + { #if 0 - // DBCS test - char *a1 = ANSI_COLOR(1;33) "代刚" ANSI_COLOR(34) "いゅ" - ANSI_COLOR(7) "代刚" ANSI_RESET "代刚" - "代刚a" ANSI_RESET "\n"; - outstr(a1); - move(0, 2); - outstr("いゅ1"); - outstr(ANSI_COLOR(1;33)"いゅ2"); - outstr(" い\x85"); - outstr("okok herer\x8a"); - - move(0, 8); - inansistr(buf, sizeof(buf)-1); - - move(3,5); outs(ANSI_RESET "(From inansistr:) "); outs(buf); - move(7, 3); - sprintf(buf, "strlen()=%d\n", fterm_strdlen(a1)); - outstr(buf); - refresh(); - getchar(); - - outs(ANSI_COLOR(1;33) "test " ANSI_COLOR(34) "x" - ANSI_RESET "te" ANSI_COLOR(43;0;1;35) " st" - ANSI_COLOR(0) "testx\n"); - refresh(); - getchar(); - - clear(); - outs("いゅいゅいゅいゅいゅいゅいゅいゅいゅいゅいゅいゅ"); - move(0, 0); - outs(" this\xFF (ff)is te.(80 tail)->\x80 (80)"); - refresh(); - getchar(); + // DBCS test + char *a1 = ANSI_COLOR(1;33) "代刚" ANSI_COLOR(34) "いゅ" + ANSI_COLOR(7) "代刚" ANSI_RESET "代刚" + "代刚a" ANSI_RESET "\n"; + outstr(a1); + move(0, 2); + outstr("いゅ1"); + outstr(ANSI_COLOR(1;33)"いゅ2"); + outstr(" い\x85"); + outstr("okok herer\x8a"); + + move(0, 8); + inansistr(buf, sizeof(buf)-1); + + move(3,5); outs(ANSI_RESET "(From inansistr:) "); outs(buf); + move(7, 3); + sprintf(buf, "strlen()=%d\n", fterm_strdlen(a1)); + outstr(buf); + refresh(); + getchar(); + + outs(ANSI_COLOR(1;33) "test " ANSI_COLOR(34) "x" + ANSI_RESET "te" ANSI_COLOR(43;0;1;35) " st" + ANSI_COLOR(0) "testx\n"); + refresh(); + getchar(); + + clear(); + outs("いゅいゅいゅいゅいゅいゅいゅいゅいゅいゅいゅいゅ"); + move(0, 0); + outs(" this\xFF (ff)is te.(80 tail)->\x80 (80)"); + refresh(); + getchar(); #endif #if 1 - // test resize - clear(); move(1, 0); outs("test resize\n"); - doupdate(); getchar(); - // expand X - resizeterm(25,200); - clear(); move(20, 0); clrtoeol(); outs("200x25"); - doupdate(); getchar(); - // resize back - resizeterm(25,80); - clear(); move(20, 0); clrtoeol(); outs("80x25"); - doupdate(); getchar(); - // expand Y - resizeterm(60,80); - clear(); move(20, 0); clrtoeol(); outs("80x60"); - doupdate(); getchar(); - // see if you crash here. - resizeterm(60,200); - clear(); move(20, 0); clrtoeol(); outs("200x60"); - doupdate(); getchar(); + // test resize + clear(); move(1, 0); outs("test resize\n"); + doupdate(); getchar(); + // expand X + resizeterm(25,200); + clear(); move(20, 0); clrtoeol(); outs("200x25"); + doupdate(); getchar(); + // resize back + resizeterm(25,80); + clear(); move(20, 0); clrtoeol(); outs("80x25"); + doupdate(); getchar(); + // expand Y + resizeterm(60,80); + clear(); move(20, 0); clrtoeol(); outs("80x60"); + doupdate(); getchar(); + // see if you crash here. + resizeterm(60,200); + clear(); move(20, 0); clrtoeol(); outs("200x60"); + doupdate(); getchar(); #endif #if 0 - // test optimization - clear(); - move(1, 0); - outs("x++ optimization test\n"); - outs("1 2 3 4 5 6 7 8 9 0\n"); - outs("1122233334444455555566666667777777788888888899999999990\n"); - refresh(); - getchar(); - - move(2, 0); - outs("1122233334444455555566666667777777788888888899999999990\n"); - outs("1 2 3 4 5 6 7 8 9 0\n"); - refresh(); - getchar(); - - rscroll(); - refresh(); - getchar(); + // test optimization + clear(); + move(1, 0); + outs("x++ optimization test\n"); + outs("1 2 3 4 5 6 7 8 9 0\n"); + outs("1122233334444455555566666667777777788888888899999999990\n"); + refresh(); + getchar(); + + move(2, 0); + outs("1122233334444455555566666667777777788888888899999999990\n"); + outs("1 2 3 4 5 6 7 8 9 0\n"); + refresh(); + getchar(); + + rscroll(); + refresh(); + getchar(); #endif - } else { - FILE *fp = fopen(argv[1], "r"); - int c = 0; - - while (fp && (c=getc(fp)) > 0) - { - outc(c); - } - fclose(fp); - refresh(); - } - - endwin(); - printf("\ncomplete. enter to exit.\n"); - getchar(); - return 0; + } else { + FILE *fp = fopen(argv[1], "r"); + int c = 0; + + while (fp && (c=getc(fp)) > 0) + { + outc(c); + } + fclose(fp); + refresh(); + } + + endwin(); + printf("\ncomplete. enter to exit.\n"); + getchar(); + return 0; } #endif // _PFTERM_TEST_MAIN #endif // defined(EXP_PFTERM) || defined(USE_PFTERM) -// vim:ts=4:sw=4 +// vim:ts=4:sw=4:expandtab |