1 /***************************************************************************
3 ****************************************************************************
4 * ncurses is copyright (C) 1992-1995 *
6 * zmbenhal@netcom.com *
8 * esr@snark.thyrsus.com *
10 * Permission is hereby granted to reproduce and distribute ncurses *
11 * by any means and for any fee, whether alone or as part of a *
12 * larger distribution, in source or in binary form, PROVIDED *
13 * this notice is included with any such distribution, and is not *
14 * removed from any of its header files. Mention of ncurses in any *
15 * applications linked with it is highly appreciated. *
17 * ncurses comes AS IS with no warranty, implied or expressed. *
19 ***************************************************************************/
22 /*-----------------------------------------------------------------
26 * The routine doupdate() and its dependents. Also _nc_outstr(),
27 * so all physical output is concentrated here (except _nc_outch()
30 *-----------------------------------------------------------------*/
32 #include <curses.priv.h>
34 #if defined(TRACE) && HAVE_SYS_TIMES_H && HAVE_TIMES
35 #define USE_TRACE_TIMES 1
37 #define USE_TRACE_TIMES 0
40 #if HAVE_SYS_TIME_H && ! SYSTEM_LOOKS_LIKE_SCO
45 #include <sys/times.h>
53 #include <sys/select.h>
59 MODULE_ID("$Id: lib_doupdate.c,v 1.60 1997/05/03 19:32:55 Alexander.V.Lukyanov Exp $")
62 * This define controls the line-breakout optimization. Every once in a
63 * while during screen refresh, we want to check for input and abort the
64 * update if there's some waiting. CHECK_INTERVAL controls the number of
65 * changed lines to be emitted between input checks.
67 * Note: Input-check-and-abort is no longer done if the screen is being
68 * updated from scratch. This is a feature, not a bug.
70 #define CHECK_INTERVAL 6
73 * Enable checking to see if doupdate and friends are tracking the true
74 * cursor position correctly. NOTE: this is a debugging hack which will
75 * work ONLY on ANSI-compatible terminals!
77 /* #define POSITION_DEBUG */
79 static inline chtype ClrBlank ( WINDOW *win );
80 static inline chtype ClrSetup ( WINDOW *scr );
81 static int ClrBottom(int total);
82 static int InsStr( chtype *line, int count );
83 static void ClearScreen( void );
84 static void ClrUpdate( WINDOW *scr );
85 static void DelChar( int count );
86 static void TransformLine( int const lineno );
89 /****************************************************************************
91 * Debugging code. Only works on ANSI-standard terminals.
93 ****************************************************************************/
95 void position_check(int expected_y, int expected_x, char *legend)
96 /* check to see if the real cursor position matches the virtual */
104 memset(buf, '\0', sizeof(buf));
105 (void) write(1, "\033[6n", 4); /* only works on ANSI-compatibles */
106 (void) read(0, (void *)buf, 8);
107 _tracef("probe returned %s", _nc_visbuf(buf));
109 /* try to interpret as a position report */
110 if (sscanf(buf, "\033[%d;%dR", &y, &x) != 2)
111 _tracef("position probe failed in %s", legend);
112 else if (y - 1 != expected_y || x - 1 != expected_x)
113 _tracef("position seen (%d, %d) doesn't match expected one (%d, %d) in %s",
114 y-1, x-1, expected_y, expected_x, legend);
116 _tracef("position matches OK in %s", legend);
118 #endif /* POSITION_DEBUG */
120 /****************************************************************************
122 * Optimized update code
124 ****************************************************************************/
126 static inline void GoTo(int const row, int const col)
128 chtype oldattr = SP->_current_attr;
130 TR(TRACE_MOVE, ("GoTo(%d, %d) from (%d, %d)",
131 row, col, SP->_cursrow, SP->_curscol));
133 #ifdef POSITION_DEBUG
134 position_check(SP->_cursrow, SP->_curscol, "GoTo");
135 #endif /* POSITION_DEBUG */
138 * Force restore even if msgr is on when we're in an alternate
139 * character set -- these have a strong tendency to screw up the
140 * CR & LF used for local character motions!
142 if ((oldattr & A_ALTCHARSET)
143 || (oldattr && !move_standout_mode))
145 TR(TRACE_CHARPUT, ("turning off (%#lx) %s before move",
146 oldattr, _traceattr(oldattr)));
150 mvcur(SP->_cursrow, SP->_curscol, row, col);
155 static inline void PutAttrChar(chtype ch)
157 if (tilde_glitch && (TextOf(ch) == '~'))
158 ch = ('`' | AttrOf(ch));
160 TR(TRACE_CHARPUT, ("PutAttrChar(%s) at (%d, %d)",
162 SP->_cursrow, SP->_curscol));
164 putc((int)TextOf(ch), SP->_ofp);
170 TPUTS_TRACE("char_padding");
175 static bool check_pending(void)
176 /* check for pending input */
178 if (SP->_checkfd >= 0) {
180 struct pollfd fds[1];
181 fds[0].fd = SP->_checkfd;
182 fds[0].events = POLLIN;
183 if (poll(fds, 1, 0) > 0)
190 struct timeval ktimeout;
193 ktimeout.tv_usec = 0;
196 FD_SET(SP->_checkfd, &fdset);
197 if (select(SP->_checkfd+1, &fdset, NULL, NULL, &ktimeout) > 0)
208 * No one supports recursive inline functions. However, gcc is quieter if we
209 * instantiate the recursive part separately.
211 #if CC_HAS_INLINE_FUNCS
212 static void callPutChar(chtype const);
214 #define callPutChar(ch) PutChar(ch)
217 static inline void PutChar(chtype const ch)
218 /* insert character, handling automargin stuff */
220 if (!(SP->_cursrow == screen_lines-1 && SP->_curscol == screen_columns-1
221 && auto_right_margin && !eat_newline_glitch))
223 PutAttrChar(ch); /* normal case */
225 else if (!auto_right_margin /* maybe we can suppress automargin */
226 || (enter_am_mode && exit_am_mode))
228 bool old_am = auto_right_margin;
232 TPUTS_TRACE("exit_am_mode");
238 TPUTS_TRACE("enter_am_mode");
244 GoTo(screen_lines-1,screen_columns-2);
246 GoTo(screen_lines-1,screen_columns-2);
247 if (InsStr(newscr->_line[screen_lines-1].text+screen_columns-2,1)==ERR)
251 if (SP->_curscol >= screen_columns)
253 if (eat_newline_glitch)
256 * xenl can manifest two different ways. The vt100
257 * way is that, when you'd expect the cursor to wrap,
258 * it stays hung at the right margin (on top of the
259 * character just emitted) and doesn't wrap until the
260 * *next* graphic char is emitted. The c100 way is
261 * to ignore LF received just after an am wrap.
263 * An aggressive way to handle this would be to
264 * emit CR/LF after the char and then assume the wrap
265 * is done, you're on the first position of the next
266 * line, and the terminal out of its weird state.
267 * Here it's safe to just tell the code that the
268 * cursor is in hyperspace and let the next mvcur()
269 * call straighten things out.
274 else if (auto_right_margin)
284 #ifdef POSITION_DEBUG
285 position_check(SP->_cursrow, SP->_curscol, "PutChar");
286 #endif /* POSITION_DEBUG */
290 * Issue a given span of characters from an array.
291 * Must be functionally equivalent to:
292 * for (i = 0; i < num; i++)
294 * but can leave the cursor positioned at the middle of the interval.
296 * Returns: 0 - cursor is at the end of interval
297 * 1 - cursor is somewhere in the middle
299 * This code is optimized using ech and rep.
301 static inline int EmitRange(const chtype *ntext, int num)
305 if (erase_chars || repeat_char)
312 while (num>1 && ntext[0]!=ntext[1])
326 while (runcount < num && ntext[runcount] == ntext0)
330 * The cost expression in the middle isn't exactly right.
331 * _cup_cost is an upper bound on the cost for moving to the
332 * end of the erased area, but not the cost itself (which we
333 * can't compute without emitting the move). This may result
334 * in erase_chars not getting used in some situations for
335 * which it would be marginally advantageous.
338 && runcount > SP->_ech_cost + SP->_cup_cost
339 && can_clear_with(ntext0))
342 putp(tparm(erase_chars, runcount));
345 * If this is the last part of the given interval,
346 * don't bother moving cursor, since it can be the
347 * last update on the line.
350 GoTo(SP->_cursrow, SP->_curscol + runcount);
352 return 1; /* cursor stays in the middle */
354 else if (repeat_char && runcount > SP->_rep_cost)
356 bool wrap_possible = (SP->_curscol + runcount >= screen_columns);
357 int rep_count = runcount;
363 putp(tparm(repeat_char, TextOf(ntext0), rep_count));
364 SP->_curscol += rep_count;
371 for (i = 0; i < runcount; i++)
380 for (i = 0; i < num; i++)
386 * Output the line in the given range [first .. last]
388 * If there's a run of identical characters that's long enough to justify
389 * cursor movement, use that also.
391 * Returns: same as EmitRange
400 int cost = min(SP->_cup_ch_cost, SP->_hpa_ch_cost);
402 TR(TRACE_CHARPUT, ("PutRange(%p, %p, %d, %d, %d)",
403 otext, ntext, row, first, last));
406 && (last-first+1) > cost) {
407 for (j = first, run = 0; j <= last; j++) {
408 if (otext[j] == ntext[j]) {
412 int before_run = (j - run);
413 EmitRange(ntext+first, before_run-first);
414 GoTo(row, first = j);
420 return EmitRange(ntext + first, last-first+1);
423 #if CC_HAS_INLINE_FUNCS
424 static void callPutChar(chtype const ch)
430 #define MARK_NOCHANGE(win,row) \
432 win->_line[row].firstchar = _NOCHANGE; \
433 win->_line[row].lastchar = _NOCHANGE; \
434 win->_line[row].oldindex = row; \
442 struct tms before, after;
443 #endif /* USE_TRACE_TIMES */
445 T((T_CALLED("doupdate()")));
448 if (_nc_tracing & TRACE_UPDATE)
451 _tracef("curscr is clear");
453 _tracedump("curscr", curscr);
454 _tracedump("newscr", newscr);
458 _nc_signal_handler(FALSE);
460 if (SP->_endwin == TRUE) {
462 T(("coming back from shell mode"));
466 * This is a transparent extension: XSI does not address it,
467 * and applications need not know that ncurses can do it.
469 * Check if the terminal size has changed while curses was off
470 * (this can happen in an xterm, for example), and resize the
471 * ncurses data structures accordingly.
473 _nc_get_screensize();
474 resizeterm(LINES, COLS);
477 _nc_mouse_resume(SP);
478 newscr->_clear = TRUE;
483 /* zero the metering machinery */
485 (void) times(&before);
486 #endif /* USE_TRACE_TIMES */
489 * This is the support for magic-cookie terminals. The
490 * theory: we scan the virtual screen looking for attribute
491 * turnons. Where we find one, check to make sure it's
492 * realizable by seeing if the required number of
493 * un-attributed blanks are present before and after the
494 * attributed range; try to shift the range boundaries over
495 * blanks (not changing the screen display) so this becomes
496 * true. If it is, shift the beginning attribute change
497 * appropriately (the end one, if we've gotten this far, is
498 * guaranteed room for its cookie). If not, nuke the added
499 * attributes out of the span.
501 if (magic_cookie_glitch > 0) {
503 attr_t rattr = A_NORMAL;
505 for (i = 0; i < screen_lines; i++)
506 for (j = 0; j < screen_columns; j++)
509 chtype turnon = AttrOf(newscr->_line[i].text[j]) & ~rattr;
511 /* is an attribute turned on here? */
515 T(("At (%d, %d): from %s...", i, j, _traceattr(rattr)));
516 T(("...to %s",_traceattr(turnon)));
519 * If the attribute change location is a blank with a
520 * "safe" attribute, undo the attribute turnon. This may
521 * ensure there's enough room to set the attribute before
522 * the first non-blank in the run.
524 #define SAFE(a) !((a) & ~NONBLANK_ATTR)
525 if (TextOf(newscr->_line[i].text[j])==' ' && SAFE(turnon))
527 newscr->_line[i].text[j] &= ~turnon;
531 /* check that there's enough room at start of span */
532 for (k = 1; k <= magic_cookie_glitch; k++)
534 || TextOf(newscr->_line[i].text[j-k]) != ' '
535 || !SAFE(AttrOf(newscr->_line[i].text[j-k])))
539 bool end_onscreen = FALSE;
542 /* find end of span, if it's onscreen */
543 for (m = i; m < screen_lines; m++)
544 for (n = j; n < screen_columns; n++)
545 if (AttrOf(newscr->_line[m].text[n]) == rattr)
548 T(("Range attributed with %s ends at (%d, %d)",
549 _traceattr(turnon),m,n));
552 T(("Range attributed with %s ends offscreen",
553 _traceattr(turnon)));
558 chtype *lastline = newscr->_line[m].text;
561 * If there are safely-attributed blanks at the
562 * end of the range, shorten the range. This will
563 * help ensure that there is enough room at end
567 && TextOf(lastline[n]) == ' '
568 && SAFE(AttrOf(lastline[n])))
569 lastline[n--] &=~ turnon;
571 /* check that there's enough room at end of span */
572 for (k = 1; k <= magic_cookie_glitch; k++)
573 if (n + k >= screen_columns
574 || TextOf(lastline[n + k]) != ' '
575 || !SAFE(AttrOf(lastline[n+k])))
584 T(("Clearing %s beginning at (%d, %d)",
585 _traceattr(turnon), i, j));
587 /* turn off new attributes over span */
588 for (p = i; p < screen_lines; p++)
589 for (q = j; q < screen_columns; q++)
590 if (AttrOf(newscr->_line[p].text[q]) == rattr)
593 newscr->_line[p].text[q] &=~ turnon;
598 T(("Cookie space for %s found before (%d, %d)",
599 _traceattr(turnon), i, j));
602 * back up the start of range so there's room
603 * for cookies before the first nonblank character
605 for (k = 1; k <= magic_cookie_glitch; k++)
606 newscr->_line[i].text[j-k] |= turnon;
609 rattr = AttrOf(newscr->_line[i].text[j]);
613 /* show altered highlights after magic-cookie check */
614 if (_nc_tracing & TRACE_UPDATE)
616 _tracef("After magic-cookie check...");
617 _tracedump("newscr", newscr);
623 if (curscr->_clear) { /* force refresh ? */
624 T(("clearing and updating curscr"));
625 ClrUpdate(newscr); /* yes, clear all & update */
626 curscr->_clear = FALSE; /* reset flag */
627 } else if (newscr->_clear) {
628 T(("clearing and updating newscr"));
630 newscr->_clear = FALSE;
634 nonempty = min(screen_lines, newscr->_maxy+1);
635 #if 0 /* still 5% slower 960928 */
636 #if defined(TRACE) || defined(NCURSES_TEST)
637 if (_nc_optimize_enable & OPTIMIZE_HASHMAP)
641 #if defined(TRACE) || defined(NCURSES_TEST)
642 if (_nc_optimize_enable & OPTIMIZE_SCROLL)
644 _nc_scroll_optimize();
647 nonempty = ClrBottom(nonempty);
649 T(("Transforming lines, nonempty %d", nonempty));
650 for (i = changedlines = 0; i < nonempty; i++) {
652 * newscr->line[i].firstchar is normally set
653 * by wnoutrefresh. curscr->line[i].firstchar
654 * is normally set by _nc_scroll_window in the
655 * vertical-movement optimization code,
657 if (newscr->_line[i].firstchar != _NOCHANGE
658 || curscr->_line[i].firstchar != _NOCHANGE)
664 /* mark line changed successfully */
665 if (i <= newscr->_maxy)
666 MARK_NOCHANGE(newscr,i)
667 if (i <= curscr->_maxy)
668 MARK_NOCHANGE(curscr,i)
671 * Here is our line-breakout optimization.
673 if ((changedlines % CHECK_INTERVAL) == CHECK_INTERVAL-1
679 /* put everything back in sync */
680 for (i = nonempty; i <= newscr->_maxy; i++)
681 MARK_NOCHANGE(newscr,i)
682 for (i = nonempty; i <= curscr->_maxy; i++)
683 MARK_NOCHANGE(curscr,i)
685 curscr->_curx = newscr->_curx;
686 curscr->_cury = newscr->_cury;
688 GoTo(curscr->_cury, curscr->_curx);
692 * Keep the physical screen in normal mode in case we get other
693 * processes writing to the screen.
695 UpdateAttrs(A_NORMAL);
698 curscr->_attrs = newscr->_attrs;
699 /* curscr->_bkgd = newscr->_bkgd; */
702 (void) times(&after);
703 TR(TRACE_TIMES, ("Update cost: %ld chars, %ld clocks system time, %ld clocks user time",
705 after.tms_stime-before.tms_stime,
706 after.tms_utime-before.tms_utime));
707 #endif /* USE_TRACE_TIMES */
709 _nc_signal_handler(TRUE);
717 * Returns the attributed character that corresponds to the "cleared"
718 * screen. If the terminal has the back-color-erase feature, this will be
719 * colored according to the wbkgd() call. (Other attributes are
720 * unspecified, hence assumed to be reset in accordance with
723 * We treat 'curscr' specially because it isn't supposed to be set directly
724 * in the wbkgd() call. Assume 'stdscr' for this case.
726 #define BCE_ATTRS (A_NORMAL|A_COLOR)
727 #define BCE_BKGD(win) (((win) == curscr ? stdscr : (win))->_bkgd)
729 static inline chtype ClrBlank (WINDOW *win)
731 chtype blank = BLANK;
732 if (back_color_erase)
733 blank |= (BCE_BKGD(win) & BCE_ATTRS);
740 * Ensures that if the terminal recognizes back-color-erase, that we
741 * set the video attributes to match the window's background color
742 * before an erase operation.
744 static inline chtype ClrSetup (WINDOW *win)
746 if (back_color_erase)
747 vidattr(BCE_BKGD(win) & BCE_ATTRS);
748 return ClrBlank(win);
754 ** Update by clearing and redrawing the entire screen.
758 static void ClrUpdate(WINDOW *scr)
762 chtype blank = ClrSetup(scr);
764 T(("ClrUpdate(%p) called", scr));
768 for (i = 0; i < screen_lines ; i++)
769 for (j = 0; j < screen_columns; j++)
770 curscr->_line[i].text[j] = blank;
773 T(("updating screen from scratch"));
774 for (i = 0; i < min(screen_lines, scr->_maxy + 1); i++) {
775 lastNonBlank = scr->_maxx;
777 while (lastNonBlank >= 0
778 && scr->_line[i].text[lastNonBlank] == blank)
781 if (lastNonBlank >= 0) {
782 if (lastNonBlank > screen_columns)
783 lastNonBlank = screen_columns;
785 PutRange(curscr->_line[i].text,
786 scr->_line[i].text, i, 0, lastNonBlank);
791 for (i = 0; i < screen_lines ; i++)
792 memcpy(curscr->_line[i].text,
794 screen_columns * sizeof(chtype));
801 ** Clear to end of current line, starting at the cursor position
804 static void ClrToEOL(chtype blank)
807 bool needclear = FALSE;
809 for (j = SP->_curscol; j < screen_columns; j++)
811 chtype *cp = &(curscr->_line[SP->_cursrow].text[j]);
823 TPUTS_TRACE("clr_eol");
824 if (SP->_el_cost > (screen_columns - SP->_curscol))
826 int count = (screen_columns - SP->_curscol);
838 * Test if clearing the end of the screen would satisfy part of the
839 * screen-update. Do this by scanning backwards through the lines in the
840 * screen, checking if each is blank, and one or more are changed.
842 static int ClrBottom(int total)
844 static chtype *tstLine;
845 static size_t lenLine;
849 int last = min(screen_columns, newscr->_maxx+1);
850 size_t length = sizeof(chtype) * last;
851 chtype blank = newscr->_line[total-1].text[last-1]; /* lower right char */
853 if(!can_clear_with(blank))
857 tstLine = (chtype *)malloc(length);
858 else if (length > lenLine)
859 tstLine = (chtype *)realloc(tstLine, length);
863 for (col = 0; col < last; col++)
864 tstLine[col] = blank;
866 for (row = total-1; row >= 0; row--) {
867 if (memcmp(tstLine, newscr->_line[row].text, length))
869 if (newscr->_line[row].firstchar != _NOCHANGE)
876 TPUTS_TRACE("clr_eos");
878 while (total-- > top) {
879 for (col = 0; col <= curscr->_maxx; col++)
880 curscr->_line[total].text[col] = blank;
886 FreeAndNull(tstLine);
893 ** TransformLine(lineno)
895 ** Transform the given line in curscr to the one in newscr, using
896 ** Insert/Delete Character if _nc_idcok && has_ic().
898 ** firstChar = position of first different character in line
899 ** oLastChar = position of last different character in old line
900 ** nLastChar = position of last different character in new line
903 ** overwrite chars up to min(oLastChar, nLastChar)
904 ** if oLastChar < nLastChar
905 ** insert newLine[oLastChar+1..nLastChar]
907 ** delete oLastChar - nLastChar spaces
910 static void TransformLine(int const lineno)
912 int firstChar, oLastChar, nLastChar;
913 chtype *newLine = newscr->_line[lineno].text;
914 chtype *oldLine = curscr->_line[lineno].text;
916 bool attrchanged = FALSE;
918 T(("TransformLine(%d) called", lineno));
920 if(ceol_standout_glitch && clr_eol) {
922 while(firstChar < screen_columns) {
923 if(AttrOf(newLine[firstChar]) != AttrOf(oldLine[firstChar]))
931 if (attrchanged) { /* we may have to disregard the whole line */
932 GoTo(lineno, firstChar);
933 ClrToEOL(ClrBlank(curscr));
934 PutRange(oldLine, newLine, lineno, 0, (screen_columns-1));
938 /* find the first differing character */
939 while (firstChar < screen_columns &&
940 newLine[firstChar] == oldLine[firstChar])
943 /* if there wasn't one, we're done */
944 if (firstChar >= screen_columns)
947 /* it may be cheap to clear leading whitespace with clr_bol */
948 if (clr_bol && can_clear_with(blank=newLine[0]))
950 int oFirstChar, nFirstChar;
952 for (oFirstChar = 0; oFirstChar < screen_columns; oFirstChar++)
953 if (oldLine[oFirstChar] != blank)
955 for (nFirstChar = 0; nFirstChar < screen_columns; nFirstChar++)
956 if (newLine[nFirstChar] != blank)
959 if (nFirstChar > oFirstChar + SP->_el1_cost)
961 GoTo(lineno, nFirstChar - 1);
963 TPUTS_TRACE("clr_bol");
966 while (firstChar < nFirstChar)
967 oldLine[firstChar++] = blank;
969 if (firstChar >= screen_columns)
974 blank = newLine[screen_columns-1];
976 if(!can_clear_with(blank))
978 /* find the last differing character */
979 nLastChar = screen_columns - 1;
981 while (nLastChar > firstChar
982 && newLine[nLastChar] == oldLine[nLastChar])
985 if (nLastChar >= firstChar) {
986 GoTo(lineno, firstChar);
987 PutRange(oldLine, newLine, lineno, firstChar, nLastChar);
988 memcpy( oldLine + firstChar,
990 (nLastChar - firstChar + 1) * sizeof(chtype));
995 /* find last non-blank character on old line */
996 oLastChar = screen_columns - 1;
997 while (oLastChar > firstChar && oldLine[oLastChar] == blank)
1000 /* find last non-blank character on new line */
1001 nLastChar = screen_columns - 1;
1002 while (nLastChar > firstChar && newLine[nLastChar] == blank)
1005 if((nLastChar == firstChar)
1006 && (SP->_el_cost < (screen_columns - nLastChar))) {
1007 GoTo(lineno, firstChar);
1009 if(newLine[firstChar] != blank )
1010 PutChar(newLine[firstChar]);
1011 } else if( newLine[nLastChar] != oldLine[oLastChar]
1012 || !(_nc_idcok && has_ic()) ) {
1013 GoTo(lineno, firstChar);
1014 if ((oLastChar - nLastChar) > SP->_el_cost) {
1015 if(PutRange(oldLine, newLine, lineno, firstChar, nLastChar))
1016 GoTo(lineno, nLastChar+1);
1019 n = max( nLastChar , oLastChar );
1020 PutRange(oldLine, newLine, lineno, firstChar, n);
1023 int nLastNonblank = nLastChar;
1024 int oLastNonblank = oLastChar;
1026 /* find the last characters that really differ */
1027 while (newLine[nLastChar] == oldLine[oLastChar]) {
1029 && oLastChar != 0) {
1037 n = min(oLastChar, nLastChar);
1038 if (n >= firstChar) {
1039 GoTo(lineno, firstChar);
1040 PutRange(oldLine, newLine, lineno, firstChar, n);
1044 if (oLastChar < nLastChar) {
1045 int m = max(nLastNonblank, oLastNonblank);
1046 if (InsCharCost(nLastChar - oLastChar)
1048 PutRange(oldLine, newLine, lineno, n+1, m);
1050 InsStr(&newLine[n+1], nLastChar - oLastChar);
1052 } else if (oLastChar > nLastChar ) {
1053 if (DelCharCost(oLastChar - nLastChar)
1054 > SP->_el_cost + nLastNonblank - (n+1)) {
1055 if(PutRange(oldLine, newLine, lineno,
1056 n+1, nLastNonblank))
1057 GoTo(lineno, nLastNonblank+1);
1061 * The delete-char sequence will
1062 * effectively shift in blanks from the
1063 * right margin of the screen. Ensure
1064 * that they are the right color by
1065 * setting the video attributes from
1066 * the last character on the row.
1069 DelChar(oLastChar - nLastChar);
1075 /* update the code's internal representation */
1076 if (screen_columns > firstChar)
1077 memcpy( oldLine + firstChar,
1078 newLine + firstChar,
1079 (screen_columns - firstChar) * sizeof(chtype));
1085 ** Clear the physical screen and put cursor at home
1089 static void ClearScreen(void)
1092 T(("ClearScreen() called"));
1095 TPUTS_TRACE("clear_screen");
1097 SP->_cursrow = SP->_curscol = 0;
1098 #ifdef POSITION_DEBUG
1099 position_check(SP->_cursrow, SP->_curscol, "ClearScreen");
1100 #endif /* POSITION_DEBUG */
1101 } else if (clr_eos) {
1102 SP->_cursrow = SP->_curscol = -1;
1105 TPUTS_TRACE("clr_eos");
1107 } else if (clr_eol) {
1108 SP->_cursrow = SP->_curscol = -1;
1110 while (SP->_cursrow < screen_lines) {
1111 GoTo(SP->_cursrow, 0);
1112 TPUTS_TRACE("clr_eol");
1117 T(("screen cleared"));
1122 ** InsStr(line, count)
1124 ** Insert the count characters pointed to by line.
1128 static int InsStr(chtype *line, int count)
1130 T(("InsStr(%p,%d) called", line, count));
1132 if (enter_insert_mode && exit_insert_mode) {
1133 TPUTS_TRACE("enter_insert_mode");
1134 putp(enter_insert_mode);
1140 TPUTS_TRACE("exit_insert_mode");
1141 putp(exit_insert_mode);
1143 } else if (parm_ich) {
1144 TPUTS_TRACE("parm_ich");
1145 tputs(tparm(parm_ich, count), count, _nc_outch);
1154 TPUTS_TRACE("insert_character");
1155 putp(insert_character);
1159 TPUTS_TRACE("insert_padding");
1160 putp(insert_padding);
1172 ** Delete count characters at current position
1176 static void DelChar(int count)
1178 T(("DelChar(%d) called, position = (%d,%d)", count, newscr->_cury, newscr->_curx));
1181 TPUTS_TRACE("parm_dch");
1182 tputs(tparm(parm_dch, count), count, _nc_outch);
1186 TPUTS_TRACE("delete_character");
1187 putp(delete_character);
1193 ** _nc_outstr(char *str)
1195 ** Emit a string without waiting for update.
1198 void _nc_outstr(const char *str)
1200 FILE *ofp = SP ? SP->_ofp : stdout;
1202 (void) fputs(str, ofp);
1206 _nc_outchars += strlen(str);