Beispiel #1
0
/*
 * Display a new line at physical line p, returning
 * the depth of the newly displayed line.  We may decide
 * to expand the window on an intelligent terminal if it is
 * less than a full screen by deleting a line above the top of the
 * window before doing an insert line to keep all the good text
 * on the screen in which case the line may actually end up
 * somewhere other than line p.
 */
void 
vopen(line *tp, int p)
{
	register int cnt;
	register struct vlinfo *vp, *vpc;

#ifdef ADEBUG
	if (trace != NULL)
		tfixnl(), fprintf(trace, "vopen(%d, %d)\n", lineno(tp), p);
#endif
	if (state != VISUAL) {
		if (vcnt)
			if (hold & HOLDROL)
				vup1();
			else
				vclean();

		/*
		 * Forget all that we once knew.
		 */
		vcnt = vcline = 0;
		p = WBOT; LASTLINE = WBOT + 1;
		state = bastate;
		WTOP = basWTOP;
		WLINES = basWLINES;
	}
	vpc = &vlinfo[vcline];
	for (vp = &vlinfo[vcnt]; vp >= vpc; vp--)
		vlcopy(vp[1], vp[0]);
	vcnt++;
	if (Pline == numbline)
		/*
		 * Dirtying all the lines is rather inefficient
		 * internally, but number mode is used rarely
		 * and so its not worth optimizing.
		 */
		vdirty(vcline+1, WECHO);
	getline(*tp);

	/*
	 * If we are opening at the top of the window, can try a window
	 * expansion at the top.
	 */
	if (state == VISUAL && vcline == 0 && vcnt > 1 && p > ZERO) {
		cnt = p + vdepth() - LINE(1);
		if (cnt > 0) {
			p -= cnt;
			if (p < ZERO)
				p = ZERO;
			WTOP = p;
			WLINES = WBOT - WTOP + 1;
		}
	}
	vpc->vliny = p, vpc->vdepth = 0, vpc->vflags = 0;
	cnt = vreopen(p, lineno(tp), vcline);
	if (vcline + 1 == vcnt)
		LINE(vcnt) = LINE(vcline) + cnt;
}
Beispiel #2
0
/*
 * Delete operator.
 *
 * Hard case of deleting a range where both wcursor and wdot
 * are specified is treated as a special case of change and handled
 * by vchange (although vchange may pass it back if it degenerates
 * to a full line range delete.)
 */
void 
vdelete(int c)
{
	register char *cp;
	register int i;

	if (wdot) {
		if (wcursor) {
			vchange(EOF);
			return;
		}
		if ((i = xdw()) < 0)
			return;
		if (state != VISUAL) {
			vgoto(LINE(0), 0);
			vputchar('@');
		}
		wdot = dot;
		vremote(i, delete, 0);
		notenam = "delete";
		DEL[0] = 0;
		killU();
		vreplace(vcline, i, 0);
		if (wdot > dol)
			vcline--;
		vrepaint(NOSTR);
		return;
	}
	if (wcursor < linebuf)
		wcursor = linebuf;
	if (cursor == wcursor) {
		beep();
		return;
	}
	i = vdcMID();
	cp = cursor;
	setDEL();
	CP(cp, wcursor);
	if (cp > linebuf && (cp[0] == 0 || c == '#'))
		cp--;
	if (state == HARDOPEN) {
		bleep(i, cp);
		cursor = cp;
		return;
	}
	physdc(column(cursor + skipleft(linebuf, cursor)), i);
	DEPTH(vcline) = 0;
	vreopen(LINE(vcline), lineDOT(), vcline);
	vsyncCL();
	vsetcurs(cp);
}
Beispiel #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();
}
Beispiel #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);
}
Beispiel #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
}
Beispiel #6
0
/*ARGSUSED*/
void 
vmove(int unused)
{
	register int cnt;

	if (wdot) {
		if (wdot < one || wdot > dol) {
			beep();
			return;
		}
		cnt = wdot - dot;
		wdot = NOLINE;
		if (cnt)
			killU();
		vupdown(cnt, wcursor);
		return;
	}

	/*
	 * When we move onto a new line, save information for U undo.
	 */
	if (vUNDdot != dot) {
		vUNDsav = *dot;
		vUNDcurs = wcursor;
		vUNDdot = dot;
	}

	/*
	 * In hardcopy open, type characters to left of cursor
	 * on new line, or back cursor up if its to left of where we are.
	 * In any case if the current line is ``rubbled'' i.e. has trashy
	 * looking overstrikes on it or \'s from deletes, we reprint
	 * so it is more comprehensible (and also because we can't work
	 * if we let it get more out of sync since column() won't work right.
	 */
	if (state == HARDOPEN) {
		register char *cp;
		if (rubble) {
			register int c;
			int oldhold = hold;

			sethard();
			cp = wcursor;
			c = *cp;
			*cp = 0;
			hold |= HOLDDOL;
			vreopen(WTOP, lineDOT(), vcline);
			hold = oldhold;
			*cp = c;
		} else if (wcursor > cursor) {
			vfixcurs();
			for (cp = cursor; *cp && cp < wcursor;) {
				int	c, n;
				nextc(c, cp, n);
				cp += n;
				c &= TRIM;
				putchar(c ? c : ' ');
			}
		}
	}
	vsetcurs(wcursor);
}
Beispiel #7
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();
}