Exemplo n.º 1
0
/*
 * Read a line from the echo area, with single character prompt c.
 * A return value of 1 means the user blewit or blewit away.
 */
int
readecho(int c)
{
	register char *sc = cursor;
	void (*OP)();
	bool waste;
	register int OPeek;

	if (WBOT == WECHO)
		vclean();
	else
		vclrech(0);
	splitw++;
	vgoto(WECHO, 0);
	ex_putchar(c);
	vclreol();
	vgoto(WECHO, 1);
	cursor = linebuf; linebuf[0] = 0; genbuf[0] = c;
	if (peekbr()) {
		if (!INS[0] || (INS[0] & (OVERBUF|TRIM)) == OVERBUF)
			goto blewit;
		vglobp = INS;
	}
	OP = Pline; Pline = normline;
	ignore(vgetline(0, genbuf + 1, &waste, c));
	if (Outchar == termchar)
		ex_putchar('\n');
	vscrap();
	Pline = OP;
	if (Peekkey != ATTN && Peekkey != QUIT && Peekkey != CTRL('h')) {
		cursor = sc;
		vclreol();
		return (0);
	}
blewit:
	OPeek = Peekkey==CTRL('h') ? 0 : Peekkey; Peekkey = 0;
	splitw = 0;
	vclean();
	vshow(dot, NOLINE);
	vnline(sc);
	Peekkey = OPeek;
	return (1);
}
Exemplo n.º 2
0
/*
 * Logically open up after line l, cnt of them.
 * We need to know if it was done ``physically'' since in this
 * case we accept what the hardware gives us.  If we have to do
 * it ourselves (brute force) we will squish out @ lines in the process
 * if this will save us work.
 */
