summaryrefslogtreecommitdiffstats
path: root/lib/libcurses/lib_doupdate.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libcurses/lib_doupdate.c')
-rw-r--r--lib/libcurses/lib_doupdate.c840
1 files changed, 840 insertions, 0 deletions
diff --git a/lib/libcurses/lib_doupdate.c b/lib/libcurses/lib_doupdate.c
new file mode 100644
index 00000000000..3d6f2d79e38
--- /dev/null
+++ b/lib/libcurses/lib_doupdate.c
@@ -0,0 +1,840 @@
+
+/***************************************************************************
+* COPYRIGHT NOTICE *
+****************************************************************************
+* ncurses is copyright (C) 1992-1995 *
+* Zeyd M. Ben-Halim *
+* zmbenhal@netcom.com *
+* Eric S. Raymond *
+* esr@snark.thyrsus.com *
+* *
+* Permission is hereby granted to reproduce and distribute ncurses *
+* by any means and for any fee, whether alone or as part of a *
+* larger distribution, in source or in binary form, PROVIDED *
+* this notice is included with any such distribution, and is not *
+* removed from any of its header files. Mention of ncurses in any *
+* applications linked with it is highly appreciated. *
+* *
+* ncurses comes AS IS with no warranty, implied or expressed. *
+* *
+***************************************************************************/
+
+
+/*-----------------------------------------------------------------
+ *
+ * lib_doupdate.c
+ *
+ * The routine doupdate() and its dependents. Also _nc_outstr(),
+ * so all physcal output is concentrated here.
+ *
+ *-----------------------------------------------------------------*/
+
+#include "curses.priv.h"
+#include <stdlib.h>
+#include <sys/types.h>
+#if HAVE_SYS_TIME_H && ! SYSTEM_LOOKS_LIKE_SCO
+#include <sys/time.h>
+#endif
+#if HAVE_SYS_SELECT_H
+#include <sys/types.h>
+#include <sys/select.h>
+#endif
+#include <string.h>
+#include "term.h"
+
+/*
+ * This define controls the line-breakout optimization. Every once in a
+ * while during screen refresh, we want to check for input and abort the
+ * update if there's some waiting. CHECK_INTERVAL controls the number of
+ * changed lines to be emitted between input checks.
+ *
+ * Note: Input-check-and-abort is no longer done if the screen is being
+ * updated from scratch. This is a feature, not a bug.
+ */
+#define CHECK_INTERVAL 6
+
+/*
+ * Enable checking to see if doupdate and friends are tracking the true
+ * cursor position correctly. NOTE: this is a debugging hack which will
+ * work ONLY on ANSI-compatible terminals!
+ */
+/* #define POSITION_DEBUG */
+
+static void ClrUpdate( WINDOW *scr );
+static void TransformLine( int const lineno );
+static void NoIDcTransformLine( int const lineno );
+static void IDcTransformLine( int const lineno );
+static void ClearScreen( void );
+static int InsStr( chtype *line, int count );
+static void DelChar( int count );
+
+#define UpdateAttrs(c) if (curscr->_attrs != AttrOf(c)) { \
+ curscr->_attrs = AttrOf(c); \
+ vidputs(curscr->_attrs, _nc_outch); \
+ }
+
+#ifdef POSITION_DEBUG
+/****************************************************************************
+ *
+ * Debugging code. Only works on ANSI-standard terminals.
+ *
+ ****************************************************************************/
+
+void position_check(int expected_y, int expected_x, char *legend)
+/* check to see if the real cursor position matches the virtual */
+{
+ static char buf[9];
+ int y, x;
+
+ if (_nc_tracing)
+ return;
+
+ memset(buf, '\0', sizeof(buf));
+ (void) write(1, "\033[6n", 4); /* only works on ANSI-compatibles */
+ (void) read(0, (void *)buf, 8);
+ _tracef("probe returned %s", _nc_visbuf(buf));
+
+ /* try to interpret as a position report */
+ if (sscanf(buf, "\033[%d;%dR", &y, &x) != 2)
+ _tracef("position probe failed in %s", legend);
+ else if (y - 1 != expected_y || x - 1 != expected_x)
+ _tracef("position seen (%d, %d) doesn't match expected one (%d, %d) in %s",
+ y-1, x-1, expected_y, expected_x, legend);
+ else
+ _tracef("position matches OK in %s", legend);
+}
+#endif /* POSITION_DEBUG */
+
+/****************************************************************************
+ *
+ * Optimized update code
+ *
+ ****************************************************************************/
+
+static __inline void GoTo(int const row, int const col)
+{
+ chtype oldattr = SP->_current_attr;
+
+ TR(TRACE_MOVE, ("GoTo(%d, %d) from (%d, %d)",
+ row, col, SP->_cursrow, SP->_curscol));
+
+#ifdef POSITION_DEBUG
+ position_check(SP->_cursrow, SP->_curscol, "GoTo");
+#endif /* POSITION_DEBUG */
+
+ /*
+ * Force restore even if msgr is on when we're in an alternate
+ * character set -- these have a strong tendency to screw up the
+ * CR & LF used for local character motions!
+ */
+ if ((oldattr & A_ALTCHARSET)
+ || (oldattr && !move_standout_mode))
+ {
+ TR(TRACE_CHARPUT, ("turning off (%lx) %s before move",
+ oldattr, _traceattr(oldattr)));
+ vidattr(A_NORMAL);
+ curscr->_attrs = A_NORMAL;
+ }
+
+ mvcur(SP->_cursrow, SP->_curscol, row, col);
+ SP->_cursrow = row;
+ SP->_curscol = col;
+}
+
+static __inline void PutAttrChar(chtype ch)
+{
+ if (tilde_glitch && (TextOf(ch) == '~'))
+ ch = ('`' | AttrOf(ch));
+
+ TR(TRACE_CHARPUT, ("PutAttrChar(%s, %s) at (%d, %d)",
+ _tracechar((unsigned char)TextOf(ch)),
+ _traceattr(AttrOf(ch)),
+ SP->_cursrow, SP->_curscol));
+ UpdateAttrs(ch);
+ putc((int)TextOf(ch), SP->_ofp);
+ SP->_curscol++;
+ if (char_padding) {
+ TPUTS_TRACE("char_padding");
+ putp(char_padding);
+ }
+}
+
+static bool check_pending(void)
+/* check for pending input */
+{
+ if (SP->_checkfd >= 0) {
+ fd_set fdset;
+ struct timeval ktimeout;
+
+ ktimeout.tv_sec =
+ ktimeout.tv_usec = 0;
+
+ FD_ZERO(&fdset);
+ FD_SET(SP->_checkfd, &fdset);
+ if (select(SP->_checkfd+1, &fdset, NULL, NULL, &ktimeout) != 0)
+ {
+ fflush(SP->_ofp);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * No one supports recursive inline functions. However, gcc is quieter if we
+ * instantiate the recursive part separately.
+ */
+#if CC_HAS_INLINE_FUNCS
+static void callPutChar(chtype const);
+#else
+#define callPutChar(ch) PutChar(ch)
+#endif
+
+static __inline void PutChar(chtype const ch)
+/* insert character, handling automargin stuff */
+{
+ if (!(SP->_cursrow == screen_lines-1 && SP->_curscol == screen_columns-1
+ && auto_right_margin && !eat_newline_glitch))
+ {
+ PutAttrChar(ch); /* normal case */
+ }
+ else if (!auto_right_margin /* maybe we can suppress automargin */
+ || (enter_am_mode && exit_am_mode))
+ {
+ bool old_am = auto_right_margin;
+
+ if (old_am)
+ {
+ TPUTS_TRACE("exit_am_mode");
+ putp(exit_am_mode);
+ }
+ PutAttrChar(ch);
+ if (old_am)
+ {
+ TPUTS_TRACE("enter_am_mode");
+ putp(enter_am_mode);
+ }
+ }
+ else
+ {
+ GoTo(screen_lines-1,screen_columns-2);
+ callPutChar(ch);
+ GoTo(screen_lines-1,screen_columns-2);
+ if (InsStr(newscr->_line[screen_lines-1].text+screen_columns-2,1)==ERR)
+ return;
+ }
+
+ if (SP->_curscol >= screen_columns)
+ {
+ if (eat_newline_glitch)
+ {
+ /*
+ * xenl can manifest two different ways. The vt100
+ * way is that, when you'd expect the cursor to wrap,
+ * it stays hung at the right margin (on top of the
+ * character just emitted) and doesn't wrap until the
+ * *next* graphic char is emitted. The c100 way is
+ * to ignore LF received just after an am wrap.
+ *
+ * An aggressive way to handle this would be to
+ * emit CR/LF after the char and then assume the wrap
+ * is done, you're on the first position of the next
+ * line, and the terminal out of its weird state.
+ * Here it's safe to just tell the code that the
+ * cursor is in hyperspace and let the next mvcur()
+ * call straighten things out.
+ */
+ SP->_curscol = -1;
+ SP->_cursrow = -1;
+ }
+ else if (auto_right_margin)
+ {
+ SP->_curscol = 0;
+ SP->_cursrow++;
+ }
+ else
+ {
+ SP->_curscol--;
+ }
+ }
+#ifdef POSITION_DEBUG
+ position_check(SP->_cursrow, SP->_curscol, "PutChar");
+#endif /* POSITION_DEBUG */
+}
+
+#if CC_HAS_INLINE_FUNCS
+static void callPutChar(chtype const ch)
+{
+ PutChar(ch);
+}
+#endif
+
+int doupdate(void)
+{
+int i;
+
+ T(("doupdate() called"));
+
+#ifdef TRACE
+ if (_nc_tracing & TRACE_UPDATE)
+ {
+ if (curscr->_clear)
+ _tracef("curscr is clear");
+ else
+ _tracedump("curscr", curscr);
+ _tracedump("newscr", newscr);
+ }
+#endif /* TRACE */
+
+ _nc_signal_handler(FALSE);
+
+ if (SP->_endwin == TRUE) {
+ T(("coming back from shell mode"));
+ reset_prog_mode();
+ if (enter_ca_mode)
+ {
+ TPUTS_TRACE("enter_ca_mode");
+ putp(enter_ca_mode);
+ }
+ /*
+ * Undo the effects of terminal init strings that assume
+ * they know the screen size. Useful when you're running
+ * a vt100 emulation through xterm. Note: this may change
+ * the physical cursor location.
+ */
+ if (change_scroll_region)
+ {
+ TPUTS_TRACE("change_scroll_region");
+ putp(tparm(change_scroll_region, 0, screen_lines - 1));
+ }
+ _nc_mouse_resume(SP);
+ newscr->_clear = TRUE;
+ SP->_endwin = FALSE;
+ }
+
+ /*
+ * FIXME: Full support for magic-cookie terminals could go in here.
+ * The theory: we scan the virtual screen looking for attribute
+ * changes. Where we find one, check to make sure it's realizable
+ * by seeing if the required number of un-attributed blanks are
+ * present before or after the change. If not, nuke the attributes
+ * out of the following or preceding cells on the virtual screen,
+ * forward to the next change or backwards to the previous one. If
+ * so, displace the change by the required number of characters.
+ */
+
+ if (curscr->_clear) { /* force refresh ? */
+ T(("clearing and updating curscr"));
+ ClrUpdate(curscr); /* yes, clear all & update */
+ curscr->_clear = FALSE; /* reset flag */
+ } else {
+ if (newscr->_clear) {
+ T(("clearing and updating newscr"));
+ ClrUpdate(newscr);
+ newscr->_clear = FALSE;
+ } else {
+ int changedlines;
+
+ _nc_scroll_optimize();
+
+ T(("Transforming lines"));
+ for (i = changedlines = 0;
+ i < min(screen_lines,newscr->_maxy+1);
+ i++)
+ {
+ /*
+ * newscr->line[i].firstchar is normally set
+ * by wnoutrefresh. curscr->line[i].firstchar
+ * is normally set by _nc_scroll_window in the
+ * vertical-movement optimization code,
+ */
+ if (newscr->_line[i].firstchar != _NOCHANGE
+ || curscr->_line[i].firstchar != _NOCHANGE)
+ {
+ TransformLine(i);
+ changedlines++;
+ }
+
+ /* mark line changed successfully */
+ if (i <= newscr->_maxy)
+ {
+ newscr->_line[i].firstchar = _NOCHANGE;
+ newscr->_line[i].lastchar = _NOCHANGE;
+ newscr->_line[i].oldindex = i;
+ }
+ if (i <= curscr->_maxy)
+ {
+ curscr->_line[i].firstchar = _NOCHANGE;
+ curscr->_line[i].lastchar = _NOCHANGE;
+ curscr->_line[i].oldindex = i;
+ }
+
+ /*
+ * Here is our line-breakout optimization.
+ */
+ if ((changedlines % CHECK_INTERVAL) == changedlines-1
+ && check_pending())
+ goto cleanup;
+ }
+ }
+ }
+
+ /* this code won't be executed often */
+ for (i = screen_lines; i <= newscr->_maxy; i++)
+ {
+ newscr->_line[i].firstchar = _NOCHANGE;
+ newscr->_line[i].lastchar = _NOCHANGE;
+ newscr->_line[i].oldindex = i;
+ }
+ for (i = screen_lines; i <= curscr->_maxy; i++)
+ {
+ curscr->_line[i].firstchar = _NOCHANGE;
+ curscr->_line[i].lastchar = _NOCHANGE;
+ curscr->_line[i].oldindex = i;
+ }
+
+ curscr->_curx = newscr->_curx;
+ curscr->_cury = newscr->_cury;
+
+ GoTo(curscr->_cury, curscr->_curx);
+
+ cleanup:
+ if (curscr->_attrs != A_NORMAL)
+ vidattr(curscr->_attrs = A_NORMAL);
+
+ fflush(SP->_ofp);
+
+ _nc_signal_handler(TRUE);
+
+ return OK;
+}
+
+/*
+** ClrUpdate(scr)
+**
+** Update by clearing and redrawing the entire screen.
+**
+*/
+
+static void ClrUpdate(WINDOW *scr)
+{
+int i = 0, j = 0;
+int lastNonBlank;
+
+ T(("ClrUpdate(%p) called", scr));
+ if (back_color_erase) {
+ T(("back_color_erase, turning attributes off"));
+ vidattr(A_NORMAL);
+ }
+ ClearScreen();
+
+ if (scr != curscr) {
+ for (i = 0; i < screen_lines ; i++)
+ for (j = 0; j < screen_columns; j++)
+ curscr->_line[i].text[j] = ' '; /* shouldn't this include the bkgd? */
+ }
+
+ T(("updating screen from scratch"));
+ for (i = 0; i < min(screen_lines, scr->_maxy + 1); i++) {
+ GoTo(i, 0);
+ lastNonBlank = scr->_maxx;
+
+ while (scr->_line[i].text[lastNonBlank] == BLANK && lastNonBlank > 0)
+ lastNonBlank--;
+
+ for (j = 0; j <= min(lastNonBlank, screen_columns); j++) {
+ PutChar(scr->_line[i].text[j]);
+ }
+ }
+
+
+ if (scr != curscr) {
+ for (i = 0; i < screen_lines ; i++)
+ for (j = 0; j < screen_columns; j++)
+ curscr->_line[i].text[j] = scr->_line[i].text[j];
+ }
+}
+
+/*
+** ClrToEOL()
+**
+** Clear to EOL. Deal with background color erase if terminal has this
+** glitch. This code forces the current color and highlight to A_NORMAL
+** before emitting the erase sequence, then restores the current
+** attribute.
+*/
+
+static void ClrToEOL(void)
+{
+int j;
+attr_t oldcolor = 0; /* initialization pacifies -Wall */
+
+ if (back_color_erase) {
+ TPUTS_TRACE("orig_pair");
+ putp(orig_pair);
+ oldcolor = SP->_current_attr & A_COLOR;
+ SP->_current_attr &=~ A_COLOR;
+ }
+ TPUTS_TRACE("clr_eol");
+ putp(clr_eol);
+ if (back_color_erase)
+ vidattr(SP->_current_attr | oldcolor);
+
+ for (j = SP->_curscol; j < screen_columns; j++)
+ curscr->_line[SP->_cursrow].text[j] = ' ';
+}
+
+static void ClrToBOL(void)
+{
+int j;
+attr_t oldcolor = 0; /* initialization pacifies -Wall */
+
+ if (back_color_erase) {
+ TPUTS_TRACE("orig_pair");
+ putp(orig_pair);
+ oldcolor = SP->_current_attr & A_COLOR;
+ SP->_current_attr &=~ A_COLOR;
+ }
+ TPUTS_TRACE("clr_bol");
+ putp(clr_bol);
+ if (back_color_erase)
+ vidattr(SP->_current_attr | oldcolor);
+
+ for (j = 0; j <= SP->_curscol; j++)
+ curscr->_line[SP->_cursrow].text[j] = ' ';
+}
+
+/*
+** TransformLine(lineno)
+**
+** Call either IDcTransformLine or NoIDcTransformLine to do the
+** update, depending upon availability of insert/delete character.
+*/
+
+static void TransformLine(int const lineno)
+{
+
+ T(("TransformLine(%d) called",lineno));
+
+ if ( (insert_character || (enter_insert_mode && exit_insert_mode))
+ && delete_character)
+ IDcTransformLine(lineno);
+ else
+ NoIDcTransformLine(lineno);
+}
+
+
+
+/*
+** NoIDcTransformLine(lineno)
+**
+** Transform the given line in curscr to the one in newscr, without
+** using Insert/Delete Character.
+**
+** firstChar = position of first different character in line
+** lastChar = position of last different character in line
+**
+** overwrite all characters between firstChar and lastChar.
+**
+*/
+
+static void NoIDcTransformLine(int const lineno)
+{
+int firstChar, lastChar;
+chtype *newLine = newscr->_line[lineno].text;
+chtype *oldLine = curscr->_line[lineno].text;
+int k;
+int attrchanged = 0;
+
+ T(("NoIDcTransformLine(%d) called", lineno));
+
+ firstChar = 0;
+ while (firstChar < screen_columns - 1 && newLine[firstChar] == oldLine[firstChar]) {
+ if(ceol_standout_glitch) {
+ if(AttrOf(newLine[firstChar]) != AttrOf(oldLine[firstChar]))
+ attrchanged = 1;
+ }
+ firstChar++;
+ }
+
+ T(("first char at %d is %lx", firstChar, newLine[firstChar]));
+ if (firstChar > screen_columns)
+ return;
+
+ if(ceol_standout_glitch && attrchanged) {
+ firstChar = 0;
+ lastChar = screen_columns - 1;
+ GoTo(lineno, firstChar);
+ if(clr_eol)
+ ClrToEOL();
+ } else {
+ lastChar = screen_columns - 1;
+ while (lastChar > firstChar && newLine[lastChar] == oldLine[lastChar])
+ lastChar--;
+ GoTo(lineno, firstChar);
+ }
+
+ T(("updating chars %d to %d", firstChar, lastChar));
+ for (k = firstChar; k <= lastChar; k++) {
+ PutChar(newLine[k]);
+ oldLine[k] = newLine[k];
+ }
+}
+
+/*
+** IDcTransformLine(lineno)
+**
+** Transform the given line in curscr to the one in newscr, using
+** Insert/Delete Character.
+**
+** firstChar = position of first different character in line
+** oLastChar = position of last different character in old line
+** nLastChar = position of last different character in new line
+**
+** move to firstChar
+** overwrite chars up to min(oLastChar, nLastChar)
+** if oLastChar < nLastChar
+** insert newLine[oLastChar+1..nLastChar]
+** else
+** delete oLastChar - nLastChar spaces
+*/
+
+static void IDcTransformLine(int const lineno)
+{
+int firstChar, oLastChar, nLastChar;
+chtype *newLine = newscr->_line[lineno].text;
+chtype *oldLine = curscr->_line[lineno].text;
+int k, n;
+int attrchanged = 0;
+
+ T(("IDcTransformLine(%d) called", lineno));
+
+ if(ceol_standout_glitch && clr_eol) {
+ firstChar = 0;
+ while(firstChar < screen_columns) {
+ if(AttrOf(newLine[firstChar]) != AttrOf(oldLine[firstChar]))
+ attrchanged = 1;
+ firstChar++;
+ }
+ }
+
+ firstChar = 0;
+
+ if (attrchanged) {
+ GoTo(lineno, firstChar);
+ ClrToEOL();
+ for( k = 0 ; k <= (screen_columns-1) ; k++ )
+ PutChar(newLine[k]);
+ } else {
+ while (firstChar < screen_columns &&
+ newLine[firstChar] == oldLine[firstChar])
+ firstChar++;
+
+ if (firstChar >= screen_columns)
+ return;
+
+ if (clr_bol)
+ {
+ int oFirstChar, nFirstChar;
+
+ for (oFirstChar = 0; oFirstChar < screen_columns; oFirstChar++)
+ if (oldLine[oFirstChar] != BLANK)
+ break;
+ for (nFirstChar = 0; nFirstChar < screen_columns; nFirstChar++)
+ if (newLine[nFirstChar] != BLANK)
+ break;
+
+ if (nFirstChar > oFirstChar + (int)strlen(clr_bol))
+ {
+ GoTo(lineno, nFirstChar - 1);
+ ClrToBOL();
+
+ if(nFirstChar == screen_columns)
+ return;
+
+ if (nFirstChar > firstChar)
+ firstChar = nFirstChar;
+ }
+ }
+
+ oLastChar = screen_columns - 1;
+ while (oLastChar > firstChar && oldLine[oLastChar] == BLANK)
+ oLastChar--;
+
+ nLastChar = screen_columns - 1;
+ while (nLastChar > firstChar && newLine[nLastChar] == BLANK)
+ nLastChar--;
+
+ if((nLastChar == firstChar)
+ && clr_eol
+ && (curscr->_attrs == A_NORMAL)) {
+ GoTo(lineno, firstChar);
+ ClrToEOL();
+ if(newLine[firstChar] != BLANK )
+ PutChar(newLine[firstChar]);
+ } else if( newLine[nLastChar] != oldLine[oLastChar] ) {
+ n = max( nLastChar , oLastChar );
+
+ GoTo(lineno, firstChar);
+ for( k=firstChar ; k <= n ; k++ )
+ PutChar(newLine[k]);
+ } else {
+ while (newLine[nLastChar] == oldLine[oLastChar]) {
+ if (nLastChar != 0
+ && oLastChar != 0) {
+ nLastChar--;
+ oLastChar--;
+ } else {
+ break;
+ }
+ }
+
+ n = min(oLastChar, nLastChar);
+ GoTo(lineno, firstChar);
+
+ for (k=firstChar; k <= n; k++)
+ PutChar(newLine[k]);
+
+ if (oLastChar < nLastChar)
+ InsStr(&newLine[k], nLastChar - oLastChar);
+
+ else if (oLastChar > nLastChar ) {
+ /*
+ * The delete-char sequence will effectively
+ * shift in blanks from the right margin of the
+ * screen. Ensure that they are the right
+ * color by setting the video attributes from
+ * the last character on the row.
+ */
+ UpdateAttrs(newLine[screen_columns-1]);
+ DelChar(oLastChar - nLastChar);
+ }
+ }
+ }
+ for (k = firstChar; k < screen_columns; k++)
+ oldLine[k] = newLine[k];
+}
+
+/*
+** ClearScreen()
+**
+** Clear the physical screen and put cursor at home
+**
+*/
+
+static void ClearScreen(void)
+{
+
+ T(("ClearScreen() called"));
+
+ if (clear_screen) {
+ TPUTS_TRACE("clear_screen");
+ putp(clear_screen);
+ SP->_cursrow = SP->_curscol = 0;
+#ifdef POSITION_DEBUG
+ position_check(SP->_cursrow, SP->_curscol, "ClearScreen");
+#endif /* POSITION_DEBUG */
+ } else if (clr_eos) {
+ SP->_cursrow = SP->_curscol = -1;
+ GoTo(0,0);
+
+ TPUTS_TRACE("clr_eos");
+ putp(clr_eos);
+ } else if (clr_eol) {
+ SP->_cursrow = SP->_curscol = -1;
+
+ while (SP->_cursrow < screen_lines) {
+ GoTo(SP->_cursrow, 0);
+ TPUTS_TRACE("clr_eol");
+ putp(clr_eol);
+ }
+ GoTo(0,0);
+ }
+ T(("screen cleared"));
+}
+
+
+/*
+** InsStr(line, count)
+**
+** Insert the count characters pointed to by line.
+**
+*/
+
+static int InsStr(chtype *line, int count)
+{
+ T(("InsStr(%p,%d) called", line, count));
+
+ if (enter_insert_mode && exit_insert_mode) {
+ TPUTS_TRACE("enter_insert_mode");
+ putp(enter_insert_mode);
+ while (count) {
+ PutAttrChar(*line);
+ line++;
+ count--;
+ }
+ TPUTS_TRACE("exit_insert_mode");
+ putp(exit_insert_mode);
+ return(OK);
+ } else if (parm_ich) {
+ TPUTS_TRACE("parm_ich");
+ tputs(tparm(parm_ich, count), count, _nc_outch);
+ while (count) {
+ PutAttrChar(*line);
+ line++;
+ count--;
+ }
+ return(OK);
+ } else {
+ while (count) {
+ TPUTS_TRACE("insert_character");
+ putp(insert_character);
+ PutAttrChar(*line);
+ if (insert_padding)
+ {
+ TPUTS_TRACE("insert_padding");
+ putp(insert_padding);
+ }
+ line++;
+ count--;
+ }
+ return(OK);
+ }
+}
+
+/*
+** DelChar(count)
+**
+** Delete count characters at current position
+**
+*/
+
+static void DelChar(int count)
+{
+ T(("DelChar(%d) called, position = (%d,%d)", count, newscr->_cury, newscr->_curx));
+
+ if (parm_dch) {
+ TPUTS_TRACE("parm_dch");
+ tputs(tparm(parm_dch, count), count, _nc_outch);
+ } else {
+ while (count--)
+ {
+ TPUTS_TRACE("delete_character");
+ putp(delete_character);
+ }
+ }
+}
+
+/*
+** _nc_outstr(char *str)
+**
+** Emit a string without waiting for update.
+*/
+
+void _nc_outstr(char *str)
+{
+ FILE *ofp = SP ? SP->_ofp : stdout;
+
+ (void) fputs(str, ofp);
+ (void) fflush(ofp);
+}