term_out() can in turn call ldisc_send() which calls back to
from_backend() when local echo is enabled. This was giving rise to
crazy re-entrancy stuff and stack overflows. Instead from_backend()
deposits its data in a bufchain which term_out() empties the next
time it's called.
git-svn-id: svn://svn.tartarus.org/sgt/putty@1276
cda61777-01e9-0310-a592-
d414129be87e
GLOBAL int rows, cols, savelines;
GLOBAL int rows, cols, savelines;
-#define INBUF_SIZE 2048
-GLOBAL unsigned char inbuf[INBUF_SIZE];
-GLOBAL int inbuf_head;
-
-#define OUTBUF_SIZE 2048
-#define OUTBUF_MASK (OUTBUF_SIZE-1)
-GLOBAL unsigned char outbuf[OUTBUF_SIZE];
-GLOBAL int outbuf_head, outbuf_reap;
-
GLOBAL int has_focus;
GLOBAL int in_vbell;
GLOBAL int has_focus;
GLOBAL int in_vbell;
/*
* If this is before the real session begins, just return.
*/
/*
* If this is before the real session begins, just return.
*/
#define incpos(p) ( (p).x == cols ? ((p).x = 0, (p).y++, 1) : ((p).x++, 0) )
#define decpos(p) ( (p).x == 0 ? ((p).x = cols, (p).y--, 1) : ((p).x--, 0) )
#define incpos(p) ( (p).x == cols ? ((p).x = 0, (p).y++, 1) : ((p).x++, 0) )
#define decpos(p) ( (p).x == 0 ? ((p).x = cols, (p).y--, 1) : ((p).x--, 0) )
+static bufchain inbuf; /* terminal input buffer */
static pos curs; /* cursor */
static pos savecurs; /* saved cursor position */
static int marg_t, marg_b; /* scroll margins */
static pos curs; /* cursor */
static pos savecurs; /* saved cursor position */
static int marg_t, marg_b; /* scroll margins */
+ int c, unget;
+ unsigned char localbuf[256], *chars;
+ int nchars = 0;
+
+ unget = -1;
+
+ while (nchars > 0 || bufchain_size(&inbuf) > 0) {
+ if (unget == -1) {
+ if (nchars == 0) {
+ void *ret;
+ bufchain_prefix(&inbuf, &ret, &nchars);
+ if (nchars > sizeof(localbuf))
+ nchars = sizeof(localbuf);
+ memcpy(localbuf, ret, nchars);
+ bufchain_consume(&inbuf, nchars);
+ chars = localbuf;
+ assert(chars != NULL);
+ }
+ c = *chars++;
+ nchars--;
- /*
- * Optionally log the session traffic to a file. Useful for
- * debugging and possibly also useful for actual logging.
- */
- if (cfg.logtype == LGTYP_DEBUG)
- for (inbuf_reap = 0; inbuf_reap < inbuf_head; inbuf_reap++) {
- logtraffic((unsigned char) inbuf[inbuf_reap], LGTYP_DEBUG);
+ /*
+ * Optionally log the session traffic to a file. Useful for
+ * debugging and possibly also useful for actual logging.
+ */
+ if (cfg.logtype == LGTYP_DEBUG)
+ logtraffic((unsigned char) &c, LGTYP_DEBUG);
+ } else {
+ c = unget;
+ unget = -1;
- for (inbuf_reap = 0; inbuf_reap < inbuf_head; inbuf_reap++) {
- c = inbuf[inbuf_reap];
-
/* Note only VT220+ are 8-bit VT102 is seven bit, it shouldn't even
* be able to display 8-bit characters, but I'll let that go 'cause
* of i18n.
/* Note only VT220+ are 8-bit VT102 is seven bit, it shouldn't even
* be able to display 8-bit characters, but I'll let that go 'cause
* of i18n.
case 4:
case 5:
if ((c & 0xC0) != 0x80) {
case 4:
case 5:
if ((c & 0xC0) != 0x80) {
c = UCSERR;
utf_state = 0;
break;
c = UCSERR;
utf_state = 0;
break;
check_selection(curs, cursplus);
}
}
check_selection(curs, cursplus);
}
}
*/
int from_backend(int is_stderr, char *data, int len)
{
*/
int from_backend(int is_stderr, char *data, int len)
{
- while (len--) {
- if (inbuf_head >= INBUF_SIZE)
- term_out();
- inbuf[inbuf_head++] = *data++;
- }
+ bufchain_add(&inbuf, data, len);
- * We process all stdout/stderr data immediately we receive it,
- * and don't return until it's all gone. Therefore, there's no
- * reason at all to return anything other than zero from this
- * function.
- *
+ * term_out() always completely empties inbuf. Therefore,
+ * there's no reason at all to return anything other than zero
+ * from this function, because there _can't_ be a question of
+ * the remote side needing to wait until term_out() has cleared
+ * a backlog.
+ *
* This is a slightly suboptimal way to deal with SSH2 - in
* principle, the window mechanism would allow us to continue
* to accept data on forwarded ports and X connections even
* This is a slightly suboptimal way to deal with SSH2 - in
* principle, the window mechanism would allow us to continue
* to accept data on forwarded ports and X connections even
* portability. So we manage stdout buffering the old SSH1 way:
* if the terminal processing goes slowly, the whole SSH
* connection stops accepting data until it's ready.
* portability. So we manage stdout buffering the old SSH1 way:
* if the terminal processing goes slowly, the whole SSH
* connection stops accepting data until it's ready.
* In practice, I can't imagine this causing serious trouble.
*/
return 0;
* In practice, I can't imagine this causing serious trouble.
*/
return 0;
session_closed = FALSE;
/*
session_closed = FALSE;
/*
- * Set up the input and output buffers.
- */
- inbuf_head = 0;
- outbuf_reap = outbuf_head = 0;
-
- /*
* Prepare the mouse handler.
*/
lastact = MA_NOTHING;
* Prepare the mouse handler.
*/
lastact = MA_NOTHING;
timer_id = 0;
}
HideCaret(hwnd);
timer_id = 0;
}
HideCaret(hwnd);
- if (inbuf_head)
- term_out();
term_update();
ShowCaret(hwnd);
term_update();
ShowCaret(hwnd);
case WM_TIMER:
if (pending_netevent)
enact_pending_netevent();
case WM_TIMER:
if (pending_netevent)
enact_pending_netevent();
- if (inbuf_head)
- term_out();
noise_regular();
HideCaret(hwnd);
term_update();
noise_regular();
HideCaret(hwnd);
term_update();