void 
vopenup(int cnt, int could, int l)
{
	register struct vlinfo *vc = &vlinfo[l + 1];
	register struct vlinfo *ve = &vlinfo[vcnt];

#ifdef ADEBUG
	if (trace)
		tfixnl(), fprintf(trace, "vopenup(%d, %d, %d)\n", cnt, could, l);
#endif
	if (could)
		/*
		 * This will push @ lines down the screen,
		 * just as the hardware did.  Since the default
		 * for intelligent terminals is to never have @
		 * lines on the screen, this should never happen,
		 * and the code makes no special effort to be nice in this
		 * case, e.g. squishing out the @ lines by delete lines
		 * before doing append lines.
		 */
		for (; vc <= ve; vc++)
			vc->vliny += cnt;
	else {
		/*
		 * Will have to clean up brute force eventually,
		 * so push the line data around as little as possible.
		 */
		vc->vliny += cnt, vc->vflags |= VDIRT;
		while (vc < ve) {
			register int i = vc->vliny + vc->vdepth;

			vc++;
			if (i <= vc->vliny)
				break;
			vc->vliny = i, vc->vflags |= VDIRT;
		}
	}
	vscrap();
}
Exemplo n.º 3
0
void
vappend(int ch, int cnt, int indent)
{
	register int i;
	register char *gcursor;
	bool escape;
	int repcnt;
	short oldhold = hold;

	/*
	 * Before a move in hardopen when the line is dirty
	 * or we are in the middle of the printed representation,
	 * we retype the line to the left of the cursor so the
	 * insert looks clean.
	 */
	if (ch != 'o' && state == HARDOPEN && (rubble || !ateopr())) {
		rubble = 1;
		wcursor = cursor;
		vmove();
	}
	vaifirst = indent == 0;

	/*
	 * Handle replace character by (eventually)
	 * limiting the number of input characters allowed
	 * in the vgetline routine.
	 */
	if (ch == 'r')
		repcnt = 2;
	else
		repcnt = 0;

	/*
	 * If an autoindent is specified, then
	 * generate a mixture of blanks to tabs to implement
	 * it and place the cursor after the indent.
	 * Text read by the vgetline routine will be placed in genbuf,
	 * so the indent is generated there.
	 */
	if (value(AUTOINDENT) && indent != 0) {
		gcursor = genindent(indent);
		*gcursor = 0;
		vgotoCL(qcolumn(cursor - 1, genbuf));
	} else {
		gcursor = genbuf;
		*gcursor = 0;
		if (ch == 'o')
			vfixcurs();
	}

	/*
	 * Prepare for undo.  Pointers delimit inserted portion of line.
	 */
	vUA1 = vUA2 = cursor;

	/*
	 * If we are not in a repeated command and a ^@ comes in
	 * then this means the previous inserted text.
	 * If there is none or it was too long to be saved,
	 * then beep() and also arrange to undo any damage done
	 * so far (e.g. if we are a change.)
	 */
	if ((vglobp && *vglobp == 0) || peekbr()) {
		if ((INS[0] & (OVERBUF|TRIM)) == OVERBUF) {
			beep();
			if (!splitw)
				ungetkey('u');
			doomed = 0;
			hold = oldhold;
			return;
		}
		/*
		 * Unread input from INS.
		 * An escape will be generated at end of string.
		 * Hold off n^^2 type update on dumb terminals.
		 */
		vglobp = INS;
		hold |= HOLDQIK;
	} else if (vglobp == 0)
		/*
		 * Not a repeated command, get
		 * a new inserted text for repeat.
		 */
		INS[0] = 0;

	/*
	 * For wrapmargin to hack away second space after a '.'
	 * when the first space caused a line break we keep
	 * track that this happened in gobblebl, which says
	 * to gobble up a blank silently.
	 */
	gobblebl = 0;

	/*
	 * Text gathering loop.
	 * New text goes into genbuf starting at gcursor.
	 * cursor preserves place in linebuf where text will eventually go.
	 */
	if (*cursor == 0 || state == CRTOPEN)
		hold |= HOLDROL;
	for (;;) {
		if (ch == 'r' && repcnt == 0)
			escape = 0;
		else {
			gcursor = vgetline(repcnt, gcursor, &escape);

			/*
			 * After an append, stick information
			 * about the ^D's and ^^D's and 0^D's in
			 * the repeated text buffer so repeated
			 * inserts of stuff indented with ^D as backtab's
			 * can work.
			 */
			if (HADUP)
				addtext("^");
			else if (HADZERO)
				addtext("0");
			while (CDCNT > 0)
				addtext("\204"), CDCNT--;
			if (gobbled)
				addtext(" ");
			addtext(ogcursor);
		}
		repcnt = 0;

		/*
		 * Smash the generated and preexisting indents together
		 * and generate one cleanly made out of tabs and spaces
		 * if we are using autoindent.
		 */
		if (!vaifirst && value(AUTOINDENT)) {
			i = fixindent(indent);
			if (!HADUP)
				indent = i;
			gcursor = strend(genbuf);
		}

		/*
		 * Limit the repetition count based on maximum
		 * possible line length; do output implied
		 * by further count (> 1) and cons up the new line
		 * in linebuf.
		 */
		cnt = vmaxrep(ch, cnt);
		CP(gcursor + 1, cursor);
		do {
			CP(cursor, genbuf);
			if (cnt > 1) {
				int oldhold = hold;

				Outchar = vinschar;
				hold |= HOLDQIK;
				ex_printf("%s", genbuf);
				hold = oldhold;
				Outchar = vputchar;
			}
			cursor += gcursor - genbuf;
		} while (--cnt > 0);
		endim();
		vUA2 = cursor;
		if (escape != '\n')
			CP(cursor, gcursor + 1);

		/*
		 * If doomed characters remain, clobber them,
		 * and reopen the line to get the display exact.
		 */
		if (state != HARDOPEN) {
			DEPTH(vcline) = 0;
			if (doomed > 0) {
				register int cind = cindent();

				physdc(cind, cind + doomed);
				doomed = 0;
			}
			i = vreopen(LINE(vcline), lineDOT(), vcline);
		}

		/*
		 * All done unless we are continuing on to another line.
		 */
		if (escape != '\n')
			break;

		/*
		 * Set up for the new line.
		 * First save the current line, then construct a new
		 * first image for the continuation line consisting
		 * of any new autoindent plus the pushed ahead text.
		 */
		killU();
		addtext(gobblebl ? " " : "\n");
		vsave();
		cnt = 1;
		if (value(AUTOINDENT)) {
#ifdef LISP
			if (value(LISP))
				indent = lindent(dot + 1);
			else
#endif
			     if (!HADUP && vaifirst)
				indent = whitecnt(linebuf);
			vaifirst = 0;
			strcLIN(vpastwh(gcursor + 1));
			gcursor = genindent(indent);
			*gcursor = 0;
			if (gcursor + strlen(linebuf) > &genbuf[LBSIZE - 2])
				gcursor = genbuf;
			CP(gcursor, linebuf);
		} else {
			CP(genbuf, gcursor + 1);
			gcursor = genbuf;
		}

		/*
		 * If we started out as a single line operation and are now
		 * turning into a multi-line change, then we had better yank
		 * out dot before it changes so that undo will work
		 * correctly later.
		 */
		if (vundkind == VCHNG) {
			vremote(1, (void (*)(int))yank, 0);
			undap1--;
		}

		/*
		 * Now do the append of the new line in the buffer,
		 * and update the display.  If slowopen
		 * we don't do very much.
		 */
		vdoappend(genbuf);
		vundkind = VMANYINS;
		vcline++;
		if (state != VISUAL)
			vshow(dot, NOLINE);
		else {
			i += LINE(vcline - 1);
			vopen(dot, i);
			if (value(SLOWOPEN))
				vscrap();
			else
				vsync1(LINE(vcline));
		}
		strcLIN(gcursor);
		*gcursor = 0;
		cursor = linebuf;
		vgotoCL(qcolumn(cursor - 1, genbuf));
	}

	/*
	 * All done with insertion, position the cursor
	 * and sync the screen.
	 */
	hold = oldhold;
	if (cursor > linebuf)
		cursor--;
	if (state != HARDOPEN)
		vsyncCL();
	else if (cursor > linebuf)
		back1();
	doomed = 0;
	wcursor = cursor;
	vmove();
}
Exemplo n.º 4
0
/*
 * The guts of a sync.  Similar to redraw but
 * just less ambitous.
 */
