/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 1995, by Sun Microsystems, Inc.
* All rights reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
*
* XCurses Library
*
* Copyright 1990, 1995 by Mortice Kern Systems Inc. All rights reserved.
*
*/
#ifdef M_RCSID
#ifndef lint
static char const rcsID[] = "$Header: /rd/src/libc/xcurses/rcs/doupdate.c 1.9 1995/07/26 17:45:06 ant Exp $";
#endif
#endif
#include <private.h>
#include <string.h>
#include <setjmp.h>
#include <signal.h>
/*
* Disable typeahead trapping because it slow down updated dramatically
*/
#ifdef MPE_STUB
#endif
/*
* This value is the ideal length for the cursor addressing sequence
* being four bytes long, ie. "<escape><cursor addressing code><row><col>".
* eg. VT52 - "\EYrc" or ADM3A - "\E=rc"
*/
/*
* This value is the ideal length for the clear-to-eol sequence
* being two bytes long, ie "<escape><clear eol code>".
*/
typedef struct cost_op {
short cost;
short op;
} lcost;
typedef void (*t_action)(int, int);
static unsigned long *nhash = (unsigned long *) 0;
STATIC void erase_bottom(int);
STATIC void clear_bottom(int);
STATIC void lines_delete(int, int);
STATIC void lines_insert(int, int);
STATIC void lines_replace(int, int);
STATIC void text_replace(int);
STATIC void block_over(int, int, int);
/*f
* Wrapper that streams Curses output.
*
* All escape sequences going to the screen come through here.
* All ordinary characters go to the screen via the putc in doupdate.c
*/
int
int ch;
{
}
/*
* Allocate or grow doupdate() structures.
*/
int
{
void *new;
static short nlines = 0;
if (lines <= 0)
return -1;
return 0;
if (new == (void *) 0)
return -1;
if (new == (void *) 0)
return -1;
if (new == (void *) 0)
return -1;
if (nhash != (unsigned long *) 0)
return 0;
}
STATIC void
erase_bottom(y)
int y;
{
int i;
for (i = y; i < LINES; ++i) {
}
}
/*f
* Clear from the start of the current row to bottom of screen.
*/
STATIC void
clear_bottom(y)
int y;
{
erase_bottom(y);
/* Restore default color pair before doing area clears. */
if (back_color_erase)
if (y == 0 && clear_screen != (char *) 0) {
} else {
if (clr_eos != (char *) 0) {
} else if (clr_eol != (char *) 0) {
for (;;) {
if (LINES <= y)
break;
++y;
}
}
}
}
/*f
* Replace a line of text.
*
* The principal scheme is to overwrite the region of a line between
* the first and last differing characters. A clear-eol is used to
* optimise an update region that consist largely of blanks. This can
* happen fairly often in the case of scrolled lines or full redraws.
*
* Miller's line redraw algorithm, used in the 'S' editor [Mil87],
* should be re-investigated to see if it is simple and fast enough for
* our needs, and if it can be adapted to handle the ceol_standout_glitch
* (HP 2392A terminals) and multibyte character sequences.
*
* Very early versions of this code applied a Gosling algorithm column
* wise in addition to the row-wise used in complex(). It was removed
* in favour of both computation and transmission speed. The assumption
* being that overwrites of a line region occured far more frequently
*
* References:
* [Mil87] W. Miller, A Software Tools Sampler, Prentice-Hall, 1987
*/
STATIC void
int row;
{
short npair;
#ifdef M_CURSES_TYPEAHEAD
/* Before replacing a line of text, check for type-ahead. */
unsigned char cc;
}
}
#endif /* M_CURSES_TYPEAHEAD */
if (col < 0)
col = 0;
if (clr_eol != (char *) 0) {
/* Find start of blank tail region. */
break;
}
/* Only consider clear-to-end-of-line optimization if the
* blank tail falls within the end of the dirty region by
* more than ideal length of clear-to-end-of-line sequence.
* Else disable the check by forcing tail to be at the
* end-of-line.
*/
}
/* Skip common regions. */
/* Advance before possible goto. */
++optr;
++nptr;
goto done;
}
/* Move the cursor by redrawing characters or using
* cursor motion commands. The first time that we
* address this row, jump equals -1, so that the cursor
* will be forced to the correct screen line. Once
* there, we should be able to track the cursor motion
* along the line and jump only when the cost of redrawing
* to column N is more expensive than a jump to column N.
*/
/* First time addressing this row or cost of
* jumping cheaper than redrawing.
*/
count = 0;
/* If attributes at start of field are different
* force an attribute cookie to be dropped.
*/
ATTR_STATE |= WA_COOKIE;
} else {
/* Redraw to move short distance. */
}
/* Write difference region. */
/* Check for clear-to-end-of-line optimization. */
/* For HP terminals, only clear-to-end-of-line
* once the attributes have been turned off.
* Other terminals, we can proceed normally.
*/
if (!ceol_standout_glitch
|| ATTR_STATE == WA_NORMAL) {
goto done;
}
}
++col;
/* Make sure we don't scroll the screen by writing
* to the bottom right corner.
*/
&& auto_right_margin && !eat_newline_glitch) {
/*** TODO
*** Insert character/auto_right_margin
*** hacks for writting into the last
*** column of the last line so as not
*** to scroll.
***/
goto done;
}
/* Remember any existing attribute cookie. */
/* Change attribute state. On HP terminals we also
* have to check for attribute cookies that may need
* to be changed.
*/
if (ATTR_STATE != nattr
(void) vid_puts(
);
/* Remember new or existing cookie. */
}
/* Don't display internal characters. */
(void) __m_cc_write(nptr);
/* Update copy of screen image. */
}
/* Check the attributes at the end of the field with
* those of start of the next common region. If they
* differ, force another iteration of the write-loop
* that will change the attribute state.
*/
goto write_loop;
}
done:
/* Before leaving this line, check if we have to turn off
* attributes and record a cookie.
*/
/* ceol_standout_glitch, which affects HP terminals,
* drops hidden cookies on the screen where ever the
* cursor is, so disabling attributes before a cursor
* motion operation could disturb existing highlights.
*/
if (ceol_standout_glitch)
/* Attributes on an HP terminal do not cross lines. */
else
}
/* Re-check for clear to end-of-line optimization. */
/* Is the tail of the current screen image non-blank? */
break;
/* If tail didn't reach the right margin of
* the current screen image, then we will
* make it look like the new image with a
* clear to end-of-line.
*/
/* Restore default color pair before area clear. */
if (back_color_erase)
(void) vid_puts(
);
}
}
/* Line wrapping checks. */
if (eat_newline_glitch) {
__m_outc('\r');
__m_outc('\n');
}
}
}
}
/*f
* Replace a block of lines.
* Only ever used for complex().
*/
STATIC void
{
}
/*f
* Delete a block of lines.
* Only ever used for complex().
*/
STATIC void
{
} else {
if (parm_delete_line != (char *) 0) {
/* Assume that the sequence to delete more than one
* line is faster than repeated single delete_lines.
*/
(void) tputs(
parm_delete_line, (long) count,
0, 0, 0, 0, 0, 0, 0, 0
);
} else if (delete_line != (char *) 0) {
} else {
/* Error -- what to do. */
return;
}
}
}
/*f
* Insert a block of lines.
* Only ever used for complex().
*
* We must assume that insert_line and parm_insert_line reset the
* cursor column to zero. Therefore it is text_replace() responsiblity
* to move the cursor to the correct column to begin the update.
*/
STATIC void
{
/* Position the cursor and insert a block of lines into the screen
* image now, insert lines into the physical screen, then draw the
* new screen lines.
*/
if (parm_insert_line != (char *) 0) {
/* Assume that the sequence to insert more than one line is
* faster than repeated single insert_lines.
*/
(void) tputs(
parm_insert_line, (long) count,
0, 0, 0, 0, 0, 0, 0, 0
);
} else if (insert_line != (char *) 0) {
/* For the single line insert we use to iterate moving
* the cursor, inserting, and then drawing a line. That
* would appear to be slow but visually appealing. However,
* people on slow terminals want speed and those on fast
* terminal won't see it.
*/
} else {
/* Error -- what to do. */
return;
}
}
STATIC int
scroll_up(n)
int n;
{
int count = n;
if (scroll_forward != (char *) 0) {
while (0 < n--)
} else if (parm_delete_line != (char *) 0 && 1 < n) {
GOTO(0, 0);
(void) tputs(
parm_delete_line, (long) n,
0, 0, 0, 0, 0, 0, 0, 0
), n, __m_outc
);
} else if (delete_line != (char *) 0) {
GOTO(0, 0);
while (0 < n--)
} else {
return 0;
}
/* Scroll recorded image. */
start = 0;
(void) __m_ptr_move(
);
simple();
return 1;
}
STATIC int
scroll_dn(n)
int n;
{
int count = n;
if (LINES < n)
return 0;
if (scroll_reverse != (char *) 0) {
GOTO(0, 0);
while (0 < n--)
} else if (parm_insert_line != (char *) 0 && 1 < n) {
GOTO(0, 0);
(void) tputs(
parm_insert_line, (long) n,
0, 0, 0, 0, 0, 0, 0, 0
), n, __m_outc
);
} else if (insert_line != (char *) 0) {
GOTO(0, 0);
while (0 < n--)
} else {
return 0;
}
/* Scroll recorded image. */
to = 0;
(void) __m_ptr_move(
);
simple();
return 1;
}
#ifdef NEVER
STATIC int
int count;
{
while (0 < count--)
return 0;
return 1;
}
#endif /* NEVER */
/*f
* Dynamic programming algorithm for the string edit problem.
*
* This is a modified Gosling cost algorithm that takes into account
*
* Costs for move, delete, replace, and insert are 0, 1, 2, and 3
* repectively.
*/
STATIC int
{
/* Prepare initial row and column of cost matrix.
*
* 0 3 6 9 ...
* 1
* 2
* 3
* :
*/
/* Top row is 3, 6, 9, ... */
/* Left column is 1, 2, 3, ... */
}
/* Assume move op. */
#ifdef NEVER
/* Should no longer require this code. Using the POSIX 32-bit CRC to
* generate a hash value should be sufficient now, since text_replace()
* will compare the contents of a line and output only the dirty regions.
*/
#endif
) {
/* Lines are different, assume replace op. */
}
/* Compare insert op. */
}
/* Compare delete op. */
}
}
}
}
/*f
* Build edit script.
*
* Normally this would be a recursve routine doing the deletes, inserts,
* and replaces on individual lines. Instead we build the script so that
* we can later do the operations on a block basis. For terminals with
* parm_delete or parm_insert strings this will be better in terms of the
* number of characters sent to delete and insert a block of lines.
*
* Also we can optimize the script so that tail inserts become replaces.
* This saves unnecessary inserts operations when the tail can just be
* overwritten.
*/
STATIC void
{
int i, j;
i = j = lr + 1;
do {
/* We don't have to bounds check i or j becuase row fr and
* column fr of lc have been preset in order to guarantee the
* correct motion.
*/
case 'i':
--j;
ins_rep[j] = lines_insert;
break;
case 'd':
--i;
del[i] = lines_delete;
break;
case 'm':
--i;
--j;
break;
case 'r':
--i;
--j;
ins_rep[j] = lines_replace;
break;
}
/* Optimize Tail Inserts */
/* Make each character in the screen line image invalid. */
ins_rep[i] = lines_replace;
}
}
/*f
*
* References:
* [MyM86] E.W. Myers & W. Miller, Row Replacement Algorithms for
* Screen Editors, TR 86-19, Dept. Computer Science, U. of Arizona
* [MyM87] E.W. Myers & W. Miller, A Simple Row Replacement Method,
* TR 86-28, Dept. Computer Science, U. of Arizona
* [Mil87] W. Miller, A Software Tools Sampler, Prentice-Hall, 1987
* [Gos81] James Gosling, A redisplay algorithm, Proceedings of the
* ACM Symposium on Text Manipulation, SIGPLAN Notices,
* 16(6) June 1981, pg 123-129
*
* All the above were reviewed and experimented with. Due to the nature of
* Curses' having to handling overlapping WINDOWs, the only suitable
* algorithum is [Gos81]. The others are better suited to editor type
* applications that have one window being the entire terminal screen.
*
*/
STATIC void
complex()
{
int i, j, lr;
/* Find block of lines to change */
for (i = 0; i < LINES; ++i) {
/* Compute new hash. */
if (fr == -1)
fr = i;
lr = i;
} else {
/* Line not dirty so hash same as before. */
}
}
if (fr != -1) {
/* Gosling */
/* Do deletes first in reverse order. */
for (i = j-1; fr <= i; --i)
break;
j = i;
}
}
/* Find size of block */
;
(*func)(i, j);
i = j-1;
}
}
/* _line[], which contains pointers to screen lines,
* may be shuffled.
*/
/* Save new hash for next update. */
/* Mark line as untouched. */
}
}
}
/*f
* Simple screen update algorithm
*
* We perform a simple incremental update of the terminal screen.
* Only the segment of a line that was touched is replaced on the
* line.
*/
STATIC void
simple()
{
int row;
/* Mark line as untouched. */
}
}
}
/*f
* Send all changes made to _newscr to the physical terminal.
*
* If idlok() is set TRUE then doupdate will try and use hardware insert
* and delete line sequences in an effort to optimize output. idlok()
* should really only be used in applications that want a proper scrolling
* effect.
*
* Added scroll heuristic to handle special case where a full size window
* with full size scroll region, will scroll the window and replace dirty
*/
int
doupdate()
{
#ifdef SIGTSTP
#endif
#ifdef M_CURSES_TYPEAHEAD
unsigned char cc;
/* Set up non-blocking input for typeahead trapping. */
}
#endif /* M_CURSES_TYPEAHEAD */
#ifdef M_CURSES_TRACE
"doupdate(void) using %s algorithm.",
);
#endif
/* Return from temporary escape done with endwin(). */
(void) reset_prog_mode();
if (enter_ca_mode != (char *) 0)
if (keypad_xmit != (char *) 0)
if (ena_acs != (char *) 0)
/* Force redraw of screen. */
}
#ifdef M_CURSES_TYPEAHEAD
}
#endif /* M_CURSES_TYPEAHEAD */
/* When redrawwing a window, we not only assume that line
* noise may have lost characters, but line noise may have
* generated bogus characters on the screen outside the
* the window in question, in which case redraw the entire
* screen to be sure.
*/
clear_bottom(0);
}
simple();
#if 0 /* This first expression, of undefined section, is useless
* since newscr->_scroll is unsigned and never LT zero.
*/
#else
#endif
;
;
complex();
else
simple();
#ifdef M_CURSES_TYPEAHEAD
}
/* Restore previous input mode. */
}
#endif /* M_CURSES_TYPEAHEAD */
#ifdef SIGTSTP
#endif
}
/*
* If true, the implementation may use hardware insert and delete,
* character features of the terminal. The window parameter
* is ignored.
*/
void
{
#ifdef M_CURSES_TRACE
#endif
if (bf)
__m_return_void("idcok");
}
/*
* If true, the implementation may use hardware insert, delete,
* and scroll line features of the terminal. The window parameter
* is ignored.
*/
int
{
#ifdef M_CURSES_TRACE
#endif
}
/*
* Use the POSIX 32-bit CRC function to compute a hash value
* for the window line.
*/
void
WINDOW *w;
unsigned long *array;
int y;
{
array[y] = 0;
);
}