home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
rtsi.com
/
2014.01.www.rtsi.com.tar
/
www.rtsi.com
/
OS9
/
OSK
/
CMDS
/
pvic_10a.lzh
/
SRCE
/
screen.c
< prev
next >
Wrap
Text File
|
1998-04-23
|
16KB
|
627 lines
/*
* Routines to manipulate the screen representations.
*/
#include <stdio.h>
#include "pvic.h"
#include "locdefs.h"
/*
* This gets set if we ignored an update request while input was pending.
* We check this when the input is drained to see if the screen should be
* updated.
*/
int need_redraw=0;
/*
* The following variable is set (in filetonext) 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 routines lfiletonext() and lnexttoscreen()
* make 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 routines
* filetonext() and nexttoscreen() to examine the entire screen.
*/
static int cursor_line_size; /* size (in rows) of the cursor line */
static int cursor_line_row; /* starting row of the cursor line */
static char *mkline(); /* calculate line string for "number" mode */
/*
* filetonext()
*
* Based on the current value of top_char, transfer a screenfull of
* stuff from file_memory to next_screen, and update bottom_char.
*/
static void filetonext(do_allways)
int do_allways;
{
register int row, col;
register char *screenp = next_screen;
LPTR memp;
LPTR save; /* save pos. in case line won't fit */
register char *endscreen;
register char *nextrow;
char extra[16];
int nextra = 0;
register int c;
int n;
int done; /* if (1), we hit the end of the file */
int didline; /* if (1), we finished the last line */
int srow; /* starting row of the current line */
int lno; /* number of the line we're doing */
int coff; /* column offset */
if(!do_allways && is_input_pending())
{
need_redraw=1;
return;
}
coff = PARAMETER_VALUE(PARAMETER_NUMBER) ? 8 : 0;
save = memp = *top_char;
if (PARAMETER_VALUE(PARAMETER_NUMBER))
lno = cntllines(file_memory, top_char);
/*
* The number of rows shown is current_lines-1.
* The last line is the status/command line.
*/
endscreen = &screenp[(current_lines-1)*current_columns];
done = didline = (0);
srow = row = col = 0;
/*
* We go one past the end of the screen so we can find out if the
* last line fit on the screen or not.
*/
while ( screenp <= endscreen && !done) {
if (PARAMETER_VALUE(PARAMETER_NUMBER) && col == 0 && memp.index == 0) {
strcpy(extra, mkline(lno++));
nextra = 8;
}
/* Get the next character to put on the screen. */
/* The 'extra' array contains the extra stuff that is */
/* inserted to represent special characters (tabs, and */
/* other non-printable stuff. The order in the 'extra' */
/* array is reversed. */
if ( nextra > 0 )
c = extra[--nextra];
else {
c = (unsigned)(0xff & gchar(&memp));
if (inc(&memp) == -1)
done = 1;
/* when getting a character from the file, we */
/* may have to turn it into something else on */
/* the way to putting it into 'next_screen'. */
if ( c == CTRL_I && !PARAMETER_VALUE(PARAMETER_LIST) ) {
strcpy(extra," ");
/* tab amount depends on current column */
nextra = ((PARAMETER_VALUE(PARAMETER_TABSTOP)-1) - (col - coff)%PARAMETER_VALUE(PARAMETER_TABSTOP));
c = ' ';
}
else if ( c == '\0' && PARAMETER_VALUE(PARAMETER_LIST) ) {
extra[0] = '\0';
nextra = 1;
c = '$';
} else if ( (n = chars[c].ch_size) > 1 ) {
char *p;
nextra = 0;
p = chars[c].ch_str;
/* copy 'ch-str'ing into 'extra' in reverse */
while ( n > 1 )
extra[nextra++] = p[--n];
c = p[0];
}
}
if (screenp == endscreen) {
/*
* We're one past the end of the screen. If the
* current character is null, then we really did
* finish, so set didline = (1). In either case,
* break out because we're done.
*/
dec(&memp);
if (memp.index != 0 && c == '\0') {
didline = (1);
inc(&memp);
}
break;
}
if ( c == '\0' ) {
srow = ++row;
/*
* Save this position in case the next line won't
* fit on the screen completely.
*/
save = memp;
/* get pointer to start of next row */
nextrow = &next_screen[row*current_columns];
/* blank out the rest of this row */
while ( screenp != nextrow )
*screenp++ = ' ';
col = 0;
continue;
}
if ( col >= current_columns ) {
row++;
col = 0;
}
/* store the character in next_screen */
*screenp++ = c;
col++;
}
/*
* 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) {
/*
* Clear the rest of the screen and mark the unused lines.
*/
screenp = &next_screen[srow * current_columns];
while (screenp < endscreen)
*screenp++ = ' ';
for (; srow < (current_lines-1) ;srow++)
next_screen[srow * current_columns] = '@';
*bottom_char = save;
return;
}
/* make sure the rest of the screen is blank */
while ( screenp < endscreen )
*screenp++ = ' ';
/* put '~'s on rows that aren't part of the file. */
if ( col != 0 )
row++;
while ( row < current_lines ) {
next_screen[row*current_columns] = '~';
row++;
}
if (done) /* we hit the end of the file */
*bottom_char = *end_of_file;
else
*bottom_char = memp; /* FIX - prev? */
}
/*
* nexttoscreen
*
* Transfer the contents of next_screen to the screen, using real_screen
* to avoid unnecesssary output.
*/
static void nexttoscreen(do_allways)
int do_allways;
{
register char *np = next_screen;
register char *rp = real_screen;
register char *endscreen;
register int row = 0, col = 0;
int i;
int gorow = -1, gocol = -1;
endscreen = &np[(current_lines-1)*current_columns];
termcap_out(termcap_cursor_invisible); /* disable cursor */
for (i=0 ; np < endscreen ; np++,rp++,i++ ) {
if ((i%current_columns)==0 && is_input_pending() &&
!do_allways) {
need_redraw = (1);
return;
}
/* If desired screen (contents of next_screen) does not */
/* match what's really there, put it there. */
if ( *np != *rp ) {
/* if we are positioned at the right place, */
/* we don't have to use goto_screen_pos(). */
if (gocol != col || gorow != row) {
/*
* If we're just off by one, don't send
* an entire esc. seq. (this happens a lot!)
*/
if (gorow == row && gocol+1 == col) {
putc(*(np-1),stdout);
gocol++;
} else
goto_screen_pos(gorow=row,gocol=col);
}
putc(*rp = *np,stdout);
gocol++;
}
if ( ++col >= current_columns ) {
col = 0;
row++;
}
}
termcap_out(termcap_cursor_visible); /* enable cursor again */
}
/*
* lfiletonext() - like filetonext() but only for cursor line
*
* Returns true if the size of the cursor line (in rows) hasn't changed.
* This determines whether or not we need to call filetonext() to examine
* the entire screen for changes.
*/
static int lfiletonext()
{
register int row, col;
register char *screenp;
LPTR memp;
register char *nextrow;
char extra[16];
int nextra = 0;
register int c;
int n;
int eof;
int lno; /* number of the line we're doing */
int coff; /* column offset */
coff = PARAMETER_VALUE(PARAMETER_NUMBER) ? 8 : 0;
/*
* This should be done more efficiently.
*/
if (PARAMETER_VALUE(PARAMETER_NUMBER))
lno = cntllines(file_memory, cursor_char);
screenp = next_screen + (cursor_line_row * current_columns);
memp = *cursor_char;
memp.index = 0;
eof = (0);
col = 0;
row = cursor_line_row;
while (!eof) {
if (PARAMETER_VALUE(PARAMETER_NUMBER) && col == 0 && memp.index == 0) {
strcpy(extra, mkline(lno));
nextra = 8;
}
/* Get the next character to put on the screen. */
/* The 'extra' array contains the extra stuff that is */
/* inserted to represent special characters (tabs, and */
/* other non-printable stuff. The order in the 'extra' */
/* array is reversed. */
if ( nextra > 0 )
c = extra[--nextra];
else {
c = (unsigned)(0xff & gchar(&memp));
if (inc(&memp) == -1)
eof = (1);
/* when getting a character from the file, we */
/* may have to turn it into something else on */
/* the way to putting it into 'next_screen'. */
if ( c == CTRL_I && !PARAMETER_VALUE(PARAMETER_LIST) ) {
strcpy(extra," ");
/* tab amount depends on current column */
nextra = ((PARAMETER_VALUE(PARAMETER_TABSTOP)-1) - (col - coff)%PARAMETER_VALUE(PARAMETER_TABSTOP));
c = ' ';
} else if ( c == '\0' && PARAMETER_VALUE(PARAMETER_LIST) ) {
extra[0] = '\0';
nextra = 1;
c = '$';
} else if ( c != '\0' && (n=chars[c].ch_size) > 1 ) {
char *p;
nextra = 0;
p = chars[c].ch_str;
/* copy 'ch-str'ing into 'extra' in reverse */
while ( n > 1 )
extra[nextra++] = p[--n];
c = p[0];
}
}
if ( c == '\0' ) {
row++;
/* get pointer to start of next row */
nextrow = &next_screen[row*current_columns];
/* blank out the rest of this row */
while ( screenp != nextrow )
*screenp++ = ' ';
col = 0;
break;
}
if ( col >= current_columns ) {
row++;
col = 0;
}
/* store the character in next_screen */
*screenp++ = c;
col++;
}
return ((row - cursor_line_row) == cursor_line_size);
}
/*
* lnexttoscreen
*
* Like nexttoscreen() but only for the cursor line.
*/
static void lnexttoscreen()
{
register char *np = next_screen + (cursor_line_row * current_columns);
register char *rp = real_screen + (cursor_line_row * current_columns);
register char *endline;
register int row, col;
int gorow = -1, gocol = -1;
if (is_input_pending()) {
need_redraw = (1);
return;
}
endline = np + (cursor_line_size * current_columns);
row = cursor_line_row;
col = 0;
termcap_out(termcap_cursor_invisible); /* disable cursor */
for ( ; np < endline ; np++,rp++ ) {
/* If desired screen (contents of next_screen) does not */
/* match what's really there, put it there. */
if ( *np != *rp ) {
/* if we are positioned at the right place, */
/* we don't have to use goto_screen_pos(). */
if (gocol != col || gorow != row) {
/*
* If we're just off by one, don't send
* an entire esc. seq. (this happens a lot!)
*/
if (gorow == row && gocol+1 == col) {
putc(*(np-1),stdout);
gocol++;
} else
goto_screen_pos(gorow=row,gocol=col);
}
putc(*rp = *np,stdout);
gocol++;
}
if ( ++col >= current_columns ) {
col = 0;
row++;
}
}
termcap_out(termcap_cursor_visible); /* enable cursor again */
}
static char * mkline(n)
register int n;
{
static char lbuf[9];
register int i = 2;
strcpy(lbuf, " ");
lbuf[i++] = (n % 10) + '0';
n /= 10;
if (n != 0) {
lbuf[i++] = (n % 10) + '0';
n /= 10;
}
if (n != 0) {
lbuf[i++] = (n % 10) + '0';
n /= 10;
}
if (n != 0) {
lbuf[i++] = (n % 10) + '0';
n /= 10;
}
if (n != 0) {
lbuf[i++] = (n % 10) + '0';
n /= 10;
}
return lbuf;
}
/*
* update_line() - update the line the cursor is on
*
* Updateline() is called after changes that only affect the line that
* the cursor is on. This improves performance tremendously for normal
* insert mode operation. The only thing we have to watch for is when
* the cursor line grows or shrinks around a row boundary. This means
* we have to repaint other parts of the screen appropriately. If
* lfiletonext() returns (0), the size of the cursor line (in rows)
* has changed and we have to call update_screen() to do a complete job.
*/
void update_line()
{
if (!lfiletonext())
update_screen(1); /* bag it, do the whole screen */
else
lnexttoscreen();
}
void update_screen(do_allways)
int do_allways;
{
extern int interactive;
if(!do_allways && is_input_pending())
{
need_redraw=1;
return;
}
if (interactive) {
filetonext(do_allways);
nexttoscreen(do_allways);
}
}
/*
* prt_line() - print the given line
*/
void prt_line(s)
char *s;
{
register int si = 0;
register int c;
register int col = 0;
char extra[16];
int nextra = 0;
int n;
for (;;) {
if ( nextra > 0 )
c = extra[--nextra];
else {
c = s[si++];
if ( c == CTRL_I && !PARAMETER_VALUE(PARAMETER_LIST) ) {
strcpy(extra, " ");
/* tab amount depends on current column */
nextra = (PARAMETER_VALUE(PARAMETER_TABSTOP) -
1) - col%PARAMETER_VALUE(PARAMETER_TABSTOP);
c = ' ';
} else if ( c == '\0' && PARAMETER_VALUE(PARAMETER_LIST) ) {
extra[0] = '\0';
nextra = 1;
c = '$';
} else if ( c != '\0' && (n=chars[c].ch_size) > 1 ) {
char *p;
nextra = 0;
p = chars[c].ch_str;
/* copy 'ch-str'ing into 'extra' in reverse */
while ( n > 1 )
extra[nextra++] = p[--n];
c = p[0];
}
}
if ( c == '\0' )
break;
putc(c,stdout);
col++;
}
}
void clear_screen()
{
register char *rp, *np;
register char *end;
termcap_out(termcap_clear_screen); /* clear the display */
termcap_out(termcap_cursor_address,0,0);
rp = real_screen;
end = real_screen + current_lines * current_columns;
np = next_screen;
/* blank out the stored screens */
while (rp != end)
*rp++ = *np++ = ' ';
}
void update_cursor(do_allways)
int do_allways;
{
register LPTR *p;
register int icnt, c, nlines;
register int i;
int didinc;
if (buffer_empty()) { /* special case - file is empty */
*top_char = *file_memory;
*cursor_char = *file_memory;
} else if ( LINEOF(cursor_char) < LINEOF(top_char) ) {
nlines = cntllines(cursor_char,top_char);
/* if the cursor is above the top of */
/* the screen, put it at the top of the screen.. */
*top_char = *cursor_char;
top_char->index = 0;
/* ... and, if we weren't very close to begin with, */
/* we scroll so that the line is close to the middle. */
if ( nlines > current_lines/3 ) {
for (i=0, p = top_char; i < current_lines/3 ;i++, *top_char = *p)
if ((p = previous_line(p)) == NULL)
break;
}
update_screen(do_allways);
}
else if (LINEOF(cursor_char) >= LINEOF(bottom_char)) {
nlines = cntllines(bottom_char,cursor_char);
/* If the cursor is off the bottom of the screen, */
/* put it at the top of the screen.. */
/* ... and back up */
if ( nlines > current_lines/3 ) {
p = cursor_char;
for (i=0; i < (2*current_lines)/3 ;i++)
if ((p = previous_line(p)) == NULL)
break;
*top_char = *p;
} else {
scroll_up(nlines);
}
update_screen(do_allways);
}
cursor_row = cursor_column = cursor_virtual_column = 0;
for ( p=top_char; p->linep != cursor_char->linep ;p = next_line(p) )
cursor_row += plines(p);
cursor_line_row = cursor_row;
cursor_line_size = plines(p);
if (PARAMETER_VALUE(PARAMETER_NUMBER))
cursor_column = 8;
for (i=0; i <= cursor_char->index ;i++) {
c = cursor_char->linep->s[i];
/* A tab gets expanded, depending on the current column */
if ( c == CTRL_I && !PARAMETER_VALUE(PARAMETER_LIST) )
icnt = PARAMETER_VALUE(PARAMETER_TABSTOP) - (cursor_virtual_column % PARAMETER_VALUE(PARAMETER_TABSTOP));
else
icnt = chars[(unsigned)(c & 0xff)].ch_size;
cursor_column += icnt;
cursor_virtual_column += icnt;
if ( cursor_column >= current_columns ) {
cursor_column -= current_columns;
cursor_row++;
didinc = (1);
}
else
didinc = (0);
}
if (didinc)
cursor_row--;
if (c == CTRL_I && current_status == STATUS_NORMAL && !PARAMETER_VALUE(PARAMETER_LIST)) {
cursor_column--;
cursor_virtual_column--;
} else {
cursor_column -= icnt;
cursor_virtual_column -= icnt;
}
if (cursor_column < 0)
cursor_column += current_columns;
if (set_wanted_cursor_column) {
wanted_cursor_column = cursor_virtual_column;
set_wanted_cursor_column = (0);
}
if(do_allways || !is_input_pending())
goto_screen_pos(cursor_row,cursor_column);
}