void 
vsync1(register int p)
{
	register int l;
	char temp[LBSIZE];
	register struct vlinfo *vp = &vlinfo[0];
	short oldhold = hold;

#ifdef ADEBUG
	if (trace)
		tfixnl(), fprintf(trace, "vsync1(%d)\n", p), tvliny();
#endif
	if (holdupd) {
		if (holdupd < 3)
			holdupd = 2;
		return;
	}
	if (state == HARDOPEN || splitw)
		return;
	vscrap();
	CP(temp, linebuf);
	if (vcnt == 0)
		LINE(0) = WTOP;
	l = 0;
	while (l < vcnt && vp->vliny < p)
		l++, vp++;
	heldech = 0;
	hold |= HOLDECH;
	while (p <= WBOT && Peekkey != ATTN) {
		/*
		 * Want to put a line here if not in visual and first line
		 * or if there are lies left and this line starts before
		 * the current line, or if this line is piled under the
		 * next line (vreplace does this and we undo it).
		 */
		if (l == 0 && state != VISUAL ||
		    (l < vcnt && (vp->vliny <= p || vp[0].vliny == vp[1].vliny))) {
			if (l == 0 || vp->vliny < p || (vp->vflags & VDIRT)) {
				if (l == vcline)
					strcLIN(temp);
				else
					getline(dot[l - vcline]);
				/*
				 * Be careful that a long line doesn't cause the
				 * screen to shoot up.
				 */
				if (l != vcline && (vp->vflags & VDIRT)) {
					vp->vdepth = vdepth();
					vp->vflags &= ~VDIRT;
					if (p + vp->vdepth - 1 > WBOT)
						break;
				}
				vreopen(p, lineDOT() + (l - vcline), l);
			}
			p = vp->vliny + vp->vdepth;
			vp++;
			l++;
		} else
			/*
			 * A physical line between logical lines,
			 * so we settle for an @ at the beginning.
			 */
			vclrlin(p, dot + (l - vcline)), p++;
	}
	strcLIN(temp);
	hold = oldhold;
	if (heldech)
		vclrech(0);
}
Exemplo n.º 5
0
/*
 * Fully cleanup the screen, leaving no @ lines except at end when
 * line after last won't completely fit.  The routine vsync is
 * more conservative and much less work on dumb terminals.
 */
