Commit 2aa91851 authored by Jiri Slaby (SUSE)'s avatar Jiri Slaby (SUSE) Committed by Greg Kroah-Hartman
Browse files

tty: n_tty: extract ECHO_OP processing to a separate function



__process_echoes() contains ECHO_OPs processing. It is stuffed in a
while loop and the whole function is barely readable. Separate it to a
new function: n_tty_process_echo_ops().

Signed-off-by: default avatar"Jiri Slaby (SUSE)" <jirislaby@kernel.org>
Link: https://lore.kernel.org/r/20230827074147.2287-14-jirislaby@kernel.org


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent e30364c7
Loading
Loading
Loading
Loading
+98 −96
Original line number Diff line number Diff line
@@ -582,139 +582,141 @@ static ssize_t process_output_block(struct tty_struct *tty,
	return i;
}

/**
 * __process_echoes	-	write pending echo characters
 * @tty: terminal device
 *
 * Write previously buffered echo (and other ldisc-generated) characters to the
 * tty.
 *
 * Characters generated by the ldisc (including echoes) need to be buffered
 * because the driver's write buffer can fill during heavy program output.
 * Echoing straight to the driver will often fail under these conditions,
 * causing lost characters and resulting mismatches of ldisc state information.
 *
 * Since the ldisc state must represent the characters actually sent to the
 * driver at the time of the write, operations like certain changes in column
 * state are also saved in the buffer and executed here.
 *
 * A circular fifo buffer is used so that the most recent characters are
 * prioritized. Also, when control characters are echoed with a prefixed "^",
 * the pair is treated atomically and thus not separated.
 *
 * Locking: callers must hold %output_lock.
 */
static size_t __process_echoes(struct tty_struct *tty)
static int n_tty_process_echo_ops(struct tty_struct *tty, size_t *tail,
				  int space)
{
	struct n_tty_data *ldata = tty->disc_data;
	int	space, old_space;
	size_t tail;
	u8 c;

	old_space = space = tty_write_room(tty);

	tail = ldata->echo_tail;
	while (MASK(ldata->echo_commit) != MASK(tail)) {
		c = echo_buf(ldata, tail);
		if (c == ECHO_OP_START) {
	u8 op;
			bool space_left = true;

	/*
			 * Since add_echo_byte() is called without holding
			 * output_lock, we might see only portion of multi-byte
			 * operation.
	 * Since add_echo_byte() is called without holding output_lock, we
	 * might see only portion of multi-byte operation.
	 */
			if (MASK(ldata->echo_commit) == MASK(tail + 1))
				goto not_yet_stored;
	if (MASK(ldata->echo_commit) == MASK(*tail + 1))
		return -ENODATA;

	/*
			 * If the buffer byte is the start of a multi-byte
			 * operation, get the next byte, which is either the
			 * op code or a control character value.
	 * If the buffer byte is the start of a multi-byte operation, get the
	 * next byte, which is either the op code or a control character value.
	 */
			op = echo_buf(ldata, tail + 1);
	op = echo_buf(ldata, *tail + 1);

	switch (op) {
	case ECHO_OP_ERASE_TAB: {
		unsigned int num_chars, num_bs;

				if (MASK(ldata->echo_commit) == MASK(tail + 2))
					goto not_yet_stored;
				num_chars = echo_buf(ldata, tail + 2);
		if (MASK(ldata->echo_commit) == MASK(*tail + 2))
			return -ENODATA;

		num_chars = echo_buf(ldata, *tail + 2);

		/*
				 * Determine how many columns to go back
				 * in order to erase the tab.
				 * This depends on the number of columns
				 * used by other characters within the tab
				 * area.  If this (modulo 8) count is from
				 * the start of input rather than from a
				 * previous tab, we offset by canon column.
				 * Otherwise, tab spacing is normal.
		 * Determine how many columns to go back in order to erase the
		 * tab. This depends on the number of columns used by other
		 * characters within the tab area. If this (modulo 8) count is
		 * from the start of input rather than from a previous tab, we
		 * offset by canon column. Otherwise, tab spacing is normal.
		 */
		if (!(num_chars & 0x80))
			num_chars += ldata->canon_column;
		num_bs = 8 - (num_chars & 7);

				if (num_bs > space) {
					space_left = false;
					break;
				}
		if (num_bs > space)
			return -ENOSPC;

		space -= num_bs;
		while (num_bs--) {
			tty_put_char(tty, '\b');
			if (ldata->column > 0)
				ldata->column--;
		}
				tail += 3;
		*tail += 3;
		break;
	}
	case ECHO_OP_SET_CANON_COL:
		ldata->canon_column = ldata->column;
				tail += 2;
		*tail += 2;
		break;

	case ECHO_OP_MOVE_BACK_COL:
		if (ldata->column > 0)
			ldata->column--;
				tail += 2;
		*tail += 2;
		break;

	case ECHO_OP_START:
		/* This is an escaped echo op start code */
				if (!space) {
					space_left = false;
					break;
				}
		if (!space)
			return -ENOSPC;

		tty_put_char(tty, ECHO_OP_START);
		ldata->column++;
		space--;
				tail += 2;
		*tail += 2;
		break;

	default:
		/*
				 * If the op is not a special byte code,
				 * it is a ctrl char tagged to be echoed
				 * as "^X" (where X is the letter
				 * representing the control char).
				 * Note that we must ensure there is
				 * enough space for the whole ctrl pair.
				 *
		 * If the op is not a special byte code, it is a ctrl char
		 * tagged to be echoed as "^X" (where X is the letter
		 * representing the control char). Note that we must ensure
		 * there is enough space for the whole ctrl pair.
		 */
				if (space < 2) {
					space_left = false;
					break;
				}
		if (space < 2)
			return -ENOSPC;

		tty_put_char(tty, '^');
		tty_put_char(tty, op ^ 0100);
		ldata->column += 2;
		space -= 2;
				tail += 2;
		*tail += 2;
		break;
	}

	return space;
}

			if (!space_left)
/**
 * __process_echoes	-	write pending echo characters
 * @tty: terminal device
 *
 * Write previously buffered echo (and other ldisc-generated) characters to the
 * tty.
 *
 * Characters generated by the ldisc (including echoes) need to be buffered
 * because the driver's write buffer can fill during heavy program output.
 * Echoing straight to the driver will often fail under these conditions,
 * causing lost characters and resulting mismatches of ldisc state information.
 *
 * Since the ldisc state must represent the characters actually sent to the
 * driver at the time of the write, operations like certain changes in column
 * state are also saved in the buffer and executed here.
 *
 * A circular fifo buffer is used so that the most recent characters are
 * prioritized. Also, when control characters are echoed with a prefixed "^",
 * the pair is treated atomically and thus not separated.
 *
 * Locking: callers must hold %output_lock.
 */
static size_t __process_echoes(struct tty_struct *tty)
{
	struct n_tty_data *ldata = tty->disc_data;
	int	space, old_space;
	size_t tail;
	u8 c;

	old_space = space = tty_write_room(tty);

	tail = ldata->echo_tail;
	while (MASK(ldata->echo_commit) != MASK(tail)) {
		c = echo_buf(ldata, tail);
		if (c == ECHO_OP_START) {
			int ret = n_tty_process_echo_ops(tty, &tail, space);
			if (ret == -ENODATA)
				goto not_yet_stored;
			if (ret < 0)
				break;
			space = ret;
		} else {
			if (O_OPOST(tty)) {
				int retval = do_output_char(c, tty, space);