u_int
wsemul_sun_output(void *cookie, const u_char *data, u_int count, int kernel)
{
	struct wsemul_sun_emuldata *edp = cookie;
	struct wsemul_inputstate *instate;
	u_int processed = 0;
#ifdef HAVE_JUMP_SCROLL
	int lines;
#endif
	int rc = 0;

#ifdef DIAGNOSTIC
	if (kernel && !edp->console)
		panic("wsemul_sun_output: kernel output, not console");
#endif

	instate = kernel ? &edp->kstate : &edp->instate;

	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;
	}

	for (;;) {
#ifdef HAVE_JUMP_SCROLL
		switch (edp->abortstate.state) {
		case ABORT_FAILED_JUMP_SCROLL:
			/*
			 * If we failed a previous jump scroll attempt, we
			 * need to try to resume it with the same distance.
			 * We can not recompute it since there might be more
			 * bytes in the tty ring, causing a different result.
			 */
			lines = edp->abortstate.lines;
			break;
		case ABORT_OK:
			/*
			 * If scrolling is not disabled and we are the bottom of
			 * the screen, count newlines until an escape sequence
			 * appears.
			 */
			if ((edp->state == SUN_EMUL_STATE_NORMAL || kernel) &&
			    ROWS_LEFT == 0 && edp->scrolldist != 0)
				lines = wsemul_sun_jump_scroll(edp, data,
				    count, kernel);
			else
				lines = 0;
			break;
		default:
			/*
			 * If we are recovering a non-scrolling failure,
			 * do not try to scroll yet.
			 */
			lines = 0;
			break;
		}

		if (lines > 1) {
			wsemul_resume_abort(&edp->abortstate);
			rc = wsemul_sun_scrollup(edp, lines);
			if (rc != 0) {
				wsemul_abort_jump_scroll(&edp->abortstate,
				    lines);
				return processed;
			}
			wsemul_reset_abortstate(&edp->abortstate);
			edp->crow--;
		}
#endif

		wsemul_resume_abort(&edp->abortstate);

		if (wsemul_getchar(&data, &count, instate,
#ifdef HAVE_UTF8_SUPPORT
		    (edp->state == SUN_EMUL_STATE_NORMAL && !kernel) ?
		      edp->flags & SUN_EMUL_FLAGS_UTF8 : 0
#else
		    0
#endif
		    ) != 0)
			break;

		if (instate->inchar < ' ') {
			rc = wsemul_sun_output_lowchars(edp, instate, kernel);
			if (rc != 0)
				break;
			processed++;
			continue;
		}

		if (kernel) {
			rc = wsemul_sun_output_normal(edp, instate, 1);
			if (rc != 0)
				break;
			processed++;
			continue;
		}

		switch (edp->state) {
		case SUN_EMUL_STATE_NORMAL:
			rc = wsemul_sun_output_normal(edp, instate, 0);
			break;
		case SUN_EMUL_STATE_HAVEESC:
			rc = wsemul_sun_output_haveesc(edp, instate);
			break;
		case SUN_EMUL_STATE_CONTROL:
			rc = wsemul_sun_output_control(edp, instate);
			break;
#ifdef HAVE_UTF8_SUPPORT
		case SUN_EMUL_STATE_PERCENT:
			rc = wsemul_sun_output_percent(edp, instate);
			break;
#endif
		default:
#ifdef DIAGNOSTIC
			panic("wsemul_sun: invalid state %d", edp->state);
#else
			/* try to recover, if things get screwed up... */
			edp->state = SUN_EMUL_STATE_NORMAL;
			rc = wsemul_sun_output_normal(edp, instate, 0);
#endif
			break;
		}
		if (rc != 0)
			break;
		processed++;
	}

	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;
}
Exemple #2
0
u_int
wsemul_dumb_output(void *cookie, const u_char *data, u_int count, int kernel)
{
	struct wsemul_dumb_emuldata *edp = cookie;
	u_int processed = 0;
	u_char c;
	int n;
	int rc = 0;

	if (edp->crippled) {
		while (count-- > 0) {
			wsemul_resume_abort(&edp->abortstate);

			c = *data++;
			if (c == ASCII_BEL)
				wsdisplay_emulbell(edp->cbcookie);
			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;
	}

	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) {
		wsemul_resume_abort(&edp->abortstate);

		c = *data++;
		switch (c) {
		case ASCII_BEL:
			wsdisplay_emulbell(edp->cbcookie);
			break;

		case ASCII_BS:
			if (edp->ccol > 0)
				edp->ccol--;
			break;

		case ASCII_CR:
			edp->ccol = 0;
			break;

		case ASCII_HT:
			n = min(8 - (edp->ccol & 7),
			    edp->ncols - edp->ccol - 1);
			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:
			WSEMULOP(rc, edp, &edp->abortstate, eraserows,
			    (edp->emulcookie, 0, edp->nrows, edp->defattr));
			if (rc != 0)
				break;
			edp->ccol = 0;
			edp->crow = 0;
			break;

		case ASCII_VT:
			if (edp->crow > 0)
				edp->crow--;
			break;

		default:
			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. */
			if (edp->ccol < edp->ncols)
				break;

			/* wrap the column around. */
			edp->ccol = 0;

                	/* FALLTHROUGH */

		case ASCII_LF:
	                /* if the cur line isn't the last, incr and leave. */
			if (edp->crow < edp->nrows - 1) {
				edp->crow++;
				break;
			}
			n = 1;		/* number of lines to scroll */
			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++;
	}

	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;
}