void 
vredraw(register int p)
{
	register int l;
	register line *tp;
	char temp[LBSIZE];
	bool anydl = 0;
	short oldhold = hold;

#ifdef ADEBUG
	if (trace)
		tfixnl(), fprintf(trace, "vredraw(%d)\n", p), tvliny();
#endif
	if (holdupd) {
		holdupd = 3;
		return;
	}
	if (state == HARDOPEN || splitw)
		return;
	if (p < 0 /* || p > WECHO */)
		error(catgets(catd, 1, 221, "Internal error: vredraw"));

	/*
	 * Trim the ragged edges (lines which are off the screen but
	 * not yet logically discarded), save the current line, and
	 * search for first logical line affected by the redraw.
	 */
	vscrap();
	CP(temp, linebuf);
	l = 0;
	tp = dot - vcline;
	if (vcnt == 0)
		LINE(0) = WTOP;
	while (l < vcnt && LINE(l) < p)
		l++, tp++;

	/*
	 * We hold off echo area clearing during the redraw in deference
	 * to a final clear of the echo area at the end if appropriate.
	 */
	heldech = 0;
	hold |= HOLDECH;
	for (; l < vcnt && Peekkey != ATTN; l++) {
		if (l == vcline)
			strcLIN(temp);
		else
			getline(*tp);

		/*
		 * Delete junk between displayed lines.
		 */
		if (LINE(l) != LINE(l + 1) && LINE(l) != p) {
			if (anydl == 0 && DB && CD) {
				hold = oldhold;
				vclrech(0);
				anydl = 1;
				hold |= HOLDECH;
				heldech = 0;
			}
			vdellin(p, LINE(l) - p, l);
		}

		/*
		 * If line image is not know to be up to date, then
		 * redisplay it;  else just skip onward.
		 */
		LINE(l) = p;
		if (FLAGS(l) & VDIRT) {
			DEPTH(l) = vdepth();
			if (l != vcline && p + DEPTH(l) - 1 > WBOT) {
				vscrap();
				break;
			}
			FLAGS(l) &= ~VDIRT;
			vreopen(p, lineno(tp), l);
			p = LINE(l) + DEPTH(l);
		} else
			p += DEPTH(l);
		tp++;
	}

	/*
	 * That takes care of lines which were already partially displayed.
	 * Now try to fill the rest of the screen with text.
	 */
	if (state == VISUAL && p <= WBOT) {
		int ovcline = vcline;

		vcline = l;
		for (; tp <= dol && Peekkey != ATTN; tp++) {
			getline(*tp);
			if (p + vdepth() - 1 > WBOT)
				break;
			vopen(tp, p);
			p += DEPTH(vcline);
			vcline++;
		}
		vcline = ovcline;
	}

	/*
	 * Thats all the text we can get on.
	 * Now rest of lines (if any) get either a ~ if they
	 * are past end of file, or an @ if the next line won't fit.
	 */
	for (; p <= WBOT && Peekkey != ATTN; p++)			
		vclrlin(p, tp);
	strcLIN(temp);
	hold = oldhold;
	if (heldech)
		vclrech(0);
#ifdef ADEBUG
	if (trace)
		tvliny();
#endif
}
Exemplo n.º 6
0
/*
 * Repaint the screen, with cursor at curs, aftern an arbitrary change.
 * Handle notification on large changes.
 */
void 
vrepaint(char *curs)
{

	wdot = NOLINE;
	/*
	 * In open want to notify first.
	 */
	noteit(0);
	vscrap();

	/*
	 * Deal with a totally useless display.
	 */
	if (vcnt == 0 || vcline < 0 || vcline > vcnt || holdupd && state != VISUAL) {
		register line *odol = dol;

		vcnt = 0;
		if (holdupd)
			if (state == VISUAL)
				ignore(peekkey());
			else
				vup1();
		holdupd = 0;
		if (odol == zero)
			fixzero();
		vcontext(dot, '.');
		noteit(1);
		if (noteit(1) == 0 && odol == zero) {
			CATCH
				error(catgets(catd, 1, 220,
						"No lines in buffer"));
			ENDCATCH
			linebuf[0] = 0;
			splitw = 0;
		}
		vnline(curs);
		return;
	}

	/*
	 * Have some useful displayed text; refresh it.
	 */
	getDOT();

	/*
	 * This is for boundary conditions in open mode.
	 */
	if (FLAGS(0) & VDIRT)
		vsync(WTOP);
	
	/*
	 * If the current line is after the last displayed line
	 * or the bottom of the screen, then special effort is needed
	 * to get it on the screen.  We first try a redraw at the
	 * last line on the screen, hoping it will fill in where @
	 * lines are now.  If this doesn't work, then roll it onto
	 * the screen.
	 */
	if (vcline >= vcnt || LINE(vcline) > WBOT) {
		short oldhold = hold;
		hold |= HOLDAT, vredraw(LASTLINE), hold = oldhold;
		if (vcline >= vcnt) {
			register int i = vcline - vcnt + 1;

			dot -= i;
			vcline -= i;
			vroll(i);
		} else
			vsyncCL();
	} else
		vsync(vcline > 0 ? LINE(vcline - 1) : WTOP);

	/*
	 * Notification on large change for visual
	 * has to be done last or we may lose
	 * the echo area with redisplay.
	 */
	noteit(1);

	/*
	 * Finally.  Move the cursor onto the current line.
	 */
	vnline(curs);
}
Exemplo n.º 7
0
/*
 * Open new lines.
 *
 * Tricky thing here is slowopen.  This causes display updating
 * to be held off so that 300 baud dumb terminals don't lose badly.
 * This also suppressed counts, which otherwise say how many blank
 * space to open up.  Counts are also suppressed on intelligent terminals.
 * Actually counts are obsoleted, since if your terminal is slow
 * you are better off with slowopen.
 */
