diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2009-09-05 14:49:21 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2009-09-05 14:49:21 +0000 |
commit | ec17529a5bd62e044b53345c38f067d1451d619b (patch) | |
tree | 4db8b16a998a02869773fbb021ddbd2d11ca0d63 /sys/dev/wscons/wsemul_dumb.c | |
parent | c818bfbdec899fc627d95f7d7149b9425f7f9188 (diff) |
Check the return value of all emulops in the emulation code, and abort
tty output as soon as we hit a failure.
Since the `output' of a character may cause several emulops to be called
(e.g. if it causes scrollup or if this is the end of an escape sequence),
all emulation code maintain a so-called `abort state', to be able to properly
recover when the character is tentatively output later, and not reissue
the emulops which did not fail the first time.
With help from mglocker@
Diffstat (limited to 'sys/dev/wscons/wsemul_dumb.c')
-rw-r--r-- | sys/dev/wscons/wsemul_dumb.c | 108 |
1 files changed, 87 insertions, 21 deletions
diff --git a/sys/dev/wscons/wsemul_dumb.c b/sys/dev/wscons/wsemul_dumb.c index 5dedc3e24ea..08358d122a9 100644 --- a/sys/dev/wscons/wsemul_dumb.c +++ b/sys/dev/wscons/wsemul_dumb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: wsemul_dumb.c,v 1.8 2009/09/05 14:30:24 miod Exp $ */ +/* $OpenBSD: wsemul_dumb.c,v 1.9 2009/09/05 14:49:20 miod Exp $ */ /* $NetBSD: wsemul_dumb.c,v 1.7 2000/01/05 11:19:36 drochner Exp $ */ /* @@ -44,7 +44,7 @@ void *wsemul_dumb_cnattach(const struct wsscreen_descr *, void *, int, int, long); -void *wsemul_dumb_attach(int console, const struct wsscreen_descr *, +void *wsemul_dumb_attach(int, const struct wsscreen_descr *, void *, int, int, void *, long); u_int wsemul_dumb_output(void *, const u_char *, u_int, int); int wsemul_dumb_translate(void *, keysym_t, const char **); @@ -63,6 +63,7 @@ const struct wsemul_ops wsemul_dumb_ops = { struct wsemul_dumb_emuldata { const struct wsdisplay_emulops *emulops; + struct wsemul_abortstate abortstate; void *emulcookie; void *cbcookie; int crippled; @@ -95,6 +96,7 @@ wsemul_dumb_cnattach(type, cookie, ccol, crow, defattr) edp->crippled = emulops->cursor == NULL || emulops->copycols == NULL || emulops->copyrows == NULL || emulops->erasecols == NULL || emulops->eraserows == NULL; + wsemul_reset_abortstate(&edp->abortstate); return (edp); } @@ -122,6 +124,7 @@ wsemul_dumb_attach(console, type, cookie, ccol, crow, cbcookie, defattr) edp->crow = crow; edp->ccol = ccol; edp->defattr = defattr; + wsemul_reset_abortstate(&edp->abortstate); } edp->cbcookie = cbcookie; @@ -140,26 +143,54 @@ wsemul_dumb_output(cookie, data, count, kernel) u_int processed = 0; u_char c; int n; + int rc = 0; if (edp->crippled) { while (count-- > 0) { - c = *data++; + wsemul_resume_abort(&edp->abortstate); + c = *data++; if (c == ASCII_BEL) wsdisplay_emulbell(edp->cbcookie); - else - (*edp->emulops->putchar)(edp->emulcookie, 0, - 0, c, 0); + else { + WSEMULOP(rc, edp, &edp->abortstate, putchar, + (edp->emulcookie, 0, 0, c, 0)); + if (rc != 0) + break; + } processed++; } + if (rc != 0) + wsemul_abort_other(&edp->abortstate); return processed; } - /* XXX */ - (*edp->emulops->cursor)(edp->emulcookie, 0, edp->crow, edp->ccol); + switch (edp->abortstate.state) { + case ABORT_FAILED_CURSOR: + /* + * If we could not display the cursor back, we pretended not + * having been able to display the last character. But this + * is a lie, so compensate here. + */ + data++, count--; + processed++; + wsemul_reset_abortstate(&edp->abortstate); + break; + case ABORT_OK: + /* remove cursor image */ + rc = (*edp->emulops->cursor) + (edp->emulcookie, 0, edp->crow, edp->ccol); + if (rc != 0) + return 0; + break; + default: + break; + } + while (count-- > 0) { - c = *data++; + wsemul_resume_abort(&edp->abortstate); + c = *data++; switch (c) { case ASCII_BEL: wsdisplay_emulbell(edp->cbcookie); @@ -177,14 +208,19 @@ wsemul_dumb_output(cookie, data, count, kernel) case ASCII_HT: n = min(8 - (edp->ccol & 7), edp->ncols - edp->ccol - 1); - (*edp->emulops->erasecols)(edp->emulcookie, - edp->crow, edp->ccol, n, edp->defattr); + WSEMULOP(rc, edp, &edp->abortstate, erasecols, + (edp->emulcookie, edp->crow, edp->ccol, n, + edp->defattr)); + if (rc != 0) + break; edp->ccol += n; break; case ASCII_FF: - (*edp->emulops->eraserows)(edp->emulcookie, 0, - edp->nrows, edp->defattr); + WSEMULOP(rc, edp, &edp->abortstate, eraserows, + (edp->emulcookie, 0, edp->nrows, edp->defattr)); + if (rc != 0) + break; edp->ccol = 0; edp->crow = 0; break; @@ -195,8 +231,11 @@ wsemul_dumb_output(cookie, data, count, kernel) break; default: - (*edp->emulops->putchar)(edp->emulcookie, edp->crow, - edp->ccol, c, edp->defattr); + WSEMULOP(rc, edp, &edp->abortstate, putchar, + (edp->emulcookie, edp->crow, edp->ccol, c, + edp->defattr)); + if (rc != 0) + break; edp->ccol++; /* if cur col is still on cur line, done. */ @@ -215,17 +254,44 @@ wsemul_dumb_output(cookie, data, count, kernel) break; } n = 1; /* number of lines to scroll */ - (*edp->emulops->copyrows)(edp->emulcookie, n, 0, - edp->nrows - n); - (*edp->emulops->eraserows)(edp->emulcookie, - edp->nrows - n, n, edp->defattr); + WSEMULOP(rc, edp, &edp->abortstate, copyrows, + (edp->emulcookie, n, 0, edp->nrows - n)); + if (rc == 0) + WSEMULOP(rc, edp, &edp->abortstate, eraserows, + (edp->emulcookie, edp->nrows - n, n, + edp->defattr)); + if (rc != 0) { + /* undo wrap-at-eol processing if necessary */ + if (c != ASCII_LF) + edp->ccol = edp->ncols - 1; + break; + } edp->crow -= n - 1; break; } + if (rc != 0) + break; processed++; } - /* XXX */ - (*edp->emulops->cursor)(edp->emulcookie, 1, edp->crow, edp->ccol); + + if (rc != 0) + wsemul_abort_other(&edp->abortstate); + else { + /* put cursor image back */ + rc = (*edp->emulops->cursor) + (edp->emulcookie, 1, edp->crow, edp->ccol); + if (rc != 0) { + /* + * Fail the last character output, remembering that + * only the cursor operation really needs to be done. + */ + wsemul_abort_cursor(&edp->abortstate); + processed--; + } + } + + if (rc == 0) + wsemul_reset_abortstate(&edp->abortstate); return processed; } |