home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
World_Of_Computer_Software-02-387-Vol-3of3.iso
/
x
/
xvisrc.zoo
/
sunback.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-07-28
|
11KB
|
534 lines
#ifndef lint
static char *sccsid = "@(#)sunback.c 2.1 (Chris & John Downey) 7/29/92";
#endif
/***
* program name:
xvi
* function:
PD version of UNIX "vi" editor, with extensions.
* module name:
sunback.c
* module function:
Terminal interface module for SunView: module for linking to
main program.
* history:
STEVIE - ST Editor for VI Enthusiasts, Version 3.10
Originally by Tim Thompson (twitch!tjt)
Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
Heavily modified by Chris & John Downey
***/
#include "xvi.h"
/*
* Exported.
*/
unsigned int Rows = 0; /* screen dimensions */
unsigned int Columns = 0;
/*
* These are used to optimize output.
*/
static int real_row, real_col;
static int virt_row, virt_col;
static bool_t optimize;
#define NO_COLOUR -1
static int old_colour = NO_COLOUR;
/*
* Update real cursor position.
*
* SunView can be painfully slow, at least on Sun 3's and 386i's, but
* it's difficult to know the best way of optimizing it. The number of
* characters sent to the display probably isn't really significant,
* because it isn't a terminal. The things that take the most time are
* more likely to be calculations (especially divisions &
* multiplications) & manipulating bit maps. The bitmap for a single
* character has to be xor'ed twice for each cursor movement, since
* terminal subwindows use a reverse video block cursor.
*/
#define MAXCMOVES 3 /*
* This is a guess at the probable
* maximum number of individual cursor
* movements that's worthwhile to
* avoid the calculations involved in
* an absolute goto.
*/
#ifndef ABS
# define ABS(n) ((n) < 0 ? -(n) : (n))
#endif
static void
xyupdate()
{
int hdisp, /* horizontal (rightward) displacement wanted */
vdisp, /* vertical (downward) displacement wanted */
ahdisp, /* absolute horizontal displacement wanted */
avdisp, /* absolute vertical displacement wanted */
homedisp; /* total displacement from home position */
if (optimize) {
if (virt_col == real_col && virt_row == real_row)
/*
* Nothing to do.
*/
return;
} else {
hdisp = virt_col - real_col;
vdisp = virt_row - real_row;
ahdisp = ABS(hdisp);
avdisp = ABS(vdisp);
}
}
homedisp = virt_row + virt_col;
/*
* Is it worth sending a cursor home sequence?
*/
if (homedisp < MAXCMOVES && (!optimize || homedisp < avdisp + ahdisp)) {
fputs("\033[H", stdout);
real_row = real_col = 0;
ahdisp = hdisp = virt_col;
avdisp = vdisp = virt_row;
optimize = TRUE;
}
if (optimize) {
/*
* Is it worth sending a carriage return?
*/
if (hdisp < 0 && virt_col < ahdisp && virt_col < MAXCMOVES) {
putc('\r', stdout);
real_col = 0;
ahdisp = hdisp = virt_col;
}
if (hdisp == 0 && vdisp == 0) {
/*
* We're already there, so there's nothing to do.
*/
return;
}
/*
* Calculate total absolute displacement to see
* whether it's worthwhile doing any of this.
*/
if (ahdisp + avdisp <= MAXCMOVES) {
for (; real_col < virt_col; real_col++)
/*
* Do non-destructive spaces.
*/
fputs("\033[C", stdout);
for (; real_col > virt_col; real_col--)
/*
* Do backspaces.
*/
putc('\b', stdout);
for (; real_row < virt_row; real_row++)
/*
* Go down.
*/
putc('\n', stdout);
for (; real_row > virt_row; real_row--)
/*
* Go up.
*/
fputs("\033[A", stdout);
return;
}
/*
* It isn't worthwhile. Give up & send an absolute
* goto.
*/
}
fprintf(stdout, "\033[%d;%dH", virt_row + 1, virt_col + 1);
real_row = virt_row;
real_col = virt_col;
optimize = TRUE;
}
/*
* Flush any pending output, including cursor position.
*/
void
flush_output()
{
xyupdate();
(void) fflush(stdout);
}
/*
* Put out a "normal" character, updating the cursor position.
*/
void
outchar(c)
register int c;
{
xyupdate();
putc(c, stdout);
if (++virt_col >= Columns) {
virt_col = 0;
if (++virt_row >= Rows)
--virt_row;
real_row = virt_row;
}
real_col = virt_col;
}
/*
* Put out a "normal" string, updating the cursor position.
*/
void
outstr(s)
register char *s;
{
xyupdate();
for (; *s; s++)
{
putc(*s, stdout);
if (++virt_col >= Columns)
{
virt_col = 0;
if (++virt_row >= Rows)
--virt_row;
}
}
real_row = virt_row;
real_col = virt_col;
}
/*
* Beep at the user.
*/
void
alert()
{
putc('\007', stdout);
(void) fflush(stdout);
}
/*
* Get a hexadecimal number from the front end process.
*/
static
hexnumber()
{
register int x;
x = 0;
for (;;) {
register int c;
c = inch(0);
if (c == ';')
return x;
if (!is_xdigit(c))
return -1;
x = (x << 4) | hex_to_bin(c);
}
}
/*
* Get single character or control sequence from front-end process.
* The following control sequences are understood:
*
* Sequence Meaning
*
* PREFIXCHAR 'k' up arrow key pressed
* PREFIXCHAR 'j' down arrow key pressed
* PREFIXCHAR '\b' left arrow key pressed
* PREFIXCHAR ' ' right arrow key pressed
* PREFIXCHAR CTRL('F') page down key pressed
* PREFIXCHAR CTRL('B') page up key pressed
* PREFIXCHAR 'H' home key pressed
* PREFIXCHAR 'L' end key pressed
* PREFIXCHAR PREFIXCHAR PREFIXCHAR pressed
* PREFIXCHAR 'p' hexnum ';' hexnum ';'
* mouse button pressed at row & column
* specified by the digits.
* PREFIXCHAR 'm' hexnum ';' hexnum ';' hexnum ';' hexnum ';'
* mouse dragged with middle button held
* down. Numbers give starting row &
* column, then ending row & column, in
* that order.
*
* PREFIXCHAR is currently control-R. A `hexnum' is 0 or more
* hexadecimal digits.
*
* Any other process run in the same tty subwindow (with the ":!" or
* "sh" commands) will also receive the same sequences for the events
* shown, but using control-R as a prefix should be reasonably safe.
*
* The sequence for mouse clicks is dealt with by mouseposn().
*/
int
inchar(timeout)
long timeout;
{
for (;;) {
register int c;
if ((c = inch(timeout)) == PREFIXCHAR) {
/*
* This looks like the beginning of a control sequence.
*/
switch (c = inch(0)) {
case PREFIXCHAR:
return PREFIXCHAR;
case CTRL('B'): case CTRL('F'):
case 'H': case 'L':
case '\b': case ' ':
case 'j': case 'k':
/*
* This looks like a function
* key.
*/
if (State == NORMAL) {
return c;
} else {
alert();
continue;
}
case 'm':
{
unsigned row1, row2, col1, col2;
/*
* Even if we aren't in normal
* mode here, we have to call
* hexnumber() to eat all the
* hex. digits we should be
* getting.
*/
if (
(row1 = hexnumber()) >= 0
&&
(row2 = hexnumber()) >= 0
&&
(col1 = hexnumber()) >= 0
&&
(col2 = hexnumber()) >= 0
&&
State == NORMAL
) {
mousedrag(row1, row2, col1, col2);
}
continue;
}
case 'p':
{
unsigned row, col;
/*
* Even if we aren't in normal
* mode here, we have to call
* hexnumber() to eat all the
* hex. digits we should be
* getting.
*/
if (
(row = hexnumber()) >= 0
&&
(col = hexnumber()) >= 0
&&
State == NORMAL
) {
mouseclick(row, col);
}
continue;
}
default:
continue;
}
} else if (c == CTRL('Z') && State == NORMAL) {
/*
* This isn't reasonable. Job control isn't
* available here because this process wasn't
* started from a shell (it was started by the
* SunView Notifier). They can always use
* another window to run commands.
*/
alert();
continue;
} else { /* It's just a normal character. */
return c;
}
}
}
static time_t starttime;
/*
* Initialise the terminal interface.
*
* This must be done before any screen-based i/o is performed.
*/
void
tty_open(prows, pcolumns)
unsigned int *prows,
*pcolumns;
{
/*
* If sys_startv() hasn't already got valid values for the
* window size from its TIOCGWINSZ ioctl, something is
* seriously wrong with SunOS.
*/
Rows = *prows;
Columns = *pcolumns;
(void) time(&starttime);
#ifdef sparc
/*
* Unfortunately, this implementation still doesn't give us
* scrolling windows, but SparcStations are fast enough that
* it doesn't really matter.
*/
set_param(P_jumpscroll, js_OFF, (char **) NULL);
#endif
{
/*
* These escape sequences may be generated by the
* arrow keys, depending on how the defaults database
* has been set up. All other function keys (page up,
* page down, etc.) should be received as function
* keys & handled appropriately by the front end
* process.
*/
static char *mapargs[] = {
"\033[A", "k",
"\033[B", "j",
"\033[C", "l",
"\033[D", "h",
NULL
};
char **argp;
for (argp = mapargs; *argp != NULL; argp += 2) {
xvi_keymap(argp[0], argp[1]);
}
}
}
void
tty_startv()
{
old_colour = NO_COLOUR;
optimize = FALSE;
}
/*
* Set terminal into the mode it was in when we started.
*/
void
tty_endv()
{
flush_output();
}
/*
* Tell front end process to quit.
*/
void
tty_close()
{
time_t stayuptime, now;
/*
* If we're immediately crashing with an error message, give
* them a chance (5 seconds) to read it.
*/
stayuptime = starttime + 5;
if ((now = time((time_t *) 0)) < stayuptime)
sleep(stayuptime - now);
write(3, "q", 1);
}
void
tty_goto(row, col)
int row, col;
{
virt_row = row;
virt_col = col;
}
/*
* Erase the entire current line.
*/
void
erase_line()
{
xyupdate();
fputs("\033[K", stdout);
}
/*
* Insert one line.
*/
void
insert_line()
{
xyupdate();
fputs("\033[L", stdout);
}
/*
* Delete one line.
*/
void
delete_line()
{
xyupdate();
fputs("\033[M", stdout);
}
/*
* Erase display (may optionally home cursor).
*/
void
erase_display()
{
putc('\f', stdout);
optimize = FALSE;
old_colour = NO_COLOUR;
}
/*
* Set the specified colour. Just does standout/standend mode for now.
*
* Colour mapping is as follows:
*
* 0 (default systemcolour) normal
* 1 (default colour) normal
* 2 (default statuscolour) reverse video
*/
void
set_colour(c)
int c;
{
if (c == 1) {
c = 0;
} else if (c > 2) {
c = 2;
}
if (c != old_colour) {
xyupdate();
fputs((c ? "\033[7m" : "\033[m"), stdout);
old_colour = c;
}
}
/*
* Insert the given character at the cursor position.
*/
void
inschar(c)
char c;
{
xyupdate();
fputs("\033[@", stdout);
outchar(c);
}