/* vi:ts=4:sw=4
*
* VIM - Vi IMproved
*
* Code Contributions By: Bram Moolenaar mool@oce.nl
* Tim Thompson twitch!tjt
* Tony Andrews onecom!wldrdg!tony
* G. R. (Fred) Walter watmath!watcgl!grwalter
*/
/*
* screen.c: code for displaying on the screen
*/
#include "vim.h"
#include "globals.h"
#include "proto.h"
#include "param.h"
#ifdef JP
#include "jp.h"
#endif
#ifdef JP
static int kanji;
static char kcode = NUL, *kin = NULL, *kout = NULL;
#endif
#ifdef JPFEP
static int uline;
#endif
/*
Macros handling inverted lines
*/
#define ScreenAttr(screenp) ((screenp) - Nextscreen + Nextattrib)
#define ScreenSetAttr(x) (*x = 0x0)
#define ScreenClrAttr(x) (*x = 0x0)
#define AM_None 0x00
#define AM_Inv 0x02
#ifdef JPFEP
# define AM_UL 0x04
#endif /* JPFEP */
#ifdef JP
# define AM_K1 0x01
#endif /* JP */
/*
* Switch Attribute
*/
#ifdef JP
# define KANJI_ON {if (!kanji) { if (kin ) outstr(kin ); kanji = TRUE; }}
# define KANJI_OFF {if ( kanji) { if (kout) outstr(kout); kanji = FALSE; }}
#endif
#ifdef JPFEP
# define ULINE_ON {if (!uline) { KANJI_OFF outstr(T_US); uline = TRUE; }}
# define ULINE_OFF {if ( uline) { KANJI_OFF outstr(T_UE); uline = FALSE; }}
#endif
#ifdef JP
# define INVERT_ON {if (!invert) { KANJI_OFF outstr(T_TI); invert = TRUE; }}
# define INVERT_OFF {if ( invert) { KANJI_OFF outstr(T_TP); invert = FALSE; }}
#else
# define INVERT_ON {if (!invert) { outstr(T_TI); invert = TRUE; }}
# define INVERT_OFF {if ( invert) { outstr(T_TP); invert = FALSE; }}
#endif
char *tgoto __PARMS((char *cm, int col, int line));
char *getvptr __PARMS((char *ptr, int vcol));
colnr_t vcol2col __PARMS((linenr_t lnum, int vcol));
static u_char *Nextscreen = NULL; /* What's to be put on the screen. */
static u_char *Nextattrib = NULL; /* Attributes for Nextscreen. */
static int NumLineSizes = 0; /* # of active LineSizes */
static linenr_t *LineNumbers = NULL; /* Pointer to the line for LineSizes */
static u_char *LineSizes = NULL; /* Number of rows the lines occupy */
static u_char **LinePointers = NULL; /* array of pointers into Netscreen */
/*
* The following variable is set (in cursupdate) to the number of physical
* lines taken by the line the cursor is on. We use this to avoid extra calls
* to plines(). The optimized routine updateline()
* makes sure that the size of the cursor line hasn't changed. If so, lines
* below the cursor will move up or down and we need to call the routine
* updateScreen() to examine the entire screen.
*/
static int Cline_size; /* size (in rows) of the cursor line */
static int Cline_row; /* starting row of the cursor line */
static int Leftcol = 0; /* starting column of the screen */
static FPOS oldCurpos = {0, 0}; /* last known end of visual part */
static int oldCurswant = 0; /* last known value of Curswant */
static int canopt; /* TRUE when cursor goto can be optimized */
static int screenline __ARGS((linenr_t, int, int));
static void screenchar __ARGS((u_char *, int, int));
static void screenfill __ARGS((int, int));
static void screenalloc __ARGS((int));
static void screenclear2 __ARGS((void));
/*
* updateline() - like updateScreen() but only for cursor line
*
* This determines whether or not we need to call updateScreen() to examine
* the entire screen for changes. This occurs if the size of the cursor line
* (in rows) hasn't changed.
*/
void
updateline()
{
int row;
int n;
if (must_redraw) /* must redraw whole screen */
{
updateScreen(VALID);
return;
}
screenalloc(TRUE); /* allocate screen buffers if size changed */
if (Nextscreen == NULL || RedrawingDisabled)
return;
screenchar(NULL, 0, 0); /* init cursor position of screenchar() */
cursor_off();
row = screenline(Curpos.lnum, Cline_row, (int)Rows - 1);
cursor_on();
if (row == Rows) /* line too long for screen */
updateScreen(VALID_TO_CURSCHAR);
else
{
n = row - Cline_row;
if (n != Cline_size) /* line changed size */
{
if (n < Cline_size) /* got smaller: delete lines */
s_del(row, Cline_size - n, FALSE);
else /* got bigger: insert lines */
s_ins(Cline_row + Cline_size, n - Cline_size, FALSE);
updateScreen(VALID_TO_CURSCHAR);
}
}
}
/*
* updateScreen()
*
* Based on the current value of Topline, transfer a screenfull of stuff from
* Filemem to Nextscreen, and update Botline.
*/
void
updateScreen(type)
int type;
{
register int row;
register int endrow;
linenr_t lnum;
linenr_t lastline = 0; /* only valid if endrow != Rows -1 */
int done; /* if TRUE, we hit the end of the file */
int didline; /* if TRUE, we finished the last line */
int srow = 0; /* starting row of the current line */
int idx;
int i;
long j;
static int postponed_not_valid = FALSE;
register u_char *screenp;
register u_char *attribp;
#ifdef JP
/*
* Prepare kanji-shift-in / out character sequence
*/
if (kcode != JP_DISP)
{
kin = kanjiin(kcode = JP_DISP);
kout= kanjiout(kcode);
}
#endif
screen_msg(FALSE, NULL);
screenalloc(TRUE); /* allocate screen buffers if size changed */
if (Nextscreen == NULL)
return;
cmdoffset = 0; /* after redraw command line has no offset */
if (must_redraw)
{
type = must_redraw;
must_redraw = 0;
}
if (type == CLEAR) /* first clear screen */
{
screenclear();
type = NOT_VALID;
}
if (type == CURSUPD) /* update cursor and then redraw */
{
NumLineSizes = 0;
cursupdate(); /* will call updateScreen(VALID) */
return;
}
if (NumLineSizes == 0)
type = NOT_VALID;
if (RedrawingDisabled)
{
if (type == NOT_VALID)
postponed_not_valid = TRUE; /* use NOT_VALID next time */
return;
}
if (postponed_not_valid)
{
type = NOT_VALID;
postponed_not_valid = FALSE;
}
/* return if there is nothing to do */
if ((type == VALID && Topline == LineNumbers[0]) ||
(type == INVERTED && oldCurpos.lnum == Curpos.lnum &&
oldCurpos.col == Curpos.col && Curswant == oldCurswant))
return;
if (type == NOT_VALID)
{
redraw_msg = TRUE;
NumLineSizes = 0;
}
idx = 0;
row = 0;
lnum = Topline;
cursor_off();
/* The number of rows shown is Rows-1. */
/* The default last row is the status/command line. */
endrow = Rows - 1;
if (type == VALID || type == VALID_TO_CURSCHAR)
{
/*
* We handle two special cases:
* 1: we are off the top of the screen by a few lines: scroll down
* 2: Topline is below LineNumbers[0]: may scroll up
*/
if (Topline < LineNumbers[0]) /* may scroll down */
{
j = LineNumbers[0] - Topline;
if (j < Rows - 3) /* not too far off */
{
lastline = LineNumbers[0] - 1;
i = plines_m(Topline, lastline);
if (i < Rows - 3) /* less than a screen off */
{
/*
* Try to insert the correct number of lines.
* This may fail and the screen may have been cleared.
*/
if (s_ins(0, i, FALSE) && NumLineSizes)
{
endrow = i;
if ((NumLineSizes += j) > Rows - 1)
NumLineSizes = Rows - 1;
for (idx = NumLineSizes; idx - j >= 0; idx--)
{
LineNumbers[idx] = LineNumbers[idx - j];
LineSizes[idx] = LineSizes[idx - j];
}
idx = 0;
}
}
else /* far off: clearing the screen is faster */
screenclear();
}
else /* far off: clearing the screen is faster */
screenclear();
}
else /* may scroll up */
{
j = -1;
for (i = 0; i < NumLineSizes; i++) /* try to find Topline in LineNumbers[] */
{
if (LineNumbers[i] == Topline)
{
j = i;
break;
}
row += LineSizes[i];
}
if (j == -1) /* Topline is not in LineNumbers */
{
row = 0;
screenclear(); /* far off: clearing the screen is faster */
}
else
{
/*
* Try to delete the correct number of lines.
* Topline is at LineNumbers[i].
*/
if ((row == 0 || s_del(0, row, FALSE)) && NumLineSizes)
{
srow = row;
row = 0;
for (;;)
{
if (type == VALID_TO_CURSCHAR && lnum == Curpos.lnum)
break;
if (row + srow + (int)LineSizes[j] >= Rows - 1)
break;
LineSizes[idx] = LineSizes[j];
LineNumbers[idx] = lnum++;
row += LineSizes[idx++];
if ((int)++j >= NumLineSizes)
break;
}
NumLineSizes = idx;
}
else
row = 0; /* update all lines */
}
}
if (endrow == Rows - 1 && idx == 0) /* no scrolling */
NumLineSizes = 0;
}
done = didline = FALSE;
screenchar(NULL, 0, 0); /* init cursor position of screenchar() */
if (Visual.lnum) /* check if we are updating the inverted part */
{
linenr_t from, to;
/* find the line numbers that need to be updated */
if (Curpos.lnum < oldCurpos.lnum)
{
from = Curpos.lnum;
to = oldCurpos.lnum;
}
else
{
from = oldCurpos.lnum;
to = Curpos.lnum;
}
/* if in block mode and changed column or Curswant: update all lines */
#ifdef JP
if (Visual_block)
#else
if (Visual_block && (Curpos.col != oldCurpos.col || Curswant != oldCurswant))
#endif
{
if (from > Visual.lnum)
from = Visual.lnum;
if (to < Visual.lnum)
to = Visual.lnum;
}
if (from < Topline)
from = Topline;
if (to >= Botline)
to = Botline - 1;
/* find the minimal part to be updated */
if (type == INVERTED)
{
while (lnum < from) /* find start */
{
row += LineSizes[idx++];
++lnum;
}
srow = row;
for (j = idx; j < NumLineSizes; ++j) /* find end */
{
if (LineNumbers[j] == to + 1)
{
endrow = srow;
break;
}
srow += LineSizes[j];
}
oldCurpos = Curpos;
oldCurswant = Curswant;
}
/* if we update the lines between from and to set oldCurpos */
else if (lnum <= from && (endrow == Rows - 1 || lastline >= to))
{
oldCurpos = Curpos;
oldCurswant = Curswant;
}
}
/*
* Update the screen rows from "row" to "endrow".
* Start at line "lnum" which is at LineNumbers[idx].
*/
for (;;)
{
if (lnum > line_count) /* hit the end of the file */
{
done = TRUE;
break;
}
srow = row;
row = screenline(lnum, srow, endrow);
if (row > endrow) /* past end of screen */
{
LineSizes[idx] = plines(lnum); /* we may need the size of that */
LineNumbers[idx++] = lnum; /* too long line later on */
break;
}
LineSizes[idx] = row - srow;
LineNumbers[idx++] = lnum;
if (++lnum > line_count)
{
done = TRUE;
break;
}
if (row == endrow)
{
didline = TRUE;
break;
}
}
if (idx > NumLineSizes)
NumLineSizes = idx;
/* Do we have to do off the top of the screen processing ? */
if (endrow != Rows - 1)
{
row = 0;
for (idx = 0; idx < NumLineSizes && row < (Rows - 1); idx++)
row += LineSizes[idx];
if (row < (Rows - 1))
{
done = TRUE;
}
else if (row > (Rows - 1)) /* Need to blank out the last line */
{
lnum = LineNumbers[idx - 1];
srow = row - LineSizes[idx - 1];
didline = FALSE;
}
else
{
lnum = LineNumbers[idx - 1] + 1;
didline = TRUE;
}
}
emptyrows = 0;
/*
* If we didn't hit the end of the file, and we didn't finish the last
* line we were working on, then the line didn't fit.
*/
if (!done && !didline)
{
if (lnum == Topline)
{
/*
* Single line that does not fit!
* Fill last line with '@' characters.
*/
screenp = LinePointers[Rows - 2];
attribp = ScreenAttr(screenp);
for (i = 0; i < Columns; ++i)
{
if (*screenp != '@' || *attribp)
{
*screenp = '@';
*attribp = AM_None;
screenchar(screenp, (int)(Rows - 2), i);
}
++screenp;
++attribp;
}
Botline = lnum + 1;
}
else
{
/*
* Clear the rest of the screen and mark the unused lines.
*/
screenfill(srow, '@');
Botline = lnum;
}
}
else
{
/* make sure the rest of the screen is blank */
/* put '~'s on rows that aren't part of the file. */
screenfill(row, '~');
emptyrows = Rows - row - 1;
if (done) /* we hit the end of the file */
Botline = line_count + 1;
else
Botline = lnum;
}
if (redraw_msg)
{
showmode();
redraw_msg = FALSE;
}
cursor_on();
}
static int invert; /* shared by screenline() and screenchar() */
/*
* Move line "lnum" to the screen.
* Start at row "startrow", stop when "endrow" is reached.
* Return the number of last row the line occupies.
*/
static int
screenline(lnum, startrow, endrow)
linenr_t lnum;
int startrow;
int endrow;
{
register u_char *screenp;
register u_char *attribp;
register u_char c;
register int col; /* visual column on screen */
register int vcol; /* visual column for tabs */
register int row;
register u_char *ptr;
char extra[16]; /* "%ld" must fit in here */
char *p_extra;
int n_extra;
int n_spaces = 0;
int fromcol, tocol; /* start/end of inverting */
#ifdef JPFEP
int kufrom, kuto; /* start/end of underilne for KANAKAN */
int krfrom, krto; /* start/end of inverting for KANAKAN */
#endif
int noinvcur = FALSE; /* don't invert the cursor */
int temp;
FPOS *top, *bot;
row = startrow;
col = 0;
vcol = 0;
invert = FALSE;
fromcol = -10;
tocol = MAXCOL;
#ifdef JPFEP
uline = FALSE;
#endif
ptr = (u_char *)nr2ptr(lnum);
canopt = TRUE;
if (Visual.lnum) /* visual active */
{
if (ltoreq(Curpos, Visual)) /* Visual is after Curpos */
{
top = &Curpos;
bot = &Visual;
}
else /* Visual is before Curpos */
{
top = &Visual;
bot = &Curpos;
}
if (Visual_block) /* block mode */
{
if (lnum >= top->lnum && lnum <= bot->lnum)
{
FPOS tpos;
fromcol = getvcol(top, 2);
temp = getvcol(bot, 2);
if (temp < fromcol)
fromcol = temp;
#ifdef JP
/* adjust for multibyte char. */
tpos.lnum = lnum;
tpos.col = vcol2col(lnum, fromcol);
if (*pos2ptr(&tpos) != '\t')
fromcol = getvcol(&tpos, 2);
#endif
if (Curswant != MAXCOL)
{
tocol = getvcol(top, 3);
temp = getvcol(bot, 3);
if (temp > tocol)
tocol = temp;
#ifdef JP
/* adjust for multibyte char. */
tpos.col = vcol2col(lnum, tocol);
if (*pos2ptr(&tpos) != '\t')
tocol = getvcol(&tpos, 3);
#endif
++tocol;
}
}
}
else /* non-block mode */
{
if (lnum > top->lnum && lnum <= bot->lnum)
fromcol = 0;
else if (lnum == top->lnum)
fromcol = getvcol(top, 2);
if (lnum == bot->lnum)
tocol = getvcol(bot, 3) + 1;
if (Visual.col == VISUALLINE) /* linewise */
{
if (fromcol > 0)
fromcol = 0;
tocol = VISUALLINE;
}
}
/* if the cursor can't be switched off, don't invert the character
where the cursor is */
if ((T_CI == NULL || *T_CI == NUL) && lnum == Curpos.lnum)
noinvcur = TRUE;
/* if inverting in this line, can't optimize cursor positioning */
if (fromcol >= 0)
canopt = FALSE;
}
if (!p_wrap) /* advance to first character to be displayed */
{
while (vcol < Leftcol && *ptr)
#ifdef JP
if (IsKanji(*ptr))
{
vcol += 2;
ptr += 2;
}
else
#endif
vcol += chartabsize(*ptr++, vcol);
if (vcol > Leftcol)
{
n_spaces = vcol - Leftcol; /* begin with some spaces */
vcol = Leftcol;
}
}
#ifdef JPFEP
if (Kconvlnum == lnum)
{
FPOS tmp;
tmp.lnum = lnum;
tmp.col = KconvAltStart; krfrom = getvcol(&tmp, 2);
tmp.col = KconvAltEnd; krto = getvcol(&tmp, 2);
tmp.col = KconvStart; kufrom = getvcol(&tmp, 2);
tmp.col = KconvEnd; kuto = getvcol(&tmp, 2);
canopt = FALSE;
}
else
krfrom = kufrom = krto = kuto = -10;
#endif /* JPFEP */
screenp = LinePointers[row];
attribp = ScreenAttr(screenp);
if (p_nu)
{
sprintf(extra, "%7ld ", (long)lnum);
p_extra = extra;
n_extra = 8;
vcol -= 8; /* so vcol is 0 when line number has been printed */
}
else
{
p_extra = NULL;
n_extra = 0;
}
#ifdef JP
kanji = FALSE;
#endif
for (;;)
{
if (!canopt) /* Visual in this line */
{
if (((vcol == fromcol && !(noinvcur && vcol == Cursvcol)) ||
(noinvcur && vcol >= fromcol &&
#ifdef JP
(vcol == Cursvcol + 1 || vcol == Cursvcol + 2)
#else
vcol == Cursvcol + 1
#endif
)) && vcol < tocol)
INVERT_ON /* start inverting */
else if (invert && (
#ifdef JP
(vcol == tocol || vcol == tocol + 1)
#else
vcol == tocol
#endif
|| (noinvcur && vcol == Cursvcol)))
INVERT_OFF /* stop inverting */
#ifdef JPFEP
if (fromcol < 0)
{
/* invert for KANAKAN */
if (!invert)
{
if (((vcol == krfrom && !(noinvcur && vcol == Cursvcol)) ||
(noinvcur && vcol == Cursvcol + 1 && vcol >= krfrom)) &&
vcol < krto) /* start inverting */
INVERT_ON
}
else if (vcol == krto || (noinvcur && vcol == Cursvcol))
{ /* stop inverting */
int ul;
if ((ul = uline)) ULINE_OFF
INVERT_OFF
if (ul) ULINE_ON
}
/* underline for KANAKAN */
if (!uline)
{
if (vcol == kufrom && vcol < kuto) /* start underline */
ULINE_ON
}
else if (vcol == kuto)
{
int inv;
if ((inv = invert)) INVERT_OFF;
ULINE_OFF /* stop underline */
if (inv) INVERT_ON;
}
}
#endif
}
/* Get the next character to put on the screen. */
/*
* The 'extra' array contains the extra stuff that is inserted to
* represent special characters (non-printable stuff).
*/
if (n_extra)
{
c = (u_char)*p_extra++;
n_extra--;
}
else if (n_spaces)
{
c = ' ';
n_spaces--;
}
else
{
if ((c = *ptr++) < ' ' || (c > '~' && c <= 0xa0))
{
/*
* when getting a character from the file, we may have to turn it
* into something else on the way to putting it into 'Nextscreen'.
*/
if (c == TAB && !p_list)
{
/* tab amount depends on current column */
n_spaces = (int)p_ts - col % (int)p_ts - 1;
c = ' ';
}
else if (c == NUL && p_list)
{
p_extra = "";
n_extra = 1;
c = '$';
}
else if (c != NUL)
{
p_extra = (char *)transchar(c);
n_extra = charsize(c) - 1;
c = (u_char)*p_extra++;
}
}
}
if (c == NUL)
{
#ifdef UNIX
int ler; /* Line Erased */
ler= FALSE;
#endif
if (invert)
{
if (vcol == 0) /* invert first char of empty line */
{
if (*screenp != ' ' || !(*attribp & AM_Inv))
{
*screenp = ' ';
*attribp = AM_Inv;
screenchar(screenp, row, col);
}
++screenp;
++attribp;
++col;
}
outstr(T_TP);
invert = FALSE;
}
/*
* could also use clear-to-end-of-line, but it is slower
* on an Amiga
*/
while (col < Columns)
{
if (*screenp != ' ' || *attribp)
{
*screenp = ' ';
*attribp = AM_None;
#ifdef UNIX
if (!ler)
{
ler = TRUE;
windgoto(row, col);
clear_line();
}
#else
screenchar(screenp, row, col);
#endif
}
screenp++;
attribp++;
col++;
}
row++;
#ifdef JP
KANJI_OFF
#endif /* JP */
break;
}
#ifdef JP
if (col >= (IsKanji(c) ? Columns - 1 : Columns)) /* continuous line */
{
int inv;
#ifdef JPFEP
int ul;
#endif
KANJI_OFF
inv = invert;
INVERT_OFF
#ifdef JPFEP
ul = uline;
ULINE_OFF
#endif
if (col == Columns - 1 && (*screenp != '\\' || *attribp != AM_None))
{
*screenp = '\\';
*attribp = AM_None;
screenchar(screenp, row, col);
}
col = 0;
if (!p_wrap || ++row == endrow) /* line got too long for screen */
{
++row;
break;
}
screenp = LinePointers[row];
attribp = ScreenAttr(screenp);
screen_msg(FALSE, NULL);
if (inv) INVERT_ON
#ifdef JPFEP
if (ul) ULINE_ON
#endif
}
#else /* JP */
if (col >= Columns)
{
col = 0;
if (!p_wrap || ++row == endrow) /* line got too long for screen */
{
++row;
break;
}
screenp = LinePointers[row];
attribp = ScreenAttr(screenp);
screen_msg(FALSE, NULL);
}
#endif /* JP */
/* store the character in Nextscreen */
#ifdef JP
if (IsKanji(c) && kcode != JP_NONE)
{ u_char c1, c2;
int attr;
c1 = c;
c2 = *ptr++;
attr = *attribp;
if (*screenp != c1 || *(screenp + 1) != c2
|| !(attr & AM_K1)
|| (invert ? !(attr & AM_Inv) : (attr & AM_Inv))
#ifdef JPFEP
|| (uline ? !(attr & AM_UL) : (attr & AM_UL))
#endif
)
{
if (invert)
{
*attribp++ = AM_Inv | AM_K1;
*attribp++ = AM_Inv;
}
#ifdef JPFEP
else if (uline)
{
*attribp++ = AM_UL | AM_K1;
*attribp++ = AM_UL;
}
#endif
else
{
*attribp++ = AM_K1;
*attribp++ = AM_None;
}
*screenp++ = c1;
*screenp++ = c2;
screenchar(screenp - 2, row, col);
col += 2;
vcol += 2;
}
else
{
attribp += 2;
screenp += 2;
vcol += 2;
col += 2;
}
}
else
#endif /* JP */
{
int attr;
attr = *attribp;
if (*screenp != c
|| (invert ? !(attr & AM_Inv) : (attr & AM_Inv))
#ifdef JPFEP
|| (uline ? !(attr & AM_UL) : (attr & AM_UL))
#endif
)
{
*screenp = c;
if (invert) *attribp = AM_Inv;
#ifdef JPFEP
else if (uline) *attribp = AM_UL;
#endif
else *attribp = AM_None;
screenchar(screenp, row, col);
}
screenp ++;
attribp ++;
vcol ++;
col ++;
}
}
#ifdef JP
KANJI_OFF
#endif
#ifdef JPFEP
ULINE_OFF
#endif
INVERT_OFF
return (row);
}
/*
* put character '*p' on the screen at position 'row' and 'col'
*/
static void
screenchar(p, row, col)
u_char *p;
int row;
int col;
{
static int oldrow, oldcol; /* old cursor position */
if (p == NULL) /* initialize cursor position */
{
oldrow = oldcol = -1;
return;
}
if (oldcol != col || oldrow != row)
{
/*
* If we're on the same row (which happens a lot!), try to
* avoid a windgoto().
* If we are only a few characters off, output the
* characters. That is faster than cursor positioning.
* This can't be used when inverting (a part of) the line.
*/
if (oldrow == row && oldcol < col)
{
register int i;
i = col - oldcol;
#ifdef JP
if (i <= 10 && canopt)
{
u_char k1, k2;
u_char *ptr;
ptr = p - i;
while(ptr < p)
if (IsKanji(k1 = *(ptr++)))
{
KANJI_ON
k2 = *(ptr++);
kanjito(&k1, &k2, kcode);
outchar(k1);
outchar(k2);
}
else
{
KANJI_OFF
outchar(k1);
}
}
#else /* JP */
if (i <= 4 && canopt)
while (i)
outchar( *(p - i--) );
#endif /* JP */
else
{
#ifdef JP
KANJI_OFF
#endif
if (T_CRI && *T_CRI) /* use tgoto interface! jw */
outstr(tgoto(T_CRI, 0, i));
else
windgoto(row, col);
}
oldcol = col;
}
else
{
#ifdef JP
KANJI_OFF
#endif
windgoto(oldrow = row, oldcol = col);
}
}
#ifdef JP
if (IsKanji(*p))
{
u_char k1, k2;
k1 = *p++;
k2 = *p;
KANJI_ON;
kanjito(&k1, &k2, kcode);
outchar(k1);
outchar(k2);
oldcol++;
}
else
{
KANJI_OFF
outchar(*p);
}
#else
outchar(*p);
#endif
oldcol++;
}
/*
* Fill the screen at 'srow' with character 'c' followed by blanks.
*/
static void
screenfill(srow, c)
int srow;
int c;
{
register int row;
register int col;
register u_char *screenp;
register u_char *attribp;
for (row = srow; row < (Rows - 1); ++row)
{
screenp = LinePointers[row];
attribp = ScreenAttr(screenp);
if (*screenp != c || *attribp)
{
*screenp = c;
*attribp = AM_None;
screenchar(screenp, row, 0);
}
++attribp;
++screenp;
for (col = 1; col < Columns; ++col)
{
if (*screenp != ' ' || *attribp)
{
*screenp = ' ';
*attribp = AM_None;
screenchar(screenp, row, col);
}
++attribp;
++screenp;
}
}
}
/*
* compute Botline. Can be called after Topline or Rows changed.
*/
void
comp_Botline()
{
linenr_t lnum;
int done = 0;
for (lnum = Topline; lnum <= line_count; ++lnum)
{
if ((done += plines(lnum)) >= Rows)
break;
}
Botline = lnum; /* Botline is the line that is just below the window */
}
/*
* prt_line() - print the given line
* returns the number of characters written.
*/
int
prt_line(s)
char *s;
{
register int si = 0;
#ifdef JP
char c, k;
#else
register char c;
#endif
register int col = 0;
int n_extra = 0;
int n_spaces = 0;
char *p = NULL; /* init to make SASC shut up */
int n;
for (;;)
{
if (n_extra)
{
--n_extra;
c = *p++;
}
else if (n_spaces)
{
--n_spaces;
c = ' ';
}
else
{
c = s[si++];
#ifdef JP
if (IsKanji(c))
k = s[si++];
else
#endif
if (c == TAB && !p_list)
{
/* tab amount depends on current column */
n_spaces = p_ts - col % p_ts - 1;
c = ' ';
}
else if (c == NUL && p_list)
{
p = "";
n_extra = 1;
c = '$';
}
else if (c != NUL && (n = charsize(c)) > 1)
{
n_extra = n - 1;
p = transchar(c);
c = *p++;
}
}
if (c == NUL)
break;
#ifdef JP
if (IsKanji(c))
{
if (k == NUL) break;
KANJI_ON
kanjito(&c, &k, kcode);
outchar(c);
outchar(k);
col += 2;
}
else
{
KANJI_OFF
outchar(c);
col++;
}
#else
outchar(c);
col++;
#endif
}
#ifdef JP
KANJI_OFF
#endif
return col;
}
static void
screenalloc(clear)
int clear;
{
static int old_Rows = 0;
static int old_Columns = 0;
register int i;
/*
* Allocation of the sceen buffers is done only when the size changes
*/
if ((Nextscreen != NULL && Rows == old_Rows && Columns == old_Columns) || Rows == 0 || Columns == 0)
return;
comp_col(); /* recompute columns for shown command and ruler */
old_Rows = Rows;
old_Columns = Columns;
/*
* If we're changing the size of the screen, free the old arrays
*/
if (Nextscreen != NULL)
free((char *)Nextscreen);
if (Nextattrib != NULL)
free((char *)Nextattrib);
if (LinePointers != NULL)
free((char *)LinePointers);
if (LineNumbers != NULL)
free((char *) LineNumbers);
if (LineSizes != NULL)
free(LineSizes);
Nextscreen = (u_char *)malloc((size_t) (Rows * Columns));
Nextattrib = (u_char *)malloc((size_t) (Rows * Columns));
LineNumbers = (linenr_t *) malloc((size_t) (Rows * sizeof(linenr_t)));
LineSizes = (u_char *)malloc((size_t) Rows);
LinePointers = (u_char **)malloc(sizeof(u_char *) * Rows);
if (Nextscreen == NULL || Nextattrib == NULL
|| LineNumbers == NULL || LineSizes == NULL || LinePointers == NULL)
{
emsg(e_outofmem);
if (Nextscreen != NULL)
{
free((char *)Nextscreen);
free((char *)Nextattrib);
}
Nextscreen = Nextattrib = NULL;
}
else
{
for (i = 0; i < Rows; ++i)
LinePointers[i] = Nextscreen + i * Columns;
}
if (clear)
screenclear2();
}
void
screenclear()
{
screenalloc(FALSE); /* allocate screen buffers if size changed */
screenclear2();
}
static void
screenclear2()
{
if (starting || Nextscreen == NULL)
return;
outstr(T_ED); /* clear the display */
/* blank out Nextscreen & Nextattrib */
memset((char *)Nextscreen, ' ', (size_t)(Rows * Columns));
memset((char *)Nextattrib, NUL, (size_t)(Rows * Columns));
NumLineSizes = 0; /* clear screen info */
redraw_msg = TRUE; /* refresh cmdline at next screen redraw */
}
void
cursupdate()
{
linenr_t p;
long nlines;
int i;
int temp;
screenalloc(TRUE); /* allocate screen buffers if size changed */
if (Nextscreen == NULL)
return;
if (Curpos.lnum > line_count)
Curpos.lnum = line_count;
if (bufempty()) /* special case - file is empty */
{
Topline = 1;
Curpos.lnum = 1;
Curpos.col = 0;
#ifdef JPFEP
LineSizes[0] = 1;
for (i = 1; i < Rows; i++)
#else
for (i = 0; i < Rows; i++)
#endif
LineSizes[i] = 0;
if (NumLineSizes == 0) /* don't know about screen contents */
updateScreen(NOT_VALID);
NumLineSizes = 1;
}
else if (Curpos.lnum < Topline)
{
/*
* If the cursor is above the top of the screen, scroll the screen to
* put it at the top of the screen.
* If we weren't very close to begin with, we scroll more, so that
* the line is close to the middle.
*/
temp = Rows / 2 - 1;
if (Topline - Curpos.lnum >= temp) /* not very close */
{
p = Curpos.lnum;
i = plines(p);
temp += i;
/* count lines for 1/2 screenheight */
while (i < Rows && i < temp && p > 1)
i += plines(--p);
Topline = p;
if (i >= Rows) /* cursor line won't fit, backup one line */
++Topline;
}
else if (p_sj > 1) /* scroll at least p_sj lines */
{
for (i = 0; i < p_sj && Topline > 1; i += plines(--Topline))
;
}
if (Topline > Curpos.lnum)
Topline = Curpos.lnum;
updateScreen(VALID);
}
else if (Curpos.lnum >= Botline)
{
/* number of lines the cursor is below the bottom of the screen */
nlines = Curpos.lnum - Botline + 1;
/*
* If the cursor is less than a screenheight down
* compute the number of lines at the top which have the same or more
* rows than the rows of the lines below the bottom
*/
if (nlines <= Rows)
{
/* get the number or rows to scroll minus the number of
free '~' rows */
temp = plines_m(Botline, Curpos.lnum) - emptyrows;
if (temp <= 0) /* emptyrows is larger, no need to scroll */
nlines = 0;
else if (temp >= Rows) /* more than a screenfull, don't scroll */
nlines = temp;
else
{
/* scroll minimal number of lines */
if (temp < p_sj)
temp = p_sj;
for (i = 0, p = Topline; i < temp && p < Botline; ++p)
i += plines(p);
if (i >= temp) /* it's possible to scroll */
nlines = p - Topline;
else /* below Botline, don't scroll */
nlines = 9999;
}
}
/*
* Scroll up if the cursor is off the bottom of the screen a bit.
* Otherwise put it at 1/2 of the screen.
*/
if (nlines >= Rows / 2 && nlines > p_sj)
{
p = Curpos.lnum;
temp = Rows / 2 + 1;
nlines = 0;
i = 0;
do /* this loop could win a contest ... */
i += plines(p);
while (i < temp && (nlines = 1) != 0 && --p != 0);
Topline = p + nlines;
}
else
scrollup(nlines);
updateScreen(VALID);
}
else if (NumLineSizes == 0) /* don't know about screen contents */
updateScreen(NOT_VALID);
Cursrow = Curscol = Cursvcol = i = 0;
for (p = Topline; p != Curpos.lnum; ++p)
if (RedrawingDisabled) /* LineSizes[] invalid */
Cursrow += plines(p);
else
Cursrow += LineSizes[i++];
Cline_row = Cursrow;
if (!RedrawingDisabled && i > NumLineSizes)
/* Should only happen with a line that is too */
/* long to fit on the last screen line. */
Cline_size = 0;
else
{
if (RedrawingDisabled) /* LineSizes[] invalid */
Cline_size = plines(Curpos.lnum);
else
Cline_size = LineSizes[i];
curs_columns(!RedrawingDisabled); /* compute Cursvcol and Curscol */
if (must_redraw)
updateScreen(VALID);
}
if (set_want_col)
{
if (Track)
{
if (Curswant < Cursvcol)
Curswant = getvcol(&Curpos, 2);
else if (Curswant > Cursvcol && Curswant != MAXCOL)
Curswant = getvcol(&Curpos, 3);
else
Curswant = Cursvcol;
}
else
Curswant = Cursvcol;
set_want_col = FALSE;
}
}
/*
* compute Curscol and Cursvcol
*/
void
curs_columns(scroll)
int scroll; /* when TRUE, may scroll horizontally */
{
int diff;
#ifdef JP
u_char *ptr, c;
int col;
Cursvcol = 0;
if (p_nu)
Curscol = 8;
else
Curscol = 0;
Cursrow = Cline_row;
ptr = (u_char *)nr2ptr(Curpos.lnum);
col = 0;
while(col < Curpos.col)
{
if (!(c = *ptr)) break;
if (IsKanji(c))
{
if (Curscol >= Columns - 1 && p_wrap)
{ /* last column wrapping for multi-byte char. */
Cursrow ++;
Curscol = 0;
}
ptr += 2;
col += 2;
Cursvcol += 2;
Curscol += 2;
}
else
{
int cw;
ptr ++;
col ++;
cw = chartabsize(c, Curscol);
Cursvcol += cw;
Curscol += cw;
}
if (Curscol >= Columns && p_wrap)
{ /* long line wrapping, adjust Cursrow */
Cursrow ++;
Curscol = 0;
}
}
if (IsKanji(*ptr) && Curscol == Columns - 1)
{ /* last column kanji */
Cursrow ++;
Curscol = 0;
}
if ((c = *ptr) == TAB && State == NORMAL && !p_list)
{
int cw;
cw = chartabsize(c, Curscol) - 1;
Cursvcol += cw;
Curscol += cw;
}
if (p_wrap)
{ }
#else
Cursvcol = getvcol(&Curpos, 1);
Curscol = Cursvcol;
if (p_nu)
Curscol += 8;
Cursrow = Cline_row;
if (p_wrap) /* long line wrapping, adjust Cursrow */
while (Curscol >= Columns)
{
Curscol -= Columns;
Cursrow++;
}
#endif
else if (scroll) /* no line wrapping, compute Leftcol if scrolling is on */
/* if scrolling is off, Leftcol is assumed to be 0 */
{
/* If Cursor is left of the screen, scroll rightwards */
/* If Cursor is right of the screen, scroll leftwards */
if (((diff = Leftcol + (p_nu ? 8 : 0) - Curscol) > 0 ||
(diff = Curscol - (Leftcol + Columns) + 1) > 0))
{
if (p_ss == 0 || diff >= Columns / 2)
Leftcol = Curscol - Columns / 2;
else
{
if (diff < p_ss)
diff = p_ss;
if (Curscol < Leftcol + 8)
Leftcol -= diff;
else
Leftcol += diff;
}
if (Leftcol < 0)
Leftcol = 0;
must_redraw = NOT_VALID; /* screen has to be redrawn with new Leftcol */
}
Curscol -= Leftcol;
}
if (Cursrow > Rows - 2) /* Cursor past end of screen */
Cursrow = Rows - 2; /* happens with line that does not fit on screen */
}
/*
* get virtual column number of pos
* type = 1: where the cursor is on this character
* type = 2: on the first position of this character (TAB)
* type = 3: on the last position of this character (TAB)
*/
int
getvcol(pos, type)
FPOS *pos;
int type;
{
int col;
int vcol;
u_char *ptr;
int incr;
u_char c;
vcol = 0;
ptr = (u_char *)nr2ptr(pos->lnum);
for (col = pos->col; col >= 0; --col)
{
c = *ptr++;
#ifdef JP
if (IsKanji(c))
ptr++;
#endif
if (c == NUL) /* make sure we don't go past the end of the line */
break;
/* A tab gets expanded, depending on the current column */
#ifdef JP
if (IsKanji(c))
incr = 2;
else
#endif
incr = chartabsize(c, vcol);
if (col <= 0) /* character at pos.col */
{
if (type == 3 || (type == 1 && c == TAB && State == NORMAL && !p_list))
--incr;
else
break;
}
#ifdef JP
if (IsKanji(c))
col--;
#endif
vcol += incr;
}
return vcol;
}
/*
* get pointer corresponding to vcol
*/
colnr_t
vcol2col(lnum, dvcol)
linenr_t lnum;
int dvcol;
{
char *line, *ptr, c;
int vcol;
ptr = line = nr2ptr(lnum);
vcol = 0;
while((c = *ptr))
{
#ifdef JP
if (IsKanji(c))
{
vcol += 2;
if (vcol > dvcol)
break;
ptr += 2;
continue;
}
#endif
vcol += chartabsize(c, vcol);
if (vcol > dvcol)
break;
ptr ++;
}
return (colnr_t)(ptr - line);
}
void
scrolldown(nlines)
long nlines;
{
register long done = 0; /* total # of physical lines done */
/* Scroll up 'nlines' lines. */
while (nlines--)
{
if (Topline == 1)
break;
done += plines(--Topline);
}
/*
* Compute the row number of the last row of the cursor line
* and move it onto the screen.
*/
Cursrow += done;
if (p_wrap)
Cursrow += plines(Curpos.lnum) - 1 - Cursvcol / Columns;
while (Cursrow >= Rows - 1 && Curpos.lnum > 1)
Cursrow -= plines(Curpos.lnum--);
}
void
scrollup(nlines)
long nlines;
{
#ifdef NEVER
register long done = 0; /* total # of physical lines done */
/* Scroll down 'nlines' lines. */
while (nlines--)
{
if (Topline == line_count)
break;
done += plines(Topline);
if (Curpos.lnum == Topline)
++Curpos.lnum;
++Topline;
}
s_del(0, done, TRUE);
#endif
Topline += nlines;
if (Topline > line_count)
Topline = line_count;
if (Curpos.lnum < Topline)
Curpos.lnum = Topline;
}
/*
* The rest of the routines in this file perform screen manipulations. The
* given operation is performed physically on the screen. The corresponding
* change is also made to the internal screen image. In this way, the editor
* anticipates the effect of editing changes on the appearance of the screen.
* That way, when we call screenupdate a complete redraw isn't usually
* necessary. Another advantage is that we can keep adding code to anticipate
* screen changes, and in the meantime, everything still works.
*/
/*
* s_ins(row, nlines, invalid) - insert 'nlines' lines at 'row'
* if 'invalid' is TRUE the LineNumbers[] is invalidated.
* Returns 0 if the lines are not inserted, 1 for success.
*/
int
s_ins(row, nlines, invalid)
int row;
int nlines;
int invalid;
{
int i;
int j;
u_char *temp;
screenalloc(TRUE); /* allocate screen buffers if size changed */
if (Nextscreen == NULL)
return 0;
if (invalid)
NumLineSizes = 0;
if (nlines > (Rows - 1 - row))
nlines = Rows - 1 - row;
if (RedrawingDisabled || nlines <= 0 ||
((T_CIL == NULL || *T_CIL == NUL) &&
(T_IL == NULL || *T_IL == NUL) &&
(T_SR == NULL || *T_SR == NUL || row != 0)))
return 0;
if (Rows - nlines < 5) /* only a few lines left: redraw is faster */
{
screenclear(); /* will set NumLineSizes to 0 */
return 0;
}
if (Rows != Rows_max)
{
windgoto((int)Rows - 1, 0); /* delete any garbage that may have */
clear_line(); /* been shifted to the bottom line */
}
/*
* It "looks" better if we do all the inserts at once
*/
if (T_CIL && *T_CIL)
{
windgoto(row, 0);
if (nlines == 1 && T_IL && *T_IL)
outstr(T_IL);
else
outstr(tgoto(T_CIL, 0, nlines));
}
else
{
for (i = 0; i < nlines; i++)
{
if (i == 0 || row != 0)
windgoto(row, 0);
if (T_IL && *T_IL)
outstr(T_IL);
else
outstr(T_SR);
}
}
windgoto((int)Rows - 1, 0); /* delete any garbage that may have */
clear_line(); /* been shifted to the bottom line */
redraw_msg = TRUE;
/*
* Now shift LinePointers nlines down to reflect the inserted lines.
* Clear the inserted lines.
*/
for (i = 0; i < nlines; ++i)
{
j = Rows - 2 - i;
temp = LinePointers[j];
while ((j -= nlines) >= row)
LinePointers[j + nlines] = LinePointers[j];
LinePointers[j + nlines] = temp;
memset((char *)temp, ' ', (size_t)Columns);
}
return 1;
}
/*
* s_del(row, nlines, invalid) - delete 'nlines' lines at 'row'
* If 'invalid' is TRUE LineNumbers[] is invalidated.
* Return 1 for success, 0 if the lines are not deleted.
*/
int
s_del(row, nlines, invalid)
int row;
int nlines;
int invalid;
{
int j;
int i;
u_char *temp;
screenalloc(TRUE); /* allocate screen buffers if size changed */
if (Nextscreen == NULL)
return 0;
if (invalid)
NumLineSizes = 0;
if (nlines > (Rows - 1 - row))
nlines = Rows - 1 - row;
if (RedrawingDisabled || nlines <= 0 ||
((T_DL == NULL || *T_DL == NUL) &&
(T_CDL == NULL || *T_CDL == NUL) &&
row != 0))
return 0;
if (Rows - nlines < 5) /* only a few lines left: redraw is faster */
{
screenclear(); /* will set NumLineSizes to 0 */
return 0;
}
windgoto((int)Rows - 1, 0); /* delete any garbage that may be */
clear_line(); /* on the bottom line */
redraw_msg = TRUE;
/* delete the lines */
if (T_CDL && *T_CDL)
{
windgoto(row, 0);
if (nlines == 1 && T_DL && *T_DL)
outstr(T_DL);
else
outstr(tgoto(T_CDL, 0, nlines));
}
else
{
if (row == 0)
{
if (Rows != Rows_max)
windgoto((int)Rows_max - 1, 0);
for (i = 0; i < nlines; i++)
outchar('\n');
}
else
{
for (i = 0; i < nlines; i++)
{
windgoto(row, 0);
outstr(T_DL); /* delete a line */
}
}
}
/*
* Now shift LinePointers nlines up to reflect the deleted lines.
* Clear the deleted lines.
*/
for (i = 0; i < nlines; ++i)
{
j = row + i;
temp = LinePointers[j];
while ((j += nlines) < Rows - 1)
LinePointers[j - nlines] = LinePointers[j];
LinePointers[j - nlines] = temp;
memset((char *)temp, ' ', (size_t)Columns);
}
return 1;
}
void
showmode()
{
if ((p_smd && (State == INSERT || State == REPLACE)) || Recording)
{
gotocmdline(TRUE, NUL);
if (p_smd)
{
#ifdef ONEW
if (!KanjiInput && !p_oh && (State == INSERT || State == REPLACE))
{
if (p_ri)
outstrn("[<-");
else
outstrn("[");
if (State == INSERT)
outstrn("INS");
else if (State == REPLACE)
outstrn("REP");
outstrn("]");
if (p_ja)
outstrn(p_ji);
if (Recording)
outstrn("....");
}
#else
if (State == INSERT || State == REPLACE)
{
outstrn("-- ");
if (p_ri)
outstrn("REVERSE ");
if (State == INSERT)
outstrn("INSERT --");
else
outstrn("REPLACE --");
}
#endif
}
#ifndef JP
if (!p_fm && Recording)
outstrn("recording");
#endif
}
showruler(1);
}
/*
* delete mode message
*/
void
delmode()
{
if (Recording)
msg("recording");
else
msg("");
}
/*
* if ruler option is set: show current cursor position
* if always is FALSE, only print if position has changed
*/
void
showruler(always)
int always;
{
static linenr_t oldlnum = 0;
static colnr_t oldcol = 0;
static int oldlen = 0;
int newlen;
char buffer[20];
if (p_ru && p_fm)
{
sprintf(buffer, "%ld,%d", Curpos.lnum, (int)Curpos.col + 1);
newlen = strlen(buffer);
if (Curpos.col != Cursvcol)
{
sprintf(buffer + newlen, "-%d", Cursvcol + 1);
newlen = strlen(buffer);
}
screen_msg(TRUE, buffer);
return;
}
if (p_ru && (redraw_msg || always || Curpos.lnum != oldlnum || Cursvcol != oldcol))
{
windgoto((int)Rows - 1, ru_col);
/*
* Some sprintfs return the lenght, some return a pointer.
* To avoid portability problems we use strlen here.
*/
sprintf(buffer, "%ld,%d", Curpos.lnum, (int)Curpos.col + 1);
newlen = strlen(buffer);
if (Curpos.col != Cursvcol)
{
sprintf(buffer + newlen, "-%d", Cursvcol + 1);
newlen = strlen(buffer);
}
outstrn(buffer);
while (newlen < oldlen)
{
outchar(' ');
--oldlen;
}
oldlen = newlen;
oldlnum = Curpos.lnum;
oldcol = Cursvcol;
redraw_msg = FALSE;
}
}
/*
* Clear a line. The cursor must be at the first char of the line.
*/
void
clear_line()
{
register int i;
if (T_EL != NULL && *T_EL != NUL)
outstr(T_EL);
else
for (i = 1; i < Columns; ++i)
outchar(' ');
}
#define MAXMSG 80
void
screen_msg(rev, msg)
int rev;
char *msg;
{
static int srow, scol, slen = 0;
static u_char orgscr[MAXMSG + 1], orgatr[MAXMSG + 1];
u_char *mp, *screenp, *attribp, attr;
u_char *osp, *oap;
#ifdef JP
KANJI_OFF
#endif
if (!LinePointers)
{
if (msg)
{
if (rev) outstr(T_TI);
outstr((char *)msg);
if (rev) outstr(T_TP);
}
return;
}
/* do not display the same message */
if (msg && slen)
{
screenp = LinePointers[srow] + scol;
attribp = ScreenAttr(screenp);
for(mp = (u_char *)msg; mp - (u_char *)msg < slen; mp++, screenp++)
if (*mp != *screenp) break;
if (mp - (u_char *)msg >= slen) return;
}
INVERT_OFF
#ifdef JPFEP
ULINE_OFF
#endif
/* remove old message */
if (slen)
{
screenp = LinePointers[srow];
attribp = ScreenAttr(screenp);
screenp += scol;
attribp += scol;
osp = orgscr;
oap = orgatr;
windgoto(srow, scol);
for(; slen > 0; slen--)
{
char c1, c2;
c1 =
*screenp++ = *osp++;
*attribp++ = *oap++;
#ifdef JP
if (IsKanji(c1))
{
slen --;
c2 =
*screenp++ = *osp++;
*attribp++ = *oap++;
KANJI_ON
kanjito(&c1, &c2, kcode);
outchar(c1);
outchar(c2);
}
else
{
KANJI_OFF
outchar(c1);
}
#else /* JP */
outchar(c1);
#endif /* JP */
}
#ifdef JP
KANJI_OFF
#endif /* JP */
}
/* write new message */
if (msg)
{
u_char *cp, *msgend;
curs_columns(TRUE);
srow = Cursrow;
scol = Curscol;
slen = 0;
cp = (u_char *)msg;
while(*cp && slen < MAXMSG && slen < Columns)
#ifdef JP
if (IsKanji(*cp))
{
cp += 2;
slen+= 2;
}
else
#endif
{
++ cp;
++ slen;
}
msgend = cp;
if (srow < Rows - (State == CMDLINE ? 2 : 1))
srow ++;
else
srow --;
#ifdef ONEW
{
extern int onew_noredraw;
if (State == CMDLINE && onew_noredraw)
srow = 0;
}
#endif
if (srow < 0) srow = 0;
if (srow > Rows) srow = Rows - 1;
screenp = LinePointers[srow];
attribp = ScreenAttr(screenp);
attr = rev ? AM_None : AM_Inv;
/* search white spaces */
{
int fscol, bscol;
u_char *cp, *sp, *startp;
fscol = bscol = -1;
/* search forward */
startp = screenp;
if (scol > slen / 2)
startp += scol - slen / 2;
for(cp = startp; cp <= screenp + Columns - slen; cp++)
{
for(sp = cp; sp - cp != slen ; sp++)
if (*sp != ' ')
{
cp = sp;
break;
}
if (cp != sp)
{
fscol = cp - screenp;
break;
}
}
/* search backward */
cp = startp + slen - 1;
if (cp - screenp > Columns)
cp = screenp + Columns - 1;
for(; cp >= screenp + slen; cp--)
{
for(sp = cp; cp - sp != slen; sp--)
if (*sp != ' ')
{
cp = sp;
break;
}
if (cp != sp)
{
bscol = sp - screenp + 1;
break;
}
}
if (fscol < 0)
if (bscol < 0) /* when no enough space is found */
if (scol > Columns - slen / 2 - 1)
scol = Columns - slen;
else if (scol > slen / 2)
scol -= slen / 2;
else
scol = 0;
else /* when space is found backword */
scol = bscol;
else
if (bscol < 0) /* when space is found foreword */
scol = fscol;
else
scol = (scol - bscol -slen < fscol - scol) ? bscol : fscol;
}
#ifdef JP
KANJI_OFF
if (IsKanji(*(screenp + scol)) && !(*(attribp + scol) & AM_K1))
{
if (scol > Columns / 2)
scol--;
else
scol++;
}
#endif /* JP */
screenp += scol;
attribp += scol;
osp = orgscr;
oap = orgatr;
for(mp = (u_char *)msg; mp < msgend; mp++)
{
*osp ++ = *screenp;
*oap ++ = *attribp;
*screenp++ = *mp;
*attribp++ = attr;
}
if (rev) outstr(T_TI);
windgoto(srow, scol);
for(mp = (u_char *)msg; mp < msgend; mp++)
{
u_char c1, c2;
c1 = *mp;
#ifdef JP
if (IsKanji(c1))
{
c2 = * ++mp;
KANJI_ON
kanjito(&c1, &c2, kcode);
outchar(c1);
outchar(c2);
}
else
{
KANJI_OFF
outchar(c1);
}
#else /* JP */
outchar(c1);
#endif /* JP */
}
#ifdef JP
KANJI_OFF
if (IsKanji(*screenp) && !(*attribp & AM_K1))
{
*osp++ = *screenp;
*oap++ = *attribp;
*screenp = ' ';
*attribp = attr;
outchar(' ');
slen++;
}
#endif /* JP */
if (rev) outstr(T_TP);
}
flushbuf();
}
syntax highlighted by Code2HTML, v. 0.9.1