void 
voOpen (
    int c,	/* mjm: char --> int */
    register int cnt
)
{
	register int ind = 0, i;
	short oldhold = hold;
#ifdef	SIGWINCH
	sigset_t set, oset;
#endif

	if (value(SLOWOPEN) || value(REDRAW) && AL && DL)
		cnt = 1;
#ifdef	SIGWINCH
	sigemptyset(&set);
	sigaddset(&set, SIGWINCH);
	sigprocmask(SIG_BLOCK, &set, &oset);
#endif
	vsave();
	setLAST();
	if (value(AUTOINDENT))
		ind = whitecnt(linebuf);
	if (c == 'O') {
		vcline--;
		dot--;
		if (dot > zero)
			getDOT();
	}
	if (value(AUTOINDENT)) {
#ifdef LISPCODE
		if (value(LISP))
			ind = lindent(dot + 1);
#endif
	}
	killU();
	prepapp();
	if (FIXUNDO)
		vundkind = VMANY;
	if (state != VISUAL)
		c = WBOT + 1;
	else {
		c = vcline < 0 ? WTOP - cnt : LINE(vcline) + DEPTH(vcline);
		if (c < ZERO)
			c = ZERO;
		i = LINE(vcline + 1) - c;
		if (i < cnt && c <= WBOT && (!AL || !DL))
			vinslin(c, cnt - i, vcline);
	}
	*genindent(ind) = 0;
	vdoappend(genbuf);
	vcline++;
	oldhold = hold;
	hold |= HOLDROL;
	vopen(dot, c);
	hold = oldhold;
	if (value(SLOWOPEN))
		/*
		 * Oh, so lazy!
		 */
		vscrap();
	else
		vsync1(LINE(vcline));
	cursor = linebuf;
	linebuf[0] = 0;
	vappend('o', 1, ind);
#ifdef	SIGWINCH
	sigprocmask(SIG_SETMASK, &oset, NULL);
#endif
}
Exemplo n.º 8
0
void
vappend(int ch, int cnt, int indent)
{
	int i;
	unsigned char *gcursor;
	bool escape;
	int repcnt, savedoomed;
	short oldhold = hold;
	int savecnt = cnt;
	line *startsrcline;
	int startsrccol, endsrccol;
	int gotNL = 0;
	int imultlinecnt = 0;
	int omultlinecnt = 0;

	if ((savecnt > 1) && (ch == 'o' || ch == 'O')) {
		omultlinecnt = 1;
	}
#ifdef XPG6
	if ((savecnt > 1) && (ch == 'a' || ch == 'A' || ch == 'i' || ch == 'I'))
		imultlinecnt = 1;
#endif /* XPG6 */

	/*
	 * Before a move in hardopen when the line is dirty
	 * or we are in the middle of the printed representation,
	 * we retype the line to the left of the cursor so the
	 * insert looks clean.
	 */

	if (ch != 'o' && state == HARDOPEN && (rubble || !ateopr())) {
		rubble = 1;
		gcursor = cursor;
		i = *gcursor;
		*gcursor = ' ';
		wcursor = gcursor;
		(void) vmove();
		*gcursor = i;
	}
	/*
	 * If vrep() passed indent = 0, this is the 'r' command,
	 * so don't autoindent until the last char.
	 */
	vaifirst = indent == 0;

	/*
	 * Handle replace character by (eventually)
	 * limiting the number of input characters allowed
	 * in the vgetline routine.
	 */
	if (ch == 'r')
		repcnt = 2;
	else
		repcnt = 0;

	/*
	 * If an autoindent is specified, then
	 * generate a mixture of blanks to tabs to implement
	 * it and place the cursor after the indent.
	 * Text read by the vgetline routine will be placed in genbuf,
	 * so the indent is generated there.
	 */
	if (value(vi_AUTOINDENT) && indent != 0) {
		unsigned char x;
		gcursor = genindent(indent);
		*gcursor = 0;
		vgotoCL(nqcolumn(lastchr(linebuf, cursor), genbuf)); 
	} else {
		gcursor = genbuf;
		*gcursor = 0;
		if (ch == 'o')
			vfixcurs();
	}

	/*
	 * Prepare for undo.  Pointers delimit inserted portion of line.
	 */
	vUA1 = vUA2 = cursor;

	/*
	 * If we are not in a repeated command and a ^@ comes in
	 * then this means the previous inserted text.
	 * If there is none or it was too long to be saved,
	 * then beep() and also arrange to undo any damage done
	 * so far (e.g. if we are a change.)
	 */
	switch (ch) {
	case 'r':
		break;
	case 'a':
		/*
		 * TRANSLATION_NOTE
		 *	"A" is a terse mode message corresponding to
		 *	"APPEND MODE".
		 *	Translated message of "A" must be 1 character (not byte).
		 *	Or, just leave it.
		 */
		if (value(vi_TERSE)) {
			vshowmode(gettext("A"));
		} else {
			vshowmode(gettext("APPEND MODE"));
		}
		break;
	case 's':
		/*
		 * TRANSLATION_NOTE
		 *	"S" is a terse mode message corresponding to
		 *	"SUBSTITUTE MODE".
		 *	Translated message of "S" must be 1 character (not byte).
		 *	Or, just leave it.
		 */
		if (value(vi_TERSE)) {
			vshowmode(gettext("S"));
		} else {
			vshowmode(gettext("SUBSTITUTE MODE"));
		}
		break;
	case 'c':
		/*
		 * TRANSLATION_NOTE
		 *	"C" is a terse mode message corresponding to
		 *	"CHANGE MODE".
		 *	Translated message of "C" must be 1 character (not byte).
		 *	Or, just leave it.
		 */
		if (value(vi_TERSE)) {
			vshowmode(gettext("C"));
		} else {
			vshowmode(gettext("CHANGE MODE"));
		}
		break;
	case 'R':
		/*
		 * TRANSLATION_NOTE
		 *	"R" is a terse mode message corresponding to
		 *	"REPLACE MODE".
		 *	Translated message of "R" must be 1 character (not byte).
		 *	Or, just leave it.
		 */
		if (value(vi_TERSE)) {
			vshowmode(gettext("R"));
		} else {
			vshowmode(gettext("REPLACE MODE"));
		}
		break;
	case 'o':
		/*
		 * TRANSLATION_NOTE
		 *	"O" is a terse mode message corresponding to
		 *	"OPEN MODE".
		 *	Translated message of "O" must be 1 character (not byte).
		 *	Or, just leave it.
		 */
		if (value(vi_TERSE)) {
			vshowmode(gettext("O"));
		} else {
			vshowmode(gettext("OPEN MODE"));
		}
		break;
	case 'i':
		/*
		 * TRANSLATION_NOTE
		 *	"I" is a terse mode message corresponding to
		 *	"INSERT MODE" and the following "INPUT MODE".
		 *	Translated message of "I" must be 1 character (not byte).
		 *	Or, just leave it.
		 */
		if (value(vi_TERSE)) {
			vshowmode(gettext("I"));
		} else {
			vshowmode(gettext("INSERT MODE"));
		}
		break;
	default:
		/*
		 * TRANSLATION_NOTE
		 *	"I" is a terse mode message corresponding to
		 *	"INPUT MODE" and the previous "INSERT MODE".
		 *	Translated message of "I" must be 1 character (not byte).
		 *	Or, just leave it.
		 */
		if (value(vi_TERSE)) {
			vshowmode(gettext("I"));
		} else {
			vshowmode(gettext("INPUT MODE"));
		}
	}
	ixlatctl(1);
	if ((vglobp && *vglobp == 0) || peekbr()) {
		if (INS[128] == 0200) {
			(void) beep();
			if (!splitw)
				ungetkey('u');
			doomed = 0;
			hold = oldhold;
			return;
		}
		/*
		 * Unread input from INS.
		 * An escape will be generated at end of string.
		 * Hold off n^^2 type update on dumb terminals.
		 */
		vglobp = INS;
		inscdcnt = INSCDCNT;
		hold |= HOLDQIK;
	} else if (vglobp == 0) {
		/*
		 * Not a repeated command, get
		 * a new inserted text for repeat.
		 */
		INS[0] = 0;
		INS[128] = 0;
		INSCDCNT = 0;
	}

	/*
	 * For wrapmargin to hack away second space after a '.'
	 * when the first space caused a line break we keep
	 * track that this happened in gobblebl, which says
	 * to gobble up a blank silently.
	 */
	gobblebl = 0;

	startsrcline = dot;
	startsrccol = cursor - linebuf;

	/*
	 * Text gathering loop.
	 * New text goes into genbuf starting at gcursor.
	 * cursor preserves place in linebuf where text will eventually go.
	 */
	if (*cursor == 0 || state == CRTOPEN)
		hold |= HOLDROL;
	for (;;) {
		if (ch == 'r' && repcnt == 0)
			escape = 0;
		else {
			ixlatctl(1);
			/*
			 * When vgetline() returns, gcursor is
			 * pointing to '\0' and vgetline() has
			 * read an ESCAPE or NL.
			 */
			gcursor = vgetline(repcnt, gcursor, &escape, ch);
			if (escape == '\n') {
				gotNL = 1;
#ifdef XPG6
				if (ch == 'r') {
					/*
					 * XPG6 assertion 313 [count]r\n :
					 * Arrange to set cursor correctly.
					 */
					endsrccol = gcursor - genbuf - 1;
				}
#endif /* XPG6 */
			} else {
				/*
				 * Upon escape, gcursor is pointing to '\0'
				 * terminating the string in genbuf.
				 */
				endsrccol = gcursor - genbuf - 1;
			}
			ixlatctl(0);

			/*
			 * After an append, stick information
			 * about the ^D's and ^^D's and 0^D's in
			 * the repeated text buffer so repeated
			 * inserts of stuff indented with ^D as backtab's
			 * can work.
			 */
			if (HADUP)
				addtext("^");
			else if (HADZERO)
				addtext("0");
			if(!vglobp)
				INSCDCNT = CDCNT;
			while (CDCNT > 0) {
				addtext("\004");
				CDCNT--;
			}
			if (gobbled)
				addtext(" ");
			addtext(ogcursor);
		}
		repcnt = 0;

		/*
		 * Smash the generated and preexisting indents together
		 * and generate one cleanly made out of tabs and spaces
		 * if we are using autoindent and this isn't 'r' command.
		 */
		if (!vaifirst && value(vi_AUTOINDENT)) {
			i = fixindent(indent);
			if (!HADUP)
				indent = i;
			gcursor = strend(genbuf);
		}

		/*
		 * Set cnt to 1 to avoid repeating the text on the same line.
		 * Do this for commands 'i', 'I', 'a', and 'A', if we're
		 * inserting anything with a newline for XPG6.  Always do this
		 * for commands 'o' and 'O'.
		 */
		if ((imultlinecnt && gotNL) || omultlinecnt) {
			cnt = 1;
		}

		/*
		 * Limit the repetition count based on maximum
		 * possible line length; do output implied
		 * by further count (> 1) and cons up the new line
		 * in linebuf.
		 */
		cnt = vmaxrep(ch, cnt);
		/*
		 * cursor points to linebuf
		 * Copy remaining old text (cursor) in original
		 * line to after new text (gcursor + 1) in genbuf.
		 */
		CP(gcursor + 1, cursor);
		/*
		 * For [count] r \n command, when replacing [count] chars
		 * with '\n', this loop replaces [count] chars with "".
		 */
		do {
			/* cp new text (genbuf) into linebuf (cursor) */
			CP(cursor, genbuf);
			if (cnt > 1) {
				int oldhold = hold;

				Outchar = vinschar;
				hold |= HOLDQIK;
				viprintf("%s", genbuf);
				hold = oldhold;
				Outchar = vputchar;
			}
			/* point cursor after new text in linebuf */
			cursor += gcursor - genbuf;
		} while (--cnt > 0);
		endim();
		vUA2 = cursor;
		/* add the remaining old text after the cursor */
		if (escape != '\n')
			CP(cursor, gcursor + 1);

		/*
		 * If doomed characters remain, clobber them,
		 * and reopen the line to get the display exact.
		 * eg. c$ to change to end of line
		 */
		if (state != HARDOPEN) {
			DEPTH(vcline) = 0;
			savedoomed = doomed;
			if (doomed > 0) {
				int cind = cindent();

				physdc(cind, cind + doomed);
				doomed = 0;
			}
			if(MB_CUR_MAX > 1)
				rewrite = _ON;
			i = vreopen(LINE(vcline), lineDOT(), vcline);
			if(MB_CUR_MAX > 1)
				rewrite = _OFF;
#ifdef TRACE
			if (trace)
				fprintf(trace, "restoring doomed from %d to %d\n", doomed, savedoomed);
#endif
			if (ch == 'R')
				doomed = savedoomed;
		}

		/*
		 * Unless we are continuing on to another line
		 * (got a NL), break out of the for loop (got
		 * an ESCAPE).
		 */
		if (escape != '\n') {
			vshowmode("");
			break;
		}

		/*
		 * Set up for the new line.
		 * First save the current line, then construct a new
		 * first image for the continuation line consisting
		 * of any new autoindent plus the pushed ahead text.
		 */
		killU();
		addtext(gobblebl ? " " : "\n");
		/* save vutmp (for undo state) into temp file */
		vsave();
		cnt = 1;
		if (value(vi_AUTOINDENT)) {
			if (value(vi_LISP))
				indent = lindent(dot + 1);
			else
			     if (!HADUP && vaifirst)
				indent = whitecnt(linebuf);
			vaifirst = 0;
			strcLIN(vpastwh(gcursor + 1));
			gcursor = genindent(indent);
			*gcursor = 0;
			if (gcursor + strlen(linebuf) > &genbuf[LBSIZE - 2])
				gcursor = genbuf;
			CP(gcursor, linebuf);
		} else {
			/*
			 * Put gcursor at start of genbuf to wipe
			 * out previous line in preparation for
			 * the next vgetline() loop.
			 */
			CP(genbuf, gcursor + 1);
			gcursor = genbuf;
		}

		/*
		 * If we started out as a single line operation and are now
		 * turning into a multi-line change, then we had better yank
		 * out dot before it changes so that undo will work
		 * correctly later.
		 */
		if (FIXUNDO && vundkind == VCHNG) {
			vremote(1, yank, 0);
			undap1--;
		}

		/*
		 * Now do the append of the new line in the buffer,
		 * and update the display, ie: append genbuf to
		 * the file after dot.  If slowopen
		 * we don't do very much.
		 */
		vdoappend(genbuf);
		vundkind = VMANYINS;
		vcline++;
		if (state != VISUAL)
			vshow(dot, NOLINE);
		else {
			i += LINE(vcline - 1);
			vopen(dot, i);
			if (value(vi_SLOWOPEN))
				vscrap();
			else
				vsync1(LINE(vcline));
		}
		switch (ch) {
		case 'r':
			break;
		case 'a':
			if (value(vi_TERSE)) {
				vshowmode(gettext("A"));
			} else {
				vshowmode(gettext("APPEND MODE"));
			}
			break;
		case 's':
			if (value(vi_TERSE)) {
				vshowmode(gettext("S"));
			} else {
				vshowmode(gettext("SUBSTITUTE MODE"));
			}
			break;
		case 'c':
			if (value(vi_TERSE)) {
				vshowmode(gettext("C"));
			} else {
				vshowmode(gettext("CHANGE MODE"));
			}
			break;
		case 'R':
			if (value(vi_TERSE)) {
				vshowmode(gettext("R"));
			} else {
				vshowmode(gettext("REPLACE MODE"));
			}
			break;
		case 'i':
			if (value(vi_TERSE)) {
				vshowmode(gettext("I"));
			} else {
				vshowmode(gettext("INSERT MODE"));
			}
			break;
		case 'o':
			if (value(vi_TERSE)) {
				vshowmode(gettext("O"));
			} else {
				vshowmode(gettext("OPEN MODE"));
			}
			break;
		default:
			if (value(vi_TERSE)) {
				vshowmode(gettext("I"));
			} else {
				vshowmode(gettext("INPUT MODE"));
			}
		}
		strcLIN(gcursor);
		/* zero genbuf */
		*gcursor = 0;
		cursor = linebuf;
		vgotoCL(nqcolumn(cursor - 1, genbuf));
	} /* end for (;;) loop in vappend() */

	if (imultlinecnt && gotNL) {
		imultlinerep(savecnt, startsrcline, startsrccol, endsrccol);
	} else if (omultlinecnt) {
		omultlinerep(savecnt, startsrcline, endsrccol);
#ifdef XPG6
	} else if (savecnt > 1 && ch == 'r' && gotNL) {
		/*
		 * XPG6 assertion 313 & 254 : Position cursor for [count]r\n
		 * then insert [count -1] newlines.
		 */
		endsrccol = gcursor - genbuf - 1;
		rmultlinerep(savecnt, endsrccol);
#endif /* XPG6 */
	}

	/*
	 * All done with insertion, position the cursor
	 * and sync the screen.
	 */
	hold = oldhold;
	if ((imultlinecnt && gotNL) || omultlinecnt) {
		fixdisplay();
#ifdef XPG6
	} else if (savecnt > 1 && ch == 'r' && gotNL) {
		fixdisplay();
		/*
		 * XPG6 assertion 313 & 254 [count]r\n : Set flag to call
		 * fixdisplay() after operate() has finished.  To be sure that
		 * the text (after the last \n followed by an indent) is always
		 * displayed, fixdisplay() is called right before getting
		 * the next command.
		 */
		redisplay = 1;
#endif /* XPG6 */
	} else if (cursor > linebuf) {
		cursor = lastchr(linebuf, cursor);
#ifdef XPG6
		/*
		 * XPG6 assertion 313 & 254 [count]r\n :
		 * For 'r' command, when the replacement char causes new
		 * lines to be created, point cursor to first non-blank.
		 * The old code, ie: cursor = lastchr(linebuf, cursor);
		 * set cursor to the blank before the first non-blank
		 * for r\n
		 */
		if (ch == 'r' && gotNL && isblank((int)*cursor))
			++cursor;
#endif /* XPG6 */
	}
	if (state != HARDOPEN)
		vsyncCL();
	else if (cursor > linebuf)
		back1();
	doomed = 0;
	wcursor = cursor;
	(void) vmove();
}