27856896b0a4be6ffbff6cba3de36fa8a595623e
12 #define CL_ANSIMIN 0x0001 /* Codes in all ANSI like terminals. */
13 #define CL_VT100 0x0002 /* VT100 */
14 #define CL_VT100AVO 0x0004 /* VT100 +AVO; 132x24 (not 132x14) & attrs */
15 #define CL_VT102 0x0008 /* VT102 */
16 #define CL_VT220 0x0010 /* VT220 */
17 #define CL_VT320 0x0020 /* VT320 */
18 #define CL_VT420 0x0040 /* VT420 */
19 #define CL_VT510 0x0080 /* VT510, NB VT510 includes ANSI */
20 #define CL_VT340TEXT 0x0100 /* VT340 extensions that appear in the VT420 */
21 #define CL_SCOANSI 0x1000 /* SCOANSI not in ANSIMIN. */
22 #define CL_ANSI 0x2000 /* ANSI ECMA-48 not in the VT100..VT420 */
23 #define CL_OTHER 0x4000 /* Others, Xterm, linux, putty, dunno, etc */
25 #define TM_VT100 (CL_ANSIMIN|CL_VT100)
26 #define TM_VT100AVO (TM_VT100|CL_VT100AVO)
27 #define TM_VT102 (TM_VT100AVO|CL_VT102)
28 #define TM_VT220 (TM_VT102|CL_VT220)
29 #define TM_VTXXX (TM_VT220|CL_VT340TEXT|CL_VT510|CL_VT420|CL_VT320)
30 #define TM_SCOANSI (CL_ANSIMIN|CL_SCOANSI)
32 #define TM_PUTTY (0xFFFF)
34 #define compatibility(x) \
35 if ( ((CL_##x)&compatibility_level) == 0 ) { \
39 #define compatibility2(x,y) \
40 if ( ((CL_##x|CL_##y)&compatibility_level) == 0 ) { \
45 #define has_compat(x) ( ((CL_##x)&compatibility_level) != 0 )
47 static int compatibility_level
= TM_PUTTY
;
49 static tree234
*scrollback
; /* lines scrolled off top of screen */
50 static tree234
*screen
; /* lines on primary screen */
51 static tree234
*alt_screen
; /* lines on alternate screen */
52 static int disptop
; /* distance scrolled back (0 or -ve) */
54 static unsigned long *cpos
; /* cursor position (convenience) */
56 static unsigned long *disptext
; /* buffer of text on real screen */
57 static unsigned long *dispcurs
; /* location of cursor on real screen */
58 static unsigned long curstype
; /* type of cursor on real screen */
60 #define VBELL_TIMEOUT (TICKSPERSEC/10) /* visual bell lasts 1/10 sec */
63 struct beeptime
*next
;
66 static struct beeptime
*beephead
, *beeptail
;
71 #define TSIZE (sizeof(unsigned long))
72 #define fix_cpos do { cpos = lineptr(curs.y) + curs.x; } while(0)
74 static unsigned long curr_attr
, save_attr
;
75 static unsigned long erase_char
= ERASE_CHAR
;
80 #define poslt(p1,p2) ( (p1).y < (p2).y || ( (p1).y == (p2).y && (p1).x < (p2).x ) )
81 #define posle(p1,p2) ( (p1).y < (p2).y || ( (p1).y == (p2).y && (p1).x <= (p2).x ) )
82 #define poseq(p1,p2) ( (p1).y == (p2).y && (p1).x == (p2).x )
83 #define posdiff(p1,p2) ( ((p1).y - (p2).y) * (cols+1) + (p1).x - (p2).x )
84 #define incpos(p) ( (p).x == cols ? ((p).x = 0, (p).y++, 1) : ((p).x++, 0) )
85 #define decpos(p) ( (p).x == 0 ? ((p).x = cols, (p).y--, 1) : ((p).x--, 0) )
87 /* Product-order comparisons for rectangular block selection. */
88 #define posPlt(p1,p2) ( (p1).y <= (p2).y && (p1).x < (p2).x )
89 #define posPle(p1,p2) ( (p1).y <= (p2).y && (p1).x <= (p2).x )
91 static bufchain inbuf
; /* terminal input buffer */
92 static pos curs
; /* cursor */
93 static pos savecurs
; /* saved cursor position */
94 static int marg_t
, marg_b
; /* scroll margins */
95 static int dec_om
; /* DEC origin mode flag */
96 static int wrap
, wrapnext
; /* wrap flags */
97 static int insert
; /* insert-mode flag */
98 static int cset
; /* 0 or 1: which char set */
99 static int save_cset
, save_csattr
; /* saved with cursor position */
100 static int save_utf
, save_wnext
; /* saved with cursor position */
101 static int rvideo
; /* global reverse video flag */
102 static unsigned long rvbell_startpoint
;/* for ESC[?5hESC[?5l vbell */
103 static int cursor_on
; /* cursor enabled flag */
104 static int reset_132
; /* Flag ESC c resets to 80 cols */
105 static int use_bce
; /* Use Background coloured erase */
106 static int blinker
; /* When blinking is the cursor on ? */
107 static int tblinker
; /* When the blinking text is on */
108 static int blink_is_real
; /* Actually blink blinking text */
109 static int term_echoing
; /* Does terminal want local echo? */
110 static int term_editing
; /* Does terminal want local edit? */
111 static int sco_acs
, save_sco_acs
; /* CSI 10,11,12m -> OEM charset */
112 static int vt52_bold
; /* Force bold on non-bold colours */
113 static int utf_state
; /* Is there a pending UTF-8 character */
114 static int utf_char
; /* and what is it so far. */
115 static int utf_size
; /* The size of the UTF character. */
116 static int printing
, only_printing
; /* Are we doing ANSI printing? */
117 static int print_state
; /* state of print-end-sequence scan */
118 static bufchain printer_buf
; /* buffered data for printer */
119 static printer_job
*print_job
;
121 static int xterm_mouse
; /* send mouse messages to app */
123 static unsigned long cset_attr
[2];
126 * Saved settings on the alternate screen.
128 static int alt_x
, alt_y
, alt_om
, alt_wrap
, alt_wnext
, alt_ins
, alt_cset
, alt_sco_acs
, alt_utf
;
129 static int alt_t
, alt_b
;
130 static int alt_which
;
132 #define ARGS_MAX 32 /* max # of esc sequence arguments */
133 #define ARG_DEFAULT 0 /* if an arg isn't specified */
134 #define def(a,d) ( (a) == ARG_DEFAULT ? (d) : (a) )
135 static int esc_args
[ARGS_MAX
];
136 static int esc_nargs
;
137 static int esc_query
;
138 #define ANSI(x,y) ((x)+((y)<<8))
139 #define ANSI_QUE(x) ANSI(x,TRUE)
141 #define OSC_STR_MAX 2048
142 static int osc_strlen
;
143 static char osc_string
[OSC_STR_MAX
+ 1];
146 static char id_string
[1024] = "\033[?6c";
148 static unsigned char *tabs
;
160 OSC_STRING
, OSC_MAYBE_ST
,
169 NO_SELECTION
, ABOUT_TO
, DRAGGING
, SELECTED
172 LEXICOGRAPHIC
, RECTANGULAR
175 SM_CHAR
, SM_WORD
, SM_LINE
177 static pos selstart
, selend
, selanchor
;
179 static short wordness
[256] = {
180 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
181 0, 0, 0, 0, 0, 0, 0, 0, /* 01 */
182 0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
183 2, 2, 1, 1, 1, 1, 1, 1, /* 23 */
184 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
185 2, 2, 2, 1, 1, 1, 1, 2, /* 45 */
186 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
187 2, 2, 2, 1, 1, 1, 1, 1, /* 67 */
188 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
189 1, 1, 1, 1, 1, 1, 1, 1, /* 89 */
190 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
191 1, 1, 1, 1, 1, 1, 1, 1, /* AB */
192 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
193 2, 2, 2, 2, 2, 2, 2, 2, /* CD */
194 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
195 2, 2, 2, 2, 2, 2, 2, 2, /* EF */
198 #define sel_nl_sz (sizeof(sel_nl)/sizeof(wchar_t))
199 static wchar_t sel_nl
[] = SEL_NL
;
200 static wchar_t *paste_buffer
= 0;
201 static int paste_len
, paste_pos
, paste_hold
;
204 * Internal prototypes.
206 static void do_paint(Context
, int);
207 static void erase_lots(int, int, int);
208 static void swap_screen(int, int, int);
209 static void update_sbar(void);
210 static void deselect(void);
211 static void term_print_finish(void);
214 * Resize a line to make it `cols' columns wide.
216 unsigned long *resizeline(unsigned long *line
, int cols
)
219 unsigned long lineattrs
;
221 if (line
[0] != (unsigned long)cols
) {
223 * This line is the wrong length, which probably means it
224 * hasn't been accessed since a resize. Resize it now.
227 lineattrs
= line
[oldlen
+ 1];
228 line
= srealloc(line
, TSIZE
* (2 + cols
));
230 for (i
= oldlen
; i
< cols
; i
++)
231 line
[i
+ 1] = ERASE_CHAR
;
232 line
[cols
+ 1] = lineattrs
& LATTR_MODE
;
239 * Retrieve a line of the screen or of the scrollback, according to
240 * whether the y coordinate is non-negative or negative
243 unsigned long *lineptr(int y
, int lineno
)
245 unsigned long *line
, *newline
;
253 whichtree
= scrollback
;
254 treeindex
= y
+ count234(scrollback
);
256 line
= index234(whichtree
, treeindex
);
258 /* We assume that we don't screw up and retrieve something out of range. */
259 assert(line
!= NULL
);
261 newline
= resizeline(line
, cols
);
262 if (newline
!= line
) {
263 delpos234(whichtree
, treeindex
);
264 addpos234(whichtree
, newline
, treeindex
);
271 #define lineptr(x) lineptr(x,__LINE__)
273 * Set up power-on settings for the terminal.
275 static void power_on(void)
277 curs
.x
= curs
.y
= alt_x
= alt_y
= savecurs
.x
= savecurs
.y
= 0;
280 alt_b
= marg_b
= rows
- 1;
285 for (i
= 0; i
< cols
; i
++)
286 tabs
[i
] = (i
% 8 == 0 ? TRUE
: FALSE
);
288 alt_om
= dec_om
= cfg
.dec_om
;
289 alt_wnext
= wrapnext
= alt_ins
= insert
= FALSE
;
290 alt_wrap
= wrap
= cfg
.wrap_mode
;
293 alt_sco_acs
= sco_acs
= 0;
294 cset_attr
[0] = cset_attr
[1] = ATTR_ASCII
;
299 save_attr
= curr_attr
= ATTR_DEFAULT
;
300 term_editing
= term_echoing
= FALSE
;
301 ldisc_send(NULL
, 0, 0); /* cause ldisc to notice changes */
302 app_cursor_keys
= cfg
.app_cursor
;
303 app_keypad_keys
= cfg
.app_keypad
;
305 blink_is_real
= cfg
.blinktext
;
306 erase_char
= ERASE_CHAR
;
311 for (i
= 0; i
< 256; i
++)
312 wordness
[i
] = cfg
.wordness
[i
];
315 swap_screen(1, FALSE
, FALSE
);
316 erase_lots(FALSE
, TRUE
, TRUE
);
317 swap_screen(0, FALSE
, FALSE
);
318 erase_lots(FALSE
, TRUE
, TRUE
);
323 * Force a screen update.
325 void term_update(void)
330 int need_sbar_update
= seen_disp_event
;
331 if (seen_disp_event
&& cfg
.scroll_on_disp
) {
332 disptop
= 0; /* return to main screen */
334 need_sbar_update
= TRUE
;
336 if (need_sbar_update
)
339 sys_cursor(curs
.x
, curs
.y
- disptop
);
345 * Called from front end when a keypress occurs, to trigger
346 * anything magical that needs to happen in that situation.
348 void term_seen_key_event(void)
351 * On any keypress, clear the bell overload mechanism
352 * completely, on the grounds that large numbers of
353 * beeps coming from deliberate key action are likely
354 * to be intended (e.g. beeps from filename completion
355 * blocking repeatedly).
357 beep_overloaded
= FALSE
;
359 struct beeptime
*tmp
= beephead
;
360 beephead
= tmp
->next
;
367 * Reset the scrollback on keypress, if we're doing that.
369 if (cfg
.scroll_on_key
) {
370 disptop
= 0; /* return to main screen */
376 * Same as power_on(), but an external function.
378 void term_pwron(void)
388 * When the user reconfigures us, we need to check the forbidden-
389 * alternate-screen config option, disable raw mouse mode if the
390 * user has disabled mouse reporting, and abandon a print job if
391 * the user has disabled printing.
393 void term_reconfig(void)
395 if (cfg
.no_alt_screen
)
396 swap_screen(0, FALSE
, FALSE
);
397 if (cfg
.no_mouse_rep
) {
399 set_raw_mouse_mode(0);
401 if (cfg
.no_remote_charset
) {
402 cset_attr
[0] = cset_attr
[1] = ATTR_ASCII
;
403 sco_acs
= alt_sco_acs
= 0;
412 * Clear the scrollback.
414 void term_clrsb(void)
418 while ((line
= delpos234(scrollback
, 0)) != NULL
) {
425 * Initialise the terminal.
429 screen
= alt_screen
= scrollback
= NULL
;
431 disptext
= dispcurs
= NULL
;
436 beephead
= beeptail
= NULL
;
439 beep_overloaded
= FALSE
;
443 * Set up the terminal for a given size.
445 void term_size(int newrows
, int newcols
, int newsavelines
)
448 unsigned long *newdisp
, *line
;
451 int save_alt_which
= alt_which
;
453 if (newrows
== rows
&& newcols
== cols
&& newsavelines
== savelines
)
454 return; /* nothing to do */
457 swap_screen(0, FALSE
, FALSE
);
460 alt_b
= marg_b
= newrows
- 1;
463 scrollback
= newtree234(NULL
);
464 screen
= newtree234(NULL
);
469 * Resize the screen and scrollback. We only need to shift
470 * lines around within our data structures, because lineptr()
471 * will take care of resizing each individual line if
474 * - If the new screen and the old screen differ in length, we
475 * must shunt some lines in from the scrollback or out to
478 * - If doing that fails to provide us with enough material to
479 * fill the new screen (i.e. the number of rows needed in
480 * the new screen exceeds the total number in the previous
481 * screen+scrollback), we must invent some blank lines to
484 * - Then, if the new scrollback length is less than the
485 * amount of scrollback we actually have, we must throw some
488 sblen
= count234(scrollback
);
489 /* Do this loop to expand the screen if newrows > rows */
490 for (i
= rows
; i
< newrows
; i
++) {
492 line
= delpos234(scrollback
, --sblen
);
494 line
= smalloc(TSIZE
* (newcols
+ 2));
496 for (j
= 0; j
<= newcols
; j
++)
497 line
[j
+ 1] = ERASE_CHAR
;
499 addpos234(screen
, line
, 0);
501 /* Do this loop to shrink the screen if newrows < rows */
502 for (i
= newrows
; i
< rows
; i
++) {
503 line
= delpos234(screen
, 0);
504 addpos234(scrollback
, line
, sblen
++);
506 assert(count234(screen
) == newrows
);
507 while (sblen
> newsavelines
) {
508 line
= delpos234(scrollback
, 0);
512 assert(count234(scrollback
) <= newsavelines
);
515 newdisp
= smalloc(newrows
* (newcols
+ 1) * TSIZE
);
516 for (i
= 0; i
< newrows
* (newcols
+ 1); i
++)
517 newdisp
[i
] = ATTR_INVALID
;
522 newalt
= newtree234(NULL
);
523 for (i
= 0; i
< newrows
; i
++) {
524 line
= smalloc(TSIZE
* (newcols
+ 2));
526 for (j
= 0; j
<= newcols
; j
++)
527 line
[j
+ 1] = erase_char
;
528 addpos234(newalt
, line
, i
);
531 while (NULL
!= (line
= delpos234(alt_screen
, 0)))
533 freetree234(alt_screen
);
537 tabs
= srealloc(tabs
, newcols
* sizeof(*tabs
));
540 for (i
= (cols
> 0 ? cols
: 0); i
< newcols
; i
++)
541 tabs
[i
] = (i
% 8 == 0 ? TRUE
: FALSE
);
545 curs
.y
+= newrows
- rows
;
548 if (curs
.y
>= newrows
)
549 curs
.y
= newrows
- 1;
550 if (curs
.x
>= newcols
)
551 curs
.x
= newcols
- 1;
553 wrapnext
= alt_wnext
= FALSE
;
557 savelines
= newsavelines
;
560 swap_screen(save_alt_which
, FALSE
, FALSE
);
568 * Swap screens. If `reset' is TRUE and we have been asked to
569 * switch to the alternate screen, we must bring most of its
570 * configuration from the main screen and erase the contents of the
571 * alternate screen completely. (This is even true if we're already
572 * on it! Blame xterm.)
574 static void swap_screen(int which
, int reset
, int keep_cur_pos
)
580 reset
= FALSE
; /* do no weird resetting if which==0 */
582 if (which
!= alt_which
) {
589 if (!reset
&& !keep_cur_pos
)
593 if (!reset
&& !keep_cur_pos
)
597 if (!reset
) marg_t
= alt_t
;
600 if (!reset
) marg_b
= alt_b
;
603 if (!reset
) dec_om
= alt_om
;
606 if (!reset
) wrap
= alt_wrap
;
609 if (!reset
) wrapnext
= alt_wnext
;
612 if (!reset
) insert
= alt_ins
;
615 if (!reset
) cset
= alt_cset
;
618 if (!reset
) utf
= alt_utf
;
621 if (!reset
) sco_acs
= alt_sco_acs
;
625 if (reset
&& screen
) {
627 * Yes, this _is_ supposed to honour background-colour-erase.
629 erase_lots(FALSE
, TRUE
, TRUE
);
633 * This might not be possible if we're called during
641 * Update the scroll bar.
643 static void update_sbar(void)
647 nscroll
= count234(scrollback
);
649 set_sbar(nscroll
+ rows
, nscroll
+ disptop
, rows
);
653 * Check whether the region bounded by the two pointers intersects
654 * the scroll region, and de-select the on-screen selection if so.
656 static void check_selection(pos from
, pos to
)
658 if (poslt(from
, selend
) && poslt(selstart
, to
))
663 * Scroll the screen. (`lines' is +ve for scrolling forward, -ve
664 * for backward.) `sb' is TRUE if the scrolling is permitted to
665 * affect the scrollback buffer.
667 * NB this function invalidates all pointers into lines of the
668 * screen data structures. In particular, you MUST call fix_cpos
669 * after calling scroll() and before doing anything else that
670 * uses the cpos shortcut pointer.
672 static void scroll(int topline
, int botline
, int lines
, int sb
)
674 unsigned long *line
, *line2
;
677 if (topline
!= 0 || alt_which
!= 0)
682 line
= delpos234(screen
, botline
);
683 line
= resizeline(line
, cols
);
684 for (i
= 0; i
< cols
; i
++)
685 line
[i
+ 1] = erase_char
;
687 addpos234(screen
, line
, topline
);
689 if (selstart
.y
>= topline
&& selstart
.y
<= botline
) {
691 if (selstart
.y
> botline
) {
692 selstart
.y
= botline
;
696 if (selend
.y
>= topline
&& selend
.y
<= botline
) {
698 if (selend
.y
> botline
) {
708 line
= delpos234(screen
, topline
);
709 if (sb
&& savelines
> 0) {
710 int sblen
= count234(scrollback
);
712 * We must add this line to the scrollback. We'll
713 * remove a line from the top of the scrollback to
714 * replace it, or allocate a new one if the
715 * scrollback isn't full.
717 if (sblen
== savelines
) {
718 sblen
--, line2
= delpos234(scrollback
, 0);
720 line2
= smalloc(TSIZE
* (cols
+ 2));
723 addpos234(scrollback
, line
, sblen
);
727 * If the user is currently looking at part of the
728 * scrollback, and they haven't enabled any options
729 * that are going to reset the scrollback as a
730 * result of this movement, then the chances are
731 * they'd like to keep looking at the same line. So
732 * we move their viewpoint at the same rate as the
733 * scroll, at least until their viewpoint hits the
734 * top end of the scrollback buffer, at which point
735 * we don't have the choice any more.
737 * Thanks to Jan Holmen Holsten for the idea and
738 * initial implementation.
740 if (disptop
> -savelines
&& disptop
< 0)
743 line
= resizeline(line
, cols
);
744 for (i
= 0; i
< cols
; i
++)
745 line
[i
+ 1] = erase_char
;
747 addpos234(screen
, line
, botline
);
750 * If the selection endpoints move into the scrollback,
751 * we keep them moving until they hit the top. However,
752 * of course, if the line _hasn't_ moved into the
753 * scrollback then we don't do this, and cut them off
754 * at the top of the scroll region.
756 * This applies to selstart and selend (for an existing
757 * selection), and also selanchor (for one being
758 * selected as we speak).
760 seltop
= sb ?
-savelines
: topline
;
762 if (selstart
.y
>= seltop
&& selstart
.y
<= botline
) {
764 if (selstart
.y
< seltop
) {
769 if (selend
.y
>= seltop
&& selend
.y
<= botline
) {
771 if (selend
.y
< seltop
) {
776 if (selanchor
.y
>= seltop
&& selanchor
.y
<= botline
) {
778 if (selanchor
.y
< seltop
) {
779 selanchor
.y
= seltop
;
790 * Move the cursor to a given position, clipping at boundaries. We
791 * may or may not want to clip at the scroll margin: marg_clip is 0
792 * not to, 1 to disallow _passing_ the margins, and 2 to disallow
793 * even _being_ outside the margins.
795 static void move(int x
, int y
, int marg_clip
)
802 if ((curs
.y
>= marg_t
|| marg_clip
== 2) && y
< marg_t
)
804 if ((curs
.y
<= marg_b
|| marg_clip
== 2) && y
> marg_b
)
818 * Save or restore the cursor and SGR mode.
820 static void save_cursor(int save
)
824 save_attr
= curr_attr
;
827 save_wnext
= wrapnext
;
828 save_csattr
= cset_attr
[cset
];
829 save_sco_acs
= sco_acs
;
832 /* Make sure the window hasn't shrunk since the save */
838 curr_attr
= save_attr
;
841 wrapnext
= save_wnext
;
843 * wrapnext might reset to False if the x position is no
844 * longer at the rightmost edge.
846 if (wrapnext
&& curs
.x
< cols
-1)
848 cset_attr
[cset
] = save_csattr
;
849 sco_acs
= save_sco_acs
;
852 erase_char
= (' ' | ATTR_ASCII
|
853 (curr_attr
& (ATTR_FGMASK
| ATTR_BGMASK
)));
858 * Erase a large portion of the screen: the whole screen, or the
859 * whole line, or parts thereof.
861 static void erase_lots(int line_only
, int from_begin
, int to_end
)
865 unsigned long *ldata
;
887 check_selection(start
, end
);
889 /* Clear screen also forces a full window redraw, just in case. */
890 if (start
.y
== 0 && start
.x
== 0 && end
.y
== rows
)
893 ldata
= lineptr(start
.y
);
894 while (poslt(start
, end
)) {
895 if (start
.x
== cols
&& !erase_lattr
)
896 ldata
[start
.x
] &= ~LATTR_WRAPPED
;
898 ldata
[start
.x
] = erase_char
;
899 if (incpos(start
) && start
.y
< rows
)
900 ldata
= lineptr(start
.y
);
905 * Insert or delete characters within the current line. n is +ve if
906 * insertion is desired, and -ve for deletion.
908 static void insch(int n
)
910 int dir
= (n
< 0 ?
-1 : +1);
913 unsigned long *ldata
;
915 n
= (n
< 0 ?
-n
: n
);
916 if (n
> cols
- curs
.x
)
918 m
= cols
- curs
.x
- n
;
920 cursplus
.x
= curs
.x
+ n
;
921 check_selection(curs
, cursplus
);
922 ldata
= lineptr(curs
.y
);
924 memmove(ldata
+ curs
.x
, ldata
+ curs
.x
+ n
, m
* TSIZE
);
926 ldata
[curs
.x
+ m
++] = erase_char
;
928 memmove(ldata
+ curs
.x
+ n
, ldata
+ curs
.x
, m
* TSIZE
);
930 ldata
[curs
.x
+ n
] = erase_char
;
935 * Toggle terminal mode `mode' to state `state'. (`query' indicates
936 * whether the mode is a DEC private one or a normal one.)
938 static void toggle_mode(int mode
, int query
, int state
)
944 case 1: /* application cursor keys */
945 app_cursor_keys
= state
;
947 case 2: /* VT52 mode */
950 blink_is_real
= FALSE
;
953 blink_is_real
= cfg
.blinktext
;
956 case 3: /* 80/132 columns */
958 if (!cfg
.no_remote_resize
)
959 request_resize(state ?
132 : 80, rows
);
962 case 5: /* reverse video */
964 * Toggle reverse video. If we receive an OFF within the
965 * visual bell timeout period after an ON, we trigger an
966 * effective visual bell, so that ESC[?5hESC[?5l will
967 * always be an actually _visible_ visual bell.
969 ticks
= GETTICKCOUNT();
970 /* turn off a previous vbell to avoid inconsistencies */
971 if (ticks
- vbell_startpoint
>= VBELL_TIMEOUT
)
973 if (rvideo
&& !state
&& /* we're turning it off... */
974 (ticks
- rvbell_startpoint
) < VBELL_TIMEOUT
) { /* ...soon */
975 /* If there's no vbell timeout already, or this one lasts
976 * longer, replace vbell_timeout with ours. */
978 (rvbell_startpoint
- vbell_startpoint
< VBELL_TIMEOUT
))
979 vbell_startpoint
= rvbell_startpoint
;
980 in_vbell
= TRUE
; /* we may clear rvideo but we set in_vbell */
981 } else if (!rvideo
&& state
) {
982 /* This is an ON, so we notice the time and save it. */
983 rvbell_startpoint
= ticks
;
986 seen_disp_event
= TRUE
;
990 case 6: /* DEC origin mode */
993 case 7: /* auto wrap */
996 case 8: /* auto key repeat */
999 case 10: /* set local edit mode */
1000 term_editing
= state
;
1001 ldisc_send(NULL
, 0, 0); /* cause ldisc to notice changes */
1003 case 25: /* enable/disable cursor */
1004 compatibility2(OTHER
, VT220
);
1006 seen_disp_event
= TRUE
;
1008 case 47: /* alternate screen */
1009 compatibility(OTHER
);
1011 swap_screen(cfg
.no_alt_screen ?
0 : state
, FALSE
, FALSE
);
1014 case 1000: /* xterm mouse 1 */
1015 xterm_mouse
= state ?
1 : 0;
1016 set_raw_mouse_mode(state
);
1018 case 1002: /* xterm mouse 2 */
1019 xterm_mouse
= state ?
2 : 0;
1020 set_raw_mouse_mode(state
);
1022 case 1047: /* alternate screen */
1023 compatibility(OTHER
);
1025 swap_screen(cfg
.no_alt_screen ?
0 : state
, TRUE
, TRUE
);
1028 case 1048: /* save/restore cursor */
1030 if (!state
) seen_disp_event
= TRUE
;
1032 case 1049: /* cursor & alternate screen */
1035 if (!state
) seen_disp_event
= TRUE
;
1036 compatibility(OTHER
);
1038 swap_screen(cfg
.no_alt_screen ?
0 : state
, TRUE
, FALSE
);
1045 case 4: /* set insert mode */
1046 compatibility(VT102
);
1049 case 12: /* set echo mode */
1050 term_echoing
= !state
;
1051 ldisc_send(NULL
, 0, 0); /* cause ldisc to notice changes */
1053 case 20: /* Return sends ... */
1054 cr_lf_return
= state
;
1056 case 34: /* Make cursor BIG */
1057 compatibility2(OTHER
, VT220
);
1058 big_cursor
= !state
;
1063 * Process an OSC sequence: set window title or icon name.
1065 static void do_osc(void)
1068 while (osc_strlen
--)
1069 wordness
[(unsigned char) osc_string
[osc_strlen
]] = esc_args
[0];
1071 osc_string
[osc_strlen
] = '\0';
1072 switch (esc_args
[0]) {
1075 if (!cfg
.no_remote_wintitle
)
1076 set_icon(osc_string
);
1077 if (esc_args
[0] == 1)
1079 /* fall through: parameter 0 means set both */
1082 if (!cfg
.no_remote_wintitle
)
1083 set_title(osc_string
);
1090 * ANSI printing routines.
1092 static void term_print_setup(void)
1094 bufchain_clear(&printer_buf
);
1095 print_job
= printer_start_job(cfg
.printer
);
1097 static void term_print_flush(void)
1102 while ((size
= bufchain_size(&printer_buf
)) > 5) {
1103 bufchain_prefix(&printer_buf
, &data
, &len
);
1106 printer_job_data(print_job
, data
, len
);
1107 bufchain_consume(&printer_buf
, len
);
1110 static void term_print_finish(void)
1116 if (!printing
&& !only_printing
)
1117 return; /* we need do nothing */
1120 while ((size
= bufchain_size(&printer_buf
)) > 0) {
1121 bufchain_prefix(&printer_buf
, &data
, &len
);
1123 if (c
== '\033' || c
== '\233') {
1124 bufchain_consume(&printer_buf
, size
);
1127 printer_job_data(print_job
, &c
, 1);
1128 bufchain_consume(&printer_buf
, 1);
1131 printer_finish_job(print_job
);
1133 printing
= only_printing
= FALSE
;
1137 * Remove everything currently in `inbuf' and stick it up on the
1138 * in-memory display. There's a big state machine in here to
1139 * process escape sequences...
1144 unsigned char localbuf
[256], *chars
;
1149 chars
= NULL
; /* placate compiler warnings */
1150 while (nchars
> 0 || bufchain_size(&inbuf
) > 0) {
1154 bufchain_prefix(&inbuf
, &ret
, &nchars
);
1155 if (nchars
> sizeof(localbuf
))
1156 nchars
= sizeof(localbuf
);
1157 memcpy(localbuf
, ret
, nchars
);
1158 bufchain_consume(&inbuf
, nchars
);
1160 assert(chars
!= NULL
);
1166 * Optionally log the session traffic to a file. Useful for
1167 * debugging and possibly also useful for actual logging.
1169 if (cfg
.logtype
== LGTYP_DEBUG
)
1170 logtraffic((unsigned char) c
, LGTYP_DEBUG
);
1176 /* Note only VT220+ are 8-bit VT102 is seven bit, it shouldn't even
1177 * be able to display 8-bit characters, but I'll let that go 'cause
1182 * If we're printing, add the character to the printer
1186 bufchain_add(&printer_buf
, &c
, 1);
1189 * If we're in print-only mode, we use a much simpler
1190 * state machine designed only to recognise the ESC[4i
1191 * termination sequence.
1193 if (only_printing
) {
1196 else if (c
== (unsigned char)'\233')
1198 else if (c
== '[' && print_state
== 1)
1200 else if (c
== '4' && print_state
== 2)
1202 else if (c
== 'i' && print_state
== 3)
1206 if (print_state
== 4) {
1207 term_print_finish();
1213 /* First see about all those translations. */
1214 if (termstate
== TOPLEVEL
) {
1216 switch (utf_state
) {
1219 /* UTF-8 must be stateless so we ignore iso2022. */
1220 if (unitab_ctrl
[c
] != 0xFF)
1222 else c
= ((unsigned char)c
) | ATTR_ASCII
;
1224 } else if ((c
& 0xe0) == 0xc0) {
1225 utf_size
= utf_state
= 1;
1226 utf_char
= (c
& 0x1f);
1227 } else if ((c
& 0xf0) == 0xe0) {
1228 utf_size
= utf_state
= 2;
1229 utf_char
= (c
& 0x0f);
1230 } else if ((c
& 0xf8) == 0xf0) {
1231 utf_size
= utf_state
= 3;
1232 utf_char
= (c
& 0x07);
1233 } else if ((c
& 0xfc) == 0xf8) {
1234 utf_size
= utf_state
= 4;
1235 utf_char
= (c
& 0x03);
1236 } else if ((c
& 0xfe) == 0xfc) {
1237 utf_size
= utf_state
= 5;
1238 utf_char
= (c
& 0x01);
1249 if ((c
& 0xC0) != 0x80) {
1255 utf_char
= (utf_char
<< 6) | (c
& 0x3f);
1261 /* Is somebody trying to be evil! */
1263 (c
< 0x800 && utf_size
>= 2) ||
1264 (c
< 0x10000 && utf_size
>= 3) ||
1265 (c
< 0x200000 && utf_size
>= 4) ||
1266 (c
< 0x4000000 && utf_size
>= 5))
1269 /* Unicode line separator and paragraph separator are CR-LF */
1270 if (c
== 0x2028 || c
== 0x2029)
1273 /* High controls are probably a Baaad idea too. */
1277 /* The UTF-16 surrogates are not nice either. */
1278 /* The standard give the option of decoding these:
1279 * I don't want to! */
1280 if (c
>= 0xD800 && c
< 0xE000)
1283 /* ISO 10646 characters now limited to UTF-16 range. */
1287 /* This is currently a TagPhobic application.. */
1288 if (c
>= 0xE0000 && c
<= 0xE007F)
1291 /* U+FEFF is best seen as a null. */
1294 /* But U+FFFE is an error. */
1295 if (c
== 0xFFFE || c
== 0xFFFF)
1298 /* Oops this is a 16bit implementation */
1303 /* Are we in the nasty ACS mode? Note: no sco in utf mode. */
1305 (c
!='\033' && c
!='\n' && c
!='\r' && c
!='\b'))
1307 if (sco_acs
== 2) c
^= 0x80;
1310 switch (cset_attr
[cset
]) {
1312 * Linedraw characters are different from 'ESC ( B'
1313 * only for a small range. For ones outside that
1314 * range, make sure we use the same font as well as
1315 * the same encoding.
1318 if (unitab_ctrl
[c
] != 0xFF)
1321 c
= ((unsigned char) c
) | ATTR_LINEDRW
;
1325 /* If UK-ASCII, make the '#' a LineDraw Pound */
1327 c
= '}' | ATTR_LINEDRW
;
1330 /*FALLTHROUGH*/ case ATTR_ASCII
:
1331 if (unitab_ctrl
[c
] != 0xFF)
1334 c
= ((unsigned char) c
) | ATTR_ASCII
;
1337 if (c
>=' ') c
= ((unsigned char)c
) | ATTR_SCOACS
;
1343 /* How about C1 controls ? */
1344 if ((c
& -32) == 0x80 && termstate
< DO_CTRLS
&& !vt52_mode
&&
1345 has_compat(VT220
)) {
1346 termstate
= SEEN_ESC
;
1348 c
= '@' + (c
& 0x1F);
1351 /* Or the GL control. */
1352 if (c
== '\177' && termstate
< DO_CTRLS
&& has_compat(OTHER
)) {
1353 if (curs
.x
&& !wrapnext
)
1357 if (!cfg
.no_dbackspace
) /* destructive bksp might be disabled */
1358 *cpos
= (' ' | curr_attr
| ATTR_ASCII
);
1360 /* Or normal C0 controls. */
1361 if ((c
& -32) == 0 && termstate
< DO_CTRLS
) {
1363 case '\005': /* terminal type query */
1364 /* Strictly speaking this is VT100 but a VT100 defaults to
1365 * no response. Other terminals respond at their option.
1367 * Don't put a CR in the default string as this tends to
1368 * upset some weird software.
1370 * An xterm returns "xterm" (5 characters)
1372 compatibility(ANSIMIN
);
1374 char abuf
[256], *s
, *d
;
1376 for (s
= cfg
.answerback
, d
= abuf
; *s
; s
++) {
1378 if (*s
>= 'a' && *s
<= 'z')
1379 *d
++ = (*s
- ('a' - 1));
1380 else if ((*s
>= '@' && *s
<= '_') ||
1381 *s
== '?' || (*s
& 0x80))
1386 } else if (*s
== '^') {
1391 lpage_send(DEFAULT_CODEPAGE
, abuf
, d
- abuf
, 0);
1396 struct beeptime
*newbeep
;
1397 unsigned long ticks
;
1399 ticks
= GETTICKCOUNT();
1401 if (!beep_overloaded
) {
1402 newbeep
= smalloc(sizeof(struct beeptime
));
1403 newbeep
->ticks
= ticks
;
1404 newbeep
->next
= NULL
;
1408 beeptail
->next
= newbeep
;
1414 * Throw out any beeps that happened more than
1418 beephead
->ticks
< ticks
- cfg
.bellovl_t
) {
1419 struct beeptime
*tmp
= beephead
;
1420 beephead
= tmp
->next
;
1427 if (cfg
.bellovl
&& beep_overloaded
&&
1428 ticks
- lastbeep
>= (unsigned)cfg
.bellovl_s
) {
1430 * If we're currently overloaded and the
1431 * last beep was more than s seconds ago,
1432 * leave overload mode.
1434 beep_overloaded
= FALSE
;
1435 } else if (cfg
.bellovl
&& !beep_overloaded
&&
1436 nbeeps
>= cfg
.bellovl_n
) {
1438 * Now, if we have n or more beeps
1439 * remaining in the queue, go into overload
1442 beep_overloaded
= TRUE
;
1447 * Perform an actual beep if we're not overloaded.
1449 if (!cfg
.bellovl
|| !beep_overloaded
) {
1450 if (cfg
.beep
== BELL_VISUAL
) {
1452 vbell_startpoint
= ticks
;
1461 if (curs
.x
== 0 && (curs
.y
== 0 || wrap
== 0));
1462 else if (curs
.x
== 0 && curs
.y
> 0)
1463 curs
.x
= cols
- 1, curs
.y
--;
1469 seen_disp_event
= TRUE
;
1472 compatibility(VT100
);
1476 compatibility(VT100
);
1481 termstate
= VT52_ESC
;
1483 compatibility(ANSIMIN
);
1484 termstate
= SEEN_ESC
;
1492 seen_disp_event
= TRUE
;
1494 logtraffic((unsigned char) c
, LGTYP_ASCII
);
1497 if (has_compat(SCOANSI
)) {
1499 erase_lots(FALSE
, FALSE
, TRUE
);
1502 seen_disp_event
= 1;
1506 compatibility(VT100
);
1508 if (curs
.y
== marg_b
)
1509 scroll(marg_t
, marg_b
, 1, TRUE
);
1510 else if (curs
.y
< rows
- 1)
1516 seen_disp_event
= 1;
1518 logtraffic((unsigned char) c
, LGTYP_ASCII
);
1522 pos old_curs
= curs
;
1523 unsigned long *ldata
= lineptr(curs
.y
);
1527 } while (curs
.x
< cols
- 1 && !tabs
[curs
.x
]);
1529 if ((ldata
[cols
] & LATTR_MODE
) != LATTR_NORM
) {
1530 if (curs
.x
>= cols
/ 2)
1531 curs
.x
= cols
/ 2 - 1;
1538 check_selection(old_curs
, curs
);
1540 seen_disp_event
= TRUE
;
1544 switch (termstate
) {
1546 /* Only graphic characters get this far, ctrls are stripped above */
1547 if (wrapnext
&& wrap
) {
1548 cpos
[1] |= LATTR_WRAPPED
;
1549 if (curs
.y
== marg_b
)
1550 scroll(marg_t
, marg_b
, 1, TRUE
);
1551 else if (curs
.y
< rows
- 1)
1559 if (selstate
!= NO_SELECTION
) {
1560 pos cursplus
= curs
;
1562 check_selection(curs
, cursplus
);
1564 if ((c
& CSET_MASK
) == ATTR_ASCII
|| (c
& CSET_MASK
) == 0)
1565 logtraffic((unsigned char) c
, LGTYP_ASCII
);
1567 extern int wcwidth(wchar_t ucs
);
1572 width
= wcwidth((wchar_t) c
);
1575 *cpos
++ = c
| curr_attr
;
1576 if (++curs
.x
== cols
) {
1577 *cpos
|= LATTR_WRAPPED
;
1578 if (curs
.y
== marg_b
)
1579 scroll(marg_t
, marg_b
, 1, TRUE
);
1580 else if (curs
.y
< rows
- 1)
1585 *cpos
++ = UCSWIDE
| curr_attr
;
1588 *cpos
++ = c
| curr_attr
;
1595 if (curs
.x
== cols
) {
1599 if (wrap
&& vt52_mode
) {
1600 cpos
[1] |= LATTR_WRAPPED
;
1601 if (curs
.y
== marg_b
)
1602 scroll(marg_t
, marg_b
, 1, TRUE
);
1603 else if (curs
.y
< rows
- 1)
1610 seen_disp_event
= 1;
1615 * This state is virtually identical to SEEN_ESC, with the
1616 * exception that we have an OSC sequence in the pipeline,
1617 * and _if_ we see a backslash, we process it.
1621 termstate
= TOPLEVEL
;
1624 /* else fall through */
1626 if (c
>= ' ' && c
<= '/') {
1633 termstate
= TOPLEVEL
;
1634 switch (ANSI(c
, esc_query
)) {
1635 case '[': /* enter CSI mode */
1636 termstate
= SEEN_CSI
;
1638 esc_args
[0] = ARG_DEFAULT
;
1641 case ']': /* xterm escape sequences */
1642 /* Compatibility is nasty here, xterm, linux, decterm yuk! */
1643 compatibility(OTHER
);
1644 termstate
= SEEN_OSC
;
1647 case '7': /* save cursor */
1648 compatibility(VT100
);
1651 case '8': /* restore cursor */
1652 compatibility(VT100
);
1654 seen_disp_event
= TRUE
;
1657 compatibility(VT100
);
1658 app_keypad_keys
= TRUE
;
1661 compatibility(VT100
);
1662 app_keypad_keys
= FALSE
;
1664 case 'D': /* exactly equivalent to LF */
1665 compatibility(VT100
);
1666 if (curs
.y
== marg_b
)
1667 scroll(marg_t
, marg_b
, 1, TRUE
);
1668 else if (curs
.y
< rows
- 1)
1672 seen_disp_event
= TRUE
;
1674 case 'E': /* exactly equivalent to CR-LF */
1675 compatibility(VT100
);
1677 if (curs
.y
== marg_b
)
1678 scroll(marg_t
, marg_b
, 1, TRUE
);
1679 else if (curs
.y
< rows
- 1)
1683 seen_disp_event
= TRUE
;
1685 case 'M': /* reverse index - backwards LF */
1686 compatibility(VT100
);
1687 if (curs
.y
== marg_t
)
1688 scroll(marg_t
, marg_b
, -1, TRUE
);
1689 else if (curs
.y
> 0)
1693 seen_disp_event
= TRUE
;
1695 case 'Z': /* terminal type query */
1696 compatibility(VT100
);
1697 ldisc_send(id_string
, strlen(id_string
), 0);
1699 case 'c': /* restore power-on settings */
1700 compatibility(VT100
);
1703 if (!cfg
.no_remote_resize
)
1704 request_resize(80, rows
);
1709 seen_disp_event
= TRUE
;
1711 case 'H': /* set a tab */
1712 compatibility(VT100
);
1713 tabs
[curs
.x
] = TRUE
;
1716 case ANSI('8', '#'): /* ESC # 8 fills screen with Es :-) */
1717 compatibility(VT100
);
1719 unsigned long *ldata
;
1723 for (i
= 0; i
< rows
; i
++) {
1725 for (j
= 0; j
< cols
; j
++)
1726 ldata
[j
] = ATTR_DEFAULT
| 'E';
1730 seen_disp_event
= TRUE
;
1731 scrtop
.x
= scrtop
.y
= 0;
1734 check_selection(scrtop
, scrbot
);
1738 case ANSI('3', '#'):
1739 case ANSI('4', '#'):
1740 case ANSI('5', '#'):
1741 case ANSI('6', '#'):
1742 compatibility(VT100
);
1744 unsigned long nlattr
;
1745 unsigned long *ldata
;
1746 switch (ANSI(c
, esc_query
)) {
1747 case ANSI('3', '#'):
1750 case ANSI('4', '#'):
1753 case ANSI('5', '#'):
1754 nlattr
= LATTR_NORM
;
1756 default: /* spiritually case ANSI('6', '#'): */
1757 nlattr
= LATTR_WIDE
;
1760 ldata
= lineptr(curs
.y
);
1761 ldata
[cols
] &= ~LATTR_MODE
;
1762 ldata
[cols
] |= nlattr
;
1766 case ANSI('A', '('):
1767 compatibility(VT100
);
1768 if (!cfg
.no_remote_charset
)
1769 cset_attr
[0] = ATTR_GBCHR
;
1771 case ANSI('B', '('):
1772 compatibility(VT100
);
1773 if (!cfg
.no_remote_charset
)
1774 cset_attr
[0] = ATTR_ASCII
;
1776 case ANSI('0', '('):
1777 compatibility(VT100
);
1778 if (!cfg
.no_remote_charset
)
1779 cset_attr
[0] = ATTR_LINEDRW
;
1781 case ANSI('U', '('):
1782 compatibility(OTHER
);
1783 if (!cfg
.no_remote_charset
)
1784 cset_attr
[0] = ATTR_SCOACS
;
1787 case ANSI('A', ')'):
1788 compatibility(VT100
);
1789 if (!cfg
.no_remote_charset
)
1790 cset_attr
[1] = ATTR_GBCHR
;
1792 case ANSI('B', ')'):
1793 compatibility(VT100
);
1794 if (!cfg
.no_remote_charset
)
1795 cset_attr
[1] = ATTR_ASCII
;
1797 case ANSI('0', ')'):
1798 compatibility(VT100
);
1799 if (!cfg
.no_remote_charset
)
1800 cset_attr
[1] = ATTR_LINEDRW
;
1802 case ANSI('U', ')'):
1803 compatibility(OTHER
);
1804 if (!cfg
.no_remote_charset
)
1805 cset_attr
[1] = ATTR_SCOACS
;
1808 case ANSI('8', '%'): /* Old Linux code */
1809 case ANSI('G', '%'):
1810 compatibility(OTHER
);
1811 if (!cfg
.no_remote_charset
)
1814 case ANSI('@', '%'):
1815 compatibility(OTHER
);
1816 if (!cfg
.no_remote_charset
)
1822 termstate
= TOPLEVEL
; /* default */
1824 if (esc_nargs
<= ARGS_MAX
) {
1825 if (esc_args
[esc_nargs
- 1] == ARG_DEFAULT
)
1826 esc_args
[esc_nargs
- 1] = 0;
1827 esc_args
[esc_nargs
- 1] =
1828 10 * esc_args
[esc_nargs
- 1] + c
- '0';
1830 termstate
= SEEN_CSI
;
1831 } else if (c
== ';') {
1832 if (++esc_nargs
<= ARGS_MAX
)
1833 esc_args
[esc_nargs
- 1] = ARG_DEFAULT
;
1834 termstate
= SEEN_CSI
;
1835 } else if (c
< '@') {
1842 termstate
= SEEN_CSI
;
1844 switch (ANSI(c
, esc_query
)) {
1845 case 'A': /* move up N lines */
1846 move(curs
.x
, curs
.y
- def(esc_args
[0], 1), 1);
1847 seen_disp_event
= TRUE
;
1849 case 'e': /* move down N lines */
1850 compatibility(ANSI
);
1853 move(curs
.x
, curs
.y
+ def(esc_args
[0], 1), 1);
1854 seen_disp_event
= TRUE
;
1856 case ANSI('c', '>'): /* report xterm version */
1857 compatibility(OTHER
);
1858 /* this reports xterm version 136 so that VIM can
1859 use the drag messages from the mouse reporting */
1860 ldisc_send("\033[>0;136;0c", 11, 0);
1862 case 'a': /* move right N cols */
1863 compatibility(ANSI
);
1866 move(curs
.x
+ def(esc_args
[0], 1), curs
.y
, 1);
1867 seen_disp_event
= TRUE
;
1869 case 'D': /* move left N cols */
1870 move(curs
.x
- def(esc_args
[0], 1), curs
.y
, 1);
1871 seen_disp_event
= TRUE
;
1873 case 'E': /* move down N lines and CR */
1874 compatibility(ANSI
);
1875 move(0, curs
.y
+ def(esc_args
[0], 1), 1);
1876 seen_disp_event
= TRUE
;
1878 case 'F': /* move up N lines and CR */
1879 compatibility(ANSI
);
1880 move(0, curs
.y
- def(esc_args
[0], 1), 1);
1881 seen_disp_event
= TRUE
;
1884 case '`': /* set horizontal posn */
1885 compatibility(ANSI
);
1886 move(def(esc_args
[0], 1) - 1, curs
.y
, 0);
1887 seen_disp_event
= TRUE
;
1889 case 'd': /* set vertical posn */
1890 compatibility(ANSI
);
1892 (dec_om ? marg_t
: 0) + def(esc_args
[0],
1895 seen_disp_event
= TRUE
;
1898 case 'f': /* set horz and vert posns at once */
1900 esc_args
[1] = ARG_DEFAULT
;
1901 move(def(esc_args
[1], 1) - 1,
1902 (dec_om ? marg_t
: 0) + def(esc_args
[0],
1905 seen_disp_event
= TRUE
;
1907 case 'J': /* erase screen or parts of it */
1909 unsigned int i
= def(esc_args
[0], 0) + 1;
1912 erase_lots(FALSE
, !!(i
& 2), !!(i
& 1));
1915 seen_disp_event
= TRUE
;
1917 case 'K': /* erase line or parts of it */
1919 unsigned int i
= def(esc_args
[0], 0) + 1;
1922 erase_lots(TRUE
, !!(i
& 2), !!(i
& 1));
1924 seen_disp_event
= TRUE
;
1926 case 'L': /* insert lines */
1927 compatibility(VT102
);
1928 if (curs
.y
<= marg_b
)
1929 scroll(curs
.y
, marg_b
, -def(esc_args
[0], 1),
1932 seen_disp_event
= TRUE
;
1934 case 'M': /* delete lines */
1935 compatibility(VT102
);
1936 if (curs
.y
<= marg_b
)
1937 scroll(curs
.y
, marg_b
, def(esc_args
[0], 1),
1940 seen_disp_event
= TRUE
;
1942 case '@': /* insert chars */
1943 /* XXX VTTEST says this is vt220, vt510 manual says vt102 */
1944 compatibility(VT102
);
1945 insch(def(esc_args
[0], 1));
1946 seen_disp_event
= TRUE
;
1948 case 'P': /* delete chars */
1949 compatibility(VT102
);
1950 insch(-def(esc_args
[0], 1));
1951 seen_disp_event
= TRUE
;
1953 case 'c': /* terminal type query */
1954 compatibility(VT100
);
1955 /* This is the response for a VT102 */
1956 ldisc_send(id_string
, strlen(id_string
), 0);
1958 case 'n': /* cursor position query */
1959 if (esc_args
[0] == 6) {
1961 sprintf(buf
, "\033[%d;%dR", curs
.y
+ 1,
1963 ldisc_send(buf
, strlen(buf
), 0);
1964 } else if (esc_args
[0] == 5) {
1965 ldisc_send("\033[0n", 4, 0);
1968 case 'h': /* toggle modes to high */
1970 compatibility(VT100
);
1973 for (i
= 0; i
< esc_nargs
; i
++)
1974 toggle_mode(esc_args
[i
], esc_query
, TRUE
);
1979 compatibility(VT100
);
1981 if (esc_nargs
!= 1) break;
1982 if (esc_args
[0] == 5 && *cfg
.printer
) {
1984 only_printing
= !esc_query
;
1987 } else if (esc_args
[0] == 4 && printing
) {
1988 term_print_finish();
1992 case 'l': /* toggle modes to low */
1994 compatibility(VT100
);
1997 for (i
= 0; i
< esc_nargs
; i
++)
1998 toggle_mode(esc_args
[i
], esc_query
, FALSE
);
2001 case 'g': /* clear tabs */
2002 compatibility(VT100
);
2003 if (esc_nargs
== 1) {
2004 if (esc_args
[0] == 0) {
2005 tabs
[curs
.x
] = FALSE
;
2006 } else if (esc_args
[0] == 3) {
2008 for (i
= 0; i
< cols
; i
++)
2013 case 'r': /* set scroll margins */
2014 compatibility(VT100
);
2015 if (esc_nargs
<= 2) {
2017 top
= def(esc_args
[0], 1) - 1;
2018 bot
= (esc_nargs
<= 1
2020 0 ? rows
: def(esc_args
[1], rows
)) - 1;
2023 /* VTTEST Bug 9 - if region is less than 2 lines
2024 * don't change region.
2026 if (bot
- top
> 0) {
2031 * I used to think the cursor should be
2032 * placed at the top of the newly marginned
2033 * area. Apparently not: VMS TPU falls over
2036 * Well actually it should for Origin mode - RDB
2038 curs
.y
= (dec_om ? marg_t
: 0);
2040 seen_disp_event
= TRUE
;
2044 case 'm': /* set graphics rendition */
2047 * A VT100 without the AVO only had one attribute, either
2048 * underline or reverse video depending on the cursor type,
2049 * this was selected by CSI 7m.
2052 * This is sometimes DIM, eg on the GIGI and Linux
2054 * This is sometimes INVIS various ANSI.
2056 * This like 22 disables BOLD, DIM and INVIS
2058 * The ANSI colours appear on any terminal that has colour
2059 * (obviously) but the interaction between sgr0 and the
2060 * colours varies but is usually related to the background
2061 * colour erase item.
2062 * The interaction between colour attributes and the mono
2063 * ones is also very implementation dependent.
2065 * The 39 and 49 attributes are likely to be unimplemented.
2068 for (i
= 0; i
< esc_nargs
; i
++) {
2069 switch (def(esc_args
[i
], 0)) {
2070 case 0: /* restore defaults */
2071 curr_attr
= ATTR_DEFAULT
;
2073 case 1: /* enable bold */
2074 compatibility(VT100AVO
);
2075 curr_attr
|= ATTR_BOLD
;
2077 case 21: /* (enable double underline) */
2078 compatibility(OTHER
);
2079 case 4: /* enable underline */
2080 compatibility(VT100AVO
);
2081 curr_attr
|= ATTR_UNDER
;
2083 case 5: /* enable blink */
2084 compatibility(VT100AVO
);
2085 curr_attr
|= ATTR_BLINK
;
2087 case 7: /* enable reverse video */
2088 curr_attr
|= ATTR_REVERSE
;
2090 case 10: /* SCO acs off */
2091 compatibility(SCOANSI
);
2092 if (cfg
.no_remote_charset
) break;
2094 case 11: /* SCO acs on */
2095 compatibility(SCOANSI
);
2096 if (cfg
.no_remote_charset
) break;
2098 case 12: /* SCO acs on flipped */
2099 compatibility(SCOANSI
);
2100 if (cfg
.no_remote_charset
) break;
2102 case 22: /* disable bold */
2103 compatibility2(OTHER
, VT220
);
2104 curr_attr
&= ~ATTR_BOLD
;
2106 case 24: /* disable underline */
2107 compatibility2(OTHER
, VT220
);
2108 curr_attr
&= ~ATTR_UNDER
;
2110 case 25: /* disable blink */
2111 compatibility2(OTHER
, VT220
);
2112 curr_attr
&= ~ATTR_BLINK
;
2114 case 27: /* disable reverse video */
2115 compatibility2(OTHER
, VT220
);
2116 curr_attr
&= ~ATTR_REVERSE
;
2127 curr_attr
&= ~ATTR_FGMASK
;
2129 (esc_args
[i
] - 30) << ATTR_FGSHIFT
;
2131 case 39: /* default-foreground */
2132 curr_attr
&= ~ATTR_FGMASK
;
2133 curr_attr
|= ATTR_DEFFG
;
2144 curr_attr
&= ~ATTR_BGMASK
;
2146 (esc_args
[i
] - 40) << ATTR_BGSHIFT
;
2148 case 49: /* default-background */
2149 curr_attr
&= ~ATTR_BGMASK
;
2150 curr_attr
|= ATTR_DEFBG
;
2155 erase_char
= (' ' | ATTR_ASCII
|
2157 (ATTR_FGMASK
| ATTR_BGMASK
)));
2160 case 's': /* save cursor */
2163 case 'u': /* restore cursor */
2165 seen_disp_event
= TRUE
;
2167 case 't': /* set page size - ie window height */
2169 * VT340/VT420 sequence DECSLPP, DEC only allows values
2170 * 24/25/36/48/72/144 other emulators (eg dtterm) use
2171 * illegal values (eg first arg 1..9) for window changing
2175 && (esc_args
[0] < 1 || esc_args
[0] >= 24)) {
2176 compatibility(VT340TEXT
);
2177 if (!cfg
.no_remote_resize
)
2178 request_resize(cols
, def(esc_args
[0], 24));
2180 } else if (esc_nargs
>= 1 &&
2183 compatibility(OTHER
);
2185 switch (esc_args
[0]) {
2195 if (esc_nargs
>= 3) {
2196 if (!cfg
.no_remote_resize
)
2197 move_window(def(esc_args
[1], 0),
2198 def(esc_args
[2], 0));
2202 /* We should resize the window to a given
2203 * size in pixels here, but currently our
2204 * resizing code isn't healthy enough to
2208 set_zorder(TRUE
); /* move to top */
2211 set_zorder(FALSE
); /* move to bottom */
2217 if (esc_nargs
>= 3) {
2218 if (!cfg
.no_remote_resize
)
2219 request_resize(def(esc_args
[2], cfg
.width
),
2220 def(esc_args
[1], cfg
.height
));
2225 set_zoomed(esc_args
[1] ? TRUE
: FALSE
);
2228 ldisc_send(is_iconic() ?
"\033[1t" : "\033[2t",
2232 get_window_pos(&x
, &y
);
2233 len
= sprintf(buf
, "\033[3;%d;%dt", x
, y
);
2234 ldisc_send(buf
, len
, 0);
2237 get_window_pixels(&x
, &y
);
2238 len
= sprintf(buf
, "\033[4;%d;%dt", x
, y
);
2239 ldisc_send(buf
, len
, 0);
2242 len
= sprintf(buf
, "\033[8;%d;%dt",
2244 ldisc_send(buf
, len
, 0);
2248 * Hmmm. Strictly speaking we
2249 * should return `the size of the
2250 * screen in characters', but
2251 * that's not easy: (a) window
2252 * furniture being what it is it's
2253 * hard to compute, and (b) in
2254 * resize-font mode maximising the
2255 * window wouldn't change the
2256 * number of characters. *shrug*. I
2257 * think we'll ignore it for the
2258 * moment and see if anyone
2259 * complains, and then ask them
2260 * what they would like it to do.
2264 p
= get_window_title(TRUE
);
2266 ldisc_send("\033]L", 3, 0);
2267 ldisc_send(p
, len
, 0);
2268 ldisc_send("\033\\", 2, 0);
2271 p
= get_window_title(FALSE
);
2273 ldisc_send("\033]l", 3, 0);
2274 ldisc_send(p
, len
, 0);
2275 ldisc_send("\033\\", 2, 0);
2281 compatibility(SCOANSI
);
2282 scroll(marg_t
, marg_b
, def(esc_args
[0], 1), TRUE
);
2285 seen_disp_event
= TRUE
;
2288 compatibility(SCOANSI
);
2289 scroll(marg_t
, marg_b
, -def(esc_args
[0], 1), TRUE
);
2292 seen_disp_event
= TRUE
;
2294 case ANSI('|', '*'):
2295 /* VT420 sequence DECSNLS
2296 * Set number of lines on screen
2297 * VT420 uses VGA like hardware and can support any size in
2298 * reasonable range (24..49 AIUI) with no default specified.
2300 compatibility(VT420
);
2301 if (esc_nargs
== 1 && esc_args
[0] > 0) {
2302 if (!cfg
.no_remote_resize
)
2303 request_resize(cols
, def(esc_args
[0], cfg
.height
));
2307 case ANSI('|', '$'):
2308 /* VT340/VT420 sequence DECSCPP
2309 * Set number of columns per page
2310 * Docs imply range is only 80 or 132, but I'll allow any.
2312 compatibility(VT340TEXT
);
2313 if (esc_nargs
<= 1) {
2314 if (!cfg
.no_remote_resize
)
2315 request_resize(def(esc_args
[0], cfg
.width
), rows
);
2319 case 'X': /* write N spaces w/o moving cursor */
2320 /* XXX VTTEST says this is vt220, vt510 manual says vt100 */
2321 compatibility(ANSIMIN
);
2323 int n
= def(esc_args
[0], 1);
2325 unsigned long *p
= cpos
;
2326 if (n
> cols
- curs
.x
)
2330 check_selection(curs
, cursplus
);
2333 seen_disp_event
= TRUE
;
2336 case 'x': /* report terminal characteristics */
2337 compatibility(VT100
);
2340 int i
= def(esc_args
[0], 0);
2341 if (i
== 0 || i
== 1) {
2342 strcpy(buf
, "\033[2;1;1;112;112;1;0x");
2344 ldisc_send(buf
, 20, 0);
2348 case 'Z': /* BackTab for xterm */
2349 compatibility(OTHER
);
2351 int i
= def(esc_args
[0], 1);
2352 pos old_curs
= curs
;
2354 for(;i
>0 && curs
.x
>0; i
--) {
2357 } while (curs
.x
>0 && !tabs
[curs
.x
]);
2360 check_selection(old_curs
, curs
);
2363 case ANSI('L', '='):
2364 compatibility(OTHER
);
2365 use_bce
= (esc_args
[0] <= 0);
2366 erase_char
= ERASE_CHAR
;
2368 erase_char
= (' ' | ATTR_ASCII
|
2370 (ATTR_FGMASK
| ATTR_BGMASK
)));
2372 case ANSI('E', '='):
2373 compatibility(OTHER
);
2374 blink_is_real
= (esc_args
[0] >= 1);
2376 case ANSI('p', '"'):
2377 /* Allow the host to make this emulator a 'perfect' VT102.
2378 * This first appeared in the VT220, but we do need to get
2379 * back to PuTTY mode so I won't check it.
2381 * The arg in 40..42,50 are a PuTTY extension.
2382 * The 2nd arg, 8bit vs 7bit is not checked.
2384 * Setting VT102 mode should also change the Fkeys to
2385 * generate PF* codes as a real VT102 has no Fkeys.
2386 * The VT220 does this, F11..F13 become ESC,BS,LF other Fkeys
2389 * Note ESC c will NOT change this!
2392 switch (esc_args
[0]) {
2394 compatibility_level
&= ~TM_VTXXX
;
2395 compatibility_level
|= TM_VT102
;
2398 compatibility_level
&= ~TM_VTXXX
;
2399 compatibility_level
|= TM_VT220
;
2403 if (esc_args
[0] > 60 && esc_args
[0] < 70)
2404 compatibility_level
|= TM_VTXXX
;
2408 compatibility_level
&= TM_VTXXX
;
2411 compatibility_level
= TM_PUTTY
;
2414 compatibility_level
= TM_SCOANSI
;
2418 compatibility_level
= TM_PUTTY
;
2424 /* Change the response to CSI c */
2425 if (esc_args
[0] == 50) {
2428 strcpy(id_string
, "\033[?");
2429 for (i
= 1; i
< esc_nargs
; i
++) {
2431 strcat(id_string
, ";");
2432 sprintf(lbuf
, "%d", esc_args
[i
]);
2433 strcat(id_string
, lbuf
);
2435 strcat(id_string
, "c");
2438 /* Is this a good idea ?
2439 * Well we should do a soft reset at this point ...
2441 if (!has_compat(VT420
) && has_compat(VT100
)) {
2442 if (!cfg
.no_remote_resize
) {
2444 request_resize(132, 24);
2446 request_resize(80, 24);
2456 case 'P': /* Linux palette sequence */
2457 termstate
= SEEN_OSC_P
;
2460 case 'R': /* Linux palette reset */
2463 termstate
= TOPLEVEL
;
2465 case 'W': /* word-set */
2466 termstate
= SEEN_OSC_W
;
2479 esc_args
[0] = 10 * esc_args
[0] + c
- '0';
2483 * Grotty hack to support xterm and DECterm title
2484 * sequences concurrently.
2486 if (esc_args
[0] == 2) {
2490 /* else fall through */
2492 termstate
= OSC_STRING
;
2498 * This OSC stuff is EVIL. It takes just one character to get into
2499 * sysline mode and it's not initially obvious how to get out.
2500 * So I've added CR and LF as string aborts.
2501 * This shouldn't effect compatibility as I believe embedded
2502 * control characters are supposed to be interpreted (maybe?)
2503 * and they don't display anything useful anyway.
2507 if (c
== '\n' || c
== '\r') {
2508 termstate
= TOPLEVEL
;
2509 } else if (c
== 0234 || c
== '\007') {
2511 * These characters terminate the string; ST and BEL
2512 * terminate the sequence and trigger instant
2513 * processing of it, whereas ESC goes back to SEEN_ESC
2514 * mode unless it is followed by \, in which case it is
2515 * synonymous with ST in the first place.
2518 termstate
= TOPLEVEL
;
2519 } else if (c
== '\033')
2520 termstate
= OSC_MAYBE_ST
;
2521 else if (osc_strlen
< OSC_STR_MAX
)
2522 osc_string
[osc_strlen
++] = c
;
2526 int max
= (osc_strlen
== 0 ?
21 : 16);
2528 if (c
>= '0' && c
<= '9')
2530 else if (c
>= 'A' && c
<= 'A' + max
- 10)
2532 else if (c
>= 'a' && c
<= 'a' + max
- 10)
2535 termstate
= TOPLEVEL
;
2538 osc_string
[osc_strlen
++] = val
;
2539 if (osc_strlen
>= 7) {
2540 palette_set(osc_string
[0],
2541 osc_string
[1] * 16 + osc_string
[2],
2542 osc_string
[3] * 16 + osc_string
[4],
2543 osc_string
[5] * 16 + osc_string
[6]);
2545 termstate
= TOPLEVEL
;
2561 esc_args
[0] = 10 * esc_args
[0] + c
- '0';
2564 termstate
= OSC_STRING
;
2569 termstate
= TOPLEVEL
;
2570 seen_disp_event
= TRUE
;
2573 move(curs
.x
, curs
.y
- 1, 1);
2576 move(curs
.x
, curs
.y
+ 1, 1);
2579 move(curs
.x
+ 1, curs
.y
, 1);
2582 move(curs
.x
- 1, curs
.y
, 1);
2585 * From the VT100 Manual
2586 * NOTE: The special graphics characters in the VT100
2587 * are different from those in the VT52
2589 * From VT102 manual:
2590 * 137 _ Blank - Same
2591 * 140 ` Reserved - Humm.
2592 * 141 a Solid rectangle - Similar
2593 * 142 b 1/ - Top half of fraction for the
2594 * 143 c 3/ - subscript numbers below.
2597 * 146 f Degrees - Same
2598 * 147 g Plus or minus - Same
2600 * 151 i Ellipsis (dots)
2603 * 154 l Bar at scan 0
2604 * 155 m Bar at scan 1
2605 * 156 n Bar at scan 2
2606 * 157 o Bar at scan 3 - Similar
2607 * 160 p Bar at scan 4 - Similar
2608 * 161 q Bar at scan 5 - Similar
2609 * 162 r Bar at scan 6 - Same
2610 * 163 s Bar at scan 7 - Similar
2625 cset_attr
[cset
= 0] = ATTR_LINEDRW
;
2628 cset_attr
[cset
= 0] = ATTR_ASCII
;
2635 scroll(0, rows
- 1, -1, TRUE
);
2636 else if (curs
.y
> 0)
2642 erase_lots(FALSE
, FALSE
, TRUE
);
2646 erase_lots(TRUE
, FALSE
, TRUE
);
2650 /* XXX Print cursor line */
2653 /* XXX Start controller mode */
2656 /* XXX Stop controller mode */
2660 termstate
= VT52_Y1
;
2663 ldisc_send("\033/Z", 3, 0);
2666 app_keypad_keys
= TRUE
;
2669 app_keypad_keys
= FALSE
;
2672 /* XXX This should switch to VT100 mode not current or default
2673 * VT mode. But this will only have effect in a VT220+
2677 blink_is_real
= cfg
.blinktext
;
2681 /* XXX Enter auto print mode */
2684 /* XXX Exit auto print mode */
2687 /* XXX Print screen */
2693 /* compatibility(ATARI) */
2695 erase_lots(FALSE
, FALSE
, TRUE
);
2699 /* compatibility(ATARI) */
2700 if (curs
.y
<= marg_b
)
2701 scroll(curs
.y
, marg_b
, -1, FALSE
);
2704 /* compatibility(ATARI) */
2705 if (curs
.y
<= marg_b
)
2706 scroll(curs
.y
, marg_b
, 1, TRUE
);
2709 /* compatibility(ATARI) */
2710 termstate
= VT52_FG
;
2713 /* compatibility(ATARI) */
2714 termstate
= VT52_BG
;
2717 /* compatibility(ATARI) */
2718 erase_lots(FALSE
, TRUE
, FALSE
);
2722 /* compatibility(ATARI) */
2726 /* compatibility(ATARI) */
2729 /* case 'j': Save cursor position - broken on ST */
2730 /* case 'k': Restore cursor position */
2732 /* compatibility(ATARI) */
2733 erase_lots(TRUE
, TRUE
, TRUE
);
2739 /* compatibility(ATARI) */
2740 erase_lots(TRUE
, TRUE
, FALSE
);
2743 /* compatibility(ATARI) */
2744 curr_attr
|= ATTR_REVERSE
;
2747 /* compatibility(ATARI) */
2748 curr_attr
&= ~ATTR_REVERSE
;
2750 case 'v': /* wrap Autowrap on - Wyse style */
2751 /* compatibility(ATARI) */
2754 case 'w': /* Autowrap off */
2755 /* compatibility(ATARI) */
2760 /* compatibility(OTHER) */
2762 curr_attr
= ATTR_DEFAULT
;
2764 erase_char
= (' ' | ATTR_ASCII
|
2766 (ATTR_FGMASK
| ATTR_BGMASK
)));
2769 /* compatibility(VI50) */
2770 curr_attr
|= ATTR_UNDER
;
2773 /* compatibility(VI50) */
2774 curr_attr
&= ~ATTR_UNDER
;
2777 /* compatibility(VI50) */
2779 curr_attr
|= ATTR_BOLD
;
2782 /* compatibility(VI50) */
2784 curr_attr
&= ~ATTR_BOLD
;
2790 termstate
= VT52_Y2
;
2791 move(curs
.x
, c
- ' ', 0);
2794 termstate
= TOPLEVEL
;
2795 move(c
- ' ', curs
.y
, 0);
2800 termstate
= TOPLEVEL
;
2801 curr_attr
&= ~ATTR_FGMASK
;
2802 curr_attr
&= ~ATTR_BOLD
;
2803 curr_attr
|= (c
& 0x7) << ATTR_FGSHIFT
;
2804 if ((c
& 0x8) || vt52_bold
)
2805 curr_attr
|= ATTR_BOLD
;
2808 erase_char
= (' ' | ATTR_ASCII
|
2809 (curr_attr
& (ATTR_FGMASK
| ATTR_BGMASK
)));
2812 termstate
= TOPLEVEL
;
2813 curr_attr
&= ~ATTR_BGMASK
;
2814 curr_attr
&= ~ATTR_BLINK
;
2815 curr_attr
|= (c
& 0x7) << ATTR_BGSHIFT
;
2817 /* Note: bold background */
2819 curr_attr
|= ATTR_BLINK
;
2822 erase_char
= (' ' | ATTR_ASCII
|
2823 (curr_attr
& (ATTR_FGMASK
| ATTR_BGMASK
)));
2826 default: break; /* placate gcc warning about enum use */
2828 if (selstate
!= NO_SELECTION
) {
2829 pos cursplus
= curs
;
2831 check_selection(curs
, cursplus
);
2840 * Compare two lines to determine whether they are sufficiently
2841 * alike to scroll-optimise one to the other. Return the degree of
2844 static int linecmp(unsigned long *a
, unsigned long *b
)
2848 for (i
= n
= 0; i
< cols
; i
++)
2849 n
+= (*a
++ == *b
++);
2855 * Given a context, update the window. Out of paranoia, we don't
2856 * allow WM_PAINT responses to do scrolling optimisations.
2858 static void do_paint(Context ctx
, int may_optimise
)
2860 int i
, j
, our_curs_y
;
2861 unsigned long rv
, cursor
;
2864 long cursor_background
= ERASE_CHAR
;
2865 unsigned long ticks
;
2868 * Check the visual bell state.
2871 ticks
= GETTICKCOUNT();
2872 if (ticks
- vbell_startpoint
>= VBELL_TIMEOUT
)
2876 rv
= (!rvideo
^ !in_vbell ? ATTR_REVERSE
: 0);
2879 * screen array, disptop, scrtop,
2881 * cfg.blinkpc, blink_is_real, tblinker,
2882 * curs.y, curs.x, blinker, cfg.blink_cur, cursor_on, has_focus, wrapnext
2885 /* Has the cursor position or type changed ? */
2888 if (blinker
|| !cfg
.blink_cur
)
2889 cursor
= TATTR_ACTCURS
;
2893 cursor
= TATTR_PASCURS
;
2895 cursor
|= TATTR_RIGHTCURS
;
2898 our_curs_y
= curs
.y
- disptop
;
2900 if (dispcurs
&& (curstype
!= cursor
||
2902 disptext
+ our_curs_y
* (cols
+ 1) + curs
.x
)) {
2903 if (dispcurs
> disptext
&&
2904 (*dispcurs
& (CHAR_MASK
| CSET_MASK
)) == UCSWIDE
)
2905 dispcurs
[-1] |= ATTR_INVALID
;
2906 if ( (dispcurs
[1] & (CHAR_MASK
| CSET_MASK
)) == UCSWIDE
)
2907 dispcurs
[1] |= ATTR_INVALID
;
2908 *dispcurs
|= ATTR_INVALID
;
2913 /* The normal screen data */
2914 for (i
= 0; i
< rows
; i
++) {
2915 unsigned long *ldata
;
2917 int idx
, dirty_line
, dirty_run
, selected
;
2918 unsigned long attr
= 0;
2919 int updated_line
= 0;
2922 int last_run_dirty
= 0;
2924 scrpos
.y
= i
+ disptop
;
2925 ldata
= lineptr(scrpos
.y
);
2926 lattr
= (ldata
[cols
] & LATTR_MODE
);
2928 idx
= i
* (cols
+ 1);
2929 dirty_run
= dirty_line
= (ldata
[cols
] != disptext
[idx
+ cols
]);
2930 disptext
[idx
+ cols
] = ldata
[cols
];
2932 for (j
= 0; j
< cols
; j
++, idx
++) {
2933 unsigned long tattr
, tchar
;
2934 unsigned long *d
= ldata
+ j
;
2938 tchar
= (*d
& (CHAR_MASK
| CSET_MASK
));
2939 tattr
= (*d
& (ATTR_MASK
^ CSET_MASK
));
2940 switch (tchar
& CSET_MASK
) {
2942 tchar
= unitab_line
[tchar
& 0xFF];
2945 tchar
= unitab_xterm
[tchar
& 0xFF];
2948 tchar
= unitab_scoacs
[tchar
&0xFF];
2951 tattr
|= (tchar
& CSET_MASK
);
2953 if ((d
[1] & (CHAR_MASK
| CSET_MASK
)) == UCSWIDE
)
2956 /* Video reversing things */
2957 if (seltype
== LEXICOGRAPHIC
)
2958 selected
= posle(selstart
, scrpos
) && poslt(scrpos
, selend
);
2960 selected
= posPle(selstart
, scrpos
) && posPlt(scrpos
, selend
);
2962 ^ (selected ? ATTR_REVERSE
: 0));
2964 /* 'Real' blinking ? */
2965 if (blink_is_real
&& (tattr
& ATTR_BLINK
)) {
2966 if (has_focus
&& tblinker
) {
2968 tattr
&= ~CSET_MASK
;
2971 tattr
&= ~ATTR_BLINK
;
2975 * Check the font we'll _probably_ be using to see if
2976 * the character is wide when we don't want it to be.
2978 if ((tchar
| tattr
) != (disptext
[idx
]& ~ATTR_NARROW
)) {
2979 if ((tattr
& ATTR_WIDE
) == 0 &&
2980 CharWidth(ctx
, (tchar
| tattr
) & 0xFFFF) == 2)
2981 tattr
|= ATTR_NARROW
;
2982 } else if (disptext
[idx
]&ATTR_NARROW
)
2983 tattr
|= ATTR_NARROW
;
2985 /* Cursor here ? Save the 'background' */
2986 if (i
== our_curs_y
&& j
== curs
.x
) {
2987 cursor_background
= tattr
| tchar
;
2988 dispcurs
= disptext
+ idx
;
2991 if ((disptext
[idx
] ^ tattr
) & ATTR_WIDE
)
2994 break_run
= (tattr
!= attr
|| j
- start
>= sizeof(ch
));
2996 /* Special hack for VT100 Linedraw glyphs */
2997 if ((attr
& CSET_MASK
) == 0x2300 && tchar
>= 0xBA
2998 && tchar
<= 0xBD) break_run
= TRUE
;
3000 if (!dbcs_screenfont
&& !dirty_line
) {
3001 if ((tchar
| tattr
) == disptext
[idx
])
3003 else if (!dirty_run
&& ccount
== 1)
3008 if ((dirty_run
|| last_run_dirty
) && ccount
> 0) {
3009 do_text(ctx
, start
, i
, ch
, ccount
, attr
, lattr
);
3015 if (dbcs_screenfont
)
3016 last_run_dirty
= dirty_run
;
3017 dirty_run
= dirty_line
;
3020 if ((tchar
| tattr
) != disptext
[idx
])
3022 ch
[ccount
++] = (char) tchar
;
3023 disptext
[idx
] = tchar
| tattr
;
3025 /* If it's a wide char step along to the next one. */
3026 if (tattr
& ATTR_WIDE
) {
3030 /* Cursor is here ? Ouch! */
3031 if (i
== our_curs_y
&& j
== curs
.x
) {
3032 cursor_background
= *d
;
3033 dispcurs
= disptext
+ idx
;
3035 if (disptext
[idx
] != *d
)
3041 if (dirty_run
&& ccount
> 0) {
3042 do_text(ctx
, start
, i
, ch
, ccount
, attr
, lattr
);
3046 /* Cursor on this line ? (and changed) */
3047 if (i
== our_curs_y
&& (curstype
!= cursor
|| updated_line
)) {
3048 ch
[0] = (char) (cursor_background
& CHAR_MASK
);
3049 attr
= (cursor_background
& ATTR_MASK
) | cursor
;
3050 do_cursor(ctx
, curs
.x
, i
, ch
, 1, attr
, lattr
);
3057 * Flick the switch that says if blinking things should be shown or hidden.
3060 void term_blink(int flg
)
3062 static long last_blink
= 0;
3063 static long last_tblink
= 0;
3064 long now
, blink_diff
;
3066 now
= GETTICKCOUNT();
3067 blink_diff
= now
- last_tblink
;
3069 /* Make sure the text blinks no more than 2Hz; we'll use 0.45 s period. */
3070 if (blink_diff
< 0 || blink_diff
> (TICKSPERSEC
* 9 / 20)) {
3072 tblinker
= !tblinker
;
3081 blink_diff
= now
- last_blink
;
3083 /* Make sure the cursor blinks no faster than system blink rate */
3084 if (blink_diff
>= 0 && blink_diff
< (long) CURSORBLINK
)
3092 * Invalidate the whole screen so it will be repainted in full.
3094 void term_invalidate(void)
3098 for (i
= 0; i
< rows
* (cols
+ 1); i
++)
3099 disptext
[i
] = ATTR_INVALID
;
3103 * Paint the window in response to a WM_PAINT message.
3105 void term_paint(Context ctx
, int left
, int top
, int right
, int bottom
)
3108 if (left
< 0) left
= 0;
3109 if (top
< 0) top
= 0;
3110 if (right
>= cols
) right
= cols
-1;
3111 if (bottom
>= rows
) bottom
= rows
-1;
3113 for (i
= top
; i
<= bottom
&& i
< rows
; i
++) {
3114 if ((disptext
[i
* (cols
+ 1) + cols
] & LATTR_MODE
) == LATTR_NORM
)
3115 for (j
= left
; j
<= right
&& j
< cols
; j
++)
3116 disptext
[i
* (cols
+ 1) + j
] = ATTR_INVALID
;
3118 for (j
= left
/ 2; j
<= right
/ 2 + 1 && j
< cols
; j
++)
3119 disptext
[i
* (cols
+ 1) + j
] = ATTR_INVALID
;
3122 /* This should happen soon enough, also for some reason it sometimes
3123 * fails to actually do anything when re-sizing ... painting the wrong
3127 do_paint (ctx
, FALSE
);
3131 * Attempt to scroll the scrollback. The second parameter gives the
3132 * position we want to scroll to; the first is +1 to denote that
3133 * this position is relative to the beginning of the scrollback, -1
3134 * to denote it is relative to the end, and 0 to denote that it is
3135 * relative to the current position.
3137 void term_scroll(int rel
, int where
)
3139 int sbtop
= -count234(scrollback
);
3141 disptop
= (rel
< 0 ?
0 : rel
> 0 ? sbtop
: disptop
) + where
;
3142 if (disptop
< sbtop
)
3150 static void clipme(pos top
, pos bottom
, int rect
)
3153 wchar_t *wbptr
; /* where next char goes within workbuf */
3155 int wblen
= 0; /* workbuf len */
3156 int buflen
; /* amount of memory allocated to workbuf */
3158 buflen
= 5120; /* Default size */
3159 workbuf
= smalloc(buflen
* sizeof(wchar_t));
3160 wbptr
= workbuf
; /* start filling here */
3161 old_top_x
= top
.x
; /* needed for rect==1 */
3163 while (poslt(top
, bottom
)) {
3165 unsigned long *ldata
= lineptr(top
.y
);
3169 * nlpos will point at the maximum position on this line we
3170 * should copy up to. So we start it at the end of the
3177 * ... move it backwards if there's unused space at the end
3178 * of the line (and also set `nl' if this is the case,
3179 * because in normal selection mode this means we need a
3180 * newline at the end)...
3182 if (!(ldata
[cols
] & LATTR_WRAPPED
)) {
3183 while (((ldata
[nlpos
.x
- 1] & 0xFF) == 0x20 ||
3184 (DIRECT_CHAR(ldata
[nlpos
.x
- 1]) &&
3185 (ldata
[nlpos
.x
- 1] & CHAR_MASK
) == 0x20))
3186 && poslt(top
, nlpos
))
3188 if (poslt(nlpos
, bottom
))
3193 * ... and then clip it to the terminal x coordinate if
3194 * we're doing rectangular selection. (In this case we
3195 * still did the above, so that copying e.g. the right-hand
3196 * column from a table doesn't fill with spaces on the
3200 if (nlpos
.x
> bottom
.x
)
3202 nl
= (top
.y
< bottom
.y
);
3205 while (poslt(top
, bottom
) && poslt(top
, nlpos
)) {
3208 sprintf(cbuf
, "<U+%04x>", (ldata
[top
.x
] & 0xFFFF));
3210 wchar_t cbuf
[16], *p
;
3211 int uc
= (ldata
[top
.x
] & 0xFFFF);
3214 if (uc
== UCSWIDE
) {
3219 switch (uc
& CSET_MASK
) {
3222 uc
= unitab_xterm
[uc
& 0xFF];
3226 uc
= unitab_line
[uc
& 0xFF];
3229 uc
= unitab_scoacs
[uc
&0xFF];
3232 switch (uc
& CSET_MASK
) {
3234 uc
= unitab_font
[uc
& 0xFF];
3237 uc
= unitab_oemcp
[uc
& 0xFF];
3241 set
= (uc
& CSET_MASK
);
3242 c
= (uc
& CHAR_MASK
);
3246 if (DIRECT_FONT(uc
)) {
3247 if (c
>= ' ' && c
!= 0x7F) {
3248 unsigned char buf
[4];
3251 if (is_dbcs_leadbyte(font_codepage
, (BYTE
) c
)) {
3253 buf
[1] = (unsigned char) ldata
[top
.x
+ 1];
3254 rv
= mb_to_wc(font_codepage
, 0, buf
, 2, wbuf
, 4);
3258 rv
= mb_to_wc(font_codepage
, 0, buf
, 1, wbuf
, 4);
3262 memcpy(cbuf
, wbuf
, rv
* sizeof(wchar_t));
3269 for (p
= cbuf
; *p
; p
++) {
3270 /* Enough overhead for trailing NL and nul */
3271 if (wblen
>= buflen
- 16) {
3274 sizeof(wchar_t) * (buflen
+= 100));
3275 wbptr
= workbuf
+ wblen
;
3284 for (i
= 0; i
< sel_nl_sz
; i
++) {
3286 *wbptr
++ = sel_nl
[i
];
3290 top
.x
= rect ? old_top_x
: 0;
3292 #if SELECTION_NUL_TERMINATED
3296 write_clip(workbuf
, wblen
, FALSE
); /* transfer to clipboard */
3297 if (buflen
> 0) /* indicates we allocated this buffer */
3301 void term_copyall(void)
3304 top
.y
= -count234(scrollback
);
3306 clipme(top
, curs
, 0);
3310 * The wordness array is mainly for deciding the disposition of the US-ASCII
3313 static int wordtype(int uc
)
3316 int start
, end
, ctype
;
3317 } *wptr
, ucs_words
[] = {
3323 0x037e, 0x037e, 1}, /* Greek question mark */
3325 0x0387, 0x0387, 1}, /* Greek ano teleia */
3327 0x055a, 0x055f, 1}, /* Armenian punctuation */
3329 0x0589, 0x0589, 1}, /* Armenian full stop */
3331 0x0700, 0x070d, 1}, /* Syriac punctuation */
3333 0x104a, 0x104f, 1}, /* Myanmar punctuation */
3335 0x10fb, 0x10fb, 1}, /* Georgian punctuation */
3337 0x1361, 0x1368, 1}, /* Ethiopic punctuation */
3339 0x166d, 0x166e, 1}, /* Canadian Syl. punctuation */
3341 0x17d4, 0x17dc, 1}, /* Khmer punctuation */
3343 0x1800, 0x180a, 1}, /* Mongolian punctuation */
3345 0x2000, 0x200a, 0}, /* Various spaces */
3347 0x2070, 0x207f, 2}, /* superscript */
3349 0x2080, 0x208f, 2}, /* subscript */
3351 0x200b, 0x27ff, 1}, /* punctuation and symbols */
3353 0x3000, 0x3000, 0}, /* ideographic space */
3355 0x3001, 0x3020, 1}, /* ideographic punctuation */
3357 0x303f, 0x309f, 3}, /* Hiragana */
3359 0x30a0, 0x30ff, 3}, /* Katakana */
3361 0x3300, 0x9fff, 3}, /* CJK Ideographs */
3363 0xac00, 0xd7a3, 3}, /* Hangul Syllables */
3365 0xf900, 0xfaff, 3}, /* CJK Ideographs */
3367 0xfe30, 0xfe6b, 1}, /* punctuation forms */
3369 0xff00, 0xff0f, 1}, /* half/fullwidth ASCII */
3371 0xff1a, 0xff20, 1}, /* half/fullwidth ASCII */
3373 0xff3b, 0xff40, 1}, /* half/fullwidth ASCII */
3375 0xff5b, 0xff64, 1}, /* half/fullwidth ASCII */
3377 0xfff0, 0xffff, 0}, /* half/fullwidth ASCII */
3382 uc
&= (CSET_MASK
| CHAR_MASK
);
3384 switch (uc
& CSET_MASK
) {
3386 uc
= unitab_xterm
[uc
& 0xFF];
3389 uc
= unitab_line
[uc
& 0xFF];
3392 uc
= unitab_scoacs
[uc
&0xFF];
3395 switch (uc
& CSET_MASK
) {
3397 uc
= unitab_font
[uc
& 0xFF];
3400 uc
= unitab_oemcp
[uc
& 0xFF];
3404 /* For DBCS font's I can't do anything usefull. Even this will sometimes
3405 * fail as there's such a thing as a double width space. :-(
3407 if (dbcs_screenfont
&& font_codepage
== line_codepage
)
3411 return wordness
[uc
];
3413 for (wptr
= ucs_words
; wptr
->start
; wptr
++) {
3414 if (uc
>= wptr
->start
&& uc
<= wptr
->end
)
3422 * Spread the selection outwards according to the selection mode.
3424 static pos
sel_spread_half(pos p
, int dir
)
3426 unsigned long *ldata
;
3428 int topy
= -count234(scrollback
);
3430 ldata
= lineptr(p
.y
);
3435 * In this mode, every character is a separate unit, except
3436 * for runs of spaces at the end of a non-wrapping line.
3438 if (!(ldata
[cols
] & LATTR_WRAPPED
)) {
3439 unsigned long *q
= ldata
+ cols
;
3440 while (q
> ldata
&& (q
[-1] & CHAR_MASK
) == 0x20)
3442 if (q
== ldata
+ cols
)
3444 if (p
.x
>= q
- ldata
)
3445 p
.x
= (dir
== -1 ? q
- ldata
: cols
- 1);
3450 * In this mode, the units are maximal runs of characters
3451 * whose `wordness' has the same value.
3453 wvalue
= wordtype(ldata
[p
.x
]);
3457 if (wordtype(ldata
[p
.x
+ 1]) == wvalue
)
3462 if (ldata
[cols
] & LATTR_WRAPPED
) {
3463 unsigned long *ldata2
;
3464 ldata2
= lineptr(p
.y
+1);
3465 if (wordtype(ldata2
[0]) == wvalue
) {
3478 if (wordtype(ldata
[p
.x
- 1]) == wvalue
)
3483 unsigned long *ldata2
;
3486 ldata2
= lineptr(p
.y
-1);
3487 if ((ldata2
[cols
] & LATTR_WRAPPED
) &&
3488 wordtype(ldata2
[cols
-1]) == wvalue
) {
3500 * In this mode, every line is a unit.
3502 p
.x
= (dir
== -1 ?
0 : cols
- 1);
3508 static void sel_spread(void)
3510 if (seltype
== LEXICOGRAPHIC
) {
3511 selstart
= sel_spread_half(selstart
, -1);
3513 selend
= sel_spread_half(selend
, +1);
3518 void term_do_paste(void)
3523 get_clip(&data
, &len
);
3524 if (data
&& len
> 0) {
3527 term_seen_key_event(); /* pasted data counts */
3530 sfree(paste_buffer
);
3531 paste_pos
= paste_hold
= paste_len
= 0;
3532 paste_buffer
= smalloc(len
* sizeof(wchar_t));
3535 while (p
< data
+ len
) {
3536 while (p
< data
+ len
&&
3537 !(p
<= data
+ len
- sel_nl_sz
&&
3538 !memcmp(p
, sel_nl
, sizeof(sel_nl
))))
3543 for (i
= 0; i
< p
- q
; i
++) {
3544 paste_buffer
[paste_len
++] = q
[i
];
3548 if (p
<= data
+ len
- sel_nl_sz
&&
3549 !memcmp(p
, sel_nl
, sizeof(sel_nl
))) {
3550 paste_buffer
[paste_len
++] = '\r';
3556 /* Assume a small paste will be OK in one go. */
3557 if (paste_len
< 256) {
3558 luni_send(paste_buffer
, paste_len
, 0);
3560 sfree(paste_buffer
);
3562 paste_pos
= paste_hold
= paste_len
= 0;
3565 get_clip(NULL
, NULL
);
3568 void term_mouse(Mouse_Button b
, Mouse_Action a
, int x
, int y
,
3569 int shift
, int ctrl
, int alt
)
3572 unsigned long *ldata
;
3573 int raw_mouse
= (xterm_mouse
&&
3574 !cfg
.no_mouse_rep
&&
3575 !(cfg
.mouse_override
&& shift
));
3576 int default_seltype
;
3580 if (a
== MA_DRAG
&& !raw_mouse
)
3585 if (a
== MA_DRAG
&& !raw_mouse
)
3598 selpoint
.y
= y
+ disptop
;
3600 ldata
= lineptr(selpoint
.y
);
3601 if ((ldata
[cols
] & LATTR_MODE
) != LATTR_NORM
)
3605 int encstate
= 0, r
, c
;
3607 static int is_down
= 0;
3611 encstate
= 0x20; /* left button down */
3622 case MBT_WHEEL_DOWN
:
3625 default: break; /* placate gcc warning about enum use */
3629 if (xterm_mouse
== 1)
3642 default: break; /* placate gcc warning about enum use */
3651 sprintf(abuf
, "\033[M%c%c%c", encstate
, c
, r
);
3652 ldisc_send(abuf
, 6, 0);
3656 b
= translate_button(b
);
3659 * Set the selection type (rectangular or normal) at the start
3660 * of a selection attempt, from the state of Alt.
3662 if (!alt
^ !cfg
.rect_select
)
3663 default_seltype
= RECTANGULAR
;
3665 default_seltype
= LEXICOGRAPHIC
;
3667 if (selstate
== NO_SELECTION
) {
3668 seltype
= default_seltype
;
3671 if (b
== MBT_SELECT
&& a
== MA_CLICK
) {
3673 selstate
= ABOUT_TO
;
3674 seltype
= default_seltype
;
3675 selanchor
= selpoint
;
3677 } else if (b
== MBT_SELECT
&& (a
== MA_2CLK
|| a
== MA_3CLK
)) {
3679 selmode
= (a
== MA_2CLK ? SM_WORD
: SM_LINE
);
3680 selstate
= DRAGGING
;
3681 selstart
= selanchor
= selpoint
;
3685 } else if ((b
== MBT_SELECT
&& a
== MA_DRAG
) ||
3686 (b
== MBT_EXTEND
&& a
!= MA_RELEASE
)) {
3687 if (selstate
== ABOUT_TO
&& poseq(selanchor
, selpoint
))
3689 if (b
== MBT_EXTEND
&& a
!= MA_DRAG
&& selstate
== SELECTED
) {
3690 if (seltype
== LEXICOGRAPHIC
) {
3692 * For normal selection, we extend by moving
3693 * whichever end of the current selection is closer
3696 if (posdiff(selpoint
, selstart
) <
3697 posdiff(selend
, selstart
) / 2) {
3701 selanchor
= selstart
;
3705 * For rectangular selection, we have a choice of
3706 * _four_ places to put selanchor and selpoint: the
3707 * four corners of the selection.
3709 if (2*selpoint
.x
< selstart
.x
+ selend
.x
)
3710 selanchor
.x
= selend
.x
-1;
3712 selanchor
.x
= selstart
.x
;
3714 if (2*selpoint
.y
< selstart
.y
+ selend
.y
)
3715 selanchor
.y
= selend
.y
;
3717 selanchor
.y
= selstart
.y
;
3719 selstate
= DRAGGING
;
3721 if (selstate
!= ABOUT_TO
&& selstate
!= DRAGGING
)
3722 selanchor
= selpoint
;
3723 selstate
= DRAGGING
;
3724 if (seltype
== LEXICOGRAPHIC
) {
3726 * For normal selection, we set (selstart,selend) to
3727 * (selpoint,selanchor) in some order.
3729 if (poslt(selpoint
, selanchor
)) {
3730 selstart
= selpoint
;
3734 selstart
= selanchor
;
3740 * For rectangular selection, we may need to
3741 * interchange x and y coordinates (if the user has
3742 * dragged in the -x and +y directions, or vice versa).
3744 selstart
.x
= min(selanchor
.x
, selpoint
.x
);
3745 selend
.x
= 1+max(selanchor
.x
, selpoint
.x
);
3746 selstart
.y
= min(selanchor
.y
, selpoint
.y
);
3747 selend
.y
= max(selanchor
.y
, selpoint
.y
);
3750 } else if ((b
== MBT_SELECT
|| b
== MBT_EXTEND
) && a
== MA_RELEASE
) {
3751 if (selstate
== DRAGGING
) {
3753 * We've completed a selection. We now transfer the
3754 * data to the clipboard.
3756 clipme(selstart
, selend
, (seltype
== RECTANGULAR
));
3757 selstate
= SELECTED
;
3759 selstate
= NO_SELECTION
;
3760 } else if (b
== MBT_PASTE
3762 #if MULTICLICK_ONLY_EVENT
3763 || a
== MA_2CLK
|| a
== MA_3CLK
3776 sfree(paste_buffer
);
3781 int term_paste_pending(void)
3783 return paste_len
!= 0;
3788 static long last_paste
= 0;
3789 long now
, paste_diff
;
3794 /* Don't wait forever to paste */
3796 now
= GETTICKCOUNT();
3797 paste_diff
= now
- last_paste
;
3798 if (paste_diff
>= 0 && paste_diff
< 450)
3803 while (paste_pos
< paste_len
) {
3805 while (n
+ paste_pos
< paste_len
) {
3806 if (paste_buffer
[paste_pos
+ n
++] == '\r')
3809 luni_send(paste_buffer
+ paste_pos
, n
, 0);
3812 if (paste_pos
< paste_len
) {
3817 sfree(paste_buffer
);
3822 static void deselect(void)
3824 selstate
= NO_SELECTION
;
3825 selstart
.x
= selstart
.y
= selend
.x
= selend
.y
= 0;
3828 void term_deselect(void)
3834 int term_ldisc(int option
)
3836 if (option
== LD_ECHO
)
3837 return term_echoing
;
3838 if (option
== LD_EDIT
)
3839 return term_editing
;
3844 * from_backend(), to get data from the backend for the terminal.
3846 int from_backend(int is_stderr
, char *data
, int len
)
3850 bufchain_add(&inbuf
, data
, len
);
3853 * term_out() always completely empties inbuf. Therefore,
3854 * there's no reason at all to return anything other than zero
3855 * from this function, because there _can't_ be a question of
3856 * the remote side needing to wait until term_out() has cleared
3859 * This is a slightly suboptimal way to deal with SSH2 - in
3860 * principle, the window mechanism would allow us to continue
3861 * to accept data on forwarded ports and X connections even
3862 * while the terminal processing was going slowly - but we
3863 * can't do the 100% right thing without moving the terminal
3864 * processing into a separate thread, and that might hurt
3865 * portability. So we manage stdout buffering the old SSH1 way:
3866 * if the terminal processing goes slowly, the whole SSH
3867 * connection stops accepting data until it's ready.
3869 * In practice, I can't imagine this causing serious trouble.